23

您所在的位置:网站首页 rmt什么单位 23

23

2024-07-17 19:02| 来源: 网络整理| 查看: 265

ESP32 IDF库中的RMT驱动

RMT(Remote Control Module)驱动是ESP-IDF库中的一个重要组成部分,它主要用于处理远程控制编码和解码。

红外遥控器介绍 一、红外遥控技术介绍

红外遥控是一种无线、非接触控制技术,具有抗干扰能力强,信息传输可靠,功耗低,成本低,易实现等显著优点。它被诸多电子设备特别是家用电器广泛采用,并越来越多的应用到计算机和手机系统中。

红外遥控系统由发射和接收两大部分组成,应用编码/解码专用集成电路芯片来进行控制操作。发射部分包括键盘矩阵、编码调制、LED红外发送器;接收部分包括光、电转换放大器、解调、解码电路。

二、红外器件特性

红外遥控器主要由红外发射器和红外接收器两部分组成。

红外发射器:红外发射器通常是一个红外LED,它可以发射红外光。当电流通过LED时,它会发射出红外光。红外LED的发射波长通常在940nm左右,这是人眼无法看到的红外光。

红外接收器:红外接收器是一个光电二极管,它可以将接收到的红外光转换为电信号。红外接收器通常有一个滤波器,可以过滤掉大部分的环境光,只接收特定频率的红外光。

红外发射管也是属于二极管类,红外发射电路通常使用三极管控制红外发射器的导通或者截至,在导通的时候,红外发射管会发射出红外光,反之,就不会发射出红外光。虽然我们用肉眼看不到红外光,但是我们借助手机摄像头就能看到红外光。但是红外接收管的特性是当接收到红外载波信号时,OUT 引脚输出低电平;假如没有接收到红外载波信号时,OUT 引脚输出高电平。

红外载波信号其实就是由一个个红外载波周期组成。在频率为 ( 38 K H z ) (38KHz ) (38KHz)下,红外载波周期约等于 26.3 u s ( 1 s / 38 K H z ≈ 26.3 u s ) 26.3us(1s / 38KHz ≈ 26.3us) 26.3us(1s/38KHz≈26.3us)。在一个红外载波发射周期里,发射红外光时间 8.77 u s 8.77us 8.77us 和不发射红外光 17.53 u s 17.53us 17.53us,发射红外光的占空比一般为 1 / 3 1/3 1/3。相对的,整个周期内不发射红外光,就是载波不发射周期。在红外遥控器内已经把载波和不载波信号处理好,我们需要做的就是识别遥控器按键发射出的信号,信号也是遵循某种协议的。

这里推荐一个视频可以快速了解红外控制器件:

📻一帧红外遥控信号,竟如此复杂,超乎你的想象!红外遥控的工作原理!

三、红外编解码协议介绍

红外遥控器通常使用特定的编解码协议来发送和接收数据。目前广泛使用的是:PWM(脉冲宽度调制)的NEC 协议和Philips PPM(脉冲位置调制)的 RC-5 协议的。这里以NEC为主讲解ESP32 红外遥控 (RMT)

NEC 协议,其特征如下:

8 位地址和 8 位指令长度地址和命令 2 次传输(确保可靠性)PWM 脉冲位置调制,以发射红外载波的占比代表“0”和“1”载波频率为 38Khz位时间为 1.125ms 或 2.25ms

在 NEC 协议中,如何为协议中的数据‘0’或者‘1’这里分开红外接收器和红外发射器 红外发射器:

发送协议数据‘0’ = 发射载波信号560us + 不发射载波信号 560us发送协议数据‘1’ = 发射载波信号 560us + 不发射载波信号 1680us

红外发射器的位定义如下图所示。 在这里插入图片描述 🚨需要注意的是红外编码发送的时候,并不单单是通过高低电平发送的,是在38khz的载波下进行发送的

红外接收器:

接收到协议数据‘0’ = 560us 低电平 + 560us 高电平接收到协议数据‘1’ = 560us 低电平 + 1680us 高电平

红外接收器的位定义如下图所示 在这里插入图片描述 NEC协议的数据格式包括以下几个部分:

