40.1 呼吸灯简介

呼吸灯,就是指灯光设备的亮度随着时间由暗到亮逐渐增强,再由亮到暗逐渐衰减,很有节奏感地一起一伏,就像是在呼吸一样。

40.2 呼吸灯与 PWM 控制原理

呼吸的特性是一种类似图指数曲线 中的指数曲线过程,吸气是指数上升过程,呼气是指数下降过程,成年人吸气呼气整个过程持续约 3 秒。

实现过程

要控制 LED 灯达到呼吸灯的效果,实际上就是要控制 LED 灯的亮度拟合呼吸特性曲线。前面控制全彩 LED 灯时,通过控制脉冲的占空比来调整各个通道 LED 灯的亮度,从而达到混色的效果。若控制脉冲的占空比在 3 秒的时间周期内按呼吸特性曲线变化,那么就可以实现呼吸灯的效果

运用原理

使用脉冲占空比拟合不同波形的方式称为 PWM(脉冲宽度调制) 控制技术——通过对一系列脉冲的宽度进行调制,来等效地获得所需要波形(含形状和幅值)。

PWM 控制的基本原理为:冲量相等而开头不同的窄脉冲加在具有惯性的环节上时,其效果基本相同。其中冲量指窄脉冲的面积;效果相同指环节输出响应波形基本相同。

PWM等效正弦波

• 把正弦半波 N 等分,可看成 N 个彼此相连的脉冲序列,宽度相等,但幅值不等;

• 用矩形脉冲代替,各个矩形脉冲等幅,不等宽,中点重合,脉冲宽度按正弦规律变化,脉冲的总面积(冲量)与正弦半波相等。

这种脉冲波形被称为 SPWM 波形——脉冲宽度按正弦规律变化而和正弦波等效的 PWM 波形。

若把拟合的波形改成呼吸特性曲线,即可得到控制呼吸灯使用的 PWM 波形,要生成拟合的 PWM波形,通常使用计算法调制法

(1) 计算法:根据拟合波形的频率、幅值和半周期脉冲数,准确计算 PWM 波各脉冲宽度和间隔,据此控制开关器件的通断,就可得到所需 PWM 波形;

(2) 调制法:拟合波形作调制信号,进行调制得到期望的 PWM 波;该方法一般采用等腰三角波为载波,其任一点水平宽度和高度成线性关系且左右对称。载波 (等腰三角波) 与平缓变化的调制信号波 (即要拟合的波形) 相交,在载波与信号波的交点控制器件通断,就得宽度正比于信号波幅值的脉冲,符合 PWM 的要求,见图调制法得到 PWM 波 。相对于计算法,其处理过程计算简单。

使用计算法得到的呼吸曲线 PWM 波和 SPWM 波,并使用 STM32定时器 TIM 的 PWM 功能输出波形控制 LED 灯,达到呼吸灯的效果。

40.3 硬件设计

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

40.4 单色呼吸灯实验

4.1 编程要点

  1. 初始化 PWM 输出通道,初始化 PWM 工作模式;
  2. 计算获取 PWM 数据表;
  3. 编写中断服务函数,在中断服务函数根据 PWM 数据表切换比较寄存器的值;

4.2 代码分析

4.2.1 LED 灯硬件相关宏定义
4.2.2 初始化 GPIO
4.2.3 定义 PWM 表
4.2.4 定时器 PWM 配置
4.2.5 定时器中断服务函数
4.2.6 计算拟合波形的周期

• 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:幅值分级,在后面全彩呼吸灯和 SPWM 实验中,我们还会增加该变量,它可以把拟合曲线的幅值分成 N 个等级,控制时可以选择按某个幅值等级进行输出。本实验中没有配置该参数,所以只能输出最大的等级,即 amplitude_class=1。以上各个参数虽然侧重点不同,但若修改其中的任何一个,最终都会影响到所拟合曲线的周期,所以在实际应用中,通常先设定好 TIMPeriod、TIM_Prescaler、PWM 表的点数以及幅值等级数amplitude_class,得到适合的控制精度、动态特性拟合度以及幅值等级后,然后再调period_class控制拟合曲线的周期,而且 period_class 在程序中动态修改非常方便,不需要重置定时器和PWM表。

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

(1) STM32 系统时钟默认频率和周期:f_pclk = 72000000 t_pclk = 1/f_pclk

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

