资讯详情

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

前几天发现了一个人工智能学习网站,通俗易懂,幽默幽默,忍不住和大家分享。点击跳转到教程。


实现目标

  • 每隔一秒,点亮模块上的一个LED
  • 点亮模块上的一切LED

所需的工具和环境

本文源码

微信官方账号后台回复关键词”,获取模块数据、数据手册和工程源代码。

简介

电压:DC4~7V

多位(几个LED就是几位)通过引脚级联接一个到另一个的输出引脚,通过这种级联的方式,只需要使用一个IO口(单片机引脚)可以尽可能多地控制LED,每个LED里面集成了驱动芯片,让我们LED变得智能和寻址,每个内部都有恒流驱动,所以LED颜色非常一致,即使电压有轻微的抖动,电压变化也是如此。

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

单线通信可以最大限度地减少单片机IO口压,另外这个RGB灯使用了WS2812B驱动芯片,让外围电路能够满足电路的需求,使电路最大限度地简单美观。

特点

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

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

引脚图

引脚功能描述:

1 VDD LED,Vdd 范围 3.5~ 5.3 V
2 DOUT 控制信号数据输出
3 VSS
4 DIN 引脚控制信号数据输入

典型电路

串联方法

原理图

除了灯珠,只需要额外添加0.1uF电容。

硬件连接

PA6 DIN
VCC 5V
GND GND

驱动原理

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

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

由于数据被内部锁定,只要颜色值不改变(模块连续供电),颜色就不会改变,设置颜色的脉冲也不需要连续提供(单片机复位无影响),只需在修改颜色值时再次发送。

0和1的区分

Treset:复位时间

从上图可以看出,我们必须发送它 ‘’ ,需要将GPIO引脚置高并持续0.4 us(400 ns),然后GPIO置低并持续0.85 us(850 ns),这个过程就完成了具体代码如下:

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

我们要发送 ‘’ ,需要将GPIO引脚位高并持续0.85 us(850 ns),然后GPIO置低并持续0.4 us(400 ns),这个过程就完成了具体代码如下:

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

所以这个程序的难点是4000 ns 和 850 ns 延迟时间相对准确。

实现延迟函数

单片机中的延迟函数通常通过执行一些无意义的循环来延迟,例如定义以下函数:

void delay(unsigned char i) {   while(--i); } 

这里需要的延迟周期很小,只有1.25us,因为函数的调用需要进出栈,如果使用上述延迟函数,一进一出就会接近几百。ns因此,为了精确控制,这里延迟函数的定义如下:

#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该延迟函数采用以下方法测试:

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

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

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

注意空指令前面是两个“”。

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

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

24 bit数据的组成

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

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;
}

数组中用于记录待传输的RGB数据,每一个灯珠的颜色占用三个字节,因为数据传输顺序按GRB的顺序传输,所以赋值的时候注意先后顺序,上面函数是设置某一个灯珠的颜色值。

数组中颜色值设置完毕之后,就要把这个数组的数据发送到模块中,具体的实现函数如下:

void ws2812_refresh(u8 ws_count)
{
	u8 ws_ri=0;
    
	for(;ws_ri<ws_count*3;ws_ri++)
	{
		if((ws_data[ws_ri]&0x80)==0)	send_0();	else send_1();
		if((ws_data[ws_ri]&0x40)==0)	send_0();	else send_1();
		if((ws_data[ws_ri]&0x20)==0)	send_0();	else send_1();
		if((ws_data[ws_ri]&0x10)==0)	send_0();	else send_1();
		if((ws_data[ws_ri]&0x08)==0)	send_0();	else send_1();
		if((ws_data[ws_ri]&0x04)==0)	send_0();	else send_1();
		if((ws_data[ws_ri]&0x02)==0)	send_0();	else send_1();
		if((ws_data[ws_ri]&0x01)==0)	send_0();	else send_1();
	}
    
    //延时一段时间
	ws2812_reset();
}

数组中的每一个字节按位判断发送,因为高位在前,所以先发送每个字节的高位,获取最高位的值的方法为:

数据传输方法

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

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

main函数调用

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

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

int main(void)  
{ 
	int times = 0; 
    
	//初始化
	//延时函数初始化 	 
	delay_init();
		  
	uart_init(115200);	 		//串口1:Debug,初始化为115200 

    ws2812_init();
    
	printf("System Init OK ...\r\n");
	
	while(1) 
	{		
		times++;	

        if(times > 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

程序中颜色预定义如下:

#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

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

结果展示

标签: 内置电阻led灯珠

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台