1,WS2812B和WS2811F簡(jiǎn)介 RGBLED驅(qū)動(dòng)芯片有兩個(gè)常用的選擇:WS2812B和WS2811F,它們都采用單線歸零碼的通訊方式,數(shù)據(jù)發(fā)送速度可達(dá)800Kbps。 芯片在上電復(fù)位以后,DIN端接受從控制器傳輸過(guò)來(lái)的數(shù)據(jù),首先送過(guò)來(lái)的24bit數(shù)據(jù)被第一個(gè)芯片提取后,送到芯片內(nèi)部的數(shù)據(jù)鎖存器,剩余的數(shù)據(jù)經(jīng)過(guò)內(nèi)部整形處理電路整形放大后通過(guò)DO端口開(kāi)始轉(zhuǎn)發(fā)輸出給下一個(gè)級(jí)聯(lián)的芯片,每經(jīng)過(guò)一個(gè)芯片的傳輸,信號(hào)減少24bit。芯片采用自動(dòng)整形轉(zhuǎn)發(fā)技術(shù),使得該芯片的級(jí)聯(lián)個(gè)數(shù)不受信號(hào)傳送的限制,僅僅受限信號(hào)傳輸速度要求。 當(dāng)各個(gè)芯片都收到24bit的數(shù)據(jù)后,我們?cè)侔l(fā)送一個(gè)大于280us的低電平復(fù)位信號(hào),所有的芯片再同步發(fā)送對(duì)應(yīng)的R、G、B信號(hào),來(lái)控制RGBLED燈的紅色、綠色和藍(lán)色三種發(fā)光二極。我們就可以看見(jiàn)RGBLED燈亮不同的顏色了。 特別說(shuō)明:WS2812B和WS2811F通訊和級(jí)聯(lián)方式等,都基本一樣,只是24位數(shù)據(jù)結(jié)構(gòu)有先后區(qū)別。
圖1 WS2812B或WS2811F級(jí)聯(lián)示意圖
圖2 WS2812B或WS2811F數(shù)據(jù)傳輸方法
24位的數(shù)據(jù)結(jié)構(gòu)(WS2812B):按GRB順序,高位在前
圖3 24位的數(shù)據(jù)結(jié)構(gòu)(WS2812B)
24位的數(shù)據(jù)結(jié)構(gòu)(WS2811F):按RGB順序,高位在前
圖4 24位的數(shù)據(jù)結(jié)構(gòu)(WS2811F) 對(duì)我們的驅(qū)動(dòng)來(lái)說(shuō),圖3和圖4是WS2812B和WS2811F的唯一區(qū)別,其他部分的代碼編寫(xiě)是一模一樣的。
WS2812B和WS2811F邏輯0、邏輯1和復(fù)位信號(hào)的時(shí)序如下:
圖5 WS2812B和WS2811F邏輯0、邏輯1和復(fù)位信號(hào)的時(shí)序圖
表1 WS2812B和WS2811F數(shù)據(jù)傳輸時(shí)間表 實(shí)際使用中,PWM的占空比為三分之一代表邏輯0,PWM的占空比為三分之二代表邏輯1,這個(gè)時(shí)間大致即可。 文章開(kāi)頭說(shuō)了,數(shù)據(jù)發(fā)送速度可達(dá)800Kbps,即每一個(gè)數(shù)據(jù)位傳輸時(shí)間就是:1 / 800000s = 1.25us。每個(gè)RGB燈數(shù)據(jù)有24位,所以每一個(gè)RGB數(shù)據(jù)傳輸時(shí)間就是:1.25 * 24us = 30us。 假設(shè)用1000顆RGB燈組成一個(gè)矩陣屏,那么給屏幕刷一幀數(shù)據(jù)的時(shí)間為:1000*30+280us = 30280us,即矩陣屏的幀率為33幀每秒。這個(gè)幀率看個(gè)視頻是夠了,打游戲可能差點(diǎn)意思,哈哈哈。 特別注意:級(jí)聯(lián)的燈珠太多,要考慮供電問(wèn)題。一個(gè)LED電流大概是10~20mA,一個(gè)RGB燈有三個(gè)LED,即30~60mA。 2, 實(shí)驗(yàn)硬件簡(jiǎn)介2.1,RGB燈方案 WS2811F方案的RGB燈,我們使用的是正點(diǎn)原子的BEE BLOCK系列的RGBLED模塊。該模塊設(shè)計(jì)非常美觀,燈珠夠大,顯示效果很好,預(yù)留了燈珠級(jí)聯(lián)接口。 WS2812B方案的RGB燈,我自己畫(huà)了一塊由20顆RGB燈級(jí)聯(lián)的燈板。注意WS2812B芯片是集成到RGB燈內(nèi)部了。
圖6 BEE BLOCK系列RGBLED模塊(左) 和 20顆RGB燈的燈板(右)
2.2,主控方案 主控制器使用STM32F103C8T6,這里直接使用正點(diǎn)原子的STM32入門(mén)套件BEE BLOCK系列,價(jià)格雖然貴一些,但是外觀和品質(zhì)是真的很好。
圖7 正點(diǎn)原子的STM32入門(mén)套件BEE BLOCK系列
2.3,儀表工具 儀表工具使用正點(diǎn)原子的DL16邏輯分析儀,方便觀察WS2812B和WS2811F的時(shí)序。
圖8 正點(diǎn)原子的DL16邏輯分析儀
3,實(shí)驗(yàn)代碼3.1,WS2812B驅(qū)動(dòng)代碼 ws2812b.c代碼如下: TIM_HandleTypeDef g_tim2_handle = {0}; /* 定時(shí)器x句柄 */ DMA_HandleTypeDef g_dma_handle = {0}; /* DMA句柄 */
/* 用于存放10個(gè)RGBLED燈的顏色值 */ uint32_t g_rgb888_color[10] = { GRB888_RED, /* 紅色 */ GRB888_GREEN, /* 綠色 */ GRB888_BLUE, /* 藍(lán)色 */ GRB888_VIOLET, /* 紫羅蘭 */ GRB888_YELLOW, /* 黃色 */ GRB888_IRED, /* 淺紅色 */ GRB888_ORANGE, /* 橙色 */ GRB888_PURPLE, /* 紫色 */ GRB888_PING, /* 粉色 */ GRB888_CYAN, /* 青色 */ };
uint16_t g_pixel_buf[LED_NUM][DATA_SIZE]; /* 用于存放RGBLED燈數(shù)據(jù)對(duì)應(yīng)的比較值 */
/** * @brief 發(fā)送數(shù)據(jù)給ws2812b * @param 無(wú) * @retval 無(wú) */ void ws2812b_dats_send(void) { /* 使用DMA將數(shù)據(jù)發(fā)送到定時(shí)器的CCRx */ HAL_TIM_PWM_Start_DMA(&g_tim2_handle, TIM_CHANNEL_3, (uint32_t *)g_pixel_buf, sizeof(g_pixel_buf)); }
/** * @brief 復(fù)位ws2812b * @note 保持低電平280us以上即可 * @param 無(wú) * @retval 無(wú) */ void ws2812b_reset(void) { /* CCRX設(shè)置為0,直接輸出低電平 */ __HAL_TIM_SetCompare(&g_tim2_handle, TIM_CHANNEL_3, 0); delay_us(280); }
/** * @brief 將GRB888的顏色值轉(zhuǎn)換成邏輯1和邏輯0對(duì)應(yīng)的CCRx值并存放到 * g_pixel_buf里,并發(fā)送給CCRx,生成PWM * @note 可指定第幾個(gè)燈 * @param led_num : 需控制燈的數(shù)量 * @param color : GRB888顏色值指針 * @retval 無(wú) */ void ws2812b_display(uint8_t led_num, uint32_t *color_buf) { uint8_t i, j; if(led_num > LED_NUM)return; /* 防止寫(xiě)入LED數(shù)量大于LED總數(shù) */
/* 這里是對(duì) g_pixel_buf[j]寫(xiě)入一個(gè)周期內(nèi)高電平的持續(xù)時(shí)間 (是要存放在比較值寄存器CCR的值)*/ for(i = 0; i < led_num; i++) { for(j = 0; j < DATA_SIZE; j++) { g_pixel_buf[j] = (((color_buf << j) & 0x800000) ? HIGH_LEVEL : LOW_LEVEL); } }
ws2812b_dats_send(); /* 將g_pixel_buf發(fā)送到定時(shí)器的CCRx中,生成相應(yīng)波形 */ }
/** * @brief ws2812b不顯示顏色,復(fù)位狀態(tài) * @param 無(wú) * @retval 無(wú) */ void ws2812b_show_black(void) { uint32_t rgb_buf[LED_NUM]; for(int j = 0; j < LED_NUM; j++) { rgb_buf[j] = GRB888_BLACK; } ws2812b_display(LED_NUM, rgb_buf); /* RGBLED燈光顯示 */ }
/** * @brief 初始化ws2812b相關(guān)IO口,以及配置定時(shí)器和DMA功能 并使能時(shí)鐘 * @param 無(wú) * @retval 無(wú) */ void ws2812b_init(void) { TIM_OC_InitTypeDeftimx_oc_pwm_chy = {0}; /* 定時(shí)器輸出句柄 */ GPIO_InitTypeDefgpio_init_struct = {0};
__HAL_RCC_DMA1_CLK_ENABLE(); /* DMA1時(shí)鐘使能 */ __HAL_RCC_GPIOA_CLK_ENABLE(); /* 開(kāi)啟通道y的GPIO時(shí)鐘 */ __HAL_RCC_TIM2_CLK_ENABLE(); /* 使能定時(shí)器時(shí)鐘 */
gpio_init_struct.Pin = GPIO_PIN_2; /* 通道的GPIO口 */ gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* 復(fù)用推挽輸出 */ gpio_init_struct.Pull = GPIO_NOPULL; /* 無(wú)上下拉 */ gpio_init_struct.Speed =GPIO_SPEED_FREQ_HIGH; /* 高速 */ HAL_GPIO_Init(GPIOA, &gpio_init_struct);
g_tim2_handle.Instance = TIM2; /* 定時(shí)器x */ g_tim2_handle.Init.Prescaler = (1 - 1); /* 定時(shí)器分頻 */ g_tim2_handle.Init.CounterMode = TIM_COUNTERMODE_UP; /* 遞增計(jì)數(shù)模式 */ g_tim2_handle.Init.Period = (90 - 1); /* 自動(dòng)重裝載值 */ g_tim2_handle.Init.ClockDivision =TIM_CLOCKDIVISION_DIV1; g_tim2_handle.Init.AutoReloadPreload =TIM_AUTORELOAD_PRELOAD_DISABLE; HAL_TIM_PWM_Init(&g_tim2_handle); /* 初始化PWM */
timx_oc_pwm_chy.OCMode = TIM_OCMODE_PWM1; /* 模式選擇PWM1 */ timx_oc_pwm_chy.Pulse = 0; /* 設(shè)置比較值,此值用來(lái)確定占空比 */ timx_oc_pwm_chy.OCPolarity =TIM_OCPOLARITY_HIGH; /* 輸出比較極性為高 */ timx_oc_pwm_chy.OCIdleState =TIM_OCIDLESTATE_RESET;/* 空閑時(shí)輸出低電平 */ HAL_TIM_PWM_ConfigChannel(&g_tim2_handle, &timx_oc_pwm_chy,TIM_CHANNEL_3); /* 使能CCRX的影子寄存器,當(dāng)修改CCRX的值時(shí),等產(chǎn)生更新事件在生效 */ __HAL_TIM_ENABLE_OCxPRELOAD(&g_tim2_handle, TIM_CHANNEL_3);
g_dma_handle.Instance = DMA1_Channel1; /* DMA1通道1 */ g_dma_handle.Init.Direction =DMA_MEMORY_TO_PERIPH; /* 從內(nèi)存到外設(shè)模式 */ g_dma_handle.Init.PeriphInc = DMA_PINC_DISABLE; /* 外設(shè)非增量模式 */ g_dma_handle.Init.MemInc = DMA_MINC_ENABLE; /* 存儲(chǔ)器增量模式 */ g_dma_handle.Init.PeriphDataAlignment= DMA_PDATAALIGN_HALFWORD;/* 16位 */ g_dma_handle.Init.MemDataAlignment =DMA_MDATAALIGN_BYTE; /* 16位 */ g_dma_handle.Init.Mode = DMA_NORMAL; /* 普通模式 */ g_dma_handle.Init.Priority = DMA_PRIORITY_HIGH; /* 高優(yōu)先級(jí) */ HAL_DMA_Init(&g_dma_handle);
/* 將DMA與timer聯(lián)系起來(lái) */ __HAL_LINKDMA(&g_tim2_handle, hdma[TIM_DMA_ID_CC3], g_dma_handle);
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 1, 1); HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
ws2812b_show_black(); }
/** * @brief DMA1通道1中斷服務(wù)函數(shù) * @param 無(wú) * @retval 無(wú) */ void DMA1_Channel1_IRQHandler(void) { if(__HAL_DMA_GET_FLAG(&g_dma_handle, __HAL_DMA_GET_TC_FLAG_INDEX(&g_dma_handle)) != RESET) { __HAL_DMA_CLEAR_FLAG(&g_dma_handle, __HAL_DMA_GET_TC_FLAG_INDEX(&g_dma_handle));
ws2812b_reset(); /* 傳輸完成后手動(dòng)停止PWM */ HAL_TIM_PWM_Stop_DMA(&g_tim2_handle, TIM_CHANNEL_3); } } ws2812b.h代碼如下: /**************************************************************************/ /* RGBLED的數(shù)據(jù)高低電平邏輯定義 */ #define HIGH_LEVEL (uint16_t)60 /* CCR3為占空比為三分之二代表邏輯1 */ #define LOW_LEVEL (uint16_t)30 /* CCR3為占空比為三分之一代表邏輯0 */
#define LED_NUM 20 /* 燈珠的個(gè)數(shù) */ #define DATA_SIZE 24 /* 一個(gè)RGB數(shù)據(jù)的位數(shù),3*8 */ /**************************************************************************/ /* RGB888顏色值 */ #define GRB888_RED 0x00FF00 /* 紅色 */ #define GRB888_GREEN 0xFF0000 /* 綠色 */ #define GRB888_BLUE 0x0000FF /* 藍(lán)色 */ #define GRB888_BLACK 0x000000 /* 黑色 */ #define GRB888_WHITE 0xFFFFFF /* 白色 */ #define GRB888_YELLOW 0xFFFF00 /* 黃色 */ #define GRB888_IRED 0x5CCD5C /* 淺紅色 */ #define GRB888_ORANGE 0xA5FF00 /* 橙色 */ #define GRB888_PURPLE 0x008080 /* 紫色 */ #define GRB888_PING 0xB6FFC1 /* 淺粉色 */ #define GRB888_CYAN 0xFF00FF /* 青色 */ #define GRB888_PBLUE 0x80008C /* 孔雀藍(lán) */ #define GRB888_VIOLET 0x008BFF /* 紫羅蘭 */ /**************************************************************************/
extern TIM_HandleTypeDefg_tim2_handle; /* 定時(shí)器x句柄 */ extern uint32_t g_rgb888_color[10];
/* 函數(shù)聲明 */ void ws2812b_init(void); /* 初始化W2812B */ void ws2812b_reset(void); /* 復(fù)位W2812B */ /* 寫(xiě)入多個(gè)顏色值到W2812B(控制多個(gè)燈) */ void ws2812b_display(uint8_t led_num, uint32_t *color); uint32_t color_change_brigh(uint32_t rgb, float k); /* 改變顏色的亮度值 */ void ws2812b_show_black(void); /* 不顯示顏色,關(guān)燈 */ 3.2,WS2811F驅(qū)動(dòng)代碼 WS2811F的代碼和ws2812b幾乎一樣,只有RGB數(shù)據(jù)結(jié)構(gòu)順序上有區(qū)別。下面把有差異的代碼貼出來(lái)。 WS2811F.c有差異部分代碼如下: /* 用于存放10個(gè)RGBLED燈的顏色值 */ uint32_t g_rgb888_color[10] = { RGB888_RED, /* 紅色 */ RGB888_GREEN, /* 綠色 */ RGB888_BLUE, /* 藍(lán)色 */ RGB888_VIOLET, /* 紫羅蘭 */ RGB888_YELLOW, /* 黃色 */ RGB888_VRED, /* 朱紅色 */ RGB888_ORANGE, /* 橙色 */ RGB888_PURPLE, /* 紫色 */ RGB888_PGREEN, /* 孔雀綠 */ RGB888_CYAN, /* 青色 */ }; WS2811F.h有差異部分代碼如下: /**************************************************************************/ /* RGB888顏色值 */ #define RGB888_RED 0xFF0000 /* 紅色 */ #define RGB888_GREEN 0x00FF00 /* 綠色 */ #define RGB888_BLUE 0x0000FF /* 藍(lán)色 */ #define RGB888_BLACK 0x000000 /* 黑色 */ #define RGB888_WHITE 0xFFFFFF /* 白色 */ #define RGB888_YELLOW 0xFFFF00 /* 黃色 */ #define RGB888_VRED 0xFF4D00 /* 朱紅色 */ #define RGB888_ORANGE 0xFFA500 /* 橙色 */ #define RGB888_PURPLE 0x800080 /* 紫色 */ #define RGB888_PING 0xFFC0CB /* 粉色 */ #define RGB888_CYAN 0x00FFFF /* 青色 */ #define RGB888_PGREEN 0x00A15C /* 孔雀綠 */ #define RGB888_VIOLET 0x8B00FF /* 紫羅蘭 */ /**************************************************************************/ 3.3,main.c代碼 int main(void) { uint8_t i = 0, j = 0; uint32_t rgb_buf[LED_NUM]; /* 各燈珠RGB顏色緩沖區(qū) */
HAL_Init(); /* 初始化HAL庫(kù) */ sys_stm32_clock_init(RCC_PLL_MUL9); /* 設(shè)置時(shí)鐘, 72Mhz */ delay_init(72); /* 延時(shí)初始化 */ usart_init(115200); /* 串口初始化為115200 */ ws2812b_init(); /* 初始化RGBLED */
while (1) { /* 多個(gè)燈珠亮相同顏色,10種顏色 */ for(i = 0; i < 10; i++) { for(j = 0; j < LED_NUM; j++) { rgb_buf[j] = g_rgb888_color; }
ws2812b_display(LED_NUM, rgb_buf); /* RGBLED燈光顯示 */ delay_ms(500); } } } 在本實(shí)驗(yàn)中,我們根據(jù)連接的燈珠數(shù)量設(shè)置好LED_NUM宏定義。 mian函數(shù)中,實(shí)現(xiàn)多個(gè)燈珠亮相同顏色,共10種顏色。 詳細(xì)的代碼可以下載正點(diǎn)原子BEE BLOCK系列RGBLED模塊的資料查看。網(wǎng)址如下:openedv/docs/boards/stm32/beeblock.html 4,實(shí)驗(yàn)現(xiàn)象1,WS2812B實(shí)驗(yàn)現(xiàn)象
圖9 WS2812B實(shí)驗(yàn)現(xiàn)象
2,WS2811F實(shí)驗(yàn)現(xiàn)象
圖10 WS2811F實(shí)驗(yàn)現(xiàn)象
3,用DL16邏輯分析儀觀察PWM WS2812B數(shù)據(jù)結(jié)構(gòu)是GRB888,所以紅色數(shù)據(jù)是0x00FF00。
圖11 WS2812B時(shí)序
WS2811F數(shù)據(jù)結(jié)構(gòu)是RGB888,所以紅色數(shù)據(jù)是0xFF0000。
圖12 WS2811F時(shí)序 PWM詳細(xì)參數(shù)如下圖:
圖13 PWM時(shí)序信息 PWM周期為1.25us,邏輯1高電平時(shí)間為850ns,低電平時(shí)間為400ns。所以可以知道邏輯0高電平時(shí)間為400ns,低電平時(shí)間為850ns。
|