ESP32-C3入门教程 基础篇(五、RMT应用 — 控制SK6812全彩RGB 灯)_esp32中的rmt

369 阅读15分钟

img img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

3、ESP8266

  • ESP8266的GPIO有效翻转大约须要2.5us(0.4MHz)
  • ESP8266的GPIO0的翻转速度最快,配合寄存器操作可以实现

算下来,目前来说MCU的发展,还是有能够直接控制 IO 口电平实现的条件,这种简单粗暴的方式需要经过反复的测试调整,因为对于时间的控制还需要考虑很多因素。所以这里介绍一下,不过多探究。

1.2.2 SPI方式

SPI方式,SPI通讯的速度目前器件可以达到大几十Mbps,一般情况下,SPI模块的最大时钟频率为系统时钟频率的1/2。
SPI 的基础知识网上很多,在我博文《总线协议记录》也有记录。

所以通过 SPI 总线发送是比较可行的一种方式。 只要将 SPI 的时钟调整为 8MHz左右(小于等于8Mhz),这样不同的 MCU下,都可以实现。

采用 8Mhz SPI,发送一个字节所需时间1.25us,满足上面 SK6812 的24bit 数据结构 一个bit 的时间:

再根据 “1” 码 < 1us && >0.6us 的 高电平, >0.2us的低电平,得出,SPI发送一个字节 11111100b 即表示 “1” 码,0XF0。

同理可得,SPI发送字节 11000000b 即表示 “0” 码,0xC0。

那么还是按照上面原理部分举的例子,显示黄色的 24bit 数据结构为:1111 1111 1111 1111 0000 0000

那么SPI总线发送如下的24个字节数据(十六进制),就能使得LED显示为黄色:

F0 F0 F0 F0 F0 F0 F0 F0 F0 F0 F0 F0 F0 F0 F0 F0 C0 C0 C0 C0 C0 C0 C0 C0

1.2.2 PWM方式

PWM 方式也是一种常见的控制高低电平的方式,通过上面我们得知,“1”码 和 “0” 码的高低电平比例为3:1. 那么就是调节占空比 ,“1”码的占空比为 75% ,“0”码的占空比为 25%。 那么剩下的只需要把 PWM 的周期设置成 SK6812 的码元周期 > 1.2us 左右。 注意占空比多少,可以根据实际情况调整。

给出2个网上的结论,仅供参考:

  • cycle(周期)=1.2us,占空比=50%为1,占空比=30%为0;
    (833Khz ,感觉还行)
  • 周期设置为3MHz,占空比 = 66% 为1,占空比=33%为0;
    (0.33us周期,估计写错了,1MHZ还差不多, 1us)

关于ESP32 -C3 使用PWM 方式,不确定可不可以用,毕竟 ESP32 -C3 的PWM按照我们的博文流程我们还没有学习测试,下一篇博文写一下 ESP32 -C3 的PWM学习测试记录。

1.2.3 RMT方式(ESP32)

RMT,是ESP32 系列特有的一个红外发送和接收控制器,红外协议转化为信号,体现在IO上也就是高低电平。

将上面讲到的 “1” 码 和 “0” 码当成红外信号,也可以实现 SK6812 的控制。下面就先来了解下 ESP32-C3 的 RMT。

二、 ESP32-C3 RMT介绍

2.1 RMT 基础介绍

在乐鑫官方 ESP32-C3 芯片手册《esp32-c3_technical_reference_manual_cn》文档中对于 RMT 有详细的介绍:
ESP32-C3手册RMT部分
在官方网站也有关于 RMT 相关API的详细介绍:乐鑫官方ESP32-C3 RMT部分说明

所以详细的资料还是可以通过上面的途径查看,这里我们需要关注的一点就是:

RMT 是如何控制 SK6812 的?

通过前面的SK6812 控制原理我们知道了,控制 SK2812 就是实现符合时间规定的高低电平,那么在ESP32-C3 芯片手册中,有提到 RMT 是如何实现此功能的,对于部分如下图:(当然如果要了解更深还是要好好查看官方的资料)

在这里插入图片描述
结合官网图片就能更容易理解:
在这里插入图片描述

2.2 RMT 使用介绍(API相关)

