保姆级教程:用ESP32的RMT模块DIY一个万能红外遥控器(附完整代码)

张开发
2026/4/11 23:39:55 15 分钟阅读

分享文章

保姆级教程:用ESP32的RMT模块DIY一个万能红外遥控器(附完整代码)
用ESP32的RMT模块打造万能红外遥控器从硬件连接到完整代码实现周末整理房间时翻出一堆积灰的老旧遥控器——空调、电视、机顶盒、风扇每个电器都配着一个专属遥控器不仅占地方还经常找不到。作为物联网爱好者我决定用ESP32开发板和红外发射管DIY一个万能遥控器把这些功能全部整合到手机App里。本文将分享这个项目的完整实现过程从硬件连接到软件配置最后提供可直接编译运行的完整项目代码。1. 项目准备与硬件连接1.1 所需材料清单开始前需要准备以下硬件组件ESP32开发板推荐ESP32-S3内置RMT硬件模块红外发射二极管940nm波长如TSAL6200100Ω限流电阻面包板与连接线USB数据线用于供电和编程现有红外遥控器用于信号学习红外发射管的选型很重要常见的TSAL6200参数如下参数典型值说明波长940nm最佳匹配大多数家电接收器正向电压1.35V需配合限流电阻使用发射角度±20°指向性较强需对准设备1.2 电路连接示意图将组件按以下方式连接ESP32 GPIO引脚 → 100Ω电阻 → 红外发射管阳极 红外发射管阴极 → GND关键细节推荐使用GPIO17ESP32-S3的RMT通道默认引脚电阻值可根据实际亮度调整80-150Ω范围发射管要伸出开发板外避免被其他元件遮挡提示用手机摄像头可以检查红外管是否工作——正常发射时会看到紫色光点2. 开发环境配置与RMT基础2.1 ESP-IDF环境搭建我们使用官方ESP-IDF框架进行开发# 安装工具链以Linux为例 sudo apt-get install git wget flex bison gperf python3 python3-venv cmake ninja-build ccache libffi-dev libssl-dev dfu-util # 获取ESP-IDF git clone --recursive https://github.com/espressif/esp-idf.git cd esp-idf ./install.sh . ./export.sh # 创建项目目录 mkdir ~/esp32_ir_remote cd ~/esp32_ir_remote cp -r $IDF_PATH/examples/peripherals/rmt/ir_nec_transceiver .2.2 RMT模块工作原理ESP32的RMTRemote Control模块有8个独立通道每个通道都能将内存中的脉冲编码转换为实际信号输出支持载波调制38kHz红外常用频率硬件级精确时序控制分辨率可达12.5ns典型红外信号发送流程配置RMT发送通道创建编码器如NEC协议将指令数据转换为RMT符号通过GPIO输出调制信号3. 红外信号学习与解析3.1 搭建信号接收电路增加一个红外接收头如VS1838B用于学习现有遥控器信号VS1838B OUT → ESP32 GPIO18 VS1838B GND → GND VS1838B VCC → 3.3V3.2 NEC协议信号解析代码在main.c中添加以下接收逻辑#include driver/rmt_rx.h #include driver/rmt_tx.h #define RMT_IR_GPIO_NUM 18 void ir_nec_rx_example() { rmt_channel_handle_t rx_channel NULL; rmt_rx_channel_config_t rx_config { .gpio_num RMT_IR_GPIO_NUM, .clk_src RMT_CLK_SRC_DEFAULT, .resolution_hz 1000000, // 1MHz 1us/step .mem_block_symbols 64, .flags.invert_out false, }; ESP_ERROR_CHECK(rmt_new_rx_channel(rx_config, rx_channel)); rmt_receive_config_t receive_config { .signal_range_min_ns 1250, .signal_range_max_ns 12000000, }; ESP_ERROR_CHECK(rmt_enable(rx_channel)); rmt_symbol_word_t raw_symbols[64]; while(1) { // 等待接收完成 ESP_ERROR_CHECK(rmt_receive(rx_channel, raw_symbols, sizeof(raw_symbols), receive_config)); // 解析NEC协议 uint32_t addr 0; uint32_t cmd 0; for(int i0; i32; i) { if(raw_symbols[2*i1].duration0 1500) { addr | (1 i); } if(raw_symbols[2*i33].duration0 1500) { cmd | (1 i); } } printf(解码结果地址0x%02X 命令0x%02X\n, addr, cmd); } }4. 完整项目实现4.1 项目目录结构esp32_ir_remote/ ├── main/ │ ├── CMakeLists.txt │ ├── component.mk │ ├── ir_nec.h # NEC协议定义 │ ├── ir_remote.c # 主逻辑 │ └── ir_remote.h ├── Makefile └── sdkconfig4.2 核心发送代码实现// ir_remote.c #include driver/rmt_tx.h #include ir_nec.h #define RMT_TX_GPIO_NUM 17 void ir_nec_tx_example(uint16_t addr, uint16_t cmd) { rmt_channel_handle_t tx_channel NULL; rmt_tx_channel_config_t tx_config { .gpio_num RMT_TX_GPIO_NUM, .clk_src RMT_CLK_SRC_DEFAULT, .resolution_hz 1000000, .mem_block_symbols 64, }; ESP_ERROR_CHECK(rmt_new_tx_channel(tx_config, tx_channel)); rmt_encoder_handle_t nec_encoder NULL; ir_nec_encoder_config_t nec_encoder_config { .resolution 1000000, }; ESP_ERROR_CHECK(rmt_new_ir_nec_encoder(nec_encoder_config, nec_encoder)); rmt_transmit_config_t transmit_config { .loop_count 0, }; ir_nec_scan_code_t nec_code { .address addr, .command cmd, }; ESP_ERROR_CHECK(rmt_enable(tx_channel)); ESP_ERROR_CHECK(rmt_transmit(tx_channel, nec_encoder, nec_code, sizeof(nec_code), transmit_config)); ESP_ERROR_CHECK(rmt_tx_wait_all_done(tx_channel, 1000)); }4.3 常用家电红外码库在ir_nec.h中预存常见设备的红外编码// 空调控制指令 #define AC_POWER_TOGGLE 0x45 #define AC_MODE_AUTO 0x46 #define AC_TEMP_UP 0x47 #define AC_TEMP_DOWN 0x44 // 电视控制指令 #define TV_POWER 0x01 #define TV_VOL_UP 0x02 #define TV_VOL_DOWN 0x03 #define TV_CH_UP 0x04 #define TV_CH_DOWN 0x05 // 自定义设备地址 #define DEV_AC 0x00FF #define DEV_TV 0xFE015. 进阶功能与优化5.1 通过WiFi实现手机控制添加WiFi连接和HTTP服务器功能#include esp_http_server.h httpd_handle_t start_webserver(void) { httpd_config_t config HTTPD_DEFAULT_CONFIG(); httpd_handle_t server NULL; if (httpd_start(server, config) ESP_OK) { httpd_uri_t ir_cmd { .uri /api/ir, .method HTTP_POST, .handler ir_command_handler, }; httpd_register_uri_handler(server, ir_cmd); } return server; } esp_err_t ir_command_handler(httpd_req_t *req) { char buf[50]; int ret httpd_req_recv(req, buf, sizeof(buf)); if(ret 0) { uint16_t addr, cmd; sscanf(buf, addr%hucmd%hu, addr, cmd); ir_nec_tx_example(addr, cmd); } httpd_resp_send(req, OK, HTTPD_RESP_USE_STRLEN); return ESP_OK; }5.2 信号发送优化技巧提升红外信号发射距离和稳定性的方法电源优化单独为红外发射管供电3.3V线性稳压在VCC和GND之间添加100uF电容软件优化增加载波调制深度重复发送3次指令间隔100msvoid robust_send(uint16_t addr, uint16_t cmd) { for(int i0; i3; i) { ir_nec_tx_example(addr, cmd); vTaskDelay(pdMS_TO_TICKS(100)); } }硬件优化使用多个红外管并联需相应减小电阻值添加反射罩增强指向性6. 实际应用案例6.1 创建统一控制面板将不同设备的常用功能整合到一个界面typedef struct { const char* name; uint16_t addr; uint16_t cmd; } ir_command_t; const ir_command_t control_panel[] { {客厅空调开, DEV_AC, AC_POWER_TOGGLE}, {客厅温度, DEV_AC, AC_TEMP_UP}, {主卧电视开, DEV_TV, TV_POWER}, {音量, DEV_TV, TV_VOL_UP}, // 添加更多命令... };6.2 定时任务实现利用ESP32的RTC功能实现定时控制#include esp_timer.h void schedule_ir_command(uint16_t addr, uint16_t cmd, int delay_sec) { esp_timer_create_args_t timer_args { .callback timer_callback, .arg (void*)((addr 16) | cmd), .name ir_timer }; esp_timer_handle_t timer; esp_timer_create(timer_args, timer); esp_timer_start_once(timer, delay_sec * 1000000); } void timer_callback(void* arg) { uint32_t param (uint32_t)arg; uint16_t addr param 16; uint16_t cmd param 0xFFFF; ir_nec_tx_example(addr, cmd); }这个项目最让我惊喜的是ESP32的RMT模块的精度——实测可以准确控制到微秒级的红外信号时序完美兼容各种老旧家电。遇到不响应的情况时建议先用手机摄像头检查红外管是否正常工作再逐步排查协议和时序问题。

更多文章