红外线遥控是目前使用最广泛的一种通信和遥控手段。由于红外线遥控装置具有体积小、功耗低、功能强、成本低等特点,因而,继彩电、录像机之后,在录音机、音响设备、空凋机以及玩具等其它小型电器装置上也纷纷采用红外线遥控。工业设备中,在高压、辐射、有毒气体、粉尘等环境下,采用红外线遥控不仅完全可靠而且能有效地隔离电气干扰。
1 红外遥控系统
通用红外遥控系统由发射和接收两大部分组成,应用编/解码专用集成电路芯片来进行控制操作,如图1所示。发射部分包括键盘矩阵、编码调制、LED红外发送器;接收部分包括光、电转换放大器、解调、解码电路。

2 遥控发射器及其编码
遥控发射器专用芯片很多,根据编码格式可以分成两大类,这里我们以运用比较广泛,解码比较容易的一类来加以说明,现以日本NEC的uPD6121G组成发射电路为例说明编码原理。当发射器按键按下后,即有遥控码发出,所按的键不同遥控编码也不同。这种遥控码具有以下特征:
采用脉宽调制的串行码,以脉宽为0.565ms、间隔0.56ms、周期为1.125ms的组合表示二进制的“0”;以脉宽为0.565ms、间隔1.685ms、周期为2.25ms的组合表示二进制的“1”,其波形如图2所示。

上述“0”和“1”组成的32位二进制码经38kHz的载频进行二次调制以提高发射效率,达到降低电源功耗的目的。然后再通过红外发射二极管产生红外线向空间发射,如图3所示。

UPD6121G产生的遥控编码是连续的32位二进制码组,其中前16位为用户识别码,能区别不同的电器设备,防止不同机种遥控码互相干扰。该芯片的用户识别码固定为十六进制01H;后16位为8位操作码(功能码)及其反码。UPD6121G最多额128种不同组合的编码。
遥控器在按键按下后,周期性地发出同一种32位二进制码,周期约为108ms。一组码本身的持续时间随它包含的二进制“0”和“1”的个数不同而不同,大约在45~63ms之间,图4为发射波形图。
当一个键按下超过36ms,振荡器使芯片激活,将发射一组108ms的编码脉冲,这108ms发射代码由一个起始码(9ms),一个结果码(4.5ms),低8位地址码(9ms~18ms),高8位地址码(9ms~18ms),8位数据码(9ms~18ms)和这8位数据的反码(9ms~18ms)组成。如果键按下超过108ms仍未松开,接下来发射的代码(连发代码)将仅由起始码(9ms)和结束码(2.5ms)组成。
代码格式(以接收代码为准,接收代码与发射代码反向)
①位定义 
 
 
 
           
②单发代码格式 
 
        
③连发代码格式 

注:代码宽度算法:
16位地址码的最短宽度:1.12×16=18ms 16位地址码的最长宽度:2.24ms×16=36ms 
易知8位数据代码及其8位反代码的宽度和不变:(1.12ms+2.24ms)×8=27ms
∴32位代码的宽度为(18ms+27ms)~(36ms+27ms)
1. 解码的关键是如何识别“0”和“1”,从位的定义我们可以发现“0”、“1”均以0.56ms的低电平开始,不同的是高电平的宽度不同,“0”为0.56ms,“1”为1.68ms,所以必须根据高电平的宽度区别“0”和“1”。如果从0.56ms低电平过后,开始延时,0.56ms以后,若读到的电平为低,说明该位为“0”,反之则为“1”,为了可靠起见,延时必须比0.56ms长些,但又不能超过1.12ms,否则如果该位为“0”,读到的已是下一位的高电平,因此取(1.12ms+0.56ms)/2=0.84ms最为可靠,一般取0.84ms左右均可。
2. 根据码的格式,应该等待9ms的起始码和4.5ms的结果码完成后才能读码。
 