同步码:这是一个9ms的低电平+4.5ms的高电平,用于同步。地址码和地址反码:这是一个8位数据格式,低位在前,高位在后。控制码和控制反码:这部分用于表示具体的控制命令。

如果你长时间按住遥控按钮,使用NEC协议的红外遥控器将会发射一个以110ms为周期的重复码。每一次用户按下遥控器按钮,遥控器在发送一次指令码后,就不会再发送指令码了,而是发送一段重复码。

RMT驱动 简介

ESP32-S3的RMT 是一个红外发送和接收控制器,可通过软件加解密多种红外协议。RMT 模块可以实现模块内置 RAM 中的脉冲编码转换为信号输出,或将模块的输入信号转换为脉冲编码存入 RAM 中。此外,RMT 模块可以选择是否对输出信号进行载波调制,也可以选择是否对输入信号进行滤波和去噪处理。

RMT 共有八个通道,编码为 0 ~ 7,各通道可独立用于发送或接收信号:

0 ~ 3 通道专门用于发送信号;4 ~ 7 通道专门用于接收信号。

每个发送通道和接收通道分别有一组功能相同的寄存器。另外,发送通道 3 和接收通道 7 对应的 RAM 支持 DMA访问,因此还有 DMA 相关的控制和状态寄存器。

RMT 符号的内存布局

RMT 硬件定义了自己的数据模式,称为 RMT 符号。对于一个 RMT 符号的位字段:每个符号由两对两个值组成,每对中的第一个值是一个 15 位的值,表示信号持续时间,以 RMT 滴答计。每对中的第二个值是一个 1 位的值,表示信号的逻辑电平,即高电平或低电平。

请添加图片描述

RMT RX驱动的接收解码 1️⃣安装 RMT 接收通道

该函数用于安装 RMT 接收通道,其函数原型如下所示:

esp_err_t rmt_new_rx_channel(const rmt_rx_channel_config_t *config, rmt_channel_handle_t *ret_chan);

该函数的形参描述,如下表所示:

形参描述config指向配置 RMT 接收通道的指针ret_chan返回的通用 RMT 通道句柄

该函数的使用示例,如下所示:

#include "driver/gpio.h" void example_fun(void) { // 初始化 RMT 接收通道句柄为 NULL rmt_channel_handle_t rx_chan = NULL; // 配置 RMT 接收通道参数 rmt_rx_channel_config_t rx_chan_config = { .clk_src = RMT_CLK_SRC_DEFAULT, // 使用默认时钟源 .gpio_num = 0, // 使用 GPIO0 .mem_block_symbols = 64, // 内存块大小为 64 .resolution_hz = 1 * 1000 * 1000, // 分辨率为 1MHz .trans_queue_depth = 4, // 传输队列深度为 4 .flags.invert_out = false, // 不反转输出信号 .flags.with_dma = false, // 不使用 DMA }; // 安装 RMT 接收通道,并检查错误 ESP_ERROR_CHECK(rmt_new_rx_channel(&rx_chan_config, &rx_chan)); } 2️⃣配置 RMT 接收通道的回调函数

该函数用于配置 RMT 接收通道的回调函数,其函数原型如下所示:

esp_err_t rmt_rx_register_event_callbacks(rmt_channel_handle_t rx_channel, const rmt_rx_event_callbacks_t *cbs, void *user_data);

该函数的形参描述,如下表所示:

形参描述rx_channel创建的 RMT 通道句柄cbsRMT 接收事件回调函数结构体指针user_data用户数据,将直接传递给回调函数

该函数的使用示例,如下所示:

