🍌
今天又是新的一天,早起码字发文章。通过这些天的分享,学到了挺多东西的,也认识很多优秀的伙伴,发表文章的同时,也加深了自己对整个知识的理解,自己动手查查资料,收货了很多,这个月最后一篇文章了,希望下个月能发表更多高质量的文章,与大家共同进步!!
🍌🍌
作者简介:大家好啊,我叫DW,每天分享一些我新学到的知识,期待和大家一起进步
🍋
🍋🍋
系列专栏:STM32
🍎
🍎🍎
🍎🍎🍎
🌞小实验目标:使得LED灯由亮到暗再由暗到亮(呼吸灯)🌞
🍊如有写得不好的地方欢迎大家指正🍊
创作时间:🍊🍊🍊2022年4月29日🍊🍊🍊
1. PWM简介
脉冲宽度调制(PWM),简称脉宽调制,就是对脉冲宽度的控制。
PWM原理图
假定TIM定时器采取向上计数PWM模式,当 CNT小于CCRx 时,PWM输出逻辑1(高电平),当 CNT大于等于CCRx 时PWM输出逻辑0(低电平)。当 CNT达到 ARR 值的时候,重新归零,然后重新向上计数,一直循环。我们只需要改变 CCRx 的值,就可以改变 PWM 输出的占空比,改变 ARR 的值,就可以改变 PWM 输出的频率,这就是 PWM 输出的原理。
频率与周期关系
关系:f=1/T。(其中f为频率,T为周期)。
频率:物质在1s内完成周期性变化的次数叫做频率,常用f表示。符号为Hz。通俗来说,可以认为你一秒钟可以投篮三次,三次就是所谓的频率,故频率为3。
周期:物体作往复运动或物理量作周而复始的变化时,重复一次所经历的时间。由上图可以知道,高低电平持续的时间就是一个周期,即周期T=t1+t2,频率f=1/T。
常见的转换关系
1Mhz = 1000Khz = 1000 000hz;
1s = 1000ms = 1000 000us = 1000 000 000ns
本次实验使用的是通用定时器TIM3,我们使用没有重映像功能的PA6,PA6对应着通道一(CH1)
2. PWM配置
本次使用三个寄存器来控制 PWM 的输出。这三个寄存器分别是:
捕获/比较模式寄存器(TIMx_CCMR1/2)
捕获/比较使能寄存器(TIMx_CCER)
捕获/比较寄存器(TIMx_CCR1~4)
2.1捕获/比较模式寄存器
该寄存器总共有2 个,TIMx _CCMR1和 TIMx _CCMR2。TIMx_CCMR1 控制 CH1 和 CH2,而 TIMx_CCMR2 控制 CH3 和 CH4。该寄存器的各位描述如下图所示:
我们使用的是PWM2模式,OC1M[2:0]3位必须设置为111。PWM1和PWM2两种模式的区别就是输出电平的极性相反。
2.2 捕获/比较使能寄存器
该寄存器控制着各个输入输出通道的开关。该寄存器的各位描述如下图所示:
我们这里只用到了位0(CC1E 位),该位是输入/捕获 1 输出使能位,要想PWM从IO口输出,这个位必须设置为1,所以我们需要设置该位为1。
2.3 捕获/比较寄存器
该寄存器总共有 4 个,对应着4个输通道CH1至CH4。
在输出模式下,该寄存器的值与 CNT 的值比较,根据比较结果产生相应动作。利用这点,我们通过修改这个寄存器的值,就可以控制 PWM 的输出脉宽了。本章,我们使用的是 TIM3的通道1(CH1),所以我们需要修改 TIM3_CCR1 以实现脉宽控制LED灯的亮度。
🎵🎵 小提示
如果是通用定时器,则配置以上三个寄存器就够了,但是如果是高级定时器,则还需要配置:刹车和死区寄存器(TIMx_BDTR)
2.3 PWM配置
本次用到的寄存器已经全部说完,我们TIM3_CH1输出PWM来控制LED的亮度。配置步骤如下:
(1)开启TIM3时钟,配置PA6为复用输出。
(2)设置 TIM3 的ARR和PSC。
(3)设置TIM3_CH1的PWM模式及通道方向, 使能TIM3的CH1输出。
(4)使能 TIM3。
(5)修改 TIM3_CCR1 来控制占空比。
🎵🎵 小提示
高级定时器,我们还需要使能刹车和死区寄存器(TIM1_BDTR)的 MOE 位,以使能整个 OCx(即 PWM)输出。数的设置函数为:
TIM_CtrlPWMOutputs(TIM1,ENABLE);// MOE 主输出使能
#define CH1 GPIO_Pin_6
#define PWM_PROT GPIOA
void PWM_UserConfig(u16 Period,u16 Prescaler){
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_InitStructure;
TIM_OCInitTypeDef PWM_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
//PA1 TIM2_CH2
GPIO_InitStructure.GPIO_Pin = CH1;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
GPIO_Init(PWM_PROT,&GPIO_InitStructure);
TIM_InitStructure.TIM_Period = Period;
TIM_InitStructure.TIM_Prescaler = Prescaler;
TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//不分割
TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_InitStructure.TIM_RepetitionCounter = DISABLE;//不重复计数
TIM_TimeBaseInit(TIM3,&TIM_InitStructure);
TIM_Cmd(TIM3,ENABLE);//开启全局使能
//PWM配置
PWM_InitStructure.TIM_OCMode = TIM_OCMode_PWM2;
PWM_InitStructure.TIM_OutputState = TIM_OutputState_Enable;//输出使能
PWM_InitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//输出极性高
TIM_OC1Init(TIM3,&PWM_InitStructure);//通道几就选oc几
TIM_OC1PreloadConfig(TIM3,ENABLE);//预装在寄存器
TIM_SetCompare1(TIM3,0);//控制占空比
}
🎵🎵 小提示
PW1模式和PWM2模式区别:
假定TIM_OCPolarity_High,则起始波形为高电位。
PWM1:
当计时器值小于比较器设定值时则TIMX输出脚此时输出有效高电位。
当计时器值大于或等于比较器设定值时则TIMX输出脚此时输出低电位。
PWM2:
当计时器值小于比较器设定值时则TIMX输出脚此时输出有效低电位。
当计时器值大于或等于比较器设定值时则TIMX输出脚此时输出高电位。
2.4 主函数配置
我们设置频率为50hz(20ms),那么怎么可以实现LED的呼吸灯功能呢?我们利用标志位,然后利用占空比调制函数:
`TIM_SetCompare1(TIM3,time);`
其中time是不断变化的,至此就实现了呼吸灯的功能。
#include "sys.h"
#include "delay.h"
#include "pwm.h"
int main(void)
{
u8 flag = 0,time = 0;
delay_init();
PWM_UserConfig(200-1,7200-1);//50hz 20ms
while(1){
delay_ms(10);//去掉这个延时,速度太快,没有效果
if(flag==0)
{
time++;
}
else
{
time--;
}
if(time>=100) flag=0;
if(time<=0) flag=0;
TIM_SetCompare1(TIM3,time);
}
}
最后,我们可以看到LED由亮变暗再由暗变亮。
如何计算脉宽请:基本定时器
3.结语
今天的分享就到这里,谢谢大家的耐心阅读,如果觉得有用的话给个👍👍👍
🌜🌜🌜本章结束,我们下一章见🌜🌜🌜
参考资料:
1.STM32固件库手册、正点原子STM32不完全手册_库函数版本
2.学习视频链接
资料已上传,需要自取