1 Star 2 Fork 0

Pinno/drv_ws2812b

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
drv_ws2812b.c 19.78 KB
一键复制 编辑 原始数据 按行查看 历史
fuhua-chen 提交于 2022-06-20 23:48 +08:00 . 修复bug
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
#include "drv_ws2812b.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "driver/gpio.h"
#include "esp_event.h"
#if (WS2812B_DRV_MODE == WS2812B_DRV_MODE_SPI)
#include "driver/spi_master.h"
uint8_t ws2812b_buffer[WS2812B_PIXEL_NUM][WS2812B_GRB] = {0};
uint32_t ws2812b_buffer_size = WS2812B_PIXEL_NUM*WS2812B_GRB;
/**************************************************************
*
* @brief spi设备句柄
*
* ************************************************************/
static spi_device_handle_t ws2812b_spi;
/**************************************************************
*
* @brief spi驱动方式的初始化
* @param pin_mosi spi mosi 引脚号,用于输出驱动信号,其他引脚
* 不需要设置
* @param dma_ch dma通道号,用于发送数据
*
* ************************************************************/
void ws2812b_spi_init(uint32_t pin_mosi, uint32_t dma_ch)
{
esp_err_t ret;
spi_bus_config_t buscfg={
.miso_io_num = -1,
.mosi_io_num = pin_mosi,
.sclk_io_num = -1,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = SOC_SPI_MAXIMUM_BUFFER_SIZE,
.flags = SPICOMMON_BUSFLAG_MASTER,
.intr_flags = 0
};
spi_device_interface_config_t devcfg={
.clock_speed_hz = 8*1000*1000, //Clock out at 8 MHz
.mode = 0, //SPI mode 0
.spics_io_num = -1, //CS pin
.queue_size = 7, //We want to be able to queue 7 transactions at a time
};
ret=spi_bus_initialize(WS2812B_SPI_HOST, &buscfg, dma_ch);
ESP_ERROR_CHECK(ret);
ret=spi_bus_add_device(WS2812B_SPI_HOST, &devcfg, &ws2812b_spi);
ESP_ERROR_CHECK(ret);
}
/*************************************************************************************************************
*
* @brief spi驱动方式发送数据
* @param data 数据缓存指针
* @param len 数据长度
*
* ***********************************************************************************************************/
void ws2812b_spi_send(const uint8_t *data, uint32_t len)
{
esp_err_t ret;
spi_transaction_t t;
if (len==0) return;
memset(&t, 0, sizeof(t));
t.length=len*8;
t.tx_buffer=data;
t.user=(void*)1;
//ret=spi_device_polling_transmit(ws2812b_spi, &t);
ret=spi_device_transmit(ws2812b_spi, &t);
assert(ret==ESP_OK);
}
/*************************************************************************************************************
*
* @brief 设置单个像素的某bit值
* @param n 像素点位置
* @param bit 像素点的某个位
* @param value 像素点某个位左移后的取值 ((grb << i) & 0x800000)用于判别输出值
*
* **********************************************************************************************************/
void ws2812b_set_pixel_bit(uint32_t n, uint8_t bit, uint32_t value)
{
ws2812b_buffer[n][bit] = value ? WS2812B_SPI_TH : WS2812B_SPI_TL;
}
/*************************************************************************************************************
*
* @brief show all pixel to display
*
* **********************************************************************************************************/
void ws2812b_show(void)
{
ws2812b_spi_send((const uint8_t*)ws2812b_buffer, sizeof(ws2812b_buffer));
}
#elif (WS2812B_DRV_MODE == WS2812B_DRV_MODE_RMT)
#include "driver/rmt.h"
rmt_item32_t ws2812b_buffer[WS2812B_PIXEL_NUM*WS2812B_GRB];
uint32_t ws2812b_buffer_size = WS2812B_PIXEL_NUM*WS2812B_GRB;
/*************************************************************************************************************
*
* @brief rmt驱动方式的初始化
* @param pin_rmt rmt 信号输出引脚号,用于输出驱动信号,其他引脚
* 不需要设置
* @param rmt_ch rmt通道号,用于发送数据
*
* ***********************************************************************************************************/
void ws2812b_rmt_init(uint32_t pin_rmt, uint32_t rmt_ch)
{
rmt_config_t config;
config.rmt_mode = RMT_MODE_TX;
config.channel = rmt_ch;
config.gpio_num = pin_rmt;
config.mem_block_num = 3;
config.tx_config.loop_en = false;
config.tx_config.carrier_en = false;
config.tx_config.idle_output_en = true;
config.tx_config.idle_level = 0;
config.clk_div = WS2812B_RMT_CLK_DIV;
ESP_ERROR_CHECK(rmt_config(&config));
ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0));
}
/**************************************************************
*
* @brief rmt驱动方式发送数据
* @param data 数据缓存指针
* @param len 数据长度
*
* ************************************************************/
void ws2812b_rmt_send(const rmt_item32_t *data, uint32_t len, uint32_t rmt_ch)
{
ESP_ERROR_CHECK(rmt_write_items(rmt_ch, data, len, false));
ESP_ERROR_CHECK(rmt_wait_tx_done(rmt_ch, portMAX_DELAY));
}
/*************************************************************************************************************
*
* @brief 设置单个像素的某bit值
* @param n 像素点位置
* @param bit 像素点的某个位
* @param value 像素点某个位左移后的取值 ((grb << i) & 0x800000)用于判别输出值
*
* **********************************************************************************************************/
void ws2812b_set_pixel_bit(uint32_t n, uint8_t bit, uint32_t value)
{
ws2812b_buffer[ n * WS2812B_GRB + bit] = value ? (rmt_item32_t){{{WS2812B_RMT_T1H, 1, WS2812B_RMT_T1L, 0}}} : (rmt_item32_t){{{WS2812B_RMT_T0H, 1, WS2812B_RMT_T0L, 0}}};
}
/*************************************************************************************************************
*
* @brief show all pixel to display
*
* **********************************************************************************************************/
void ws2812b_show(void)
{
ws2812b_rmt_send((const rmt_item32_t*)ws2812b_buffer, ws2812b_buffer_size, WS2812B_RMT_CHANNEL);
}
#endif
/*************************************************************************************************************
*
* @brief ws2812 delay
*
* **********************************************************************************************************/
__attribute__((__weak__)) void ws2812b_delay(uint32_t ms)
{
vTaskDelay((ms) / portTICK_PERIOD_MS);
}
/*************************************************************************************************************
*
* @brief 呼吸灯曲线表
*
* **********************************************************************************************************/
const uint8_t breathing_index[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4,
4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 12, 12,
13, 13, 14, 14, 15, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23, 24, 25, 25, 26, 27, 28, 30, 31, 32, 33,
34, 36, 37, 38, 40, 41, 43, 45, 46, 48, 50, 52, 54, 56, 58, 60, 62, 65, 67, 70, 72, 75, 78, 81, 84, 87, 90,
94, 97, 101, 105, 109, 113, 117, 122, 126, 131, 136, 141, 146, 152, 158, 164, 170, 176, 183, 190, 197, 205,
213, 221, 229, 238, 247, 255, 255, 247, 238, 229, 221, 213, 205, 197, 190, 183, 176, 170, 164, 158, 152, 146,
141, 136, 131, 126, 122, 117, 113, 109, 105, 101, 97, 94, 90, 87, 84, 81, 78, 75, 72, 70, 67, 65, 62, 60, 58,
56, 54, 52, 50, 48, 46, 45, 43, 41, 40, 38, 37, 36, 34, 33, 32, 31, 30, 28, 27, 26, 25, 25, 24, 23, 22, 21, 20,
20, 19, 18, 18, 17, 16, 16, 15, 15, 14, 14, 13, 13, 12, 12, 11, 11, 10, 10, 10, 9, 9, 9, 8, 8, 8, 7, 7, 7, 7, 6,
6, 6, 6, 6, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
/*************************************************************************************************************
*
* @brief 取三个数中最小值
*
* **********************************************************************************************************/
static float min(float a, float b, float c)
{
float m;
m = a < b ? a : b;
return (m < c ? m : c);
}
/*************************************************************************************************************
*
* @brief 取三个数中最大值
*
* **********************************************************************************************************/
static float max(float a, float b, float c)
{
float m;
m = a > b ? a : b;
return (m > c ? m : c);
}
/*************************************************************************************************************
*
* @brief rgb颜色转换为hsv颜色
*
* **********************************************************************************************************/
void ws2812b_rgb2hsv(uint8_t r, uint8_t g, uint8_t b, float *h, float *s, float *v)
{
float red, green, blue;
float cmax, cmin, delta;
red = (float)r / 255;
green = (float)g / 255;
blue = (float)b / 255;
cmax = max(red, green, blue);
cmin = min(red, green, blue);
delta = cmax - cmin;
/* H */
if (delta == 0)
{
*h = 0;
}
else
{
if (cmax == red)
{
if (green >= blue)
{
*h = 60 * ((green - blue) / delta);
}
else
{
*h = 60 * ((green - blue) / delta) + 360;
}
}
else if (cmax == green)
{
*h = 60 * ((blue - red) / delta + 2);
}
else if (cmax == blue)
{
*h = 60 * ((red - green) / delta + 4);
}
}
/* S */
if (cmax == 0)
{
*s = 0;
}
else
{
*s = delta / cmax;
}
/* V */
*v = cmax;
}
/*************************************************************************************************************
*
* @brief hsv颜色 转换为 rgb颜色
*
* **********************************************************************************************************/
void ws2812b_hsv2rgb(float h, float s, float v, uint8_t *r, uint8_t *g, uint8_t *b)
{
int hi = ((int)h / 60) % 6;
float f = h * 1.0 / 60 - hi;
float p = v * (1 - s);
float q = v * (1 - f * s);
float t = v * (1 - (1 - f) * s);
switch (hi)
{
case 0:
*r = 255 * v;
*g = 255 * t;
*b = 255 * p;
break;
case 1:
*r = 255 * q;
*g = 255 * v;
*b = 255 * p;
break;
case 2:
*r = 255 * p;
*g = 255 * v;
*b = 255 * t;
break;
case 3:
*r = 255 * p;
*g = 255 * q;
*b = 255 * v;
break;
case 4:
*r = 255 * t;
*g = 255 * p;
*b = 255 * v;
break;
case 5:
*r = 255 * v;
*g = 255 * p;
*b = 255 * q;
break;
}
}
/*************************************************************************************************************
*
* @brief rgb 转grb
*
* **********************************************************************************************************/
uint32_t ws2812b_rgb2grb(uint32_t rgb)
{
return (((rgb&0x00FF00)<<8) | ((rgb&0xFF0000)>>8) | (rgb&0x0000FF));
}
/*************************************************************************************************************
*
* @brief grb转rgb
*
* **********************************************************************************************************/
uint32_t ws2812b_grb2rgb(uint32_t grb)
{
return (((grb&0x00FF00)<<8) | ((grb&0xFF0000)>>8) | (grb&0x0000FF));
}
/*************************************************************************************************************
*
* @brief 输入r,g,b 合成为颜色值
*
* **********************************************************************************************************/
uint32_t ws2812b_set_color(uint8_t r, uint8_t g, uint8_t b)
{
return g << 16 | r << 8 | b;
}
/*************************************************************************************************************
*
* @brief 清屏显示
*
* **********************************************************************************************************/
void ws2812b_close_all(void)
{
uint16_t i;
uint8_t j;
for(i = 0; i < WS2812B_PIXEL_NUM; i++)
{
for(j = 0; j < WS2812B_GRB; j++)
{
ws2812b_set_pixel_bit(i,j,0);
}
}
ws2812b_show();
}
/*************************************************************************************************************
*
* @brief 设置单个像素grb颜色
* @param n 像素点位置
* @param grb grb颜色值
*
* **********************************************************************************************************/
void ws2812b_set_pixel_grb(uint32_t n, uint32_t grb)
{
uint8_t i;
if(n < WS2812B_PIXEL_NUM)
{
for(i = 0; i < WS2812B_GRB; i++)
{
ws2812b_set_pixel_bit(n,i,((grb << i) & 0x800000));
}
}
}
/*************************************************************************************************************
*
* @brief 设置单个像素rgb颜色
* @param n 像素点位置
* @param rgb rgb颜色值
*
* **********************************************************************************************************/
void ws2812b_set_pixel_rgb(uint32_t n, uint32_t rgb)
{
uint8_t i;
uint32_t grb = ws2812b_rgb2grb(rgb);
if(n < WS2812B_PIXEL_NUM)
{
for(i = 0; i < WS2812B_GRB; i++)
{
ws2812b_set_pixel_bit(n,i,((grb << i) & 0x800000));
}
}
}
/*************************************************************************************************************
*
* @brief set pixel color
*
* **********************************************************************************************************/
void ws2812b_set_pixel_color(uint16_t n, uint32_t WS2812_GRBColor)
{
uint8_t i;
if(n < WS2812B_PIXEL_NUM)
{
for(i = 0; i < WS2812B_GRB; i++)
{
ws2812b_set_pixel_bit(n,i,((WS2812_GRBColor << i) & 0x800000));
}
}
}
/*************************************************************************************************************
*
* @brief Input a value 0 to 255 to get a color value.
* The colours are a transition r - g - b - back to r.
*
* **********************************************************************************************************/
uint32_t ws2812b_wheel(uint8_t wheelPos)
{
wheelPos = 255 - wheelPos;
if(wheelPos < 85) {
return ws2812b_set_color(255 - wheelPos * 3, 0, wheelPos * 3);
}
if(wheelPos < 170) {
wheelPos -= 85;
return ws2812b_set_color(0, wheelPos * 3, 255 - wheelPos * 3);
}
wheelPos -= 170;
return ws2812b_set_color(wheelPos * 3, 255 - wheelPos * 3, 0);
}
/*************************************************************************************************************
*
* @brief // Fill the dots one after the other with a color
*
* **********************************************************************************************************/
void ws2812b_fill_color(uint32_t rgb) {
for(uint16_t i=0; i<WS2812B_PIXEL_NUM; i++) {
ws2812b_set_pixel_rgb(i, rgb);
}
ws2812b_show();
}
/*************************************************************************************************************
*
* @brief // breathing light
* **********************************************************************************************************/
uint16_t ws2812b_get_brightness(uint16_t t)
{
uint16_t brightness = 0;
if (t < WS2812B_BREATHING_LEVEL/2) {
brightness = t;
} else if (t < WS2812B_BREATHING_LEVEL) {
brightness = (WS2812B_BREATHING_LEVEL - t);
}
return brightness/WS2812B_BREATHING_RATIO;
}
void ws2812b_set_breathing0(uint32_t c, uint8_t wait)
{
static uint32_t color = 0;
static float h = 0.0;
static float s = 0.0;
static float v = 0.0;
uint8_t r = 0;
uint8_t g = 0;
uint8_t b = 0;
if(c != color)
{
color = c;
ws2812b_rgb2hsv((color>>16)&0xFF,(color>>8)&0xFF,color&0xFF, &h, &s, &v);
}
for(uint16_t j = 0; j < WS2812B_BREATHING_LEVEL; j++)
{
ws2812b_hsv2rgb(h,s,ws2812b_get_brightness(j), &r, &g, &b);
for(uint16_t i=0; i< WS2812B_PIXEL_NUM; i++)
{
ws2812b_set_pixel_color(i, ws2812b_set_color(r,g,b));
}
ws2812b_show();
ws2812b_delay(wait);
}
}
void ws2812b_set_breathing1(uint32_t c)
{
static uint32_t color = 0;
static uint16_t index = 0;
static float h = 0.0;
static float s = 0.0;
static float v = 0.0;
uint8_t r = 0;
uint8_t g = 0;
uint8_t b = 0;
if(c != color)
{
color = c;
ws2812b_rgb2hsv((color>>16)&0xFF,(color>>8)&0xFF,color&0xFF, &h, &s, &v);
}
index++;
if(index >= WS2812B_BREATHING_LEVEL-20)
{
index = 20;
}
ws2812b_hsv2rgb(h,s,ws2812b_get_brightness(index), &r, &g, &b);
for(uint16_t i=0; i< WS2812B_PIXEL_NUM; i++)
{
ws2812b_set_pixel_color(i, ws2812b_set_color(r,g,b));
}
ws2812b_show();
}
/*************************************************************************************************************
*
* @brief // Fill the dots one after the other with a color
*
* **********************************************************************************************************/
void ws2812b_rainbow(uint8_t wait) {
uint16_t i, j;
for(j=0; j<256; j++) {
for(i=0; i<WS2812B_PIXEL_NUM; i++) {
ws2812b_set_pixel_rgb(i, ws2812b_wheel((i+j) & 255));
}
ws2812b_show();
ws2812b_delay(wait);
}
}
/*************************************************************************************************************
*
* @brief // Slightly different, this makes the rainbow equally distributed throughout
*
* **********************************************************************************************************/
void ws2812b_rainbow_cycle(uint8_t wait) {
uint16_t i, j;
for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
for(i=0; i< WS2812B_PIXEL_NUM; i++) {
ws2812b_set_pixel_rgb(i, ws2812b_wheel(((i * 256 / WS2812B_PIXEL_NUM) + j) & 255));
}
ws2812b_show();
ws2812b_delay(wait);
}
}
/*************************************************************************************************************
*
* @brief //Theatre-style crawling lights.
*
* **********************************************************************************************************/
void ws2812b_theater_chase(uint32_t c, uint8_t wait) {
for (int j=0; j<10; j++) { //do 10 cycles of chasing
for (int q=0; q < 3; q++) {
for (uint16_t i=0; i < WS2812B_PIXEL_NUM; i=i+3) {
ws2812b_set_pixel_rgb(i+q, c); //turn every third pixel on
}
ws2812b_show();
ws2812b_delay(wait);
for (uint16_t i=0; i < WS2812B_PIXEL_NUM; i=i+3) {
ws2812b_set_pixel_rgb(i+q, 0); //turn every third pixel off
}
}
}
}
/*************************************************************************************************************
*
* @brief //Theatre-style crawling lights with rainbow effect
*
* **********************************************************************************************************/
void ws2812b_theater_chase_rainbow(uint8_t wait) {
for (int j=0; j < 256; j++) { // cycle all 256 colors in the wheel
for (int q=0; q < 3; q++) {
for (uint16_t i=0; i < WS2812B_PIXEL_NUM; i=i+3) {
ws2812b_set_pixel_rgb(i+q, ws2812b_wheel( (i+j) % 255)); //turn every third pixel on
}
ws2812b_show();
ws2812b_delay(wait);
for (uint16_t i=0; i < WS2812B_PIXEL_NUM; i=i+3) {
ws2812b_set_pixel_rgb(i+q, 0); //turn every third pixel off
}
}
}
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/pinno/drv_ws2812b.git
git@gitee.com:pinno/drv_ws2812b.git
pinno
drv_ws2812b
drv_ws2812b
master

搜索帮助