STM32学习100步之第八十三步-第八十五步——定时器与PWM模块

定时器

定时器本质上是一个以单位时间为准的计数器,计数值可从0开始累加,也可从一个设定数值递减。每隔一个固定时间计时器的值加1或减1,当加到(或减到)到头时,会产生一个溢出信号,并将计时值清0重新计时。
利用定时器溢出可产生总周期,利用PWM可以调制该周期的占空比。

对于我们的STM32F103定时器的计数方式如下:

STM32学习100步之第八十三步-第八十五步——定时器与PWM模块_第1张图片

STM32F103

通用定时器(TIM 2、3、4)

STM32F103xx增强型产品中,内置了多达3个可同步运行的标准定时器(TIM2、TIM3、TIM4)。每个定时器都有一个16位的自动加载递加/递减计数器、一个16位的预分频器和4个独立的通道,每个通道都可用于输入捕获、输出比较、PWM和单脉冲模式输出,在大的封装配置中可提供多12个输入捕获、输出比较或PWM通道。它们还能通过定时器链接功能与高级控制定时器共同工作,提供同步或事件链接功能。在调试模式下,计数器可以被冻结。任一标准定时器都能用于产生PWM输出。每个定时器都有独立的DMA请求机制。这些定时器还能够处理增量编码器的信号,也能处理1至3个霍尔传感器的数字输出。

高级定时器(TIM 1)

高级控制定时器(TIM1)可以被看成是分配到6个通道的三相PWM发生器,它具有带死区插入的互补PWM输出,还可以被当成完整的通用定时器。四个独立的通道可以用于:

输入捕获、输出比较、产生PWM(边缘或中心对齐模式)、单脉冲输出

配置为16位标准定时器时,它与TIMx定时器具有相同的功能。
配置为16位PWM发生器时,它具有全调制能力(0~100%)。
在调试模式下,计数器可以被冻结,同时PWM输出被禁止,从而切断由这些输出所控制的开关。
很多功能都与标准的TIM定时器相同,内部结构也相同,
因此高级控制定时器可以通过定时器链接功能与TIM定时器协同操作,提供同步或事件链接功能。

定时器的工作模式如下图:STM32学习100步之第八十三步-第八十五步——定时器与PWM模块_第2张图片

本次我们具体了解定时器产生PWM的功能

PWM

PWM脉宽调制
脉冲宽度调制(PWM),是英文“Pulse Width Modulation’ 的缩写,简称脉宽调制。脉宽调制也叫占空比。
它是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,广泛应用在从测量、通信到功率控制与变换的许多领域中。

在我看来就是单片机通过相应定时器的设置,将某个IO端口设置成可以产生一定周期、一定占空比的方波。

利用定时器产生PWM的原理图如下:
STM32学习100步之第八十三步-第八十五步——定时器与PWM模块_第3张图片
STM32学习100步之第八十三步-第八十五步——定时器与PWM模块_第4张图片
通过设置计数值ARR的值,我们用来产生一定周期的波形(因为每过一个机器周期,计数值加1),通过设定CCRx的值,当计数值在CCRx之前的值,将IO端口设置成低电平,在CCRx和ARR值之间设置成高电平 ,如此即完成了相应的占空比。

STM32F103对应的定时器的通道与IO端口复用,同时也可以通过重映射,将对应的通道映射到其他的IO端口,只需要使用固件库函数即可。
由于本例我们利用了TIM3定时器产生PWM波,因此特将TIM3的重映射表列下:
STM32学习100步之第八十三步-第八十五步——定时器与PWM模块_第5张图片

由于TIM3的3通道和PB0复用,因此需要开启复用时钟:
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//使能AFIO时钟(定时器3通道3需要重映射到BP5引脚)

又因为我们使用了48引脚封装,因此不可使用重映射。

下面是具体TIM3产生的PWM程序

STM32F103的定时器产生PWM有两种方式,如下图:

STM32学习100步之第八十三步-第八十五步——定时器与PWM模块_第6张图片
通过下面函数初始化产生PWM的方式:

    TIM_TimeBaseInitStrue.TIM_CounterMode=TIM_CounterMode_Up;  
      //计数器向上溢出
    TIM_OCInitStrue.TIM_OCMode=TIM_OCMode_PWM1;   
         // PWM模式1:CNT < CCR时输出有效电平

可以对相应的字符串修改改变方式(字符串被重定义为相应功能的代码)

具体有效电平的设置如下图:

STM32学习100步之第八十三步-第八十五步——定时器与PWM模块_第7张图片
通过下面程序设置极性:

TIM_OCInitStrue.TIM_OCPolarity=TIM_OCPolarity_High;// 设置极性-有效电平为:高电平

