原创 ESP32开发之WS2812B控制

2025-6-9 22:37 929 0 1 分类: MCU/ 嵌入式 文集: ESP32
  • WS2812B数据手册重点摘录
  • 硬件电路
  • Remote Control Transceive(RMT)概念
  • RMT的相关API函数
  • 一段简单的控制WS2812B的应用举例
  • 总结

WS2812B数据手册重点摘录

WS2812的数据手册还是很好找的,可以直接去立创商城输入型号就可以找到。

  • 重点一:引脚结构

VDD:供电输入;DI:数据输入;DO:数据输出(用于级联);GND:供电地

fig:

  • 重点二:供电

如图供电5V足够了

fig:

  • 重点三:数据结构

每个颜色数据为8bit

fig:

  • 重点四:数据传输波形

波形图还是很明了易懂的,类似于NEC编码方式。根据数据传输定义,可以知道咱们需要给它的控制信号是1MHz的。

fig:

  • 重点五:厂商给的设计建议

一定要看,厂商一般都会做大量的测试,他们的建议是最好的参考标准。这个器件的手册还是很详细的,如图的1、2条说明仔细看。

fig:

电路图

根据器件的数据手册,可以很轻松的绘制电路图

fig:

Remote Control Transceive(RMT)概念

  • 背景:还记得在上次的呼吸灯么?通过ESP32自带的LEDC控制器实现的呼吸灯还是很轻松的。通过对WS2812B的数据手册阅读,可以发现对它的驱动其实也是PWM,是否也可用LEDC呢?答案是不行的,在使用LEDC产生PWM的时候可以发现,PWM的占空比是不可控的(无法控制其之发送一段PWM)。由WS2812B的传输波形可知,其需要的波形是一段的且每个周期是可控的。

  • 引入:根据WS2812B的传输波形特征,发现ESP32中有一个Remote Control Transceive的外设控制器,结合安可信官网的知识解读,这个RMT是控制WS2812B的不二之选。且在RMT的案例库中有一个控制WS2812这类LED的例程,路径如下:fig:

例程内容较为复杂,初学者一时半会很难明白其中的逻辑。在此,我做一个简单的实现例程,

  • RMT的概念:RMT是一个红外发射和接收控制器,数据格式灵活,可以发送或接收多种类型的信号。它有自己的数据模式,叫做RMT符号。每个符号由两对两个值组成,每对中的第一个值是一个 15 位的值,表示信号持续时间,以 RMT 滴答计。每对中的第二个值是一个 1 位的值,表示信号的逻辑电平,即高电平或低电平。这个格式非常适合控制WS2812B .

fig:

RMT的相关API函数

目前只用到了RMT的发送,所以只说明发送的API函数

  • RMT发送通道配置结构体


typedef struct {
    gpio_num_t gpio_num;        /*所要映射的GPIO口,不使用时设置为-1*/
    rmt_clock_source_t clk_src; /*RMT通道所使用的时钟源 */
    uint32_t resolution_hz;     /*此通道的时钟分辨率 */
    size_t mem_block_symbols;   /*内存块大小,如果启用了DMA,则该字段可以控制内部DMA缓冲区大小,建议设置1024;如果未启用DMA,则至少设置为64。不是所有通道都支持DMA,具体要查看芯片的TRM文档*/
    size_t trans_queue_depth;   /*设置后台等待处理的事务数量*/
    int intr_priority;          /*设置中断优先级 */
    struct {
        uint32_t invert_out: 1;   /*设置是否反转输出信号*/
        uint32_t with_dma: 1;     /*是否开启DMA */
        uint32_t io_loop_back: 1; /*是否返回给输入,作为换回测试 */
        uint32_t io_od_mode: 1;   /*设置GPIO是否作为开漏模式 */
    } flags;                      /*!< TX channel config flags */
} rmt_tx_channel_config_t;


  • 分配和初始化TX通道


