本帖最后由 suncat0504 于 2024-12-5 12:03 编辑
WS2812是一种基于数字信号传输的RGB LED灯珠,包含了三种颜色的LED和一个控制电路。
WS2812的工作电压范围比较宽,3.5V ~ 5.3V。其构成的三色LED参数:
驱动时,每个LED占用3个字节,数据形式为:
每个 bit 都是通过(一个高电平 + 一个低电平)表示。
按照这个要求,发送0码/1码,需要1/3.5≈3MHz的时钟。 WS2812的数据传输速率较慢,在使用单片机驱动WS2812时要注意传输速率。
在实际应用中经常使用级联方式,将多个WS2812串接起来,制作成灯条、灯带等方式。
在级联方式下的数据传输方法:
如果以SPI方式驱动WS2812,前面已经计算,SPI的时钟频率要达到3MHz。下例是使一个WS2812发绿色光,亮度为16的数据,
下面我就用MCXN947开发板编程驱动一款WS2812B模块(6个WS2812B)。MCXN947开发板有几组可用的SPI输出接口,这里只使用J2中的SPI的MOSI(J2 - 8)输出控制WS2812B,为了避免供电不足,不用开发板上的电源,而是使用独立的供电给WS2812B供电。开发环境使用MCUXpresso,在已有的SPI例程(frdmmcxn947_lpspi_edma_b2b_transfer_master)上进行修改。 追加的处理代码: - // 传输72字节,等同于24组码位
- // 每个WS2812使用3个字节、24位控制,换成码位数据为96位,
- // 这96位换算成码位字节数数据=96/8=12字节,6个WS2812就是6*12=72字节
- #define TRANSFER_SIZE 72U /* Transfer dataSize */
- // SPI主频设置为3MHz,保证WS2812的驱动时序
- #define TRANSFER_BAUDRATE 3000000U /* Transfer baudrate - 3MHz */
- #define LED_LD 10 //亮度,最大255
- #define WS2812_NUM 6 //LED灯个数
- #define SPI_NUM (WS2812_NUM*12) //LED灯对应SPI字节数(码位数据,供72字节)
- uint8_t led_RGB[WS2812_NUM][3]; //LED对应的RGB,led_buff[i][0]-->绿,led_buff[i][1]-->红,led_buff[i][0]-->蓝.
- // 将颜色装载到SPI发送数据单元
- void convWS2812Data(void) {
- uint8_t *px;
- uint16_t i,j;
- uint16_t k;
- uint8_t dat;
- // 测试用数据:红、绿、蓝、蓝、绿、红
- // 第1个LED:红色
- led_RGB[0][0] = 0;
- led_RGB[0][1] = LED_LD; //红色的显示亮度
- led_RGB[0][2] = 0;
- // 第2个LED:绿色
- led_RGB[1][0] = LED_LD; //绿色的显示亮度
- led_RGB[1][1] = 0;
- led_RGB[1][2] = 0;
- // 第3个LED:蓝色
- led_RGB[2][0] = 0;
- led_RGB[2][1] = 0;
- led_RGB[2][2] = LED_LD; //蓝色的显示亮度
- // 第4个LED:蓝色
- led_RGB[3][0] = 0;
- led_RGB[3][1] = 0;
- led_RGB[3][2] = LED_LD; //蓝色的显示亮度
- // 第5个LED:绿色
- led_RGB[4][0] = LED_LD; //绿色的显示亮度
- led_RGB[4][1] = 0;
- led_RGB[4][2] = 0;
- // 第6个LED:红色
- led_RGB[5][0] = 0;
- led_RGB[5][1] = LED_LD; //红色的显示亮度
- led_RGB[5][2] = 0;
- // 初始化要发送的数据
- for(i=0; i<SPI_NUM; i++) masterTxData[i] = 0;
- // 设置中间变量使用的起始地址
- px = &led_RGB[0][0]; //首地址
- // 循环WS2812数量对应的红绿蓝三个字节数据
- for(i=0, j=0; i<(WS2812_NUM*3); i++) {
- dat = *px;
- px++;
- // 处理对应WS2812的字节数据,每个WS2812的绿红蓝3个字节,对应为24位。
- // 每次处理2位
- // 转换每个数据位对应的0码/1码为4位基本码位数据
- for(k=0; k<4; k++) {
- if(dat & 0x80)
- masterTxData[j] = 0xE0; // 字码1 : 1110xxxx,
- else
- masterTxData[j] = 0x80; // 字码0 : 1000xxxx
- if(dat & 0x40)
- masterTxData[j] |= 0x0E; // 字码1 : 1110
- else
- masterTxData[j] |= 0x08; // 字码0 : 1000
- // 每次处理2位,2位对应WS2912的一个字节
- dat <<= 2;
- // 指向下一个字节(红、绿、蓝顺序)
- j++;
- }
- }
- }
复制代码在主程序处理中,完成了SPI外设的初始化后,启动WS2812的驱动处理: - // 配置WS2812数据
- convWS2812Data();
- /* Print out transmit buffer */
- PRINTF("\r\n Master transmit:\r\n");
- for (i = 0; i < TRANSFER_SIZE; i++) {
- /* Print 16 numbers in a line */
- if ((i % 12) == 0U) {
- PRINTF("\r\n");
- }
- PRINTF(" %02X", masterTxData[i]);
- }
- PRINTF("\r\n");
- // 启动传输
- masterXfer.txData = masterTxData;
- masterXfer.rxData = NULL;
- masterXfer.dataSize = TRANSFER_SIZE;
- isTransferCompleted = false;
- LPSPI_MasterTransferEDMALite(EXAMPLE_LPSPI_MASTER_BASEADDR, &g_m_edma_handle,&masterXfer);
- // 等待传输完成
- while (!isTransferCompleted);
- PRINTF("The Transfer is Completed!\r\n");
复制代码
测试效果如下:
实测SPI的接口波形信号:
|