电子工程师技术服务社区
公告
登录
|
注册
首页
技术问答
厂商活动
正点原子
板卡试用
资源库
下载
文章
社区首页
文章
一个IO控制很多个LED,这个技能你get到了吗
分 享
扫描二维码分享
一个IO控制很多个LED,这个技能你get到了吗
ws2812b
灯珠
RGB模块
嵌入式从0到1
关注
发布时间: 2021-01-25
丨
阅读: 560
### 实现目标 * 每隔一秒,点亮模块上的一个LED * 点亮模块上的所有LED ### 所需工具及环境 * Keil 5 * STM32F103RET6核心板(本平台自制专用核心板,随便找一个开发板亦可) * 8位 圆形 WS2812B LED模块 ### 本文源码 ![](https://img-blog.csdnimg.cn/20210120232057998.png) 公众号【嵌入式从0到1】后台回复关键字“**WS2812B**”,获取**WS2812B**模块资料、数据手册及工程源码。 ### 简介 电压:DC4~7V 多位(几个LED就是几位)通过引脚级联接一个到另一个的输出引脚,通过这种级联的方式,只需要使用一个IO口(单片机引脚)就能控制尽可能多的LED,每个LED都集成了一颗驱动芯片在里面,让我们的LED变得智能和寻址,每一个内部都有恒流驱动,所以LED颜色非常一致,即使电压有小幅抖动,电压变化也是一样的。 不需要外部电阻——限流电阻使LED灯的布局设计变得简单。 单线通信,能够最大限度的减少单片机IO口的压力,另外这款RGB灯使用了WS2812B驱动芯片,让外围电路**只需要一颗电容**就能够满足电路需求,从而最大可能的让电路变得简单优美。 ### 特点 1. 智能反接保护,电源反接不会损坏IC; 2. IC控制电路与LED点光源公用一个电源; 3. 控制电路与RGB芯片集成在一个5050封装的元器件中,构成一个外控像素点; 4. 内置信号整形电路,任何一个像素点收到信号后经过波形整形再输出,保证线路波形畸变不会累加; 5. 内置上电复位和掉电复位电路; 6. 每个像素点的三基色颜色可实现256级亮度显示,完成16777216种颜色的全真色彩显示,扫描频率不低于400Hz; 7. 串行级联接口,能通过一根信号线完成数据的接收与解码; 8. 任意两点传输距离在不超过5米时,无需增加额外电路; 9. 当刷新速率30帧/秒时,级联数不小于1024点; 10. 数据发送速度可达800Kbps; 11. 光的颜色高度一致,性价比高。 **注意:** 800Kbps,相当于1.25us传输一比特数据。 ### 引脚图 ![](https://img-blog.csdnimg.cn/2021012023215228.png) ![](https://img-blog.csdnimg.cn/20210120232204572.png) 引脚功能描述: | **NO.** | **Symbol** | **功能描述** | | --- | --- | --- | | 1 | VDD | LED的供电电源,Vdd 范围 +3.5~+5.3 V | | 2 | DOUT | 控制信号数据输出引脚 | | 3 | VSS | 地 | | 4 | DIN | 控制信号数据输入引脚 | ### 典型电路 #### 串联方法 ![](https://img-blog.csdnimg.cn/2021012023225229.png) #### 原理图 ![](https://img-blog.csdnimg.cn/20210120232305211.png) 除了灯珠以外只需要额外增加一个0.1uF的电容即可。 ### 硬件连接 | **STM32F103RET6核心板** | **WS2812B模块** | | :---: | :---: | | PA6 | DIN | | VCC | +5V | | GND | GND | ### 驱动原理 数据协议采用单线归零码的通讯方式,像素点在上电复位以后,DIN端接受从控制器传输过来的数据,首先送过来的24bit数据被第一个像素点提取后,送到像素点内部的数据锁存器,剩余的数据经过内部整形处理电路整形放大后通过DOUT端口开始转发输出给下一个级联的像素点,每经过一个像素点的传输,信号减少24bit。 像素点采用自动整形转发技术,使得该像素点的级联个数不受信号传送的限制,仅仅受限信号传输速度要求。 因为数据被内部锁存,所以只要不改变颜色值(模块持续供电),颜色是不会发生改变的,设置颜色的脉冲也不需要持续提供(单片机发生复位也无影响),只需要在修改颜色值的时候,发送一遍即可。 ### 0和1的区分 ![](https://img-blog.csdnimg.cn/20210120232329190.png) Treset:复位时间 ![](https://img-blog.csdnimg.cn/20210120232342373.png) 由上图可知,我们要发送 '**0**' ,需要将GPIO引脚置高并持续0.4 us(400 ns),然后GPIO置低并持续0.85 us(850 ns),此过程即完成**0 code**的发送,具体代码实现如下: ```C void send_0(void) { IN_H; Wait400ns; IN_L; Wait850ns; } ``` 我们要发送 '**1**' ,需要将GPIO引脚置高并持续0.85 us(850 ns),然后GPIO置低并持续0.4 us(400 ns),此过程即完成**1 code**的发送,具体代码实现如下: ```C void send_1(void) { IN_H; Wait850ns; IN_L; Wait400ns; } ``` 所以本程序的难点即是求取400 ns 和 850 ns 相对精确的延时时间。 ### 延时函数的实现 单片机里的延时函数一般通过执行一些无意义的循环进行延时,比如定义如下函数: ```C void delay(unsigned char i) { while(--i); } ``` 我们这里需要的延时周期很小,才1.25us,因为函数的调用,需要入栈和出栈,所以如果使用上面的延时函数的方式的话,那么一进一出就接近几百ns的时间就没了,所以为了精确控制,我们这里延时函数的定义如下: ```C #define Wait10nop {__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();} #define Wait250ns {__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();} #define Wait400ns {Wait250ns;Wait10nop;} //388 #define Wait850ns {Wait250ns;Wait10nop;Wait10nop;Wait10nop;Wait10nop;__NOP();__NOP();__NOP();__NOP();__NOP();} //860 ``` 我们在main函数中使用如下方式测试这个延时函数: ```C while(1) { IN_H; //Wait250ns; Wait850ns; IN_L; //Wait250ns; Wait850ns; } ``` 然后用示波器观察与模块DIN引脚相连的GPIO输出的脉冲信号,查看其高电平是否与咱们预定义的一致,如果不一致,增加或减少空指令进行调整。 注意一个 **__NOP();** 空指令的耗时大约:1000/72 ≈ 14 ns 的时间,自己可以在上面定义的基础上,根据需要随意增加或者减少 **__NOP();** 空指令的个数。 > 注意空指令前面是两个“**\_**”。 经过示波器测量,不断调整,上面定义的 Wait250ns 宏定义的耗时如下图所示。 ![](https://img-blog.csdnimg.cn/2021012023241395.png) 经过示波器测试,上面的 Wait400ns 耗时为 388 ns , Wait850ns 耗时为 860 ns,满足上面"0"和"1"的时间区间范围。 ### 24 bit数据的组成 ![](https://img-blog.csdnimg.cn/20210120232427563.png) **注意:** 数据传输顺序按GRB顺序传输,并且高位在前。 ```C void ws2812_rgb(u8 ws_num,u8 ws_r,u8 ws_g,u8 ws_b) { ws_data[(ws_num-1)*3]=ws_g; ws_data[(ws_num-1)*3+1]=ws_r; ws_data[(ws_num-1)*3+2]=ws_b; } ``` **ws_data[]** 数组中用于记录待传输的RGB数据,每一个灯珠的颜色占用三个字节,因为数据传输顺序按GRB的顺序传输,所以赋值的时候注意先后顺序,上面函数是设置某一个灯珠的颜色值。 **ws_data[]** 数组中颜色值设置完毕之后,就要把这个数组的数据发送到模块中,具体的实现函数如下: ```C void ws2812_refresh(u8 ws_count) { u8 ws_ri=0; for(;ws_ri
8) times = 0; switch(times) { case 0: ws2812_rgb(1, WS_RED); ws2812_rgb(2, WS_GREEN); ws2812_rgb(3, WS_BLUE); ws2812_rgb(4, WS_WHITE); ws2812_rgb(5, WS_PURPLE); ws2812_rgb(6, WS_YELLOW); ws2812_rgb(7, WS_BROWN); ws2812_rgb(8, WS_BLUE); ws2812_refresh(8); break; case 1: memset(ws_data,0,WS_ARRAY_SIZE*sizeof(u8)); ws2812_rgb(1, WS_RED); ws2812_refresh(8); break; case 2: memset(ws_data,0,WS_ARRAY_SIZE*sizeof(u8)); ws2812_rgb(2, WS_GREEN); ws2812_refresh(8); break; case 3: memset(ws_data,0,WS_ARRAY_SIZE*sizeof(u8)); ws2812_rgb(3, WS_BLUE); ws2812_refresh(8); break; case 4: memset(ws_data,0,WS_ARRAY_SIZE*sizeof(u8)); ws2812_rgb(4, WS_WHITE); ws2812_refresh(8); break; case 5: memset(ws_data,0,WS_ARRAY_SIZE*sizeof(u8)); ws2812_rgb(5, WS_PURPLE); ws2812_refresh(8); break; case 6: memset(ws_data,0,WS_ARRAY_SIZE*sizeof(u8)); ws2812_rgb(6, WS_YELLOW); ws2812_refresh(8); break; case 7: memset(ws_data,0,WS_ARRAY_SIZE*sizeof(u8)); ws2812_rgb(7, WS_BROWN); ws2812_refresh(8); break; case 8: memset(ws_data,0,WS_ARRAY_SIZE*sizeof(u8)); ws2812_rgb(8, WS_BLUE); ws2812_refresh(8); break; } delay_ms(1000); } } ``` ### 颜色RGB值查询 颜色的RGB值和名称可以参考下面链接: https://code.ziqiangxuetang.com/try/color.py 程序中颜色预定义如下: ```C #define WS_DARK 0,0,0 #define WS_WHITE 255,255,255 #define WS_RED 255,0,0 #define WS_GREEN 0,255,0 #define WS_BLUE 0,0,255 #define WS_YELLOW 255,255,0 #define WS_PURPLE 255,0,255 #define WS_CYAN 0,255,255 #define WS_BROWN 165,42,42 ``` 大家可以根据自己的喜欢,随意替换颜色。 ### 结果展示 ![](https://img-blog.csdnimg.cn/20210121002604228.png) ### 欢迎关注 一个专注于嵌入式知识分享,学习路上不迷路的公众号【**嵌入式从0到1**】,欢迎关注。 想加技术交流群的,可以扫码加我微信【**chengxuyuanxiaoha**】,让我拉你进群。
原创作品,未经权利人授权禁止转载。详情见
转载须知
。
举报文章
点赞
(
3
)
嵌入式从0到1
关注
评论
(1)
登录后可评论,请
登录
或
注册
nemon
82
天前...
请教一下,这个灯珠,一组可以串几个?
0
回复
发布
相关文章推荐
MK-米客方德推出工业级存储卡
Beetle ESP32 C3 蓝牙数据收发
Beetle ESP32 C3 wifi联网获取实时天气信息
开箱测评Beetle ESP32-C3 (RISC-V芯片)模块
正点原子数控电源DP100测评
DP100试用评测-----开箱+初体验
Beetle ESP32 C3环境搭建
【花雕体验】16 使用Beetle ESP32 C3控制8X32位WS2812硬屏之二
X
你的打赏是对原创作者最大的认可
请选择打赏IC币的数量,一经提交无法退回 !
100IC币
500IC币
1000IC币
自定义
IC币
确定
X
提交成功 ! 谢谢您的支持
返回
我要举报该内容理由
×
广告及垃圾信息
抄袭或未经授权
其它举报理由
请输入您举报的理由(50字以内)
取消
提交