红外解码程序详解
最简单详细的红外解码程序
#include<reg52.h> //包含头文件名sbit IRIN=P3^2; //定义红外接收头的外部接口,即外部中断0sbit BEEP=P1^5; //定义蜂鸣器接口,我的在P1^5unsigned char IRCOM[7]; //定义数组,用来存储红外接收到的数据void delay(unsigned char x){ //延时子程序unsigned char i; //延时约x*0.14mswhile(x--) //不同遥控器应设置不同的参数{for(i=0;i<13;i++){}} //参数的选择咱们先不管,先看这个}void beep(){unsigned char i; //蜂鸣器发声子程序for(i=0;i<100;i++){delay(4); //这个得看你的蜂鸣器内部是否有振荡源BEEP=~BEEP;} //如果没有振荡源就应该输入脉冲信号BEEP=1;}void IR_IN() interrupt 0 using 0 //外部中断0程序{unsigned char j,k,n=0; //先定义变量,记住n=0EX0=0; //禁止中断,以免再次进入中断delay(15); //延时0.14ms*15=2.1msif(IRIN==1) //如果在这期间有高电平说明{ //信号不是来自遥控的,返回主程序EX0=1;return;}while(!IRIN){delay(1);} //死循环,等待9ms前导低电平信号的结束for(j=0;j<4;j++) //一共有4组数据{for(k=0;k<8;k++) //每组数据有8位{while(IRIN){delay(1);} //死循环,等待4.5ms前导高电平的结束while(!IRIN){delay(1);} //等待0.56ms低电平的结束,准备采集数据,while(IRIN) //开始采集数据{delay(1); //延时0.14ms,每过0.14ms时n就加1n++; //用n记录一共有多少个0.14msif(n>=30) //如果超过0.14ms*30=4.2ms{ //说明是乱码,放弃不要EX0=1;return;}}IRCOM[j]=IRCOM[j]>>1; //右移1位,xxxx xxxx变成0xxx xxx//我们先认为这一位数据是0,现在已经送入一位数据了/*你肯定知道_cror_(x,1)和x>>1的区别吧*/if(n>=8){IRCOM[j]=IRCOM[j]|0x80;}//但是如果不是0呢,//0xxx xxxx和0x80相或后变成了1xxx xxxx//这样这一们数据就被记录为1了/*想一下这里为什么是8呢,0.14ms*8=1.12ms,知道了吧*//*这样反复执行8次,8位数据就存在IRCOM[j]中了*//*外层再循环4次,4*8=32位数据码全都在IRCOM[0],IRCOM[1],IRCOM[2],IRCO M[3]中了*/n=0; //n计数后一定要记得清0,否则下一次就不能准确计数了}}if(IRCOM[2]!=~IRCOM[3]) //这里我们判断数据码和数据反码是不是相反{ //因为相反才是正确的,否则就放弃EX0=1;return;}beep();EX0=1; //记得开中断,你可以去掉这句话试一试}void main(){IE=0x81;TCON=0X01;BEEP=1;IRIN=1;while(1);}怎么样,你看懂了吗?作者:任杰。
(完整word版)红外编码解码程序(word文档良心出品)
红外编码解码程序,我写的是:发送模块通过按键,发送出相应键值的编码,接收模块接收到信号后解码该键值,并点亮相应的状态灯(新手,高手勿喷)//************************* 单片机红外发射******************************* #include<reg52.h> sbit ir=P 1人3;sbit k1= P2A5;sbit k2=P2M;sbit k3=P2A3;sbit k4=P2A2;sbit k5=Pil;unsigned int count, set_count; bit irflag,keyflag; unsigned char irsys[]={0x00,0xff}; unsigned char irdata,ircode;void delay(unsigned int a){unsigned char i;while(--a!=0) for(i=300;i>0;i--);}void keyscan(){/*if(k1==0){delay(10);if(k1==0){keyflag=1;while(!k1);irdata=0x01;}*/ if(k2==0) {delay(10); if(k2==0) {keyflag=1;while(!k2); irdata=0x02;}{delay(10); if(k3==0) {keyflag=1;while(!k3); irdata=0x03;} if(k4==0){delay(10); if(k4==0) {keyflag=1;while(!k4); irdata=0x04;} if(k5==0){delay(10); if(k5==0) {keyflag=1;while(!k5); irdata=0x05;void ir_sendbyte() // 红外发送一个字节数据{ unsigned char i; for(i=0;i<8;i++) //发送8 位数据{set_count=43; //发送编码中的0.56ms 高电平irflag=1;count=0;TR0=1; while(count<set_count);TR0=0;if(ircode&0x01) set_count=130; // 判断红外编码最低位,若为 1 则 1.69ms 的低电平else set_count=43; // 为0 则0.565ms 的低电平irflag=0;count=0;TR0=1; while(count<set_count);TR0=0; ircode=ircode>>1;}}void ir_send(){set_count=346; //发送编码中的引导码(4.5ms高电平+4.5ms低电平)irflag=1;count=0;TR0=1;while(count<set_count);set_cou nt=346; //发送编码中的 4.5ms低电平irflag=0;count=0;TR0=1;while(count<set_count);TR0=0; ircode=irsys[0];ir_sendbyte();ircode=irsys[1];ir_sendbyte();ircode=irdata; //发送8 位数据码ir_sendbyte();ircode=~irdata; // 发送8 位数据反码ir_sendbyte();set_count=43; //发送编码中的0.56ms高电平irflag=1;count=0;TR0=1;while(count<set_count);TR0=0;irflag=0;/*delay(23); //延时23ms (编码中的23ms低电平)set_count=346; //发送编码中的引导码(4.5ms高电平+4.5ms低电平) irflag=1;count=0;TR0=1; while(count<set_count);TR0=0; set_count=346; irflag=0;count=0;TR0=1;while(count<set_count);TR0=0;*/ set_count=43;irflag=1;count=0;TR0=1;while(count<set_count);TR0=0;irflag=0;delay(23);}void timer0_init(){EA=1;TMOD=0x02;//定时0 8 位自动重装模式ET0=1;TH0=0xe6; //定时13us,38K 红外矩形波,晶振24M TL0=0xe6; }void main(){timer0_init();count=0;ir=0;irflag=0;while(1){keyscan(); if(keyflag) {delay(10); ir_send(); delay(500); keyflag=0;delay(100);}}}void timer0() interrupt 1 {count++;if(irflag==1)ir=~ir; // 有发射标志,则发射38khz 的矩形波elseir=0;红外接收**************************** //*************************#include<reg52.h>#define uchar unsigned char #define uint unsigned intsbit led仁P2A1;sbit led2=卩2人2;sbit led3=卩2人3;uchar irtime;uchar startflag;uchar irdata[33];uchar bitnum;uchar irreceok;uchar ircode[4]; uchar irprosok;void display();void timer0init(){TMOD=0x02;TH0=0x00;TL0=0x00;ET0=1;EA=1;TR0=1;void int0init(){IT0=1;EX0=1; EA=1;}}void irpros(){uchar k,i,j;uchar value;k=1;for(j=0;j<4;j++){for(i=0;i<8;i++){ value=value>>1; if(irdata[k]>6){value=value | 0x80;}k++;if(k>33)k=1;}ircode[j]=value;}irprosok=1;}void main(){ timer0init(); int0init(); while(1) { if(irreceok) { irpros(); irreceok=0;} display();}void display()switch(ircode[2]){case 0x05:led1=1; led2=1; led3=1; break;case 0x02:led1=0;led2=1; led3=1; break;case 0x03:led2=0; led1=1; led3=1; break;case 0x04:led3=0;led1=1;led2=1; break;//case 0x01: 备用}void timer0 () interrupt 1 { irtime++;}void int0 () interrupt 0 {if(startflag){if(irtime>32) // 检测引导码{bitnum=0;}irdata[bitnum]=irtime;irtime=0;bitnum++;if(bitnum==33){bitnum=0;irreceok=1;startflag=0;}else{startflag=1; irtime=0;}}。
红外脉冲解码程序
单片机红外脉冲解码电路采用共阴极四位数码管;8050开关三极管;STC89C52单片机;12M晶振。
C51程序/*红外脉冲破解程序。
脉冲波长用四位数码管以十六进制显示。
脉冲个数用四位数码管以十进制显示。
*/#include<reg52.h>sbit show=P2^4;sbit back=P2^5;sbitNshow=P2^6;unsignedint box[46];unsigned char code Num[]={0xEB,0x41,0xB3,0xBA,0x78,0xDA,0xDB,0xA8,0xFB,0xFA,0xF9,0x5B,0xC3,0x3B,0xD3,0xD1,0x04}; //数码管1-F 显示的花样程序(根据数码管的接线方法的不同,花样码也会不同)unsigned char Nu[4];unsigned char k=0; //脉冲计数判断unsigned char e=0; //脉冲总数存储unsigned char y=0; //数码管显示第几个脉冲unsignedintA,w;voidshow_led(void);voidwait_short(void);void four_led(unsigned char led) //四个数码管用十六进制显示脉冲长度。
{Nu[1]=box[led]%16;Nu[2]=(box[led]/16)%16;Nu[3]=(box[led]/256)%16;Nu[4]=box[led]/4096;}void main(){P2=0XF0;EA=1;EX0=1;IT0=1;ET0=1;TMOD=0x01;TR0=0;TH0=0;TL0=0;y=0;k=0;e=0;while(1)if(Nshow==0) //检查显示的脉冲数数码管用十进制显示{Nu[1]=y%10;Nu[2]=(y/10)%10;Nu[3]=(y/100)%10;Nu[4]=(y/1000)%10;A=3000;while(A--)show_led();four_led(y);}//================================================================================ if(back==0) //回看脉冲长度{A=10000;while(A--);if(y>=1){y=y-1;four_led(y);}else{y=0 ;four_led(y);}four_led(y); //巩固A=400;while(A--)show_led();four_led(y);}//========================================================================== if(show==0) //下一个脉冲长度{P2=0XF0;P1=0X00;A=10000;while(A--);if(y<e){y=y+1;four_led(y);}else{Nu[1]=16;Nu[2]=16;Nu[4]=16;A=400;while(A--)show_led();y=0;four_led(y);}four_led(y); //巩固A=400;while(A--)show_led();four_led(y);}//=============================================================================== show_led();}while(1);}void Int0_Routine() interrupt 0 using 0 //下降沿中断{TR0=0;box[k]=TH0*256+TL0;TH0=0;TL0=0;TR0=1;if(k==0)e=0;e=e+1;k=k+1;}void time_int() interrupt 1 using 0 //计数器中断{TR0=0;box[k]=TH0*256+TL0;TH0=0;TL0=0;k=0; //计数器溢出K归零准备下一个脉冲信号的接受y=0; // 计数器溢出脉冲结束数码管开始显示第0个脉冲four_led(y);}void show_led(void) //数码管显示数值{if(Nu[4]!=0){P1=Num[Nu[1]];wait_short();P2=0xF2;P1=Num[Nu[2]];wait_short();P2=0xF4;P1=Num[Nu[3]];wait_short();P2=0xF8;P1=Num[Nu[4]];wait_short();}else{if(Nu[3]!=0){P2=0xF1;P1=Num[Nu[1]];wait_short();P2=0xF2;P1=Num[Nu[2]];wait_short();P2=0xF4;P1=Num[Nu[3]];wait_short();}else{if(Nu[2]!=0){P2=0xF1;P1=Num[Nu[1]];wait_short();P2=0xF2;P1=Num[Nu[2]];wait_short();}else{P2=0xF1;P1=Num[Nu[1]];wait_short();}}}void wait_short(void) //消岐延时{w=40;while(w--);}解码结果。
一文教会你红外线遥控器软件解码程序
一文教会你红外线遥控器软件解码程序
红外线一开始发送一段13.5ms的引导码,引导码由9ms的高电平和4.5ms的低电平组成,跟着引导码是系统码,系统反码,按键码,按键反码,如果按着键不放,则遥控器则发送一段重复码,重复码由9ms的高电平,2.25ms的低电平,跟着是一个短脉冲。
#includeat89x52.h
#defineNULL0x00//数据无效
#defineRESET0X01//程序复位
#defineREQUEST0X02//请求信号
#defineACK0x03//应答信号,在接收数据后发送ACK信号表示数据接收正确,
也位请求信号的应答信号
#defineNACK0x04//应答信号,表示接收数据错误
#defineBUSY0x05//忙信号,表示正在忙
#defineFREE0x06//空闲信号,表示处于空闲状态
#defineREAD_IR0x0b//读取红外
#defineSTORE_IR0x0c//保存数据
#defineREAD_KEY0x0d//读取键值
#defineRECEIVE0Xf400//接收缓冲开始地址
#defineSEND0xfa00//发送缓冲开始地址
#defineIR0x50//红外接收缓冲开始地址
#defineHEAD0xaa//数据帧头
#defineTAIL0x55//数据帧尾
#defineSDAP1_7
#defineSCLP1_6
unsigned char xdata *buf1;//接受数据缓冲。
红外解码程序详解
//此程序为网上下载后修改,要弄懂的话,可以去看看HT6221的时序图。
当然也欢迎在这里留言。
///C51的红外解码程序,可以根据需要自己修改://11.0592Mhz#include<reg51.h>//根据自己的接线来改sbit IRIN = P3^2; //红外接收器数据线sbit led = P3^7; //指示灯//////////////////////////////////////////////定义数组IRCOM,分别装解码后得到的数据//IRCOM[0] 低8位地址码//IRCOM[1] 高8位地址码//IRCOM[2] 8位数据码//IRCOM[3] 8位数据码的反码/////////////////////////////////////////////#define uchar unsigned char#define uint unsigned intuchar IRCOM[4]=0;bit flag=0;/********************/void delay014ms(unsigned char x); //x*0.14MSvoid IR_init(void);void delay014ms(unsigned char x) //x*0.14MS STC10F04延时约0.15MS {unsigned char i;while(x--){for (i = 0; i<125; i++) //13{;}}}/////////////////初始化////////////void IR_init(void){EA=1;EX0=1; //允许总中断中断,使能 INT0 外部中断IT0=1; //触发方式为脉冲负边沿触发IRIN=1; //I/O口初始化}////////////解码过程//////////////void IR_CODE(void) interrupt 0 //在外部中断子程序中解码{unsigned char j,k,N=0;EX0 = 0;delay014ms(15);if (IRIN==1){ EX0 =1;return;} //确认IR信号出现while (!IRIN) //等IR变为高电平,跳过9ms的前导低电平信号。
红外解码及超声测距程序
lcden= 0; lcdrs = 1; lcdwr = 0; P0 = date; delay(5); lcden = 1; delay(5); lcden = 0; }
//使能 //选择发送命令 //选择写入 //放入命令 //等待数据稳定 //写入时序 //保持时间
void LCD1602_init() { write_com(0x38);//设置 16X2 显示,5X7 点阵,8 位数据接口 write_com(0x0c);//设置开显示,不显示光标 write_com(0x06);//写一个字符后地址指针加 1 write_com(0x01);//显示清零,数据指针清零 } void ShowString(uchar line,uchar * str) { uchar addr; if(line==0) addr=0x80; if(line==1) addr==0xc0; write_com(addr); while(*str!=’\0’) { write_data(*str++); } } /*-----------------------------------------------主函数-----------------------------------------------*/ main() {
IT0 = 1; EX0 = 1; EA = 1; }
//指定外部中断 0 下降沿触发,INT0 (P3.2)
/*------------------------------------------红外码值处理-----------------------------------------------*/ void Ircordpro(void) { uchar i, j, k; uchar cord,value; k=1; for(i=0;i<4;i++) { for(j=1;j<=8;j++) { cord=irdata[k]; value>>=1; if(cord>7) value|=0x80; k++; } IRcord[i]=value; value=0; } irpro_ok=1; } uint Get_KeyValue() { uint KeyValue; TIM0init(); EX0init(); Ircordpro(); If(irpro_ok) { KeyValue=(IRcode[2]/100)*100+(IRcode[2]%100/10)*10+IRcode[2]%10; //处理完毕标志位置 1 //大于某值为 1,这个和晶振有绝对关系,这里使用 12M 计算,此值可以有一定误差 //处理 1 个字节 8 位 //处理 4 个字节
红外遥控解码程序
红外遥控解码程序红外接收头的型号有很多HS0038 VS838等功能⼤致相同,只是引脚封装不同。
红外接收有⼏种统⼀的编码⽅式,采样哪种编码⽅式取决于遥控器使⽤的芯⽚,接收头收到的都是⼀样的。
电视遥控器使⽤的是专⽤集成发射芯⽚来实现遥控码的发射,如东芝TC9012,飞利浦AA3010T等,通常彩电遥控信号的发射,就是将某个按键所对应的控制指令和系统码(由0和1组成的序列),调制在38KHz的载波上,然后经放⼤、驱动红外发射管将信号发射出去。
不同公司的遥控芯⽚,采样的遥控码格式也不⼀样,较普遍的有两种,⼀种NEC标准,⼀种是PHILIPS标准。
NEC标准:遥控载波的频率为38KHz(占空⽐1:3)当某个键按下时,系统⾸先发射⼀个完整的全码,如果按键超过108ms仍未松开,接下来发射的代码(连发代码)将由起始码(9ms)和结束码(2.5ms)组成。
⼀个完整的全码 = 引导码 +⽤户码 +⽤户码 + 数据码 + 数据码 + 数据反码。
其中,引导码⾼电平9ms,低电平4.5ms;系统码8位,数据码8位,共32位;其中前16位为⽤户识别码,能区别不同的红外遥控设备,以防⽌不同的机种遥控码互相⼲扰。
后16位为8位的操作码和8位的操作反码,⽤于核对数据是否接收准确。
收端根据数据码做出应该执⾏上⾯动作的判断。
连发代码是在持续按键时发送的码。
它告知接收端。
某键是在被连续的按着。
NEC标准下的发射码表⽰发射数据0时⽤”0.56ms⾼电平 + 0.565ms低电平 = 1.125ms”表⽰;数据1⽤”⾼电平0.56ms + 1.69ms = 2.25ms”表⽰。
遥控器发射信号:需要注意的是:当⼀体化接收头收到38kHz红外信号时,输出端输出低电平,否则为⾼电平。
所以⼀体化接收头输出的波形和发射波形是反向的PHILIPS标准:载波频率38KHz:没有筒,点按键时,控制码1和0之间切换,若持续按键,则控制码不变。
⼀个全码 = 起始码’11’ +控制码 + ⽤户码 + ⽤户码数据0⽤“低电平1.778ms + ⾼电平1.778ms”表⽰;数据1⽤“⾼电平1.778ms + 低电平1.778ms”表⽰。
红外解码程序
红外解码程序本篇介绍红外解码的原理和程序的写法。
下面来看一下,红外线是如何编码的。
下面来具体说一下,解码的原理,每按一下遥控器的一个按键,遥控器就会发出32个“0”“1”代码(当然是通过高低电平的占空比来判断是0还是1的),具体是0,1是如何编码的上面图片中有介绍,和一个引导码,引导码的作用是告诉处理器,接下来将要开始发送代码,我们在编写程序时,当检测到引导码时,就应该准备接受数据了。
32位代码中的前16位是用户识别码,不同的遥控器不相同,防止互相干扰的,后16是8为数据码,和8位数据反码。
接下来开始介绍如何解码程序的编写。
程序中用到了两个中断,一个是定时器中断,一个是外部中断。
定时器中断用来准确计时,判断接受的代码是0还是1,外部中断用来准确确定定电平到来的时刻,然后开始计时。
/*********************************************************函数功能:红外解码,用八位数码管显示红外线的按键码,便于红外控制测试环境:hot 51学习板编译环境:keil4整理人:张家越QQ:435835181整理时间:2011-04-03************************************************************/#include<reg51.h>#define uchar unsigned char#define uint unsigned intuchar code seg_du[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0 x6f,0x77,0x7c,0x39,0x5E,0x79,0x71 };//0-f的段选码unsigned char code seg_we[]={0,1,2,3,4,5,6,7};uchar irtime,startflag,bitnum,irreceok;uchar irdata[33];uchar irprosok;uchar display[8];uchar ircode[8] ;sbit led1=P0^1;sbit led2=P0^2;/******************************************************************** ****函数功能:延时函数,在数码管显示时使用,不需要很精确********************************************************************* ****/void delay_50us(uint t){uchar j;for(;t>0;t--)for(j=19;j>0;j--);}/******************************************************************** ******函数的功能:定时器0的初始化********************************************************************* *****/void timer0init(){TMOD=0x02; //设置定时器工作在方式2TH0=0x00; //TL0=0x00; //设置定时器的初值ET0=1; //开定时器中断TR0=1; // 打开定时器EA=1; //开总中断}/******************************************************************** ****外部中断1的初始化********************************************************************* **/void int1init(){IT1=1; //设置触发方式为上升沿EX1=1; //开外部中断1EA=1; //开总中断}/******************************************************************** **定时器0的功能函数,每中断一次irtime++,用于计时********************************************************************* **/void timer0() interrupt 1{irtime++; //定时器中断一次irtime++,用于计时}/******************************************************************** ***外部中断0的处理函数,每当有低电平数据过来时,中断一次,(使用次中断的前提是,信号线必需接在外部中断0上面,也就是P3^2口),函数功能是,把信号从高低电平变成时间的代码放入irdata【】中********************************************************************* ***/void int1() interrupt 2{if(startflag){if(irtime>32) //一组代码检测完毕{bitnum=0;}irdata[bitnum]=irtime; //把检测到的时间送到数组irdata【】中去irtime=0;bitnum++;if(bitnum==33) //如果检测到bitnum=33,说明32位用户码已经检测完毕{bitnum=0; //将bitnum清零以便重新计数irreceok=1; //接收完毕标志位置一}}else //(此函数先进入else语句,跳过引导码的检测){startflag=1; //将开始标志位置一irtime=0; //设置时间初值为零irreceok=1; //接收完毕标志位置一}}/******************************************************************** *****函数功能:把irdata【】中的时间代码转换成二进制代码存放在ircode【】中********************************************************************* *****/void irpros(){uchar k=1,value,j,i;for(j=0;j<4;j++){for(i=0;i<8;i++){value=value>>1; //右移7次(第一次是00,相当于没有移位)if(irdata[k]>6) //循环8次{value=value|0x80;}k++;}ircode[j]=value;}irprosok=1;}/******************************************************************** ********函数的功能是:将ircode【】中的二进制代码转换成为16进制代码便于在数码管上显示******************************************************************* ********/void irwork(){display[0]=ircode[0]/16;display[1]=ircode[0]%16;display[2]=ircode[1]/16;display[3]=ircode[1]%16;display[4]=ircode[2]/16;display[5]=ircode[2]%16;display[6]=ircode[3]/16;display[7]=ircode[3]%16;}/******************************************************************** ****函数功能:用数码管显示解码结果********************************************************************* ***/void display1(){uchar i;for(i=0;i<8;i++){P2=seg_we[i];P0=seg_du[display[i]];delay_50us(40);}}void main(){timer0init(); //定时器初始化int1init(); //外部中断初始化while(1){if(irreceok) //判断数据接收完毕(数组中存储的是高低电平的时间){irpros(); //执行处理函数,将高低电平时间转化成16进制的0,1代码,存放在数组中irreceok=0; //标志清零}if(irprosok) //处理函数执行完毕,{irwork(); //将存储的16进制代码分离,便于数码管显示irprosok=0; //标志清零}display1();}}//在最后我再分析一下程序的编写思路,便于大家理解,一旦有按键按下,接受管接收到引导码,进入外部中断,并将高低电平的时间放入irdata【】数组中,接受完毕标志位置一,判断接受标志位,为1,进行处理函数,将高低电平转换成16进制数,处理标志位置一,判断处理标志位,为1,执行分离函数,将16进制数分离,便于数码管显示,分离完毕后显示。
51单片机红外遥控解码,很详细(汇编语言,C语言等)
//i++;
if(TH0<3)
b=1;
else b=0;
TH0=0;
TL0=0;
}
uchar hw_key()
{
uchar j,m;
//i=0;
hw_start(); //等待低电平到来
hw_pulse();
for(j=0;j<24;j++) //测试用户码脉冲宽度
{
hw_pulse();
}
for(j=0;j<8;j++) //测试键码脉冲宽度
{
hw_pulse();
if(b==1)
m=(m<<1)|1;
else
m<<=1;
}
return m; //键码
}
while(in==0); //高电平到了,
TR0=0; //关闭定+;
TH0=0;
TL0=0;
TR0=1; //高电平到了,启动定时器1,测试高电平宽度
while(in==1); //低电平到了,
TR0=0; //关闭定时器1,高电平宽度测试完
请注意甄别内容中的联系方式诱导购买等信息谨防诈骗
51单片机红外遥控解码,很详细(汇编语言,C语言等)
单片机源程序如下:
#include
#define hw_hs0038_ENTITY
#include "hw_hs0038.h"
sbit in=P3^2;
//uchar i=0;
//uchar k[2];
bit bdata b=0;
/*
void timer0(void) interrupt 1 using 1
单片机的红外线解码程序
switch(inf_shuju)
{
case inf_code_0: inf_array[1]=30;
break;
case inf_code_1: inf_array[1]=1;
break;
case inf_code_2: infe inf_code_3: inf_array[1]=3;
TR1 = 1; //定时器1开始计数,由于晶振是24M
inf_shunxu++;
}
//#############################################################################
//函数名称:void inf_gongcuowu()
//功能:红外线错误子程序
break;
case inf_code_12: inf_array[1]=12;
break;
case inf_code_13: inf_array[1]=13;
break;
case inf_code_14: inf_array[1]=14;
break;
case inf_code_15: inf_array[1]=15;
//入口参数:无
//出口参数:无
//#############################################################################
void inf_gongcuowu(void)
{
inf_mode_cuowu = 1; //红外线接收出现错误
void T_1(void) interrupt 3 //参与红外线接收
{
TR1 = 0;
红外遥控器解码程序
//===================================================================== //// 红外遥控器解码程序演示//// 本程序主要将现在比较常用TX1300遥控器进行解码,将解码后的数据通过P2端////口的数码管显示出来,为了更好的看到运行过程,特加了三个指示灯用来指示当////前运行状态.P10主要用来闪亮,表示程序正在运行,P11则用来表示接收到数据, ////P12表示触发内部的定时器操作.P13的闪亮表示正确接收完一个数据. //// 程序运行效果: 打开本机电源开关,可以看到P10不停的闪动,按下遥控器的数////字键,数码管则显示相应的数字键(1-9).可以看到P11,P12在显示后呈亮状态.则////可以接收下一个数据,在上面过程中可以看到P13闪亮了一下.表明上次正确接收////到数据. ////---------------------------------------------------------------------//// 开发日期: 2009/01/30 研发单位:上海腾芯实业有限公司//#include <reg52.h> //包含51单片机相关的头文件#define uint unsigned int //重定义无符号整数类型#define uchar unsigned char //重定义无符号字符类型uchar code LedShowData[]={0x03,0x9F,0x25,0x0D,0x99, //定义数码管显示数据0x49,0x41,0x1F,0x01,0x19};//0,1,2,3,4,5,6,7,8,9uchar code RecvData[]={0x07,0x0A,0x1B,0x1F,0x0C,0x0D,0x0E,0x00,0x0F,0x19};uchar IRCOM[7];static unsigned int LedFlash; //定义闪动频率计数变量unsigned char RunFlag=0; //定义运行标志位bit EnableLight=0; //定义指示灯使能位/***********完成基本数据变量定义**************/sbit S1State=P1^0; //定义S1状态标志位sbit S2State=P1^1; //定义S2状态标志位sbit B1State=P1^2; //定义B1状态标志位sbit IRState=P1^3; //定义IR状态标志位sbit RunStopState=P1^4; //定义运行停止标志位sbit FontIRState=P1^5; //定义FontIR状态标志位sbit LeftIRState=P1^6; //定义LeftIR状态标志位sbit RightIRState=P1^7; //定义RightIRState状态标志位/*************完成状态指示灯定义*************/sbit S1=P3^2; //定义S1按键端口sbit S2=P3^4; //定义S2按键端口/*************完成按键端口的定义*************/sbit LeftLed=P2^0; //定义前方左侧指示灯端口sbit RightLed=P0^7; //定义前方右侧指示灯端口/*************完成前方指示灯端口定义*********/sbit LeftIR=P3^5; //定义前方左侧红外探头sbit RightIR=P3^6; //定义前主右侧红外探头sbit FontIR=P3^7; //定义正前方红外探头/*************完成红外探头端口定义***********/sbit M1A=P0^0; //定义电机1正向端口sbit M1B=P0^1; //定义电机1反向端口sbit M2A=P0^2; //定义电机2正向端口sbit M2B=P0^3; //定义电机2反向端口/*************完成电机端口定义***************/sbit B1=P0^4; //定义话筒传感器端口sbit RL1=P0^5; //定义光敏电阻端口sbit SB1=P0^6; //定义蜂鸣端口/*********完成话筒,光敏电阻,蜂鸣器.端口定义**/sbit IRIN=P3^3; //定义红外接收端口/*********完成红外接收端口的定义*************/#define ShowPort P2 //定义数码管显示端口extern void ControlCar(uchar CarType); //声明小车控制子程序void delayms(unsigned char x) //0.14mS延时程序{unsigned char i; //定义临时变量while(x--) //延时时间循环{for (i = 0; i<13; i++) {} //14mS延时}}void Delay() //定义延时子程序{ uint DelayTime=30000; //定义延时时间变量while(DelayTime--); //开始进行延时循环return; //子程序返回}void IR_IN() interrupt 2 using 0 //定义INT2外部中断函数{unsigned char j,k,N=0; //定义临时接收变量EX1 = 0; //关闭外部中断,防止再有信号到达delayms(15); //延时时间,进行红外消抖if (IRIN==1) //判断红外信号是否消失{EX1 =1; //外部中断开return; //返回}while (!IRIN) //等IR变为高电平,跳过9ms 的前导低电平信号。
红外遥控解码程序
1./*************************************************************************2.** 红外遥控器解码程序(采用中断)----基于SM0038接收芯片3.**说明:采用P2.0口中断,可通过修改IR_IN和P2来切换中断口的选择.4.**使用方法: 当IR_FLAG==1时,表示有键按下,全局变量IR_KeyValue是键号.5.** IR_KeyValueN--按键非码;IR_KeyValueSB--遥控器识别码6.** IR_UK--用户自定义的键号7.** 使用此模块时应先执行 IR_Init()8.**使用示例: if(IR_FLAG==1)9.** {10.** IR_FLAG=0;//每次使用时须将标志位清零.11.** Display_Int(IR_KeyValue,0x90);12.** }13.*************************************************************************/14.15.16.#include "ir_key.h"17.#include "delay.h"18./**********************以下是本程序中使用到的全局变量********************/19.unsigned char IR_BitCnt=0;20.unsigned char IR_KeyValue=10; //按键码(始值不能为按键号中包含的值)21.unsigned char IR_UK=0; //用户定义的键号22.unsigned char IR_KeyValueN=0; //按键非码;按键码+按键非码=0xff23.long int IR_KeyValueSB=0; //遥控器识别码.24.unsigned char IR_FLAG = 0; //有键按下时此标志为125.26./*****************************************************************************27.**此结构休是为键号转换用,IR_KV为遥控器本身的键号,IR_UK为用户自定义的按键号28.*****************************************************************************/29. struct IR_KEY30.{31. unsigned char IR_KV;//遥控器自身键码32. unsigned char IR_UV;//user's value33.};34./*****************************************************************************35.**通过修改结构体数组中的值来设定遥控器的键号.36.*******************************************************************************/37.struct IR_KEY IR_UserKEY[IR_NUM]=38.{39. {68,1},{71,2},{14,3},{72,4},{73,5},{81,6},{10,7},{80,8},{74,9},{83,10},40. {18,11},{84,12},{78,13},{75,14},{3,15},{21,16},{86,17},{67,18},{2,19},{76,20},41. {82,21},{79,22},{70,23},{77,24},{69,25},{6,26},{66,27},{65,28},{64,29},{22,30},42. {85,31},{23,32},{9,33},{13,34},{87,35},{15,36},{8,37},{25,38},{24,39},{11,40},43. {0,41},{4,42},{16,43},{19,44},{5,45},{1,46},{17,47},{95,48},{94,49},{30,50},{26,51}44.};45.46.47./*************************************************************************48.**函数名称: IR_DELAY49.**功能描述: 用于延时.50.**调用模块: delay.h51.**全局变量: 无52.****************************************************************************/53.void IR_DELAY(unsigned int delayTime)54.{55. DELAY(delayTime);//延时8MS56.}57.58.59./*************************************************************************60.**函数名称: IR_Init61.**功能描述: 端口初始化设置,在main函数里面应先执行此函数62.**输入变量:无63.**返回值:无64.**调用模块:无65.**全局变量: IR_IN66.****************************************************************************/67.void IR_Init(void)68.{69. P2DIR &=~IR_IN; //端口设置为输入方向70. P2IE |= IR_IN; //使能中断71. P2IES |= IR_IN; //下降沿中断72. P2IFG &=~IR_IN; //为避免程序运行后直接进中断,此处需先将中断标志位清零73. _EINT();74.}75.76.77./*************************************************************************78.**函数名称: IR_getkey79.**功能描述: 读取遥控器键值,包括识别码,非码80.**输入变量: 无81.**返回值: 无82.**调用模块: IR_DELAY();83.**全局变量: IR_Delay_8MS,IR_Delay8MS,IR_IN84.****************************************************************************/85.void IR_getkey(void)86.{87. P2IFG &=~IR_IN;88. P2IE &=~IR_IN;89. /**********以下是判断中断是由按键引起的***************/90. IR_DELAY(IR_Delay_8MS); //延时0.8MS91. if(P2IN & IR_IN) goto IR_NXT;92. IR_DELAY(IR_Delay8MS); //延时8MS93. if(!(P2IN & BIT0)) goto IR_NXT;94. while(!(P2IN & IR_IN));//等待变高95. IR_DELAY(8900); //延时5MS左右96. if(P2IN & IR_IN) goto IR_NXT;97. IR_FLAG = 0;98. /********以下是读取16位识别码*******************/99. IR_KeyValueSB=0;100. for(IR_BitCnt=0;IR_BitCnt<16;IR_BitCnt++)101. {102. while(!(P2IN & IR_IN));//WAIT HIGH103. IR_KeyValueSB >>=1;104. IR_DELAY(IR_Delay_8MS);105. if(P2IN & IR_IN)106. IR_KeyValueSB |=0x80;107. else108. IR_KeyValueSB &=0x7f;109. while(P2IN & IR_IN);//WAIT LOW110. }111. /***********以下是读取8位的键码*******************/ 112. IR_KeyValue=0;113. for(IR_BitCnt=0;IR_BitCnt<8;IR_BitCnt++)114. {115. while(!(P2IN & IR_IN));//WAIT HIGH116. IR_KeyValue >>=1;117. IR_DELAY(IR_Delay_8MS);118. if(P2IN & IR_IN)119. IR_KeyValue |=0x80;120. else121. IR_KeyValue &=0x7f;122. while(P2IN & IR_IN);//WAIT LOW123.124. }125. /************以下是读取8位的非码****************/ 126. IR_KeyValueN=0;127. for(IR_BitCnt=0;IR_BitCnt<8;IR_BitCnt++)128. {129. while(!(P2IN & IR_IN));//WAIT HIGH130. IR_KeyValueN >>=1;131. IR_DELAY(IR_Delay_8MS);132. if(P2IN & IR_IN)133. IR_KeyValueN |=0x80;134. else135. IR_KeyValueN &=0x7f;136. while(P2IN & IR_IN);//WAIT LOW137.138. }139. for(unsigned char i=0;i<20;i++)140. IR_DELAY(IR_Delay8MS);141.IR_NXT:P2IFG &=~IR_IN;142.P2IE |=IR_IN;143.144.IR_FLAG=1;145.}146.147.148./********************************************************* ****************149.**函数名称: IR_getUK150.**功能描述: 根据得到的IR_KeyValue从IR_UserKEY表中查出对应的用户自定义的键值151.**输入变量: 无152.**返回值: 无153.**调用模块: 无154.**全局变量: IR_BitCnt,IR_NUM,IR_UserKEY,IR_KeyValue,IR_UK155.********************************************************** ******************/156.void IR_getUK(void)157.{158.159. for(IR_BitCnt=0;IR_BitCnt<IR_NUM;IR_BITCNT++) pre < **** *************************************************************** ********** **以下是SM0038输入信号引脚的中断函数. *********************************************************** ***************** } IR_UK="IR_UserKEY[IR_BitCnt].IR_UV;" if(IR_ BitCnt="=IR_NUM)" return; { if(IR_KeyValue="=IR_UserKEY[IR_BitC nt].IR_KV)">160.<SCRIPT src="/inc/gg_read2.js"></SCRIPT>。
红外解码讲解
红外解码一直是单片机中应用较多的,需要设备加装专用解码芯片,这就大大减轻了单片机的负担。
需要单片机样例使用延时做红外解码,比较容易理解,但是由于在主程序中使用,当存在许多中断时就可能造成误码,很多时候误码率较高,成品中则一般使用中断方式。
下面通过TC9012和uPD6121芯片为例大致讲解解码原理:先看一些遥控器发射波形图从上图可以看出 4.5ms高电平+4.5ms低电平称为头码,用于识别是否遥控码开始,uPD6121的头码是9ms+4.5ms,其他的一样,一些datasheet会提及连续发射码的波形图(就是一直按下某一遥控器按键),这里我们不做分析,仅分析单次按键发射的正个码的波形图。
头码过后可以看到4个8位的数据,我们最终目的就是要把这个 32位(4x8)从一体化红外接收头提取出来,并转换成16进制数,用于区分不同按键按下得出的不同数值。
在遥控器发射波形中,可以看出,8位数中的0或者1不是用高低电平表示,而是用不同的低电平的宽度表示,0.565ms表示0,1.69ms表示1,2个位中间还会有一个0.56ms的高电平(上图阴影部分)。
这个是红外遥控器发射的波形,图中看到的阴影高电平表示载波,一般使用38KHz,遥控器发射出去的含有载波的红外信号通过一体化红外接收头处理后得到的是含有载波的反向的波形,也就是没有上图中的阴影部分。
大致如下图一体化红外接收头内部集成了选频放大(38KHz左右频率增益最大),检波(把38KHz的载波滤除),放大整形(变成容易检测的矩形波)。
看到如上图波形,表示单片机引脚可以接收到的波形,我们只要通过单片机读取波形并分析波形的宽度,然后分辨出是头码,还是0或者1,最后整理出这组码的16进制组合。
正确的解码结果是按同一个按键得出的16进制数值是不变化的。
通过这个原理,我们可以分辨出每个按键的键值。
mini80/mini80e样例程序中使用的红外解码程序,应用了外部中断,平时从书上或者网络上看到的解码一般是单纯解码,整个程序不做其他工作,这种方式可以使用普通io口,用延时等待的方法判断接收到的是高电平还是低电平,从而判断码值。
红外遥控解码程序
本文是对与以前发表的程序做个适当更改,因为在使用的过程中出现了一个问题,也就是在外部中断的处理函数里面处理欠妥。
在执行外部中断函数的时候,本意以定时器中断来代表解码超时,可实际情况是,即使解码超时,定时器产生溢出,但是程序却不能按照正常程序跳进定时器中断,执行定时中断函数,本以为是中断优先级的原因,但是在设置了定时器中断优先级为最高,也还是不能正常进入。
随后本人想到了解决办法,利用定时器0溢出标志TF0作为判断超时的依据,因为当TF0为1时,定时器向CUP申请中断,我们可以通过查询的方式,当TF0为1,则解码超时,退出解码。
此时不需要定时器中断函数,也可判断解码是否超时。
有人就说了,那我判断超时是否我可以定义变量,当变量超过一定数值时代表超时。
我想说,何必呢,本身定时器0溢出标志就是TF0,红外解码用到定时器,那不就刚好么,何必再去定义变量呢。
按照了解,通用的红外信号电平持续最长的时间是起始电平,一个9ms的低电平时间,定时器从0开始计时到溢出,如果是52单片机12M晶振速度,按照12分频,一个定时器脉冲时间是1us,溢出所需要的时间是65ms左右。
所以当定时器溢出,我们就不必等待,TF0作为停止解码的标志也只能用在这种速度比较低的单片机上,对于高速单片机,假如定时器溢出只需要2ms,那要是再使用TF0做判断,也就无意义了。
好了,废话不多说了。
注:主函数由读者自己编写,本程序只用于解码,最终得出的按键码存于变量Key_Temp 中。
本人习惯写某个器件的程序的时候,习惯创建.c和.h文件,因为这样方便移植,在新建的程序中只需添加.C文件和include .h文件就行了,很方便。
本人用芯片是STC15W4K32S4。
自己用这块芯片做有开发板,平时写程序都用它。
也可用一般的51单片机,但要注意定时器的时间和外部中断的端口。
本程序只适用NEC编码的解码,RC5编码请绕道。
以下是头文件信息:#ifndef __IR_H__#define __IR_H__sbit IR = P3^6;extern unsigned char Long_Press,Long_Press1; //长按计数,用作长按判断extern unsigned char Key_Temp; //保存按键变量void Init_IR(); //初始化红外有关参数#endif以下是.c文件:#include <STC15W.h>//也可以用reg52.h ,一般的编译器没有<STC15W.h>这个头文件,因为这是我个人添加进编译器里面的 #include "IR.h"#include "IR.h"/*******************************************************************时间计算:时间由定时器计的定时值来决定,本程序设定工作频率是24MHz,但定时器是12T模式。
(完整)简单的红外解码程序
简单的红外解码程序(不用中断)#ifndef __IR_H__#define __IR_H__#include <reg52.h>#include ”delay。
h"#define uchar unsigned char//8位#define uint unsigned int//16位sbit IR_IN=P3^2;//信号接收IR_JS();//无线接收程序#endif#include "IR.h”uchar data dat_IR[3]; //写缓存//==========红外接收程序=================IR_JS()//{uchar r1,r2,dat,dat1,dat2;if(IR_IN!=0){return 0;}//无信号退出delay_ms(1);if(IR_IN!=0){return 0;}//干扰退出r2=0;while(IR_IN ==0)//等高电平{delay_ms(1);r2++;}if(r2〈5){return 0;}//检测是否有同步头//delay_ms(4);//跳过同步码的高电平do{delay_100us(1);r2++;if(r2〉20){return 0;}}//防卡死while(IR_IN ==1);//开始解码for(r1=0;r1〈8;r1++)//接收8位数(系统码1){r2=0;while(IR_IN ==0);delay_100us(6);dat=dat<〈1;if(IR_IN ==1)dat=dat+1; //读数据位,接收的数据位放入retc中do{delay_100us(1);r2++;if(r2>20){return 0;}}//防卡死while(IR_IN ==1);}for(r1=0;r1〈8;r1++)//接收8位数(系统码2){r2=0;while(IR_IN ==0);delay_100us(6);//dat1=dat1<<1;if(IR_IN ==1)dat1=dat1+1; //读数据位,接收的数据位放入retc中 do{delay_100us(1);r2++;if(r2>20){return 0;}}//防卡死while(IR_IN ==1);}for(r1=0;r1〈8;r1++)//接收8位数(键值){r2=0;while(IR_IN ==0);delay_100us(6);//dat2=dat2<<1;if(IR_IN ==1)dat2=dat2+1; //读数据位,接收的数据位放入retc中 do{delay_100us(1);r2++;if(r2〉20){;return 0;}}//防卡死while(IR_IN ==1);}for(r1=0;r1<8;r1++)//接收8位数(键值反码){r2=0;while(IR_IN ==0);delay_100us(6);//dat=dat<〈1;if(IR_IN ==1)dat=dat+1; //读数据位,接收的数据位放入retc中 do{delay_100us(1);r2++;if(r2〉20){return 0;}}//防卡死while(IR_IN ==1);}//接收完32位数据if(dat2!= ~dat){return 0;}//检测键值和键值反码,出错退出//解码完成,保存数据dat_IR[0]=dat;dat_IR[1]=dat1;dat_IR[2]=dat2;//P2显示数据P2=dat2;delay_ms(1000);//显示一秒P2=0xFF;return 1; //解码成功}。
红外解码完全解析
1、红外遥控系统通用红外遥控系统由发射和接收两大部分组成,应用编/解码专用集成电路芯片来进行控制操作,如图1所示。
发射部分包括键盘矩阵、编码调制、LED红外发送器;接收部分包括光、电转换放大器、解调、解码电路。
下面,我们将使用下面两种设备:另外,使用51单片机进行解码。
2、原理图从原理图看出,IR的data脚与51的PD2(P3.2)相连。
2、红外发射原理要对红外遥控器所发的信号进行解码,必须先理解这些信号。
a) 波形首先来看看,当我们按下遥控器时,红外发射器是发送了一个什么样的信号波形,如下图:由上图所示,当一个键按下超过22ms,振荡器使芯片激活,将发射一组108ms的编码脉冲(由位置1所示)。
如果键按下超过108ms仍未松开,接下来发射的代码(连发代码由位置3所示)将仅由起始码(9ms)和结束码(2.5ms)组成。
下面把位置1的波形放大:由位置1的波形得知,这108ms发射代码由一个起始码(9ms),一个结果码(4.5ms),低8位地址码(用户编码)(9ms~18ms),高8位地址码(用户编码)(9ms~18ms),8位数据码(键值数据码)(9ms~18ms)和这8位数据的反码(键值数据码反码)(9ms~18ms)组成。
b) 编码格式遥控器发射的信号由一串0和1的二进制代码组成.不同的芯片对0和1的编码有所不同。
通常有曼彻斯特编码和脉冲宽度编码。
XS-091遥控板的0和1采用PWM方法编码,即脉冲宽度调制。
下图为一个发射波形对应的编码方法:放大0和1的波形如下图:这种编码具有以下特征:以脉宽为0.565ms、间隔0.56ms、周期为1.125ms的组合表示二进制的“0”;以脉宽为0.565ms、间隔1.685ms、周期为2.25ms的组合表示二进制的“1”。
3、红外接收原理a) 波形红外接收头将38K载波信号过虑,接收到的波形刚好与发射波形相反:放大,位定义0和位定义1波形如下:4、解码原理及算法注:代码宽度算法:16位地址码的最短宽度:1.12×16=18ms 16位地址码的最长宽度:2.24ms×16=36ms可以得知8位数据代码及其8位反代码的宽度和不变:(1.12ms+2.24ms)×8=27ms所有32位代码的宽度为(18ms+27ms)~(36ms+27ms)对于红外线遥控对于很多电子爱好者来讲,都感觉到非常神奇,看不到,摸不着,但能实现无线遥控,其实控制的关键就是我们要用单片机芯片来识别红外线遥控器发出红外光信号,即我们通常所说的解码。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
红外遥控解码程序设计——————基于uPD6121红外编码制式红外传感系统是目前应用最为广泛的遥控系统,一个红外遥控系统可分为发射和接收两部分组成,发射端称之为红外遥控器,一般由矩阵键盘,红外编码调制芯片和红外发射管组成;接收端用一体化红外接收头即可,这个东东内置光电放大器和解调部分,信号接收之后一般很微弱须放大后才可解码,为有效发射出去得先托付在载波上所以需经历调制、解调的过程,其实对于发射部分主要工作在于编码,而对于编码方式只有几种主流方式,而目前国内大部分均为uPD6121编码方式(日本NEC公司搞出来的。
),所以我们只须弄清楚这种编码的时序,即可写出万能的红外解码程序,只要是基于这种编码方式的遥控器(家里的电视、空调、电扇遥控器)都可以用该程序来解码(这点也充分证明了C语言的高移植性啊。
)这种编码的格式其实很简单,开头是一个引导码,人家芯片在编码时将其设计成9ms的高电平和4.5ms的低电平,也就是说你必须跳过这段引导码之后才会接收到数据,第一个问题来了:为什么要加这段引导码?因为红外传感是非常容易受到干扰的,如果直接传送数据很可能并非发送端的信号,很可能来自其他辐射,后面设计程序时会遇到这个问题。
所以我们在写程序时在引导码时可以加入检测代码,如果是引导码则继续接收,否则跳出。
第二个问题就是:接收数据时我们用外部中断接收,这是考虑到CPU 的执行效率,如果你在主函数里接收数据,就好比CPU一直在问:你接收到数据没?你接收到没?..很明显不靠谱,和串口通信一样,接收数据用中断这是经验,有利于单片机的执行效率。
第三个要注意的就是红外接收端和编码发送的数据是反向的!这点很重要,我看很多资料没有写明这点,让很多童鞋疑惑不解,也就是说引导码编码时确实是9ms高电平和4.5ms 的低电平,但是到了接收端是9ms的低电平和4.5ms的高电平,所以我们在解码时就得注意引导码高电平出现的顺序。
对于编码格式,引导码后接了4个字节的数据,前两个字节为用户码和用户反码,简单点说就是器件地址;后两字节为操作码和操作反码,就是我们真正需要的数据。
图为发送端编码格式,注意接收到的已反向!说到这里,可能会想到既然第三个字节才是我们真正的操作数据,那么我设置一个4字节数组ircode[4] 把四字节数据依次装进去,那么ircode[2]就是数据码,ircode[3]就是其反码,这样我们可以通过判断ircode[2]是否等于ircode[3]的求反?如果是,则说明接收的数据是对的!这样可以作为接收是否正确的检测代码。
最关键的问题来了:如何判断接收的是‘1’还是‘0’? uPD6121编码中说明:一个逻辑单位前0.565ms 为低电平,接着为高电平,如果高电平持续时间为0.565Ms则说明为逻辑‘1’,如果高电平持续超过0.565ms 则说明为逻辑‘0’(接收端反向后的结果,实际编码时相反)。
图为编码格式,解码应反向。
所以理清红外解码的整体流程如下:跳过引导码9ms————跳过引导码4.5ms——循环接收四字节数据(每个字节八位,每位都须判断高还是低电平)好了,思路有了,开始写程序,代码如下:#include<reg52.h>#include"delay.h"#include"lcd.h"#define uint unsigned int#define uchar unsigned charsbit irin=P3^2;sbit BEEP=P1^5;sbit lcdrw=P2^5;sbit lcdrs=P2^6;sbit lcden=P2^7;uchar ircode[4];uchar send_da;uchar table[]="IR_test:";uint k,i,j;void ir_ini();void write_da(uchar da);void write_comd(uchar comd);void beep();void delay(unsigned char x) //x*0.14MS{unsigned char i;while(x--){for (i = 0; i<13; i++) {;}}}void main(){uint i;ir_ini();serial_ini();lcd_ini();for(i=0;i<8;i++){write_da(table[i]);msdelay(1);}while(1);}void ir_ini(){EA=1;EX0=1;IT0=1;}void ir() interrupt 0{EX0=0; //关闭外部中断while(!irin) //跳过9ms低电平{delay(1);}while(irin) //跳过4.5ms高电平{delay(1);}for(i=0;i<4;i++) //4个字节的数据,前16位为用户码和其反码,后16位为操作码和其反码{for(j=0;j<8;j++) //每字节八位{while(!irin); //等待irin出现高电平msdelay(1); //短暂延时一下再判断if(irin) //irin为logic '1'{msdelay(1);ircode[i]>>=1; //右移,高位补零ircode[i]|=0x80; //最高位置位}else if(!irin) //irin为logic '0'{ircode[i]>>=1; //右移,高位补零ircode[i]&=0x7f;}}EX0=1;打开外部中断}程序写到这里,发现还没有程序能说明是否收到了数据。
于是我们加入串口通信代码,把接收到的数据发送给PC机,在调试助手上观察那四个字节的数据到底是什么东东,这样我才能知道遥控器上每个按键对应的操作码是多少,才能进行后续按键功能的设置。
串口通信初始化函数:void serial_ini(){TMOD=0x20;TH1=0xe6; //1200bpsTL1=0xe6;SM0=0;SM1=1;REN=1;TR1=1;}串口发送数据函数:for(i=0;i<4;i++){send_da=ircode[i];SBUF=send_da;while(!TI);TI=0;}加入后我们编译下载到单片机,然后打开串口调试助手观察:发现每按一个键,电脑上接收了4个字节的16进制数据,这说明确实接收成功了!因为编码格式就是一次红外发射数据中包含4个字节的数据,第三个位操作码!所以我们把每个操作码对应的十六进制数记录下来就知道这个遥控器按键在设计时对应的操作码是多少了。
(用串口的方式发送数据到电脑显示是我想到的一个方法,当然也可以发送到数码管或LCD显示,目的都是为了找到你的遥控器对应按键的操作码)从上面可以发现四个字节数据对应的第三个分别是0x45,0x46,0x47,0x44,0x40.。
(注意勾上hex选项,意思是以16进制显示)这样就好办了,我每个按键都对应一个操作码,如果我用一个选择语句,岂不是就可以让它们执行对应的功能吧,太好了,为了简单,我们现在只让他们对应显示在LCD上(知道方法后可以让它们实现你想要的功能),于是加入“lcd.h”头文件,这是我写好的LCD文件,包括其初始化,写指令和写数据函数,这些代码我在以前的日志已经写过,现在只是将其封装在一个头文件里,方便调用(详见“C51模块化编程方法”)我的遥控器上一共21个键,用两个数组建两个按键表,其实只是取了个名字,方便LCD显示:uchar code jianma2[]="0 /1 /2 /3 /4 /5 /6 /7 /8 /9 ";uchar code jianma1[]="switch/mode /quiet /start /< /> /eq /vol- /vol+ /rpt /u/sd ";然后加入选择结构,让不同按键在LCD显示出对应的按键名称。
switch(ircode[2]){ // 显示遥控上的字符按键case 0x45:write_comd(0x80+0x48); //移动数据指针for(i=0;i<=5;i++)write_da(jianma1[i]); //写入数据显示break;case 0x46:write_comd(0x80+0x48);for(i=7;i<=12;i++)write_da(jianma1[i]);break;case 0x47:write_comd(0x80+0x48);for(i=14;i<=19;i++)write_da(jianma1[i]);break;case 0x44:write_comd(0x80+0x48);for(i=21;i<=26;i++)write_da(jianma1[i]);break;case 0x40:write_comd(0x80+0x48);for(i=28;i<=33;i++)write_da(jianma1[i]);break;case 0x43:write_comd(0x80+0x48);for(i=35;i<=40;i++)write_da(jianma1[i]);break;case 0x07:write_comd(0x80+0x48);for(i=42;i<=47;i++)write_da(jianma1[i]);break;case 0x15:write_comd(0x80+0x48);for(i=49;i<=54;i++)write_da(jianma1[i]);break;case 0x09:write_comd(0x80+0x48);for(i=56;i<=61;i++)write_da(jianma1[i]);break;case 0x19:write_comd(0x80+0x48);for(i=63;i<=68;i++)write_da(jianma1[i]);break;case 0x0d:write_comd(0x80+0x48);write_da(jianma1[i]);break;case 0x16: //显示遥控上得数字write_comd(0x80+0x48);for(i=0;i<=5;i++)write_da(jianma2[i]);break;case 0x0c:write_comd(0x80+0x48);for(i=7;i<=12;i++)write_da(jianma2[i]);break;case 0x18:write_comd(0x80+0x48);for(i=14;i<=19;i++)write_da(jianma2[i]);break;case 0x5e:write_comd(0x80+0x48);for(i=21;i<=26;i++)write_da(jianma2[i]);break;case 0x08:write_comd(0x80+0x48);write_da(jianma2[i]);break;case 0x1c:write_comd(0x80+0x48);for(i=35;i<=40;i++)write_da(jianma2[i]);break;case 0x5a:write_comd(0x80+0x48);for(i=42;i<=47;i++)write_da(jianma2[i]);break;case 0x42:write_comd(0x80+0x48);for(i=49;i<=54;i++)write_da(jianma2[i]);break;case 0x52:write_comd(0x80+0x48);write_da(jianma2[i]);break;case 0x4a:write_comd(0x80+0x48);for(i=63;i<=68;i++)write_da(jianma2[i]);break;}到这里红外解码后的效果就可以在LCD上看到了,我们这里都只是让各个按键显示应的名字,如果想让某个按键实现某种特定功能也非常方便了,比如按下第三个键(对应操作码0x47)时想让蜂鸣器发声只须将一个case分支改成蜂鸣器发声函数就可以了!似乎代码写到这里我们已经成功了大半,但是实际测试时会发现一个非常重要的问题,抗干扰能力!几乎我一上电复位它就会接收到数据,其实是假码,甚至我电脑开个机都能影响到它(- -.) ,因为这些设备在启动或关闭时都会辐射一定的红外线,而我们的红外接收头又是相当灵敏,所以必然被干扰信号扰乱。