Files
Dorm-Air-Conditioner-Smart-…/ir_control.cpp
2025-09-22 18:49:14 +08:00

385 lines
13 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "ir_control.h"
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;
}
// 配置RMT接收通道
rmt_config_t rmt_rx_config = RMT_DEFAULT_CONFIG_RX((gpio_num_t)IR_RECEIVE_PIN, RMT_RX_CHANNEL);
rmt_rx_config.clk_div = RMT_CLK_DIV;
rmt_rx_config.mem_block_num = RMT_MEM_BLOCK_NUM;
rmt_rx_config.rx_config.filter_en = RMT_RX_FILTER_EN;
rmt_rx_config.rx_config.filter_ticks_thresh = RMT_RX_FILTER_THRESH_US;
rmt_rx_config.rx_config.idle_threshold = RMT_RX_IDLE_THRESH_US;
err = rmt_config(&rmt_rx_config);
if (err != ESP_OK) {
Serial.printf("RMT接收通道配置失败: %s\n", esp_err_to_name(err));
return;
}
err = rmt_driver_install(RMT_RX_CHANNEL, 1000, 0);
if (err != ESP_OK) {
Serial.printf("RMT接收驱动安装失败: %s\n", esp_err_to_name(err));
return;
}
Serial.println("红外控制模块初始化完成 (使用RMT)");
Serial.printf("发送引脚: %d (RMT通道: %d)\n", IR_SEND_PIN, RMT_TX_CHANNEL);
Serial.printf("接收引脚: %d (RMT通道: %d)\n", IR_RECEIVE_PIN, RMT_RX_CHANNEL);
Serial.printf("载波频率: %d Hz\n", RMT_TX_CARRIER_FREQ_HZ);
Serial.printf("时钟分辨率: %d us\n", RMT_CLK_DIV);
}
bool checkIRSignalStart() {
// 使用RMT检查是否有信号开始
// 启动接收并检查是否立即有数据
rmt_rx_start(RMT_RX_CHANNEL, true);
// 等待短时间检查是否有信号
vTaskDelay(pdMS_TO_TICKS(1));
// 获取RMT环形缓冲区句柄
RingbufHandle_t rb = NULL;
esp_err_t err = rmt_get_ringbuf_handle(RMT_RX_CHANNEL, &rb);
if (err != ESP_OK) {
rmt_rx_stop(RMT_RX_CHANNEL);
return false;
}
// 检查RMT接收缓冲区是否有数据
size_t rx_size = 0;
rmt_item32_t* items = (rmt_item32_t*)xRingbufferReceive(rb, &rx_size, 0);
bool hasSignal = (items != nullptr && rx_size > 0);
if (items) {
vRingbufferReturnItem(rb, (void*)items);
}
rmt_rx_stop(RMT_RX_CHANNEL);
return hasSignal;
}
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("开始接收红外信号 (使用RMT)...");
// 启动RMT接收
rmt_rx_start(RMT_RX_CHANNEL, true);
// 获取RMT环形缓冲区句柄
RingbufHandle_t rb = NULL;
esp_err_t err = rmt_get_ringbuf_handle(RMT_RX_CHANNEL, &rb);
if (err != ESP_OK) {
Serial.printf("获取RMT缓冲区句柄失败: %s\n", esp_err_to_name(err));
rmt_rx_stop(RMT_RX_CHANNEL);
return signal;
}
// 等待接收数据
size_t rx_size = 0;
rmt_item32_t* items = (rmt_item32_t*)xRingbufferReceive(rb, &rx_size, pdMS_TO_TICKS(RECEIVE_TIMEOUT_US / 1000));
if (items == nullptr || rx_size == 0) {
Serial.println("RMT接收超时或无数据");
rmt_rx_stop(RMT_RX_CHANNEL);
return signal;
}
// 计算接收到的项目数量
size_t item_count = rx_size / sizeof(rmt_item32_t);
Serial.printf("接收到 %d 个RMT项目\n", item_count);
if (item_count == 0) {
Serial.println("接收到的数据为空");
vRingbufferReturnItem(rb, (void*)items);
rmt_rx_stop(RMT_RX_CHANNEL);
return signal;
}
// 分配临时数组存储时序数据
unsigned int* tempData = (unsigned int*)malloc(item_count * 2 * sizeof(unsigned int));
if (tempData == nullptr) {
Serial.println("临时数据内存分配失败");
vRingbufferReturnItem(rb, (void*)items);
rmt_rx_stop(RMT_RX_CHANNEL);
return signal;
}
int tempLength = 0;
// 解析RMT数据项
for (size_t i = 0; i < item_count; i++) {
// 每个RMT项目包含两个时间段level0的持续时间和level1的持续时间
if (items[i].duration0 > 0 && tempLength < item_count * 2) {
tempData[tempLength++] = items[i].duration0;
}
if (items[i].duration1 > 0 && tempLength < item_count * 2) {
tempData[tempLength++] = items[i].duration1;
}
}
// 释放RMT缓冲区
vRingbufferReturnItem(rb, (void*)items);
rmt_rx_stop(RMT_RX_CHANNEL);
if (tempLength > 0) {
// 分离mark和space时间
signal.markCount = (tempLength + 1) / 2; // 奇数索引是mark
signal.spaceCount = tempLength / 2; // 偶数索引是space
// 分配mark时间数组
if (signal.markCount > 0) {
signal.markTimes = (unsigned int*)malloc(signal.markCount * sizeof(unsigned int));
if (signal.markTimes == nullptr) {
Serial.println("mark时间数组内存分配失败");
free(tempData);
return signal;
}
// 复制mark时间从索引0开始每隔2个取一个
for (int i = 0; i < signal.markCount; i++) {
signal.markTimes[i] = tempData[i * 2];
}
}
// 分配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;
}
free(tempData);
return signal;
}
// 复制space时间从索引1开始每隔2个取一个
for (int i = 0; i < signal.spaceCount; i++) {
signal.spaceTimes[i] = tempData[i * 2 + 1];
}
}
signal.isValid = true;
Serial.printf("RMT信号接收成功mark数量: %d, space数量: %d\n", signal.markCount, signal.spaceCount);
} else {
Serial.println("未接收到有效的RMT信号数据");
}
free(tempData);
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;
// 分配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);
}