当前位置:首页 >> 耐磨砖

一个IO控制很多个LED,这个技能你get到了吗反光纸

2022-10-11 12:42:05  精锐机械网

一个IO控制很多个LED,这个技能你get到了吗 实现目标每隔一秒,点亮模块上的一个 LED点亮模块上的所有 LED所需工具及环境Keil 5STM32F103RET6 核心板(本平台自制专用核心板,随便找一个开发板亦可)8 位 圆形 WS2812B LED 模块本文源码

后台回复关键字WS2812B,获取WS2812B模块资料、数据手册及工程源码。

简介

多位(几个 LED 就是几位)通过引脚级联,接一个 LED 的 DOUT 引脚到另一个 LED 的 DIN 引脚,通过这种级联的方式,只需要使用一个 IO 口(单片机引脚)就能控制尽可能多的 LED。

每个 LED 都集成了一颗驱动芯片在里面,让我们的 LED 变得智能和寻址,每一个内部都有恒流驱动,所以 LED 颜色非常一致,即使电压有小幅抖动,电压变化也是一样的。

不需要外部电阻——限流电阻,使 LED 灯的布局设计变得简单。

单线通信,能够最大限度的减少单片机 IO 口的压力,另外这款 RGB 灯使用了 WS2812B 驱动芯片,让外围电路只需要一颗电容就能够满足电路需求,从而最大可能的让电路变得简单优美。

特点智能反接保护,电源反接不会损坏 IC;IC 控制电路与 LED 点光源公用一个电源;控制电路与 RGB 芯片集成在一个 5050 封装的元器件中,构成一个外控像素点;内置信号整形电路,任何一个像素点收到信号后经过波形整形再输出,保证线路波形畸变不会累加;内置上电复位和掉电复位电路;每个像素点的三基色颜色可实现 256 级亮度显示,完成 16777216 种颜色的全真色彩显示,扫描频率不低于 400Hz;串行级联接口,能通过一根信号线完成数据的接收与解码;任意两点传输距离在不超过 5 米时,无需增加额外电路;当刷新速率 30 帧 / 秒时,级联数不小于 1024 点;数据发送速度可达 800Kbps;光的颜色高度一致,性价比高。

注意: 800Kbps,相当于 1.25us 传输一比特数据。

引脚图

引脚功能描述:

NO.Symbol功能描述1VDDLED 的供电电源,Vdd 范围 +3.5~+5.3 V2DOUT控制信号数据输出引脚3VSS地4DIN控制信号数据输入引脚典型电路串联方法 原理图

除了灯珠以外只需要额外增加一个 0.1uF 的电容即可。

硬件连接 STM32F103RET6 核心板WS2812B 模块PA6DINVCC+5VGNDGND驱动原理

数据协议采用单线归零码的通讯方式,像素点在上电复位以后,DIN 端接受从控制器传输过来的数据,首先送过来的 24bit 数据被第一个像素点提取后,送到像素点内部的数据锁存器,剩余的数据经过内部整形处理电路整形放大后通过 DOUT 端口开始转发输出给下一个级联的像素点,每经过一个像素点的传输,信号减少 24bit。

像素点采用自动整形转发技术,使得像素点的级联个数不受信号传送的限制,仅仅受限信号传输速度要求。

因为数据被内部锁存,所以只要不改变颜色值(模块持续供电),颜色是不会发生改变的,设置颜色的脉冲也不需要持续提供(单片机发生复位也无影响),只需要在修改颜色值的时候,发送一遍即可。

0 和 1 的区分

Treset:复位时间

由上图可知,我们要发送 '0' ,需要将 GPIO 引脚置高并持续 0.4 us(400 ns),然后 GPIO 置低并持续 0.85 us(850 ns),此过程即完成0 code的发送,具体代码实现如下:

voidsend_0(void){IN_H;Wait400ns;IN_L;Wait850ns;}

我们要发送 '1' ,需要将 GPIO 引脚置高并持续 0.85 us(850 ns),然后 GPIO 置低并持续 0.4 us(400 ns),此过程即完成1 code的发送,具体代码实现如下:

voidsend_1(void){IN_H;Wait850ns;IN_L;Wait400ns;}

所以本程序的难点即是求取 400 ns 和 850 ns 相对精确的延时时间。

延时函数的实现

单片机里的延时函数一般通过执行一些无意义的循环进行延时,比如定义如下函数:

voiddelay(unsignedchari){while(--i);}

我们这里需要的延时周期很小,才 1.25us,因为函数的调用,需要入栈和出栈,所以如果使用上面的延时函数的方式的话,那么一进一出就接近几百 ns 的时间就没了,所以为了精确控制,我们这里延时函数的定义如下:

#defineWait10nop{__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();}#defineWait250ns{__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();}#defineWait400ns{Wait250ns;Wait10nop;}//388#defineWait850ns{Wait250ns;Wait10nop;Wait10nop;Wait10nop;Wait10nop;__NOP();__NOP();__NOP();__NOP();__NOP();}//860

