各红外线通信协议解码(通用型)【NEC、Sony SIRC、RC-5、RC-6、Samsung】
红外线通信协议解码 是指将接收到的红外线信号转换为可理解的数字数据,以便对其进行进一步处理和操作的过程。红外线通信协议解码通常用于遥控器接收器等设备中。
在红外线通信中,遥控器发送器使用特定的红外线协议来编码命令和数据,并通过红外线发射器将这些信息转换为红外线信号。接收器捕获这些红外线信号,并通过解码过程将其还原为原始的命令和数据。
一、通信协议
1. NEC
NEC红外协议是一种最常见的红外遥控协议,通常用于电视遥控器、空调遥控器等。NEC协议通过调制红外载频信号来表示数字信号。每个数字信号由9ms的起始位和4.5ms的起始位隔开,然后由16位地址码、16位数据码和8位反码构成。地址码用于区分不同的遥控器设备,数据码表示遥控器键值。接收设备在解码后,通过判断地址码和数据码来判断是哪个键被按下。
传输的数据帧格式为引导码 + 8位用户码 + 8位用户反码 + 8位数据码 + 8位数据反码
如下所示:
位定义:
在引导码之后,通过各位值去计算用户码与数据码,当检测到0.56ms的低电平+0.56ms的高电平
时记为该位为0,当检测到0.56ms的低电平+1.68ms的高电平
时记为该位为1。
由上可知:
- 引导码: 红外接收口(空闲时低电平)接收到上升沿的跳变,即9ms的上升沿随即4.5ms的低电平;
- 32位数据: 每八位组成一个字节用于记录用户码与数据码
2. Sony SIRC
Sony SIRC使用双向编码(又称曼彻斯特编码),使用40K载波对编码后的波形进行调制,位时间长度 1.2ms 或 0.6ms,有12 位,15 位和 20 位三个版本,这里介绍12位。
位定义: 1.2ms 的 40K 载波脉冲重现逻辑“1”,0.6ms 重现逻辑“0”。脉冲间隔均位 0.6ms。
数据帧格式:
(1) 帧定时基于600μS脉冲宽度T的倍数。
(2)帧以4T开始标记脉冲开始。
(3)帧中的每个位由1T空格表示,如果该位是“0”,则后跟1T标记;如果该位是“1”,则后跟2T标记
(4)若遥控器按键一直按下,命令码会每 45ms 重复发送一次。
3. RC-5、RC-6、Samsung
RC-5红外协议也是一种常见的红外遥控协议,常用于DVD遥控器、音响遥控器等家电设备中。RC-5协议将每个红外信号分为两个连续的半周期。每个半周期由1.778ms的载频信号和1.778ms的无载频信号组成。一个完整的信号由13位二进制数据构成,其中1位为起始位,5位为地址码,6位为命令码,1位为反码。接收设备通过解码操作,根据地址码和命令码执行相应的功能。
RC-6红外协议是RC-5的升级版,具有更高的功能扩展性和更低的误码率。RC-6协议将红外信号延长到2.667ms的载频信号和2.667ms的无载频信号。一个完整的信号由20位二进制数据构成,其中1位为起始位,2位为系统码,5位为地址码,8位为命令码,1位为反码,3位为扩展码。接收设备在解码后,根据地址码和命令码进行区分和执行命令。
Samsung红外发射协议是一种红外通讯协议,常用于家电控制等领域。该协议使用38kHz的载波信号进行通讯,并采用了脉冲宽度编码(PulseWidth Modulation,PWM)技术。具体来说,每个数据位通过一系列的载波事件来表示,其中高电平载波事件表示0,低电平载波事件表示1。每个数据位的载波事件数量和载波事件持续时间的长短均不相同,这种编码方式可以有效地减少数据传输时的冗余信息,提高传输效率。在三星红外发射协议中,载波时间是指将38kHz载波信号分成若干个时间片段,每个时间片段的持续时间称为载波时间。具体来说,每个数据位由一组高低电平的载波事件组成,其中高电平载波事件表示0,低电平载波事件表示1。每个数据位的载波事件数量和载波事件持续时间的长短均不相同,但是每个时间片段的持续时间是固定的,通常为1.125ms或2.25ms。在使用三星红外发射协议进行通讯时,发送方需要按照协议规定的载波时间序列来发送数据,接收方则需要根据协议规定的载波时间序列来解码数据。
二、数据抓取分析
这里我抓取一种自定义红外传输协议数据,具体操作如下:
-
- 将红外发射器上电,持续发送数据
-
- 准备红外接收器,将示波器通道接上输出口,对准发射器,随机抓取一针数据分析
如下:
选取某一帧数据具体分析:
我直接将我的分析结果写出来,大家可自行分析哈:
- 引导位: 2.8ms的低电平突变
- 数据位: 八位数据。其中位定义 我以
0.56ms高电平+0.56ms低电平为数据0
,0.56ms高电平+1.68ms低电平为数据1
- 结束位:
2.8ms高电平+2.8ms低电平
三、程序设计实现
这里我用外部中断去检测信号突变,定时器去计算电平持续时间。
具体如下:
1. 外部中断初始化
#define IR_PIN GET_PIN(E, 3)
rt_pin_mode(IR_PIN, PIN_MODE_INPUT_PULLUP);
rt_pin_attach_irq(IR_PIN, PIN_IRQ_MODE_FALLING , External_IR, RT_NULL);/* 绑定中断,下降沿模式,回调函数名为External_IR */
rt_pin_irq_enable(IR_PIN, PIN_IRQ_ENABLE);/* 使能中断 */
2. 定时器初始化
#define BSP_USING_TIM
#ifdef BSP_USING_TIM
#define BSP_USING_TIM3
#endif
#define HWTIMER_DEV_NAME "timer3" /* 定时器名称 */
rt_hwtimerval_t timeout_s; /* 定时器超时值 */
rt_device_t hw_dev = RT_NULL; /* 定时器设备句柄 */
rt_hwtimer_mode_t mode; /* 定时器模式 */
rt_uint32_t freq = 1000000; /* 计数频率 */
void Timer_init()
{
/* 查找定时器设备 */
hw_dev = rt_device_find(HWTIMER_DEV_NAME);
if (hw_dev == RT_NULL)
{
rt_kprintf("hwtimer sample run failed! can't find %s device!\n", HWTIMER_DEV_NAME);
}
/* 以读写方式打开设备 */
ret = rt_device_open(hw_dev, RT_DEVICE_OFLAG_RDWR);
if (ret != RT_EOK)
{
rt_kprintf("open %s device failed!\n", HWTIMER_DEV_NAME);
}
/* 设置超时回调函数 */
rt_device_set_rx_indicate(hw_dev, timeout_cb);
/* 设置计数频率(若未设置该项,默认为1Mhz 或 支持的最小计数频率) */
rt_device_control(hw_dev, HWTIMER_CTRL_FREQ_SET, &freq);
/* 设置模式为周期性定时器(若未设置,默认是HWTIMER_MODE_ONESHOT)*/
mode = HWTIMER_MODE_PERIOD;
ret = rt_device_control(hw_dev, HWTIMER_CTRL_MODE_SET, &mode);
if (ret != RT_EOK)
{
rt_kprintf("set mode failed! ret is :%d\n", ret);
}
/* 设置定时器超时值为5s并启动定时器 */
timeout_s.sec = 0; /* 秒 */
timeout_s.usec = 10; /* 微秒 */
if (rt_device_write(hw_dev, 0, &timeout_s, sizeof(timeout_s)) != sizeof(timeout_s))
{
rt_kprintf("set timeout value failed\n");
}
}
/* 定时器超时回调函数 */
rt_err_t timeout_cb(rt_device_t dev, rt_size_t size)
{
n++;
return 0;
}
3. 获取电平持续时间
int get_H_Value(void)
{
n=0;
while(1)
{
if(rt_pin_read(IR_PIN)==RESET) break;
}
return n;
}
int get_L_Value(void)
{
n=0;
while(1)
{
if(rt_pin_read(IR_PIN)==SET) break;
}
return n;
}
4. 解码
void External_IR(void *args)
{
m++;
rt_uint32_t time;
rt_uint8_t j,data=0;
time=get_L_Value();
if(time<265||time>300) return;
for(j=0;j<8;j++)
{
time=get_H_Value(); //得到低电平时间
if(time<40||time>70)return; //标准时间: 560us
time=get_L_Value(); //得到高电平时间
if(time>150&&time<180) //数据1 1680us
{
data>>=1;
data|=0x80;
}
else if(time>40&&time<70) //数据0 560us
{
data>>=1;
}
else return;
InfraredRecvData[0]=data; //存放解码成功的值
}
//解码成功
InfraredRecvState=1;
}
5. main.c
int main(void)
{
oled_func();
rt_pin_mode(IR_PIN, PIN_MODE_INPUT_PULLUP);
rt_pin_attach_irq(IR_PIN, PIN_IRQ_MODE_FALLING , External_IR, RT_NULL);/* 绑定中断,上升沿模式,回调函数名为External_IR */
rt_pin_irq_enable(IR_PIN, PIN_IRQ_ENABLE);/* 使能中断 */
uart2_init();
Timer_init();
rt_device_write(serial, 0,&InfraredRecvData[0],1);
rt_thread_mdelay(200);
while(1)
{
if(InfraredRecvState)
{
InfraredRecvState=0;
rt_device_write(serial, 0,&InfraredRecvData[0],1);
rt_thread_mdelay(100);
}
}
return RT_EOK;
}
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!