41. 呼吸灯与SPWM波

您所在的位置:网站首页 沦落人怎么不上映 41. 呼吸灯与SPWM波

41. 呼吸灯与SPWM波

2024-07-11 12:08:00| 来源: 网络整理| 查看: 265

41.5. 全彩呼吸灯及输出SPWM波实验¶

全彩呼吸灯例程和输出SPWM波实验的工程基本一样,只是控制使用的的PWM表不同,一个为呼吸特性曲线,另一个为正弦半波曲线,下面讲解主要以全彩呼吸灯实验为例子。这两个工程的核心驱动代码分别位于bsp_breathing.c和bsp_spwm.h文件中,可根据应用需要移植这些文件。

这两个工程都是在单色呼吸灯例程拓展的,主要增加了对拟合曲线幅值等级的控制功能。

41.5.1. 编程要点¶

在单色呼吸灯的基础上,增加PWM输出通道,三个通道分别控制红绿蓝颜色;

编写中断服务函数,增加对拟合波形幅值的控制;

计算获取新的PWM数据表;

41.5.2. 代码分析¶

下面主要以全彩呼吸灯的例程分析,输出SPWM波例程只是宏的名称和PWM表的数据不一样。

41.5.2.1. LED灯硬件相关宏定义¶

类似地,实验中把硬件相关的部分使用宏定义到bsp_breathing.h文件中,使用不同硬件设计时, 修改该文件即可,见 代码清单:SPWM-8。

代码清单:SPWM-8 硬件相关宏定义(bsp_breathing.h文件)¶ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57/*电压幅值等级数*/ #define AMPLITUDE_CLASS 256 //控制输出波形的频率 extern __IO uint16_t period_class ; /*PWM表中的点数*/ extern uint16_t POINT_NUM; /********************定时器通道**************************/ #define BRE_TIMx TIM3 //中断相关 #define BRE_TIMx_IRQn TIM3_IRQn #define BRE_TIMx_IRQHandler TIM3_IRQHandler //时钟 #define BRE_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd #define BRE_TIM_CLK RCC_APB1Periph_TIM3 #define BRE_TIM_GPIO_CLK (RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO) //红灯的引脚需要重映射 #define BRE_GPIO_REMAP_FUN() GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); /************红灯***************/ #define BRE_RED_TIM_LED_PORT GPIOB #define BRE_RED_TIM_LED_PIN GPIO_Pin_5 #define BRE_RED_TIM_OCxInit TIM_OC2Init //通道初始化函数 #define BRE_RED_TIM_OCxPreloadConfig TIM_OC2PreloadConfig //通道比较寄存器,以TIMx->CCRx方式可访问该寄存器,设置新的比较值,控制占空比 //以宏封装后,使用这种形式:BRE_TIMx->BRE_RED_CCRx ,可访问该通道的比较寄存器 #define BRE_RED_CCRx CCR2 /************绿灯***************/ #define BRE_GREEN_TIM_LED_PORT GPIOB #define BRE_GREEN_TIM_LED_PIN GPIO_Pin_0 #define BRE_GREEN_TIM_OCxInit TIM_OC3Init //通道初始化函数 #define BRE_GREEN_TIM_OCxPreloadConfig TIM_OC3PreloadConfig //通道比较寄存器,以TIMx->CCRx方式可访问该寄存器,设置新的比较值,控制占空比 //以宏封装后,使用这种形式:BRE_TIMx->BRE_GREEN_CCRx ,可访问该通道的比较寄存器 #define BRE_GREEN_CCRx CCR3 /************蓝灯***************/ #define BRE_BLUE_TIM_LED_PORT GPIOB #define BRE_BLUE_TIM_LED_PIN GPIO_Pin_1 #define BRE_BLUE_TIM_OCxInit TIM_OC4Init //通道初始化函数 #define BRE_BLUE_TIM_OCxPreloadConfig TIM_OC4PreloadConfig //通道比较寄存器,以TIMx->CCRx方式可访问该寄存器,设置新的比较值,控制占空比 //以宏封装后,使用这种形式:BRE_TIMx->BRE_BLUE_CCRx ,可访问该通道的比较寄存器 #define BRE_BLUE_CCRx CCR4 41.5.2.2. 初始化GPIO¶

首先,初始化用于定时器输出通道的GPIO,见 代码清单:SPWM-9。