esp_err_t rmt_new_tx_channel(const rmt_tx_channel_config_t *config, rmt_channel_handle_t *ret_chan)
/*第一个参数是 rmt_tx_channel_config_t定义并填充的结构体变量,第二个参数是此函数返回的RMT通道句柄,需要使用rmt_channel_handle_t先声明一个变量*/


  • 使能通道和禁用通道


//使能
esp_err_t rmt_enable(rmt_channel_handle_t channel) //参数为rmt_new_tx_channel返回的RMT通道句柄
//禁用
esp_err_t rmt_disable(rmt_channel_handle_t channel)//参数为rmt_new_tx_channel返回的RMT通道句柄


  • 设置RMT符号格式,即输出什么样的信号


typedef struct {
    rmt_symbol_word_t bit0; /*RMT符号的bit0字节格式 */
    rmt_symbol_word_t bit1; /*RMT符号的bit1字节格式*/
    struct {
        uint32_t msb_first: 1; /*最先编最高有效位*/
    } flags;                   /*编码配置状态 */
} rmt_bytes_encoder_config_t;

typedef union {
    struct {
        uint16_t duration0 : 15; /* level0 持续时间*/
        uint16_t level0 : 1;     /*Level0的电平值*/
        uint16_t duration1 : 15; /*level1 持续时间*/
        uint16_t level1 : 1;     /*Level1的电平值 */
    };
    uint32_t val; /* 与RMT 符号等价的无符号值 */
} rmt_symbol_word_t;


  • 创建字节编码器


esp_err_t rmt_new_bytes_encoder(
    const rmt_bytes_encoder_config_t *config, //创建好的 rmt_bytes_encoder_config_t的结构体变量
    rmt_encoder_handle_t *ret_encoder//返回的编码器句柄,需要在调用前创建 rmt_encoder_handle_t变量
)


  • 发送配置结构体


typedef struct {
    int loop_count; /*循环次数 ,设置为-1则无限循环*/
    struct {
        uint32_t eot_level : 1;         /*发送结束后输出的电平 */
        uint32_t queue_nonblocking : 1; /*设置当传输队列满的时候该函数是否需要等待 */
    } flags;                            /*!< Transmit specific config flags */
} rmt_transmit_config_t;


  • 启动发送


esp_err_t rmt_transmit(
    rmt_channel_handle_t tx_channel,//发送通道句柄
    rmt_encoder_handle_t encoder, //编码器句柄
    const void *payload, //指向需要发送的值
    size_t payload_bytes, //发送的值的大小
    const rmt_transmit_config_t *config//发送的配置结构体
)


一段简单的控制WS2812B的应用举例


/**
 * Copyright (C) 2024-2034 HalfMoon2.
 * All rights reserved.
 * 
 * @file 	 Filename without the absolute path
 * @brief 	 Brief description
 * @author 	 HalfMoon2
 * @date 	 2025-06-05
 * @version	 v0.1
 * 
 * @revision history:
 * 	 2025-06-05 - Initial version.
 */
#include <stdio.h>
#include "driver/rmt_common.h"
#include "driver/rmt_tx.h"
#include "driver/rmt_encoder.h"
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>

void app_main(void)
{
	uint8_t value[3]={0x0f,0xb0,0x01};
	rmt_channel_handle_t tx_chan = NULL;
	rmt_tx_channel_config_t tx_chan_config = {
		.clk_src = RMT_CLK_SRC_DEFAULT,   // 选择时钟源
		.gpio_num = 48,                    // GPIO 编号
		.mem_block_symbols = 64,          // 内存块大小,即 64 * 4 = 256 字节
		.resolution_hz = 10 * 1000 * 1000, // 10 MHz 滴答分辨率,即 1 滴答 = 100ns
		.trans_queue_depth = 4,           // 设置后台等待处理的事务数量
		.flags.invert_out = false,        // 不反转输出信号
		.flags.with_dma = false,          // 不需要 DMA 后端
	};
	ESP_ERROR_CHECK(rmt_new_tx_channel(&tx_chan_config, &tx_chan));
	rmt_encoder_handle_t rmt_encoder=NULL;
	rmt_bytes_encoder_config_t rmt_bytes_encoder={
		.bit0={
			.level0=1,
			.duration0=0.3*10000000/1000000, //T0H
			.level1=0,
			.duration1=0.6*10000000/1000000, //T0L
		},
		.bit1={
			.level0=1,
			.duration0=0.6*10000000/1000000, //T1H
			.level1=0,
			.duration1=0.3*10000000/1000000, //T1L
		},
		.flags={
			.msb_first=1,
		}
	};

	rmt_new_bytes_encoder(&rmt_bytes_encoder,&rmt_encoder);
	
	rmt_transmit_config_t rmt_transmit_config={
		.loop_count=0,
	};
	
	ESP_ERROR_CHECK(rmt_enable(tx_chan));
	ESP_ERROR_CHECK(rmt_transmit(tx_chan,rmt_encoder,value,sizeof(value),&rmt_transmit_config));
}