我们在 main 函数中使用如下方式测试这个延时函数:

while(1){IN_H;//Wait250ns;Wait850ns;IN_L;//Wait250ns;Wait850ns;}

然后用示波器观察与模块 DIN 引脚相连的 GPIO 输出的脉冲信号,查看其高电平是否与咱们预定义的一致,如果不一致,增加或减少空指令进行调整。

注意:一个 __NOP(); 空指令的耗时大约:1000/72 ≈ 14 ns 的时间,自己可以在上面定义的基础上,根据需要随意增加或者减少 __NOP(); 空指令的个数。

注意空指令前面是两个_。

经过示波器测量,不断调整,上面定义的 Wait250ns 宏定义的耗时如下图所示。

经过示波器测试,上面的 Wait400ns 耗时为 388 ns , Wait850ns 耗时为 860 ns,满足上面"0"和"1"的时间区间范围。

24 bit 数据的组成

注意: 数据传输顺序按 GRB 顺序传输,并且高位在前。

voidws2812_rgb(u8ws_num,u8ws_r,u8ws_g,u8ws_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[] 数组中颜色值设置完毕之后,就要把这个数组的数据发送到模块中,具体的实现函数如下:

voidws2812_refresh(u8ws_count){u8ws_ri=0;for(;ws_ri{if((ws_data[ws_ri]&0x80)==0)send_0();elsesend_1();if((ws_data[ws_ri]&0x40)==0)send_0();elsesend_1();if((ws_data[ws_ri]&0x20)==0)send_0();elsesend_1();if((ws_data[ws_ri]&0x10)==0)send_0();elsesend_1();if((ws_data[ws_ri]&0x08)==0)send_0();elsesend_1();if((ws_data[ws_ri]&0x04)==0)send_0();elsesend_1();if((ws_data[ws_ri]&0x02)==0)send_0();elsesend_1();if((ws_data[ws_ri]&0x01)==0)send_0();elsesend_1();}// 延时一段时间ws2812_reset();}

ws_data[] 数组中的每一个字节按位发送,因为高位在前,所以先发送每个字节的高位,获取最高位的值的方法为:ws_data[ws_ri]&0x80 。

数据传输方法

N 位的模块,一次就要发送 N * 3 字节的数据。

注意:上图中 D1 的数据是通过单片机发送,D2,D3,D4 通过像素内重塑放大传输。

main 函数实现

main 函数中,每隔 1S,点亮一个 LED,当 8 个 LED 都点亮一次之后,所有 LED 点亮一次,然后再开启下一次循环。

main 函数的具体实现如下所示:

intmain(void){inttimes=0;// 初始化// 延时函数初始化delay_init();uart_init(115200);// 串口 1:Debug,初始化为 115200ws2812_init();printf("SystemInitOK...\r\n");while(1){times++;if(times>8)times=0;switch(times){case0: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;case1:memset(ws_data,0,WS_ARRAY_SIZE*sizeof(u8));ws2812_rgb(1,WS_RED);ws2812_refresh(8);break;case2:memset(ws_data,0,WS_ARRAY_SIZE*sizeof(u8));ws2812_rgb(2,WS_GREEN);ws2812_refresh(8);break;case3:memset(ws_data,0,WS_ARRAY_SIZE*sizeof(u8));ws2812_rgb(3,WS_BLUE);ws2812_refresh(8);break;case4:memset(ws_data,0,WS_ARRAY_SIZE*sizeof(u8));ws2812_rgb(4,WS_WHITE);ws2812_refresh(8);break;case5:memset(ws_data,0,WS_ARRAY_SIZE*sizeof(u8));ws2812_rgb(5,WS_PURPLE);ws2812_refresh(8);break;case6:memset(ws_data,0,WS_ARRAY_SIZE*sizeof(u8));ws2812_rgb(6,WS_YELLOW);ws2812_refresh(8);break;case7:memset(ws_data,0,WS_ARRAY_SIZE*sizeof(u8));ws2812_rgb(7,WS_BROWN);ws2812_refresh(8);break;case8: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

程序中颜色预定义如下:

#defineWS_DARK0,0,0#defineWS_WHITE255,255,255#defineWS_RED255,0,0#defineWS_GREEN0,255,0#defineWS_BLUE0,0,255#defineWS_YELLOW255,255,0#defineWS_PURPLE255,0,255#defineWS_CYAN0,255,255#defineWS_BROWN165,42,42

大家可以根据自己的喜欢,随意替换颜色。

结果展示 欢迎关注

关注公众号,第一时间获得技术干货,扫描加我微信,拉你进入技术交流群。

营口可靠的做人流手术医院
沈阳有名的做人流手术医院
西安治癫痫的医院哪里好
兰州治白癜风去哪家医院
相关资讯
友情链接