基于定时器捕获功能的红外解码程序(NEC协议)


前言

在可视范围内,红外遥控是设备最廉价的遥控实现方式。该技术兼具应用实现原理简单、器件廉价的优势,成为我们日常设备控制的理想方式。目前几乎所有的视频和音频设备都可以通过这种方式遥控。

本文将简单介绍一些日常使用到的消费类电器红外控制协议,着重介绍NEC协议,并基于MSP430单片机的定时器捕获功能实现红外解码


一、红外协议简介

1. ITT Protocol

ITT 红外协议不使用调制信号,直接发送是区别于其他协议的重要特点。
每个信号都是由 14 个 10us 时间间隔的脉冲信号组成来发送,解码则是根据脉冲的间隔进行。
该协议非常实用,并耗能很低,大大提高了电池寿命。

在这里插入图片描述
一个红外信号通过 14 个脉冲发送,每个脉冲都是 10us 长。
通常使用三个不同的时间间隔去区分一个信号:
100us 表示逻辑 0;
200us 表示逻辑 1;
300us 则表示起始条件脉冲(lead-in)和结束条件脉冲(lead-out);

在这里插入图片描述

2. NEC 协议

该协议由 NEC 开发,具有以下特征:
8 位地址码,8 位命令码;
完整发射两次地址码和命令码,以提高可靠性;
脉冲时间长短调制方式;
38KHz 载波频率;
位时间 1.12ms 或 2.25ms;

在这里插入图片描述
NEC 协议根据脉冲时间长短解码。每个脉冲为 560us 长的 38KHz 载波(约 21 个载波周期)。
逻辑”1”脉冲时间为 2.25ms;
逻辑”0”脉冲时间为 1.12ms。
推荐的载波周期为 1/4 或者 1/3,即 38K 载波信号的周期里,只有 1/4 或者 1/3是高电平。

在这里插入图片描述

在这里插入图片描述

注:发送端与接收端的信号电平正好发生翻转;

3. Nokia NRC17 协议

Nokia 协议使用 17 位比特发送红外指令;
8 位命令码,4 位地址码 4 子码;
38K 载波,双向解码;
位传送时间 1ms ;
在这里插入图片描述
该协议采用所谓的不归零法解调 38K 载波,所有位的时间都相等且都为 1ms,每位都有一半的时间(500us)都是 38K 载波,剩下一半时间时空闲的低电平。逻辑 1 位表示为前面的一半时间为 38K 的载波,后面一半时间为低电平,反之逻辑 0 位刚好相反。

注:此外市场上也存在其他的协议,如夏普协议、索尼 SIRC 协议、飞利浦 RC-5 协议等。

二、红外解码程序(NEC协议)

1. 软硬件环境及红外解码状态图

芯片:MSP430FR57xx;
编译环境:Code Composer Studio;
在这里插入图片描述

注:下面程序中新增加了一个用于检验传输地址、数据的状态:IRDA_RECEIVE_CHECKOUT;

2. 基于定时器捕获中断方式的NEC协议红外解码程序

代码如下:

#include <string.h> 
#include "sysclock.h"

#include "gpio.h"
#include "timer.h"
#include "mcu_api.h"
#include "protocol.h"

// 红外解码状态机
//(空闲、下降沿9ms、上升沿4.5ms、接收数据、信号检验、0、1信号判断、重复发送——2.25秒)
#define IRDA_IDLE_STATE                  0
#define IRDA_RECEIVE_9MS_LEADING         1
#define IRDA_RECEIVE_4MS_LEADING         2
#define IRDA_RECEIVE_32BIT_DATA          3
#define IRDA_RECEIVE_CHECKOUT            4 
#define IRDA_1_0_IDENTIFY                5
#define IRDA_REPEAT_CODE                 6

// 红外初始状态(空闲)、存储数据、计数、解码完成标志位
uint8_t irde_state = IRDA_IDLE_STATE;
uint8_t irde_bytes[4] = {
    
    0,0,0,0};
uint8_t irde_bit_counts = 0;
uint8_t irde_ok = 0;

