久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 553|回復: 0
打印 上一主題 下一主題
收起左側

[正點原子]WS2812B和WS2811F 驅動技術分享

[復制鏈接]
跳轉到指定樓層
樓主
ID:1148840 發表于 2025-4-24 11:49 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
1,WS2812B和WS2811F簡介
RGBLED驅動芯片有兩個常用的選擇:WS2812B和WS2811F,它們都采用單線歸零碼的通訊方式,數據發送速度可達800Kbps。
芯片在上電復位以后,DIN端接受從控制器傳輸過來的數據,首先送過來的24bit數據被第一個芯片提取后,送到芯片內部的數據鎖存器,剩余的數據經過內部整形處理電路整形放大后通過DO端口開始轉發輸出給下一個級聯的芯片,每經過一個芯片的傳輸,信號減少24bit。芯片采用自動整形轉發技術,使得該芯片的級聯個數不受信號傳送的限制,僅僅受限信號傳輸速度要求。
當各個芯片都收到24bit的數據后,我們再發送一個大于280us的低電平復位信號,所有的芯片再同步發送對應的R、G、B信號,來控制RGBLED燈的紅色、綠色和藍色三種發光二極。我們就可以看見RGBLED燈亮不同的顏色了。
特別說明:WS2812B和WS2811F通訊和級聯方式等,都基本一樣,只是24位數據結構有先后區別。


圖1 WS2812B或WS2811F級聯示意圖


圖2 WS2812B或WS2811F數據傳輸方法

24位的數據結構(WS2812B):按GRB順序,高位在前

圖3 24位的數據結構(WS2812B)

24位的數據結構(WS2811F):按RGB順序,高位在前

圖4 24位的數據結構(WS2811F)
對我們的驅動來說,圖3和圖4是WS2812B和WS2811F的唯一區別,其他部分的代碼編寫是一模一樣的。

WS2812B和WS2811F邏輯0、邏輯1和復位信號的時序如下:

圖5 WS2812B和WS2811F邏輯0、邏輯1和復位信號的時序圖


表1 WS2812B和WS2811F數據傳輸時間表
實際使用中,PWM的占空比為三分之一代表邏輯0,PWM的占空比為三分之二代表邏輯1,這個時間大致即可。
文章開頭說了,數據發送速度可達800Kbps,即每一個數據位傳輸時間就是:1 / 800000s = 1.25us。每個RGB燈數據有24位,所以每一個RGB數據傳輸時間就是:1.25 * 24us = 30us。
假設用1000顆RGB燈組成一個矩陣屏,那么給屏幕刷一幀數據的時間為:1000*30+280us = 30280us,即矩陣屏的幀率為33幀每秒。這個幀率看個視頻是夠了,打游戲可能差點意思,哈哈哈。
特別注意:級聯的燈珠太多,要考慮供電問題。一個LED電流大概是10~20mA,一個RGB燈有三個LED,即30~60mA。
2, 實驗硬件簡介
2.1,RGB燈方案
WS2811F方案的RGB燈,我們使用的是正點原子的BEE BLOCK系列的RGBLED模塊。該模塊設計非常美觀,燈珠夠大,顯示效果很好,預留了燈珠級聯接口。
WS2812B方案的RGB燈,我自己畫了一塊由20顆RGB燈級聯的燈板。注意WS2812B芯片是集成到RGB燈內部了。

圖6 BEE BLOCK系列RGBLED模塊(左) 和 20顆RGB燈的燈板(右)

2.2,主控方案
主控制器使用STM32F103C8T6,這里直接使用正點原子的STM32入門套件BEE BLOCK系列,價格雖然貴一些,但是外觀和品質是真的很好。

圖7 正點原子的STM32入門套件BEE BLOCK系列

2.3,儀表工具
儀表工具使用正點原子的DL16邏輯分析儀,方便觀察WS2812B和WS2811F的時序。

圖8 正點原子的DL16邏輯分析儀

3,實驗代碼
3.1,WS2812B驅動代碼
ws2812b.c代碼如下:
TIM_HandleTypeDef g_tim2_handle = {0};          /* 定時器x句柄 */
DMA_HandleTypeDef g_dma_handle = {0};           /* DMA句柄 */

/* 用于存放10個RGBLED燈的顏色值 */
uint32_t g_rgb888_color[10] =
{
    GRB888_RED,         /* 紅色 */
    GRB888_GREEN,       /* 綠色 */
    GRB888_BLUE,        /* 藍色 */
    GRB888_VIOLET,      /* 紫羅蘭 */
    GRB888_YELLOW,      /* 黃色 */
    GRB888_IRED,        /* 淺紅色 */
    GRB888_ORANGE,      /* 橙色 */
    GRB888_PURPLE,      /* 紫色 */
    GRB888_PING,        /* 粉色 */
    GRB888_CYAN,        /* 青色 */
};