#include "driver/gpio.h" void example_fun(void) { QueueHandle_t receive_queue; rmt_channel_handle_t rx_chan = NULL; rmt_rx_channel_config_t rx_chan_config = { .clk_src = RMT_CLK_SRC_DEFAULT, // 使用默认时钟源 .gpio_num = 0, // 使用 GPIO0 .mem_block_symbols = 64, // 内存块大小为 64 .resolution_hz = 1 * 1000 * 1000, // 分辨率为 1MHz .trans_queue_depth = 4, // 传输队列深度为 4 .flags.invert_out = false, // 不反转输出信号 .flags.with_dma = false, // 不使用 DMA }; ESP_ERROR_CHECK(rmt_new_rx_channel(&rx_chan_config, &rx_chan)); // 创建用于存储接收完成事件数据的队列 receive_queue = xQueueCreate(1, sizeof(rmt_rx_done_event_data_t)); assert(receive_queue); //检查队列是否创建成功 rmt_rx_event_callbacks_t cbs = { .on_recv_done = RMT_Rx_Done_Callback, // 设置接收完成回调函数 }; ESP_ERROR_CHECK(rmt_rx_register_event_callbacks(rx_chan, &cbs, receive_queue)); } 3️⃣创建一个基于 NEC 协议的 RMT 编码器

该函数用于创建一个基于 NEC 协议的 RMT 编码器,其函数原型如下所示:

esp_err_t rmt_new_ir_nec_encoder(const ir_nec_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder);

该函数的形参描述,如下表所示:

形参描述config指向 RMT 编码器配置的指针ret_encoder返回的 RMT 编码器句柄

该函数的使用示例,如下所示:

#include "driver/gpio.h" void example_fun(void) { // 配置 NEC 编码器参数 ir_nec_encoder_config_t nec_encoder_cfg = { .resolution = 1000000, // 分辨率为 1MHz }; // 初始化 NEC 编码器句柄 rmt_encoder_handle_t nec_encoder = NULL; // 创建基于 NEC 协议的 RMT 编码器,并检查错误 ESP_ERROR_CHECK(rmt_new_ir_nec_encoder(&nec_encoder_cfg, &nec_encoder)); } 4️⃣使能 RMT 接收通道

该函数用于使能 RMT 接收通道,其函数原型如下所示:

esp_err_t rmt_enable(rmt_channel_handle_t channel);

该函数的形参描述,如下表所示:

形参描述channel创建的 RMT 通道句柄

该函数的使用示例,如下所示:

#include "driver/gpio.h" void example_fun(void) { // 初始化 RMT 接收通道句柄为 NULL rmt_channel_handle_t rx_channel = NULL; //省略中间过程..... // 使能 RMT 接收通道,并检查错误 rmt_enable(rx_channel); } 5️⃣启动 RMT 接收通道的接收任务

该函数用于启动 RMT 接收通道的接收任务,其函数原型如下所示:

esp_err_t rmt_receive(rmt_channel_handle_t rx_channel, void *buffer, size_t buffer_size, const rmt_receive_config_t *config);

该函数的形参描述,如下表所示:

形参描述rx_channel创建的 RMT 通道句柄buffer用于存储接收到的 RMT 符号的缓冲区buffer_size缓冲区大小config接收特定配置

该函数的使用示例,如下所示:

#include "driver/gpio.h" void example_fun(void) { // 声明用于存储接收到的 RMT 符号的缓冲区 rmt_symbol_word_t raw_symbols[64]; // 配置接收任务特定配置 rmt_receive_config_t receive_config; // 启动 RMT 接收通道的接收任务,并检查错误 rmt_receive(rx_channel, raw_symbols, sizeof(raw_symbols), &receive_config); } RMT TX驱动的发送 1️⃣安装 RMT 发送通道

该函数用于安装 RMT 接收通道,其函数原型如下所示:

esp_err_t rmt_new_tx_channel(const rmt_tx_channel_config_t *config, rmt_channel_handle_t *ret_chan);

该函数的形参描述,如下表所示:

形参描述config指向配置 RMT 发送通道的指针ret_chan返回的通用 RMT 通道句柄

该函数的使用示例,如下所示:

