国民技术N32G031开发笔记 - 高级定时器TIM1输出互补PWM

国民技术N32G031使用高级定时器TIM1输出互补PWM

高级定时器介绍

高级定时器具有互补输出功能、死区插入和刹车功能。适用于电机控制。
16 位自动装载计数器。(可实现向上计数、向下计数、向上/下计数)
 16 位可编程预分频器。(分频系数可配置为1 到65536 之间的任意值)
 可编程重复计数器
 TIM1 最多6 个通道,TIM8 最多6 个通道
 4 个捕获/比较通道,工作模式为:PWM输出、输出比较、单脉冲模式输出、输入捕获
 如下事件发生时产生中断/DMA:
 更新事件
 触发事件
 输入捕获
 输出比较
 刹车信号输入
 死区时间可编程的互补输出
 对于TIM1、TIM8,通道1、2、3 支持此功能
 可通过外部信号控制定时器
 多个定时器内部连接在一起,以实现定时器的同步或链接
 TIM1_CC5 和 TIM8_CC5 用于比较器消隐
 TIM1_CC6 用于 OPAMP1 和 OPAMP2 的输入通道切换
 增量(正交)编码器接口:用于追踪运行轨迹和解析旋转方位
 霍尔传感器接口:用于三相电机控制

结构框图

在这里插入图片描述

  • 详细介绍请看国名技术官方指导手册,此处不细讲。

代码讲解

  • 目标:使用TIM1产生一组带有死区的互补PWM波形,此处使用寄存器来编写。使用库来编写的话,请参考官方的实例即可。

PWM.h

#ifndef __PWM_H__
#define __PWM_H__

#include "n32g031.h"
#include <stdint.h>

void PWMInit_ds(uint16_t PrescalerVal, uint16_t period);

#endif 

PWM.c

#include "pwm.h"

