?????? WS2812B是一款貼片RGB燈。由于采用了單總線通訊,所以需要特別關注下它的通訊時序。
?????
調試細節:
?????? 本來以為會是一個比較簡單的調試,結果還是花了很長時間才調試完成。
?????? 首先是關于ESP32的納秒級延時確定,當時按照空指令始終調試不出來。之前在STM32平臺上的nop()函數也不知道怎么用。
?????? 后來發掘出了一個比較簡單的辦法。就是一個個試,然后在main函數中按照1S的頻率打印調試信息來倒推ns級別的延時是否可靠。
?????? 注意:在ESP32不能使用空語句加;來進行空指令延時,需要使用操作語句。
unsigned long ns_delay_value = 0;void delay_100_ns(int data)
{unsigned char i;ns_delay_value = 0;for(i = 0; i < data; i++){ns_delay_value++;}
}void delay_1_us()
{delay_100_ns(10);
}void delay_1_ms()
{long i;for(i = 0; i < 1000; i++){delay_1_us();}
}void delay_1_s()
{long i;for(i = 0; i < 1000; i++){delay_1_ms();}
}
??????? 然后在main函數中按照1S的頻率打印調試信息:
while(1){printf("ws2812B demo system run ...\n");
// vTaskDelay(1000 / portTICK_PERIOD_MS);delay_1_s();}
?????? 基本確定了ns級別延時后,就可以按照時序來寫ws2812的驅動函數啦。
*WS2812B Drive*/
#define WS2812B_GPIO 8
#define WS2812B_GPIO_ACTIVE_LEVEL 1
#define ws2812b_pin_set() gpio_set_level(WS2812B_GPIO, 1)
#define ws2812b_pin_rst() gpio_set_level(WS2812B_GPIO, 0)void ws2812b_writebyte(unsigned char data)
{unsigned char i;for(i = 0; i < 8; i++){if(data & 0X80){ws2812b_pin_set();delay_100_ns(3);ws2812b_pin_rst();delay_100_ns(3);}else{ws2812b_pin_set();delay_100_ns(1);ws2812b_pin_rst();delay_100_ns(3);}data <<= 1;}
}void ws2812b_write_rgb(unsigned char red_value, unsigned char green_value, unsigned char blue_value)
{ws2812b_writebyte(red_value);ws2812b_writebyte(green_value);ws2812b_writebyte(blue_value);
}
?????? 后來發現依然無法驅動,到了晚上才發現自己犯了一個低級錯誤。ESP32的IO口沒有進行初始化配置!
void ws2812b_gpio_init(void)
{gpio_config_t gpio_conf;gpio_conf.intr_type = GPIO_INTR_DISABLE;gpio_conf.mode = GPIO_MODE_OUTPUT;gpio_conf.pin_bit_mask = (1ULL << WS2812B_GPIO);if (WS2812B_GPIO_ACTIVE_LEVEL) {gpio_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;gpio_conf.pull_up_en = GPIO_PULLUP_DISABLE;} else {gpio_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;gpio_conf.pull_up_en = GPIO_PULLUP_ENABLE;}gpio_config(&gpio_conf);
}
?????? 配置完IO口就可以進行WS2812B驅動啦。不過還是出現了一些小bug,比如初始化第一次點燈,綠色燈珠總是會不受控制地自動點亮!后來發現在IO初始化函數前預先執行一次點亮指令就可以消除這個bug!Nice!
void app_main(void)
{ws2812b_write_rgb(0, 255, 0);ws2812b_gpio_init();delay_1_s();ws2812b_write_rgb(20, 20, 20);while(1){printf("ws2812B demo system run ...\n");
// vTaskDelay(1000 / portTICK_PERIOD_MS);delay_1_s();}
}
???????
?????? 至此,ESP32對于WS2812B的驅動函數就調試完成啦。
?????? 對于這個說起來簡單但是異常曲折的小demo項目積累了如下經驗:
????? 1.ESP32的IO也是需要進行初始化配置的。
????? 2.MCU的單指令確實能夠進行粗略的ns級延時,為后續調試一些芯片時序提供了新的方法。
????? 3.ESP32的GPIO8需要使用一個10K電阻上拉3.3V,否則無法進行程序下載。
2023-05-04 細節補充
????? 1.在后續demo項目完善該驅動時,發現會出現初始化后,在別處點燈時,依然會出現亮出綠燈現象。
???? 后來增加了燈珠的復位函數:
void ws2812b_write_reset(void)
{unsigned int i = 0;ws2812b_pin_rst();for(i = 0; i < 300; i++){delay_1_us();}}
?????? 然后初始化變更為:
ws2812b_write_rgb(0, 255, 0);
ws2812b_gpio_init();
ws2812b_write_reset();
ws2812b_write_rgb(20, 20, 20);
?????? 如果需要在別的函數位置電燈,擇執行以下函數即可,親測有效。
ws2812b_write_rgb(0, 0, 0);
ws2812b_write_reset();
ws2812b_write_rgb(0, 0, 20);