你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32F103VET6实现呼吸灯

[复制链接]
STMCU小助手 发布时间:2023-2-5 18:03
前言
在本章中,演示如何使用计算法得到的呼吸曲线 PWM 波和 SPWM 波,并使用 STM32定时器 TIM的 PWM功能输出波形控制 LED 灯,实现三色LED的呼吸效果。

一、相关知识介绍
1.呼吸灯简介
呼吸灯,就是指灯光设备的亮度随着时间由暗到亮逐渐增强,再由亮到暗逐渐衰减,
很有节奏感地一起一伏,就像是在呼吸一样,因而被广泛应用于手机、电脑等电子设备的指示灯中

要控制 LED 灯达到呼吸灯的效果,实际上就是要控制 LED 灯的亮度拟合呼吸特性曲线。前面控制全彩 LED 灯时,通过控制脉冲的占空比来调整各个通道 LED 灯的亮度,从而达到混色的效果。若控制脉冲的占空比在 3 秒的时间周期内按呼吸特性曲线变化,那么就可以实现呼吸灯的效果了。
这种使用脉冲占空比拟合不同波形的方式称为 PWM(脉冲宽度调制)控制技术—— 通过对一系列脉冲的宽度进行调制,来等效地获得所需要波形(含形状和幅值)。

PWM 控制的基本原理为:冲量相等而开头不同的窄脉冲加在具有惯性的环节上时,其效果基本相同。其中冲量指窄脉冲的面积;效果相同指环节输出响应波形基本相同。
SPWM 波形——脉冲宽度按正弦规律变化而和正弦波等效的PWM 波形。SPWM 是一种非常典型的 PWM 波形,它在数字电路控制中应用非常广泛,如果使用低通滤波器,可以由 SPWM 波得到其等效的连续正弦半波。

若把拟合的波形改成呼吸特性曲线,即可得到控制呼吸灯使用的 PWM 波形,要生成拟合的 PWM 波形,通常使用计算法和调制法:
(1) 计算法:根据拟合波形的频率、幅值和半周期脉冲数,准确计算 PWM 波各脉冲宽度和间隔,据此控制开关器件的通断,就可得到所需 PWM 波形;
(2) 调制法:拟合波形作调制信号,进行调制得到期望的 PWM 波;该方法一般采用等腰三角波为载波,其任一点水平宽度和高度成线性关系且左右对称。载波(等腰三角波)与平缓变化的调制信号波(即要拟合的波形)相交,在载波与信号波的交点控制器件通断,就得宽度正比于信号波幅值的脉冲,符合 PWM 的要求 。相对于计算法,其处理过程计算简单。


2. 硬件简介
TIM—单色呼吸灯 使用呼吸曲线 PWM 波控制 LED 灯,可实现红、绿、蓝三种
颜色的单色呼吸灯。
RGB 灯,里面由红蓝绿三个小灯构成, 使用 PWM控制时可以混合成 256 不同的颜色

3d34c8e705b4431abdc1ecafd03d459c.png

本开发板中设计的 RGB 灯控制引脚是经过仔细选择的,因为使用STM32 的定时器控制输出 PWM脉冲,然而并不是任意 GPIO都具有 STM32 定时器的输出通道功能,所以 在设计硬件时,需要根据《STM32 中文数据手册》中的说明,选择具有定时器输出通道功能的引脚来控制 RGB 灯,如图

31fbdfc901a7485ba4079f6eca01c483.png

本实训中的 RGB 灯使用阴极分别连接到了 PB5、PB0 及 PB1,它们分别是定时器
TIM3 的通道 2、3、4,其中 PB5用于定时器输出通道时,需要使用重定义功能。


二、实现呼吸灯
1.单色呼吸灯
要点
初始化 PWM 输出通道,初始化 PWM 工作模式;
计算获取 PWM数据表;
编写中断服务函数,在中断服务函数根据 PWM 数据表切换比较寄存器的值;

