目錄
一、簡介
二、所需材料
三、官方例程
四、使用方法
4.1 RMT初始化
4.2 WS2812初始化
4.3 點(diǎn)亮WS2812
五、LED顏色漸變
5.1 第一種實(shí)現(xiàn)方法
5.2 第二種實(shí)現(xiàn)方法
5.3 彩虹跑馬燈
一、簡介
????????官方關(guān)于RMT的介紹:RMT(紅外遙控器)是一個(gè)紅外發(fā)送/接收控制器, 其特殊設(shè)計(jì)支持生成各類信號(hào)。紅外遙控發(fā)射器從內(nèi)置的 RAM(隨機(jī)存取存儲(chǔ)器)區(qū)中讀取連續(xù)的脈沖碼, 并對(duì)輸出信號(hào)進(jìn)行載波調(diào)制。盡管RMT外設(shè)主要用于遠(yuǎn)程紅外應(yīng)用,由于其靈活的數(shù)據(jù)格式,RMT同樣可支持其它協(xié)議。WS2812是集成了驅(qū)動(dòng)電路和單線控制的數(shù)字RGB LED,其協(xié)議數(shù)據(jù)格式兼容于RMT外設(shè)。
? ? ? ? 詳細(xì)參考:ESP-IDF 編程指南 Remote Control (RMT)
????????由于RMT的靈活特性,自然也可以編程以用于控制WS2812燈條。
二、所需材料
平臺(tái):VScode+ESP-IDF?
ESP32開發(fā)板? ? ? ? ????????×1
WS2812燈條? ? ? ? ? ? ? ? ?×1
連接線? ? ? ? ? ? ? ? ? ? ? ? ? ?若干
三、官方例程
????????官方給出了相關(guān)的庫以及相應(yīng)的參考例程,那只要學(xué)會(huì)怎么用輪子就可以了。
????????首先?ctrl+shift+p?打開命令面板,鍵入?ESP-IDF show examples projects?:
打開ESP-IDF example界面,找到 led_strip 例程:
點(diǎn)擊 使用例程i2s_adc_dac創(chuàng)建項(xiàng)目就可以了。
? ? ? ?
四、使用方法
4.1 RMT初始化
? ? ? ? 對(duì)RMT的初始化需要設(shè)置?rmt_config_t?中的相關(guān)參數(shù),根據(jù)官方的說明:
填好相關(guān)參數(shù)后,需要調(diào)用函數(shù)?rmt_config()???????以使初始化參數(shù)有效和函數(shù)?rmt_driver_install()?安裝驅(qū)動(dòng)。相應(yīng)代碼:
// 使用默認(rèn)參數(shù)填入rmt_config_t結(jié)構(gòu)體rmt_config_t config = RMT_DEFAULT_CONFIG_TX(CONFIG_EXAMPLE_RMT_TX_GPIO, RMT_TX_CHANNEL);// 將時(shí)鐘設(shè)置為40MHzconfig.clk_div = 2;// 調(diào)用兩個(gè)函數(shù)完成初始化ESP_ERROR_CHECK(rmt_config(&config));ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0));
4.2 WS2812初始化
? ? ? ? WS2812的初始化簡單一點(diǎn):
// install ws2812 driver 安裝ws2812驅(qū)動(dòng)led_strip_config_t strip_config = LED_STRIP_DEFAULT_CONFIG(CONFIG_EXAMPLE_STRIP_LED_NUMBER, (led_strip_dev_t)config.channel);led_strip_t *strip = led_strip_new_rmt_ws2812(&strip_config);if (!strip) { ESP_LOGE(TAG, "install WS2812 driver failed");}// Clear LED strip (turn off all LEDs)關(guān)閉所有ws2812ESP_ERROR_CHECK(strip->clear(strip, 100));
????????根據(jù)?led_strip_config_t 的定義,該結(jié)構(gòu)體的第一個(gè)參數(shù)為WS2812燈的數(shù)量,第二個(gè)參數(shù)為RMT的通道值。
/*** @brief LED Strip Configuration Type**/typedef struct { uint32_t max_leds; /*!< Maximum LEDs in a single strip */ led_strip_dev_t dev; /*!< LED strip device (e.g. RMT channel, PWM channel, etc) */} led_strip_config_t;
這樣就完成了初始化,可以開始使用了。
4.3 點(diǎn)亮WS2812
????????使用 led_strip_s 結(jié)構(gòu)體中的 set_pixel 函數(shù)設(shè)置各個(gè)燈珠的8位RGB值。使用該函數(shù)逐一設(shè)置每個(gè)燈珠的值,燈珠的位置從0開始計(jì)數(shù),每調(diào)用一次設(shè)置一個(gè)燈珠。
? ? ? ? 設(shè)置好燈珠顏色后,調(diào)用 refresh 函數(shù)將顏色更新到燈條上。
/*** @brief Set RGB for a specific pixel 設(shè)置特定燈珠的RGB值** @param strip: LED strip WS2812的結(jié)構(gòu)體* @param index: index of pixel to set 需要設(shè)置的燈的位置下標(biāo),從0開始* @param red: red part of color 紅色的值* @param green: green part of color 綠色的值* @param blue: blue part of color 藍(lán)色的值** @return* - ESP_OK: Set RGB for a specific pixel successfully* - ESP_ERR_INVALID_ARG: Set RGB for a specific pixel failed because of invalid parameters* - ESP_FAIL: Set RGB for a specific pixel failed because other error occurred*/esp_err_t (*set_pixel)(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue);/*** @brief Refresh memory colors to LEDs 用內(nèi)存中的顏色更新LEDs** @param strip: LED strip WS2812的結(jié)構(gòu)體* @param timeout_ms: timeout value for refreshing task 更新任務(wù)超時(shí)的值** @return* - ESP_OK: Refresh successfully* - ESP_ERR_TIMEOUT: Refresh failed because of timeout* - ESP_FAIL: Refresh failed because some other error occurred** @note:* After updating the LED colors in the memory, a following invocation of this API is needed to flush colors to strip.* 在更新內(nèi)存中的LED顏色值后,需要調(diào)用該API將顏色更新到燈條上。*/esp_err_t (*refresh)(led_strip_t *strip, uint32_t timeout_ms);
簡單使用:
uint32_t Green=100, Red=100, Blue=100;for(int j=0; j < LED_Number; j ++){ // 設(shè)置ws2812的RGB的值 ESP_ERROR_CHECK(strip->set_pixel(strip, j, Red, Green, Blue));}// 給WS2812發(fā)送RGB的值ESP_ERROR_CHECK(strip->refresh(strip, 100));
五、LED顏色漸變
? ? ? ? 我寫了一個(gè)顏色漸變的程序,三種顏色的值按照正弦變化,兩兩錯(cuò)開120°。原理如圖
????????根據(jù)這個(gè)原理設(shè)計(jì)程序,LED燈顏色在漸變時(shí)的過度就會(huì)十分自然。LED所顯示的顏色依次為紅、橙、黃、綠、靛、紫。
具體代碼如下:
5.1 第一種實(shí)現(xiàn)方法
? ? ? ? 第一種方法預(yù)先計(jì)算好正弦函數(shù)的樣本值,并存儲(chǔ)在一個(gè)數(shù)組中,然后依次把元素的值作為RGB的值發(fā)送給LED燈條,實(shí)現(xiàn)顏色漸變效果。
????????函數(shù)聲明(放在頭文件中):
/** * @brief 所有燈顏色漸變效果,注:必須同時(shí)包含SinValue[]數(shù)組才能使用 * * @param strip LED燈帶的結(jié)構(gòu)體 * @param LED_Number 點(diǎn)亮的LED的數(shù)量 * @param GradualChangeRate LED漸變的速度,數(shù)值越大,速度越慢,一般為50 */void WS2812B_ColourGradualChange1(led_strip_t *strip,uint16_t LED_Number,uint16_t GradualChangeRate);
函數(shù)定義(放在庫文件中):
/** * @brief sin()函數(shù)從0到2π的樣本值,一共255個(gè)點(diǎn),最大值為255,最小值為0 * * 離散信號(hào)函數(shù):SinValue(k)=(255*sin(2*k*π/255)+255)/2 (四舍五入取整數(shù)) * */uint8_t const SinValue[256]={ 128, 131, 134, 137, 140, 143, 147, 150, 153, 156, 159, 162, 165, 168, 171, 174, 177, 180, 182, 185, 188, 191, 194, 196, 199, 201, 204, 206, 209, 211, 214, 216, 218, 220, 223, 225, 227, 229, 230, 232, 234, 236, 237, 239, 240, 242, 243, 245, 246, 247, 248, 249, 250, 251, 252, 252, 253, 253, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 254, 253, 253, 252, 251, 250, 249, 249, 247, 246, 245, 244, 243, 241, 240, 238, 237, 235, 233, 231, 229, 228, 226, 224, 221, 219, 217, 215, 212, 210, 208, 205, 203, 200, 198, 195, 192, 189, 187, 184, 181, 178, 175, 172, 169, 166, 163, 160, 157, 154, 151, 148, 145, 142, 139, 136, 132, 129, 126, 123, 120, 117, 114, 111, 107, 104, 101, 98, 95, 92, 89, 86, 83, 80, 77, 74, 72, 69, 66, 63, 61, 58, 55, 53, 50, 48, 45, 43, 41, 38, 36, 34, 32, 30, 28, 26, 24, 22, 21, 19, 17, 16, 14, 13, 12, 10, 9, 8, 7, 6, 5, 4, 4, 3, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 5, 6, 6, 7, 9, 10, 11, 12, 14, 15, 17, 18, 20, 21, 23, 25, 27, 29, 31, 33, 35, 37, 40, 42, 44, 47, 49, 52, 54, 57, 59, 62, 65, 67, 70, 73, 76, 79, 82, 85, 88, 91, 94, 97, 100, 103, 106, 109, 112, 115, 118, 121, 125, 128};void WS2812B_ColourGradualChange1(led_strip_t *strip, uint16_t LED_Number, uint16_t GradualChangeRate){ uint32_t Green=0,Red=0,Blue=0; uint8_t i,ir,ib; for(i=0;i<255;i++) { ir=i+85; ib=i+170; Green=SinValue[i]; Red=SinValue[ir]; Blue=SinValue[ib]; for(int j=0; j < LED_Number; j ++){ // 設(shè)置ws2812的RGB的值 ESP_ERROR_CHECK(strip->set_pixel(strip, j, Red, Green, Blue)); } // 給WS2812發(fā)送RGB的值 ESP_ERROR_CHECK(strip->refresh(strip, 100)); vTaskDelay(pdMS_TO_TICKS(GradualChangeRate)); }}
?將代碼放在庫中便可直接調(diào)用。
5.2 第二種實(shí)現(xiàn)方法
? ? ? ? 第二種方法使用 math.h 中的sin()函數(shù),實(shí)時(shí)計(jì)算RGB各自的值,并發(fā)送給LED燈條。
????????函數(shù)聲明(放在頭文件中):
/** * @brief 所有燈顏色漸變效果 * * @param strip:LED燈帶的結(jié)構(gòu)體 * @param LED_Number:點(diǎn)亮的LED的數(shù)量 * @param GradualChangeRate:LED漸變的速度,數(shù)值越大,速度越慢,一般為50 */void WS2812B_ColourGradualChange2(led_strip_t *strip,uint16_t LED_Number,uint16_t GradualChangeRate);
函數(shù)定義(放在庫文件中):
// 必須包含math.h庫#include <math.h>void WS2812B_ColourGradualChange2(led_strip_t *strip,uint16_t LED_Number,uint16_t GradualChangeRate){ uint32_t Green=0,Red=0,Blue=0; for(uint16_t i=0; i<628; i++) { // 使用sin()函數(shù)分別計(jì)算三原色的值 Green = (int)(127*sin(i/100.0)+127); Red = (int)(127*sin((i+209.3)/100)+127); Blue = (int)(127*sin((i+418.7)/100)+127); for(int j=0; j < LED_Number; j ++){ // 設(shè)置ws2812的RGB的值 ESP_ERROR_CHECK(strip->set_pixel(strip, j, Red, Green, Blue)); } // 給WS2812發(fā)送RGB的值 ESP_ERROR_CHECK(strip->refresh(strip, 100)); vTaskDelay(pdMS_TO_TICKS(GradualChangeRate)); }}
兩種實(shí)現(xiàn)方法的效果差別不大
5.3 彩虹跑馬燈
? ? ? ? 依舊使用前述原理實(shí)現(xiàn)彩虹跑馬燈效果,每個(gè)燈的顏色均不同。
? ? ? ? 函數(shù)聲明(放在頭文件中):
/** * @brief 彩虹跑馬燈效果 * * @param strip:LED燈帶的結(jié)構(gòu)體 * @param LED_Number:點(diǎn)亮的LED的數(shù)量 * @param GradualChangeRate:LED漸變的速度,數(shù)值越大,速度越慢,一般為50 */void WS2812B_TrottingHorseLamp1(led_strip_t *strip,uint16_t LED_Number,uint16_t GradualChangeRate);
? ? ? ? 函數(shù)定義(放在庫文件中):
void WS2812B_TrottingHorseLamp1(led_strip_t *strip, uint16_t LED_Number, uint16_t GradualChangeRate){ uint32_t Green=0,Red=0,Blue=0; uint8_t i,ir,ib; for(i=0;i<256;i++) { ir=i+85; ib=i+170; for(int j=0; j < LED_Number; j ++){ // 根據(jù)燈珠的位置計(jì)算RGB的值 Green = SinValue[(i+10*j)%256]; Red = SinValue[(ir+10*j)%256]; Blue = SinValue[(ib+10*j)%256]; // 設(shè)置ws2812的RGB的值 ESP_ERROR_CHECK(strip->set_pixel(strip, j, Red, Green, Blue)); } // 給WS2812發(fā)送RGB的值 ESP_ERROR_CHECK(strip->refresh(strip, 100)); vTaskDelay(pdMS_TO_TICKS(GradualChangeRate)); }}
????????這樣便可實(shí)現(xiàn)平滑的彩虹跑馬燈效果。