t_timer = t_pclk * TIMER_TIM_Prescaler * TIMER_TIM_Period

(3) 每个 PWM 点的时间:T_Point = t_timer * PERIOD_CLASS

(4) 最终,遍历 PWM 表的周期,即拟合曲线的周期:T_PWM = T_Point * POINT_NUM

例如,本工程配置中:

PWM 点数:POINT_NUM = 110

周期倍数:PERIOD_CLASS = 10

定时器定时周期:TIMER_TIM_Period = 1024

定时器分频:TIMER_TIM_Prescaler = 200

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

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

4.2.7 主函数

main.c

#include "stm32f10x.h"
#include "./breathinglight/bsp_breathing.h"/*** @brief  主函数* @param  无* @retval 无*/
int main(void)
{           /* 初始化呼吸灯 */TIMx_Breathing_Init();while(1){}
}/*********************************************END OF FILE**********************/

breathing.h

#ifndef __PWM_BREATHING_H
#define __PWM_BREATHING_H#include "stm32f10x.h"/*PWM表中的点数*/
extern uint16_t  POINT_NUM  ;
//控制输出波形的频率
extern __IO uint16_t period_class ;#define RED_LIGHT        1
#define GREEN_LIGHT     2
#define BLUE_LIGHT      3/*要使用什么颜色的呼吸灯,可选RED_LIGHT、GREEN_LIGHT、BLUE_LIGHT*/
#define LIGHT_COLOR     RED_LIGHT/********************定时器通道**************************/
#if  LIGHT_COLOR == RED_LIGHT
/************红灯***************/#define   BRE_TIMx                      TIM3#define   BRE_TIM_APBxClock_FUN        RCC_APB1PeriphClockCmd#define   BRE_TIM_CLK                   RCC_APB1Periph_TIM3#define   BRE_TIM_GPIO_APBxClock_FUN   RCC_APB2PeriphClockCmd#define   BRE_TIM_GPIO_CLK              (RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO)//红灯的引脚需要重映射#define   BRE_GPIO_REMAP_FUN()                        GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);                #define  BRE_TIM_LED_PORT               GPIOB#define  BRE_TIM_LED_PIN                GPIO_Pin_5#define  BRE_TIM_OCxInit                TIM_OC2Init            //通道选择,1~4#define  BRE_TIM_OCxPreloadConfig       TIM_OC2PreloadConfig #define  BRE_CCRx                       CCR2#define   BRE_TIMx_IRQn                TIM3_IRQn              //中断#define   BRE_TIMx_IRQHandler          TIM3_IRQHandler#elif LIGHT_COLOR == GREEN_LIGHT
/************绿灯***************/#define   BRE_TIMx                      TIM3#define   BRE_TIM_APBxClock_FUN        RCC_APB1PeriphClockCmd#define   BRE_TIM_CLK                   RCC_APB1Periph_TIM3#define   BRE_TIM_GPIO_APBxClock_FUN   RCC_APB2PeriphClockCmd#define   BRE_TIM_GPIO_CLK              (RCC_APB2Periph_GPIOB)//绿灯不需要重映射#define   BRE_GPIO_REMAP_FUN()              #define  BRE_TIM_LED_PORT               GPIOB#define  BRE_TIM_LED_PIN                GPIO_Pin_0#define  BRE_TIM_OCxInit                TIM_OC3Init            //通道选择,1~4#define  BRE_TIM_OCxPreloadConfig       TIM_OC3PreloadConfig #define  BRE_CCRx                       CCR3#define   BRE_TIMx_IRQn                TIM3_IRQn              //中断#define   BRE_TIMx_IRQHandler          TIM3_IRQHandler#elif LIGHT_COLOR == BLUE_LIGHT
/************蓝灯***************/#define   BRE_TIMx                      TIM3#define   BRE_TIM_APBxClock_FUN        RCC_APB1PeriphClockCmd#define   BRE_TIM_CLK                   RCC_APB1Periph_TIM3#define   BRE_TIM_GPIO_APBxClock_FUN   RCC_APB2PeriphClockCmd#define   BRE_TIM_GPIO_CLK              (RCC_APB2Periph_GPIOB)//蓝灯不需要重映射#define   BRE_GPIO_REMAP_FUN()  #define   BRE_TIM_LED_PORT             GPIOB#define   BRE_TIM_LED_PIN              GPIO_Pin_1#define   BRE_TIM_OCxInit              TIM_OC4Init            //通道选择,1~4#define   BRE_TIM_OCxPreloadConfig    TIM_OC4PreloadConfig #define   BRE_CCRx                      CCR4#define   BRE_TIMx_IRQn                TIM3_IRQn              //中断#define   BRE_TIMx_IRQHandler          TIM3_IRQHandler#endifvoid      TIMx_Breathing_Init          (void);#endif /* __PWM_BREATHING_H */