LED灯硬件相关宏定义
breathing.h

  1. #define RED_LIGHT
  2. #define GREEN_LIGHT
  3. #define BLUE_LIGHT

  4. /*要使用什么颜色的呼吸灯,可选RED_LIGHT、GREEN_LIGHT、BLOE_LIGHT*/
  5. #define LIGHT_COLOR_RED_LIGHT
  6. /********定时器通道*******/
  7. #if LIGHT_COLOR == RED_LIGHT
  8. /************红灯***********/
  9. #define  BRE_TIMx      TIM3

  10. #define  BRE_TIM_APBxClock_FUN            RCC_APB1PeriphClockCmd
  11. #define  BRE_TIM_CLK                                        RCC_APB1Periph_TIM3
  12. #define  BRE_TIM_GPIO_APBxClock_FUN      RCC_APB2PeriphClockCmd
  13. #define  BRE_TIM_GPIO_CLK     (RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO)
  14. //红灯的引脚需要重映射
  15. #define BRE_GPIO_REMAP_FUN()  GPIO_PinRemapConfig(GPI0_PartialRemap_TIM3,ENABLE);

  16. #define BRE_TIM_LED_PORT   GPIOB
  17. #define BRE_TIM_LED_PIN   GPIO_Pin_5

  18. #define BRE_TIM_OCxInit    TIM_0C2Init      //通道选择,1~4
  19. #define BRE_TIM_OCxPreloadconfig      TIM_OC2Preloadconfig
  20. #define BRE_CCRx    CCR2
  21. #define BRE_TIMx_IRQn  TIM3_IRQn   //中断
  22. #define BRE_TIMx_IROHandler   TIM3_IRQHandler

  23. #elif LIGHT_COLOR == GREEN_LIGHT

  24. /************绿灯***********/
  25. #define  BRE_TIMx      TIM3

  26. #define  BRE_TIM_APBxClock_FUN            RCC_APB1PeriphClockCmd
  27. #define  BRE_TIM_CLK                                        RCC_APB1Periph_TIM3
  28. #define  BRE_TIM_GPIO_APBxClock_FUN      RCC_APB2PeriphClockCmd
  29. #define  BRE_TIM_GPIO_CLK     (RCC_APB2Periph_GPIOB)
  30. //绿灯的引脚不需要重映射
  31. #define  BRE_GPIO_REMAP_FUN()

  32. #define BRE_TIM_LED_PORT   GPIOB
  33. #define BRE_TIM_LED_PIN   GPIO_Pin_0

  34. #define BRE_TIM_OCxInit    TIM_0C3Init      //通道选择,1~4
  35. #define BRE_TIM_OCxPreloadconfig      TIM_OC3Preloadconfig
  36. #define BRE_CCRx    CCR3
  37. #define BRE_TIMx_IRQn  TIM3_IRQn   //中断
  38. #define BRE_TIMx_IROHandler   TIM3_IRQHandler

  39. #elif LIGHT_COLOR == BLUE_LIGHT
  40. /************蓝灯***********/
  41. #define  BRE_TIMx      TIM3

  42. #define  BRE_TIM_APBxClock_FUN            RCC_APB1PeriphClockCmd
  43. #define  BRE_TIMCLK                                        RCC_APB1Periph_TIM3
  44. #define  BRE_TIM_GPIO_APBxClock_FUN      RCC_APB2PeriphClockCmd
  45. #define  BRE_TIM_GPIO_CLK     (RCC_APB2Periph_GPIOB)
  46. //蓝灯的引脚不需要重映射
  47. #define BRE_GPIO_REMAP_FUN()  

  48. #define BRE_TIM_LED_PORT   GPIOB
  49. #define BRE_TIM_LED_PIN   GPIO_Pin_1

  50. #define BRE_TIM_OCxInit    TIM_0C4Init      //通道选择,1~4
  51. #define BRE_TIM_OCxPreloadconfig      TIM_OC4Preloadconfig
  52. #define BRE_CCRx    CCR4
  53. #define BRE_TIMx_IRQn  TIM3_IRQn   //中断
  54. #define BRE_TIMx_IROHandler   TIM3_IRQHandler

  55. #endif