uint16_t g_pixel_buf[LED_NUM][DATA_SIZE]; /* 用于存放RGBLED燈數據對應的比較值 */

/**
* @brief       發送數據給ws2812b
* @param       無
* @retval      無
*/
void ws2812b_dats_send(void)
{
/* 使用DMA將數據發送到定時器的CCRx */
HAL_TIM_PWM_Start_DMA(&g_tim2_handle, TIM_CHANNEL_3,
(uint32_t *)g_pixel_buf, sizeof(g_pixel_buf));
}

/**
* @brief       復位ws2812b
* @note        保持低電平280us以上即可
* @param       無
* @retval      無
*/
void ws2812b_reset(void)
{
/* CCRX設置為0,直接輸出低電平 */
    __HAL_TIM_SetCompare(&g_tim2_handle, TIM_CHANNEL_3, 0);
    delay_us(280);
}

/**
* @brief       將GRB888的顏色值轉換成邏輯1和邏輯0對應的CCRx值并存放到
*               g_pixel_buf里,并發送給CCRx,生成PWM
* @note        可指定第幾個燈
* @param       led_num : 需控制燈的數量
* @param       color  : GRB888顏色值指針
* @retval      無
*/
void ws2812b_display(uint8_t led_num, uint32_t *color_buf)
{
    uint8_t i, j;
    if(led_num > LED_NUM)return;    /* 防止寫入LED數量大于LED總數 */

/* 這里是對 g_pixel_buf[j]寫入一個周期內高電平的持續時間
(是要存放在比較值寄存器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發送到定時器的CCRx中,生成相應波形 */
}

/**
* @brief       ws2812b不顯示顏色,復位狀態
* @param       無
* @retval      無
*/
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相關IO口,以及配置定時器和DMA功能 并使能時鐘
* @param       無
* @retval      無
*/
void ws2812b_init(void)
{
    TIM_OC_InitTypeDeftimx_oc_pwm_chy = {0};  /* 定時器輸出句柄 */
    GPIO_InitTypeDefgpio_init_struct = {0};

    __HAL_RCC_DMA1_CLK_ENABLE();                  /* DMA1時鐘使能 */
    __HAL_RCC_GPIOA_CLK_ENABLE();                 /* 開啟通道y的GPIO時鐘 */
    __HAL_RCC_TIM2_CLK_ENABLE();                   /* 使能定時器時鐘 */

    gpio_init_struct.Pin = GPIO_PIN_2;          /* 通道的GPIO口 */
    gpio_init_struct.Mode = GPIO_MODE_AF_PP;    /* 復用推挽輸出 */
    gpio_init_struct.Pull = GPIO_NOPULL;         /* 無上下拉 */
    gpio_init_struct.Speed =GPIO_SPEED_FREQ_HIGH;     /* 高速 */
    HAL_GPIO_Init(GPIOA, &gpio_init_struct);

    g_tim2_handle.Instance = TIM2;                 /* 定時器x */
    g_tim2_handle.Init.Prescaler = (1 - 1);      /* 定時器分頻 */
    g_tim2_handle.Init.CounterMode = TIM_COUNTERMODE_UP; /* 遞增計數模式 */
    g_tim2_handle.Init.Period = (90 - 1);                   /* 自動重裝載值 */
    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;                      /* 設置比較值,此值用來確定占空比 */
    timx_oc_pwm_chy.OCPolarity =TIM_OCPOLARITY_HIGH;    /* 輸出比較極性為高 */
    timx_oc_pwm_chy.OCIdleState =TIM_OCIDLESTATE_RESET;/* 空閑時輸出低電平 */
HAL_TIM_PWM_ConfigChannel(&g_tim2_handle, &timx_oc_pwm_chy,TIM_CHANNEL_3);
/* 使能CCRX的影子寄存器,當修改CCRX的值時,等產生更新事件在生效 */
    __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;   /* 從內存到外設模式 */
    g_dma_handle.Init.PeriphInc = DMA_PINC_DISABLE;        /* 外設非增量模式 */
    g_dma_handle.Init.MemInc = DMA_MINC_ENABLE;    /* 存儲器增量模式 */
    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;      /* 高優先級 */
    HAL_DMA_Init(&g_dma_handle);

/* 將DMA與timer聯系起來 */
    __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中斷服務函數
* @param       無
* @retval      無
*/
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();
/* 傳輸完成后手動停止PWM */
        HAL_TIM_PWM_Stop_DMA(&g_tim2_handle, TIM_CHANNEL_3);  
    }
}
ws2812b.h代碼如下:
/**************************************************************************/
/* RGBLED的數據高低電平邏輯定義 */
#define HIGH_LEVEL     (uint16_t)60     /* CCR3為占空比為三分之二代表邏輯1 */
#define LOW_LEVEL      (uint16_t)30     /* CCR3為占空比為三分之一代表邏輯0 */