breathing.c

#include "./breathinglight/bsp_breathing.h"//控制输出波形的频率
__IO uint16_t period_class = 10;/* LED亮度等级 PWM表,指数曲线 ,此表使用工程目录下的python脚本index_wave.py生成*/
uint16_t indexWave[] = {1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 4,
4, 5, 5, 6, 7, 8, 9, 10, 11, 13,
15, 17, 19, 22, 25, 28, 32, 36,
41, 47, 53, 61, 69, 79, 89, 102,
116, 131, 149, 170, 193, 219, 250,
284, 323, 367, 417, 474, 539, 613,
697, 792, 901, 1024, 1024, 901, 792,
697, 613, 539, 474, 417, 367, 323,
284, 250, 219, 193, 170, 149, 131,
116, 102, 89, 79, 69, 61, 53, 47, 41,
36, 32, 28, 25, 22, 19, 17, 15, 13,
11, 10, 9, 8, 7, 6, 5, 5, 4, 4, 3, 3,
2, 2, 2, 2, 1, 1, 1, 1};//计算PWM表有多少个元素
uint16_t POINT_NUM = sizeof(indexWave)/sizeof(indexWave[0]); /*** @brief  配置TIM复用输出PWM时用到的I/O* @param  无* @retval 无*/
static void TIMx_GPIO_Config(void)
{GPIO_InitTypeDef GPIO_InitStructure;/*  clock enable */RCC_APB2PeriphClockCmd(BRE_TIM_GPIO_CLK, ENABLE); BRE_TIM_GPIO_APBxClock_FUN  ( BRE_TIM_GPIO_CLK, ENABLE );BRE_GPIO_REMAP_FUN();  /* 配置呼吸灯用到的引脚 */GPIO_InitStructure.GPIO_Pin =  BRE_TIM_LED_PIN ;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init( BRE_TIM_LED_PORT, &GPIO_InitStructure );
}/*** @brief  配置嵌套向量中断控制器NVIC* @param  无* @retval 无*/
static void NVIC_Config_PWM(void)
{NVIC_InitTypeDef NVIC_InitStructure;/* Configure one bit for preemption priority */NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);/* 配置TIM3_IRQ中断为中断源 */NVIC_InitStructure.NVIC_IRQChannel = BRE_TIMx_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);
}/*** @brief  配置TIM输出的PWM信号的模式,如周期、极性* @param  无* @retval 无*/static void TIMx_Mode_Config(void)
{TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;TIM_OCInitTypeDef  TIM_OCInitStructure;                                                                             /* 设置TIM3CLK 时钟 */BRE_TIM_APBxClock_FUN ( BRE_TIM_CLK, ENABLE ); /* 基本定时器配置 ,配合PWM表点数、中断服务函数中的period_cnt循环次数设置*/    /* 设置使得整个呼吸过程为3秒左右即可达到很好的效果 */  //要求://TIM_Period:与PWM表中数值范围一致//TIM_Prescaler:越小越好,可减轻闪烁现象//PERIOD_CLASS:中断服务函数中控制单个点循环的次数,调整它可控制拟合曲线的周期//POINT_NUM:PWM表的元素,它是PWM拟合曲线的采样点数/*************本实验中的配置***************/ /***********************************************#python计算脚本 count.py#PWM点数POINT_NUM = 110#周期倍数PERIOD_CLASS = 10#定时器定时周期TIMER_TIM_Period = 2**10#定时器分频TIMER_TIM_Prescaler = 200#STM32系统时钟频率和周期f_pclk = 72000000t_pclk = 1/f_pclk#定时器update事件周期t_timer = t_pclk*TIMER_TIM_Prescaler*TIMER_TIM_Period#每个PWM点的时间T_Point = t_timer * PERIOD_CLASS#整个呼吸周期T_Up_Down_Cycle = T_Point * POINT_NUMprint ("呼吸周期:",T_Up_Down_Cycle)#运行结果:呼吸周期:3.12888************************************************************//* 基本定时器配置 */       TIM_TimeBaseStructure.TIM_Period = (1024-1);;                                  //当定时器从0计数到 TIM_Period+1 ,为一个定时周期TIM_TimeBaseStructure.TIM_Prescaler = (200-1);                                  //设置预分频TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1 ;            //设置时钟分频系数:不分频(这里用不到)TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;    //向上计数模式TIM_TimeBaseInit(BRE_TIMx, &TIM_TimeBaseStructure);/* PWM模式配置 */TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;                      //配置为PWM模式1TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;   //使能输出TIM_OCInitStructure.TIM_Pulse = 0;                                                   //设置初始PWM脉冲宽度为0 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;     //当定时器计数值小于CCR1_Val时为低电平BRE_TIM_OCxInit ( BRE_TIMx, &TIM_OCInitStructure );                                       //使能通道BRE_TIM_OCxPreloadConfig ( BRE_TIMx, TIM_OCPreload_Enable );                      //使能预装载 TIM_ARRPreloadConfig(BRE_TIMx, ENABLE);                                                 //使能TIM重载寄存器ARR/* TIM3 enable counter */TIM_Cmd(BRE_TIMx, ENABLE);                                                          //使能定时器 TIM_ITConfig(BRE_TIMx, TIM_IT_Update, ENABLE);                                      //使能update中断NVIC_Config_PWM();                                                                                  //配置中断优先级       }/*** @brief  TIM 呼吸灯初始化*         配置PWM模式和GPIO* @param  无* @retval 无*/
void TIMx_Breathing_Init(void)
{TIMx_GPIO_Config();TIMx_Mode_Config();
}/*********************************************END OF FILE**********************/

其他配置:

40.5 呼吸灯及输出 SPWM 波实验

呼吸灯例程和输出 SPWM 波实验的工程基本一样,只是控制使用的的 PWM 表不同,一个为呼吸特性曲线,另一个为正弦半波曲线。

5.1 编程要点

  1. 在单色呼吸灯的基础上,增加 PWM 输出通道,三个通道分别控制红绿蓝颜色;
  2. 编写中断服务函数,增加对拟合波形幅值的控制;
  3. 计算获取新的 PWM 数据表;

5.2 代码分析

5.2.1 LED 灯硬件相关宏定义
5.2.2 初始化 GPIO
5.2.3 定义 PWM 表
5.2.4 定时器 PWM 配置
5.2.5 定时器中断服务函数
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,得到适合的控制精度、动态特性拟合度以及幅值等级后,然后再调整 pe-riod_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 秒,是比较平缓的呼吸周期。

5.2.7 主函数

main.c

#include "stm32f10x.h"
#include "./spwm/bsp_spwm.h"//该变量在定时器中断服务函数中使用,用于控制各通道的输出
//修改该变量的值可直接改变呼吸灯的颜色
//变量格式: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--);
}
/*********************************************END OF FILE**********************/

