红外遥控长按键处理
下面的代码单次按可以,长按键时要判断连发码。搞了几天也搞不出来。诚心求教uchar IR_buf={0x00,0x00,0x00,0x00};//IR_buf、IR_buf为用户码低位、用户码高位接收缓冲区
// IR_buf、IR_buf为键数据码和键数据码反码接收缓冲区
/********us延时程序,延时时间0.14ms(140us*)*******/
void Delayus(uint x)
{
char i, j;
for(i=0;i<x;i++)
{for(j=0;j<210;j++);}
}
interrupt void ext_int0_isr(void)
{
uchar i,j,sum=0;
GICR |=(0<<INT0);
Delayus(20); //延时20*0.14MS,2.8MS
for(i = 0;i < 14;i++)
{
Delayus(1);
if(IRIN) //9MS内有高电平,则判断为干扰,退出处理程序
{
GICR |=(1<<INT0);
return; //返回
}
}
while(!(IRIN)); //等待9ms低电平过去
for(i=0;i<4;i++)
{
for(j=0;j<8;j++)
{
while(IRIN); //等待4.5ms高电平过去
while(!(IRIN)); //等待变高电平
while(IRIN) //计算高电平时间
{
Delayus(1); //延时0.14ms
sum++; //对0.14ms延时时间进行计数
if(sum >= 30) //高电平时间过长,则退出处理程序
{
GICR |=(1<<INT0);
return;
}
}
IR_buf = IR_buf >> 1; //接受一位数据
if(sum >= 6)
{IR_buf = IR_buf | 0x80;} //若计数值大于6(高电平时间大于0.56),则为数据1
sum = 0; //若计数小于6,数据最高位补"0",说明收到的是"0",同时计时清零
}
}
if(IR_buf!=~IR_buf) //将键数据反码取反后与键数据码码比较,若不等,表示接收数据错误,放弃
{ GICR |=(1<<INT0); return;}
HW_Status=1;
}
void RR() //遥控器键控
{
if(HW_Status==1)
{ static uchar m;
if((IR_buf==0xfb)||(IR_buf==e)) //音量加
{
if( VOLUME_1<98)
{++ VOLUME_1;}
else if( VOLUME_1>=98)
{ VOLUME_1=98;}
}
if((IR_buf==0xfa)||(IR_buf==b)) //音量减
{
if( VOLUME_1>0)
{-- VOLUME_1;}
}
} 按键这边你要能区分出长按键和非长按键。
什么意思?不是很明白你说的什么,能再解释一下这个现象吗
比如按下某个键发送某个码率,如果你一直按着不松手,这个时候这边就计时器计时,当大于多少时候认定为长按键,这个时候发送一个长按键确认字符。
接收端的处理是:接收到一个长按键确认符,就结合之前接收到的那个字判断具体功能。
红外长按有重复发射的,有发射重复码的。
我也试过加入连发码的判断,但不成功,楼上能详细指导一下吗?
可以参考下我写的,任意IO解码,占用一个定时器。移植过STC,AVR,STM8,N76E003,HC89S003等,非常方便简单。
贴一下关键代码,楼主可参考:
#if USE_IR_DECODE
uchar volatileIrprot_LastState = 0; // 记录IR端口状态
uchar volatilecodeCnt = 0; // 数据码位计数
uchar volatileirTime = 0; // 码时间,用于时间计时
uchar volatileIR_data; // 接收数据缓存
uchar volatileIR_REPEAT_DELAY = 0;
#define IR_H P0_1 = 1
#define IR_L P0_1 = 0
#define IR_IO_InitSET_P01(GPIO_IN_PH_NO_SMT);
#define GET_IR_IO (P0_1)
#define IR_DELAY 3// 重复码延迟个数
#endif
// 初始化定时器T3。488us中断一次
void IR_decode_init(void)
{
#if USE_IR_DECODE
IR_IO_Init; // 初始IR接收IO
#endif
TH3 = (65536-IR_intrpt_Num)/256;
TL3 = (65536-IR_intrpt_Num)%256;
T3CON = BIT2; // Start T3 count
ET3 = 1; // enable Timer3 interrupt
}
void Timer3_ISR (void) interrupt T3_VECTOR
{
#if USE_IR_DECODE
//=================================================================================
if(irTime<250) irTime++; // ir解码后码值存放时间约97.6ms, 200*488us
else { codeCnt = 0xff; IR_REPEAT_DELAY = 0; }
if(GET_IR_IO) Irprot_LastState = 1; // 记录IO状态
else if(Irprot_LastState) // 有下降沿
{
Irprot_LastState = 0; // 记录IO状态
if(irTime<6) // 小于6*488us=2.684ms的间隔才进行处理
{ codeCnt++;codeCnt &= 0x1f;
#if IR_DECODE_MSB_MODE
IR_data <<= 1;
if( irTime&BIT2 ) {IR_data++; } // 大于3*488us=1.464ms的间隔为数据1
#else
IR_data >>= 1;
if( irTime&BIT2 ) {IR_data|=0x80;}
#endif
}
else if( (irTime<28)&&(codeCnt==0x3f)) // 重复码间隔时间28*488=13.664 > 11.25ms
{
if( IR_REPEAT_DELAY>IR_DELAY ) { codeCnt = 0x7f;}
else IR_REPEAT_DELAY++;
}
irTime = 0; // 下降沿处理完成,将时间清0
}
#endif
}
void main(void)
{
System_init(); // 系统初始化
UART1_init();
IR_decode_init();
while(1)
{
if(IR_Receive_OK)
{ IR_RST;
UART_Put_HEX(IR_data);
}
if(IR_Det_Repeat) // 检测到重复按键,重复按键值存于变量IR_data【2】
{
UART_Put_Str("IR repeat\r\n");
IR_RST;
}
}
} 补上几个宏:
#define IR_Receive_OK(codeCnt==0x1F) // IR解码完成一个数据
#define IR_Det_Repeat(codeCnt==0x7f) // IR接收到重复码
#define IR_FREE (codeCnt==0xff) // IR空闲,没有接收到任何数据
#define IR_RST codeCnt =0x3f
我是用定时器和外中断实现接收解码的。
重复码是9MS的低电平,2.25MS的高电平。
而引导码是9MS的低电平,4.5MS的高电平。
所以我是在引导码那里做判定的。 楼主是使用哪一款接收模块?
可以试下SMT - 信号测量定时器这个外设来对接收数据进行解码。
这款外设可以测量脉冲宽度,周期,占空比等信息。可以在CPU休眠状态下工作,有利于系统低功耗设计。
能把相关的代码发来参考一下吗?谢谢!
这样的代码网上一大把。
我的重复码是在引导码那里处理的,
所以只要收到低9高2.25就会执行重复上次成功收到的编码。 一旦长按时没成功收到编码数据(被其它红外设备干扰或处理机制的问题),
也是会响应后面的重复码的 但重复执行的却是上一次成功收到的编码。
if (Receive ==0)//低电平
{
Count++; //计数
if (Stage ==1)//阶段:判断是否引导码/重复码高电平
{
if ((Count >24 && Count < 28) || (Count >11 && Count < 15))
{
if (Count >24 && Count < 28)
{
Stage =2;//是码头高电平,进入解码阶段
Count =0;
RepeatCount =0;//重复码计数清零
}
if (Count >11 && Count < 15)//是重复码高电平
{
RepeatCount ++;
if (RepeatCount >6)//重复执行间隔时间
{
RepeatCount =0;
CommandToUpdate =1;
}
}
}
else
{
returnStatus ();
}
}
if (Stage ==3)//阶段:判断是否数据码高电平
{
if (Count >1 && Count < 5)
{
State_Data <<=1;//收到1位数据0
Stage =2;
State_Count ++;
}
if (Count >7 && Count < 13)
{
State_Data =(State_Data <<1) | 0x01;//收到1位数据1
Stage =2;
State_Count ++;
}
if (Stage ==3)
{
returnStatus ();
}
Count =0;
if (State_Count >7)//完成一个字节数据接收
{
State_Count =0;
DATA_Length ++;
if (DATA_Length >3)//收到4个字节数据
{
CommandToUpdate =1;
}
}
}
}
}
if (Receive==1)//高电平
{
Count++; //计数
if (Stage ==0)//阶段:判断是否引导码低电平
{
if (Count >49 && Count < 56)
{
Stage =1;//是码头低电平,进入引导码高电平阶段
Count =0;
}
else
{
returnStatus ();
}
}
if (Stage ==2)//阶段:判断是否数据码低电平
{
if (Count >1 && Count < 5)
{
Stage =3;
Count =0;
}
else
{
returnStatus ();
}
}
}
这个两种方式,一个是发送端确认长按键,一个是接收端确认
红外用的比较少,学习下
页:
[1]
2