// 复位状态机
void reset_state_machine(void)
{
    
    
    irde_ok = 0;
    irde_bit_counts = 0;
    irde_state = IRDA_IDLE_STATE;
    TA0CCTL0 |= (CM_2 + CCIS_0 + SCS + CAP + CCIE); // 重新设置为下降沿捕获
}

uint16_t intervl_time;

//定时器中断:TIMER0_A0_VECTOR
#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer0_A3_CCR_ISR(void)
{
    
    
    intervl_time = TA0CCR0;                        // 将捕获到的值取出来
    TA0R = 0;                                      // 将计时器再次清零  The TAxR register is the count of Timer_A.
 
    TA0CCTL0 ^= (CM_1 | CM_2);                     //改变捕获模式

    switch(irde_state)
    {
    
    
    case IRDA_IDLE_STATE:                          // 处于空闲状态且进入中断——下降沿,9ms
        irde_state = IRDA_RECEIVE_9MS_LEADING;
        break;

    case IRDA_RECEIVE_9MS_LEADING:                 // 处于9ms状态且进入中断
        if ((intervl_time > 8500) && (intervl_time < 9500))  // 9000
        {
    
    
            irde_state = IRDA_RECEIVE_4MS_LEADING; // 进入4.5ms
        }
        
        else
        {
    
    
            reset_state_machine();                 // 状态机复位
        }
        break;

    case IRDA_RECEIVE_4MS_LEADING:
        if ((intervl_time > 4000) && (intervl_time < 5000))        //4500
        {
    
    
            irde_state = IRDA_RECEIVE_32BIT_DATA;
        }
        
        else if ((intervl_time > 2000) && (intervl_time < 3000))   //2250
        {
    
    
            irde_state = IRDA_REPEAT_CODE;           // 发送重复信号
        }
        
        else
        {
    
    
            reset_state_machine();
        }
        break;

    case IRDA_RECEIVE_32BIT_DATA:                    // 处于接收32bit
        if (irde_bit_counts >= 32)                   // 判断传输是否完成32个字符
        {
    
    
            irde_state = IRDA_RECEIVE_CHECKOUT;      // 传输地址、数据检验
            reset_state_machine();
            irde_ok = 1;
        }
        
        else
        {
    
    
            irde_state = IRDA_1_0_IDENTIFY;
        }
        break;

    case IRDA_RECEIVE_CHECKOUT:                      // 处于传输地址、数据检验
                                                     // 判断传输是否完成  0地址 1地址反 2数据 3数据反   数据传输有误
        if ((irde_bytes[0] == ~irde_bytes[1]) && (irde_bytes[2] == ~irde_bytes[3]))
        {
    
    
            reset_state_machine();
            irde_ok = 1;                             // 数据全部传输完成并检验
        }
        
        else
        {
    
    
            reset_state_machine();
        }
        break;

    case IRDA_1_0_IDENTIFY:

        irde_bytes[irde_bit_counts/8] >>= 1;        // 数据最高位补“0”   4*8 = 32个数

        if ((intervl_time > 1500) && (intervl_time < 1800))
        {
    
    
            irde_bytes[irde_bit_counts/8] |= 0x80;  // 数据最高位补“1”
        }

        irde_bit_counts++;
        irde_state = IRDA_RECEIVE_32BIT_DATA;       // 继续接收32bit
        break;

    case IRDA_REPEAT_CODE:

        reset_state_machine();
        irde_ok = 1;
        break;
    }
}

总结

1)在可视范围内,红外遥控是设备最廉价的遥控实现方式;
2)市场上存在不少红外控制协议,NEC协议使用较多;
3)NEC协议完整发射两次地址码和命令码,可靠性较高
4)基于MSP430单片机的定时器捕获功能实现红外解码

以上便是本文的全部内容,希望本文能对大家理解和运用红外遥控及解码方法有所帮助。
当然,本文内容如有错误或不严谨之处,也恳请大家及时指出,谢谢!

猜你喜欢

转载自blog.csdn.net/m0_64770246/article/details/125016740