基于定时器捕获功能的红外解码程序(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单片机的定时器捕获功能实现红外解码

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

  • 6
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是51单片机红外遥控发射NEC协议的程序代码: ``` #include<reg51.h> #define uint unsigned int #define uchar unsigned char uchar code table[33] = {0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff}; uchar count, i, j; void delay(uint x) { uint i,j; for(i=x;i>0;i--) for(j=110;j>0;j--); } void sendone(void) { P1 = 0; delay(1); P1 = 1; delay(2); P1 = 0; delay(1); } void sendzero(void) { P1 = 0; delay(1); P1 = 1; delay(1); P1 = 0; delay(2); } void send(uchar data) { uchar i; for(i=0;i<8;i++) { if(data&0x01) sendone(); else sendzero(); data >>= 1; } } void main() { TMOD = 0x01; TH0 = 0xFC; TL0 = 0x67; TR0 = 1; ET0 = 1; EA = 1; while(1) { send(0x00); send(0x00); send(0x00); send(0x00); send(0x00); send(0x00); send(0xff); send(0x00); send(0xff); send(0x00); send(0xff); send(0x00); send(0xff); send(0x00); send(0xff); send(0x00); send(0xff); send(0x00); send(0xff); send(0x00); send(0xff); send(0x00); send(0xff); send(0x00); send(0xff); send(0x00); send(0xff); send(0x00); send(0xff); send(0x00); send(0xff); send(0x00); send(0xff); send(0x00); delay(100); } } void timer0() interrupt 1 { TH0 = 0xFC; TL0 = 0x67; count++; if(count == 15) { P1 = 1; delay(1); P1 = 0; count = 0; } } ``` 该程序使用了51单片机定时器和外部中断,通过红外发射管发送NEC协议格式的红外码。在main函数中循环发送了一组红外码,通过定时器中断控制红外码的发送频率。其中sendone和sendzero函数分别表示发送1和0的红外码,send函数用于发送8位数据。注意在使用该程序时需要根据具体硬件电路设计进行相应的修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值