各红外线通信协议解码(通用型)【NEC、Sony SIRC、RC-5、RC-6、Samsung】

2024-01-09 22:37:53


红外线通信协议解码 是指将接收到的红外线信号转换为可理解的数字数据,以便对其进行进一步处理和操作的过程。红外线通信协议解码通常用于遥控器接收器等设备中。

在红外线通信中,遥控器发送器使用特定的红外线协议来编码命令和数据,并通过红外线发射器将这些信息转换为红外线信号。接收器捕获这些红外线信号,并通过解码过程将其还原为原始的命令和数据。

一、通信协议

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。在使用三星红外发射协议进行通讯时,发送方需要按照协议规定的载波时间序列来发送数据,接收方则需要根据协议规定的载波时间序列来解码数据。

二、数据抓取分析

这里我抓取一种自定义红外传输协议数据,具体操作如下:

    1. 将红外发射器上电,持续发送数据
    1. 准备红外接收器,将示波器通道接上输出口,对准发射器,随机抓取一针数据分析

如下:
在这里插入图片描述
选取某一帧数据具体分析:
在这里插入图片描述
我直接将我的分析结果写出来,大家可自行分析哈:

  • 引导位: 2.8ms的低电平突变
    在这里插入图片描述
  • 数据位: 八位数据。其中位定义 我以0.56ms高电平+0.56ms低电平为数据00.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;
}

在这里插入图片描述
在这里插入图片描述

文章来源:https://blog.csdn.net/Dustinthewine/article/details/135488685
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。