spwn.h

#ifndef __SPWM_H
#define __SPWM_H#include "stm32f10x.h"/*电压幅值等级数*/
#define AMPLITUDE_CLASS 256//控制输出波形的频率
extern __IO uint16_t period_class ;/*PWM表中的点数*/
extern uint16_t POINT_NUM;
/********************定时器通道**************************/#define   BRE_TIMx                      TIM3#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#define   BRE_TIMx_IRQn                TIM3_IRQn              //中断
#define   BRE_TIMx_IRQHandler          TIM3_IRQHandlervoid      TIMx_Breathing_Init          (void);#endif /* __SPWM_H */

spwm.c

#include "./spwm/bsp_spwm.h"//控制输出波形的频率
__IO uint16_t period_class = 1;/* 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]); /*** @brief  配置TIM3复用输出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);}/*** @brief  配置嵌套向量中断控制器NVIC* @param  无* @retval 无*/
static void NVIC_Config_PWM(void)
{NVIC_InitTypeDef NVIC_InitStructure;/* Configure one bit for preemption priority */NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);/* 配置TIM3_IRQ中断为中断源 */NVIC_InitStructure.NVIC_IRQChannel = BRE_TIMx_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);
}/*** @brief  配置TIM3输出的PWM信号的模式,如周期、极性* @param  无* @retval 无*/static void TIMx_Mode_Config(void)
{TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;TIM_OCInitTypeDef  TIM_OCInitStructure;                                                                             /* 设置TIMCLK 时钟 */BRE_TIM_APBxClock_FUN ( BRE_TIM_CLK, ENABLE ); /* 基本定时器配置 ,配合PWM表点数、中断服务函数中的PERIOD_CLASS、AMPLITUDE_CLASS循环次数设置*/   /* 设置使得整个呼吸过程为3秒左右即可达到很好的效果 */  //要求://TIM_Period:与PWM表中数值范围一致//TIM_Prescaler:越小越好,可减轻闪烁现象//PERIOD_CLASS:中断服务函数中控制单个点循环的次数,调整它可控制拟合曲线的周期//AMPLITUDE_CLASS:中断服务函数中控制单个点循环的次数,调整它可控制幅值,//                      在本实验中它为LED通道的亮度值,分256个等级,对应RGB888格式各通道的颜色等级//POINT_NUM:PWM表的元素,它是PWM拟合曲线的采样点数/*************本实验中的配置***************/  /***********************************************#python计算脚本 count.py#PWM点数POINT_NUM = 180#幅值(颜色)等级AMPLITUDE_CLASS = 256#周期倍数PERIOD_CLASS = 1#定时器定时周期TIMER_TIM_Period = 2**9#定时器分频TIMER_TIM_Prescaler = 10#STM32系统时钟频率和周期f_pclk = 72000000t_pclk = 1/f_pclk#定时器update事件周期t_timer = t_pclk*TIMER_TIM_Prescaler*TIMER_TIM_Period#每个PWM点的时间T_Point = t_timer * RGB_CLASS#整个呼吸周期T_Up_Down_Cycle = T_Point * POINT_NUM*PERIOD_CLASSprint ("呼吸周期:",T_Up_Down_Cycle)#运行结果:呼吸周期:3.27679************************************************************/TIM_TimeBaseStructure.TIM_Period = (512-1);                                    //当定时器从0计数到 TIM_Period+1 ,为一个定时周期TIM_TimeBaseStructure.TIM_Prescaler = (10-1);                                   //设置预分频TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1 ;            //设置时钟分频系数:不分频(这里用不到)TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;    //向上计数模式TIM_TimeBaseInit(BRE_TIMx, &TIM_TimeBaseStructure);/* PWM模式配置 */TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;                      //配置为PWM模式1TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;   //使能输出TIM_OCInitStructure.TIM_Pulse = 0;                                                   //设置初始PWM脉冲宽度为0 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;     //当定时器计数值小于CCR_Val时为低电平BRE_RED_TIM_OCxInit ( BRE_TIMx, &TIM_OCInitStructure );    BRE_RED_TIM_OCxPreloadConfig ( BRE_TIMx, TIM_OCPreload_Enable );                        //使能预装载 BRE_GREEN_TIM_OCxInit ( BRE_TIMx, &TIM_OCInitStructure );   BRE_GREEN_TIM_OCxPreloadConfig ( BRE_TIMx, TIM_OCPreload_Enable );                      //使能预装载 BRE_BLUE_TIM_OCxInit ( BRE_TIMx, &TIM_OCInitStructure );    BRE_BLUE_TIM_OCxPreloadConfig ( BRE_TIMx, TIM_OCPreload_Enable );                       //使能预装载 TIM_ARRPreloadConfig(BRE_TIMx, ENABLE);                                                 //使能TIM重载寄存器ARR/* TIM3 enable counter */TIM_Cmd(BRE_TIMx, ENABLE);                                                          //使能定时器 TIM_ITConfig(BRE_TIMx, TIM_IT_Update, ENABLE);                                      //使能update中断NVIC_Config_PWM();                                                                                  //配置中断优先级       }/*** @brief  TIM3 呼吸灯初始化*         配置PWM模式和GPIO* @param  无* @retval 无*/
void TIMx_Breathing_Init(void)
{TIMx_GPIO_Config();TIMx_Mode_Config();
}/*********************************************END OF FILE**********************/

其他配置:

第 40 章 呼吸灯与 SPWM 波相关推荐

  1. 【正点原子FPGA连载】第十二章 呼吸灯实验 -摘自【正点原子】领航者ZYNQ之FPGA开发指南_V2.0

    1)实验平台:正点原子领航者ZYNQ开发板 2)平台购买地址:https://item.taobao.com/item.htm?&id=606160108761 3)全套实验源码+手册+视频下 ...

  2. 【正点原子MP157连载】 第十二章 呼吸灯实验-摘自【正点原子】【正点原子】STM32MP1嵌入式Linux驱动开发指南V1.7

    1)实验平台:正点原子STM32MP157开发板 2)购买链接:https://item.taobao.com/item.htm?&id=629270721801 3)全套实验源码+手册+视频 ...

  3. 【正点原子FPGA连载】第十二章呼吸灯实验 -摘自【正点原子】新起点之FPGA开发指南_V2.1

    1)实验平台:正点原子新起点V2开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id=609758951113 2)全套实验源码+手册+视频下载地址:ht ...

  4. PWM呼吸灯之三角波、锯齿波、正弦函数波

    脉冲宽度调制(PWM),是英文"Pulse Width Modulation" 的缩写,简称脉宽调制,是利用 微处理器(MCU)的数字输出来对模拟电路进行控制的一种非常有效的技术. ...

  5. qq自定义diy名片代码复制_「正点原子FPGA连载」第六章自定义IP核-呼吸灯实验

    1)摘自[正点原子]领航者 ZYNQ 之嵌入式开发指南 2)实验平台:正点原子领航者ZYNQ开发板 3)平台购买地址:https://item.taobao.com/item.htm?&id= ...

  6. STM8S003F3通过PWM波实现三基色呼吸灯

    前段时间使用STM8S003F3实现了一个三基色灯的各种效果,故写一篇文章作为一个记录. 1 综述 我们知道,要是的LED灯亮直接通电即可.而要改变灯的亮度,我们有两种方法:改变电流和PWM调光. 我 ...

  7. STM32学习日记3---定时器TIM3重映射PWM波呼吸灯实验

    文章目录 1. 代码 关于PWM波的输出,我们需要用到定时器的4个通道(通用定时器和高级定时器有,基本定时器没有这4个通道)里面的PWM生成.然后查看数据手册,了解定时器的重映射引脚情况.所以配置时, ...

  8. STM8S003F3通过PWM波实现三基色呼吸灯(转)

    源: STM8S003F3通过PWM波实现三基色呼吸灯 转载于:https://www.cnblogs.com/LittleTiger/p/10105311.html

  9. 通用定时器输出PWM波实现呼吸灯

    STM32F1系列含有8个定时器,分为基本定时器,通用定时器和高级定时器.基本定时器 TIM6 和 TIM7 是一个 16 位的只能向上计数的定时器,只能定时,没有外部IO.通用定时器 TIM2/3/ ...