#define LED_NUM         20               /* 燈珠的個數 */
#define DATA_SIZE       24               /* 一個RGB數據的位數,3*8 */
/**************************************************************************/
/* RGB888顏色值 */
#define GRB888_RED         0x00FF00        /* 紅色 */
#define GRB888_GREEN       0xFF0000        /* 綠色 */
#define GRB888_BLUE        0x0000FF        /* 藍色 */
#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        /* 孔雀藍 */
#define GRB888_VIOLET      0x008BFF        /* 紫羅蘭 */
/**************************************************************************/

extern  TIM_HandleTypeDefg_tim2_handle;                 /* 定時器x句柄 */
extern uint32_t g_rgb888_color[10];

/* 函數聲明 */
void ws2812b_init(void);                                    /* 初始化W2812B */
void ws2812b_reset(void);                                   /* 復位W2812B */
/* 寫入多個顏色值到W2812B(控制多個燈) */
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);                             /* 不顯示顏色,關燈 */
3.2,WS2811F驅動代碼
WS2811F的代碼和ws2812b幾乎一樣,只有RGB數據結構順序上有區別。下面把有差異的代碼貼出來。
WS2811F.c有差異部分代碼如下:
/* 用于存放10個RGBLED燈的顏色值 */
uint32_t g_rgb888_color[10] =
{
    RGB888_RED,         /* 紅色 */
    RGB888_GREEN,       /* 綠色 */
    RGB888_BLUE,        /* 藍色 */
    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        /* 藍色 */
#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顏色緩沖區 */

    HAL_Init();                             /* 初始化HAL庫 */
    sys_stm32_clock_init(RCC_PLL_MUL9); /* 設置時鐘, 72Mhz */
    delay_init(72);                        /* 延時初始化 */
    usart_init(115200);                    /* 串口初始化為115200 */
    ws2812b_init();                        /* 初始化RGBLED */

    while (1)
    {
        /* 多個燈珠亮相同顏色,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);
        }
    }
}
在本實驗中,我們根據連接的燈珠數量設置好LED_NUM宏定義。
mian函數中,實現多個燈珠亮相同顏色,共10種顏色。
詳細的代碼可以下載正點原子BEE BLOCK系列RGBLED模塊的資料查看。網址如下:openedv/docs/boards/stm32/beeblock.html
4,實驗現象
1,WS2812B實驗現象

圖9 WS2812B實驗現象


2,WS2811F實驗現象

圖10 WS2811F實驗現象

3,用DL16邏輯分析儀觀察PWM
WS2812B數據結構是GRB888,所以紅色數據是0x00FF00。

圖11 WS2812B時序

WS2811F數據結構是RGB888,所以紅色數據是0xFF0000。

圖12 WS2811F時序
PWM詳細參數如下圖:

圖13 PWM時序信息
PWM周期為1.25us,邏輯1高電平時間為850ns,低電平時間為400ns。所以可以知道邏輯0高電平時間為400ns,低電平時間為850ns。

【正點原子】WS2812B和WS2811F.pdf

1.52 MB, 下載次數: 0, 下載積分: 黑幣 -5

原文章

1,WS2812B.7z

597.23 KB, 下載次數: 0, 下載積分: 黑幣 -5

源碼

2,WS2811F.7z

597.49 KB, 下載次數: 0, 下載積分: 黑幣 -5

源碼

3,RGBLED模塊(IO模擬時序WS2811F).7z

680.97 KB, 下載次數: 0, 下載積分: 黑幣 -5

源碼

評分

參與人數 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎勵!

查看全部評分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復

使用道具 舉報

無效樓層,該帖已經被刪除
您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 在线精品亚洲欧美日韩国产 | 亚洲精品久久久一区二区三区 | 午夜日韩视频 | 国产精品久久一区 | 免费一看一级毛片 | 国产午夜在线 | 狠狠的干 | 精品日韩 | 密室大逃脱第六季大神版在线观看 | 国产精品久久久久久久久污网站 | 精品一区二区三区不卡 | 99亚洲精品| 日韩精品在线免费观看 | 日韩欧美视频 | 久久蜜桃av一区二区天堂 | 黄色网络在线观看 | 成人av在线播放 | 四虎影音 | 国产成人精品视频在线观看 | 日本电影韩国电影免费观看 | 国产精品久久久久久久粉嫩 | 国产高清在线观看 | 国产成人一区二区 | 北条麻妃99精品青青久久主播 | 国产精品亚洲欧美日韩一区在线 | 亚洲一区二区三区四区五区中文 | 91福利在线观看视频 | 久久精品国产a三级三级三级 | 亚洲国产欧美日韩 | 99综合 | 国产激情视频在线观看 | 欧美成人精品在线 | 男人天堂av网 | 国产精品污污视频 | 色婷婷av一区二区三区软件 | 国产欧美精品一区二区三区 | 精品久久精品 | 国产成人亚洲精品自产在线 | 日本成人二区 | 成人在线免费观看 | 午夜无码国产理论在线 |