代码清单:SPWM-9 初始化GPIO(bsp_breathing.c文件)¶ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32/** * @brief 配置TIM复用输出PWM时用到的I/O * @param 无 * @retval 无 */ static void TIMx_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; /* GPIO clock enable */ RCC_APB2PeriphClockCmd(BRE_TIM_GPIO_CLK, ENABLE); /*IO设置*/ BRE_GPIO_REMAP_FUN(); /* 配置LED灯用到的引脚 */ //红 GPIO_InitStructure.GPIO_Pin = BRE_RED_TIM_LED_PIN ; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(BRE_RED_TIM_LED_PORT, &GPIO_InitStructure); //绿 GPIO_InitStructure.GPIO_Pin = BRE_GREEN_TIM_LED_PIN ; GPIO_Init(BRE_GREEN_TIM_LED_PORT, &GPIO_InitStructure); //蓝 GPIO_InitStructure.GPIO_Pin = BRE_BLUE_TIM_LED_PIN ; GPIO_Init(BRE_BLUE_TIM_LED_PORT, &GPIO_InitStructure); }

本实验对GPIO的初始化也相对单色呼吸灯实验作了修改,同时初始化三个通道。

41.5.2.3. 定义PWM表¶

在全彩呼吸灯和SPWM波工程中定义了见 代码清单:SPWM-10 中的PWM表。

代码清单:SPWM-10 工程中定义的PWM表(bsp_breathing.c和bsp_spwm.c文件)¶ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53/********全彩呼吸灯实验的指数曲线表**********/ /* LED亮度等级 PWM表,指数曲线 , 此表使用工程目录下的python脚本index_wave.py生成*/ const uint16_t indexWave[] = { 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, 17, 18, 19, 20, 22, 23, 25, 27, 29, 31, 33, 36, 38, 41, 44, 47, 51, 54, 58, 63, 67, 72, 77, 83, 89, 95, 102, 110, 117, 126, 135, 145, 156, 167, 179, 192, 206, 221, 237, 254, 272, 292, 313, 336, 361, 387, 415, 445, 477, 512, 512, 477, 445, 415, 387, 361, 336, 313, 292, 272, 254, 237, 221, 206, 192, 179, 167, 156, 145, 135, 126, 117, 110, 102, 95, 89, 83, 77, 72, 67, 63, 58, 54, 51, 47, 44, 41, 38, 36, 33, 31, 29, 27, 25, 23, 22, 20, 19, 18, 17, 15, 14, 13, 12, 12, 11, 10, 9, 9, 8, 8, 7, 7, 6, 6, 5, 5, 5, 4, 4, 4, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1 }; /*********SPWM实验的正弦曲线表*************/ /* SPWM表,正弦曲线,此表使用工程目录下的python脚本sin_wave.py生成*/ const uint16_t indexWave[] = { 0, 9, 18, 27, 36, 45, 54, 63, 72, 81, 89, 98, 107, 116, 125, 133, 142, 151, 159, 168, 176, 184, 193, 201, 209, 218, 226, 234, 242, 249, 257, 265, 273, 280, 288, 295, 302, 310, 317, 324, 331, 337, 344, 351, 357, 364, 370, 376, 382, 388, 394, 399, 405, 410, 416, 421, 426, 431, 436, 440, 445, 449, 454, 458, 462, 465, 469, 473, 476, 479, 482, 485, 488, 491, 493, 496, 498, 500, 502, 503, 505, 506, 508, 509, 510, 510, 511, 512, 512, 512, 512, 512, 512, 511, 510, 510, 509, 508, 506, 505, 503, 502, 500, 498, 496, 493, 491, 488, 485, 482, 479, 476, 473, 469, 465, 462, 458, 454, 449, 445, 440, 436, 431, 426, 421, 416, 410, 405, 399, 394, 388, 382, 376, 370, 364, 357, 351, 344, 337, 331, 324, 317, 310, 302, 295, 288, 280, 273, 265, 257, 249, 242, 234, 226, 218, 209, 201, 193, 184, 176, 168, 159, 151, 142, 133, 125, 116, 107, 98, 89, 81, 72, 63, 54, 45, 36, 27, 18, 9, 0 }; //计算PWM表有多少个元素 uint16_t POINT_NUM = sizeof(indexWave)/sizeof(indexWave[0]);

代码中列出的PWM表内元素的最大值均为512,元素个数均为128, 把两个表绘制成成曲线如图 呼吸曲线和正弦曲线。

这些PWM表均由工程目录下的python脚本生成的,见 代码清单:SPWM-11 和 代码清单:SPWM-12。

代码清单:SPWM-11 生成呼吸曲线PWM表的python脚本¶ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61#! python3 #coding=utf-8 """ Python版本:3.x 外部库:matplotlib1.5.3、numpy1.11.2 运行方式: 在命令行中输入:python index_wave.py 运行结果: 命令行中会打印计算得的各点数据, 在当前目录下会生成py_index_wave.c文件,包含上述数据, 并且会弹出描绘曲线的对话框。 """ import matplotlib.pyplot as plt import numpy as np import math #修改本变量可以更改点数,如16、32、64等 POINT_NUM = 180 #指数曲线最大为2的MAX_POWER次方 MAX_POWER = 9 # POINT_NUM 个点 x1 = np.linspace(0,MAX_POWER,POINT_NUM/2) #f = 2^(x) up =[] for i in x1: temp = round(2**i) #得到升序列 up.append( temp ) x2 = np.linspace(MAX_POWER,2*MAX_POWER,POINT_NUM/2) #f = 2^(2*MAX_POWER-x) down=[] for i in x2: temp = round(2**(MAX_POWER*2-i)) #得到降序列 down.append( temp ) line = list(x1)+list(x2) val = list(up)+list(down) print(line) print("*"*80) print(list(map(int,val))) #写入序列到文件 with open("py_index_Wave.c",'w',encoding= 'gb2312') as f: print(list(map(int,val)),file= f) #绘图 plt.plot(line,val,"-o") plt.show()

