#include "ir_control.h" // IRremoteESP8266库的接收器对象 // 增加缓冲区大小到500以支持长信号,超时设置为15ms IRrecv irrecv(IR_RECEIVE_PIN, 500, 15); void initIRControl() { // 配置RMT发送通道 rmt_config_t rmt_tx_config = RMT_DEFAULT_CONFIG_TX((gpio_num_t)IR_SEND_PIN, RMT_TX_CHANNEL); rmt_tx_config.clk_div = RMT_CLK_DIV; rmt_tx_config.mem_block_num = RMT_MEM_BLOCK_NUM; rmt_tx_config.tx_config.carrier_en = RMT_TX_CARRIER_EN; rmt_tx_config.tx_config.carrier_freq_hz = RMT_TX_CARRIER_FREQ_HZ; rmt_tx_config.tx_config.carrier_duty_percent = RMT_TX_CARRIER_DUTY_PERCENT; rmt_tx_config.tx_config.carrier_level = RMT_TX_CARRIER_LEVEL; rmt_tx_config.tx_config.idle_level = RMT_IDLE_LEVEL; rmt_tx_config.tx_config.idle_output_en = true; esp_err_t err = rmt_config(&rmt_tx_config); if (err != ESP_OK) { Serial.printf("RMT发送通道配置失败: %s\n", esp_err_to_name(err)); return; } err = rmt_driver_install(RMT_TX_CHANNEL, 0, 0); if (err != ESP_OK) { Serial.printf("RMT发送驱动安装失败: %s\n", esp_err_to_name(err)); return; } Serial.println("红外控制模块初始化完成 (使用RMT发送 + IRremoteESP8266接收)"); Serial.printf("发送引脚: %d (RMT通道: %d)\n", IR_SEND_PIN, RMT_TX_CHANNEL); Serial.printf("接收引脚: %d (IRremoteESP8266)\n", IR_RECEIVE_PIN); Serial.printf("载波频率: %d Hz\n", RMT_TX_CARRIER_FREQ_HZ); Serial.printf("时钟分辨率: %d us\n", RMT_CLK_DIV); Serial.printf("接收缓冲区大小: 500, 超时: 15ms\n"); // 初始化IRremoteESP8266接收器 irrecv.enableIRIn(); // 启用红外接收 Serial.println("IRremoteESP8266接收器已启用"); } bool checkIRSignalStart() { // 使用IRremoteESP8266检查是否有信号开始 decode_results results; // 尝试解码,但不等待完整信号 if (irrecv.decode(&results, nullptr, 0, false)) { // 有信号开始,恢复接收状态 irrecv.resume(); return true; } return false; } IRSignal receiveIRSignal() { IRSignal signal; signal.markTimes = nullptr; signal.spaceTimes = nullptr; signal.markCount = 0; signal.spaceCount = 0; signal.carrierFreq = IR_CARRIER_FREQ; signal.isValid = false; Serial.println("开始接收红外信号 (使用IRremoteESP8266)..."); Serial.println("请按下遥控器按键..."); decode_results results; // 清空接收缓冲区 irrecv.resume(); // 等待接收完整的红外信号 unsigned long startTime = millis(); while (millis() - startTime < (RECEIVE_TIMEOUT_US / 1000)) { if (irrecv.decode(&results)) { Serial.printf("检测到红外信号!原始数据长度: %d\n", results.rawlen); Serial.printf("Raw数组总长度: %d\n", results.rawlen); // 检查缓冲区溢出 if (results.overflow) { Serial.println("警告: 接收缓冲区溢出!信号可能不完整"); Serial.println("建议: 增加缓冲区大小或检查信号长度"); } // 检查信号长度是否合理(典型红外信号应该有足够的数据) if (results.rawlen < 10) { Serial.printf("警告: 信号长度过短 (%d),可能不是完整信号\n", results.rawlen); } else if (results.rawlen >= 490) { // 接近缓冲区上限 Serial.printf("警告: 信号长度接近缓冲区上限 (%d/500),可能被截断\n", results.rawlen); } // 打印接收到的协议信息 Serial.printf("协议: %s\n", typeToString(results.decode_type).c_str()); Serial.printf("值: 0x%08X\n", results.value); Serial.printf("位数: %d\n", results.bits); if (results.rawlen > 1) { // IRremoteESP8266的rawbuf包含原始时序数据 // rawbuf[0]是未使用的,实际数据从rawbuf[1]开始 // 数据格式:mark, space, mark, space, ... int dataLength = results.rawlen - 1; // 减去未使用的第一个元素 // 计算mark和space的数量 signal.markCount = (dataLength + 1) / 2; // 奇数位置是mark signal.spaceCount = dataLength / 2; // 偶数位置是space Serial.printf("数据长度: %d, mark数量: %d, space数量: %d\n", dataLength, signal.markCount, signal.spaceCount); // 分配mark时间数组 if (signal.markCount > 0) { signal.markTimes = (unsigned int*)malloc(signal.markCount * sizeof(unsigned int)); if (signal.markTimes == nullptr) { Serial.println("mark时间数组内存分配失败"); irrecv.resume(); return signal; } // 提取mark时间(奇数索引:1, 3, 5, ...) for (int i = 0; i < signal.markCount; i++) { int rawIndex = i * 2 + 1; // 1, 3, 5, ... if (rawIndex < results.rawlen) { // IRremoteESP8266的时间单位是tick,需要转换为微秒 // 默认tick = 50us signal.markTimes[i] = results.rawbuf[rawIndex] * kRawTick; } } } // 分配space时间数组 if (signal.spaceCount > 0) { signal.spaceTimes = (unsigned int*)malloc(signal.spaceCount * sizeof(unsigned int)); if (signal.spaceTimes == nullptr) { Serial.println("space时间数组内存分配失败"); if (signal.markTimes != nullptr) { free(signal.markTimes); signal.markTimes = nullptr; } irrecv.resume(); return signal; } // 提取space时间(偶数索引:2, 4, 6, ...) for (int i = 0; i < signal.spaceCount; i++) { int rawIndex = i * 2 + 2; // 2, 4, 6, ... if (rawIndex < results.rawlen) { // IRremoteESP8266的时间单位是tick,需要转换为微秒 signal.spaceTimes[i] = results.rawbuf[rawIndex] * kRawTick; } } } signal.isValid = true; Serial.printf("IRremoteESP8266信号接收成功,mark数量: %d, space数量: %d\n", signal.markCount, signal.spaceCount); // 检查信号头部特征(典型的9000us mark + 4500us space) if (signal.markCount > 0 && signal.spaceCount > 0) { unsigned int firstMark = signal.markTimes[0]; unsigned int firstSpace = signal.spaceTimes[0]; Serial.printf("信号头部: mark=%dus, space=%dus\n", firstMark, firstSpace); // 检查是否有典型的信号头 if (firstMark > 8000 && firstMark < 10000 && firstSpace > 3500 && firstSpace < 5500) { Serial.println("检测到标准信号头 (约9ms mark + 4.5ms space)"); } else { Serial.println("警告: 信号头不符合标准格式,可能丢失或不完整"); } } // 打印前几个时序数据用于调试 Serial.print("前几个时序数据(us): "); for (int i = 0; i < min(10, (int)results.rawlen - 1); i++) { Serial.printf("%d ", results.rawbuf[i + 1] * kRawTick); } Serial.println(); // 打印原始数据的十六进制表示 Serial.print("原始数据(tick): "); for (int i = 1; i < min(11, (int)results.rawlen); i++) { Serial.printf("%d ", results.rawbuf[i]); } Serial.println(); } else { Serial.println("接收到的信号数据长度不足"); } // 恢复接收状态 irrecv.resume(); break; } // 短暂延时避免CPU占用过高 delay(10); } if (!signal.isValid) { Serial.println("IRremoteESP8266接收超时或无有效信号"); Serial.println("请检查:"); Serial.println("1. 遥控器是否有电"); Serial.println("2. 红外接收器是否正确连接到引脚 " + String(IR_RECEIVE_PIN)); Serial.println("3. 遥控器是否对准红外接收器"); } return signal; } // generateCarrier函数已被RMT模块替代,不再需要 bool sendIRSignal(const IRSignal& signal) { if (!isValidIRSignal(signal)) { Serial.println("信号无效,无法发送"); return false; } Serial.println("开始发送红外信号 (使用RMT)..."); Serial.printf("载波频率: %d Hz\n", signal.carrierFreq); Serial.printf("mark数量: %d, space数量: %d\n", signal.markCount, signal.spaceCount); // 计算需要的RMT项目数量 int maxCount = max(signal.markCount, signal.spaceCount); size_t item_count = maxCount; // 计算并显示raw数组总长度(mark + space的总数) int totalRawLength = signal.markCount + signal.spaceCount; Serial.printf("发送Raw数组总长度: %d (mark: %d + space: %d)\n", totalRawLength, signal.markCount, signal.spaceCount); // 分配RMT项目数组 rmt_item32_t* items = (rmt_item32_t*)malloc(item_count * sizeof(rmt_item32_t)); if (items == nullptr) { Serial.println("RMT项目内存分配失败"); return false; } // 构建RMT数据项 for (int i = 0; i < maxCount; i++) { items[i].level0 = 1; // mark期间为高电平(载波调制) items[i].duration0 = (i < signal.markCount) ? signal.markTimes[i] : 0; items[i].level1 = 0; // space期间为低电平(无载波) items[i].duration1 = (i < signal.spaceCount) ? signal.spaceTimes[i] : 0; } // 发送RMT数据 esp_err_t err = rmt_write_items(RMT_TX_CHANNEL, items, item_count, true); if (err != ESP_OK) { Serial.printf("RMT发送失败: %s\n", esp_err_to_name(err)); free(items); return false; } // 等待发送完成 err = rmt_wait_tx_done(RMT_TX_CHANNEL, pdMS_TO_TICKS(1000)); if (err != ESP_OK) { Serial.printf("RMT发送等待超时: %s\n", esp_err_to_name(err)); free(items); return false; } free(items); Serial.println("RMT信号发送完成"); return true; } void freeIRSignal(IRSignal& signal) { if (signal.markTimes != nullptr) { free(signal.markTimes); signal.markTimes = nullptr; } if (signal.spaceTimes != nullptr) { free(signal.spaceTimes); signal.spaceTimes = nullptr; } signal.markCount = 0; signal.spaceCount = 0; signal.carrierFreq = 0; signal.isValid = false; } IRSignal copyIRSignal(const IRSignal& source) { IRSignal copy; copy.markTimes = nullptr; copy.spaceTimes = nullptr; copy.markCount = 0; copy.spaceCount = 0; copy.carrierFreq = 0; copy.isValid = false; if (!isValidIRSignal(source)) { return copy; } // 复制mark时间数组 if (source.markCount > 0 && source.markTimes != nullptr) { copy.markTimes = (unsigned int*)malloc(source.markCount * sizeof(unsigned int)); if (copy.markTimes == nullptr) { Serial.println("复制mark时间数组时内存分配失败"); return copy; } for (int i = 0; i < source.markCount; i++) { copy.markTimes[i] = source.markTimes[i]; } copy.markCount = source.markCount; } // 复制space时间数组 if (source.spaceCount > 0 && source.spaceTimes != nullptr) { copy.spaceTimes = (unsigned int*)malloc(source.spaceCount * sizeof(unsigned int)); if (copy.spaceTimes == nullptr) { Serial.println("复制space时间数组时内存分配失败"); if (copy.markTimes != nullptr) { free(copy.markTimes); copy.markTimes = nullptr; copy.markCount = 0; } return copy; } for (int i = 0; i < source.spaceCount; i++) { copy.spaceTimes[i] = source.spaceTimes[i]; } copy.spaceCount = source.spaceCount; } copy.carrierFreq = source.carrierFreq; copy.isValid = true; return copy; } void printIRSignal(const IRSignal& signal, int maxPrint) { if (!isValidIRSignal(signal)) { Serial.println("信号无效,无法打印"); return; } Serial.println("=== 红外信号数据 ==="); Serial.print("载波频率: "); Serial.print(signal.carrierFreq); Serial.println(" Hz"); Serial.print("mark数量: "); Serial.println(signal.markCount); Serial.print("space数量: "); Serial.println(signal.spaceCount); Serial.print("信号有效: "); Serial.println(signal.isValid ? "是" : "否"); // 打印mark时间 int markPrintCount = (maxPrint == 0) ? signal.markCount : min(maxPrint, signal.markCount); Serial.println("Mark时间 (微秒):"); for (int i = 0; i < markPrintCount; i++) { Serial.print("Mark "); Serial.print(i); Serial.print(": "); Serial.print(signal.markTimes[i]); Serial.println(" us"); } if (markPrintCount < signal.markCount) { Serial.print("... 还有 "); Serial.print(signal.markCount - markPrintCount); Serial.println(" 个mark数据点未显示"); } // 打印space时间 int spacePrintCount = (maxPrint == 0) ? signal.spaceCount : min(maxPrint, signal.spaceCount); Serial.println("Space时间 (微秒):"); for (int i = 0; i < spacePrintCount; i++) { Serial.print("Space "); Serial.print(i); Serial.print(": "); Serial.print(signal.spaceTimes[i]); Serial.println(" us"); } if (spacePrintCount < signal.spaceCount) { Serial.print("... 还有 "); Serial.print(signal.spaceCount - spacePrintCount); Serial.println(" 个space数据点未显示"); } Serial.println("=================="); } bool isValidIRSignal(const IRSignal& signal) { return (signal.isValid && ((signal.markTimes != nullptr && signal.markCount > 0) || (signal.spaceTimes != nullptr && signal.spaceCount > 0)) && signal.carrierFreq > 0); }