复制代码

为方便切换 LED 灯的颜色,定义了三组宏,通过修改代码中的 #define LIGHT_COLOR RED_LIGHT语句,可以切换使用红、绿、蓝三种颜色的呼吸灯。在每组宏定义中,与全彩 LED 灯类似,定义了定时器编号、定时器时钟使能库函数、引脚重映射操作、GPIO 端口和引脚号、通道对应的比较寄存器名以及中断通道和中断服务函数名。不同的是,这个定时器的比较寄存器 CCRx 在控制呼吸灯的单个周期内需要切换为 PWM 表中不同的数值,所以需要利用定时器中断。


2.初始化GPIO

初始化用于定时器输出通道的 GPIO
breathing.c 文件:
  1. static void TIMx_ _GPIO_ Config (void)
  2. {
  3.         GPIO_InitTypeDef GPIO_InitStructure;
  4.        
  5.      /* clock enable */
  6.         RCC_APB2PeriphClockCmd(BRE_TIM_GPIO_CLK, ENABLE);
  7.         BRE_TIM_GPIO_APBxClock_FUN( BRE_TIM_GPIO_CLK,ENABLE );
  8.         BRE_GPIO_REMAP_FUN();

  9.         /*配置呼吸灯用到的引脚*/
  10.         GPIO_InitStructure.GPIO_Pin = BRE_TIM_LED_PIN ;
  11.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
  12.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  13.        
  14.         GPIO_Init( BRE_TIM_LED_PORT,&GPIO_InitStructure ) ;
  15. }

复制代码

由于直接使用定时器输出通道的脉冲信号控制 LED 灯,此处把 GPIO 相关的引脚配置成了复用推挽输出模式。其中由于红灯使用的引脚需要用到第二功能,本代码使用宏 BRE_GPIO_REMAP_FUN ()进行了该引脚的功能重定义操作。


3.定义 PWM表
  1. /*******breathig.c文件*********/
  2. /*LED亮度等级PWM表,指数曲线,
  3. 此表使用工程目录下的python脚本index_wave.py生成*/

  4. uint16_t indexWave[] = {
  5. 1,1,1,1,2,2,2,2,3,3,4,4,5,5,
  6. 6,7,8,9,10,11,13,15,17,19,22,
  7. 25,28,32,36,41,47,53,61,69,79,
  8. 89,102,116,131,149,170,193,219,
  9. 250,284,323,367,417,474,539,613,
  10. 697,792,901,1024,1024,901,792,697,
  11. 613,539,474,417,367,323,284,250,
  12. 219,193,170,149,131,116,102,89,
  13. 79,69,61,53,47,41,36,32,28,25,
  14. 22,19,17,15,13,11,10,9,8,7,6,
  15. 5,5,4,4,3,3,2,2,2,2,1,1,1,1
  16. };
  17. //计算PWM表有多少个元素
  18. uint16_t POINT_NUM = sizeof (indexWave)/sizeof (indexWave[0]);
复制代码


该 PWM 表是利用本工程目录下的 python 脚本 index_wave.py 生成的

b816853e130f4c2c878df52f56b98194.png

该脚本运行后会在工程目录下生成一个包含该 PWM 表的 py_index_Wave.c文件,复制这些数据到 breathing.c 文件,即可得到本工程中的 indexWave 数组。实际上使用 C 语言也可以编写这样的脚本制作出 PWM 表,只是使用 python 脚本比较方便绘制图形而已。

该 python 脚本生成 PWM表数据的原理,实质是按照如下函数曲线进行采样:

d2d813a25474488fbc982fbd7761444a.png