fig:

fig:

从波形到颜色,说明这个简单的操作是可以很轻松实现WS2812B的控制的。

总结

整篇文章结构可以看出,如果要控制一个外设要做到以下步骤:

  1. 仔细阅读数据手册,
  2. 知道硬件电路的搭建,
  3. 看懂控制外设的协议(就是时序图),
  4. 匹配主控芯片可用的外设控制器,
  5. 阅读官方指导文档,查看当前需要的API函数
  6. 一步步填充API函数及相关结构体

这样一个简单的控制程序就完成了。当然最后的结果就跟我粘贴的代码一样,都放在了main函数里了,业界称为屎山。这个时候就需要通过面向对象的编程思想以及设计模式等知识,将代码规范化、增强其可移植性等。

要记住的是,只有理解了其基本的原理,才能万变不离其中。

作者: 二月半, 来源:面包板社区

链接: https://mbb.eet-china.com/blog/uid-me-1862109.html

版权声明:本文为博主原创,未经本人允许,禁止转载!

PARTNER CONTENT
1970-01-01

文章评论2条评论)

登录后参与讨论

二月半 2025-6-10 09:16

eeNick: 支持原创技术内容,再奖励100E币
      

eeNick 2025-6-10 08:59

支持原创技术内容,再奖励100E币
相关推荐阅读
二月半 2025-06-04 09:07
10. ESP32开发之LED闪烁和呼吸的实现
硬件电路介绍GPIO输出模式GPIO配置过程闪烁灯的源码LED PWM的控制器(LEDC)概述LEDC配置过程及现象整体流程硬件电路介绍电路图如下:只要有硬件基础的应该都知道上图中,当GPIO4的输出...
二月半 2025-06-02 21:24
【Milk-V Duo 开发板】+初用体验
许久未在面包板社区申请板卡评测了。这一次偶然最近的这款Milk-V Duo开发板正在评测。首次看到如此简单切功能强大的嵌入式平台:· 支持linux、rtos· 可接一路Camera,做人脸检测、目标...
二月半 2025-05-18 20:54
7. ESP32开发之freeRTOS的互斥量
什么是互斥量互斥量的应用场合互斥量的API函数基本代码结构互斥量使用举例递归锁递归锁举例总结什么是互斥量在freeRTOS中,多个任务访问一块共享资源,会产生竞争现象。比如马路上只有一个很早以前的电话...
二月半 2025-05-18 20:48
6. ESP32开发之freeRTOS的信号量
什么是信号量信号量能干啥信号量的函数实例举例总结什么是信号量简而言之,就是发出通知,接收通知的任务获得通知后去干啥啥。通知有多有少。自定义通知数量的,叫计数型信号量;只有有无(即“0”,“1”)通知的...
二月半 2025-04-17 16:27
【原创奖励】ESP开发之ubuntu环境搭建
1. 在Ubuntu官网下载Ubuntu server  20.04版本https://releases.ubuntu.com/20.04.6/2. 在vmware下安装Ubuntu3. 改...
我要评论
2
0
关闭 站长推荐上一条 /2 下一条