完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
2个回答
|
|
红外解码的实现一般有定时器中断、外部中断+定时器、查询三种解码方案,其中查询方式解码在一些资源极少的MCU中或需要长时间关闭中断的系统中比较实用。下面给出的是用应广PMS150C单片机上实现的代码。
最近在用双元单通数字输出热释电红外传感器,感觉做出来的成本比现有方案有竞争优势,下次给大家写这个。 一.红外的编码格式 一般红外接收都采用市场上的集成接收头,它主要将38KHz的调制信号处理成电平信号,不过在一些应用中需要注意集成接收头有上电延时和接收延时,也不能长时间一直接收38KHz信号(会被接收头识别为干扰而被过滤)。 上图为编码格式:包括引导码+起始码+地址码+数据码+【结束码】其中结束码如不识别长按基本用不到! 上面为编码方式,当经过接收头的信号处理后得到的信号需要倒向,下面讲解都为倒向后的信号。 1.引导码和起始码 引导码为9ms低电平,起始码为4.5ms 高电平 注:在识别时需要考虑容错范围。 2.0码和1码 上图为0码和1码的编码方式,而实际接收到是倒向的。 3.地址码 地址码为2个八位表示 :如0xFF,0x00 其中一个码是另一个码的反码。一般应用的时候可以利用该码来屏蔽一些错误或遥控器。 4.数据码 数据码也是2个八位表示:如0x01,0xFE 2个字节也是互为反码。一般应用的时候可以了利用来屏蔽接收错误的情况。 5.结束码 如果红外遥控器的按键一直按着,一般会每隔108ms左右发送一次,这里具体的时间还需要实际测试一下! 注:上面每次的电平识别都需要考虑容错的问题!!! 二.各阶段主要代码介绍 1.空闲处理 接收初始假设是处于空闲状态,即接收端口一直为高电平。 //--------------idle if(ir_rcvsta==0)//idle { if(ir_rcvio==1) { return_byte(0);//退出 } ir_rcvsta++; ir_rcvTimeCntL = 0; ir_rcvTimeCntH = 0; ir_rcvLevel_flag = 0; } 2.引导码和起始码 一旦接收端口变为低电平后会进入该状态 //--------------boot else if(ir_rcvsta == 1) { if(ir_rcvLevel_flag == 0) {//low boot 9ms if(ir_rcvio== 0) { ir_rcvTimeCntL++; if(ir_rcvTimeCntL>=150)//>=15ms error {//boot error return_byte(0); } } else { if(ir_rcvTimeCntL<45)//<4.5ms error { return_byte(0); } ir_rcvLevel_flag = 1; } } else {//high boot 4.5ms if(ir_rcvio == 1) { ir_rcvTimeCntH++; if(ir_rcvTimeCntH>=65)//>=6.5ms error {//high level timeout return_byte(0); } } else { if(ir_rcvTimeCntH < 25) {//low<4ms or high<2.5ms boot error return_byte(0); } ir_rcvIndex = 0; ir_rcvTimeCnt = 0; ir_rcvsta++; ir_rcvTimeCntL = 0; ir_rcvTimeCntH = 0; ir_rcvLevel_flag = 0; } } }//1 end 3.地址码和数据码接收 数据码和地址码可以放在一起,因为他们都一样!只是在应用逻辑上定义不同而已。该接收方式只需要稍微改改,就可以接收任意多个数据,例如用在433的无线解码上。 else if(ir_rcvsta == 2)//address or data recive. { if(ir_rcvLevel_flag==0) {//low if(ir_rcvio==0) { ir_rcvTimeCntL++; if(ir_rcvTimeCntL>=9)//low >=900us error { return_byte(0); } } else { if(ir_rcvTimeCntL<=1) { return_byte(0); } ir_rcvLevel_flag = 1; } } else {//high if(ir_rcvio == 1) { ir_rcvTimeCntH++; if(ir_rcvTimeCntH>=25)//hig >=2.5MS error { return_byte(0); } } else { if( ir_rcvTimeCntH <= 1 ) { return_byte(0);//low<100us error } ir_rcvBuf <<= 1; if(ir_rcvTimeCntH >10 ) {//1 ok ir_rcvBuf.0 = 1; } else {//0 ok ir_rcvBuf.0 = 0; } ir_rcvTimeCnt++; if(ir_rcvTimeCnt>=8) {//recevie sucess a byte data ir_rcvTimeCnt = 0; array_set_u8_t(ir_rcvResult,ir_rcvIndex,ir_rcvBuf); ir_rcvIndex++; if(ir_rcvIndex >=4) { if(ir_rcvResult[0] != IR_ADRH) { return_byte(0); } if(ir_rcvResult[1] != IR_ADRL) { return_byte(0); } A = ~ir_rcvResult[2]; if( A != ir_rcvResult[3]) { return_byte(0); } return_byte(1);//recevie sucess return } } ir_rcvTimeCntL = 0; ir_rcvTimeCntH = 0; ir_rcvLevel_flag = 0; } } }//2 end fun_pcall(delay_20us,10);100us 这个100us延时函数比较重要,一定要测试 //MNOTB(DEBUG_OUT); 三 .解码说明 上面用到的fun_pcall(delay_20us,10); 只是一个延时函数,你可以改成你自己的。 return_byte(0); 相当于return 0; A = ~ir_rcvResult;这里的A只是一个临时变量,你可以改成你自己的。 array_set_u8_t(ir_rcvResult,ir_rcvIndex,ir_rcvBuf); 保存一个数据。 有人说这里为什么要这样做,是因为应广单片机的编译器不支持函数带参调用和返回。 把上面的解码放在while(1){fun}下,做成函数形式,函数返回0表示接收错误或空闲,当函数返回1时表示接受到正确的数据,用户可以处理该数据了。 上面整个解码过程还是很简单,其中最重要的是容错的问题!!!! |
|
|
|
|
|
只有小组成员才能发言,加入小组>>
imx6ull 和 lan8742 工作起来不正常, ping 老是丢包
1455 浏览 0 评论
3339 浏览 9 评论
3017 浏览 16 评论
3508 浏览 1 评论
9104 浏览 16 评论
1222浏览 3评论
632浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
621浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2363浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1928浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-1-13 21:20 , Processed in 1.169718 second(s), Total 81, Slave 62 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (威廉希尔官方网站 图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号