python 脚本在这样的函数曲线上取 110 个点,即可得到上述代码中 PWM 表数组indexWave。
这个 PWM 表记录了呼吸特性曲线,PWM 表的数据将会被赋值到定时器的 CCRx 比较寄存器,从而控制输出占空比呈呼吸特性曲线变化的 PWM波。至于计算 PWM 表时,为什么选择采样 110 个点以及为什么表中的最大元素为 1024,需要结合下面定时器和中断服务函数中的配置来理解。


4.定时器 PWM配置


9745fb4f32164bf4911b100c3b6fc780.png

初始化了控制 RGB 灯用的定时器,被配置为向上计数,PWM 通道输出也被配置成当计数器 CNT 的值小于输出比较寄存器CCRx 的值时,PWM 通道输出低电平,点亮 LED 灯。在函数的最后还使能了定时器中断,每当定时器的一个计数周期完成时,产生中断,配合中断服务函数,即可切换 CCRx 比较寄存器的值。
代码中的 TIM_Period和 TIM_Prescaler是关键配置。其中 TIMPeriod 被配置为(1024-1),它控制定时器的定时周期,定时器的计数寄存器 CNT 从 0 开始,每个时钟会对计数器加 1,计数至 1023 时完成一次计数,产生中断,也就是说一共 1024 个计数周期,与 PWM 表元素中的最大值相同。若定时器的输出比较寄存器 CCRx 被赋值为 PWM 表中的元素,即可改变输出对应占空比的 PWM 波,控制 LED灯,如:

cdea3da7412d400bb589aafe0d302574.png

根据本工程中的 PWM 表更新 CCRx 的值,即可输出占空比呈呼吸特性曲线变化的PWM波形,达到呼吸灯的效果。最终,拟合曲线的周期由 TIMPeriod、PWM表的点数、TIM_Prescaler以及下面中断服务函数的 period_cnt比较值共同决定,本工程需要调整这些参数使得拟合曲线的周期约为 3秒,从而达到较平缓的呼吸效果。


5.定时器中断服务函数

stm32f10x_it.c 文件
  1. //控制输出波形的频率
  2. _IO uint16_t period_class = 10;
  3. /*PWM 表*/
  4. extern uint16_t  indexWave[] ;
  5. /*PWM表中的点数*/
  6. extern uint16_t  POINT_NUM ;
  7. /*******stm32f10x_ it.c文件*******/
  8. /*呼吸灯中断服务函数*/
  9. void BRE_TIMx_IRQHandler (void)
  10. {
  11.         static uint16_t pwm_index = 0;   //用于PWM查表
  12.         static uint16_t period_cnt = 0;  //用于计算周期数
  13.         //TIM_ IT_ Update
  14.         if (TIM_GetITStatus (BRE_TIMx, TIM_IT_Update) != RESET)
  15.          {
  16.         period_cnt++;
  17.         //根据PWM表修改定时器的比较寄存器值
  18.         BRE_TIMx->BRE_CCRx = indexWave [pwm_ index] ;
  19.         //每个PWM表中的每个元素使用period_ class 次
  20.         if (period_cnt > period_class)
  21.            {
  22.                         pwm_index++;  //标志PWM表指向下一个元素
  23.                         //若PWM表已到达结尾,重新指向表头
  24.                         if ( pwm_index >= POINT_NUM)
  25.                                   {
  26.                                         pwm_index=0;
  27.                                 }
  28.                         period_ cnt=0;//重置周期计数标志
  29.                 }
  30.         TIM_ClearITPendingBit (BRE_TIMx, TIM_IT_Update); //必须要清除中断标志位
  31.         }
  32. }
复制代码

