STM32定时器应用——PWM

摘要:
STM32的定时器有三种,高级定时器,通用定时器和基本定时器。这个程序中用到了TIM2和TIM21这两个定时器,TIM2用于生成PWM调节LED的亮度,TIM21用于定时修改PWM的占空比。这次我们用到TIM2的CH1输出PWM波,所以Channel1应该选择PWMGenerationCH1。

STM32的定时器有三种,高级定时器(TIM1和TIM8),通用定时器(TIM2、TIM3、TIM4、TIM5)和基本定时器(TIM6和TIM7)。

这三者的区别是:

  • 基本定时器:基本定时器功能比较简单,主要是计时,也可以为DAC提供时钟,直接触发驱动DACSTM32定时器应用——PWM第1张
  • 通用定时器:通用定时器除了基本的定时功能外,还可以测量输入信号的脉冲长度,也就是输入捕获功能,也可以产生输出波形,即输出比较和PWM。 STM32定时器应用——PWM第2张
  • 高级定时器:通用定时器有的功能,高级定时器也有,而且高级定时器还可以输出嵌入死区的互补PWM。STM32定时器应用——PWM第3张

这几天放假,在家搜到一个NUCLEO-L010RB的开发板,并且在stm社区下载了相关的几份资料,就捣鼓了一下。

STM32定时器应用——PWM第4张

这个板子用到的MCU是STM32L010RBT6,这个板子刚开始我还不知道怎么用,不知道烧录程序时是否需要外接ST-Link,最后捣鼓着捣鼓着发现它本身自带ST-Link的功能,USB端口不仅可以给板子供电,还可以用于烧录程序。

第一个程序当然是点亮一个LED灯啦,查阅相关文档发现这个板子的PA5引脚上接了LED2,而且该引脚也是TIM2的CH1通道,那么就可以通过TIM2的CH1输出PWM波控制LED的亮度,实现呼吸灯效果。

一、首先用CubeMX工具生成代码框架:

STM32定时器应用——PWM第5张

这个MCU跟STM32的其他系列有很多的不同,比如定时器方面,这个单片机只有TIM2,TIM21和TIM22。这个程序中用到了TIM2和TIM21这两个定时器,TIM2用于生成PWM调节LED的亮度,TIM21用于定时修改PWM的占空比。

①设置时钟源,原理图上HSE上接的是8MHz的晶振,但是实物上实际并没有外接这个晶振,所以HSE没有配置。LSE上接了32.768KHz的晶振,所以LSE上就选择了Crystal/Ceramic Resonator。如图:

STM32定时器应用——PWM第6张

STM32定时器应用——PWM第7张

②定时器设置,如图:

STM32定时器应用——PWM第8张

STM32定时器应用——PWM第9张

  • 定时器的时钟源一般都选择内部时钟源。
  • 这次我们用到TIM2的CH1输出PWM波,所以Channel1应该选择PWM Generation CH1。
  • TIM2挂载在APB1上,而APB1的时钟频率为32MHz,所以TIM2的预分频器设置为32000,分频后得到1KHz,也就是1ms计数一次,计数模式选择向上,ARR设置为20。
  • PWM的模式设置为 PWM mode 1,Pulse设置为0。PWM的模式有两种,模式1:向上计数时,CNT<CCRx时输出有效电平,CNT>=CCRx时输出无效电平。向下计数时,CNT>CCRx时输出无效电平,CNT<=CCRx输出有效电平。模式2:向上计数时,CNT<CCRx时输出无效电平,CNT>=CCRx时输出有效电平。向下计数时,CNT>CCRx时输出有效电平,CNT<=CCRx输出无效电平。二者刚好是相反的。(Pulse就是CCRx的值,这里初始化为0,当然也可以设置为小于ARR大于0的其他数值)
  • CH Polarity选择为High,也就是设置有效电平为高电平。

TIM21的作用只是定时而已,所以设置比较简单,同样时钟源选择内部时钟,预分频32000,向上计数,ARR为100,因为TIM21挂载在APB2上也是32MHz,所以最终的结果是100ms产生一个中断(TIM21的全局中断需要打开)

STM32定时器应用——PWM第10张

打开TIM21的全局中断:

STM32定时器应用——PWM第11张

③时钟配置:由图可知,外部高速时钟(HSE)的外部晶振和外部低速时钟(LSE)跟整个时钟树的其他部分是断开的,所以我选择了内部高速时钟(HSI)作为系统时钟源,不过精度肯定没有外部晶振准确,因为HSI采用的是RC振荡器,容易受到温度的影响。

STM32定时器应用——PWM第12张

二、代码修改

①首先需要在main()函数里面调用两个函数:

HAL_TIM_Base_Start_IT(&htim21);//开启TIM21的中断
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1);//开启PWM的输出

②在TIM21中断的回调函数里增加功能代码:

1 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
 2{
 3     static uint8_t DutyCycle = 5;
 4     static uint8_t ToggleFlag = 0;
 5     if(htim->Instance ==TIM21)
 6{
 7         if(ToggleFlag == 0)
 8{
 9             DutyCycle += 1;
10             if(DutyCycle > 19)
11{
12                 DutyCycle = 19;
13                 ToggleFlag = 1;
14}
15}
16         else
17{
18             DutyCycle -= 1;
19             if(DutyCycle <= 1)
20{
21                 ToggleFlag = 0;
22}
23}
24         
25         TIM2->CCR1 =DutyCycle;
26}
27 }

TIM21每100ms进入一次中断,就会调用这个回调函数,这个函数里实现的功能就是修改TIM2的CCR1的值,也就是修改PWM的占空比,CCR1每次比上一次的数值增加1(直到19(ARR的值),也就是占空比为1),当CCR1的值达到了19,又开始递减。所以LED的效果就是从暗逐渐变量又从亮逐渐变暗,就好像呼吸一样。关系到呼吸灯的效果有几个参数:

①htim2.Init.Prescaler(TIM2的预分频系数),htim2.Init.Period(TIM2 的计数周期,也就是ARR的值),预分频系数越大,得到的频率越小,CNT增加得越慢,可能造成的效果就是看到灯在闪,因为我们看到灯的亮度变化并不是真的可以从本质上改变灯的亮度,而是一个周期内灯亮的时间占了多大的比例,由于一个周期时间很短,短到人眼分辨不出亮灭的变化,就会觉得灯的亮度变化了,所以周期也不应该太长,太长的话,人眼就可以分辨出亮灭变化,就会觉得灯在闪。

②CCR1每次的增量太大的话,呼吸灯就没有一个渐变的过程,显得不自然。

③htim21.Init.Prescaler 和htim21.Init.Period这两个参数决定多久更新一次CCR1的数值,也就是决定每一个亮度可以保持多久的时间。

PS:下面是TIM2和TIM21的初始化代码:

1 void MX_TIM2_Init(void)
2 {
3   TIM_ClockConfigTypeDef sClockSourceConfig = {0};
4   TIM_MasterConfigTypeDef sMasterConfig = {0};
5   TIM_OC_InitTypeDef sConfigOC = {0};
6 
7   htim2.Instance =TIM2;
8   htim2.Init.Prescaler = 8000-1;
9   htim2.Init.CounterMode =TIM_COUNTERMODE_UP;
10   htim2.Init.Period = 50-1;
11   htim2.Init.ClockDivision =TIM_CLOCKDIVISION_DIV1;
12   htim2.Init.AutoReloadPreload =TIM_AUTORELOAD_PRELOAD_DISABLE;
13   if (HAL_TIM_Base_Init(&htim2) !=HAL_OK)
14 {
15 Error_Handler();
16 }
17   sClockSourceConfig.ClockSource =TIM_CLOCKSOURCE_INTERNAL;
18   if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) !=HAL_OK)
19 {
20 Error_Handler();
21 }
22   if (HAL_TIM_PWM_Init(&htim2) !=HAL_OK)
23 {
24 Error_Handler();
25 }
26   sMasterConfig.MasterOutputTrigger =TIM_TRGO_RESET;
27   sMasterConfig.MasterSlaveMode =TIM_MASTERSLAVEMODE_DISABLE;
28   if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) !=HAL_OK)
29 {
30 Error_Handler();
31 }
32   sConfigOC.OCMode =TIM_OCMODE_PWM1;
33   sConfigOC.Pulse = 0;
34   sConfigOC.OCPolarity =TIM_OCPOLARITY_HIGH;
35   sConfigOC.OCFastMode =TIM_OCFAST_DISABLE;
36   if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) !=HAL_OK)
37 {
38 Error_Handler();
39 }
40   HAL_TIM_MspPostInit(&htim2);
41 
42 }
1 void MX_TIM21_Init(void)
2 {
3   TIM_ClockConfigTypeDef sClockSourceConfig = {0};
4   TIM_MasterConfigTypeDef sMasterConfig = {0};
5 
6   htim21.Instance =TIM21;
7   htim21.Init.Prescaler = 32000-1;
8   htim21.Init.CounterMode =TIM_COUNTERMODE_UP;
9   htim21.Init.Period = 250-1;
10   htim21.Init.ClockDivision =TIM_CLOCKDIVISION_DIV1;
11   htim21.Init.AutoReloadPreload =TIM_AUTORELOAD_PRELOAD_DISABLE;
12   if (HAL_TIM_Base_Init(&htim21) !=HAL_OK)
13 {
14 Error_Handler();
15 }
16   sClockSourceConfig.ClockSource =TIM_CLOCKSOURCE_INTERNAL;
17   if (HAL_TIM_ConfigClockSource(&htim21, &sClockSourceConfig) !=HAL_OK)
18 {
19 Error_Handler();
20 }
21   sMasterConfig.MasterOutputTrigger =TIM_TRGO_RESET;
22   sMasterConfig.MasterSlaveMode =TIM_MASTERSLAVEMODE_DISABLE;
23   if (HAL_TIMEx_MasterConfigSynchronization(&htim21, &sMasterConfig) !=HAL_OK)
24 {
25 Error_Handler();
26 }
27 
28 }

免责声明:文章转载自《STM32定时器应用——PWM》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Spring cloud 超时及重试配置【ribbon及其它http client】arthas命令trace追踪方法链路下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

STM32---喜提点灯

一:编译第一个程序 intmain()  //主函数 { } voidSystemInit()  //在执行主函数前,会被调用。不进行实现。在启动文件中被调用 { } ; Reset handler Reset_Handler PROC EXPORT Reset_Handler...

[RTOS]--uCOS、FreeRTOS、RTThread、RTX等RTOS的对比之特点

本篇博客就来细数这几个RTOS的特点。   以下内容均来自官方网站或者官方手册Feature的Google翻译的加了我的一些调整,没有任何主观成分。 1. FreeRTOS   FreeRTOS是专为小型嵌入式系统设计的可扩展的实时内核。 亮点包括: 微小的封装形式。 免费的RTOS调度程序 免费嵌入式软件源代码。 免版税。 抢占式,协作式和混合配置...

单片机中断函数的理解感悟

随着使用单片机次数越来越多,对单片机中断处理函数的理解更加升入。下面写了曾经血的教训,供大家参考。 ---------------------------------------------------------------------------------------------------------------------------------...

「雕爷学编程」Arduino动手做(29)——DS1302时钟模块

37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里准备逐一动手试试做实验,不管成功与否,都会记录下来---小小的进步或是搞不定的问题,希望能够抛砖引玉。 【Arduino】108种传感器模块系列实验(资料+代...

[加密]非对称加密STM32实现

转自:https://blog.csdn.net/kangerdong/article/details/82432701 把所有的准备工作都做完了以后,可以将加密算法移植到我们具体的项目中去了,在STM32中在出厂前已经将RSA的公钥私钥,CA数字签名和CA公钥烧写在STM32的flash上了。 4.1 身份认证 在wifi连接上服务器上后,客户端首先发...

十天学会单片机Day1点亮数码管(数码管、外部中断、定时器中断)

1.引脚定义 P3口各引脚第二功能定义 标号 引脚 第二功能 说明 P3.0 10 RXD 串行输入口 P3.1 11 TXD 串行输出口 P3.2 12 INT0(上划线) 外部中断0 P3.3 13 INT1(上划线) 外部中断1 P3.4 14 T0 定时器/计数器0 外部输入端 P3.5 15 T1 定时器/计数器1...