stm32【RGB_LED_WS2812灯珠】
RGB_LED 內置驅動IC:WS2812
測試平臺:stm32f103c8t6
庫版本:官方標準庫3.5.0版本
LED規格:RGB-5050
內置IC:ws2812
驅動方式:歸零碼
相比普通的LED燈珠,內置驅動芯片的燈珠在實用性,整體體積,電路設計,程序設計上都有很大的優勢,本文所寫內置驅動IC的WS2812的燈珠是比較常見的一種彩色LED燈珠,通過級聯方式連接每顆LED,電路設計簡單,采用歸零碼輸入彩色數據。
萬能的某寶有很多這類內置驅動的燈珠,購買前記得詢問是否由數據手冊或者規格書等,這對電路設計和程序設計有很大幫助。
注: 文中首次出現的代碼塊會標注[xxx.c]或[xxx.h],表明該代碼是屬于對應的文件,未標注的即為重復出現的
目錄
- RGB_LED 內置驅動IC:WS2812
- 1、電路設計
- 2、程序設計
- 2.1 驅動方式
- 2.2 定時器配置
- 2.3 數據處理與發送
- 2.4 定時器中斷服務函數
- 3、總結
1、電路設計
由于是級聯方式連接相鄰的燈珠,因此電路很簡單,
燈珠管腳▼
規格書描述▼
只要將相鄰燈珠的DOUT和DIN連接在一起即可,這里的104電容并不是必須的
電路原理圖▼
LED1~LED10一路
LED11~LED20一路
這里是設計需求,兩路并聯在一起,同步控制
PCB圖▼
這是一個燈板的PCB,注意左右兩邊接口表明的順序,左邊的DI對應右邊的DO,可以通過左右接口將多個燈板并聯起來控制。
2、程序設計
歸零碼通訊是單線通訊,對時序要求比較嚴格,通過單周期內的高低電平持續時間來判斷數據bit為0或1
規格書描述▼
信息1: 單顆燈珠可接收3Byte(24bit)數據
信息2: 單顆燈珠數據結構G-R-B,高位先發
信息3: 碼元周期,上邊兩張圖都是這款燈珠規格書里的截圖,碼元周期T有兩種描述,分別是2us(500kHz)和1.25us(800kHz),1.25us是網上關于WS2812教程里出現比較多的典型碼元周期,2us似乎是該燈珠特有的,在實際的測試中,兩種周期均可以實現驅動,因此程序以1.25us進行編寫
信息4: 0碼和1碼占空比
| 2us | 14% | 45% |
| 1.25us | 25.6% | 51.2% |
2.1 驅動方式
【程序以T = 1.25us為準】
要想驅動該燈珠,實際上是要實現0碼和1碼的發送時序,能夠產生這樣的時序信號的方式大致有三種:
第一種是使用延時函數在特定延時時間內對輸出管腳進行翻轉操作,這種方式非常占用單片機資源,而且實現1.25us延時的準確度不高
第二種是使用定時器進行PWM輸出,輸出頻率設置為800kHz即可實現1.25us周期循環,通過改變周期內占空比來實現0碼和1碼輸出
第三種是使用SPI,這種方式比較巧妙,使用SPI的clk線和mosi線,通過8分頻可以設置clk時鐘線的輸出頻率(主頻72Mhz),然后采用16byte數據模擬0碼和1碼,這樣輸出頻率為562.5kHz,理論上也是可以驅動的,本人沒有實踐過,該up主的文章【SPI驅動ws2812】有介紹這種方式,感興趣的可以嘗試下。
第二種使用定時器的方式,精度高,只有在更新中斷服務程序才占用系統資源,是比較理想的驅動方式,考慮到STM32單片機的定時器較多,硬件SPI有限(其他拓展功能有可能會使用到SPI),因此最終方案選擇使用定時器產生PWM來驅動燈珠
2.2 定時器配置
避開有特殊外設功能的IO口,這里選擇PB0管腳進行PWM輸出,其對應的定時器是TIM3,輸出通道是CH3
IO口配置為復用推挽輸出,啟動復用時鐘▼
TIM3基礎以及PWM模式配置▼
[ws2812.c] /********************************************************************************* @brief TIM基礎配置以及PWM配置* @param none* @retval none* @retval none*******************************************************************************/ static void TIM_PWM_Config(void) {TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;TIM_OCInitTypeDef TIM_OCInitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);/* Time base configuration */TIM_TimeBaseStructure.TIM_Period = 90-1; // (144 500KHz 2us) (90 800KHz 1.25us)TIM_TimeBaseStructure.TIM_Prescaler = 0;TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);/* PWM1 Mode configuration */TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;TIM_OCInitStructure.TIM_Pulse = 0;TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;TIM_OC3Init(TIM3, &TIM_OCInitStructure);TIM_ARRPreloadConfig(TIM3, ENABLE); //使能TIM_ARR重載,即周期重載TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能TIM_CRR重載,即占空比重載TIM_ITConfig(TIM3,TIM_IT_Update, ENABLE); //使能TIM更新中斷 // TIM_Cmd(TIM3, ENABLE); //使能TIM}注意:周期是從0開始算的,預分頻為0,即不分頻,頻率為72MHz,周期為72MHz / 90 = 800kHz
使能定時器更新中斷,這樣可以在中斷服務函數里更改占空比
配置完成先不使能TIM3,等需要發送數據時再使能定時器
NVIC配置,這個隨意▼
[ws2812.c] /********************************************************************************* @brief 配置嵌套向量中斷控制器NVIC* @param none* @retval none*******************************************************************************/ static void NVIC_TIM3_Config(void) {NVIC_InitTypeDef NVIC_InitStructure;/* Configure one bit for preemption priority */NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);/* 配置TIM3_IRQ中斷為中斷源 */NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure); }到此定時器配置完成
2.3 數據處理與發送
一顆燈珠接收3byte(24bit)數據,當接收完3byte(24bit)數據后,自動整型轉發接下來的數據,高位先發
采用PWM來產生驅動時序,一個周期代表1bit,這1bit代表0或者1則是由周期內的高電平占空比來決定
在定時器配置中,周期設置TIM_ARR = 90
那么0碼占空比設置為20(22%),1碼占空比設置為50(55%)即可
實際測試0碼小于30,1碼大于35都是可以驅動的
首先點亮一個燈珠,使其發出綠光,按數據格式G-R-B,需要發送3byte數據【0xFF0000】,總共24bit的數據,數據處理就是根據24bit數據轉換成占空比數組,然后在中斷服務函數里更新TIM_CCR的值
數據處理和發送函數▼
[ws2812.c]#define DATA_SIZE 0x800 //2k #define DATA_BUF_Address 0x20004800 u8 DATA_BUF[DATA_SIZE] __attribute__ ((at(DATA_BUF_Address)));#define DATA_BIT_0 20 //20 #define DATA_BIT_1 50 //75 /********************************************************************************* @brief 發送數據* @param *buff 緩存基地址* @retval len 發送數據量(n byte)* @retval none*******************************************************************************/ void DATA_Send(u8 *buff, u32 len) {u8 i = 0;u32 j = 0;u32 counter = 0;u8 data;for(j = 0; j < len; j++){data = buff[j];//1byte數據分解成8bytefor(i = 0; i < 8; i++){DATA_BUF[counter] = ((data & 0x80) ? DATA_BIT_1 : DATA_BIT_0);data = data << 1;counter++;}}//初始化結構體ws2812.data_cnt = len*8;ws2812.send_cnt = 0;ws2812.flag = 0;//使能TIM,開始發送數據TIM3->CR1 |= TIM_CR1_CEN; }【DATA_BUF[DATA_SIZE]】數組是一個足夠大的數組,最終的TIM_CCR值緩存數組
直接看發送函數有點難解釋,先看這個函數是如何調用的▼
[ws2812.c] u8 data[3]; /********************************************************************************* @brief 打開文件并讀取文件基礎信息* @param name 文件名稱** @retval 1 模式1* @retval 2 模式2*******************************************************************************/ void test(void) {data[0] = 0xff;data[1] = 0x00;data[2] = 0x00;DATA_Send(data,3); }使用一個u8類型的數組【data[3]】存儲綠燈數據【0xFF0000】
然后把數組地址和數據個數【3】傳遞到發送函數【DATA_Send】
回到【DATA_Send】函數,for(i = 0; i < 8; i++)循環將1byte數據轉換成8byte數據,是占空比的值,存儲在【DATA_BUF[ ]】數組里邊,那么經過三次循環,將【data[3]】分解成【DATA_BUF[24]】個數據
此時【DATA_BUF[24]】各值為
| 50 | 50 | 50 | 50 | 50 | 50 | 50 | 50 |
| 20 | 20 | 20 | 20 | 20 | 20 | 20 | 20 |
| 20 | 20 | 20 | 20 | 20 | 20 | 20 | 20 |
轉換完數據后先初始化一個結構體,然后啟動定時器TIM3
結構體定義▼
2.4 定時器中斷服務函數
在數據發送函數最后的操作是啟動定時器TIM3,具體的占空比更改是在中斷服務程序里實現的▼
[ws2812.c] /********************************************************************************* @brief TIM中斷服務程序* @param none* @retval none*******************************************************************************/ void TIM3_IRQHandler(void) {TIM3->SR = (uint16_t)~TIM_IT_Update; //清除中斷TIM3->CCR3 = DATA_BUF[ws2812.send_cnt]; //更新占空比ws2812.send_cnt++;if(ws2812.send_cnt > ws2812.data_cnt){ //當發送完所需數據之后關閉TIMTIM3->CR1 &= ~((uint16_t)TIM_CR1_CEN); //關閉TIM} }定時器每產生一次中斷,可以理解為發送了1byte數據,因此在中斷函數里更新下一個TIM_CCR值,當發送完24byte數據后,就關閉定時器TIM3,
3、總結
在主函數里調用TIM配置函數后,直接調用測試函數【void test(void)】即可驅動一顆燈珠發綠光▼
(由于左右兩路是并聯的,因此兩個燈珠同步點亮)
改下函數即可控制其他燈珠▼
RGB效果(拍照色差比較嚴重)▼
內置ws2812的彩色LED燈珠的驅動就這么些,具體怎么使用還得看應用場景
總結
以上是生活随笔為你收集整理的stm32【RGB_LED_WS2812灯珠】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python矩阵和向量乘积_矩阵与向量的
- 下一篇: mysql ip 查询工具_IP地址查询