找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 7859|回复: 1
收起左侧

STM32通用定时器(TIM2-5)PWM输出

[复制链接]
ID:105323 发表于 2016-2-12 22:20 | 显示全部楼层 |阅读模式
本帖最后由 51黑黑黑 于 2016-2-12 22:21 编辑

   STM32的定时器是个强大的模块,定时器使用的频率也是很高的,定时器可以做一些基本的定时,还可以做PWM输出或者输入捕获功能。从系统框架图下看,名为TIMx的有八个,其中TIM1和TIM8挂在APB2总线上,而TIM2-TIM7则挂在APB1总线上。其中TIM1&TIM8称为高级控制定时器(advancedcontroltimer).他们所在的APB2总线也比APB1总线要好。APB2可以工作在72MHz下,而APB1最大是36MHz。

   由上图可知,当APB1的预分频系数为1 时,这个倍频器不起作用,定时器的时钟频率等于APB1的频率;当APB1的预分频系数为其它数值(即预分频系数为2、4、8 或16)时,这个倍频器起作用,定时器的时钟频率等于APB1的频率两倍。也就是,当APB1不分频,TIM3的时钟速度为36MHz,当2分频是,APB1变成18MHz,但是TIM又会倍频,即TIM时钟等于18*2=36MHz。这里我们用向上计数的方式,即TIMx_CNT中的计数值达到TIMx_ARR中的值时,产生中断,TIMx_CNT又从0开始计。

按以下步骤编程:
1.系统初始化,主要初始化时钟等。
2.GPIO初始化,用于LED,有了灯就便于观察了。
3.TIM3的配置。
4.NVIC的配置。
5.编写中断服务函数。

void GPIO_PA_Init()
{//PA8管脚配置
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_DeInit(GPIOA);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//推挽输出
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);//使能端口时钟A
GPIO_Init(GPIOA,&GPIO_InitStructure);
}
void TIMER3_Init()
{
TIM_TimeBaseInitTypeDefTIM_TimeBaseStructure;
TIM_DeInit(TIM3);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
TIM_TimeBaseStructure.TIM_Period=10000;//ARR的值
TIM_TimeBaseStructure.TIM_Prescaler=7200-1;
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;//向上计数模式
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);
TIM_Cmd(TIM3, ENABLE); //开启时钟
}
void NVIC_Configuration()
{  
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);  // 抢占式优先级别
NVIC_InitStructure.NVIC_IRQChannel =TIM3_IRQChannel;//指定中断源
NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;// 指定响应优先级别1
NVIC_InitStructure.NVIC_IRQChannelCmd =ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
int main(void)
{     
Stm32_Clock_Init(9); //系统时钟设置
delay_init(72);     //延时初始化
GPIO_PA_Init();
TIMER3_Init();
NVIC_Configuration();
while(1);
}
void TIM3_IRQHandler()
{
if(TIM_GetITStatus(TIM3 , TIM_IT_Update) ==SET)
{
  TIM_ClearITPendingBit(TIM3 ,TIM_FLAG_Update);
  if(GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_8))GPIO_ResetBits(GPIOA, GPIO_Pin_8);
  else GPIO_SetBits(GPIOA,GPIO_Pin_8);
}
}




  脉冲宽度调制(PWM),是英文“Pulse WidthModulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。简单一点,就是对脉冲宽度的控制。一般用来控制步进电机的速度等等。STM32的定时器除了TIM6TIM7之外,其他的定时器都可以用来产生PWM输出,其中高级定时器TIM1TIM8可以同时产生7路的PWM输出,而通用定时器也能同时产生4路的PWM输出。

PWM输出模式
STM32PWM输出有两种模式,模式1和模式2,由TIMx_CCMRx寄存器中的OCxM位确定的(“110”为模式1,“111”为模式2)。模式1和模式2的区别如下:
110PWM模式1-在向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道1为有效电平,否则为无效电平;在向下计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为无效电平(OC1REF=0),否则为有效电平(OC1REF=1)
111PWM模式2-在向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道1为无效电平,否则为有效电平;在向下计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为有效电平,否则为无效电平。
由此看来,模式1和模式2正好互补,互为相反,所以在运用起来差别也并不太大。
而从计数模式上来看,PWM也和TIMx在作定时器时一样,也有向上计数模式、向下计数模式和中心对齐模式,关于3种模式的具体资料,可以查看《STM32参考手册》的“14.3.9 PWM模式”一节,在此就不详细赘述了。

