WS2812E是一個(gè)集控制電路與發(fā)光電路于一體的智能外控LED光源。其外型與一個(gè)5050LED燈珠相同,每個(gè) 元件即為一個(gè)像素點(diǎn)。像素點(diǎn)內(nèi)部包含了智能數(shù)字接口數(shù)據(jù)鎖存信號(hào)整形放大驅(qū)動(dòng)電路,還包含有高精度的內(nèi)部 振蕩器和可編程定電流控制部分,有效保證了像素點(diǎn)光的顏色高度一致。
一模塊來源
模塊實(shí)物展示:
資料鏈接:https://pan.baidu.com/s/1OkCpw8ooDyuw947V0b89Rw
資料提取碼:AB12
二規(guī)格參數(shù)
工作電壓:3.7-5.3V
工作電流:16MA
控制方式:單總線
管腳數(shù)量:4 Pin(2.54mm間距排針)
以上信息見廠家資料文件
三移植過程
我們的目標(biāo)是將例程移植至CW32F030C8T6開發(fā)板上【能夠?qū)崿F(xiàn)設(shè)置彩燈顏色的功能】。首先要獲取資料,查看數(shù)據(jù)手冊(cè)應(yīng)如何實(shí)現(xiàn)讀取數(shù)據(jù),再移植至我們的工程。
3.1查看資料
WS2812的數(shù)據(jù)協(xié)議采用單線歸零碼的通訊方式,支持串行級(jí)聯(lián)接口,能通過一根信號(hào)線完成數(shù)據(jù)的接收與解碼。每個(gè)燈就是一個(gè)像素點(diǎn),每個(gè)像素點(diǎn)的三基色顏色可實(shí)現(xiàn)256級(jí)亮度顯示,完成16777216種顏色的全真色彩顯示。
像素點(diǎn)在上電復(fù)位以后,DIN端接受從控制器傳輸過來的數(shù)據(jù),首先送過來的24bit數(shù)據(jù)被第一個(gè)像素點(diǎn)提取后,送到像素點(diǎn)內(nèi)部的數(shù)據(jù)鎖存器,剩余的數(shù)據(jù)經(jīng)過內(nèi)部整形處理電路整 形放大后通過DO端口開始轉(zhuǎn)發(fā)輸出給下一個(gè)級(jí)聯(lián)的像素點(diǎn),每經(jīng)過一個(gè)像素點(diǎn)的傳輸,信號(hào)減少24bit。像素點(diǎn)采用自動(dòng)整形轉(zhuǎn)發(fā)技術(shù),使得該像素點(diǎn)的級(jí)聯(lián)個(gè)數(shù)不受信號(hào)傳送的限制,僅受限信號(hào)傳輸速度要求。
控制方式
因?yàn)槭褂玫氖菃慰偩€,一根線完成一個(gè)燈要顯示的24位顏色數(shù)據(jù),是通過高低電平的時(shí)間長(zhǎng)度來確定發(fā)送的是什么數(shù)據(jù)。24位的數(shù)據(jù)結(jié)構(gòu)見下圖。
其中G代表三色中的綠色,R代表三色中的紅色,B表示三色中的藍(lán)色。例如想要只顯示紅色則發(fā)送 0X00FF00即可。
控制時(shí)序
發(fā)送24位顏色數(shù)據(jù),是通過高低電平的時(shí)間長(zhǎng)度來確定發(fā)送的是0還是1。
發(fā)送一位數(shù)據(jù)0,需要總線拉高T0H的時(shí)間再拉低T0L的時(shí)間,WS2812才會(huì)自動(dòng)識(shí)別該數(shù)據(jù)是0。
發(fā)送一位數(shù)據(jù)1,需要總線拉高T1H的時(shí)間再拉低T1L的時(shí)間,WS2812才會(huì)自動(dòng)識(shí)別該數(shù)據(jù)是1
3.2引腳選擇
該模塊有3個(gè)引腳,具體引腳連接見各引腳連接。
模塊接線圖
3.3移植至工程
移植步驟中的導(dǎo)入.c和.h文件與【CW32模塊使用】DHT11溫濕度傳感器相同,只是將.c和.h文件更改為bsp_ws2812.c與bsp_ws2812.h。這里不再過多講述,移植完成后面修改相關(guān)代碼。
在文件bsp_ws2812.c中,編寫如下代碼。
/*
* Change Logs:
* Date Author Notes
* 2024-06-24 LCKFB-LP first version
*/
#include "bsp_ws2812.h"
#include "stdio.h"
#include "math.h"
unsigned char LedsArray[WS2812_MAX * 3]; //定義顏色數(shù)據(jù)存儲(chǔ)數(shù)組
unsigned int ledsCount = WS2812_NUMBERS; //定義實(shí)際彩燈默認(rèn)個(gè)數(shù)
unsigned int nbLedsBytes = WS2812_NUMBERS*3; //定義實(shí)際彩燈顏色數(shù)據(jù)個(gè)數(shù)
void delay_0_30us(void)
{
__NOP;__NOP;__NOP;__NOP;__NOP;
}
/******************************************************************
* 函 數(shù) 名 稱:WS2812_GPIO_Init
* 函 數(shù) 說 明:對(duì)WS2812引腳初始化
* 函 數(shù) 形 參:無
* 函 數(shù) 返 回:無
* 作 者:LC
* 備 注:無
******************************************************************/
void WS2812_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct; // GPIO初始化結(jié)構(gòu)體
RCC_DIN_ENABLE(); // 使能GPIO時(shí)鐘
GPIO_InitStruct.Pins = GPIO_DIN; // GPIO引腳
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽輸出
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; // 輸出速度高
GPIO_Init(PORT_DIN, &GPIO_InitStruct); // 初始化
GPIO_WritePin(PORT_DIN, GPIO_DIN, GPIO_Pin_RESET);
}
/******************************************************************
* 函 數(shù) 名 稱:rgb_SetColor
* 函 數(shù) 說 明:設(shè)置彩燈顏色
* 函 數(shù) 形 參:LedId控制的第幾個(gè)燈 color顏色數(shù)據(jù)
* 函 數(shù) 返 回:無
* 作 者:LC
* 備 注:在這里我將綠和紅色進(jìn)行顛倒,這樣比較符合我們?nèi)粘I畹募t綠藍(lán)的順序
******************************************************************/
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;
}
/******************************************************************
* 函 數(shù) 名 稱:rgb_SetRGB
* 函 數(shù) 說 明:設(shè)置彩燈顏色(三原色設(shè)置)
* 函 數(shù) 形 參:LedId控制的第幾個(gè)燈 red紅色數(shù)據(jù) green綠色數(shù)據(jù) blue藍(lán)色數(shù)據(jù)
* 函 數(shù) 返 回:無
* 作 者: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);
}
/******************************************************************
* 函 數(shù) 名 稱:rgb_SendArray
* 函 數(shù) 說 明:發(fā)送彩燈數(shù)據(jù)
* 函 數(shù) 形 參:無
* 函 數(shù) 返 回:無
* 作 者:LC
* 備 注:無
******************************************************************/
void rgb_SendArray(void)
{
unsigned int i;
//發(fā)送數(shù)據(jù)
for(i=0; i<nbLedsBytes; i++)
Ws2812b_WriteByte(LedsArray[i]);
}
/******************************************************************
* 函 數(shù) 名 稱:RGB_LED_Reset
* 函 數(shù) 說 明:復(fù)位ws2812
* 函 數(shù) 形 參:無
* 函 數(shù) 返 回:無
* 作 者:LC
* 備 注:低電平280us以上
******************************************************************/
void RGB_LED_Reset(void)
{
RGB_PIN_L();
delay_us(285);
}
/******************************************************************
* 函 數(shù) 名 稱:Ws2812b_WriteByte
* 函 數(shù) 說 明:向WS2812寫入單字節(jié)數(shù)據(jù)
* 函 數(shù) 形 參:byte寫入的字節(jié)數(shù)據(jù)
* 函 數(shù) 返 回:無
* 作 者:LC
* 備 注:1碼的時(shí)序 = 高電平580ns~1us 再低電平220ns~420ns
* 0碼的時(shí)序 = 高電平220ns~380ns 再低電平580ns~1us
******************************************************************/
void Ws2812b_WriteByte(unsigned char byte)
{
int i = 0, k = 0;
for(i = 0; i < 8; i++ )
{
if( byte & (0x80 >> i) )//當(dāng)前位為1
{
RGB_PIN_H();
delay_us(1);//0.75us
RGB_PIN_L();
__NOP;__NOP;__NOP;__NOP;__NOP;//0.25us
}
else//當(dāng)前位為0
{
RGB_PIN_H();
__NOP;__NOP;__NOP;__NOP;__NOP;//0.25us
RGB_PIN_L();
delay_us(1);//0.833us
}
}
}
在文件bsp_ws2812.h中,編寫如下代碼。
/*
* Change Logs:
* Date Author Notes
* 2024-06-24 LCKFB-LP first version
*/
#ifndef _BSP_WS2812_H_
#define _BSP_WS2812_H_
#include "board.h"
#define RCC_DIN_ENABLE() __RCC_GPIOB_CLK_ENABLE()
#define PORT_DIN CW_GPIOB
#define GPIO_DIN GPIO_PIN_12
//用戶修改參數(shù)區(qū)
//#define WS2812_FREQUENCY
#define RGB_PIN_L() GPIO_WritePin(PORT_DIN, GPIO_DIN, GPIO_Pin_RESET) //控制彩燈引腳(需要配置為強(qiáng)推挽輸出)
#define RGB_PIN_H() GPIO_WritePin(PORT_DIN, GPIO_DIN, GPIO_Pin_SET) //控制彩燈引腳(需要配置為強(qiáng)推挽輸出)
#define WS2812_MAX 8 //彩燈最大個(gè)數(shù)
#define WS2812_NUMBERS 8 //彩燈個(gè)數(shù)
#define RED 0xff0000 //紅色
#define GREEN 0x00ff00 //綠色
#define BLUE 0x0000ff //藍(lán)色
#define BLACK 0x000000 //熄滅
#define WHITE 0xffffff //白色
//8.3 -8 0.000000083
//4.16 -9 0.00000000416
void Ws2812b_WriteByte(unsigned char byte);//發(fā)送一個(gè)字節(jié)數(shù)據(jù)(@12.000MHz,理論每個(gè)機(jī)器周期83ns,測(cè)試約為76ns)
void setLedCount(unsigned char count);//設(shè)置彩燈數(shù)目,范圍0-25.
unsigned char getLedCount();//彩燈數(shù)目查詢函數(shù)
void rgb_SetColor(unsigned char LedId, unsigned long color);//設(shè)置彩燈顏色
void rgb_SetRGB(unsigned char LedId, unsigned long red, unsigned long green, unsigned long blue);//設(shè)置彩燈顏色
void rgb_SendArray();//發(fā)送彩燈數(shù)據(jù)
void WS2812_GPIO_Init(void);
void RGB_LED_Write1(void);
void RGB_LED_Reset(void);
#endif
四移植驗(yàn)證
在自己工程中的main主函數(shù)中,編寫如下。
/*
* Change Logs:
* Date Author Notes
* 2024-06-24 LCKFB-LP first version
*/
#include "board.h"
#include "stdio.h"
#include "bsp_uart.h"
#include "bsp_ws2812.h"
uint8_t Co = 100;
unsigned int buff[]={RED,GREEN,BLUE,WHITE};
int32_t main(void)
{
int i = 0;
board_init();
uart1_init(115200);
WS2812_GPIO_Init();
printf("Start--->rn");
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;
}
}
移植現(xiàn)象:三秒前八個(gè)燈全亮,后面循環(huán)流水燈顯示。
模塊移植成功案例代碼:
鏈接:https://pan.baidu.com/s/1boqb5UkpomK2avKNqAjz-w?pwd=LCKF
提取碼:LCKF