通过该函数稳定定时期:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//使能AFIO时钟(定时器3通道3需要重映射到BP5引脚)
具体产生PWM周期的初始化函数如下:
void TIM3_PWM_Init(u16 arr,u16 psc){  //TIM3 PWM初始化 arr重装载值 psc预分频系数
    GPIO_InitTypeDef     GPIO_InitStrue;
    TIM_OCInitTypeDef     TIM_OCInitStrue;
    TIM_TimeBaseInitTypeDef     TIM_TimeBaseInitStrue;
    
    
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//使能TIM3和相关GPIO时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//使能GPIOB时钟(LED在PB0引脚)
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//使能AFIO时钟(定时器3通道3需要重映射到BP5引脚)
    
    GPIO_InitStrue.GPIO_Pin=GPIO_Pin_0;     // TIM_CH3
    GPIO_InitStrue.GPIO_Mode=GPIO_Mode_AF_PP;    // 复用推挽
    GPIO_InitStrue.GPIO_Speed=GPIO_Speed_50MHz;    //设置最大输出速度
    GPIO_Init(GPIOB,&GPIO_InitStrue);                //GPIO端口初始化设置
    
//    GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE); //映射,重映射只用于64、100、144脚单片机
   //当没有重映射时,TIM3的四个通道CH1,CH2,CH3,CH4分别对应PA6,PA7,PB0,PB1
   //当部分重映射时,TIM3的四个通道CH1,CH2,CH3,CH4分别对应PB4,PB5,PB0,PB1 (GPIO_PartialRemap_TIM3)
   //当完全重映射时,TIM3的四个通道CH1,CH2,CH3,CH4分别对应PC6,PC7,PC8,PC9 (GPIO_FullRemap_TIM3) 
	      
    TIM_TimeBaseInitStrue.TIM_Period=arr;    //设置自动重装载值
    TIM_TimeBaseInitStrue.TIM_Prescaler=psc;        //预分频系数
    TIM_TimeBaseInitStrue.TIM_CounterMode=TIM_CounterMode_Up;    //计数器向上溢出
    TIM_TimeBaseInitStrue.TIM_ClockDivision=TIM_CKD_DIV1;        //时钟的分频因子,起到了一点点的延时作用,一般设为TIM_CKD_DIV1
    TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStrue);        //TIM3初始化设置(设置PWM的周期)
    
    TIM_OCInitStrue.TIM_OCMode=TIM_OCMode_PWM1;        // PWM模式1:CNT < CCR时输出有效电平
    TIM_OCInitStrue.TIM_OCPolarity=TIM_OCPolarity_High;// 设置极性-有效电平为:高电平
    TIM_OCInitStrue.TIM_OutputState=TIM_OutputState_Enable;// 输出使能
    TIM_OC3Init(TIM3,&TIM_OCInitStrue);        //TIM3的通道3 PWM 模式设置

    TIM_OC3PreloadConfig(TIM3,TIM_OCPreload_Enable);        //使能预装载寄存器
    
    TIM_Cmd(TIM3,ENABLE);        //使能TIM3
    
}

使用实例如下:

	TIM3_PWM_Init(59999,23); //设置频率为50Hz,公式为:溢出时间Tout(单位秒)=(arr+1)(psc+1)/Tclk	 20MS = (59999+1)*(23+1)/72000000
                          //Tclk为通用定时器的时钟,如果APB1没有分频,则就为系统时钟,72MHZ
                          //PWM时钟频率=72000000/(59999+1)*(23+1) = 50HZ (20ms),设置自动装载值60000,预分频系数24

需要注意的是,由于之前我们利用PB0产生PWM波,而TIM3的通道3和PB0复用,因此此时一定要设置TIM3的通道3。即下面函数:

   TIM_OC3Init(TIM3,&TIM_OCInitStrue);        //TIM3的通道3 PWM 模式设置
所谓的自动重装载值在我看来就是计数的总次数,以向上加为例,从0加到该值,这时产生溢出,计数器被重新清零,继续装载,到达该值以后,重新被清零,再次计数。
所谓预分频系数在我看来就是将APB1主频除以(该值+1),即将主频分频之后(分频为除以(该值+1)),接入定时器(计数器)的脉冲输入端,即该频率的脉冲驱动计数器工作,即每经过该频率所对应的时间,定时器中计数器加一,由于自动重装载值为最大值,因此此定时器的定时时间便可由二者的乘积确定,如此便定出了对应PWM的周期。
设定PWM占空比的函数如下:
TIM_SetCompare3(TIM3,3000);

其中的第一个值3是设置定时器的通道3的值,因为前面我们用的是TIM3的通道3,因此这里要写3,一定要注意对应关系。
第二个参数是设置对应的定时器号。
第三个值是设定前面图的CCR的值,CCR值小于自动重装载值,当计数值到达CCR时,将产生高低电平的切换,结合前面PWM的方式设置,以及有效电平的设置,便可完全控制实现PWM占空比的设置。

由于前面的设定正好符合舵机需要占空比的条件,即CCR正好可以作为旋转度数的衡量标准,完全符合,将舵机驱动的PWM列下:

STM32学习100步之第八十三步-第八十五步——定时器与PWM模块_第8张图片
由于20ms是60000计数值,推算出0.5ms的计数值便是1500,2.5ms的计数值是7500。因此将CCR设置成1500,便达到了转动0°,设置成7500,便达到了转动180°,设置成3000,便达到了转动3000×180/6000=90°的要求。

上式的计算,将对应的时间转换到了对应计数次数,是为了满足对应库函数对CCR的要求。

你可能感兴趣的:(STM32学习100步之第八十三步-第八十五步——定时器与PWM模块)