第一句子网 - 唯美句子、句子迷、好句子大全
第一句子网 > ESP32使用外设RMT控制WS2812灯条

ESP32使用外设RMT控制WS2812灯条

时间:2021-12-01 18:13:35

相关推荐

ESP32使用外设RMT控制WS2812灯条

目录

一、简介

二、所需材料

三、官方例程

四、使用方法

4.1 RMT初始化

4.2 WS2812初始化

4.3 点亮WS2812

五、LED颜色渐变

5.1 第一种实现方法

5.2 第二种实现方法

5.3 彩虹跑马灯

一、简介

官方关于RMT的介绍:RMT(红外遥控器)是一个红外发送/接收控制器, 其特殊设计支持生成各类信号。红外遥控发射器从内置的 RAM(随机存取存储器)区中读取连续的脉冲码, 并对输出信号进行载波调制。尽管RMT外设主要用于远程红外应用,由于其灵活的数据格式,RMT同样可支持其它协议。WS2812是集成了驱动电路和单线控制的数字RGB LED,其协议数据格式兼容于RMT外设。

详细参考:ESP-IDF 编程指南 Remote Control (RMT)

由于RMT的灵活特性,自然也可以编程以用于控制WS2812灯条。

二、所需材料

平台:VScode+ESP-IDF

ESP32开发板 ×1

WS2812灯条 ×1

连接线 若干

三、官方例程

官方给出了相关的库以及相应的参考例程,那只要学会怎么用轮子就可以了。

首先ctrl+shift+p打开命令面板,键入ESP-IDF show examples projects

打开ESP-IDF example界面,找到 led_strip 例程:

点击 使用例程i2s_adc_dac创建项目就可以了。

四、使用方法

4.1 RMT初始化

对RMT的初始化需要设置rmt_config_t中的相关参数,根据官方的说明:

填好相关参数后,需要调用函数rmt_config()​​​​​​以使初始化参数有效和函数rmt_driver_install()安装驱动。相应代码:

// 使用默认参数填入rmt_config_t结构体rmt_config_t config = RMT_DEFAULT_CONFIG_TX(CONFIG_EXAMPLE_RMT_TX_GPIO, RMT_TX_CHANNEL);// 将时钟设置为40MHzconfig.clk_div = 2;// 调用两个函数完成初始化ESP_ERROR_CHECK(rmt_config(&config));ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0));

4.2 WS2812初始化

WS2812的初始化简单一点:

// install ws2812 driver 安装ws2812驱动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)关闭所有ws2812ESP_ERROR_CHECK(strip->clear(strip, 100));

根据led_strip_config_t 的定义,该结构体的第一个参数为WS2812灯的数量,第二个参数为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 点亮WS2812

使用 led_strip_s 结构体中的 set_pixel 函数设置各个灯珠的8位RGB值。使用该函数逐一设置每个灯珠的值,灯珠的位置从0开始计数,每调用一次设置一个灯珠。

设置好灯珠颜色后,调用 refresh 函数将颜色更新到灯条上。

/*** @brief Set RGB for a specific pixel 设置特定灯珠的RGB值** @param strip: LED strip WS2812的结构体* @param index: index of pixel to set 需要设置的灯的位置下标,从0开始* @param red: red part of color 红色的值* @param green: green part of color 绿色的值* @param blue: blue part of color 蓝色的值** @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 用内存中的颜色更新LEDs** @param strip: LED strip WS2812的结构体* @param timeout_ms: timeout value for refreshing task 更新任务超时的值** @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.*在更新内存中的LED颜色值后,需要调用该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 ++){// 设置ws2812的RGB的值ESP_ERROR_CHECK(strip->set_pixel(strip, j, Red, Green, Blue));}// 给WS2812发送RGB的值ESP_ERROR_CHECK(strip->refresh(strip, 100));

五、LED颜色渐变

我写了一个颜色渐变的程序,三种颜色的值按照正弦变化,两两错开120°。原理如图

根据这个原理设计程序,LED灯颜色在渐变时的过度就会十分自然。LED所显示的颜色依次为红、橙、黄、绿、靛、紫。

具体代码如下:

5.1 第一种实现方法

第一种方法预先计算好正弦函数的样本值,并存储在一个数组中,然后依次把元素的值作为RGB的值发送给LED灯条,实现颜色渐变效果。

函数声明(放在头文件中):

/*** @brief 所有灯颜色渐变效果,注:必须同时包含SinValue[]数组才能使用* * @param strip LED灯带的结构体* @param LED_Number 点亮的LED的数量* @param GradualChangeRate LED渐变的速度,数值越大,速度越慢,一般为50*/void WS2812B_ColourGradualChange1(led_strip_t *strip,uint16_t LED_Number,uint16_t GradualChangeRate);

函数定义(放在库文件中):

/*** @brief sin()函数从0到2π的样本值,一共255个点,最大值为255,最小值为0* * 离散信号函数:SinValue(k)=(255*sin(2*k*π/255)+255)/2 (四舍五入取整数)* */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 ++){// 设置ws2812的RGB的值ESP_ERROR_CHECK(strip->set_pixel(strip, j, Red, Green, Blue));}// 给WS2812发送RGB的值ESP_ERROR_CHECK(strip->refresh(strip, 100));vTaskDelay(pdMS_TO_TICKS(GradualChangeRate));}}

将代码放在库中便可直接调用。

5.2 第二种实现方法

第二种方法使用 math.h 中的sin()函数,实时计算RGB各自的值,并发送给LED灯条。

函数声明(放在头文件中):

/*** @brief 所有灯颜色渐变效果* * @param strip:LED灯带的结构体* @param LED_Number:点亮的LED的数量* @param GradualChangeRate:LED渐变的速度,数值越大,速度越慢,一般为50*/void WS2812B_ColourGradualChange2(led_strip_t *strip,uint16_t LED_Number,uint16_t GradualChangeRate);

函数定义(放在库文件中):

// 必须包含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()函数分别计算三原色的值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 ++){// 设置ws2812的RGB的值ESP_ERROR_CHECK(strip->set_pixel(strip, j, Red, Green, Blue));}// 给WS2812发送RGB的值ESP_ERROR_CHECK(strip->refresh(strip, 100));vTaskDelay(pdMS_TO_TICKS(GradualChangeRate));}}

两种实现方法的效果差别不大

5.3 彩虹跑马灯

依旧使用前述原理实现彩虹跑马灯效果,每个灯的颜色均不同。

函数声明(放在头文件中):

/*** @brief 彩虹跑马灯效果* * @param strip:LED灯带的结构体* @param LED_Number:点亮的LED的数量* @param GradualChangeRate:LED渐变的速度,数值越大,速度越慢,一般为50*/void WS2812B_TrottingHorseLamp1(led_strip_t *strip,uint16_t LED_Number,uint16_t GradualChangeRate);

函数定义(放在库文件中):

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 ++){// 根据灯珠的位置计算RGB的值Green = SinValue[(i+10*j)%256];Red = SinValue[(ir+10*j)%256];Blue = SinValue[(ib+10*j)%256];// 设置ws2812的RGB的值ESP_ERROR_CHECK(strip->set_pixel(strip, j, Red, Green, Blue));}// 给WS2812发送RGB的值ESP_ERROR_CHECK(strip->refresh(strip, 100));vTaskDelay(pdMS_TO_TICKS(GradualChangeRate));}}

这样便可实现平滑的彩虹跑马灯效果。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。