使用STM32F103实验和总结PWM相关知识

脉冲宽度调制PWM(Pulse Width Modulation)的原理示意图如下:

使用STM32F103实验和总结PWM相关知识_第1张图片

图中,假定定时器工作在向上计数PWM2模式,定时器从0开始计数到ARR,t时刻比较计数值CNT和CCRx,当CNT=CCRx时,IO出高。当CNT=ARR,重新计数。

显然:改变CCRx可以改变占空比,改变ARR可以改变输出频率。

STM32F103 的定时器除了 TIM6 和 7。其他的定时器都可以用来产生 PWM 输出。其中高级定时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出,高级定时器尚未研究,以后再议。用定时器也能同时产生多达 4路的 PWM 输出。

首先大致了解PWM相关的三个寄存器:捕获/比较模式寄存器(TIMx_CCMR1/2)、捕获/比较使能寄存器(TIMx_CCER)、捕获/比较寄存器(TIMx_CCR1~4)。

1.捕获/比较模式寄存器(TIMx_CCMR1/2):

该寄存器总共有 2 个, TIMx _CCMR1和 TIMx _CCMR2。 TIMx_CCMR1 控制 CH1 和 2,而 TIMx_CCMR2 控制 CH3 和 4。

通道可用于输入(捕获模式)或输出(比较模式),通道的方向由相应的CCxS定义。

该寄存器其它位的作用在输入和输出模式下不同:

OCxx描述了通道在输出模式下的功能,ICxx描述了通道在输出模式下的功能。

当OC1M为:

110:PWM模式1。

 

111: PWM模式2。

两个模式输出电平极性相反。

 

 

2.捕获/比较使能寄存器(TIMx_CCER)

CC1E:输入/捕获1输出使能 (Capture/Compare 1 output enable)
CC1通道配置为输出:
0: 关闭- OC1禁止输出。
1: 开启- OC1信号输出到对应的输出引脚。
CC1通道配置为输入:
该位决定了计数器的值是否能捕获入TIMx_CCR1寄存器。
0:捕获禁止;
1:捕获使能。

CCxE中的x对应通道定时器的4个通道CH1~4。

 

3.捕获/比较寄存器(TIMx_CCR1~4)

该寄存器总共有 4 个,对应 4 个通道 CH1~4。

CCR1[15:0]: 捕获/比较1的值 (Capture/Compare 1 value)
若CC1通道配置为输出:
CCR1包含了装入当前捕获/比较1寄存器的值(预装载值)。
如果在TIMx_CCMR1寄存器(OC1PE位)中未选择预装载特性,写入的数值会被立即传输至当前寄存器中。否则只有当更新事件发生时,此预装载值才传输至当前捕获/比较1寄存器中。当前捕获/比较寄存器参与同计数器TIMx_CNT的比较,并在OC1端口上产生输出信号。


若CC1通道配置为输入:
CCR1包含了由上一次输入捕获1事件(IC1)传输的计数器值。

 

再看代码中的配置:

初始化PWM相关的结构体:

typedef struct

  uint16_t TIM_OCMode;       //选择定时器模式,输出PWM选择PWM1/2

写捕获/比较模式寄存器(TIMx_CCMR1/2)中的OC1M。

PWM1:在向上计数时,一旦TIMx_CNTTIMx_CCR1时为无效电平(OC1REF=0),否则为有效电平(OC1REF=1)。

PWM2:在向上计数时,一旦TIMx_CNTTIMx_CCR1时为有效电平,否则为无效电平。

所以向上向下计数是什么?

向上计数:计数器从0计到自动加载值(ARR)。TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 

  uint16_t TIM_OutputState;  //比较输出使能,即使能PWM输出到端口

  uint16_t TIM_OutputNState;  /*用于TIM1 and TIM8. */

  uint16_t TIM_Pulse;         /*设置占空比,也就是设置CCR*/

库函数代码中可使用 TIM_SetComparen(TIMx,num) 来设置和修改占空比,n可为1~4,代表1~4个输出通道,num为数字

  uint16_t TIM_OCPolarity;    /*设置极性高低 */

设置比较输出的有效电平,要与计数器自动装载值、PWM模式、向上向下计数的配置相配合。举个栗子:

TIM_TimeBaseStructure.TIM_Period=899;  //计数器自动装载值

TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//PWM模式1

TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;  //PWM输出有效电平为高

TIM_OCInitStructure.TIM_Pulse=300;  //PWM输出的占空比(CCR)

则计数0-300为高,301-899为低。理论示意图可对应文章开头图片。主要就是设置这几项来获取想要的PWM波形。

  uint16_t TIM_OCNPolarity;  /*用于TIM1 and TIM8. */

  uint16_t TIM_OCIdleState;   /*用于TIM1 and TIM8. */

  uint16_t TIM_OCNIdleState;   /*用于TIM1 and TIM8. */
} TIM_OCInitTypeDef;



以上大致解释了代码中的配置的意思,那么每句配置操作了最开始提到的三个寄存器中的哪个呢?举个栗子:

使用STM32F103VET6里的定时器3通道2来输出PWM的初始化代码库函数版本:

void TIM3_PWM_Init(void)
{  
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    TIM_OCInitTypeDef  TIM_OCInitStructure;
    
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);    //定时器3时钟打开   
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE);  
   
 
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //TIM3_CH2
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
 
   

  TIM_TimeBaseStructure.TIM_Period=899; //自动重装载值(ARR)  

  TIM_TimeBaseStructure.TIM_Prescaler =0; //预分频值       

  TIM_TimeBaseStructure.TIM_ClockDivision=0; //时钟分割     

  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //向上计数

  TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure); //   

 

  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //捕获/比较模式寄存器(TIMx_CCMR1)中的OC1M为110

  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能:捕获/比较使能寄存器(TIMx_CCER)中的CC2E为1   

  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //低电平为有效电平:捕获/比较使能寄存器(TIMx_CCER)中的CC2P为1

  TIM_OC2Init(TIM3, &TIM_OCInitStructure);  //OCn中的n对应4个通道

  TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);  //OCn中的n对应4个通道
  TIM_Cmd(TIM3, ENABLE);  //

}

可使用TIM_SetCompare2(TIM3,num) 来设置和修改占空比,也可设置TIM_Pulse。

PWM的知识暂且整理到这里,供自己复习梳理之用,待有新的收获再更新。

 

参考到的文章有:原子的stm32开发指南,stm32中文参考手册和网络上的一些博文。



 

 

 

 

 

 

 

 

1

你可能感兴趣的:(STM32,STM32)