关于AVR接收红外遥控编码的若干问题
本人是阿莫电子论坛新人,做红外遥控时碰到了几个问题。遥控遵守NEC的协议。引导码是9000us(L)+4500us(H),数据位:560us(L)+560us(H)='0',560us(L)+1680us(H)='1'。引导码+8bit机器源码+8bit机器源码反码+8bit用户源码+8bit用户源码反码。用了三种方法:1)普通IO口;2)外部INT0中断;3)PD6捕捉
第一种和第二种无法得到正确的码。但移植到S52硬件上却可以得到正确的码。第三种可以得到正确的码,但有个问题,就是用户源码得到的竟然是超过255的,接收以上波码的变量可都是声明为unsigned char cod的。这让我很奇怪,后来只能cod&0xff得到正确的码。
不知大家用第三种方法的时候有没有碰到数据溢出,第一种和第二种方法有没有得到正确的码。 这个是捕捉方法
/*
//-------------------------------------------------------------------
//捕捉方式的红外遥控可以正检测到键值和及其码
//在2013-11-08AM01:00实验通过
//编译器:WinAvr2010
//遥控器为NEC协议
//-------------------------------------------------------------------
ISR(TIMER1_CAPT_vect)
{
static uint oldCapt;//旧捕捉时间
uint newCapt; //新捕捉时间
static uchar bitcnt;//接收的数据位数总长度
static uchar kk;
uint temp=0;//用来存贮newCapt和oldCapt的时间差
uchar x;
newCapt=ICR1;
temp=newCapt-oldCapt;
oldCapt=newCapt;
//数据位'0'的判断,低电平(565us)+高电平(560us) =1125us表示0
if(temp>1025&&temp<1225)
x=0;
//数据位'1'的判断,低电平(565us)+高电平(1685us)=2250us表示1
else if(temp>2150&&temp<2350)
x=0x80;
//起始信号判断,低电平(9000us)+高电平(4500us)=13500us表示headcode
else if(temp>13400&&temp<13600)
{
bitcnt=TCNT1=oldCapt=newCapt=0;
kk=kk=kk=kk=0x00;
return;//返回等待下次继续接收
}
//高低电平总和都不在以上的值则为干扰信号
else return;
if(bitcnt<8)
{
kk>>=1;
kk |=x;
}
if(7<bitcnt&&bitcnt<16)
{
kk>>=1;
kk |=x;
}
if(15<bitcnt&&bitcnt<24)
{
kk>>=1;
kk |=x;
}
if(23<bitcnt&&bitcnt<32)
{
kk>>=1;
kk |=x;
}
bitcnt++;
if((kk==((~kk)&0XFF))&&(kk==((~kk)&0XFF)))//校验,必须有&0xff,否则会有数据溢出,比如开关机的码值是0x00-0xff-0x45-0xba,若无则会变成0x00-0xff-0x2ba-0xba
{
IRKEY=kk;
IRKEY=kk;
IRKEY=kk;
IRKEY=kk;
}
}
*/
中断法
//--------------------------------------------------------------------
//下降沿中断
//--------------------------------------------------------------------
ISR(INT0_vect)
{
uchar i,j,dat,temp;
uint n=2;
//Lcd1602ShowString(0,0,"fuck");
cli();
_delay_ms(6);
if(IR_RD())
{
sei();
return;
}//确定无干扰,有干扰跳出
n=2;
while(!IR_RD()) _delay_us(1);//跳过前导9ms低电平
if(n==1)//电平持续时间过长,出错跳出
{
sei();
return;
}
n=2;
while(IR_RD()&&n++) _delay_us(1);//跳过前导4.5ms高电平
if(n==1)//电平持续时间过长,出错跳出
{
sei();
return;
}
for(i=0;i<4;i++)
//搜集4组数据,每组8位
{
dat=0;
for(j=0;j<8;j++)
{
n=2;
while(!IR_RD()&&n++) _delay_us(1);//以为数据开始前的低电平
if(n==1)//电平持续时间过长,出错跳出
{
sei();
return;
}
_delay_us(2000);
temp=0;
if(IR_RD())//若700us后端口仍然是高电平,说明读到的数据是'1'
temp=0x80;
n=2;
//while(IR_RD()&&n++) _delay_loop_1(1);//等待高电平变为低电平
if(n==1)//电平持续时间过长,出错跳出
{
sei();
return;
}
dat>>=1;
dat|=temp;
}//end for j/
key=dat;
}//end for i
sei();
}
中断法和普通IO差不多。就不贴出来了。 菜鸟飞过学习~~~~为什么没高手来评论一下呢? 本帖最后由 rjx 于 2017-7-17 08:20 编辑
用普通IO口做轮询方式和中断方式都可以得到正确的码值,只要程序是对的。但很多人都失败了,这是为什么呢?
我也曾经碰到过这些问题,后经多次试验摸索,发现主要原因是其中的延时函数的延时时间不正确所致。大多程序我们都是从书本上或网上抄来的,原来的程序是在特定的晶振频率下实现的,如原来的程序是在8M晶振下的延时时间,如果我们移植后是在4M晶振下运行,那么延时时间肯定是不对的,因为红外接收函数就是靠延时时间来判断码值的,延时时间不对,当然就无法得到正确的码值。
还有,即使和原来的晶振用的一样有时也还是不行,因为这些延时函数都是大概的时间,并不严格。我的办法是将延时程序用AVR Studio仿真软件单独测试,设定延时软件的延时时间分别为10MS,100ms,200MS进行测试,看看误差多大,再重新调整延时软件的参数,直到正确为止。如要要延时10MS,说不定参数要设成13MS才行!所以你把遥控程序里的几个用到的延时时间都仔细测试,弄到准确的延时时间,一般问题都能解决。
页:
[1]