#include "driver/gpio.h" // 定义示例函数 void example_fun(void) { // 声明 RMT 通道句柄 rmt_channel_handle_t tx_chan = NULL; // 定义 RMT 发送通道配置 rmt_tx_channel_config_t tx_chan_config = { .clk_src = RMT_CLK_SRC_DEFAULT, // 使用默认时钟源 .gpio_num = 0, // GPIO0 用于发送 .mem_block_symbols = 64, // 内存块大小为 64 .resolution_hz = 1 * 1000 * 1000, // 分辨率为 1 MHz .trans_queue_depth = 4, // 传输队列深度为 4 .flags.invert_out = false, // 输出不反转 .flags.with_dma = false, // 不使用 DMA }; // 调用函数安装 RMT 发送通道,并检查返回错误 ESP_ERROR_CHECK(rmt_new_tx_channel(&tx_chan_config, &tx_chan)); } 2️⃣使能 RMT 发送通道

该函数用于使能 RMT 发送通道,其函数原型如下所示:

esp_err_t rmt_enable(rmt_channel_handle_t channel);

该函数的形参描述,如下表所示:

形参描述channel创建的 RMT 通用通道 #include "driver/gpio.h" // 定义示例函数 void example_fun(void) { rmt_channel_handle_t tx_channel = NULL; // 声明 RMT 通道句柄 rmt_enable(tx_channel); // 调用函数使能 RMT 发送通道 } 3️⃣通过 RMT 发送通道传输数据

该函数用于启动 RMT 接收通道的接收任务,其函数原型如下所示:

esp_err_t rmt_transmit(rmt_channel_handle_t channel, rmt_encoder_t *encoder, const void *payload, size_t payload_bytes, const rmt_transmit_config_t *config)

该函数的形参描述,如下表所示:

形参描述channel创建的 RMT 通道encoder用户自己创建的编码器或者通过其它 API 构建的编码器payload要编码为 RMT 符号的原始数据payload_bytes“有效负载”的大小(以字节为单位)config发送特定配置 发送示例 #include "driver/gpio.h" #include "driver/rmt.h" // 定义示例函数 void example_fun(void) { // 1. 安装 RMT 发送通道 // 声明 RMT 通道句柄 rmt_channel_handle_t tx_chan = NULL; // 定义 RMT 发送通道配置 rmt_tx_channel_config_t tx_chan_config = { .clk_src = RMT_CLK_SRC_DEFAULT, // 使用默认时钟源 .gpio_num = GPIO_NUM_0, // GPIO0 用于发送 .mem_block_symbols = 64, // 内存块大小为 64 .resolution_hz = 1 * 1000 * 1000, // 分辨率为 1 MHz .trans_queue_depth = 4, // 传输队列深度为 4 .flags.invert_out = false, // 输出不反转 .flags.with_dma = false, // 不使用 DMA }; // 调用函数安装 RMT 发送通道,并检查返回错误 ESP_ERROR_CHECK(rmt_new_tx_channel(&tx_chan_config, &tx_chan)); // 2. 使能 RMT 发送通道 rmt_enable(tx_chan); // 调用函数使能 RMT 发送通道 // 3. 通过 RMT 发送通道传输数据 // 创建数据数组 uint8_t data[4] = {0x12, 0x34, 0x56, 0x78}; // 创建 RMT 编码器 rmt_encoder_t encoder; ESP_ERROR_CHECK(rmt_translator_init(&encoder, sizeof(data), false)); // 数据长度为4字节,不进行反转 // 创建 RMT 发送配置 rmt_transmit_config_t transmit_config = { .carrier_freq_hz = 38000, // 载波频率为38kHz .carrier_duty_percent = 50, // 载波占空比为50% .idle_level = RMT_IDLE_LEVEL_LOW, // 高电平空闲 .carrier_level = RMT_CARRIER_LEVEL_HIGH, // 高电平为载波 .loop_en = false, // 关闭循环发送 .loop_count = 0, // 循环次数为0 }; // 使用 RMT 发送通道传输数据 ESP_ERROR_CHECK(rmt_transmit(tx_chan, &encoder, data, sizeof(data), &transmit_config)); } 总结

RMT驱动是ESP32的一个强大功能,它可以方便地处理各种远程控制协议,对于开发物联网和嵌入式系统具有很大的帮助。

参考资料 ESP-IDF 红外遥控 (RMT) 正点原子DNESP32S3 开发板教程-IDF 版



【本文地址】


今日新闻


推荐新闻


    CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3