PWM输出管脚
PWM的输出管脚是确定好的,具体的引脚功能可以查看《STM32参考手册》的“8.3.7 定时器复用功能重映射”一节。在此需要强调的是,不同的TIMx有分配不同的引脚,但是考虑到管脚复用功能,STM32提出了一个重映像的概念,就是说通过设置某一些相关的寄存器,来使得在其他非原始指定的管脚上也能输出PWM。但是这些重映像的管脚也是由参考手册给出的。比如说TIM3的第2个通道,在没有重映像的时候,指定的管脚是PA.7,如果设置部分重映像之后,TIM3_CH2的输出就被映射到PB.5上了,如果设置了完全重映像的话,TIM3_CH2的输出就被映射到PC.7上了。

PWM输出信号
PWM输出的是一个方波信号,信号的频率是由TIMx的时钟频率和TIMx_ARR预分频器所决定的,具体设置方法在前面一个学习笔记中有详细的交代。而输出信号的占空比则是由TIMx_CRRx寄存器确定的。其公式为“占空比=(TIMx_CRRx/TIMx_ARR)*100%”,因此,可以通过向CRR中填入适当的数来输出自己所需的频率和占空比的方波信号。

按以下步骤配置:
1. 设置RCC时钟;
2. 设置GPIO时钟;
3. 设置TIMx定时器的相关寄存器;
4. 设置TIMx定时器的PWM相关寄存器;

   第1步设置RCC时钟已经在前文中给出了详细的代码,在此就不再多说了。需要注意的是通用定时器TIMx是由APB1提供时钟,而GPIO则是由APB2提供时钟。注意,如果需要对PWM的输出进行重映像的话,还需要开启引脚复用时钟AFIO
   第2步设置GPIO时钟时,GPIO模式应该设置为复用推挽输出GPIO_Mode_AF_PP,如果需要引脚重映像的话,则需要用GPIO_PinRemapConfig()函数进行设置。
   第3步设置TIMx定时器的相关寄存器时,和前一篇学习笔记一样,设置好相关的TIMx的时钟和技术模式等等。
   第4步设置PWM相关寄存器,首先要设置PWM模式(默认情况下PWM是冻结的),然后设置占空比(根据前面所述公式进行计算),再设置输出比较极性:当设置为High时,输出信号不反相,当设置为Low时,输出信号反相之后再输出。最重要是是要使能TIMx的输出状态和使能TIMx的PWM输出使能。相关设置完成之后,就可以通过TIM_Cmd()来打开TIMx定时器,从而得到PWM输出了。

以下是我写的参考程序:
void GPIO_PA_Init()
{//PA13管脚配置
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_DeInit(GPIOA);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);//使能端口时钟A
GPIO_Init(GPIOA,&GPIO_InitStructure);
}

void TIMER3_Init()
{
TIM_TimeBaseInitTypeDefTIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
TIM_DeInit(TIM3);
TIM_InternalClockConfig(TIM3);
TIM_TimeBaseStructure.TIM_Period=10000-1;//ARR的值周期10K
TIM_TimeBaseStructure.TIM_Prescaler=0;
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;//向上计数模式
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);
}

void TIMER3_PWM_Init()
{  
TIM_OCInitTypeDef TIMOCInitStructure;
TIMOCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//PWM模式1输出
TIMOCInitStructure.TIM_Pulse=0;//占空比=(CCRx/ARR)*100%
TIMOCInitStructure.TIM_OCPolarity =TIM_OCPolarity_High;//TIM输出比较极性高
TIMOCInitStructure.TIM_OutputState =TIM_OutputState_Enable;//使能输出状态
TIM_OC2Init(TIM3,&TIMOCInitStructure);//TIM3的CH2输出
TIM_CtrlPWMOutputs(TIM3,ENABLE);//设置TIM3的PWM输出为使能
TIM_Cmd(TIM3, ENABLE); //开启时钟
}

回复

使用道具 举报

ID:105450 发表于 2016-2-14 20:33 | 显示全部楼层
很不错
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表