返回首页
当前位置: 主页 > AVR单片机 >

利用AVR(MEGA8)的输入捕获(ICP)对万能红外线遥控器

时间:2009-11-10 19:30来源:网络 作者:网友 点击:
利用AVR(MEGA8)的输入捕获(ICP)对万能红外线遥控器进行解码

万能遥控器在使用前一般要进行设置,针对RM-2008这款万能遥控,设置方法如下:

先按住“设置”键不放,再按下“电源”(“开/关”)键,工作指示灯亮起,然后释放两键,在此时进入代码输入状态,依次键入 0 0 0 指示灯熄灭,设置成功!

说明一下:0 0 0 编码是日立公司初期的红外编码方式,也就是网上到处都通用的红外编码方式(如下图),另外本程序只能对此编码进行解码

 

   数据头的时间:Th=9+4.5=13.5ms

    数据“0”的时间:T0=0.565+0.56=1.125ms

    数据“1”的时间:T1=1.685+0.56=2.245ms

本程序通过使用输入捕获功能(ICP)捕捉红外信号的高电平脉宽,达到解码的目的;如果捕获到的脉宽是4.5ms 则表示此信号为同步码,如果捕获到的脉宽是1.685ms 的话则表示 “1” 否则表示“0”

测试电路如下:

使用DNW 串口调试软件时的效果

 

 

 

 

/////////////////////////////////只有一个文件main.c///////////////////////////////////

#include <avr/io.h>
#include <avr/signal.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>
#include <util/delay.h>
#include <stdio.h>


/*----------------------遥控操作值--------------------*/

//        key        code (hex)
#define Key_1       0x01
#define Key_2       0x02
#define Key_3       0x03
#define Key_4       0x04
#define Key_5       0x05
#define Key_6       0x06
#define Key_7       0x07
#define Key_8       0x08
#define Key_9       0x09
#define Key_0       0x00
#define Menu      0x5c       // 菜单
#define Menu_up   0x56       // 菜单上
#define Menu_down   0x57       // 菜单下
#define Menu_left   0x5f       // 菜单左
#define Menu_right 0x5b       // 菜单右
#define Menu_ok     0x16       // 菜单确认
#define Channel_up 0x1b       // 频道+
#define Channel_down 0x1f       // 频道-
#define Sound_up      0x1e       // 音量+
#define Sound_down   0x1a       // 音量-
#define Open_Close 0x12       // 开/关
#define Mute        0x10       // 静音
#define Pic_in_pic 0x51          //画中画
#define Standard    0x58       // 制式
#define Return      0x52       // 返回
#define Times       0x0b       // 倍数
#define Screen      0x16       // 屏幕
#define Audio       0x1d       // 伴音
#define NICAM       0x13       // 丽音
#define TV_Vedio    0x0f     // 电视/视频
#define Sleep       0x0e    //睡眠

/*----------------------常用参数定义-------------------*/

#define P0 0
#define P1 1
#define P2 2
#define P3 3
#define P4 4
#define P5 5
#define P6 6
#define P7 7

#define FREQ 8 //定义单片机工作频率为 8M
#define uint unsigned int
#define uchar unsigned char

#define Start_T1 TCCR1B|=_BV(CS11);TCNT1=0//复位预计分频器并开启定时器T1
#define Stop_T1 TCCR1B&=~_BV(CS11) //关闭定时器T1

/*-----------------IR信号指示灯操作函数---------*/

#define EN_IR_LED DDRB|=_BV(P1)
#define CLR_IR_LED PORTB&=~_BV(P1)
#define SET_IR_LED PORTB|=_BV(P1)

/*----------------------某些端口操作-------------------*/

volatile unsigned char i,j,k;

volatile unsigned long IRcode;                //定义一个长度为4字节的无符号long类型变量来存储代码

volatile unsigned char *IRcodePointer ;     //定义一个无符号的单字节指针变量,
              //用此地址变量来分别读取IRCode的
              //4个字节 其中操作码为 IRcodePointer[2]
              //用户码为 IRcodePointer[0]

volatile unsigned char IRReceiveEffective=0;     //IR信号接收有效 当程序响应接收以后请马上清零 这样才会继续接收下一IR码

volatile unsigned char IRReceiveCurrentBit=0; //IR信号当前接收位 0时表示第0位即同步码(4.5ms高电平)

volatile unsigned int Pulse_length=0;          //捕获的脉冲宽度

volatile unsigned char ICP_Parity=0;           //捕获中断奇偶次计数 1时为偶次 并在此时判断脉宽

volatile unsigned char Received_Key_Temp;      //红外接收操作键缓存

const unsigned char String[]={"You Have Press Key : "};


/*----------------------串口定义-------------------*/

unsigned char SetPrintfConvertMode=0; //使用printf作其他转换,并非输出到UART

void Uart_Init(void);

int System_putchar(char c, FILE *stream);
int System_getchar(FILE *stream);

FILE mystd = FDEV_SETUP_STREAM(System_putchar, System_getchar,_FDEV_SETUP_RW);

/*----------------------常用函数定义------------------*/

void delay_nms(unsigned int ms)                //N ms延时函数
{
for(i=0;i<ms;i++)
   _delay_loop_2(FREQ*250);
}


/*----------------------系统初始化函数定义------------------*/

void IO_INIT(void)
{
PORTB|=_BV(P0); //设置ICP引脚内部上拉 经过试验验证,上拉会提高红外接收灵敏度
}


ISR(TIMER1_COMPA_vect)   
{
IRReceiveCurrentBit=0;//重置IR接收位为第0位,为下次接收做准备
TIMSK&=~_BV(OCIE1A); //关闭溢出中断
TCCR1B|=_BV(ICES1); //设置输入捕获 上升沿有效
ICP_Parity=0;     

Stop_T1;   
CLR_IR_LED;
}

