完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
一、使用硬件
分享一个趣味的实验,单片机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__))) 为此,可通过以下函数设置占空比,取占空比是百分数x100,即占空比为50%,则寄存器CCRx的值为50x499/100,当占空比为100%时,CCRx的值为499,即为自动重装寄存器ARR的值。关于占空比的计算,具体可查阅芯片手册。 /******************************************************************************* * 函数名:PWM_SetDutyCycle * 功 能:设置占空比 * 参 数:Channel通道 Duty占空比 * 返回值:无 * 说 明:无 *******************************************************************************/ 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左右时间,也是比较耗时的。 代码如下: /******************************************************************************* * 函数名:RGB_ColorTraverse * 功 能:颜色遍历 * 参 数:无 * 返回值:无 * 说 明:每一种组合,延时1ms *******************************************************************************/ void RGB_ColorTraverse(void) { uint8_t i, j, k; for (i =0; i < 101; i++) { PWM_SetDutyCycle(TIM_CHANNEL_1, i);//R for (j =0; j < 101; j++) { PWM_SetDutyCycle(TIM_CHANNEL_2, j);//G for (k =0; k < 101; k++) { PWM_SetDutyCycle(TIM_CHANNEL_3, k);//B HAL_Delay(1);//延时1ms 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);//R }else { PWM_SetDutyCycle(TIM_CHANNEL_1, i);//R } 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);//G }else { PWM_SetDutyCycle(TIM_CHANNEL_2, j);//G } 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);//B }else { PWM_SetDutyCycle(TIM_CHANNEL_3, k);//B } if (k == 100) { uRGBFlag.bt.bBlueCycle = ~uRGBFlag.bt.bBlueCycle; } HAL_Delay(3); printf("%d,%d,%dn",i,j,k); HAL_IWDG_Refresh(&hiwdg); } } } } 实际效果,比较失望,可能是因为这种廉价的模块的问题,三个led之间的距离实际比较远,三种光不会很好的混合到一起,看起来没有混合色彩的效果(手机拍摄照片的效果更差): 五、总结 不要买这个LED模块。 |
|
|
|
只有小组成员才能发言,加入小组>>
imx6ull 和 lan8742 工作起来不正常, ping 老是丢包
2433 浏览 0 评论
3341 浏览 9 评论
3021 浏览 16 评论
3514 浏览 1 评论
9118 浏览 16 评论
1242浏览 3评论
635浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
627浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2373浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1936浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-1-23 04:53 , Processed in 1.186344 second(s), Total 79, Slave 60 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号