分享红外解码 基于125us定时 任意IO
本程序适用于NEC协议的红外遥控器。红外接收头可接任意IO引脚;必须每125us调用一次红外解码程序。
代码如下,写得有点难看,能用就好----------
/*
描述:红外解码程序,必须每125us调用一次
*/
void ir_decode(void)//红外解码
{
static unsigned char state=0;
static unsigned char cnt=0;
static unsigned char rec_data;
static unsigned char rec_cnt=0;
static unsigned char i=0;
if(ir_ok)return;
switch(state)
{
case 0: //判断起始码9m低电平
++cnt;
if(IR_IO == 1) //高电平到来
{
if(cnt >= 71 && cnt <= 73) //高电平之前,维持约为9ms的低电平,cnt=72=9ms,
{
state = 1; //进入下一状态
cnt = 1;
}
else
{
cnt = 0;
}
}
break;
case 1: //判断引导码4.5ms高电平
++cnt;
if(IR_IO == 0) //低电平到来
{
if(cnt >= 34) //低电平来之前,维持了约为4.5ms的高电平 cnt=36=4.5ms
{
state = 2;
cnt = 1;
rec_cnt = 0;
i = 0;
}
else //不合法退回最初状态
{
state = 0;
cnt = 0;
}
}
else //为高电平
{
if(cnt > 37)//长时间为高电平 退回最初状态
{
cnt = 0;
state = 0;
}
}
break;
// case 2 和 case 3 为接收数据
case 2: //560us的低电平
++cnt;
if(IR_IO == 1) //高电平到来
{
if(cnt >= 3) //高电平到来之前 维持了约560us的低电平 cnt=4.48=560us
{
state = 3;
cnt = 1;
}
}
else //为低电平
{
if(cnt >8) //长时间处于低电平 错误 返回
{
state = 0;
cnt = 0;
}
}
break;
case 3: //560 或 1.69ms高电平
++cnt;
if(IR_IO == 0) //低电平到来
{
rec_data >>= 1;
if(cnt > 10)//低电平到来時 高电平维持>560us bit值为1 cnt=4.48=560us
{
rec_data |= 0x80;
}
if(++i >= 8)//是否接收完一个字节
{
i = 0;
ir_data = rec_data;//保存
if(++rec_cnt >= 4) //接收完所有数据
{
ir_ok = 1; //標志接收完成
rec_cnt = 0;
state = 0;
cnt = 0;
}
else //还没有接收完 返回上一步继续
{
state = 2;
cnt = 1;
}
}
else //还没有接收完 返回上一步继续
{
state = 2;
cnt = 1;
}
}
else //为高电平
{
if(cnt > 15) //长时间为高电平 错误 返回
{
state = 0;
cnt = 0;
}
}
break;
}
}
//读取红外编码值,外部调用
//返回0 没接收到红外遥控信号
unsigned char ir_read(unsigned char *p)
{
unsigned char i;
if(ir_ok == 0)return 0; // 没接收到红外遥控信号
for(i = 0; i < 4; i++)
{
p = ir_data;
}
ir_ok = 0;
return 1;
}
在125us的定时中断里调用红外解码函数;定时中断里还可以用于别的计时,不会因为用于红外解码而独占一个定时器。
//125us 定时中断
void timer0_isr() interrupt 1
{
static unsigned char _10ms_cnt = 0;
ir_decode(); //每125us调用红外解码函数
/*还可以用作别的计时*/
if(++_10ms_cnt >= 80)
{
_10ms_cnt = 0;
_10ms_ok =1;
}
}
应用测试
void main()
{
unsigned char ir_data;
UartInit();
timer0_init(); //初始化定时器0为 125us中断
while(1)
{
if(ir_read(ir_data) == 0)continue;
UartSendByte(ir_data);
UartSendByte(ir_data);
UartSendByte(ir_data);
UartSendByte(ir_data);
}
}
谢谢分享,有空再下载来玩玩 学习了 请问同一设备解出来的码有规律吗? wangxuedong 发表于 2013-8-26 08:57 static/image/common/back.gif
请问同一设备解出来的码有规律吗?
地址会一样,就是前两个字节 那74位的怎么解释,比如:8950,4400,650,1650,650,500,650,550,650,1650,650,550,650,500,650,550,600,600,600,550,650,1650,650,500,650,1650,650,550,650,500,650,550,650,500,650,550,650,550,650,500,650,550,650,500,650,550,650,550,650,500,650,550,650,500,650,550,650,500,650,1650,650,550,650,1600,650,550,650,550,600,1650,650,550,650,32896 wangxuedong 发表于 2013-8-26 09:13 static/image/common/back.gif
那74位的怎么解释,比如:8950,4400,650,1650,650,500,650,550,650,1650,650,550,650,500,650,550,600,600, ...
这个看不懂,你这些数据是怎么来的 好东东,谢谢 好东东,收藏 tianxian 发表于 2013-8-26 09:22 static/image/common/back.gif
这个看不懂,你这些数据是怎么来的
自己解码解出来的求高手指教啊 学习一下........ mark,多谢分享 灰常感谢,我不知道原来LZ在这里分享了,不然我也不会特别发帖问这个问题。一句话,灰常感谢LZ。{:handshake:} xiaoxei 发表于 2013-9-9 16:07 static/image/common/back.gif
灰常感谢,我不知道原来LZ在这里分享了,不然我也不会特别发帖问这个问题。一句话,灰常感谢LZ。{:handshak ...
不客气 刚好有用到,正在学习,感谢楼主。 不错,我也是这个方法,画板的把io没接在中端上{:mad:} 学习一下 学习了
谢谢分享{:handshake:} 红外解码mark 正在查这些资料呢,,谢谢 定时最好是50us 或者80us的 标志,红外解码 {:biggrin:} 正在学习 状态机,不错 有用,标记一下! 问楼主一个问题。我把它移植到AVR上怎么不行啊
占用了一个定时器,可不可以用中断啊,修改一下延时就好了,不用定时器。 你好,我把你的红外遥控程序移植到我的M48单片机上,怎么不成功呢,是哪里的问题 你好,我把你的红外遥控程序移植到我的M48单片机上,怎么不成功呢,是哪里的问题 使用一个定时器和引脚电平变化中断。就不需要定时调用解码程序了。 你好,我把你的红外遥控程序移植到我的M48单片机上,怎么不成功呢,是哪里的问题 现在问题是不能解码,我的晶体是8M的 贴出程序
////////////////////////////////////////////////////////////
// 描述:红外解码程序,必须每125us调用一次
void ir_decode(void)//红外解码
{
static unsigned char state=0;
static unsigned char cnt=0;
static unsigned char rec_data;
static unsigned char rec_cnt=0;
static unsigned char i=0;
// if(ir_ok)return;
switch(state)
{
case 0: //判断起始码9m低电平
++cnt;
if(IRIN == 1) //高电平到来
{
if(cnt >= 71 && cnt <= 73) //高电平之前,维持约为9ms的低电平,cnt=72=9ms,
{
state = 1; //进入下一状态
cnt = 1;
}
else
{
cnt = 0;
}
}
break;
case 1: //判断引导码4.5ms高电平
++cnt;
if(IRIN == 0) //低电平到来
{
if(cnt >= 34) //低电平来之前,维持了约为4.5ms的高电平 cnt=36=4.5ms
{
state = 2;
cnt = 1;
rec_cnt = 0;
i = 0;
}
else //不合法退回最初状态
{
state = 0;
cnt = 0;
}
}
else //为高电平
{
if(cnt > 37)//长时间为高电平 退回最初状态
{
cnt = 0;
state = 0;
}
}
break;
// case 2 和 case 3 为接收数据
case 2: //560us的低电平
++cnt;
if(IRIN == 1) //高电平到来
{
if(cnt >= 3) //高电平到来之前 维持了约560us的低电平 cnt=4.48=560us
{
state = 3;
cnt = 1;
}
}
else //为低电平
{
if(cnt >8) //长时间处于低电平 错误 返回
{
state = 0;
cnt = 0;
}
}
break;
case 3: //560 或 1.69ms高电平
++cnt;
if(IRIN == 0) //低电平到来
{
rec_data >>= 1;
if(cnt > 10)//低电平到来時 高电平维持>560us bit值为1 cnt=4.48=560us
{
rec_data |= 0x80;
}
if(++i >= 8)//是否接收完一个字节
{
iTemp=12;
i = 0;
addr = rec_data;//保存
if(++rec_cnt >= 4) //接收完所有数据
{
ir_ok = 1; //標志接收完成
iTemp=12;
rec_cnt = 0;
state = 0;
cnt = 0;
}
else //还没有接收完 返回上一步继续
{
state = 2;
cnt = 1;
}
}
else //还没有接收完 返回上一步继续
{
state = 2;
cnt = 1;
}
}
else //为高电平
{
if(cnt > 15) //长时间为高电平 错误 返回
{
state = 0;
cnt = 0;
}
}
break;
}
}
//读取红外编码值,外部调用
//返回0 没接收到红外遥控信号
unsigned char ir_read(unsigned char *p)
{
unsigned char i;
if(ir_ok == 0)return 0; // 没接收到红外遥控信号
for(i = 0; i < 4; i++)
{
p = addr;
}
ir_ok = 0;
return 1;
}
////////////////////////////////////////////////////
//125us 定时中断
#pragma vector=TIMER2_OVF_vect
__interrupt void TIMER2_OVF_Server(void)
{
static unsigned char _10ms_cnt = 0;
ir_decode(); //每125us调用红外解码函数
TCNT2 = 0x83; //reload counter value
// iTemp=55;
/*还可以用作别的计时*/
if(++_10ms_cnt >= 80)
{
_10ms_cnt = 0;
_10ms_ok =1;
}
}
JZcrystalwlh888 发表于 2014-8-31 16:57
你好,我把你的红外遥控程序移植到我的M48单片机上,怎么不成功呢,是哪里的问题 ...
沒用過M28,但只要是125us調用一次就沒問題 颜靖峰 发表于 2014-8-31 16:53
占用了一个定时器,可不可以用中断啊,修改一下延时就好了,不用定时器。 ...
定時器不是比延时程序更有优势吗 不行哦,我用M48的T2定时器 正在查这些资料呢,,谢谢 谢谢,分享!! 天。。125us调用一次,得占用多少CPU资源啊。 记下来吧,125是不是太频繁了 同一个单片机 如果做到同时编码,同时解码。有做过类似的出来指导下!! 谢谢分享,学习了 收藏了,如果任务多的话,会有其它中断,会不会影响到解码的? l769109884 发表于 2014-10-24 09:52
收藏了,如果任务多的话,会有其它中断,会不会影响到解码的?
用定时中断方法 本就是为了解决多任务的问题,按一般用延时的做法,会影响整个软件的性能,多任务的时候就会暴露很多问题 分享红外解码 基于125us定时 任意IO 这个程式是不是参考一位前人(现在没有找那个贴)所写的都是用125us区别就是你用了开关语句,他用if了,我也是一直用那前人的那个方式解码,时实性好。 看一下好像没有写完整,程式中只识别“0”却没有“1”的识别。 再仔细看一下,好像漏洞百出,LZ有没有实际测试过? 本帖最后由 youlongam 于 2015-7-5 23:29 编辑
这种思路曾经用过,250us的时间片就可以了,反应很快。
在250US的定时中断调用下面的程序:
void ir(u32 *p)
{
static u8 delay=0,delay_n=0;
static u8 step=0;
static u32 ir_data1=0;
switch(step)
{
case 0:
if(!PORT_IR_ST)
{
delay++;
}
else
{
delay_n++;
if(delay>=20)
{
delay=0;
step=1;
}
if(delay_n>4)
{
delay=0;
delay_n=0;
}
}
break;
case 1:
if(PORT_IR_ST)
{
delay++;
if(delay>40)
{
delay=0;
step=0;
}
}
else
{
delay_n++;
if(delay_n>50)
{
delay_n=0;
delay=0;
step=0;
}
if(delay>12)
{
step=2;
delay=0;
delay_n=0;
}
}
ir_data1=0;
break;
case 2:
if(PORT_IR_ST)
{
step=3;
delay++;
}
break;
case 3:
if(PORT_IR_ST)
{
delay++;
if(delay>=20)
{
delay=0;
delay_n=0;
step=0;
}
}
else
{
step=4;
}
break;
case 4:
if(PORT_IR_ST)
{
step=3;
delay_n++;
if(delay>4)
{
ir_data1=ir_data1|(0x80000000);
}
else
{
ir_data1=ir_data1&0x7fffffff;
}
if(delay_n>=32)
{
delay_n=0;
delay=0;
step=0;
*p=ir_data1;
break;
}
ir_data1=ir_data1>>1;
delay=1;
}
break;
default:
break;
}
}
125us对51单片机来说,12M晶振时时间非常吃紧...... 学习,谢谢!!! 这个看不懂,你这些数据是怎么来的 freshuman 发表于 2015-7-5 23:12
再仔细看一下,好像漏洞百出,LZ有没有实际测试过?
测试过,漏洞在哪 mark.....
感谢分享! 好用。效果不错。stm816M.在中断运行解码程序只花了2.7us.125us的中断频率。剩余时间很多。 跟我之前看到的一个帖子挺像。马克一下 这个状态法的程序貌似只能解短按,没有解决长按状态的解码问题 mark 不错,谢谢分享 此中断函数中的静态变量,最好不要再函数中定义,东西写多了,容易跑飞。。。。 不错,好帖子 谢谢分享 这种有长按,短按功能 这个程序就跑不了 iamfiavarst 发表于 2015-7-6 11:34
125us对51单片机来说,12M晶振时时间非常吃紧......
pic的也一样吃紧 lnso 发表于 2020-7-25 15:48
pic的也一样吃紧
现在很多51都是1T了,125us很轻松,当初用普通51,都用100us中断做通讯解码都没问题。 也可以上下沿中断加定时器数数,效率更高些。
页:
[1]