ISR(TIMER1_CAPT_vect)
{
if(!IRReceiveEffective)
{
   if(ICP_Parity==0)
    {
     ICP_Parity++;
     TIMSK|=_BV(OCIE1A);
     TCCR1B&=~_BV(ICES1); //设置输入捕获 下降沿有效
     Start_T1 ;  
    }
   else
    {
    

Stop_T1;

ICP_Parity=0;
     TCCR1B|=_BV(ICES1);//设置输入捕获 上升沿有效
     Pulse_length=ICR1;
     if(IRReceiveCurrentBit==0)
      {
       if(Pulse_length>=3500&&Pulse_length<5500)// 如果是引导码 (4.5ms) 进入下一个bit的读取
        IRReceiveCurrentBit++;
      }
     else if(IRReceiveCurrentBit<33) //接收32位数据
      {
       IRcode>>=1;
       if(Pulse_length<1900&&Pulse_length>1400) //判断是否为 1 ( 1.685 ms)
        IRcode|=0x80000000;
       IRReceiveCurrentBit++;
       if(IRReceiveCurrentBit==33)
        {
         IRReceiveCurrentBit=0; //重置IR接收位为第0位,为下次接收做准备
         if(IRcodePointer[0]==(unsigned char)(~IRcodePointer[1])&&IRcodePointer[2]==(unsigned char)(~IRcodePointer[3]))
          {
           SET_IR_LED;    //开启IR信号指示灯
           IRReceiveEffective=1; //数据有效
          }
         delay_nms(5); //因为32位数据后面还有一个信号上跳变,所以要适当延时,延时0.65ms以上即可
        }
      }
    }
}
}

/////////////////////////////////////////////////////////////////


int main(void)
{

wdt_disable();

IO_INIT();

Uart_Init();


TCCR1B=_BV(WGM12)|_BV(CS11);//采用8分频 这样的话 TCNT1的计数时基为 1us
OCR1A=8000; //TCNT1 计数上限 设置IR接收超时 这里设置 8ms

TIMSK|=_BV(TICIE1);//开启输入捕获中断

TCCR1B|=_BV(ICES1);//输入捕获 上升沿有效

EN_IR_LED; //IR信号指示灯允许
CLR_IR_LED; //关闭IR信号指示灯

IRcodePointer=&IRcode;

sei();

while(1)
{
   if(IRReceiveEffective)
    {
     Received_Key_Temp=IRcodePointer[2];//把接收到的操作键放入缓存
     IRReceiveEffective=0; //允许下一次接收
     switch(Received_Key_Temp)
      {
       case Key_1      : printf("\n%sKey_1",String);break;
       case Key_2      : printf("\n%sKey_2",String);break;
       case Key_3      : printf("\n%sKey_3",String);break;
       case Key_4      : printf("\n%sKey_4",String);break;
       case Key_5      : printf("\n%sKey_5",String);break;
       case Key_6      : printf("\n%sKey_6",String);break;
       case Key_7      : printf("\n%sKey_7",String);break;
       case Key_8      : printf("\n%sKey_8",String);break;
       case Key_9      : printf("\n%sKey_9",String);break;
       case Key_0      : printf("\n%sKey_0",String);break;
       case Menu       : printf("\n%sMenu",String);break;
       case Menu_up    : printf("\n%sMenu_up",String);break;
       case Menu_down : printf("\n%sMenu_down",String);break;
       case Menu_left : printf("\n%sMenu_left",String);break;
       case Menu_right : printf("\n%sMenu_right",String);break;
       case Menu_ok    : printf("\n%sMenu_ok",String);break;
       case Channel_up : printf("\n%sChannel+",String);break;
       case Channel_down   : printf("\n%sChannel-",String);break;
       case Sound_up     : printf("\n%sSound+",String);break;
       case Sound_down   : printf("\n%sSound-",String);break;
       case Open_Close : printf("\n%sOpen_Close",String);break;
       case Mute       : printf("\n%sMute",String);break;
       case Standard   : printf("\n%sStandard",String);break;
       case Return     : printf("\n%sReturn",String);break;
       case Times      : printf("\n%sTimes",String);break;
       //case Screen     : printf("\n%sScreen",String);break;//Screen 与 menu_ok 值相同
       case Audio      : printf("\n%sAudio",String);break;
       case NICAM      : printf("\n%sNICAM" ,String);break;
       case TV_Vedio   : printf("\n%sTV_Vedio",String);break;
       case Sleep      : printf("\n%sSleep",String);break;
       case Pic_in_pic : printf("\n%sPic_in_pic",String);break;
       default:printf("\n%sOther Key 0x%x",String,Received_Key_Temp);break;
      }
    CLR_IR_LED;     //处理完数据以后关闭IR信号指示灯
    }
  
}
}


/*----------------------串口函数实体------------------*/

void Uart_Init(void)
{
UCSRB=_BV(RXEN)|_BV(TXEN);
UBRRL=25;   //8M 19200
stdout=&mystd;
stdin=&mystd;
}

int System_putchar(char c, FILE *stream)
{
if(SetPrintfConvertMode==1)
{
    
}
else
{
   if (c == '\n')
   System_putchar('\r', stream);
   loop_until_bit_is_set(UCSRA, UDRE);
   UDR = c;
}
return 0;
}


int System_getchar( FILE *stream)
{
loop_until_bit_is_set(UCSRA,RXC);
return UDR;
}

/////////////////////////////////程序结束////////////////////////////

(责任编辑:admin)
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名:密码: 验证码:点击我更换图片
推荐内容