以上脚本使用的采样函数如下:

若0= POINT_NUM) { pwm_index=0; } period_cnt = 0; //重置周期计数标志 } amplitude_cnt=0; //重置幅值计数标志 } else { //每个PWM表中的每个元素有AMPLITUDE_CLASS个等级, //每增加一级多输出一次脉冲,即PWM表中的元素多使用一次 //根据RGB颜色分量值,设置各个通道是否输出当前的PWM表元素表示的亮度 //红 if (((rgb_color&0xFF0000)>>16) >= amplitude_cnt) { //根据PWM表修改定时器的比较寄存器值 BRE_TIMx->BRE_RED_CCRx = indexWave[pwm_index]; } else { //比较寄存器值为0,通道输出高电平,该通道LED灯灭 BRE_TIMx->BRE_RED_CCRx = 0; } //绿 if (((rgb_color&0x00FF00)>>8) >= amplitude_cnt) { //根据PWM表修改定时器的比较寄存器值 BRE_TIMx->BRE_GREEN_CCRx = indexWave[pwm_index]; } else { //比较寄存器值为0,通道输出高电平,该通道LED灯灭 BRE_TIMx->BRE_GREEN_CCRx = 0; } //蓝 if ((rgb_color&0x0000FF) >= amplitude_cnt) { //根据PWM表修改定时器的比较寄存器值 BRE_TIMx->BRE_BLUE_CCRx = indexWave[pwm_index]; } else { //比较寄存器值为0,通道输出高电平,该通道LED灯灭 BRE_TIMx->BRE_BLUE_CCRx = 0; } } TIM_ClearITPendingBit (BRE_TIMx, TIM_IT_Update); //必须要清除中断标志位 } }

本中断服务函数相对于单色呼吸灯例程增加了对拟合曲线电压等级的控制,它是利用计数变量amplitude_cnt、 电压分级宏AMPLITUDE_CLASS以及电压等级变量rgb_color实现的,其实现原理如下:

为便于讲解,先假设用于配置拟合波形周期长度的period_class值为1,即在控制周期长度时, 每个PWM表中的元素只使用1次(关于period_class的作用请复习前面单色呼吸灯实验中的说明)。

在这个基础上增加对电压的分级,用于控制拟合波形的输出电压,本实验中由宏AMPLITUDE_CLASS控制,其值为256,即可输出256种不同的电压等级。

该宏值在中断中会与amplitude_cnt进行比较(第25行),amplitude_cnt每次进入中断加1, 当amplitude_cnt大于AMPLITUDE_CLASS时才会进入周期配置的判断,以便使PWM表指向下一个元素,也就是说增加电压分级配置后, 遍历每个PWM表元素时,每个元素会增加256个周期。

在这256个周期内,会进入控制电压等级的处理(第42~73行),处理的过程是使用电压等级值rgb_color与amplitude_cnt进行比较, 本实验中rgb_color包含红绿蓝三个通道的电压值,各通道的取值范围是[0:255],与RGB888颜色格式一致。当通道的电压值R/G/B数据大于amplitude_cnt时, 向该通道的比较寄存器赋予PWM表中当前指向的元素值,否则赋予0值。根据定时器的配置可知,比较寄存器中的值就是该通道输出低电平的时间, 即LED灯亮的时间,所以,在256个周期时间内,各通道有R/G/B个周期会点亮LED灯当前PWM表元素表示的时间。

例如:

若红色通道值R=0,那么R值在256个周期内,均小于amplitude_cnt,通道输出高电平,红色LED灯一直灭, 此时\(\frac{T_{R\_ LED\_ ON}}{T_{\text{CLASS}}} = \frac{0}{256}\) ;

若绿色通道值G=128,那么G值在前128个周期内大于amplitude_cnt,通道输出当前PWM表元素表示时间的低电平,绿色LED灯亮128个周期, 此时\(\frac{T_{G\_ LED\_ ON}}{T_{\text{CLASS}}} = \frac{128}{256}\) ;

