红外遥控的输入捕捉实现~~~~搞一个周刚成功!发个给同我一样的初学者
电路图:点击此处下载ourdev_215975.rar(文件大小:15K)
程序:
//包含所需头文件
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <avr/delay.h>
#include "chuankou.h"
/*------宏定义------*/
#define uchar unsigned char
#define uint unsigned int
#define BIT(x) (1<<(x))
#define NOP() asm("nop")
#define WDR() asm("wdr")
//一般说来,volatile用在如下的几个地方:
//1、中断服务程序中修改的供其它程序检测的变量需要加volatile;
//2、多任务环境下各任务间共享的标志应该加volatile;
//3、存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能由不同意义;
volatile uint data0; //前16个脉冲存放地址
volatile uint data1; //后16个脉冲存放地址
volatile uint Flag=0; //接收完成一帧标志位
volatile float oldFall=0,newFall=0;//时间的先后纪录
volatile uint bitcnt=0; //脉冲个数纪录
//端口初始化
void port_init(void)
{
PORTB = 0x01;
DDRB= 0x00;
}
//定时T1初始化
//系统时钟为8M内频,64分频,最大定时时长524.228MS
void timer1_init(void)
{
TCCR1B = 0x00;//停止定时器
TIMSK |= 0x20;//中断允许
ICR1H= 0xFF;
ICR1L= 0xFF;//输入捕捉匹配值
TCCR1A = 0x00;
TCCR1B = 0x83;//启动定时器
}
void init_devices(void)
{
cli(); //禁止所有中断
MCUCR= 0x00;
MCUCSR = 0x80;//禁止JTAG
GICR = 0x00;
port_init();
timer1_init();
sei();//开全局中断
}
//主函数
int main(void)
{
init_devices(); //端口初始化
uart_init(); //串口初始化
//在这继续添加你的代码
while(1)
{
if(Flag)
{
Flag=0;//清除标志位
bitcnt=0; //计数标志位清0
_delay_ms(5);
put_char((uchar)((data0&0xff00)>>8));//机器码
_delay_ms(5);
put_char((uchar)(data0&0x00ff));//机器反码
_delay_ms(5);
put_char((uchar)((data1&0xff00)>>8));//用户码
_delay_ms(5);
put_char((uchar)(data1&0x00ff));//用户反码
_delay_ms(5);
}
}
return 0;
}
//数据头的时间:Th=9+4.5=13.5ms
//数据“0”的时间:T0=0.565+0.56=1.125ms
//数据“1”的时间:T1=1.685+0.56=2.245ms
//定时器T1输入捕捉中断服务程序
//#pragma interrupt_handler timer1_capt_isr:6
//void timer1_capt_isr(void)
SIGNAL(SIG_INPUT_CAPTURE1)
{
//timer 1 input capture event, read (int)value in ICR1 using;
// value=ICR1L; //Read low byte first (important)
// value|=(int)ICR1H << 8; //Read high byte and shift into top byte
// TIFR|=BIT(ICF1);//软件写1清中断标志
float time=0;
unsigned int temp=0;
newFall=ICR1; //读取当前时间
time=newFall-oldFall; //计算脉冲加间隔的时间
oldFall=newFall; //存放上一次的时间
if(time<0)time=newFall-oldFall+0xffff;//定时周期交叉的情况
temp=(unsigned int)time; //取整
//T0的8分频,即(1.125*1000)/8 = 140.625us ;正负20宽范围判断
if((temp>120) && (temp<160)) // "0"信号
{
temp=0;
}
//T1的8分频为280.625us
else if((temp>260) && (temp<300)) //“1”信号
{
temp=1;
}
//Th的8分频为1687.5us
else if((temp>1660) && (temp<1700)) //header头信号
{
bitcnt=0;
data0=0;
data1=0;
return; //返回,等待下次开始接收
}
else //干扰信号
{
bitcnt=0;
data0=0;
data1=0;
return;
}
bitcnt++;
if(bitcnt<16) //开始接收前16位
{
data0=data0|temp;
data0=data0<<1;
}
else if(bitcnt==16)
{
data0=data0|temp;
}
else if(bitcnt<32) //开始接收后16位
{
data1=data1|temp;
data1=data1<<1;
}
else if(bitcnt==32) //接收完最后一位
{
data1=data1|temp;
Flag=1; //接收完一帧,标志位置1
}
}
/*头文件中的串口通讯子程序chuankou.h*/
#include <avr/io.h>
#define fosc 8000000
#define baud 4800
/*字符串输出函数*/
void put_char(unsigned char c)
{
while (!(UCSRA&(1<<UDRE)));
UDR=c;
}
/*字符输入函数*/
unsigned char getchar(void)
{
while(!(UCSRA& (1<<RXC)));
return UDR;
}
/*字符串输出函数*/
void put_s(unsigned char *s)
{
while (*s)
{
put_char(*s);
s++;
}
// put_char(0x0a);//回车换行
// put_char(0x0d);
}
/*UART初始化*/
void uart_init(void)
{
UCSRB=(1<<RXEN)|(1<<TXEN);//允许发送和接收
UBRRL=(fosc/16/baud-1)%256;
UBRRH=(fosc/16/baud-1)/256;
UCSRC=(1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);//8位数据+1位STOP位
}
谢谢21楼 kv2004提供的解码思路:(注:此图不代表与上面的程序对应)
http://cache.amobbs.com/bbs_upload782111/files_9/ourdev_195578.jpg 好。
顺便再详细说说的 解码的红外遥控器的 编码格式,和你解码的思路,这样就比较有价值了。
光放个程序感觉就像一堆字母,呵呵。 回楼上的:
1、红外编码格式在此不做解析了,提供几个相关连接吧
http://www.avrw.com/article/art_105_816.htm
http://hi.baidu.com/silencecoyote/blog/item/0d5b9b3d7130d800bba167ec.html
2、思路跟提供的连接里面的差不多,只是我发现很多我找到的资料都是同一个版本而且是不全的资料(估计都对抄的)
3、在此提供一个简单的解码过程,相关注解个人认为都蛮清楚的了
4、提几点自己发现的小问题吧:
(1)许多网上的解码做法都是1M内频加不分频解码,导致定时器1的最大定时只有65.536ms,假设全1码的时候就会出现:13.5ms+2.245ms*32=85.34ms大于一个定时周期了,何况大于的状态并没有给出如何处理!
(2)此次为通过串口测试,发送时中间加点必要延时,免出多余的码 阿莫应该发裤子 其实如果不是要求十分严格的应用。可以不用校验红外的反码,99.9%不会出错的。这样可以简化程序。 正想学学 学习了,哈哈 本次只是给出红外解码的输入捕捉实现办法……至于应用于哪方面那应该是大虾们的爱好了,有了实现的办法参考,用途上还不是随心所欲??
什么那么少人顶楼啊?有点悲哀啊……本想多帖点自己的东西的,没多大心情了,这会儿! 学习中........ 我顶你一个 这只是一种比较常用的32位红外码,还有好多种编码,LZ要加油哦,一种一种搞。。。 我也顶你一个 ding yi ge 继续哦 好!帮顶一下! 支持一下! 顶一个! 顶一下!! 支持一下楼主 attiny13可以使用吗 我跟用了楼主的程序,但是我总找不到head啊,怎么回事呢?会不会LC7461的和其他的head不一样呢,但我看了芯片资料是一样的啊 也做了一个,原理和楼主的一样,只是用了定时器0和中断0两个中断。没有判断脉冲占和空的宽度,只是靠下降沿的间隔来判断状态。效果不差。只上个图吧。
http://cache.amobbs.com/bbs_upload782111/files_9/ourdev_195578.jpg 顶一下,正需要呢! 抱歉由于本贴没有上传电路图,不能置COOL。
刚在论坛的后台管理界面增加了这一个提示的功能。 以后版主们就能很方便地提醒了。 顶一下! 点击此处下载ourdev_215975.rar(文件大小:15K)
为了有裤子穿而不至于裸奔街头,现把简陋的原理图贴上,画得粗糙望请见谅了……
对本原理图的一点说明:
总的来说电路其实很简单,跟单片机接口就三跟线而已,其他的就是单片机工作的一些基本外围电路!
目前个人应用过:(见笑了)
时钟遥控调节、配合上位机遥控电脑的一些软件(如音乐播放)、遥控你的小车 差点忘了!
armok 阿莫发条裤子不?裤衩也行……(莫大的鼓励了!)
(*^__^*) 嘻嘻……! 电路图啊 用51的也做了个红外解码,刚刚完成 拿家里电视机遥控器来调时间。 这个好象不难!! 刚试用了楼主的程序,很不错。
强烈建议在AVR中不要使用float数据,将float改为int32_t后代码量减少2KB多。 我们用的方法和21楼的一样,用单片机的一个定时器和一个中断实现红外接收解码,也可以作为无线电的接收解码(频率不是很高). 强帖 学习学习 我最近也在做这个,用电视遥控控制机器人小车的,开始一直不成功,用的CVAVR,库里没有ICR1,后来才发现ICR1L和ICR1H读写是有顺序的,要先读ICR1L,再读ICR1H. 多谢楼主,学习中,有空我也去搭个电路试下. 好东东,相见恨晚! 遥控解码程序编写是有个问题,请教大家一下:
就是每种遥控器发射的数据编码格式不一样,要是知道某个遥控器的编码格式才有办法写程序啊,
如何获取遥控器的编码?如按键1 2 。。。。。。的编码?
谢谢! . 好东西! 好东西! 看看。 好久后的回顾:
首先感谢21楼提供的解码思路图解,解码思路基本一致;
方法上有点不同的是图中为定时器解码,偶的是输入捕捉方法实现,原理上是等效的;
回【36楼】 haizaolan 如何获取遥控器的编码?如按键1 2 。。。。。。的编码?
偶的串口通信子程序就是用来查询各个按键的对应编码的啊,
每按任意一个按键都会读出四个码值(机器码、机器反码、用户码、用户反码):
机器码:对应不同的遥控板(类似的VCD遥控板)
机器反码:就是机器码取反
用户码:不同按键对应的编码,读取这个值就可区分是哪个按键
用户反码:用户码取反
至于按键功能就是你自己定义了,关键在读取~~~ 好久后的回顾:
首先感谢21楼提供的解码思路图解,解码思路基本一致;
方法上有点不同的是图中为定时器解码,偶的是输入捕捉方法实现,原理上是等效的;
回【36楼】 haizaolan 如何获取遥控器的编码?如按键1 2 。。。。。。的编码?
偶的串口通信子程序就是用来查询各个按键的对应编码的啊,
每按任意一个按键都会读出四个码值(机器码、机器反码、用户码、用户反码):
机器码:对应不同的遥控板(类似的VCD遥控板)
机器反码:就是机器码取反
用户码:不同按键对应的编码,读取这个值就可区分是哪个按键
用户反码:用户码取反
至于按键功能就是你自己定义了,关键在读取~~~ 33楼的建议很不错,这个确实需要注意~~~~~~
先读低位字节再读高位字节 利用定时器的捕捉中断功能解码是最简单效率最高的,偶的做法是依次记录脉冲间隔时间,接收完毕后置位中断标志主程序解码,不喜欢在中断干跟多事情,节省效率! mark 但是,我觉得,这种方式解。不太通用。如果程序中又有其它部分用到TC1的话,怎么处理? mark 好东西! 不错 mark 非常感谢楼主,因为我原来的红外解码代码是从51下移植过来的,在外部中断进行解码。
解码时必须关闭所有中断,CPU占用相当严重。而AVR自带的捕捉功能,没有好好利用。
所以试了一下楼主的代码,说下感受。楼主的解码原理是正确的,应该可以正常工作。
但楼主的代码相当地不够优化,建议改进:
1、例如前些楼有朋友提到的,使用了float变量问题。
2、中断中的变量数也太多了,不需要这么多。
3、中断中代码还可以优化。
我按照楼主的代码进行了修改,没有做串口输出部分。
编译后代码不到500字节,内存使用了8个字节。 顶 学习 做个记号 好东西,做个记号先。 mark 记号 mark mark个先 是个好东西,支持 mark
同意51楼的,代码风格,哈哈 支持你 好东西 要学习学习 mark 郁闷,还没成功,接收头总是受外界干扰,捕捉解码不成功,在开了日光灯或节能灯情况下不知道楼主捕捉解码成功的灵敏度如何? 我也顶一下.. 如果受到干扰,把接受头的灵敏度降低。
用硬件 支持你 支持你 我顶! 我也顶一下.. 虽然暂时用不上,不过一定要顶! 做过记号! 用数字存储示波器捕捉下来慢慢看,也是一种方法,不一定要搞一个专用的。 记号~~极好... 学习 MARK一下! mark 好东西啊,谢谢分享啊 我也顶你一个 那.记个号 学习 用51 搞出来过 现在没兴趣了啊 极好 mark一下 看看這個, 原始紅外遙控碼分析 : (使用 ATmega8/ATmega168 @16MHz)
http://www.arduino.cc/playground/Code/InfraredReceivers
也是用定时器T1输入捕捉中断服务程序, 能輸出時序數據, 再配合gnuplot,
能繪出原始紅外遙控碼. 適合初學者了解不同格式的紅外遙控碼. 實用啊. 做个记号 为什么要把
//#pragma interrupt_handler timer1_capt_isr:6
//void timer1_capt_isr(void)
两行注释掉 是不是应该在完成一次32位解码后,应停止TC1 捕捉,在处理完后再开捕捉啊,如果一直处于捕获状态,是不是对前一次的32位数据有影响,特别是在处理速慢的时候 我收下了,谢谢! 兄弟,有没有试过,同时有几个编码差不多的摇控器,一同发射,你的接收会正常吗? 支持一下~~~ MARK ding 好的 MARK 也学习下 MARK LZ 能否留下联系方式,小弟在调试中遇到了问题想请教,我也是用捕获功能来解码,下降沿触发,但总是捕获不到13.5ms的引导码!~我的QQ 416066411 希望其它知道原因的朋友能赐教,谢谢!
页:
[1]
2