如果邮购我们开发的51单片机试验板和扩展元件的网友,可以获得如上图所示的红外遥控手柄,这种遥控器的编码格式符合上面的描述规律,而且价格低廉,有32个按键,按键外形比较统一,如果用于批量开发,可以把遥控器上贴膜换成你需要的字符,这为开发产品提供了便利。
接收器及解码
一体化红外线接收器是一种集红外线接收和放大于一体,不需要任何外接元件,就能完成从红外线接收到输出与TTL电平信号兼容的所有工作,而体积和普通的塑封三极管大小一样,它适合于各种红外线遥控和红外线数据传输。
下面是一个对51实验板配套的红外线遥控器的解码程序,它可以把上图32键的红外遥控器每一个按键的键值读出来,并且通过实验板上P1口的8个LED显示出来,在解码成功的同时并且能发出“嘀嘀嘀”的提示音。
| 红外遥控器软件解码原理及程序 
 红外一开始发送一段13.5ms的引导码,引导码由9ms的高电平和4.5ms的低电平组成,跟着引导码是系统码,系统反码,按键码,按键反码,如果按着键不放,则遥控器则发送一段重复码,重复码由9ms的高电平,2.25ms的低电平,跟着是一个短脉冲,本程序经过试用,能解大部分遥控器的编码!
 
 #include "at89x52.h"
 #define NULL 0x00//数据无效
 #define RESET 0X01//程序复位
 #define REQUEST 0X02//请求信号
 #define ACK 0x03//应答信号,在接收数据后发送ACK信号表示数据接收正确,也位请求信号的应答信号
 #define NACK 0x04//应答信号,表示接收数据错误
 #define BUSY 0x05//忙信号,表示正在忙
 #define FREE 0x06//空闲信号,表示处于空闲状态
 #define READ_IR 0x0b//读取红外
 #define STORE_IR 0x0c//保存数据
 #define READ_KEY 0x0d//读取键值
 #define RECEIVE 0Xf400//接收缓冲开始地址
 #define SEND 0xfa00//发送缓冲开始地址
 #define IR 0x50//红外接收缓冲开始地址
 #define HEAD 0xaa//数据帧头
 #define TAIL 0x55//数据帧尾
 #define SDA P1_7
 #define SCL P1_6
 
 
 
 unsigned char xdata *buf1; //接受数据缓冲
 unsigned int buf1_length; //接收到的数据实际长度
 unsigned char xdata *buf2; //发送数据缓冲
 unsigned int buf2_length; //要发送的数据实际长度
 bit buf1_flag; //接收标志,1表示接受到一个数据帧,0表示没有接受到数据帧或数据帧为空
 bit buf2_flag; //发送标志,1表示需要发送或没发送完毕,0表示没有要发送的数据或发送完毕
 unsigned char state1,state2; //用来标志接收字符的状态,state1用来表示接收状态,state2用来表示发送状态
 unsigned char data *ir;
 union{
 unsigned char a[2];
 unsigned int b;
 unsigned char data *p1[2];
 unsigned int data *p2[2];
 unsigned char xdata *p3; //红外缓冲的指针
 unsigned int xdata *p4;
 }p;
 //union{ //
 // unsigned char a[2]; //
 // unsigned int b;
 // unsigned char data *p1[2];
 // unsigned int data *p2[2];
 // unsigned char xdata *p3;
 // unsigned int xdata *p4; //地址指针
 //}q; //
 
 union{
 unsigned char a[2];
 unsigned int b;
 }count;
 union{
 unsigned char a[2];
 unsigned int b;
 }temp;
 union{
 unsigned char a[4];
 unsigned int b[2];
 unsigned long c;
 }ir_code;
 
 union{
 unsigned char a[4];
 unsigned int b[2];
 unsigned long c;
 unsigned char data *p1[4];
 unsigned int data *p2[4];
 unsigned char xdata *p3[2];
 unsigned int xdata *p4[2];
 }i;
 unsigned char ir_key;
 bit ir_flag; //红外接收标志,0为缓冲区空,1为接收成功,2为缓冲溢出
 void sub(void);
 void delay(void);
 void ie_0(void);
 void tf_0(void);
 void ie_1(void);
 void tf_1(void);
 void tf_2(void);
 void read_ir(void);
 void ir_jiema(void);
 void ir_init(void);
 void ir_exit(void);
 void store_ir(void);
 void read_key(void);
 void reset_iic(void);
 unsigned char read_byte_ack_iic(void);
 unsigned char read_byte_nack_iic(void);
 bit write_byte_iic(unsigned char a);
 void send_ack_iic(void);
 void send_nack_iic(void);
 bit receive_ack_iic(void);
 void start_iic(void);
 void stop_iic(void);
 void write_key_data(unsigned char a);
 unsigned int read_key_data(unsigned char a);
 void ie0(void) interrupt 0{ie_0();}
 void tf0(void) interrupt 1{tf_0();}
 void ie1(void) interrupt 2{ie_1();}
 void tf1(void) interrupt 3{tf_1();tf_2();}
 void tf2(void) interrupt 5{ //采用中断方式跟查询方式相结合的办法解码
 EA=0; //禁止中断
 if(TF2){ //判断是否是溢出还是电平变化产生的中断
 TF2=0; //如果是溢出产生的中断则清除溢出位,重新开放中断退出
 EA=1;
 goto end;
 }
 EXF2=0; //清除电平变化产生的中断位
 *ir=RCAP2H; //把捕捉的数保存起来
 ir++;
 *ir=RCAP2L;
 *ir++;
 F0=1;
 TR0=1; //开启计数器0
 loop:
 TL0=0; //将计数器0重新置为零
 TH0=0;
 while(!EXF2){ //查询等待EXF2变为1
 if(TF0)goto exit; //检查有没超时,如果超时则退出
 };
 EXF2=0; //将EXF2清零
 if(!TH0) //判断是否是长低电平脉冲过来了
 { //不是长低电平脉冲而是短低电平
 if(F0)count.b++; //短脉冲数加一
 temp.a[0]=RCAP2H; //将捕捉数临时存放起来
 temp.a[1]=RCAP2L;
 goto loop; //返回继续查询
 }
 else{ //是低电平脉冲,则进行处理
 
 F0=0;
 *ir=temp.a[0]; //把连续的短脉冲总时间记录下来
 ir++;
 *ir=temp.a[1];
 ir++;
 *ir=RCAP2H; //把长电平脉冲时间记录下来
 ir++;
 *ir=RCAP2L;
 ir++;
 if(ir>=0xda) {
 goto exit; //判断是否溢出缓冲,如果溢出则失败退出
 }
 goto loop; //返回继续查询
 }
 exit:
 ir_flag=1; //置ir_flag为1表示接收成功
 end:
 ;
 }
 
 
 void rs232(void) interrupt 4{
 static unsigned char sbuf1,sbuf2,rsbuf1,rsbuf2; //sbuf1,sbuf2用来接收发送临时用,rsbuf1,rsbuf2用来分别用来存放接收发送的半字节
 EA=0; //禁止中断
 if(RI){
 RI=0; //清除接收中断标志位
 sbuf1=SBUF; //将接收缓冲的字符复制到sbuf1
 if(sbuf1==HEAD){ //判断是否帧开头
 state1=10; //是则把state赋值为10
 buf1=RECEIVE; //初始化接收地址
 }
 else{
 switch(state1){
 case 10:sbuf2=sbuf1>>4; //把高半字节右移到的半字节
 sbuf2=~sbuf2; //把低半字节取反
 if((sbuf2&0x0f)!=(sbuf1&0x0f)) //判断接收是否正确
 { //接收错误,有可能接收的是数据帧尾,也有可能是接收错误
 if(sbuf1==TAIL) //判断是否接收到数据帧尾
 { //是接收到数据帧尾
 buf1=RECEIVE; //初始化接收的地址
 if(*buf1==RESET) //判断是否为复位命令
 {
 ES=0;
 sbuf2=SP+1;
 for(p.p1[0]=SP-0x10;p.p1[0]<=sbuf2;p.p1[0]++)*p.p1[0]=0;
 }
 state1=0; //将接收状态标志置为零,接收下一个数据帧
 buf1_flag=1; //置接收标志为1,表示已经接收到一个数据帧
 REN=0; //禁止接收
 }
 else
 { //不是接受到数据帧尾,表明接收错误
 state1=0; // 将接收状态标志置为零,重新接收
 buf1=RECEIVE; //初始化发送的地址
 *buf1=NACK; //把NACK信号存入接收缓冲里
 buf1_flag=1; //置标志位为1,使主程序能对接收错误进行处理
 REN=0; //禁止接收
 }
 
 }
 else
 { //接收正确
 rsbuf1=~sbuf1; //按位取反,使高半字节变原码
 rsbuf1&=0xf0; //仅保留高半字节,低半字节去掉
 state1=20; //将状态标志置为20,准备接收低半字节
 }
 break;
 case 20:sbuf2=sbuf1>>4; //把高半字节右移到的半字节
 sbuf2=~sbuf2; //将低半字节取反
 if((sbuf2&0x0f)!=(sbuf1&0x0f)) //判断接收是否正确
 { //接受错误
 state1=0; // 将接收状态标志置为零,重新接收
 buf1=RECEIVE; //初始化接收的地址
 *buf1=NACK; //把NACK信号存入发送缓冲里
 buf1_flag=1; //置标志位为1,使主程序能对接收错误进行处理
 REN=0; //禁止接收
 }
 else
 {
 sbuf1&=0x0f; //仅保留低半字节,去掉高半字节
 rsbuf1|=sbuf1; //高低半字节合并
 *buf1++=rsbuf1; //将接收的数据保存至接收缓冲里,并且数据指针加一
 buf1_length++; //接收数据长度加一
 state1=10; //将state1置为10,准备接收下个字节的高半字节
 }
 break;
 
 }
 }
 
 
 
 }
 else{
 
 TI=0; //清除发送中断标志
 if(buf2_length) //判断发送长度是否为零
 { //发送长度不为零
 if(state2==0) //判断是否发送高半字节
 { //发送高半字节
 sbuf2=*buf2; //将要发送的字节送到sbuf2
 rsbuf2=~sbuf2; //取反,使高半字节变为反码
 sbuf2>>=4; //将高半字节右移到低半字节
 rsbuf2&=0xf0; //保留高半字节,去掉低半字节
 sbuf2&=0x0f; //保留低半字节,去掉高半字节
 rsbuf2|=sbuf2; //合并高低半字节
 SBUF=rsbuf2; //发送出去
 state2=10; //将state2置为10准备发送下半字节
 }
 else
 { //发送低半字节
 sbuf2=*buf2; //将要发送的字节送到sbuf2
 buf2++; //指针加一
 buf2_length--; //发送数据长度减一
 rsbuf2=~sbuf2; //取反,使低半字节变为反码
 rsbuf2<<=4; //将低半字节反码左移到高半字节
 rsbuf2&=0xf0; //保留高半字节,去掉低半字节
 sbuf2&=0x0f; //保留低半字节,去掉高半字节
 rsbuf2|=sbuf2; //合并高低半字节
 SBUF=rsbuf2; //发送出
 state2=0;
 }
 }
 else
 { //如果发送数据长度为零则发送数据帧尾
 if(buf2_flag){ //判断是否发过数据帧尾
 SBUF=TAIL; //将数据帧尾发送出去
 while(TI==0);
 TI=0;
 buf2_flag=0; //置发送标志为零,表示发送完毕
 }
 }
 }
 EA=1; //开放中断
 }
 
 
 
 
 
 
 void ack(void) //发送ACK信号子程序
 {
 buf1_flag=0; //置接收标志位位零表示已经相应了,可以接收下一帧数据
 REN=1; //接收使能
 while(buf2_flag); //判断上一帧有没发送完,没有则继续等待
 buf2=SEND; //初始化发送地址
 *buf2=ACK; //将ACK信号存入发送缓冲里
 buf2_length=1; //存入发送数据长度
 buf2_flag=1; //置发送长度为1
 SBUF=HEAD; //发送数据帧头
 }
 
 void nack(void) //发送NACK信号子程序
 {
 buf1_flag=0; //置接收标志位位零表示已经相应了,可以接收下一帧数据
 REN=1; //接收使能
 while(buf2_flag); //判断上一帧有没发送完,没有则继续等待
 buf2=SEND; //初始化发送地址
 *buf2=NACK; //将NACK信号存入发送缓冲里
 buf2_length=1; //存入发送数据长度
 buf2_flag=1; //置发送长度为1
 SBUF=HEAD; //发送数据帧头
 }
 
 void free(void) //发送FREE信号子程序
 {
 buf1_flag=0; //置接收标志位位零表示已经相应了,可以接收下一帧数据
 REN=1; //接收使能
 while(buf2_flag); //判断上一帧有没发送完,没有则继续等待
 buf2=SEND; //初始化发送地址
 *buf2=FREE; //将FREE信号存入发送缓冲里
 buf2_length=1; //存入发送数据长度
 buf2_flag=1; //置发送长度为1
 SBUF=HEAD; //发送数据帧头
 }
 
 void busy(void) //发送BUSY信号子程序
 {
 buf1_flag=0; //置接收标志位位零表示已经相应了,可以接收下一帧数据
 REN=1; //接收使能
 while(buf2_flag); //判断上一帧有没发送完,没有则继续等待
 buf2=SEND; //初始化发送地址
 *buf2=BUSY; //将BUSY信号存入发送缓冲里
 buf2_length=1; //存入发送数据长度
 buf2_flag=1; //置发送长度为1
 SBUF=HEAD; //发送数据帧头
 }
 
 void download(void)
 {
 int i; //用于循环计数
 i=buf1_length-3; //数据长度等于数据包长度减去一个字节控制字和两个字节地址
 buf1=RECEIVE+1; //使指针指向地址
 p.a[0]=*buf1++; //读入目标地址高字节
 p.a[1]=*buf1++; //读入目标地址低字节
 while(i--){ //长度减一直至为零
 *p.p3++=*buf1++; //将接受缓冲里数据送到目标地址,并且两个指针加一
 }
 REN=1; //数据处理完,允许接收下一帧数据
 buf1_flag=0; //置接收标志为零,表示已经处理完
 free(); //发送FREE信号表示已经处理完处于空闲状态
 
 }
 
 void upload(void){
 int i; //
 while(buf2_flag); //判断上一帧有没发送完,没有则继续等待
 buf1=RECEIVE+1; //将指针指向地址
 buf2=SEND; //初始化发送地址
 *buf2++=UPLOAD; //把控制字存进去并且指针加一
 *buf2++=*buf1++; //把地址高字节复制过去
 *buf2++=*buf1++; //把地址低字节复制过去
 p.a[0]=*buf1++; //把数据长度高字节复制过去
 p.a[1]=*buf1++; //把数据长度低字节复制过去
 i=p.b; //把数据长度复制过去
 buf1-=4; //将指针减4,使其指向地址处
 p.a[0]=*buf1++; //把地址高字节复制过去
 p.a[1]=*buf1++; //把地址低字节复制过去
 buf1_flag=0; //已经对接受数据处理完毕
 REN=1; //允许接收
 buf2_length=i+3; //数据包长度等于数据长度加3
 while(i--){ //判断数据长度是否为零,为零则不执行循环语句,同时长度减一
 *buf2++=*p.p3++; //把数据复制到发送缓冲区
 }
 buf2=SEND;
 buf2_flag=1; //置发送标志为1
 SBUF=HEAD; //发送数据帧头
 }
 
 void run(void) //运行下载的程序
 {
 sub();
 }
 
 
 
 void delay1s(void){
 for(i.b[0]=0;i.b[0]<0xffff;i.b[0]++){
 i.b[0]=i.b[0]++;
 i.b[0]=i.b[0]--;}
 }
 
 void ir_init(void)
 {
 ir_flag=0; //将红外接收标志置为零
 for(ir=IR;ir<0xe0;ir++){
 *ir=0; //将红外接收缓冲清零
 }
 EA=0; //禁止中断
 ES=0; //禁止串行中断
 ET2=1; //允许T2中断
 ir=IR; //初始化红外数据指针
 TR0=0; //禁止计数
 TH0=0; //将计数器置为0
 TL0=0;
 TF0=0; //清除溢出标志
 count.b=1; //初始化为零
 
 
 init:
 TR2=0;
 TL2=0x00;
 TH2=0xdc; //给T2赋一个初值,当计数器溢出时正好为6毫秒
 T2CON=0x0d; //EXEN2=1,TR2=1,C/T2=0,CP/RL2=1,工作于捕捉方式
 while(!TF2); //查询计数器是否溢出
 TF2=0; //清除溢出位
 if(EXF2) //判断在此期间又没发生过电平变化
 { //如果发生过变化则重新计数
 goto init; //等待下一次按键
 }
 else
 { //计数器溢出并且电平没有发生过变化,则开启中断开始解码
 EA=1;
 }
 
 }
 
 void ir_exit(void) //红外接收恢复程序,恢复到红外接收前的状态
 {
 TR2=0; //停止计数以便修改计数器2寄存器
 TR0=0;
 ET2=0; //禁止计数器2中断
 TL2=0xfb; //重新设置波特率为115.2kbps
 TH2=0xff;
 RCAP2H=0xff;
 RCAP2L=0xfb;
 T2CON=0x34;
 ES=1; //允许串行中断
 EA=1; //开放全局中断
 }
 
 
 void ir_jiema(void){ //解码程序,放在ir_code中,高十六位表示接收频率
 //如果解码失败则为,如果是重复码则为1
 //低八位表示载波频率,以KHz为单位
 //低十六位的高八位表示系统码,低八位为按键码
 p.p2[0]=IR;
 p.p2[1]=p.p2[0]+1;
 i.b[0]=*p.p2[0];
 i.b[1]=*p.p2[1];
 for(;i.b[1]!=0
  { if(i.b[0]>i.b[1]){
 i.b[0]=0xffff-i.b[0];
 i.b[0]+=i.b[1];
 i.b[0]++;
 }
 else{
 i.b[0]=i.b[1]-i.b[0];
 }
 *p.p2[0]=i.b[0];
 p.p2[0]++;
 i.b[0]=*p.p2[0];
 p.p2[1]++;
 i.b[1]=*p.p2[1];
 }
 *p.p2[0]=0;
 p.p2[0]=IR;
 temp.b=*p.p2[0];
 ir_code.c=count.b;
 ir_code.b[0]=(ir_code.c*1536000)/temp.b;
 for(;temp.b!=0
  { *p.p2[0]=temp.b/154;
 p.p2[0]++;
 temp.b=*p.p2[0];
 }
 ir_code.b[1]=0;
 if(p.p2[0]==IR+132){
 p.p2[0]=IR;
 p.p2[0]+=3;
 i.c=0;
 temp.b=*p.p2[0];
 for(;temp.b!=0
  { i.c<<=1;
 if(temp.b>=11){
 i.a[3]++;
 }
 p.p2[0]+=2;
 temp.b=*p.p2[0];
 }
 if(i.a[0]==(~i.a[1])&&i.a[2]==(~i.a[3])){
 ir_code.a[2]=i.a[0];
 ir_code.a[3]=i.a[2];
 }
 else ir_code.b[0]=0;
 }
 else{
 if(p.p2[0]==IR+4){
 p.p2[0]=IR;
 p.p2[0]++;
 temp.b=*p.p2[0];
 if(temp.b<=30){
 ir_code.b[0]=1;
 }
 else ir_code.b[0]=0;
 }
 else ir_code.b[0]=2;
 }
 //if(ir_flag==2)ir_code.b[0]=3;
 }
 
 void read_ir(void){
 buf1_flag=0;
 REN=1;
 buf2_length=4;
 while(buf2_flag);
 ir_init();
 while(!ir_flag);
 ir_exit();
 ir_jiema();
 buf2=SEND;
 *buf2++=ir_code.a[0];
 *buf2++=ir_code.a[1];
 *buf2++=ir_code.a[2];
 *buf2=ir_code.a[3];
 buf2=SEND;
 buf2_flag=1;
 SBUF=HEAD;
 }
 void delay(void){}
 
 void start_iic(void){
 SCL=0;
 SDA=1;
 delay();
 delay();
 SCL=1;
 delay();
 SDA=0;
 delay();
 SCL=0;
 delay();
 }
 void stop_iic(void){
 SDA=0;
 delay();
 SCL=1;
 delay();
 SDA=1;
 delay();
 SCL=0;
 delay();
 delay();
 SCL=1;
 delay();
 }
 
 void send_ack_iic(void){
 SDA=0;
 delay();
 SCL=1;
 delay();
 delay();
 SCL=0;
 delay();
 }
 
 void send_nack_iic(void){
 SDA=1;
 delay();
 SCL=1;
 delay();
 delay();
 SCL=0;
 delay();
 }
 
 bit receive_ack_iic(void){
 bit a;
 SDA=1;
 delay();
 SCL=1;
 delay();
 if(SDA) a=1;
 else a=0;
 delay();
 SCL=0;
 delay();
 return a;
 }
 
 unsigned char read_byte_ack_iic(void){
 unsigned char a;
 SDA=1;
 for(p.a[0]=0;p.a[0]<8;p.a[0]++){
 a<<=1;
 delay();
 SCL=1;
 delay();
 if(SDA) a++;
 delay();
 SCL=0;
 delay();
 }
 send_ack_iic();
 return a;
 }
 
 unsigned char read_byte_nack_iic(void){
 unsigned char a;
 SDA=1;
 for(p.a[0]=0;p.a[0]<8;p.a[0]++){
 a<<=1;
 delay();
 SCL=1;
 delay();
 if(SDA) a++;
 delay();
 SCL=0;
 delay();
 }
 send_nack_iic();
 return a;
 }
 
 
 
 void reset_iic(void){
 SDA=1;
 for(p.a[0]=0;p.a[0]<10;p.a[0]++){
 SCL=0;
 delay();
 delay();
 SCL=1;
 delay();
 delay();
 }
 }
 
 bit write_byte_iic(unsigned char a){
 for(p.a[0]=0;p.a[0]<8;p.a[0]++){
 if(a&0x80){
 SDA=1;
 }
 else{
 SDA=0;
 }
 delay();
 SCL=1;
 delay();
 delay();
 SCL=0;
 delay();
 a<<=1;
 }
 return receive_ack_iic();
 }
 
 unsigned int read_key_data(unsigned char a){
 union{
 unsigned char a[2];
 unsigned int b;
 }key_data;
 reset_iic();
 start_iic();
 write_byte_iic(0xa0);
 write_byte_iic(a);
 start_iic();
 write_byte_iic(0xa1);
 key_data.a[0]=read_byte_ack_iic();
 key_data.a[1]=read_byte_nack_iic();
 stop_iic();
 return key_data.b;
 }
 
 void write_key_data(unsigned char a){
 reset_iic();
 start_iic();
 write_byte_iic(0xa0);
 write_byte_iic(a);
 write_byte_iic(ir_code.a[2]);
 write_byte_iic(ir_code.a[3]);
 stop_iic();
 }
 
 void store_ir(void){
 buf1_flag=0;
 REN=1;
 buf1=RECEIVE+1;
 *buf1=(*buf1)<<1;
 write_key_data(*buf1);
 }
 
 unsigned char yima(void){
 unsigned char a;
 for(a=0;a<100
  { if(ir_code.b[1]==read_key_data(a)){
 
 break;
 }
 a++;
 a++;
 }
 a>>=1;
 return a;
 }
 
 void read_key(){
 unsigned char a;
 buf1_flag=0;
 REN=1;
 ir_init();
 while(!ir_flag);
 ir_exit();
 ir_jiema();
 buf2=SEND;
 a=yima();
 if(a==50){
 *buf2=0xff;
 }
 else *buf2=a;
 buf2_length=1;
 buf2_flag=1;
 SBUF=HEAD;
 }
 
 
 
 
 
 
 
 
 
 
 main(){
 unsigned char ctr;
 delay1s();
 P0=0xff;
 P1=0xff;
 P2=0xff;
 P3=0xff;
 ctr=0;
 buf1=RECEIVE;
 buf2=SEND;
 buf1_length=0;
 buf2_length=0;
 buf1_flag=0;
 buf2_flag=0;
 state1=0;
 state2=0;
 SP=0xe0; //将堆栈指针指向高端
 TL2=0xfb;
 TH2=0xff; //溢出值为5,波特率为115.2Kbps;
 RCAP2H=0xff;
 RCAP2L=0xfb;
 SCON=0x50; //方式1,8位方式,SM0=0,SM1=1,SM2=0,REN=1允许接收
 IE=0x10; //串行中断允许,全局中断不允许
 T2CON=0x34; //RCLK=1,TCLK=1,TR2=1 启动计数器
 EA=1; //开放全局中断
 free();
 
 
 
 while(1){
 //ir_init();
 //while(!ir_flag);
 //ir_exit();
 //ir_jiema();
 //if(yima()==0) P1_0=1;
 //if(yima()==1) P1_0=0;
 
 
 if(buf1_flag){
 buf1=RECEIVE;
 ctr=*buf1;
 
 switch(ctr){
 case ACK: ack();
 break;
 case NACK: nack();
 break;
 case FREE: free();
 break;
 case BUSY: busy();
 break;
 case DOWNLOAD: download();
 break;
 case UPLOAD: upload();
 break;
 case RUN: run();
 break;
 case READ_IR: read_ir();
 break;
 case READ_KEY: read_key();
 break;
 case STORE_IR: store_ir();
 break;
 default: buf1_flag=0;
 REN=1;
 break;
 }
 }
 
 
 }
 
 }
 
 
 void sub(void){
 }
 
 void ie_0(void){
 }
 
 void tf_0(void){
 }
 
 void ie_1(void){
 }
 
 void tf_1(void){
 }
 
 void tf_2(void){
 }
 |