RMT 的使用基本步骤如下,但是本文我们是需要控制 SK6812 ,所以只需要了解发送相关的配置及使用:
在这里插入图片描述

首先要了解的是一个结构体,发送配置的结构体rmt_tx_config_t
在这里插入图片描述
上述结构体内容 依次是:RMT载波频率、RMT输出的电平、空闲电平状态、占空比、最大循环计数、载波使能、循环发送使能、空闲电平输出使能。

通过初始化结构体的示例,可以更好的理解:
在这里插入图片描述
RMT 输出结构体默认配置如下:
在这里插入图片描述
对于控制 SK6812,目前了解到 RMT 的输入配置就可以了。

三、 RMT 示例测试

3.1 IDF 示例测试

在 IDF 示例程序中,官方提供了控制 WS2812 的示例 RMT Transmit Example -- LED Strip
在这里插入图片描述

程序的过程比较简单,SK6812的驱动和ws2812的驱动是一样的,相关的代码在components/led_strip/src/led_strip_rmt_ws2812.c 文件中。

针对自己的开发板,然后对于示例工程,简单修改一下既可以看到效果,因为示例大家都一样,这里就使用截图表示需要修改的地方:

在这里插入图片描述

在这里插入图片描述

在示例中EXAMPLE_CHASE_SPEED_MS 太快了,闪得我眼睛有点花,把这个时间改成了300:

#define EXAMPLE\_CHASE\_SPEED\_MS (300)//

在我的开发板上面,本来确实是只有一个LED,但是为了测试,我飞线焊接了一个:
在这里插入图片描述

测试结果,示例的现象就是,LED不同颜色的交替闪烁,并没有渐变效果,这里上几张图勉强看看:

在这里插入图片描述

3.2 示例改渐变效果

最开始也没有一点一点的去分析驱动代码,示例代码也就看看 RMT 的配置,后面的 SK6812 驱动部分并没有仔细研究,所以测试是闪烁效果,后来想想还是不得劲,不渐变闪烁,这不得亮瞎眼= =!

所以还是得改改,所以看了看示例,其实也就是简单的修改(最后一个vTaskDelay(50)不需要,这里是以前改过的代码忘了去掉了):
在这里插入图片描述

根据上面图示的说明,把所有时间改成如下,是基于例程基础 最平滑 最快速的渐变了:
在这里插入图片描述

没视频看不到= =! 上张图勉强应付一下:
在这里插入图片描述

四、 SK6812 驱动代码说明

2022/6/16 更新   by 矜辰所致

最近 ESP32-C3 的学习博主已经更新完了 蓝牙 GATT篇章,正准备写一篇蓝牙的小应用,计划要通过手机与开发板进行蓝牙连接,控制板子上的灯,能够渐变当然是最好了,忽然发现 SK6812 的驱动函数忘了怎么用了……

在官方示例中,给了最原始的驱动,但是感觉当时没有理解透彻,所以回过头来重新看一看。

4.1 驱动函数简析

我们在使用中,需要定义一个LED变量,比如:

static led\_strip\_t \*strip;

我们来看一看 led_strip_t ,他是 led_strip_s 结构体类型:

struct led\_strip\_s {
    /\*\*
 设置灯的颜色
 \*/
    esp\_err\_t (\*set_pixel)(led\_strip\_t \*strip, uint32\_t index, uint32\_t red, uint32\_t green, uint32\_t blue);

    /\*\*
 更新灯的颜色
 \*/
    esp\_err\_t (\*refresh)(led\_strip\_t \*strip, uint32\_t timeout_ms);

    /\*\*
 清除灯的颜色
 \*/
    esp\_err\_t (\*clear)(led\_strip\_t \*strip, uint32\_t timeout_ms);

    /\*\*
 删除灯这个对象
 \*/
    esp\_err\_t (\*del)(led\_strip\_t \*strip);
};

在示例中我们都使用到了这几个函数,简单记录一下这几个函数的说明:

设置灯的颜色:

/\*
参数含义:
灯的句柄,我们开始定义的变量
需要设置的灯的位置下标,从0开始,如果有很多灯,一般都是使用for循环赋值
红色的值
绿色的值
蓝色的值

\*/
static esp\_err\_t ws2812\_set\_pixel(led\_strip\_t \*strip, 
									uint32\_t index, 
									uint32\_t red, 
									uint32\_t green, 
									uint32\_t blue)

