1 硬件
相关说明:hx1838 红外遥控(1):接收时序的解码-优快云博客
接线图:
2 解码原理
红外遥控器采用了NEC编码规则:
NEC 载波频率为 38Khz
引导码:9ms 高电平 + 4.5ms 低电平
1 码 :0.56 ms 高电平 + 0.56 ms 低电平
0 码 : 0.56ms 高电平 + 1.68 ms 低电平
结束码 :0.56ms 高电平
数据帧格式:引导码 + 地址 + 地址反码 + 键值 + 键值反码 + 结束码
重复帧格式:9ms 高电平 + 2.25ms低电平 + 结束位 + 结束码
高位在前,即首先收到的是高位的数据
3 代码
实际接线 接的D8 用于解析
手动的红外遥控器是小孩的,可以接收,但无法解码:
等待空闲状态... 等待引导脉冲... 未知协议特征(低:13.90ms, 高:29.83ms) 捕获信号中...
代码如下:
% 增强版红外解码程序 - 解决解码失败问题
% 初始化Arduino对象
clear
a = arduino('COM5', 'Uno'); % 修改为你的端口和板型
configurePin(a, 'D8', 'DigitalInput');
% 增强参数配置
irPin = 'D8'; % 红外接收模块连接的引脚
timeout = 0.5; % 延长等待信号的超时时间
sampleInterval = 20e-6; % 更精细的采样间隔(20微秒)
minPulseDuration = 1e-4; % 最小脉冲持续时间(100微秒)
% 创建图形窗口
% figure;
% subplot(2,1,1);
% hWave = stairs(0,0);
% title('红外信号波形');
% xlabel('时间(ms)');
% ylabel('电平');
% ylim([-0.1 1.1]);
% grid on;
%
% subplot(2,1,2);
% hBits = stem(zeros(1,32));
% title('解码位值');
% ylim([-0.1 1.1]);
% xlim([0 33]);
% grid on;
% 主循环
while true
fprintf('\n等待红外信号...\n');
% 增强的引导脉冲检测
[pulseTimes, pulseValues, success] = waitAndCapture(a, irPin, timeout, sampleInterval);
if ~success
continue;
end
% 绘制信号波形
% plotIRSignal(hWave, pulseTimes, pulseValues);
% 增强的解码函数
[address, command, isRepeat, bits] = decodeNEC_enhanced(pulseTimes, pulseValues)
% 显示位值
% set(hBits, 'YData', bits);
% 显示解码结果
if ~isempty(address)
if isRepeat
fprintf('重复键: 地址=0x%02X, 命令=0x%02X\n', address, command);
else
fprintf('新按键: 地址=0x%02X (反码:0x%02X), 命令=0x%02X (反码:0x%02X)\n',...
address, bitcmp(address,8), command, bitcmp(command,8));
end
else
fprintf('解码失败 - 可能原因:\n');
fprintf('1. 遥控器不是NEC协议\n');
fprintf('2. 距离太远或角度不对\n');
fprintf('3. 环境光干扰太强\n');
% 显示信号统计信息辅助调试
fprintf('信号统计: 持续时间=%.2fms, 脉冲数=%d\n',...
(pulseTimes(end)-pulseTimes(1))*1000, length(pulseTimes));
end
drawnow;
end
% 释放Arduino对象
clear
%% 增强的信号捕获函数
function [times, values, success] = waitAndCapture(a, pin, timeout, interval)
times = [];
values = [];
success = false;
% 等待空闲状态(持续高电平)
fprintf('等待空闲状态...\n');
idleStart = tic;
while toc(idleStart) < timeout
if readDigitalPin(a, pin) == 1
break;
end
pause(interval*5);
end
% 等待引导脉冲开始(低电平)
fprintf('等待引导脉冲...\n');
startTime = tic;
while toc(startTime) < timeout
if readDigitalPin(a, pin) == 0
break;
end
pause(interval);
end
% 记录引导脉冲持续时间
pulseStart = tic;
while readDigitalPin(a, pin) == 0
if toc(pulseStart) > 0.015 % NEC引导脉冲最长9ms
fprintf('无效引导脉冲\n');
return;
end
end
leadLow = toc(pulseStart);
% 检查引导脉冲是否符合NEC标准(4.5ms或2.25ms)
if leadLow < 0.008 || leadLow > 0.010
fprintf('非标准引导脉冲: %.2fms\n', leadLow*1000);
return;
end
% 开始捕获完整信号
fprintf('捕获信号中...\n');
maxDuration = 0.1; % 最大捕获时长100ms
bufferSize = ceil(maxDuration / interval);
times = zeros(bufferSize, 1);
values = zeros(bufferSize, 1);
times(1) = 0;
values(1) = 0; % 引导脉冲低电平开始
captureStart = tic;
lastTime = 0;
lastValue = 0;
idx = 2;
while toc(captureStart) < maxDuration && idx <= bufferSize
currentValue = readDigitalPin(a, pin);
currentTime = toc(captureStart);
if currentValue ~= lastValue
times(idx) = currentTime;
values(idx) = currentValue;
lastValue = currentValue;
idx = idx + 1;
end
pause(interval);
end
% 裁剪数组
times = times(1:idx-1);
values = values(1:idx-1);
% 检查捕获的信号是否有效
if length(times) < 10
fprintf('捕获信号太短\n');
return;
end
success = true;
end
%% 增强的NEC解码函数
function [address, command, isRepeat, bits] = decodeNEC_enhanced(times, values)
address = [];
command = [];
isRepeat = false;
bits = zeros(1,32);
% 计算各脉冲持续时间
durations = diff(times);
% 检查是否为重复码
if length(durations) < 10
totalTime = times(end) - times(1);
if totalTime > 0.009 && totalTime < 0.015 % 重复码特征
isRepeat = true;
return;
else
fprintf('无效信号长度\n');
return;
end
end
% 查找数据位开始位置(跳过引导脉冲)
dataStart = 3; % 通常第3个脉冲开始数据
% 提取32位数据
bitCount = 0;
for i = dataStart:2:min(dataStart+63, length(durations)-1)
zeroBit = durations(i) < 0.0012; % 560us低+560us高=0
oneBit = durations(i) < 0.0012 && durations(i+1) > 0.0012; % 560us低+1690us高=1
if oneBit
if bitCount < 32
bits(bitCount+1) = 1;
end
bitCount = bitCount + 1;
elseif zeroBit
if bitCount < 32
bits(bitCount+1) = 0;
end
bitCount = bitCount + 1;
else
fprintf('无效脉冲宽度: %.2fms\n', durations(i)*1000);
end
end
% 检查是否获取了完整32位数据
if bitCount < 32
fprintf('数据不完整: 只收到%d位\n', bitCount);
return;
end
% 解码地址和命令
address = bin2dec(num2str(bits(1:8)));
invAddress = bin2dec(num2str(bits(9:16)));
command = bin2dec(num2str(bits(17:24)));
invCommand = bin2dec(num2str(bits(25:32)));
% 验证反码
if (bitcmp(address,8) ~= invAddress) || (bitcmp(command,8) ~= invCommand)
fprintf('反码验证失败\n');
address = [];
command = [];
return;
end
end
%% 信号绘图函数
function plotIRSignal(h, times, values)
timesMs = times * 1000;
% 创建阶梯图数据
x = zeros(2*length(timesMs),1);
y = zeros(2*length(timesMs),1);
for i = 1:length(timesMs)
x(2*i-1) = timesMs(i);
x(2*i) = timesMs(i);
y(2*i-1) = values(i);
y(2*i) = values(i);
end
set(h, 'XData', x, 'YData', y);
xlim([0 max(timesMs)]);
title(sprintf('红外信号波形 (持续时间: %.2fms)', max(timesMs)));
end