使用STM32实现全彩LED呼吸灯效果
最近在学习各种各样的呼吸灯,遇到一个问题:
由于我个人在单个实现全彩灯时是通过三个灯的占空比来实现RG888颜色变化,而在实现呼吸灯时也是通过改变占空比来实现呼吸效果。
所以在实现全彩呼吸灯时就遇到一个问题,我们的占空比改变要么只能用来实现颜色改变,要么只能用来实现呼吸效果也就是亮度改变。因此在这里就卡住了,很疑惑如何既实现全彩,又能实现呼吸效果。
参考野火例程后终于发现:野火是通过改变占空比来实现改变亮度,而通过改变某一个时间周期内RGB三种颜色亮的时间来实现颜色改变效果。
单个的实现呼吸灯时,我的程序如下
//初始化程序如下
static void Tim3GpioConfig(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
//PA6
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
static void Tim3PWM_Mode(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructre;
TIM_TimeBaseInitStructre.TIM_ClockDivision= TIM_CKD_DIV1; //分频因子
TIM_TimeBaseInitStructre.TIM_CounterMode=TIM_CounterMode_Up; //计数方式
TIM_TimeBaseInitStructre.TIM_Period=500-1;//500百个点 500个亮度等级 每个等级持续5次
TIM_TimeBaseInitStructre.TIM_Prescaler=50-1; //可改变来改变呼吸灯呼吸快慢
//TIM_TimeBaseInitStructre.TIM_RepetitionCounter= //重复计数器没用
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructre);
//输出 tim3_ch1
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low;
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse=0;
//
TIM_OC1Init(TIM3, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); //预装载值
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
TIM_Cmd(TIM3, ENABLE);
}
static void Tim3NVIC_Config(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=3;
NVIC_Init(&NVIC_InitStructure);
}
void Tim3LedInit(void)
{
Tim3GpioConfig();
Tim3PWM_Mode();
Tim3NVIC_Config();
}
//中断程序如下
void TIM3_IRQHandler(void)
{
//-------------单色呼吸灯通过改变占空比来改变亮度--------------------------//
//从暗到亮共500个点 从亮到暗共500个点 所以一整个呼吸灯周期有1000个点
//由于未呼吸灯函数有关的表,这里直接每次+1来实现灯由暗——亮——暗的循环过程类似呼吸
static int i=0,j=5; //每个点持续5个周期
static uint8_t flag=0; //0表示从暗——亮的过程 1表示从亮-暗的过程
if(TIM_GetITStatus(TIM3, TIM_IT_Update)==SET)
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
TIM_SetCompare1(TIM3, i);
j--;
if(j==0)
{
if(flag==0)
{
i++; //每次+1从0~500 所以共500个灯亮度等级
}
else
i--;
if(i==500)
{
flag=1;
}
if(i==-1)
{
flag=0;
}
j=5;
}
}
}
全彩实现呼吸灯程序如下:
//初始化函数
static void Color_LED_PWM_Gpio(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
//PA6,PA7
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//PB0
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
static void Color_LED_PWM_TIM_Mode(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructre;
TIM_TimeBaseInitStructre.TIM_ClockDivision= TIM_CKD_DIV1; //分频因子
TIM_TimeBaseInitStructre.TIM_CounterMode=TIM_CounterMode_Up; //计数方式
TIM_TimeBaseInitStructre.TIM_Period=200-1; //亮度等级200个
TIM_TimeBaseInitStructre.TIM_Prescaler=10-1; //由于每个亮度需要点亮256次所以尽量小一点
//TIM_TimeBaseInitStructre.TIM_RepetitionCounter= //重复计数器
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructre);
//输出 tim3_ch1
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low;
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse=0;
//
TIM_OC1Init(TIM3, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); //预装载值
TIM_OC2Init(TIM3, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);
TIM_OC3Init(TIM3, &TIM_OCInitStructure);
TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
TIM_Cmd(TIM3, ENABLE);
}
static void ColorLED_PWM_NVIC_Config(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=3;
NVIC_Init(&NVIC_InitStructure);
}
void Color_LED_PWM_Init(void)
{
Color_LED_PWM_Gpio();
Color_LED_PWM_TIM_Mode();
ColorLED_PWM_NVIC_Config();
}
//中断函数如下
void TIM3_IRQHandler(void)
{
//----------全彩呼吸灯--通过改变亮灭时间来改变颜色 通过改变占空比改变亮度-------------//
//每个亮度显示256次 其中256次按照RGB的值来实现RGB是否点亮
static int duty=0,zhouqi=0,zhouqi_cnt=0; //zhouqi每个亮度持续的周期
static uint8_t flag=0; // 无表所以用来表示方向
static int chishu=0; //256次数
if(TIM_GetITStatus(TIM3, TIM_IT_Update)==SET)
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
chishu++;
if(chishu>256-1) //某个亮度是否显示了256次 如果没有则继续显示这个亮度 否则换一个亮度
{
zhouqi_cnt++;
if(zhouqi_cnt > zhouqi)
{
if(flag==0)
duty++;
else
duty--;
if(duty==200) //由于TIM_TimeBaseInitStructre.TIM_Period=200-1;
flag=1;
if(duty==0)
flag=0;
zhouqi=0;
}
chishu=0;
}
else //256份这个亮度有多少份红色点亮多少份蓝色点亮多少份绿色点
//亮以实现颜色变化
{
//红灯
if(((color&0xFF0000)>>16)>=chishu) //
{
TIM_SetCompare1(TIM3, duty); //点亮
}
else
{
TIM_SetCompare1(TIM3, 0); //熄灭
}
//绿灯
if(((color&0x00FF00)>>8)>=chishu)
{
TIM_SetCompare3(TIM3, duty);
}
else
{
TIM_SetCompare3(TIM3, 0);
}
//蓝灯
if(((color&0x0000FF))>=chishu)
{
TIM_SetCompare2(TIM3, duty);
}
else
{
TIM_SetCompare2(TIM3, 0);
}
}
}
}
注意:PB0就是tim3通道3且是绿色的控制引脚,另外的PA6是Tim3_CH1,用杜邦线将其与PB5连接输出的PWM波用于控制红灯,PA7是TIM3的通道2,用杜邦线将其与PB1连接,输出的PWM波用于控制蓝灯。
这里没有用python来实现呼吸的函数,只是实现了从亮到暗再到亮的一个过程,其实原理都差不多TIM_TimeBaseInitStructre.TIM_Period的值就是亮度等级最高值,可以通过TIM_SetCompare这个函数改变CRR的值,借此改变占空比,而当CRR的值=TIM_TimeBaseInitStructre.TIM_Period时,亮度就是最大的。如果严谨一点也可以来生成真正的呼吸函数
下面是野火的呼吸灯函数代码值
//在中断函数里用TIM_SetCompare函数遍历这个数组使他改变占空比即可实现对应真正的呼吸灯函数图像
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
};
/* 基本定时器配置 */
TIM_TimeBaseStructure.TIM_Period = (1024-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);
作者:长寂