更新灯的值:

使用上面函数设置完LED颜色值后,需要调用ws2812_refresh 将颜色更新到灯条:


static esp\_err\_t ws2812\_refresh(led\_strip\_t \*strip, uint32\_t timeout_ms)

清除灯的颜色:

等于把等熄灭:

static esp\_err\_t ws2812\_clear(led\_strip\_t \*strip, uint32\_t timeout_ms)

SK2812设备注册函数:

另外还有一个函数需要注意,就是用来注册新的SK2812设备的函数:

led\_strip\_t \*led\_strip\_new\_rmt\_ws2812(const led\_strip\_config\_t \*config)

使用此函数来注册设备,比如:

在这里插入图片描述

4.2 设置指定颜色

设置指定延时,我们可以直接使用 ws2812_set_pixel 函数,对于我们定义的结构体变量,根据示例使用即可,设置指定颜色就很简单了:

在这里插入图片描述

上图颜色 绿色 和 红色 搞反了!set_pixel(strip, 0, 255, 0, 0)是绿色,第二个是红色 !
红色 和 绿色 对应位置好像反了,是因为ESP-IDF 驱动中的颜色处理驱动函数是反过来的:
在这里插入图片描述
为了与正常的颜色值对应,改成如下即可:
在这里插入图片描述

当然为了对应颜色代码(比如 #0033FF 形式)我们可以简单的做几个函数处理一下:

struct WS2812\_COLOR
{
	uint8\_t lamp;
	uint8\_t ligth_rank;
	uint8\_t lamp_speed;
	uint32\_t red;
	uint32\_t green;
	uint32\_t blue;
};

static led\_strip\_t \*strip;

struct WS2812\_COLOR WS2812_RGB;


void RGB16for10(struct WS2812\_COLOR \*RGB, uint32\_t reb_16)
{
	uint32\_t rgb_16 = reb_16;
	RGB->blue = rgb_16 & 0Xff;

	rgb_16 = rgb_16 >> 8;
	RGB->green = rgb_16 & 0xff;

	rgb_16 = rgb_16 >> 8;

	RGB->red = rgb_16 & 0xff;
}

void set\_rgb(uint32\_t rgb_24bit, uint8\_t ligth_rank)
{
	RGB16for10(&WS2812_RGB, rgb_24bit);
	ligth_rank = 21 - ligth_rank;
	for (int i = 0; i < LED_STRIP_NUM; i++)
	{
		strip->set\_pixel(strip, i, WS2812_RGB.red / ligth_rank, WS2812_RGB.green / ligth_rank, WS2812_RGB.blue / ligth_rank);
	}

	strip->refresh(strip, 10);
}


在使用的时候,可以直接使用 set_rgb 函数:

在这里插入图片描述

如果设置其他颜色,需要查对应的表格了,在网上找了一张表格,简单看看,网上也有很多 RGB 查询工具,一搜索就可以出来:

在这里插入图片描述

4.2 几个渐变驱动

渐变的示例,通过上文官方的示例也可以做到,我这里发现一片好的文章,文章博主写了几种好的方式,博文连接如下:

ESP32使用外设RMT控制WS2812灯条

程序选自上面推荐博文:

程序一:

/\*\*
 \* @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));
	}
}
————————————————
版权声明:本文为CSDN博主「milk_docker」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/tian\_milk/article/details/123585610

程序二:

// 必须包含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));
    }
}
————————————————
版权声明:本文为CSDN博主「milk_docker」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/tian\_milk/article/details/123585610



![img](https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/df585c9bfe4848a790786635ed59328d~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55So5oi3MzM5MTQ5MjgwNjA=:q75.awebp?rk3s=f64ab15b&x-expires=1771924759&x-signature=5R6n18zMIEV4lYT9ogcxYDjspWY%3D)
![img](https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/c457f76cc4e74de69147a708c43bc792~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55So5oi3MzM5MTQ5MjgwNjA=:q75.awebp?rk3s=f64ab15b&x-expires=1771924759&x-signature=iXhWTVUaWRgsJcXJTI4Oke%2BMtM8%3D)

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新**

**[如果你需要这些资料,可以戳这里获取](https://gitee.com/vip204888)**