万能遥控器在使用前一般要进行设置,针对RM-2008这款万能遥控,设置方法如下:
先按住“设置”键不放,再按下“电源”(“开/关”)键,工作指示灯亮起,然后释放两键,在此时进入代码输入状态,依次键入 0 0 0 指示灯熄灭,设置成功!
说明一下:0 0 0 编码shi日立公司初期de红外编码方式,也就shi网上到处都通用de红外编码方式(如下图),另外本程序只能对此编码进行解码
数据头de时间:Th=9+4.5=13.5ms
数据“0”de时间:T0=0.565+0.56=1.125ms
数据“1”de时间:T1=1.685+0.56=2.245ms
本程序通过使用输入捕获功能(ICP)捕捉红外信号de高电平脉宽,达到解码de目de;如果捕获到de脉宽shi4.5ms 则表示此信号为同步码,如果捕获到de脉宽shi1.685ms de话则表示 “1” 否则表示“0”
测试电路如下:
使用DNW 串口调试软件时de效果
/////////////////////////////////只有一个文件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字节de无符号long类型变量来存储代码
volatile unsigned char *IRcodePointer ; //定义一个无符号de单字节指针变量,
//用此地址变量来分别读取IRCodede
//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; //捕获de脉冲宽度
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)// 如果shi引导码 (4.5ms) 进入下一个bitde读取
IRReceiveCurrentBit++;
}
else if(IRReceiveCurrentBit<33) //接收32位数据
{
IRcode>>=1;
if(Pulse_length<1900&&Pulse_length>1400) //判断shi否为 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分频 这样de话 TCNT1de计数时基为 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];//把接收到de操作键放入缓存
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;
}