/*
* 使用高级定时器产生互补PWM输出
*/
void PWMInit_ds(uint16_t PrescalerVal, uint16_t period)
{
	uint32_t temp;
	OCInitType TIM_OCInitStructure;
	
	RCC->APB2PCLKEN |= (1<<12);//开启高级定时器1时钟
	RCC->APB2PCLKEN |=(1<<2);//使能GPIOA的时钟
	
	//gpio口配置
	//PA4 CH1
	GPIOA->PMODE &= (~(3 << 8));//clear PA4的模式
	GPIOA->PMODE |= (2<<8); //PA4设置复用功能模式
	GPIOA->POTYPE &=(~(1<<4)); //PA4设置为推挽输出
	GPIOA->SR &=(~(1<<4)); //PA4快速翻转
	GPIOA->PUPD &=(~(3<<8));//PA4无上下拉
	
	GPIOA->AFL &=(~(0X0F<<16));
	GPIOA->AFL |=(0X03<<16);//AF3: TIM1_CH1
	GPIOA->DS |=(1<<4);//PA4设为低驱动能力(8mA(5V)/4mA(3.3V)/2mA(1.8V)
	
	//PA7 CH1N
	GPIOA->PMODE &= (~(3 << 14));//clear PA7的模式
	GPIOA->PMODE |= (2<<14); //PA7设置复用功能模式
	GPIOA->POTYPE &=(~(1<<7)); //PA7设置为推挽输出
	GPIOA->SR &=(~(1<<7)); //PA7快速翻转
	GPIOA->PUPD &=(~(3<<14));//PA7无上下拉
	
	GPIOA->AFL &=(~(0X0F<<28));
	GPIOA->AFL |=(0X05<<28);//AF5: TIM1-CHIN
	GPIOA->DS |=(1<<7);//PA7设为低驱动能力(8mA(5V)/4mA(3.3V)/2mA(1.8V)
	
	
	//timer1配置
	TIM1->CNT=0;//计数器
	TIM1->PSC = PrescalerVal;//f=fck_psc/(PrescalerVal+1)
	TIM1->AR = period;//自动重装载的值
	TIM1->REPCNT=10;//重复计数器
	
	
	temp=TIM1->CTRL1;
	temp |=(1<<17);//PVD作为BRK启用。0:禁止;1:使能
	temp &=~(1<<16);//LockUp锁存作为BRK使能。0:禁止;1-使能
	temp &=~(1<<10);//IOM作为BRK使能。0:使能。选择外部刹车信号(来自IOM);1:禁止。选择内部刹车信号(来自COMP)
	
	temp &=(~(3<<8));
	temp |=((0<<8));//CLKD[1:0] 表示 CK_INT(定时器时钟)和 DTS(用于死区时间发生器和数字滤波器(ETR、TIx)的时钟)之间的分频比。
								//00:tDTS = tCK_INT;01:tDTS = 2 x tCK_INT;10:tDTS = 4 x tCK_INT;11:保留,不要使用这个配置
	temp |=(1<<7);//自动重装载预装载允许位。1:TIMx_AR 寄存器的影子寄存器使能
	temp &=(~(1<<5));//选择中央对齐模式。00:边缘对齐模式。 TIMx_CTRL1.DIR 指定向上计数或向下计数。
	temp &=(~(1<<4));//0:计数器向上计数;1:计数器向下计数。
	temp &=(~(1<<3));//0:禁用单脉冲模式,发生更新事件时不影响计数器计数。
	temp |=(1<<2);//更新请求源:1:如果更新中断或 DMA 请求使能,只有计数器上溢/下溢会产生更新中断或 DMA请求。
	temp &=(~(1<<1));//更新禁用: 0-启用更新事件;1-UEV 禁用
	TIM1->CTRL1 =temp;
	
	
	/*******************pwm输出配置部分 start***********************/
	
	TIM1->CCEN &= (uint32_t)(~(uint32_t)TIM_CCEN_CC1EN);
	
	temp=TIM1->CTRL2;
	temp &=~(1<<9);//输出空闲状态1(OC1N输出) 0:当MOEN=0时,死区后OC1N=0;1:当MOEN=0时,死区后OC1N=1。
	temp &=~(1<<8);//输出空闲状态1(OC1输出) 0:当MOEN=0时,如果实现了OC1N,则死区后OC1=0;1:当MOEN=0时,如果实现了OC1N,则死区后OC1=1。
	
	temp &=(~(0X07<<4));
	temp |=(0X05<<4);//101:比较 - OC2REF 信号用作触发输出(TRGO)。
	
	temp |=(1<<0);//1:CCxEN,CCxNEN和OCxMD位是预装载的;设置该位后,它们只在设置了CCUDGN位后被更新。
	TIM1->CTRL2 =temp;
	
//捕获/比较模式寄存器
	temp=TIM1->CCMOD1;
	
	temp &=(~(0x07<<12));
	temp |=(0x06<<12);//110:PWM 模式 1 - 在向上计数模式下,如果 TIMx_CNT < TIMx_CCDAT2,则通道2 的 OC2REF 信号为高电平,否则为低电平。
	 						      //在向下计数模式下,如果TIMx_CNT > TIMx_CCDAT2,则通道 2 的 OC2REF 信号为低电平,否则为高电平。
	temp |=(1<<11);//0:禁用 TIMx_CCDAT2 寄存器的预加载功能。 支持随时对TIMx_CCDAT2寄存器进行写操作,写入的值立即生效。
	 					     //1:使能 TIMx_CCDAT2 寄存器的预加载功能。 仅对预加载寄存器进行读写操作。当更新事件发生时,TIMx_CCDAT2的值被加载到影子寄存器中。
	temp &=(~(3<<8));//00:CC2通道被配置为输出;
	temp &=(~(1<<7));//输出比较1清’0’使能。0:OC1REF 不受ETRF输入的影响;1:一旦检测到ETRF输入高电平,清除OC1REF=0。
	
	temp &=(~(0x07<<4));
	temp |=(0x06<<4);//110:PWM 模式 1 - 在向上计数模式下,如果 TIMx_CNT < TIMx_CCDAT1,则通道1 的 OC1REF 信号为高电平,否则为低电平。
	 					    	 //在向下计数模式下,如果TIMx_CNT > TIMx_CCDAT1,则通道 1 的 OC1REF 信号为低电平,否则为高电平。
	temp |=(1<<3);//0:禁用 TIMx_CCDAT1 寄存器的预加载功能。 支持随时对TIMx_CCDAT1寄存器进行写操作,写入的值立即生效。
	    					//1:使能 TIMx_CCDAT1 寄存器的预加载功能。 仅对预加载寄存器进行读写操作。当更新事件发生时,TIMx_CCDAT1 的值被加载到影子寄存器中。
	temp &=(~(3<<0));//00:CC1通道被配置为输出;
	TIM1->CCMOD1 =temp;
	
	TIM1->CCMOD2=0;
	
	//捕获/比较使能寄存器
	temp=TIM1->CCEN;
	temp &=~(1<<3);//捕获/比较1互补输出极性 0:OC1N高电平有效;1:OC1N低电平有效。
	temp |=(1<<2);//0:禁用 - 禁用输出 OC1N 信号。1:使能 - 使能输出 OC1N 信号。
	temp &=(~(1<<1));//捕获/比较1输出极性 0:OC1高电平有效;1:OC1低电平有效。
	temp |=(1<<0);//0:禁用 - 禁用输出 OC1 信号。1:使能 - 使能输出 OC1信号。
	TIM1->CCEN =temp;
	
	TIM1->CCDAT1=period>>1;//比较器CC1的比较值设置为period/2,即输出占空比为50%。
	
	TIM1->EVTGEN |=(1<<5);//CCUDGN - 捕获/比较事件,产生控制更新。该位由软件设置。 如果此时 TIMx_CTRL2.CCPCTL = 1,则允许更新 CCxEN、CCxNEN 和 OCxMD 位。 该位由硬件自动清零。0:无动作  1:产生一个COM事件
		
	/*******************pwm输出配置部分 end***********************/
	
	
	//DMA/中断使能寄存器
	temp=TIM1->DINTEN;
	temp &=(~(1<<7));//1:允许刹车中断。0:禁止刹车中断;
	temp &=(~(1<<6));//1:使能触发中断。0:禁止触发中断;
	temp &=(~(1<<5));//1:允许COM中断。0:禁止COM中断;
	temp &=(~(1<<0));//1:允许更新中断。0:禁止更新中断;
	TIM1->DINTEN =temp;
	
	TIM1->SMCTRL=0;//从模式控制寄存器
	TIM1->STS=0;//状态标志位
	TIM1->EVTGEN=0;//事件产生寄存器
		
	temp=TIM1->BKDT;
	temp &=(~(1<<14));//0:只有软件可以设置TIMx_BKDT.MOEN;1:软件设置TIMx_BKDT.MOEN; 或者如果刹车输入未激活,则在下一次更新事件发生时,硬件自动设置 TIMx_BKDT.MOEN。
	temp &=(~(1<<13));//刹车输入极性:0:刹车输入低电平有效;1:刹车输入高电平有效。
	temp &=(~(1<<12));//刹车功能使能:0:禁止刹车输入(BRK及CCS时钟失效事件);1:开启刹车输入(BRK及CCS时钟失效事件)。
	temp &=(~(1<<11));//0:当定时器不工作时,禁止OC/OCN输出(OC/OCN使能输出信号=0);1:当定时器不工作时,一旦CCxEN=1或CCxNEN=1,首先开启OC/OCN并输出无效电平,然后置OC/OCN使能输出信号=1。
	temp &=(~(1<<10));//0:当定时器不工作时,禁止OC/OCN输出(OC/OCN使能输出信号=0);1:当定时器不工作时,一旦CCxEN=1 或CCxNEN=1,OC/OCN首先输出其空闲电平,然后OC/OCN使能输出信号=1。
	
	temp &=(~(0X03<<8));
	temp |=((0X01<<8));//锁定设置 (Lock configuration) 该位为防止软件错误而提供写保护。此处设置锁定级别为 1级。
	
	temp &=(~(0Xff<<0));
	temp |=(12<<0);//死区发生器设置: 
												 //DTGN[7:5]=0xx => DT=DTGN[7:0] × Tdtgn,Tdtgn = TDTS;
												 //DTGN[7:5]=10x => DT=(64+DTGN[5:0]) × Tdtgn,Tdtgn = 2 × TDTS;
												 //DTGN[7:5]=110 => DT=(32+DTGN[4:0]) × Tdtgn,Tdtgn = 8 × TDTS;
												 //DTGN[7:5]=111 => DT=(32+DTGN[4:0])× Tdtgn,Tdtgn = 16 × TDTS;
	TIM1->BKDT =temp;
	
	
	TIM1->EVTGEN |=(1<<0);//产生更新事件
	
	TIM1->CTRL1 |=1;//0:禁止计数器;1:使能计数器。
	TIM1->BKDT |=(1<<15);//主输出使能 0:OC 和 OCN 输出被禁用或强制进入空闲状态。1:如果设置了 TIMx_CCEN.CCxEN 或 TIMx_CCEN.CCxNEN 位,则使能 OC 和 OCN输出。
}

main.c

#include "main.h"
#include "sys.h"
#include "pwm.h"



int main(void)
{
	uint8_t dir=0;
	uint16_t pwm=180;
    /* SystemInit() function has been called by startup file startup_n32g031.s */
    /* Configure the system clock to 48 MHz */    
	PWMInit_ds(48-1,999);//48MHz/((48)*(999+1))=1KHz
    while (1)
    {   
		//以下是呼吸灯的实例代码。	
			if(pwm<150)
			{
				dir=0;
			}
			else if(pwm>850)
			{
				dir=1;
			}
			if(dir)pwm -=50;else pwm +=50;
       		Systick_delayMs(100);//延时100ms
			TIM1->CCDAT1 = pwm;//修改占空比
    }
}

结尾

把PA4或PA7接上LED灯,可以看到呼吸灯效果。使用示波器观察PA4、PA7脚波形,可以观察到一组互补PWM波,占空比在不断修改。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木龠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值