在中断服务函数中,包含两个静态变量 period_cnt和 pwm_index。其中 pwm_index 比较容易理解,它用于指示当前要使用 PWM 表中的哪个元素,从而在“BRE_TIMx->BRE_CCRx = indexWave[pwm_index];‖语句中可以给 CCRx 赋予正确的数值,而且当 PWM 表中的数据都使用一遍时,pwm_index 将重新指向 PWM 表的开头,开始下一次呼吸循环。
在本工程的单次呼吸循环中,每个 PWM 表元素都会使用 10 次,代码中利用period_cnt 变量指示当前使用的次数,当 period_cnt> period_class 时(即period_cnt>10 时),pwm_index 才会指向下一个元素。每个 PWM表元素使用多次,主要是为了在 TIMPeriod、PWM 表的点数、TIM_Prescaler 都固定的情况下,通过调整每个元素的重复次数可以调整整个拟合波形的周期。如把代码中的比较值 period_class 改为 100,每个 PWM 表遍历一次的时间就变为原来配置的 10 倍,其拟合的呼吸周期也就相应地改变了。


6.计算拟合波形的周期

在本工程中,TIMPeriod、PWM 表的点数、TIM_Prescaler 以及 period_cnt 都会影响到拟合曲线的周期,而在实际应用中又有如下要求:

TIMPeriod:定时器的计数周期,它的值必须与 PWM 表中的极大值相等(应用中赋值需要减 1),而 PWM 表的极大值决定了控制的分辨率。例如极大值为 10 时,PWM 占空比只有 10 个等级,精确到 0.1,当极大值为 1000 时,PWM 占空比有1000个等级,精确到 0.001。
TIM_Prescaler:定时器时钟分频因子,它控制定时器计数器 CNT 计数加 1 所需要的时间,它的值太大会导致输出的单个 PWM 波周期过长,影响控制的动态特性。如控制 LED 灯时,该值太大会导致 LED 灯开关时间变长,闪烁明显。一般来说,该值越小越好。
PWM 表的点数:PWM 表的点数即对拟合曲线的采样点数,采样点越多,能更好地还原拟合曲线,采样点太少,可能会导致失真,
period_class:周期倍数,即 PWM 表中每个元素的循环次数,它影响拟合曲线的
周期。当 period_class=1时,可以输出本配置中周期最短的拟合曲线。
amplitude_class:幅值分级,可以把拟合曲线的幅值分成 N 个等级,控制时可以选择按某个幅值等级进行输出。本工程没有配置该参数,所以只能输出最大的等级,即amplitude_class=1。

以上各个参数虽然侧重点不同,但若修改其中的任何一个,最终都会影响到所拟合曲线的周期,所以在实际应用中,通常先设定好 TIMPeriod、TIM_Prescaler、PWM 表的点数以及幅值等级数 amplitude_class,得到适合的控制精度、动态特性拟合度以及幅值等级后,然后再调整 period_class 控制拟合曲线的周期,而且 period_class 在程序中动态修改非常方便,不需要重置定时器和 PWM表。

最终,我们把本工程配置中的拟合曲线周期计算公式概括如下:

07e0a98433b047179d33d2e684882044.png


通过公式的计算可知本工程的配置可使得输出的拟合曲线周期为 3.128 秒,是比较平缓的呼吸周期。


7.主函数
  1. int main(void)
  2. {
  3.         /*初始化呼吸灯*/
  4.         TIMx_ Breathing_ Init() ;
  5.         while (1)
  6.         {
  7.        
  8.         }

  9. }
复制代码


main 函数中直接调用了 TIMx_Breathing_Init 函数,而该函数内部又直接调用了前面讲解的 GPIO 和 PWM 配置函数:TIMx_GPIO_Config 和 TIMx_Mode_Config。初始化完成后,定时器开始工作,然后它会在中断服务函数中切换 PWM 数据,控制 LED 灯显示呼吸效果。


总结
本工程通过LED灯实现了呼吸灯效果,整体不难,使用呼吸曲线 PWM 波控制 LED 灯,可实现红、绿、蓝三种颜色的单色呼吸灯。实现全彩呼吸灯需要在单色呼吸灯的基础上,添加对 PWM 波的幅值控制,分为256 个等级,从而实现RGB888 全色彩的呼吸灯。
————————————————
版权声明:清道 夫


收藏 评论0 发布时间:2023-2-5 18:03

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版