STM32实战③RGB渐变
1 简介本实验实现RGB灯的颜色渐变,从红慢慢过渡到绿,再慢慢过渡到蓝,再慢慢过渡到红。其原理是通过查表的方法给三个通道不同的pwm,从而改变颜色。2 硬件使用野火指南者开发板。2.1 RGBRGB灯由红蓝绿三个小灯构成,使用PWM控制是可以混合成256种不同的颜色。STM32的三个引脚需要选择具有定时器输出通道功能,而不是任意的GPIO口。本次实验使用PB5、PB0及PB1引脚,分别是定时器TI
·
1 简介
- 本实验实现RGB灯的颜色渐变,从红慢慢过渡到绿,再慢慢过渡到蓝,再慢慢过渡到红。其原理是通过查表的方法给三个通道不同的pwm,从而改变颜色。
2 硬件
使用野火指南者开发板。
2.1 RGB
- RGB灯由红蓝绿三个小灯构成,使用PWM控制是可以混合成256种不同的颜色。STM32的三个引脚需要选择具有定时器输出通道功能,而不是任意的GPIO口。本次实验使用PB5、PB0及PB1引脚,分别是定时器TIM3的通道2,3,4。
- PB5对应红色R,PB0对应绿色G,PB1对应蓝色B。
3 软件设计
- 首先我们需要知道三个通道的值对应的颜色。例如,红色为(255,0,0),绿色为(0,255,0),蓝色为(0,0,255)。知道值对应的颜色就可以对RGB进行颜色的控制。
RGB颜色表查询网站:https://tool.oschina.net/commons?type=3
3.1 GPIO初始化
//初始化PB5和PE5为输出口.并使能这两个口的时钟
//LED IO初始化
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* GPIO clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE);
/*IO设置*/
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);
/* 配置LED灯用到的引脚 */
//红
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//绿
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//蓝
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 ;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
- 由于本实验直接使用定时器输出通道的脉冲信号控制RGB灯,此处代码把GPIO相关的引脚都配置成了复用推挽输出模式。
- 由于红灯使用的引脚需要用到第二功能,本代码使用COLOR_GPIO_REMAP_FUN()进行了该引脚的功能重定义操作。
- 红灯为B5引脚,绿灯为B0引脚,蓝灯为B1引脚。
3.2 TIM3定时器初始化
void TIM3_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
TIM_TimeBaseStructure.TIM_Period = arr-1; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 计数到5000为500ms
TIM_TimeBaseStructure.TIM_Prescaler = psc-1; //设置用来作为TIMx时钟频率除数的预分频值 10Khz的计数频率
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
/* PWM模式配置 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //配置为PWM模式1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //使能输出
TIM_OCInitStructure.TIM_Pulse = 0; //设置初始PWM脉冲宽度为0
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //当定时器计数值小于CCR_Val时为低电平
//RGB通道
TIM_OC2Init ( TIM3, &TIM_OCInitStructure );
TIM_OC2PreloadConfig ( TIM3, TIM_OCPreload_Enable ); //使能预装载
TIM_OC3Init ( TIM3, &TIM_OCInitStructure );
TIM_OC3PreloadConfig ( TIM3, TIM_OCPreload_Enable ); //使能预装载
TIM_OC4Init ( TIM3, &TIM_OCInitStructure );
TIM_OC4PreloadConfig ( TIM3, TIM_OCPreload_Enable ); //使能预装载
TIM_ARRPreloadConfig(TIM3, ENABLE);
TIM_Cmd(TIM3, ENABLE); //使能TIMx外设
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
}
3.3 RGB渐变
uint16_t rgb_led_time=20;
const uint16_t R[] = {
255, 226, 198, 170, 141, 113, 85, 56, 28, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 28, 56, 85, 113, 141, 170, 198, 226, 255
};
const uint16_t G[] = {
0, 28, 56, 85, 113, 141, 170, 198, 226, 255,
255, 226, 198, 170, 141, 113, 85, 56, 28, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0,0
};
const uint16_t B[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 28, 56, 85, 113, 141, 170, 198, 226, 255,
255, 226, 198, 170, 141, 113, 85, 56, 28, 0
};
//定时器3中断服务程序
void TIM3_IRQHandler(void) //TIM3中断
{
static uint16_t pwm_index = 0; //用于PWM查表
static uint16_t amplitude_cnt = 0; //持续时间
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除TIMx的中断待处理位:TIM 中断源
amplitude_cnt++;
// 每个颜色持续的时间
if(amplitude_cnt>rgb_led_time)
{
pwm_index++; //标志PWM表指向下一个元素
//若PWM表已到达结尾,重新指向表头
if( pwm_index > (30-1))
{
pwm_index=0;
}
amplitude_cnt=0; //重置计数标志
}
else
{
TIM3->CCR2 = R[pwm_index]; // PWM
TIM3->CCR3 = G[pwm_index]; // PWM
TIM3->CCR4 = B[pwm_index]; // PWM
}
}
}
- 要实现RGB灯渐变,需要通过在不同时刻给其三个通道不同的PWM值,从而产生不同的颜色。因此,我制定了一个含有30个元素的数组,分别为R[30],G[30],B[30]。每个时刻t的RGB灯的颜色为[R[t],G[t],B[t]],从而实现了RGB颜色从红慢慢过渡到绿,再慢慢过渡到蓝,再慢慢过渡到红。
- RGB渐变由于需要控制其渐变周期,所以我将其写在TIM3定时器中断中。
- 该算法的思路:假设设置定时器的周期为 t ms,R,G,B三张表拥有30个PWM数值,其每个数值会持续rgb_led_time个t,因此RGB循环一次的周期为T=(30 * rgb_led_time * t)/1000 s。若rgb_led_time=10,t=10ms,则RGB循环一次的周期为T=3s。
3.4 主函数
int main(void)
{
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
uart_init(115200); //串口初始化为115200
LED_Init(); //LED端口初始化
TIM3_Int_Init(1000,72); //不分频。PWM频率=72000000/72=1000Khz 1us*1000=1ms
while(1)
{
}
}
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
已为社区贡献1条内容
所有评论(0)