WS2812 彩灯
WS2812E 是一个集控制电路与发光电路于一体的智能外控 LED 光源。其外型与一个 5050LED 灯珠相同,每个
元件即为一个像素点。像素点内部包含了智能数字接口数据锁存信号整形放大驱动电路,还包含有高精度的内部
振荡器和可编程定电流控制部分,有效保证了像素点光的颜色高度一致。
模块来源
采购链接:
8 位 WS2812 RGB 全彩 LED 模块 5050LED 灯珠内置全彩驱动直板 DIY
资料下载链接:
https://pan.baidu.com/s/1OkCpw8ooDyuw947V0b89Rw
提取码:AB12
规格参数
工作电压: 3.7-5.3V
工作电流: 16MA
控制方式: 单总线
管脚数量: 4 Pin(2.54mm 间距排针)
移植过程
我们的目标是在天空星 STM32F407 上能够实现设置彩灯颜色的功能。首先要获取资料,查看数据手册应如何实现,再移植至我们的工程。
查看资料
WS2812 的数据协议采用单线归零码的通讯方式,支持串行级联接口,能通过一根信号线完成数据的接收与解码。每个灯就是一个像素点,每个像素点的三基色颜色可实现 256 级亮度显示,完成 16777216 种颜色的全真色彩显示。
像素点在上电复位以后,DIN 端接受从控制器传输过来的数据,首先送过来的 24bit 数据被第一个像素点提取后,送到像素点内部的数据锁存器,剩余的数据经过内部整形处理电路整 形放大后通过 DO 端口开始转发输出给下一个级联的像素点,每经过一个像素点的传输,信号减少 24bit。像素点采用自动整形转发技术,使得该像素点的级联个数不受信号传送的限制,仅受限信号传输速度要求。
控制方式
因为使用的是单总线,一根线完成一个灯要显示的 24 位颜色数据,是通过高低电平的时间长度来确定发送的是什么数据。24 位的数据结构见下图。
其中 G 代表三色中的绿色,R 代表三色中的红色,B 表示三色中的蓝色。例如想要只显示红色则发送 0X00FF00 即可。
控制时序
发送 24 位颜色数据,是通过高低电平的时间长度来确定发送的是 0 还是 1。
发送一位数据 0,需要总线拉高 T0H 的时间再拉低 T0L 的时间,WS2812 才会自动识别该数据是 0。
发送一位数据 1,需要总线拉高 T1H 的时间再拉低 T1L 的时间,WS2812 才会自动识别该数据是 1。
关于高低电平时间,1us 我们可以通过官方示例开始实现,但是 220ns~420ns 我们如何准确的计算出来?
这里通过逻辑分析仪,进行采样。
执行语句 ** for(j = 0; j < 8; j++ ); **时,一共会花费 0.25us,即 250ns,处于 220ns~420ns 范围。
实现代码
/******************************************************************
* 函 数 名 称:Ws2812b_WriteByte
* 函 数 说 明:向WS2812写入单字节数据
* 函 数 形 参:byte写入的字节数据
* 函 数 返 回:无
* 作 者:LC
* 备 注:1码的时序 = 高电平580ns~1us 再低电平220ns~420ns
* 0码的时序 = 高电平220ns~380ns 再低电平580ns~1us
******************************************************************/
void Ws2812b_WriteByte(unsigned char byte)
{
int i = 0, j = 0;
for(i = 0; i < 8; i++ )
{
if( byte & (0x80 >> i) )//当前位为1
{
RGB_PIN_H();
delay_1us(1);//0.75us
RGB_PIN_L();
for(j = 0; j < 8; j++ );//0.25us
}
else//当前位为0
{
RGB_PIN_H();
for(j = 0; j < 8; j++ );//0.25us
RGB_PIN_L();
delay_1us(1);//0.833us
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
引脚选择
移植至工程
移植步骤中的导入.c 和.h 文件与第二章的第 1 小节【DHT11 温湿度传感器】相同,只是将.c 和.h 文件更改为 bsp_ws2812.c 与 bsp_ws2812.h。这里不再过多讲述,移植完成后面修改相关代码。
在文件 bsp_ws2812.c 中,编写如下代码。
/*
* 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 立创论坛:https://oshwhub.com/forum
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
*
Change Logs:
* Date Author Notes
* 2024-03-22 LCKFB-LP first version
*/
#include "bsp_ws2812.h"
#include "board.h"
#include "stdio.h"
#include "math.h"
unsigned char LedsArray[WS2812_MAX * 3]; //定义颜色数据存储数组
unsigned int ledsCount = WS2812_NUMBERS; //定义实际彩灯默认个数
unsigned int nbLedsBytes = WS2812_NUMBERS*3; //定义实际彩灯颜色数据个数
/******************************************************************
* 函 数 名 称:WS2812_GPIO_Init
* 函 数 说 明:对WS2812引脚初始化
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void WS2812_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_DIN, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_DIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; // 下拉
GPIO_Init(PORT_DIN, &GPIO_InitStructure);
GPIO_ResetBits(PORT_DIN, GPIO_DIN);
}
/******************************************************************
* 函 数 名 称:rgb_SetColor
* 函 数 说 明:设置彩灯颜色
* 函 数 形 参:LedId控制的第几个灯 color颜色数据
* 函 数 返 回:无
* 作 者:LC
* 备 注:在这里我将绿和红色进行颠倒,这样比较符合我们日常生活的红绿蓝的顺序
******************************************************************/
void rgb_SetColor(unsigned char LedId, unsigned long color)
{
if( LedId > ledsCount )
{
return; //to avoid overflow
}
LedsArray[LedId * 3] = (color>>8)&0xff;
LedsArray[LedId * 3 + 1] = (color>>16)&0xff;
LedsArray[LedId * 3 + 2] = (color>>0)&0xff;
}
/******************************************************************
* 函 数 名 称:rgb_SetRGB
* 函 数 说 明:设置彩灯颜色(三原色设置)
* 函 数 形 参:LedId控制的第几个灯 red红色数据 green绿色数据 blue蓝色数据
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void rgb_SetRGB(unsigned char LedId, unsigned long red, unsigned long green, unsigned long blue)
{
unsigned long Color=red<<16|green<<8|blue;
rgb_SetColor(LedId,Color);
}
/******************************************************************
* 函 数 名 称:rgb_SendArray
* 函 数 说 明:发送彩灯数据
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void rgb_SendArray(void)
{
unsigned int i;
//发送数据
for(i=0; i<nbLedsBytes; i++)
Ws2812b_WriteByte(LedsArray[i]);
}
/******************************************************************
* 函 数 名 称:RGB_LED_Reset
* 函 数 说 明:复位ws2812
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:低电平280us以上
******************************************************************/
void RGB_LED_Reset(void)
{
RGB_PIN_L();
delay_us(281);
}
/******************************************************************
* 函 数 名 称:Ws2812b_WriteByte
* 函 数 说 明:向WS2812写入单字节数据
* 函 数 形 参:byte写入的字节数据
* 函 数 返 回:无
* 作 者:LC
* 备 注:1码的时序 = 高电平580ns~1us 再低电平220ns~420ns
* 0码的时序 = 高电平220ns~380ns 再低电平580ns~1us
******************************************************************/
void Ws2812b_WriteByte(unsigned char byte)
{
int i = 0, j = 0;
for(i = 0; i < 8; i++ )
{
if( byte & (0x80 >> i) )//当前位为1
{
RGB_PIN_H();
delay_us(1);//0.75us
RGB_PIN_L();
for(j = 0; j < 8; j++ );//0.25us
}
else//当前位为0
{
RGB_PIN_H();
for(j = 0; j < 8; j++ );//0.25us
RGB_PIN_L();
delay_us(1);//0.833us
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
在文件 bsp_ws2812.h 中,编写如下代码。
/*
* 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 立创论坛:https://oshwhub.com/forum
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
*
Change Logs:
* Date Author Notes
* 2024-03-22 LCKFB-LP first version
*/
#ifndef _BSP_WS2812_H_
#define _BSP_WS2812_H_
#include "stm32f4xx.h"
#define RCC_DIN RCC_AHB1Periph_GPIOB
#define PORT_DIN GPIOB
#define GPIO_DIN GPIO_Pin_15
//用户修改参数区
//#define WS2812_FREQUENCY
#define RGB_PIN_L() GPIO_WriteBit(PORT_DIN, GPIO_DIN, Bit_RESET) //控制彩灯引脚(需要配置为强推挽输出)
#define RGB_PIN_H() GPIO_WriteBit(PORT_DIN, GPIO_DIN, Bit_SET) //控制彩灯引脚(需要配置为强推挽输出)
#define WS2812_MAX 8 //彩灯最大个数
#define WS2812_NUMBERS 8 //彩灯个数
#define RED 0xff0000 //红色
#define GREEN 0x00ff00 //绿色
#define BLUE 0x0000ff //蓝色
#define BLACK 0x000000 //熄灭
#define WHITE 0xffffff //白色
//8.3 -8 0.000000083
//4.16 -9 0.00000000416
void Ws2812b_WriteByte(unsigned char byte);//发送一个字节数据(@12.000MHz,理论每个机器周期83ns,测试约为76ns)
void setLedCount(unsigned char count);//设置彩灯数目,范围0-25.
unsigned char getLedCount();//彩灯数目查询函数
void rgb_SetColor(unsigned char LedId, unsigned long color);//设置彩灯颜色
void rgb_SetRGB(unsigned char LedId, unsigned long red, unsigned long green, unsigned long blue);//设置彩灯颜色
void rgb_SendArray();//发送彩灯数据
void WS2812_GPIO_Init(void);
void RGB_LED_Write1(void);
void RGB_LED_Reset(void);
#endif
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
移植验证
在自己工程中的 main 主函数中,编写如下。
/*
* 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 立创论坛:https://oshwhub.com/forum
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
*
Change Logs:
* Date Author Notes
* 2024-03-22 LCKFB-LP first version
*/
#include "board.h"
#include "bsp_uart.h"
#include <stdio.h>
#include "bsp_ws2812.h"
uint8_t Co = 100;
unsigned int buff[]={RED,GREEN,BLUE,WHITE};
int main(void)
{
int i = 0;
board_init();
uart1_init(115200U);
WS2812_GPIO_Init();
printf("Start--->\r\n");
while(1)
{
for( i = 0; i < 8; i++ )
{
rgb_SetColor(i,buff[i%3]);
rgb_SendArray();
delay_ms(10);
}
delay_ms(3000);
i = 0;
while( Co )
{
rgb_SetColor((i+0)%8,buff[0]);
rgb_SetColor((i+1)%8,buff[1]);
rgb_SetColor((i+2)%8,buff[2]);
rgb_SetColor((i+3)%8,buff[3]);
rgb_SetColor((i+4)%8,BLACK);
rgb_SetColor((i+5)%8,BLACK);
rgb_SetColor((i+6)%8,BLACK);
rgb_SetColor((i+7)%8,BLACK);
rgb_SendArray();
delay_ms(200);
Co--;
i++;
}
Co = 100;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
移植现象:三秒前八个灯全亮,后面循环流水灯显示。
代码下载
链接在开发板介绍
章节的离线资料下载!!