STM32之PWM
- 开发环境:Window 10
- 开发工具:Keil uVision5 MDK
- 硬件:STM32F103
资料参考:
【正点原子】STM32F103开发板资料(A盘);
- STM32F1开发指南(精英版)-库函数版本.pdf
- STM32固件库使用手册的中文翻译版.pdf
- STM32中文参考手册.pdf
文章目录
STM32F103ZE 简介
https://www.keil.com/dd2/stmicroelectronics/stm32f103ze/
内核:ARM Cortex-M3,72MHz
内存:64kB RAM,512kB ROM
时钟和电源:2.00V—3.60V,72 MHz
通信 :SPI、I2C、UART、I2S、CAN、USART、USB、Device
定时器/计数器/PWM :8 × 16 位定时器
模拟:2通道 12位DAC,21通道 12位ADC
I/O 和封装: -40℃—85℃,144-QFP,144-BGA
PWM简介
PWM 全称是 Pulse Width Modulation(脉冲宽度调制),即可以实现占空比可以调节的矩形脉冲,当其占空比固定为50%时便是方波。
STM32的定时器除了TIM6和7,其他的定时器都可以用来产生 PWM 输出。其中高级定时器 TIM1 和 TIM8 可以同时产生 7 路的 PWM 输出。而通用定时器也能同时产生 4路的 PWM 输出(F103系列有4个通用定时器),注意,STM32可以同时产生30路PWM输出!
PWM产生的原理
了解PWM的产生,需要理清以下几个参数之间的关系:定时器的自动重装载值ARR和计数值CNT;捕获/比较寄存器的比较值CCR;PWM模式1和模式2;有效电平
当定时器为向上计数模式时,计数值CNT从0增加到ARR,而比较值CCR是一个介于0~ARR之间的一个值。当CNT<CCR时,输出一种电平;当CNT>CCR时,输出另一种电平,而输出电平是高是低取决于PWM的模式以及有效电平。
- PWM模式1时,当CNT<CCR时,输出有效电平;当CNT>CCR时,输出无效电平;
- PWM模式2时,当CNT<CCR时,输出无效电平;当CNT>CCR时,输出有效电平;
注意:这里都是采用定时器向上计数的情况,列出向下计数情况容易混淆而且其应用较少,这边就不赘述了。
两种PWM模式与两种有效电路的组合输出如下图:(图是用PPT手绘原创的,加个水印哈)
同时,调节CCR的值可以实现占空比的改变。
PWM的使用步骤
以一个实例为基础对PWM的使用进行解析,实例要求如下:
- 用定时器TIM3的通道2在重映射的PB5引脚输出
- 占空比自变化(由小变大,再由大变小)的PWM脉冲。
(正点原子的例程-PWM输出中还包括了定时器中断控制小灯闪烁,但本篇只介绍PWM的使用,故此处不赘述定时器中断部分)
1)使能时钟,配置输出引脚
2)初始化GPIO
3)初始化定时器
4)初始化PWM模式
5)使能TIM-定时器
6)配置占空比
1)使能时钟,配置输出引脚
在使用外设前,必须要开启相应外设的时钟!
- 定时器TIM3来自于APB1时钟总线:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能定时器 3 时钟
- 重映射的PB5口以及复用IO口(AFIO)来自于APB2时钟总线:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); //使能GPIO外设和AFIO复用功能模块时钟
- 同时,对定时器TIM3通道2启用部分重映射到PB5口
注意:定时器设置了重映射,所有的通道都会启动重映射,因此开启重映射只需选择定时器,而不需要选择具体通道,重映射的对应引脚可以查看参考手册,搜索TIM3_REMAP。
void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState)
第一个参数:开启重映射的定时器
第二个参数:是否使能
范例:
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //Timer3部分重映射 TIM3_CH2->PB5
2)初始化GPIO
GPIO的配置太过普遍就不展开叙述,主要解释两个点:部分重映射和完全重映射;PB5为什么是复用推挽输出模式
部分重映射和完全重映射
- 部分重映射:功能外设的部分引脚重新映射,还有一部分引脚是原来的默认引脚。
- 完全重映射:功能外设的所有引脚都重新映射。
也就是说,不起用重映射的引脚,只具有默认连接的外设的功能;启用部分重映射的引脚,在保留原有功能的基础上新设置外设的功能;启用完全重映射的引脚,只具有新设置外设的功能。
PB5为什么是复用推挽输出模式:
- 只要开启了重映射功能,就要设置为复用模式。
- PWM是要产生数字量表示0和1的矩形脉冲,而推挽模式可以输出高(3.3V)、低电平(0V),符合需要
对PB5口的配置范例:
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //TIM_CH2
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO
3)初始化定时器
所有初始化的定义格式基本固定,第一次遇到时了解下就能懂,这里也不详细介绍
对定时器TIM3初始化的范例:
TIM_TimeBaseStructure.TIM_Period = arr; //自动重装载值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //TIMx时钟的预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割,不分割
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx
4)初始化PWM模式
PWM 通道设置是通过函数TIM_OC1Init~TIM_OC4Init()来设置的,以通道2为例:
void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct
第一个参数:待配置的定时器
第二个参数:配置PWM相关参数的结构体,下面仅列出3个常用的参数
typedef struct
{
uint16_t TIM_OCMode;
uint16_t TIM_OutputState;
uint16_t TIM_OCPolarity;
} TIM_OCInitTypeDef;
- TIM_OCMode:定时器的模式,共有6中模式,与PWM有关的有TIM_OCMode_PWM1、TIM_OCMode_PWM2两种
- TIM_OutputState:比较输出使能,也就是使能PWM 输出到端口
- TIM_OCPolarity:设置有效电平为高还是低
对TIM3 Channe2 设置PWM的范例,采用PWM模式2,有效电平为高,即输出先低后高
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
TIM_OC2Init(TIM3, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM3 OC2
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能TIM3在CCR2上的预装载寄存器
5)使能TIM-定时器
一系列的初始化配置完成后一定不要忘记开启定时器!
TIM_Cmd(TIM3, ENABLE); // 使能 TIM3
6)配置占空比
本文开篇就介绍PWM就是占空比可调的矩形脉冲,而占空比的调节需要通过TIM_SetCompare()函数来实现
void TIM_SetComparex(TIM_TypeDef* TIMx, uint16_t Compare2)
每个通道都有不同的函数名字,其函数格式是TIM_SetComparex(x=1,2,3,4)
第一个参数:待控制的定时器
第二个参数:与寄存器计数值arr进行比较的值,即控制占空比
对占空比设置的范例:
根据PWM的设定,输出先低后高,CCR的值(代码中的led0PWMval)控制的是低电平的时间,所以实现的是占空比由大变小再由小变大的过程
u16 led0pwmval++=0;
TIM3_PWM_Init(900-1,0); //TIM3的计数值为900
while(1)
{
if(dir)led0pwmval++;//占空比由大变小时,低电平时间加长
else led0pwmval--;//占空比由小变大时,低电平时间减小
if(led0pwmval>300)dir=0;//占空比最小为1-300/900 = 2/3
if(led0pwmval==0)dir=1; //这两行实现占空比变化模式的切换
TIM_SetCompare2(TIM3,led0pwmval); //将参数给到相应寄存器
}
注释:创作时尚且处于学习初期,对程序只有能用就行的要求,若理解有误或不全面之处后续仍会改进…