一、WS2812介绍WS2812是一款广泛使用的地址可控RGB LED模块,内置驱动电路和控制芯片,允许用户通过单线信号控制多个LED的颜色和亮度。以下是WS2812模块的一些主要特性和应用:
主要特点单线控制: WS2812模块通过单条数据线进行控制,简化了连接线路的复杂性。
地址可控: 每个WS2812 LED都有独立的地址,这意味着您可以单独控制每个LED的颜色和亮度,适合创建动态效果。
七彩显示器:支持全彩显示,通常可以将红、绿、蓝三基色混合产生多种颜色。
链式连接:支持多个WS2812 LED串联,可以轻松扩展LED数量。只需将下一个LED 的数据线连接到前一个LED 即可。
高亮度、高密度: WS2812 LED亮度高,可在大面积上提供均匀的光效,适合室内外装饰和显示。
控制精度:通常提供256级亮度(8位)和1670万种颜色选项,以确保丰富的视觉效果。
主控制板上的WS2812部分如下图:
原理图主控板上WS2812模块接线图如下:
可以看到总共8个模块级联在一起,由PA12控制。
通信原理WS2812的数据协议采用单线归零码通信方式,支持串行级联接口,可以通过一根信号线完成数据接收和解码。每个灯就是一个像素,每个像素的三基色可以实现256级亮度显示,完成16,777,216种颜色的全真彩显示。
像素点上电复位后,DIN端接受控制器传来的数据。发送的24位数据由第一个像素提取并发送到像素内部的数据锁存器。剩余的数据由内部整形处理电路重新整形和放大,然后通过DO端口转发并输出到下一个级联像素。每传输一个像素,信号就会减少24 位。像素点采用自动整形转发技术,使得像素点的级联数量不受信号传输的限制,仅受信号传输速度要求的限制。
控制方式因为采用单总线,一根线完成一盏灯要显示的24位颜色数据,通过高低电平的时间长度来决定发送什么数据。 24位数据结构如下图所示。
其中,G代表三种颜色中的绿色,R代表三种颜色中的红色,B代表三种颜色中的蓝色。例如,如果您只想显示红色,请发送0X00FF00。
控制时序发送24位颜色数据,通过高低电平的长度来判断发送0还是1。
要发送一位数据0,需要将总线拉高T0H,然后拉低T0L,WS2812才会自动识别该数据为0。
要发送一位数据1,需要将总线拉高T1H,然后拉低T1L,WS2812才会自动识别该数据为1。
二、驱动代码编写WS2812的驱动方式有很多种,比如定时器+DMA、SPI+DMA、软件模拟等,这里我们选择软件模拟时序方式来驱动。
首先初始化GPIO口,并将PA12口配置为推挽输出。请注意CW32F030 和CW32L012 之间时钟配置的差异。
void WS2812_Init(void){ __RCC_GPIOA_CLK_ENABLE();//打开时钟GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.IT=GPIO_IT_NONE; GPIO_InitStruct.Mode=GPIO_MODE_OUTPUT_PP;//推挽输出GPIO_InitStruct.Pins=GPIO_PIN_12; GPIO_InitStruct.Speed=GPIO_SPEED_HIGH; GPIO_Init(CW_GPIOA, GPIO_InitStruct); RGB_Color_Init();//初始化所有灯光}
然后根据时序的高低电平要求,先写一个ns延迟。由于当前主频为64mhz,因此可以计算出一条机器指令所需的时间约为1/64=15ns,然后加上GPIO电平翻转时间。
/****************************400ns 延迟****************************/void delay_400ns(void)//409{ __nop();__nop();__nop();__nop();__nop();//__nop();__nop();}/****************************800ns 延迟****************************/void delay_800ns(void)//800{ __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop(); __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();//__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();//__nop();__nop();}
然后根据时序需要的高低电平次数写入0,1指令
/********************************发送1********************************/void RGB_Send1(void){ RGB_H;延迟_800ns(); RGB_L;延迟_400ns();}/****************************发送0****************************/void RGB_Send0(void){ RGB_H;延迟_400ns(); RGB_L;延迟_800ns();}
然后就可以向芯片发送指令了。一种颜色分为三个色域:RGB,一个色域为8位,所以我们需要8位数据一起发送。编写以下代码:
/********************************发送颜色数据,高位在前****************************/void RGB_send_Data(uint8_t Data){ uint8_t i; for(i=0;i8;i++) { if(数据0x80) { RGB_Send1(); } 其他{ RGB_Send0();数据=1; }}
这样就可以将指定的颜色数据发送到芯片中。最后,封装之后,我们想要的需求是指定某个灯点亮某种颜色,或者指定某个灯关闭,而不影响其他灯,所以我们定义一个数组来保存所有灯的颜色数据。那么我们只需要改变数组中固定位置的值就可以直接改变颜色了。代码如下:
/********************************显示颜色n:哪种灯R:红G:绿B:蓝********************************/void Send_RGB(uint8_t n,uint8_t R,uint8_t G,uint8_t B){ uint8_t i; RGB_Data[3*n-3]=G; RGB_Data[3*n-2]=R; RGB_Data[3*n-1]=B; for(i=0;i24;i++) { RGB_send_Data(RGB_Data[i]); RGB_Reset();}
最后在main函数中编写如下代码(OLED显示代码这里不列出)
int main(void){ OLED_Init();//初始化OLED_ShowString(1,1,'Hello');//OLED显示字符串WS2812_Init(); while(1) { Send_RGB(1,255,0,0);//255,0,0对应红色Delay_ms(500); Send_RGB(1,0,255,0);//255,0,0对应绿色Delay_ms(500); Send_RGB(1,0,0,255);//255,0,0对应蓝色Delay_ms(500); }}
三、工作现象编写代码后,我们可以观察到以下现象。 OLED第一行第一列显示HELLO。第一个RGB 灯每500 毫秒改变一次颜色,在红、绿、蓝之间反复切换。
标题:CW32L012/F030灵眸X1智能小车——板载WS2812驱动示例
链接:https://yqqlyw.com/news/sypc/67733.html
版权:文章转载自网络,如有侵权,请联系删除!