使用STM32CubeMx驱动WS2812B实现幻彩灯

stm32cubemx驱动ws2812b实现幻彩(超详)1.创建基于stm32f03c8t6工程1.1配置时钟选择外部高速时钟源hse
在这里插入图片描述
1.2配置系统时钟树使其达到最大时钟72mhz(最大系统时钟)
在这里插入图片描述
由时钟树可以知道apb1上定时器时钟频率是72mhz,实验使用的硬件接的是pa2,用的定时器tim2_ch3, 查阅数据手册可知
tim2外设在apb1上所以tim2的定时器频率是72mhz。
在这里插入图片描述
在这里插入图片描述
3.理论分析之前写过一篇文章,文章链接在此:创客实验第一弹之驱动ws2812b彩灯;不了解的可以直接跳转,今天主要讲解如何使用stm32cubemx驱动ws2812b实现幻彩,这里做部分内容截取,完整可以跳转文章阅读。
3.1ws2812b的逻辑“1”和逻辑“0”
图片
由上图可知“0”码和“1”码都是既有高电平又有低电平不过高电平和低电平的比例不同,这点很好理解,重点是分析一下它的特点,首先直观的特点就是编码“0”的电平高电平时间短一些低电平时间长一些,这也恰好符合我们的逻辑毕竟它还是低电平多一些的,编码“1”的电平高电平时间就长一些,而低电平就短一些。
但是不管是高电平还是低电平他们占用整个时间长度是一样的,这里还有一个很长的低电平这个代表复位信号。
3.2ws2812b控制波形的精准描述如何?这里涉及到严格的数学描述了,长一点是多长?短一点是多短?这个肯定是有标准或者是约束的
图片
理论上来说,高电平时长和低电平时长加起来应该是0.4us+0.85us或者0.85us+0.4us也就是说总共要占用1.25us的时间才可以编码出来一个“0”或者“1”出来。复位是要求50us以上,显然是要比编码的0或者1占用的时间要多的。
当然既然是电路的高低电平时长就会引入误差这个在误差允许的范围内我们可以接受,这个范围就是上下不超过150ns这里是ns比us还要小的时间,这个其实时间要求还是很严格的。
3.3分析结果定时器主频是72mhz 要想实现1.25us 周期的波形也就是频率是800khz波形我们可以采用分频为1分频,计数值为90来实现具体原因如下
pwm频率计算公式:fpwm =tclk / ((arr+1)*(psc+1))(单位:hz)
上面提到数据传送频率为800khz,tclk为72mhz,我们这里设置psc = 0,arr= 89,得到频率刚好为800khz,也就是计数器计数90个数,每个数计数时间是1/72us,1/72us*90 = 1.25us;
通过控制pwm占空比发送0码和1码,额定周期为1.25us,则频率为800khz
0码占空比计算(0码高电平时间)/(周期)---> 0.4us / 1.25 us = 0.32
用占空比乘以定时器重装值加一就是0码的ccr值(代表pwm高电平计数个数)--->
0.32 * (90) = 28.8(取28,网上网友实测不可以高于28,但23到28都可以,我这里选28)
1码占空比计算
同理计算:(1码高电平时间)/ (周期)---> 0.8 / 1.25 = 0.64
(占空比)*(90)= ccr ---> 0.64 * 90 = 57.6(取57左右即可这里取58)4.配置定时器的参数
在这里插入图片描述
5.ws2812b灯带的数据是什么样的呢?
图片
在说数据格式之前先来补充一下关于色彩的知识点,就是三原色,红绿蓝,也就是我们常说的rgb,r就是red,g就是green,b就是blue,一个彩色可以用这三种颜色的比例来混合出来。
每一个led的r、g、b分别由八位数据控制颜色浓度,(每种颜色浓度有0~255档,理论上rgb就可以组成256的3次方中颜色组合)即每个led需要24bit数据,那么需要发送数据的总长度则为(要控制led数量 n)*(24),每个led保存24bit将剩余位传给后面led。全部数据发送完成后要继续发送大于24us的低电平作为reset_code等才可以点亮。
既然是24bit数据代表三种颜色,我们就要首先知道一个bit的意义是什么,我们传统意义上来说1个bit代表一个数据位,但是对于数据位bit的理解好像就是“1”或者“0”在数电里我们很容易把高低电平跟逻辑1和逻辑0对应起来,但是表示灯珠的逻辑电平不是简单的高低电平。在数值上0xffffff就是24bit的1,0x000000就是24bit的0.这里有8个bit代表颜色g分量,g7g6g5g4g3g2g1g0,有8个bit代表r分量r7r6r5r4r3r2r1r0,有8个bit代表b分量b7b6b5b4b3b2b1b0,当不同分量组合时候就会有不同的数据产生,这个数据背后其实是逻辑电平,这里要说明的是彩灯的逻辑“1”并不是简简单单的高电平,彩灯的逻辑“0”也不是简简单单的低电平。而是上面分析的占空比不同的pwm波形。
4.配置定时器的dma参数这里解释下为什么要就一颗灯也要用dma,这里仅仅是拿一个灯做,其实多个灯串起来数据量还是很大的使用dma才可以充分释放其性能优势。
内存向外设传输内存递增递增dma普通模式32为字长传输
在这里插入图片描述
4.生产代码修改完善生成工程配置可参考上篇博客
stm32cubemx定时器编码器模式(超详)
4.1添加自定义ws2812b.c文件跟ws2812b.h文件
在这里插入图片描述
在这里插入图片描述
4.2修改自定义ws2812b.c文件跟ws2812b.h文件ws2812.c文件内容#include ws2812b.h#include tim.h/*some static colors------------------------------*/const rgb_color_typedef red = {255,0,0}; //显示红色rgb数据const rgb_color_typedef orange = {127,106,0};const rgb_color_typedef yellow = {127,216,0};const rgb_color_typedef green = {0,255,0};const rgb_color_typedef cyan = {0,255,255};const rgb_color_typedef blue = {0,0,255};const rgb_color_typedef purple = {238,130,238};const rgb_color_typedef black = {0,0,0};const rgb_color_typedef white = {255,255,255};const rgb_color_typedef magenta = {255,0,220};/*二维数组存放最终pwm输出数组,每一行24个数据代表一个led,最后一行24个0代表reset码*/uint32_t pixel_buf[led_num+1][24]; /*功能:设定单个rgb led的颜色,把结构体中rgb的24bit转换为0码和1码参数:ledid为led序号,color:定义的颜色结构体*/void rgb_setcolor(uint8_t ledid,rgb_color_typedef color){ uint8_t i; if(ledid > led_num)return; //avoid overflow 防止写入id大于led总数 for(i=0;i< 8;i++) pixel_buf[ledid][i] = ( (color.g & (1 < < (7 -i)))? (code_1):code_0);//数组某一行0~7转化存放g for(i=8;i< 16;i++) pixel_buf[ledid][i] = ( (color.r & (1 < < (15-i)))? (code_1):code_0);//数组某一行8~15转化存放r for(i=16;i< 24;i++) pixel_buf[ledid][i] = ( (color.b & (1 < 24us(要求大于24us)*/void reset_load(void){ uint8_t i; for(i=0;i< 24;i++) { pixel_buf[led_num][i] = 0; }}/*功能:发送数组参数:(&htim1)定时器1,(tim_channel_2)通道2,((uint32_t *)pixel_buf)待发送数组, (pixel_num+1)*24)发送个数,数组行列相乘*/void rgb_sendarray(void){ hal_tim_pwm_start_dma(&htim2, tim_channel_3, (uint32_t *)pixel_buf,(led_num+1)*24);}/*功能:显示红色参数:pixel_len为显示led个数*/void rgb_red(uint16_t pixel_len){ uint16_t i; for(i=0;i< pixel_len;i++)//给对应个数led写入红色 { rgb_setcolor(i,red); } reset_load(); rgb_sendarray();}/*功能:显示绿色参数:pixel_len为显示led个数*/void rgb_green(uint16_t pixel_len){ uint16_t i; for(i=0;i< pixel_len;i++)//给对应个数led写入绿色 { rgb_setcolor(i,green); } reset_load(); rgb_sendarray();}/*功能:显示蓝色参数:pixel_len为显示led个数*/void rgb_blue(uint16_t pixel_len){ uint16_t i; for(i=0;i< pixel_len;i++)//给对应个数led写入蓝色 { rgb_setcolor(i,blue); } reset_load(); rgb_sendarray();}/*功能:显示白色参数:pixel_len为显示led个数*/void rgb_white(uint16_t pixel_len){ uint16_t i; for(i=0;i< pixel_len;i++)//给对应个数led写入白色 { rgb_setcolor(i,white); } reset_load(); rgb_sendarray();}//用户自定义api接口可根据实际拓展/*******************************************************************************//* 添加部分 *///显示指定颜色static void rgb_show(uint32_t pixel_len, rgb_color_typedef rgb){ uint16_t i; for(i=0;i< pixel_len;i++) { rgb_setcolor(i,rgb); } reset_load(); rgb_sendarray();}//颜色循环转换static rgb_color_typedef wheel(uint8_t wheelpos){ rgb_color_typedef rgb; wheelpos = 255 - wheelpos; if (wheelpos < 85) { rgb.r = 255 - wheelpos * 3; rgb.g = 0; rgb.b = wheelpos * 3; return rgb; } if (wheelpos < 170) { wheelpos -= 85; rgb.r = 0; rgb.g = wheelpos * 3; rgb.b = 255 - wheelpos * 3; return rgb; } wheelpos -= 170; rgb.r = wheelpos * 3; rgb.g = 255 - wheelpos * 3; rgb.b = 0; return rgb;}//彩虹呼吸灯static void rainbow(uint8_t wait){ uint32_t timestamp = hal_gettick(); uint16_t i; staticuint8_t j; staticuint32_t next_time = 0; uint32_t flag = 0; if (next_time 0) flag = 1; } elseif (timestamp > next_time) { flag = 1; } if (flag) // && (timestamp - next_time < wait*5)) { j++; next_time = timestamp + wait; for (i = 0; i next_time)) // && (timestamp - next_time < wait*5)) { j++; next_time = timestamp + wait; for (i = 0; i < led_num; i++) { rgb_setcolor(i, wheel(((i * 256 / (led_num)) + j) & 255)); } } rgb_sendarray();}ws2812.h文件内容#ifndef _ws2812b_h_#define _ws2812b_h_#include main.h/*这里是上文计算所得ccr的宏定义*/#define code_1 (58) //1码定时器计数次数#define code_0 (28) //0码定时器计数次数/*建立一个定义单个led三原色值大小的结构体*/typedefstruct{ uint8_t r; uint8_t g; uint8_t b;}rgb_color_typedef;#define led_num 1 //led数量宏定义,这里我使用一个ledvoid rgb_setcolor(uint8_t ledid,rgb_color_typedef color);//给一个led装载24个颜色数据码(0码和1码)void reset_load(void); //该函数用于将数组最后24个数据变为0,代表reset_codevoid rgb_sendarray(void); //发送最终数组void rgb_red(uint16_t pixel_len); //显示红灯void rgb_green(uint16_t pixel_len);//显示绿灯void rgb_blue(uint16_t pixel_len); //显示蓝灯void rgb_white(uint16_t pixel_len);//显示白灯#endif4.3修改主函数实现测试功能/* user code begin includes */#include ws2812b.h/* user code end includes *//* infinite loop */ /* user code begin while */ while (1) { rgb_red(1); hal_delay(1000); rgb_green(1); hal_delay(1000); rgb_blue(1); hal_delay(1000); rgb_white(1); hal_delay(1000); /* user code end while */ /* user code begin 3 */ } /* user code end 3 */5.下载验证颜色好像有点色差,基本没啥问题。ok 到这如何使用stm32cubemx驱动ws2812b实现幻彩基本搞定,后面有机会再更新幻彩灯的实现部分。

4525DO-DS3AI005DP压力传感器在环境控制相关应用
大功率电子负载的四种工作模式
什么是移动处理器
Molex推出掌上型电线铆压拉力测试仪
电容器的等效串联电阻(ESR)
使用STM32CubeMx驱动WS2812B实现幻彩灯
苹果手机与安卓的区别
人工智能、物联网和5G技术的发展背后
康宁第六代“大猩猩玻璃”遭抢 OPPO拔得头筹
如何看待全栈工程师
那些从零开发的独立Linux发行版
区块链技术将如何改变数字媒体产业
荣耀V30开启预售 带来全新的5G应用和体验
机器视觉的下一个发展空间会将是嵌入式吗
室内定位应用的5大领域介绍
什么是三极管的倒置状态?三极管倒置状态的应用
基于nRF9E5的有源超高频RFID系统设计
意法半导体STM32全系产品部署Microsoft® Azure RTOS开发包
HTC专注VR、区块链等业务推出智能手机
一文了解半导体靶材应用市场形式