分享一个趣味的实验,单片机PWM驱动全彩LED模块,快速遍历100万种颜色。
一、使用硬件
单片机为STM32F103C8T6,三色LED模块如下图(图片来源于网络)
二、STM32CubeMx配置
配置TIM3的PWM通道1、2、3,对应引脚分别为PA6、PA7、PB0,这里的计数周期根据自己的时钟频率配置,我这里配置的PWM频率为2KHz,计算方法为,时钟频率48MHz,48分频即图中PSC的值为48-1=47为1MHz,计数周期即图中Counter Period(自动重装寄存器ARR的值)为500-1=499,则T=500/1M=500us,即频率为2000Hz.
三、PWM驱动
定时器初始化的代码不再表述,我们需要一个设置PWM占空比的函数,HAL库中,该函数为__HAL_TIM_SetCompare,对应在 stm32f1xx_hal_tim.h文件中宏定义
#define __HAL_TIM_SET_COMPARE(__HANDLE__, __CHANNEL__, __COMPARE__) \
(((__CHANNEL__) == TIM_CHANNEL_1) ? ((__HANDLE__)->Instance->CCR1 = (__COMPARE__)) :\
((__CHANNEL__) == TIM_CHANNEL_2) ? ((__HANDLE__)->Instance->CCR2 = (__COMPARE__)) :\
((__CHANNEL__) == TIM_CHANNEL_3) ? ((__HANDLE__)->Instance->CCR3 = (__COMPARE__)) :\
((__HANDLE__)->Instance->CCR4 = (__COMPARE__)))
为此,可通过以下函数设置占空比,取占空比是百分数100,即占空比为50%,则寄存器CCRx的值为50499/100,当占空比为100%时,CCRx的值为499,即为自动重装寄存器ARR的值。关于占空比的计算,具体可查阅芯片手册。
void PWM_SetDutyCycle(uint32_t Channel, uint16_t Duty)
{
uint16_t u16CCR = 0;
u16CCR = Duty * 499 / 100;
__HAL_TIM_SetCompare(&htim3, Channel, u16CCR);
}
调用该函数,对三个通道分别设置占空比为25%、50%、75:
PWM_SetDutyCycle(TIM_CHANNEL_1, 25);
PWM_SetDutyCycle(TIM_CHANNEL_2, 50);
PWM_SetDutyCycle(TIM_CHANNEL_3, 75);
用逻辑分析仪采集三个引脚的输出如下图 上图可看出周期为500us,即频率为2kHz; 上图显示占空比为50%的高电平时间间隔为250us。其他两个占空比的时间不再测量、展示。
四、遍历颜色
三色LED模块由三种颜色红色R、绿色G、蓝色B的led组成,通过三种不同比例的颜色混合,可实现全彩显示。RGB三基色可把三种颜色从0~255划分为256种强度,从而混合组成共16777216种颜色,但如果遍历这么多种颜色显然太耗时,而且意义不大,我们只根据占空比0到100的组合,实现约103万种颜色的组合,如果每种组合延时1ms,103万种也需要17min左右时间,也是比较耗时的。 代码如下:
void RGB_ColorTraverse(void)
{
uint8_t i, j, k;
for (i =0; i < 101; i++)
{
PWM_SetDutyCycle(TIM_CHANNEL_1, i);
for (j =0; j < 101; j++)
{
PWM_SetDutyCycle(TIM_CHANNEL_2, j);
for (k =0; k < 101; k++)
{
PWM_SetDutyCycle(TIM_CHANNEL_3, k);
HAL_Delay(1);
HAL_IWDG_Refresh(&hiwdg);
}
}
}
}
这里采用三级for循环嵌套实现颜色遍历,HAL库延时函数延时,因为程序会一直在for循环里,所以要喂狗。 实验过程中发现,最内层for循环的颜色变化很快且闪烁太明显,应该是因为占空比从0变到100,又会突然变为0,再增大到100,如此循环;考虑改进,使占空比变到100后,再逐渐减小到0,再增大,如此循环。所以为每层for循环增加标志位,每次for循环结束则标志位取反一次,占空比根据标志位的值而确定是取循环变量的值还是(100-循环变量),代码如下:
void RGB_ColorTraverse(void)
{
uint8_t i, j, k;
RGBFlag_tu uRGBFlag;
uRGBFlag.byte = 0;
for (i =0; i < 101; i++)
{
if (uRGBFlag.bt.bRedCycle)
{
PWM_SetDutyCycle(TIM_CHANNEL_1, 100 - i);
}else
{
PWM_SetDutyCycle(TIM_CHANNEL_1, i);
}
if (i == 100)
{
uRGBFlag.bt.bRedCycle = ~uRGBFlag.bt.bRedCycle;
}
for (j =0; j < 101; j++)
{
if (uRGBFlag.bt.bGreenCycle)
{
PWM_SetDutyCycle(TIM_CHANNEL_2, 100 - j);
}else
{
PWM_SetDutyCycle(TIM_CHANNEL_2, j);
}
if (j == 100)
{
uRGBFlag.bt.bGreenCycle = ~uRGBFlag.bt.bGreenCycle;
}
for (k =0; k < 101; k++)
{
if (uRGBFlag.bt.bBlueCycle)
{
PWM_SetDutyCycle(TIM_CHANNEL_3, 100 - k);
}else
{
PWM_SetDutyCycle(TIM_CHANNEL_3, k);
}
if (k == 100)
{
uRGBFlag.bt.bBlueCycle = ~uRGBFlag.bt.bBlueCycle;
}
HAL_Delay(3);
printf("%d,%d,%d\n",i,j,k);
HAL_IWDG_Refresh(&hiwdg);
}
}
}
}
实际效果,比较失望,可能是因为这种廉价的模块的问题,三个led之间的距离实际比较远,三种光不会很好的混合到一起,看起来没有混合色彩的效果(手机拍摄照片的效果更差):
五、总结
不要买这个LED模块。
|