若蓝色通道值B=200,那么B值在前200个周期内大于amplitude_cnt,通道输出当前PWM表元素表示时间的低电平,蓝色LED灯亮200个周期, 此时\(\frac{T_{B\_ LED\_ ON}}{T_{\text{CLASS}}} = \frac{200}{256}\)。

所以,三个通道控制的LED灯点亮的时间比例即为RGB888颜色值表示的量,混合后可得到该颜色。

又由于PWM表中的元素值则表示了混合颜色的亮度,把PWM表遍历一遍,即控制混合颜色亮度呈PWM表变化,即可得到该颜色的呼吸灯效果。

当周期倍数period_class=1,电压分级数量AMPLITUDE_CLASS=5,电压等级分别为3和1时, 输出的PWM波形如图 电压等级分别为3和1时的PWM波形 所示。

推广至当period_class不等于1时,遍历PWM表中的每个元素需要进入定时器中断AMPLITUDE_CLASS*period_class次,设定时器的中断周期为T_timer, 那么输出的拟合曲线周期为T_timer *AMPLITUDE_CLASS*period_class。

41.5.2.6. 计算拟合波形的周期¶

本工程相对单色呼吸灯例程增加了电压分级AMPLITUDE_CLASS,结合前面的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表的点数即对拟合曲线的采样点数,采样点越多,能更好地还原拟合曲线,采样点太少,可能会导致失真, 见 图对呼吸特性曲线采样110个和10个点时的情况。

period_class:PWM表中每个元素的循环次数,它影响拟合曲线的周期。当period_class=1时,可以输出本配置中周期最短的拟合曲线。

AMPLITUDE_CLASS:电压分级数,它可以把输出拟合曲线的幅值分成N个等级,控制时可以选择按某个幅值等级进行输出, 可根据实际情况进行分级,如本实验中分级为与RGB888各通道一致的256等级,若只需要支持RGB555格式,那么AMPLITUDE_CLASS配置为32即可。

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

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

(5) STM32系统时钟默认频率和周期:

f_pclk = 72000000

t_pclk = 1/f_pclk

(6) 定时器update事件周期,即定时器中断周期:

t_timer = t_pclk * TIMER_TIM_Prescaler * TIMER_TIM_Period

(7) 每个PWM点的时间:

T_Point = t_timer * PERIOD_CLASS* AMPLITUDE_CLASS

(8) 最终,遍历PWM表的周期,即拟合曲线的周期:

T_PWM = T_Point * POINT_NUM

例如,本工程配置中:

PWM点数:

POINT_NUM = 180

周期倍数:

PERIOD_CLASS = 1

电压等级:

AMPLITUDE_CLASS = 256

定时器定时周期:

TIMER_TIM_Period = 1024

定时器分频:

TIMER_TIM_Prescaler = 200

代入公式,计算得T_PWM = 3.2767 秒

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

41.5.2.7. 主函数¶ 代码清单:SPWM-15 主函数¶ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39//该变量在定时器中断服务函数中使用,用于控制各通道的输出 //修改该变量的值可直接改变呼吸灯的颜色 //变量格式:RGB888 __IO uint32_t rgb_color = 0xFF00FF; #define SOFT_DELAY() Delay(0x1FFFFFF); void Delay(__IO u32 nCount); /** * @brief 主函数 * @param 无 * @retval 无 */ int main(void) { /* 初始化呼吸灯 */ TIMx_Breathing_Init(); while (1) { //可动态修改颜色,使用各种颜色的呼吸灯 rgb_color = 0xFF00FF; SOFT_DELAY(); rgb_color =0x8080ff; SOFT_DELAY(); rgb_color =0xff8000; SOFT_DELAY(); rgb_color =0xffc90e; SOFT_DELAY(); } } void Delay(__IO uint32_t nCount) //简单的延时函数 { for (; nCount != 0; nCount--); }

main函数中初始化呼吸灯使用的定时器和GPIO后,定时器开始工作,然后它会在中断服务函数中切换PWM数据,并且根据rgb_color的值控制拟合曲线的电压值, 达到控制LED灯可以各种颜色显示呼吸效果。在main函数中,可通过修改rgb_color的值可以改变呼吸灯的颜色。

对于输出SPWM波的工程,也直接使用了定时器输出的SPWM波控制RGB彩灯,因为正弦曲线和呼吸曲线变化方向类似,所以它控制RGB灯时, 看起来也有呼吸灯的效果,在实际应用中可以使用类似的方法控制SPWM波拟合正弦曲线的频率和电压, 通过定时器PWM模式初始化中的结构体成员TIM_OCInitStructure.TIM_OCPolarity可控制当定时器计数值小于CCRx_Val时为高电平还是低电平。

41.5.3. 下载验证¶

编译并下载本程序到开发板,给开发板上电复位,可看到LED灯显示呼吸效果。

41.5.4. 课后练习¶

1、修改TIMPeriod、TIM_Prescaler等配置参数,查看实验现象。



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