Compare commits
6 Commits
30585041b6
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 670b86d200 | |||
| 41e14ec828 | |||
| 9f663aed0b | |||
| 21d21f8247 | |||
| e1a749a8cd | |||
| b3c6b4cde9 |
@@ -190,8 +190,11 @@ void sendStoredIRSignal(String buttonName) {
|
||||
// 从字符串解析红外信号
|
||||
IRSignal parseIRSignalFromString(String dataStr) {
|
||||
IRSignal signal;
|
||||
signal.data = nullptr;
|
||||
signal.length = 0;
|
||||
signal.markTimes = nullptr;
|
||||
signal.spaceTimes = nullptr;
|
||||
signal.markCount = 0;
|
||||
signal.spaceCount = 0;
|
||||
signal.carrierFreq = IR_CARRIER_FREQ;
|
||||
signal.isValid = false;
|
||||
|
||||
if (dataStr.length() == 0) {
|
||||
@@ -203,11 +206,11 @@ IRSignal parseIRSignalFromString(String dataStr) {
|
||||
for (int i = 0; i < dataStr.length(); i++) {
|
||||
if (dataStr[i] == ',') commaCount++;
|
||||
}
|
||||
signal.length = commaCount + 1;
|
||||
int totalLength = commaCount + 1;
|
||||
|
||||
// 分配内存
|
||||
signal.data = (unsigned int*)malloc(signal.length * sizeof(unsigned int));
|
||||
if (signal.data == nullptr) {
|
||||
// 分配临时内存存储原始数据
|
||||
unsigned int* tempData = (unsigned int*)malloc(totalLength * sizeof(unsigned int));
|
||||
if (tempData == nullptr) {
|
||||
return signal;
|
||||
}
|
||||
|
||||
@@ -217,27 +220,78 @@ IRSignal parseIRSignalFromString(String dataStr) {
|
||||
for (int i = 0; i <= dataStr.length(); i++) {
|
||||
if (i == dataStr.length() || dataStr[i] == ',') {
|
||||
String valueStr = dataStr.substring(startPos, i);
|
||||
signal.data[index] = valueStr.toInt();
|
||||
tempData[index] = valueStr.toInt();
|
||||
index++;
|
||||
startPos = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// 分离mark和space数据
|
||||
signal.markCount = (totalLength + 1) / 2;
|
||||
signal.spaceCount = totalLength / 2;
|
||||
|
||||
// 分配mark时间数组
|
||||
if (signal.markCount > 0) {
|
||||
signal.markTimes = (unsigned int*)malloc(signal.markCount * sizeof(unsigned int));
|
||||
if (signal.markTimes == nullptr) {
|
||||
free(tempData);
|
||||
return signal;
|
||||
}
|
||||
|
||||
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) {
|
||||
if (signal.markTimes != nullptr) {
|
||||
free(signal.markTimes);
|
||||
signal.markTimes = nullptr;
|
||||
signal.markCount = 0;
|
||||
}
|
||||
free(tempData);
|
||||
return signal;
|
||||
}
|
||||
|
||||
for (int i = 0; i < signal.spaceCount; i++) {
|
||||
signal.spaceTimes[i] = tempData[i * 2 + 1];
|
||||
}
|
||||
}
|
||||
|
||||
free(tempData);
|
||||
signal.isValid = true;
|
||||
return signal;
|
||||
}
|
||||
|
||||
// 将红外信号转换为字符串
|
||||
String irSignalToString(const IRSignal& signal) {
|
||||
if (!signal.isValid || signal.data == nullptr || signal.length == 0) {
|
||||
if (!signal.isValid ||
|
||||
(signal.markTimes == nullptr && signal.spaceTimes == nullptr) ||
|
||||
(signal.markCount == 0 && signal.spaceCount == 0)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
String result = "";
|
||||
for (int i = 0; i < signal.length; i++) {
|
||||
if (i > 0) result += ",";
|
||||
result += String(signal.data[i]);
|
||||
int maxCount = max(signal.markCount, signal.spaceCount);
|
||||
|
||||
// 重建原始时序数据:交替输出mark和space
|
||||
for (int i = 0; i < maxCount; i++) {
|
||||
// 添加mark时间
|
||||
if (i < signal.markCount) {
|
||||
if (result.length() > 0) result += ",";
|
||||
result += String(signal.markTimes[i]);
|
||||
}
|
||||
|
||||
// 添加space时间
|
||||
if (i < signal.spaceCount) {
|
||||
if (result.length() > 0) result += ",";
|
||||
result += String(signal.spaceTimes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -751,7 +805,7 @@ void handleStartRecord() {
|
||||
prefs.putString(("ir_" + buttonName).c_str(), irDataStr);
|
||||
|
||||
Serial.println("红外信号录入成功: " + buttonName);
|
||||
Serial.println("信号长度: " + String(signal.length));
|
||||
Serial.println("mark数量: " + String(signal.markCount) + ", space数量: " + String(signal.spaceCount));
|
||||
|
||||
freeIRSignal(signal);
|
||||
server.send(200, "application/json", "{\"success\":true}");
|
||||
@@ -768,7 +822,7 @@ void handleSendIR() {
|
||||
return;
|
||||
}
|
||||
|
||||
DynamicJsonDocument doc(200);
|
||||
DynamicJsonDocument doc(26700);
|
||||
deserializeJson(doc, server.arg("plain"));
|
||||
|
||||
String buttonName = doc["button"];
|
||||
@@ -818,6 +872,12 @@ void handleSetSettings() {
|
||||
prefs.putFloat("min_temp", minTemp);
|
||||
prefs.putFloat("max_temp", maxTemp);
|
||||
|
||||
Serial.printf("温度设置已更新 - 最低: %.1f°C, 最高: %.1f°C\n", minTemp, maxTemp);
|
||||
|
||||
// 温度设置更改后立即执行一次判断
|
||||
Serial.println("温度设置已更改,立即执行核心判断...");
|
||||
executeJudgeLogic();
|
||||
|
||||
server.send(200, "application/json", "{\"success\":true}");
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ extern "C" {
|
||||
// 预处理参数
|
||||
#define MEL_FMIN 0.0f // Mel滤波器最低频率
|
||||
#define MEL_FMAX 8000.0f // Mel滤波器最高频率
|
||||
#define WINDOW_TYPE_HANN 1 // 汉宁窗
|
||||
#define WINDOW_TYPE_HANN 1 // 海宁窗
|
||||
#define ENERGY_THRESHOLD 0.01f // 音频活动检测阈值
|
||||
#define CONFIDENCE_THRESHOLD 0.6f // 预测置信度阈值
|
||||
|
||||
@@ -100,6 +100,8 @@ float calculate_rms_energy(const int16_t* audio_data, int length);
|
||||
void audio_model_cleanup(void);
|
||||
const unsigned char* get_audio_model_data(void);
|
||||
size_t get_audio_model_size(void);
|
||||
const char* get_class_name_en(AudioClassType class_id);
|
||||
const char* get_class_name_cn(AudioClassType class_id);
|
||||
|
||||
// ==================== 核心API函数 ====================
|
||||
|
||||
@@ -124,7 +126,7 @@ int audio_model_init(void) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 预计算汉宁窗
|
||||
// 预计算海宁窗
|
||||
for (int i = 0; i < N_FFT; i++) {
|
||||
g_preprocessor.window_buffer[i] = 0.5f * (1.0f - cosf(2.0f * M_PI * i / (N_FFT - 1)));
|
||||
}
|
||||
@@ -193,128 +195,73 @@ int audio_model_predict(const int16_t* audio_data, int audio_length, AudioPredic
|
||||
yield();
|
||||
#endif
|
||||
|
||||
// 使用栈上的小缓冲区替代大数组,减少内存使用
|
||||
const int REDUCED_FEATURES = 32; // 减少特征数量
|
||||
float mel_features[REDUCED_FEATURES];
|
||||
// TODO: 集成TensorFlow Lite模型进行真实的音频识别
|
||||
// 当前使用audio_model_data.h中的TensorFlow Lite模型数据
|
||||
// 需要实现以下步骤:
|
||||
// 1. 初始化TensorFlow Lite解释器
|
||||
// 2. 加载模型数据 (audio_model_data)
|
||||
// 3. 预处理音频数据为模型输入格式
|
||||
// 4. 执行推理
|
||||
// 5. 解析输出结果
|
||||
|
||||
// 简化的音频特征提取,避免复杂的Mel频谱图计算
|
||||
if (preprocess_audio_to_mel_simple(audio_data, audio_length, mel_features, REDUCED_FEATURES) != 0) {
|
||||
strcpy(g_last_error, "音频预处理失败");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 添加看门狗喂狗
|
||||
// 临时实现:基于音频能量的简单分类,提供更合理的结果
|
||||
#ifdef ARDUINO
|
||||
yield();
|
||||
Serial.println("警告:当前使用临时实现,等待TensorFlow Lite模型集成");
|
||||
#endif
|
||||
|
||||
// 使用简化的特征分析替代复杂的TensorFlow Lite推理
|
||||
// 计算基本统计特征
|
||||
float mean_energy = 0.0f;
|
||||
float energy_variance = 0.0f;
|
||||
float max_energy = -1000.0f;
|
||||
float min_energy = 1000.0f;
|
||||
// 计算音频能量来做简单的分类判断
|
||||
float rms_energy = calculate_rms_energy(audio_data, audio_length);
|
||||
|
||||
// 计算平均能量和能量范围
|
||||
for (int i = 0; i < REDUCED_FEATURES; i++) {
|
||||
mean_energy += mel_features[i];
|
||||
if (mel_features[i] > max_energy) max_energy = mel_features[i];
|
||||
if (mel_features[i] < min_energy) min_energy = mel_features[i];
|
||||
|
||||
// 定期喂狗
|
||||
if (i % 10 == 0) {
|
||||
// 添加调试信息:检查音频数据的实际值
|
||||
#ifdef ARDUINO
|
||||
yield();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
mean_energy /= REDUCED_FEATURES;
|
||||
int non_zero_count = 0;
|
||||
int16_t min_val = 32767, max_val = -32768;
|
||||
long long sum_abs = 0;
|
||||
|
||||
// 计算能量方差
|
||||
for (int i = 0; i < REDUCED_FEATURES; i++) {
|
||||
float diff = mel_features[i] - mean_energy;
|
||||
energy_variance += diff * diff;
|
||||
for (int i = 0; i < min(100, audio_length); i++) { // 检查前100个样本
|
||||
if (audio_data[i] != 0) non_zero_count++;
|
||||
if (audio_data[i] < min_val) min_val = audio_data[i];
|
||||
if (audio_data[i] > max_val) max_val = audio_data[i];
|
||||
sum_abs += abs(audio_data[i]);
|
||||
}
|
||||
energy_variance /= REDUCED_FEATURES;
|
||||
|
||||
// 添加看门狗喂狗
|
||||
#ifdef ARDUINO
|
||||
yield();
|
||||
Serial.printf("音频数据调试: 非零样本=%d/100, 最小值=%d, 最大值=%d, 平均绝对值=%lld\n",
|
||||
non_zero_count, min_val, max_val, sum_abs/100);
|
||||
#endif
|
||||
|
||||
// 基于简化特征的分类逻辑
|
||||
memset(result->class_probabilities, 0, sizeof(result->class_probabilities));
|
||||
// 基于能量水平进行简单分类
|
||||
AudioClassType predicted_class;
|
||||
float confidence;
|
||||
|
||||
// 使用能量和方差进行简单分类
|
||||
float energy_range = max_energy - min_energy;
|
||||
|
||||
// 钥匙声特征:中等能量,高方差
|
||||
float key_score = 0.0f;
|
||||
if (mean_energy > -5.0f && mean_energy < -2.0f && energy_variance > 2.0f) {
|
||||
key_score = 0.4f;
|
||||
if (rms_energy > 0.1f) {
|
||||
// 高能量:可能是关门声或钥匙声
|
||||
if (rms_energy > 0.3f) {
|
||||
predicted_class = AUDIO_CLASS_DOOR_CLOSING;
|
||||
confidence = 0.75f;
|
||||
} else {
|
||||
predicted_class = AUDIO_CLASS_KEY_JINGLING;
|
||||
confidence = 0.65f;
|
||||
}
|
||||
} else if (rms_energy > 0.02f) {
|
||||
// 中等能量:室内有人
|
||||
predicted_class = AUDIO_CLASS_PERSON_PRESENT;
|
||||
confidence = 0.70f;
|
||||
} else {
|
||||
// 低能量:室内无人
|
||||
predicted_class = AUDIO_CLASS_PERSON_ABSENT;
|
||||
confidence = 0.80f;
|
||||
}
|
||||
|
||||
// 关门声特征:高能量,低方差
|
||||
float door_score = 0.0f;
|
||||
if (mean_energy > -2.0f && energy_variance < 1.0f) {
|
||||
door_score = 0.5f;
|
||||
}
|
||||
// 设置结果
|
||||
result->predicted_class = predicted_class;
|
||||
result->confidence = confidence;
|
||||
|
||||
// 人员活动声特征:中等能量,中等方差
|
||||
float person_score = 0.0f;
|
||||
if (mean_energy > -6.0f && mean_energy < -1.0f && energy_variance > 0.5f && energy_variance < 3.0f) {
|
||||
person_score = 0.3f;
|
||||
}
|
||||
|
||||
// 无人声特征:低能量,低方差
|
||||
float absent_score = 0.0f;
|
||||
if (mean_energy < -8.0f && energy_variance < 0.5f) {
|
||||
absent_score = 0.6f;
|
||||
}
|
||||
|
||||
// 添加看门狗喂狗
|
||||
#ifdef ARDUINO
|
||||
yield();
|
||||
#endif
|
||||
|
||||
// 归一化概率
|
||||
float total_score = key_score + door_score + person_score + absent_score;
|
||||
if (total_score < 0.1f) {
|
||||
// 默认为有人状态
|
||||
person_score = 0.4f;
|
||||
total_score = 0.4f;
|
||||
}
|
||||
|
||||
// 添加少量随机性模拟AI不确定性
|
||||
uint32_t audio_hash = 0;
|
||||
for (int i = 0; i < audio_length; i += 1000) {
|
||||
audio_hash = audio_hash * 31 + (uint32_t)abs(audio_data[i]);
|
||||
}
|
||||
float noise_factor = (float)(audio_hash % 50) / 1000.0f; // 0-0.05的随机因子
|
||||
|
||||
result->class_probabilities[AUDIO_CLASS_KEY_JINGLING] = (key_score / total_score) + noise_factor;
|
||||
result->class_probabilities[AUDIO_CLASS_DOOR_CLOSING] = (door_score / total_score) + noise_factor * 0.8f;
|
||||
result->class_probabilities[AUDIO_CLASS_PERSON_PRESENT] = (person_score / total_score) + noise_factor * 0.6f;
|
||||
result->class_probabilities[AUDIO_CLASS_PERSON_ABSENT] = (absent_score / total_score) + noise_factor * 0.4f;
|
||||
|
||||
// 重新归一化
|
||||
float prob_sum = 0.0f;
|
||||
// 设置概率分布
|
||||
for (int i = 0; i < NUM_CLASSES; i++) {
|
||||
prob_sum += result->class_probabilities[i];
|
||||
}
|
||||
if (prob_sum > 0) {
|
||||
for (int i = 0; i < NUM_CLASSES; i++) {
|
||||
result->class_probabilities[i] /= prob_sum;
|
||||
}
|
||||
}
|
||||
|
||||
// 找到最高概率的类别
|
||||
result->confidence = 0.0f;
|
||||
result->predicted_class = AUDIO_CLASS_PERSON_PRESENT;
|
||||
for (int i = 0; i < NUM_CLASSES; i++) {
|
||||
if (result->class_probabilities[i] > result->confidence) {
|
||||
result->confidence = result->class_probabilities[i];
|
||||
result->predicted_class = (AudioClassType)i;
|
||||
if (i == (int)predicted_class) {
|
||||
result->class_probabilities[i] = confidence;
|
||||
} else {
|
||||
result->class_probabilities[i] = (1.0f - confidence) / (NUM_CLASSES - 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,6 +276,11 @@ int audio_model_predict(const int16_t* audio_data, int audio_length, AudioPredic
|
||||
g_total_confidence += result->confidence;
|
||||
}
|
||||
|
||||
#ifdef ARDUINO
|
||||
Serial.printf("音频能量: %.4f, 预测类别: %s, 置信度: %.2f\n",
|
||||
rms_energy, get_class_name_cn(predicted_class), confidence);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -406,22 +358,16 @@ int preprocess_audio_to_mel_simple(const int16_t* audio_data, int audio_length,
|
||||
int16_t prev_sample = 0;
|
||||
|
||||
for (int i = start_idx; i < end_idx; i++) {
|
||||
// 音频增益放大20倍,然后进行能量计算
|
||||
int32_t amplified_sample = (int32_t)audio_data[i] * 20;
|
||||
// 防止溢出,限制在int16_t范围内
|
||||
if (amplified_sample > 32767) amplified_sample = 32767;
|
||||
if (amplified_sample < -32768) amplified_sample = -32768;
|
||||
|
||||
float sample = (float)amplified_sample / 32768.0f;
|
||||
float sample = (float)audio_data[i] / 32768.0f;
|
||||
energy += sample * sample;
|
||||
|
||||
// 零交叉率计算 - 使用放大后的音频数据
|
||||
// 零交叉率计算
|
||||
if (i > start_idx &&
|
||||
((amplified_sample >= 0 && prev_sample < 0) ||
|
||||
(amplified_sample < 0 && prev_sample >= 0))) {
|
||||
((audio_data[i] >= 0 && prev_sample < 0) ||
|
||||
(audio_data[i] < 0 && prev_sample >= 0))) {
|
||||
zero_crossings += 1.0f;
|
||||
}
|
||||
prev_sample = (int16_t)amplified_sample;
|
||||
prev_sample = audio_data[i];
|
||||
|
||||
// 添加看门狗喂狗,防止长时间计算
|
||||
#ifdef ARDUINO
|
||||
@@ -479,22 +425,16 @@ int preprocess_audio_to_mel(const int16_t* audio_data, int audio_length, float*
|
||||
int16_t prev_sample = 0;
|
||||
|
||||
for (int i = start_idx; i < end_idx; i++) {
|
||||
// 音频增益放大20倍,然后进行能量计算
|
||||
int32_t amplified_sample = (int32_t)audio_data[i] * 20;
|
||||
// 防止溢出,限制在int16_t范围内
|
||||
if (amplified_sample > 32767) amplified_sample = 32767;
|
||||
if (amplified_sample < -32768) amplified_sample = -32768;
|
||||
|
||||
float sample = (float)amplified_sample / 32768.0f;
|
||||
float sample = (float)audio_data[i] / 32768.0f;
|
||||
energy += sample * sample;
|
||||
|
||||
// 零交叉率计算 - 使用放大后的音频数据
|
||||
// 零交叉率计算
|
||||
if (i > start_idx &&
|
||||
((amplified_sample >= 0 && prev_sample < 0) ||
|
||||
(amplified_sample < 0 && prev_sample >= 0))) {
|
||||
((audio_data[i] >= 0 && prev_sample < 0) ||
|
||||
(audio_data[i] < 0 && prev_sample >= 0))) {
|
||||
zero_crossings += 1.0f;
|
||||
}
|
||||
prev_sample = (int16_t)amplified_sample;
|
||||
prev_sample = audio_data[i];
|
||||
|
||||
// 添加看门狗喂狗,防止长时间计算
|
||||
#ifdef ARDUINO
|
||||
@@ -670,13 +610,7 @@ float calculate_rms_energy(const int16_t* audio_data, int length) {
|
||||
|
||||
float sum = 0.0f;
|
||||
for (int i = 0; i < length; i++) {
|
||||
// 音频增益放大20倍,然后计算RMS能量
|
||||
int32_t amplified_sample = (int32_t)audio_data[i] * 20;
|
||||
// 防止溢出,限制在int16_t范围内
|
||||
if (amplified_sample > 32767) amplified_sample = 32767;
|
||||
if (amplified_sample < -32768) amplified_sample = -32768;
|
||||
|
||||
float sample = (float)amplified_sample / 32768.0f; // 归一化到[-1,1]
|
||||
float sample = (float)audio_data[i] / 32768.0f; // 归一化到[-1,1]
|
||||
sum += sample * sample;
|
||||
}
|
||||
return sqrtf(sum / length);
|
||||
|
||||
7
core.h
7
core.h
@@ -188,10 +188,13 @@ int judge() {
|
||||
// 获取用户设置的温度范围 (从Preferences读取)
|
||||
Preferences prefs;
|
||||
prefs.begin("DACSC", true); // 只读模式
|
||||
float min_temp = prefs.getFloat("min_temp", 5.0); // 默认最低温度22°C
|
||||
float max_temp = prefs.getFloat("max_temp", 28.0); // 默认最高温度26°C
|
||||
float min_temp = prefs.getFloat("min_temp", 10.0); // 默认最低温度10°C
|
||||
float max_temp = prefs.getFloat("max_temp", 28.0); // 默认最高温度28°C
|
||||
prefs.end();
|
||||
|
||||
// 打印当前使用的温度设置
|
||||
Serial.printf("当前温度设置 - 最低: %.1f°C, 最高: %.1f°C\n", min_temp, max_temp);
|
||||
|
||||
// 判断逻辑:基于节假日、音频识别、时间、温度和湿度的智能控制
|
||||
|
||||
// 规则1:节假日规则(优先级最高)
|
||||
|
||||
418
ir_control.cpp
418
ir_control.cpp
@@ -1,169 +1,336 @@
|
||||
#include "ir_control.h"
|
||||
|
||||
void initIRControl() {
|
||||
pinMode(IR_RECEIVE_PIN, INPUT);
|
||||
pinMode(IR_SEND_PIN, OUTPUT);
|
||||
digitalWrite(IR_SEND_PIN, LOW);
|
||||
// IRremoteESP8266库的接收器对象
|
||||
// 增加缓冲区大小到500以支持长信号,超时设置为15ms
|
||||
IRrecv irrecv(IR_RECEIVE_PIN, 500, 15);
|
||||
|
||||
Serial.println("红外控制模块初始化完成");
|
||||
Serial.print("接收引脚: ");
|
||||
Serial.println(IR_RECEIVE_PIN);
|
||||
Serial.print("发送引脚: ");
|
||||
Serial.println(IR_SEND_PIN);
|
||||
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() {
|
||||
return (digitalRead(IR_RECEIVE_PIN) == LOW);
|
||||
// 使用IRremoteESP8266检查是否有信号开始
|
||||
decode_results results;
|
||||
|
||||
// 尝试解码,但不等待完整信号
|
||||
if (irrecv.decode(&results, nullptr, 0, false)) {
|
||||
// 有信号开始,恢复接收状态
|
||||
irrecv.resume();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
IRSignal receiveIRSignal() {
|
||||
IRSignal signal;
|
||||
signal.data = nullptr;
|
||||
signal.length = 0;
|
||||
signal.markTimes = nullptr;
|
||||
signal.spaceTimes = nullptr;
|
||||
signal.markCount = 0;
|
||||
signal.spaceCount = 0;
|
||||
signal.carrierFreq = IR_CARRIER_FREQ;
|
||||
signal.isValid = false;
|
||||
|
||||
Serial.println("开始接收红外信号...");
|
||||
Serial.println("开始接收红外信号 (使用IRremoteESP8266)...");
|
||||
Serial.println("请按下遥控器按键...");
|
||||
|
||||
// 分配内存存储信号数据
|
||||
signal.data = (unsigned int*)malloc(MAX_SIGNAL_LENGTH * sizeof(unsigned int));
|
||||
if (signal.data == nullptr) {
|
||||
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;
|
||||
}
|
||||
|
||||
unsigned long startTime = micros();
|
||||
unsigned long lastChange = startTime;
|
||||
bool currentState = HIGH;
|
||||
bool lastState = HIGH;
|
||||
|
||||
// 等待信号开始(第一个低电平)
|
||||
while (digitalRead(IR_RECEIVE_PIN) == HIGH && (micros() - startTime) < RECEIVE_TIMEOUT_US) {
|
||||
delayMicroseconds(10);
|
||||
// 提取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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((micros() - startTime) >= RECEIVE_TIMEOUT_US) {
|
||||
Serial.println("等待信号超时");
|
||||
free(signal.data);
|
||||
signal.data = nullptr;
|
||||
// 分配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;
|
||||
}
|
||||
|
||||
Serial.println("检测到信号开始");
|
||||
lastChange = micros();
|
||||
lastState = LOW;
|
||||
signal.length = 0;
|
||||
|
||||
// 接收信号数据
|
||||
while (signal.length < MAX_SIGNAL_LENGTH) {
|
||||
currentState = digitalRead(IR_RECEIVE_PIN);
|
||||
|
||||
if (currentState != lastState) {
|
||||
// 状态改变,记录持续时间
|
||||
unsigned long duration = micros() - lastChange;
|
||||
signal.data[signal.length] = duration;
|
||||
signal.length++;
|
||||
|
||||
lastState = currentState;
|
||||
lastChange = micros();
|
||||
// 提取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;
|
||||
}
|
||||
|
||||
// 检查是否信号结束(高电平持续时间过长)
|
||||
if (currentState == HIGH && (micros() - lastChange) > SIGNAL_END_TIMEOUT_US) {
|
||||
Serial.println("检测到信号结束");
|
||||
break;
|
||||
}
|
||||
|
||||
// 总体超时检查
|
||||
if ((micros() - startTime) > RECEIVE_TIMEOUT_US) {
|
||||
Serial.println("接收总体超时");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (signal.length > 0) {
|
||||
signal.isValid = true;
|
||||
Serial.print("信号接收成功,长度: ");
|
||||
Serial.println(signal.length);
|
||||
Serial.printf("IRremoteESP8266信号接收成功,mark数量: %d, space数量: %d\n",
|
||||
signal.markCount, signal.spaceCount);
|
||||
|
||||
// 重新分配内存以节省空间
|
||||
signal.data = (unsigned int*)realloc(signal.data, signal.length * sizeof(unsigned int));
|
||||
if (signal.data == nullptr) {
|
||||
Serial.println("内存重新分配失败");
|
||||
signal.isValid = false;
|
||||
signal.length = 0;
|
||||
}
|
||||
// 检查信号头部特征(典型的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("未接收到有效信号");
|
||||
free(signal.data);
|
||||
signal.data = nullptr;
|
||||
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("开始发送红外信号...");
|
||||
Serial.print("信号长度: ");
|
||||
Serial.println(signal.length);
|
||||
Serial.println("开始发送红外信号 (使用RMT)...");
|
||||
Serial.printf("载波频率: %d Hz\n", signal.carrierFreq);
|
||||
Serial.printf("mark数量: %d, space数量: %d\n", signal.markCount, signal.spaceCount);
|
||||
|
||||
// 禁用中断以确保精确的时序
|
||||
noInterrupts();
|
||||
// 计算需要的RMT项目数量
|
||||
int maxCount = max(signal.markCount, signal.spaceCount);
|
||||
size_t item_count = maxCount;
|
||||
|
||||
bool state = LOW; // 红外信号通常以低电平开始
|
||||
// 计算并显示raw数组总长度(mark + space的总数)
|
||||
int totalRawLength = signal.markCount + signal.spaceCount;
|
||||
Serial.printf("发送Raw数组总长度: %d (mark: %d + space: %d)\n",
|
||||
totalRawLength, signal.markCount, signal.spaceCount);
|
||||
|
||||
for (int i = 0; i < signal.length; i++) {
|
||||
digitalWrite(IR_SEND_PIN, state);
|
||||
delayMicroseconds(signal.data[i]);
|
||||
state = !state; // 切换状态
|
||||
// 分配RMT项目数组
|
||||
rmt_item32_t* items = (rmt_item32_t*)malloc(item_count * sizeof(rmt_item32_t));
|
||||
if (items == nullptr) {
|
||||
Serial.println("RMT项目内存分配失败");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 确保最后是低电平
|
||||
digitalWrite(IR_SEND_PIN, LOW);
|
||||
// 构建RMT数据项
|
||||
for (int i = 0; i < maxCount; i++) {
|
||||
items[i].level0 = 1; // mark期间为高电平(载波调制)
|
||||
items[i].duration0 = (i < signal.markCount) ? signal.markTimes[i] : 0;
|
||||
|
||||
// 重新启用中断
|
||||
interrupts();
|
||||
items[i].level1 = 0; // space期间为低电平(无载波)
|
||||
items[i].duration1 = (i < signal.spaceCount) ? signal.spaceTimes[i] : 0;
|
||||
}
|
||||
|
||||
Serial.println("信号发送完成");
|
||||
// 发送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.data != nullptr) {
|
||||
free(signal.data);
|
||||
signal.data = nullptr;
|
||||
if (signal.markTimes != nullptr) {
|
||||
free(signal.markTimes);
|
||||
signal.markTimes = nullptr;
|
||||
}
|
||||
signal.length = 0;
|
||||
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.data = nullptr;
|
||||
copy.length = 0;
|
||||
copy.markTimes = nullptr;
|
||||
copy.spaceTimes = nullptr;
|
||||
copy.markCount = 0;
|
||||
copy.spaceCount = 0;
|
||||
copy.carrierFreq = 0;
|
||||
copy.isValid = false;
|
||||
|
||||
if (!isValidIRSignal(source)) {
|
||||
return copy;
|
||||
}
|
||||
|
||||
// 分配内存
|
||||
copy.data = (unsigned int*)malloc(source.length * sizeof(unsigned int));
|
||||
if (copy.data == nullptr) {
|
||||
Serial.println("复制信号时内存分配失败");
|
||||
// 复制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.length; i++) {
|
||||
copy.data[i] = source.data[i];
|
||||
for (int i = 0; i < source.markCount; i++) {
|
||||
copy.markTimes[i] = source.markTimes[i];
|
||||
}
|
||||
copy.markCount = source.markCount;
|
||||
}
|
||||
|
||||
copy.length = source.length;
|
||||
// 复制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;
|
||||
@@ -176,33 +343,56 @@ void printIRSignal(const IRSignal& signal, int maxPrint) {
|
||||
}
|
||||
|
||||
Serial.println("=== 红外信号数据 ===");
|
||||
Serial.print("信号长度: ");
|
||||
Serial.println(signal.length);
|
||||
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 ? "是" : "否");
|
||||
|
||||
int printCount = (maxPrint == 0) ? signal.length : min(maxPrint, signal.length);
|
||||
|
||||
Serial.println("原始数据 (微秒):");
|
||||
for (int i = 0; i < printCount; i++) {
|
||||
Serial.print("Index ");
|
||||
// 打印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.data[i]);
|
||||
Serial.print(" us (");
|
||||
Serial.print((i % 2 == 0) ? "LOW" : "HIGH");
|
||||
Serial.println(")");
|
||||
Serial.print(signal.markTimes[i]);
|
||||
Serial.println(" us");
|
||||
}
|
||||
|
||||
if (printCount < signal.length) {
|
||||
if (markPrintCount < signal.markCount) {
|
||||
Serial.print("... 还有 ");
|
||||
Serial.print(signal.length - printCount);
|
||||
Serial.println(" 个数据点未显示");
|
||||
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.data != nullptr && signal.length > 0 && signal.isValid);
|
||||
return (signal.isValid &&
|
||||
((signal.markTimes != nullptr && signal.markCount > 0) ||
|
||||
(signal.spaceTimes != nullptr && signal.spaceCount > 0)) &&
|
||||
signal.carrierFreq > 0);
|
||||
}
|
||||
36
ir_control.h
36
ir_control.h
@@ -2,11 +2,18 @@
|
||||
#define IR_CONTROL_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "driver/rmt.h"
|
||||
#include "driver/gpio.h"
|
||||
#include <IRrecv.h>
|
||||
#include <IRutils.h>
|
||||
|
||||
// 红外信号结构体
|
||||
struct IRSignal {
|
||||
unsigned int* data; // 原始信号数据数组(微秒)
|
||||
int length; // 信号长度
|
||||
unsigned int* markTimes; // mark时间数组(微秒)
|
||||
unsigned int* spaceTimes; // space时间数组(微秒)
|
||||
int markCount; // mark数量
|
||||
int spaceCount; // space数量
|
||||
unsigned int carrierFreq; // 载波频率(Hz)
|
||||
bool isValid; // 信号是否有效
|
||||
};
|
||||
|
||||
@@ -16,6 +23,22 @@ struct IRSignal {
|
||||
#define MAX_SIGNAL_LENGTH 1000
|
||||
#define RECEIVE_TIMEOUT_US 1000000 // 1秒接收超时
|
||||
#define SIGNAL_END_TIMEOUT_US 50000 // 50ms信号结束判断
|
||||
#define IR_CARRIER_FREQ 38000 // 38kHz载波频率
|
||||
#define CARRIER_PERIOD_US 26 // 38kHz载波周期(微秒)
|
||||
|
||||
// RMT配置参数
|
||||
#define RMT_TX_CHANNEL RMT_CHANNEL_0 // RMT发送通道
|
||||
#define RMT_RX_CHANNEL RMT_CHANNEL_1 // RMT接收通道
|
||||
#define RMT_CLK_DIV 80 // RMT时钟分频器 (80MHz / 80 = 1MHz, 1us分辨率)
|
||||
#define RMT_MEM_BLOCK_NUM 1 // RMT内存块数量
|
||||
#define RMT_TX_CARRIER_EN true // 启用发送载波
|
||||
#define RMT_TX_CARRIER_FREQ_HZ 38000 // 发送载波频率
|
||||
#define RMT_TX_CARRIER_DUTY_PERCENT 33 // 载波占空比
|
||||
#define RMT_TX_CARRIER_LEVEL RMT_CARRIER_LEVEL_HIGH // 载波电平
|
||||
#define RMT_IDLE_LEVEL RMT_IDLE_LEVEL_LOW // 空闲电平
|
||||
#define RMT_RX_FILTER_EN true // 启用接收滤波器
|
||||
#define RMT_RX_FILTER_THRESH_US 100 // 接收滤波器阈值(微秒)
|
||||
#define RMT_RX_IDLE_THRESH_US 10000 // 接收空闲阈值(微秒)
|
||||
|
||||
/**
|
||||
* 初始化红外控制模块
|
||||
@@ -33,9 +56,12 @@ bool checkIRSignalStart();
|
||||
|
||||
/**
|
||||
* 接收红外信号
|
||||
* @return IRSignal 包含原始红外信号数据的结构体
|
||||
* - data: 指向信号数据数组的指针
|
||||
* - length: 信号数据长度
|
||||
* @return IRSignal 包含红外信号mark/space时序和载波频率的结构体
|
||||
* - markTimes: 指向mark时间数组的指针
|
||||
* - spaceTimes: 指向space时间数组的指针
|
||||
* - markCount: mark数量
|
||||
* - spaceCount: space数量
|
||||
* - carrierFreq: 载波频率
|
||||
* - isValid: 是否成功接收到有效信号
|
||||
*
|
||||
* 注意:调用者需要在使用完毕后调用 freeIRSignal() 释放内存
|
||||
|
||||
Reference in New Issue
Block a user