最新文章

  1. 项目管理各管理内部重点
  2. linux cal 命令详解
  3. AND、OR运算符的组合使用
  4. Covariance and Contravariance in C#, Part One
  5. eat pray love
  6. 中文依存句法分析概述及应用
  7. iec104点号_IEC104规约详细讲解全解.ppt
  8. Jquery—JQuery对checkbox的操作(01)
  9. Node:正则验证手机号和身份证号
  10. 吴恩达机器学习笔记——线性代数知识回顾、梯度下降、多项式线性回归、正则方程
  11. win10的当前桌面壁纸保存位置
  12. 一阶线性齐次,非齐次方程的通解和解的结构定理,推导过程。
  13. 求一个数各个位数之和
  14. iOS 权限设置判断和跳转 - 最全最详细
  15. 二叉树的构造(前序+中序)---(后序 + 中序)
  16. ubuntu 安装opendr失败_安装软件失败求助
  17. rust packed_simd库学习
  18. OpenCV14:Haar特征
  19. 西邮Linux小组2019-2021面试试题二三事
  20. Revit模型转Gltf

热门文章

  1. WebGL简易教程(十一):纹理
  2. 各大数据库厂商怎样看竞争对手
  3. 空间变形网络——STN
  4. ssm电商背景下精品茶网站的设计与实现毕业设计-附源码191732
  5. 其实你也可以制作一款专属的书架app,信不信看看就知道
  6. 打地鼠java代码流程图_51单片机 普中51 打地鼠游戏 仿真 程序 流程图
  7. 自建局域网 OTA 服务器
  8. 【NOI2015】BZOJ4199品酒大会题解(SAM+树形DP)
  9. win10svn图标(绿色勾)不显示
  10. VS2005 设置DLL程序无入口点