//-----------------兼容2262 1527的解码实验程序----------------// //测试单片机:STC15W408AS //晶振:内部 11.0592mHZ //复位方式:内部复位 //串口通讯:波特率9600/数据位8/停止位1/无校验 //调试环境:KEIL3 //程序功能:实现2262解码,学习、自适应多阻值,片内EEPROM,存储60个遥控器数据 // 不依赖硬件,不占用硬件资源。移植更加方便 // 学习遥控器:按一下学习键,学习灯点亮,松开学习键,按动要学习的遥控器按键,学习灯熄灭,学习成功。重复上述操作可学习多个遥控器. // // 清除:按住学习键不放,直到学习灯自动熄灭,擦除成功. /**********************************************************/ #include <STC15W408AS.h> #include <intrins.h> #define uchar unsigned char #define uint unsigned int sbit RF = P1^1; //信号输入 sbit LED = P3^3; //学习指示灯 sbit set = P1^2; //学习键 sbit D0 = P3^4; //1号继电器解码输出 sbit D1 = P3^5; //2号继电器 sbit D2 = P3^6; //3号继电器 sbit D3 = P3^7; //4号继电器 sbit deng1 = P1^7; //K1指示灯 sbit deng2 = P5^4; //K2指示灯 sbit deng3 = P5^5; //K3指示灯 sbit deng4 = P3^2; //K4指示灯 sbit VT = P1^0; //接收指示灯 sbit aj1 = P1^3; //K1 sbit aj2 = P1^4; //K2 sbit aj3 = P1^5; //K3 sbit aj4 = P1^6; //K4 bit decode_ok; //解码成功 bit rf_ok; //收到有效数据 bit study; //学习标志 bit jmnx; //编码类型 0是2262,1是1527 bit m=0,ba=0,ca=0,da=0,ea=0,za=0,aa=0,hv=0,ff=0,ra=0,rb=0,rc=0,rd=0,g=0,hm=0,biao=0,kt=0; bit biao_1=0,g_1=0,kt_1=0,hm_1=0; bit biao_2=0,g_2=0,kt_2=0,hm_2=0; bit biao_3=0,g_3=0,kt_3=0,hm_3=0; uchar da1527[2][3]; //解码过程中临时数组 uchar key_d; //遥控器按键码 uchar short_k; //窄脉冲宽度 uchar ss=0,sn=0,h=0,yz=0,hh=0,yy=0,yk=0,yu=0;hk=0,sj=0,so=0,jk=0,hu=0,t1=0,t2=0,t3=0,t4=0; uint dt=0,dr=0,dq=0,rv=0,rv_1=0,rv_2=0,rv_3=0; uchar trg=0,trg_1=0,trg_2=0,trg_3=0,cont=0,cont_1=0,cont_2=0,cont_3=0; uchar ReadData=0,ReadData_1=0,ReadData_2=0,ReadData_3=0; static uint sk=0; uchar xdata key_number[181]; //遥控器编码数组,存放60个遥控器 void delay_1ms(uint x) //1毫秒延时 { uchar b,c; for(x;x>0;x--) { for(b=3;b>0;b--) { for(c=150;c>0;c--); } } } void delay(uint ms)// { while(ms--) { ms++; ms--; } } //==================================================== /片内EEPROM读写驱动程序/// //==================================================== void IAP_Disable() //关闭IAP { //关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态, //一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关 IAP_CONTR = 0; //关闭IAP 功能 IAP_CMD = 0; //清命令寄存器,使命令寄存器无命令,此句可不用 IAP_TRIG = 0; //清命令触发寄存器,使命令触发寄存器无触发,此句可不用 IAP_ADDRH = 0; IAP_ADDRL = 0; }// //读一字节,调用前需打开IAP 功能,入口:DPTR = 字节地址,返回:A = 读出字节 uchar read_add(uint addr) //读EEPROM { IAP_DATA = 0x00; IAP_CONTR = 0x84; //打开IAP 功能, 设置Flash 操作等待时间 IAP_CMD = 0x01; //IAP/ISP/EEPROM 字节读命令 IAP_ADDRH = addr>>8; //设置目标单元地址的高8 位地址 IAP_ADDRL = addr&0xff; //设置目标单元地址的低8 位地址 EA = 0; IAP_TRIG = 0x5a; //先送 46h,再送B9h 到ISP/IAP 触发寄存器,每次都需如此 IAP_TRIG = 0xa5; //送完 B9h 后,ISP/IAP 命令立即被触发起动 _nop_(); EA = 1; IAP_Disable(); //关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态, //一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关 return (IAP_DATA); }//------------------------------------------------------------------------------ //字节编程,调用前需打开IAP 功能,入口:DPTR = 字节地址, A= 须编程字节的数据 void write_add(uint addr,uchar ch) //直接写EEPROM { IAP_CONTR = 0x84; //打开 IAP 功能, 设置Flash 操作等待时间 IAP_CMD = 0x02; //IAP/ISP/EEPROM 字节编程命令 IAP_ADDRH = addr>>8; //设置目标单元地址的高8 位地址 IAP_ADDRL = addr&0xff; //设置目标单元地址的低8 位地址 IAP_DATA = ch; //要编程的数据先送进IAP_DATA 寄存器 EA = 0; IAP_TRIG = 0x5a; //先送 46h,再送B9h 到ISP/IAP 触发寄存器,每次都需如此 IAP_TRIG = 0xa5; //送完 B9h 后,ISP/IAP 命令立即被触发起动 _nop_(); EA = 1; IAP_Disable(); //关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态, //一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关 }//------------------------------------------------------------------------------ //擦除扇区, 入口:DPTR = 扇区地址 void Sector_Erase(uint addr) //扇区擦除 { IAP_CONTR = 0x84; //打开IAP 功能, 设置Flash 操作等待时间 IAP_CMD = 0x03; //IAP/ISP/EEPROM 扇区擦除命令 IAP_ADDRH =addr>>8; //设置目标单元地址的高8 位地址 IAP_ADDRL =addr&0xff; //设置目标单元地址的低8 位地址 EA = 0; IAP_TRIG = 0x5a; //先送 46h,再送B9h 到ISP/IAP 触发寄存器,每次都需如此 IAP_TRIG = 0xa5; //送完 B9h 后,ISP/IAP 命令立即被触发起动 _nop_(); EA = 1; }//------------------------------------------------------------------------------ //============================接收解码部分========================================// void RF_decode() { uchar ii=0,j=0,k=0,rep=0; uint head_k=0; //短脉冲宽度 uchar s; //-------------------------------数据接收----------------------------------------- short_k=0; while(RF && j<250) //检测头信号前一个高脉冲的宽度 { delay(1); short_k++; } while(!RF) { delay(1); head_k++; } //检测头脉冲的宽度 if(((short_k*24)<head_k) && (head_k<(short_k*38))) //引导码宽度是窄脉冲的32倍 24/38 { for(rep=0;rep<2;rep++) { for(ii=0;ii<3;ii++)//3字节 { for(k=0;k<8;k++)//每个字节8位 { j=0; while(RF && j<245) { delay(1); j++; }// if(j>(short_k-short_k/2-short_k/3)&&j<(short_k*1.96)) { da1527[rep][ii]&=~(1<<((7-k))); } else if(j>(short_k*1.96)&&j<(short_k*5))da1527[rep][ii]|=(1<<(7-k)); else {return;} //乱码退出 j=0; while(!RF && j<150){delay(2);j++;} //跳过低电平 } }//for(ii=0;ii<12;ii++) j=0;while(RF && (j<200)){delay(1);j++;} //跳个最后一个高脉冲 head_k=0;while(!RF) {delay(1);head_k++;} //检测下一个前导信号的寬度 if((head_k<(short_k*26)) || (head_k>(short_k*38))) {return;} //引导码宽度是窄脉冲的32倍 //乱码退出 } //+++++++++++++++++++++++++2262与1527数据分离处理++++++++++++++++++++++++++++++++++++++++ if((da1527[0][0]==da1527[1][0]) && (da1527[0][1]==da1527[1][1]) && (da1527[0][2]==da1527[1][2])) //两次接收到的数据相同 { uchar u,i,x; rf_ok=1; for(i=0;i<3;i++) //判定2262与1527 { for(u=0;u<4;u++) {if(((da1527[0]>>(u*2)) & 3)==2) {i=80;break;}} //有10则为1527 if(i==80) break; } if(i==80) //1527 { key_d=da1527[1][2] & 0x0f; //分出1527的按键值 da1527[0][2]=da1527[1][2]>>4; //分出1527的后4位地址 jmnx=1; //为0是2262,1是1527 } else //2262 { key_d=0; for(i=0;i<4;i++){if(((da1527[0][2]>>(i*2))&3)==3) key_d|=1<<i;} //计算出2262的按键数据 da1527[0][2]=0x00; //2262无后4位地址,全为0 jmnx=0; //为0是2262,1是1527 jk++;//自锁用,作用:按下按键不松手继电器状态不变,松开再按下改变,一次只改变一次状态,因为按下按键后遥控会一直发码,所以让jk一直自加,但是只取jk=1的值的状态 } if (!study) //非学习状态 { rf_ok=0; for(x=0;x<60;x++) { if((da1527[0][0]==key_number[x*3+1])&&(da1527[0][1]==key_number[x*3+2]) &&(da1527[0][2]==key_number[x*3+3]))//判断是否已学习过的编码 { // D0=!(key_d&0x08); //取得按键码 // D1=!(key_d&0x04); // D2=!(key_d&0x02); // D3=!(key_d&0x01); if(m==1) //互锁 { if(key_d == 0x01){D0=0;D1=1;D2=1;D3=1;}//D4=1;D5=1;D6=1;D7=1;D8=1;D9=1;D10=1;D11=1;}//else{D0=1;} if(key_d == 0x02){D0=1;D1=0;D2=1;D3=1;}//D4=1;D5=1;D6=1;D7=1;D8=1;D9=1;D10=1;D11=1;} // if(key_d == 0x03){D0=1;D1=1;D2=0;D3=1;D4=1;D5=1;D6=1;D7=1;D8=1;D9=1;D10=1;D11=1;} if(key_d == 0x04){D0=1;D1=1;D2=0;D3=1;}//D4=1;D5=1;D6=1;D7=1;D8=1;D9=1;D10=1;D11=1;} // if(key_d == 0x05){D0=1;D1=1;D2=1;D3=1;D4=0;D5=1;D6=1;D7=1;D8=1;D9=1;D10=1;D11=1;} // if(key_d == 0x06){D0=1;D1=1;D2=1;D3=1;D4=1;D5=0;D6=1;D7=1;D8=1;D9=1;D10=1;D11=1;} // if(key_d == 0x07){D0=1;D1=1;D2=1;D3=1;D4=1;D5=1;D6=0;D7=1;D8=1;D9=1;D10=1;D11=1;} if(key_d == 0x08){D0=1;D1=1;D2=1;D3=0;}//D4=1;D5=1;D6=1;D7=0;D8=1;D9=1;D10=1;D11=1;} // if(key_d == 0x09){D0=1;D1=1;D2=1;D3=1;D4=1;D5=1;D6=1;D7=1;D8=0;D9=1;D10=1;D11=1;} // if(key_d == 0x0a){D0=1;D1=1;D2=1;D3=1;D4=1;D5=1;D6=1;D7=1;D8=1;D9=0;D10=1;D11=1;} // if(key_d == 0x0b){D0=1;D1=1;D2=1;D3=1;D4=1;D5=1;D6=1;D7=1;D8=1;D9=1;D10=0;D11=1;} // if(key_d == 0x0c){D0=1;D1=1;D2=1;D3=1;D4=1;D5=1;D6=1;D7=1;D8=1;D9=1;D10=1;D11=0;} } else { if(ba==0) //B按键自锁 { if(key_d == 0x04) { if(jk==1) { D2=~D2; } } } //B自锁 if(da==0) //A按键自锁 { if(key_d == 0x08) { if(jk==1) { D3=~D3; } } } //A自锁 if(ca==0) //C按键自锁 { if(key_d == 0x02) { if(jk==1) { D1=~D1; } } } //C自锁 if(ea==0) //D按键自锁 { if(key_d == 0x01) { if(jk==1) { D0=~D0; } } } //D自锁 if(ba==1)//B按键点动,ba为自锁转点动标志位 { if(key_d == 0x04){D2=0;} } if(da==1)//A按键点动,da为自锁转点动标志位 { if(key_d == 0x08){D3=0;} } if(ca==1)//C按键点动,da为自锁转点动标志位 { if(key_d == 0x02){D1=0;} } if(ea==1)//D按键点动,da为自锁转点动标志位 { if(key_d == 0x01){D0=0;} } } decode_ok=1; ss=1; sn=1; sj=1; so=1; VT=0; s=30; break; } } } } } if(decode_ok) //解码有效信号,类似2272 PT脚 { s--; if(!s) { jk=0; //按一下按键只做一次动作信号没有后清零 decode_ok=0; if(h==1){ss=2;} //点动标志位 if(hh==1){sn=2;} if(hk==1){sj=2;}//点动标志位 if(hu==1){so=2;} VT=1; } } } void key_buffer() //把遥控器码从 EEPROM 复制到DATA { uchar n; for(n=0;n<181;n++) { key_number[n]=read_add(0x0000+n); } } void KEY_study() //遥控器学习 { uchar num_rf; uint d_num; if(study) { rf_ok=0; d_num=0; while(!rf_ok) { RF_decode(); d_num++; if(d_num>50000) break; } d_num=0; if(rf_ok==1) { num_rf=key_number[0]; //取已学习的遥控器数量 if(num_rf>60){num_rf=0;} //如果遥控器数量超过10个,覆盖最先学习的 key_number[num_rf*3+1]=da1527[0][0]; key_number[num_rf*3+2]=da1527[0][1]; key_number[num_rf*3+3]=da1527[0][2]; key_number[0]=num_rf+1; Sector_Erase(0x0000); for(num_rf=0;num_rf<181;num_rf++) { write_add(0x0000+num_rf,key_number[num_rf]); } rf_ok=0; LED=1; //学习成功 } else { rf_ok=0; for(num_rf=0;num_rf<8;num_rf++) //操作超时 { LED=!LED; delay_1ms(100); } LED=1; } d_num=0; study=0; } } void system_res() //系统清零 { Sector_Erase(0x0000); write_add(0x0000,0x00); key_buffer(); } void set_scan() //判断学习键状态 { uchar h=0; while(!set) { if(h>5) { study=1; h=0; LED=0; while(!set) { delay_1ms(100); h++; if(h>80) { study=0; h=0; system_res(); LED=1; while(!set); } } } delay_1ms(100); h++; } if(study) { KEY_study(); } } /******************************************************************* * 按键读取 ********************************************************************/ void KeyRead()//读取按键IO口函数 { ReadData = aj1^0xff; // 读取按键状态取反后赋值给ReadData trg = ReadData & (ReadData ^ cont); //trg短按,每按下按键trg=1;抬手后为trg=0,长按为trg=0 cont = ReadData; //cont长按,长按cont=1,抬手后cont=0 /*******************************************************************/ ReadData_1 = aj2^0xff; // 读取按键状态取反后赋值给ReadData trg_1 = ReadData_1 & (ReadData_1 ^ cont_1); //trg短按,每按下按键trg=1;抬手后为trg=0,长按为trg=0 cont_1 = ReadData_1; //cont长按,长按cont=1,抬手后cont=0 /*******************************************************************/ ReadData_2 = aj3^0xff; // 读取按键状态取反后赋值给ReadData trg_2 = ReadData_2 & (ReadData_2 ^ cont_2); //trg短按,每按下按键trg=1;抬手后为trg=0,长按为trg=0 cont_2 = ReadData_2; //cont长按,长按cont=1,抬手后cont=0 /*******************************************************************/ ReadData_3 = aj4^0xff; // 读取按键状态取反后赋值给ReadData trg_3 = ReadData_3 & (ReadData_3 ^ cont_3); //trg短按,每按下按键trg=1;抬手后为trg=0,长按为trg=0 cont_3 = ReadData_3; //cont长按,长按cont=1,抬手后cont=0 } /******************************************************************* * A按键 ********************************************************************/ void key_1() { if(trg & 0x01) //短按 { rv=0; //长按延时标志位防止短按到200次后长按启动 biao=0; //这是长按屏蔽短按标志位 g=0; //这是长按只执行一次标志位 kt=1; //这是短按标志位,kt=1说明短按了 } if((aj1!=0)&&(kt==1)&&(biao==0))//判断 { D3=~D3;kt=0; } // 短按 if((cont & 0x01)&&(g==0))//长按 { rv++; //长按延时 if(rv>200) { biao=1; //屏蔽短按 hm=1; yz+=1;//选位标志位 if(yz==1){h=1;da=1;za=0;hm=0;} if(yz==2){h=2;m=1;yy=0;yk=0;yu=0;hh=0;hk=0;hu=0;ba=0;ca=0;ea=0;da=0;za=0;} if(yz==3){ yz=0; //选位标志重个位开始重新选 h=0; m=0;za=0; } g=1; //只让输出一次 rv=0; //延时时间归零 } }//长按 } /******************************************************************* * B选位按键 ********************************************************************/ void key_2() { if(trg_1 & 0x01) //短按 { rv_1=0; //长按延时标志位防止短按到200次后长按启动 biao_1=0; //这是长按屏蔽短按标志位 g_1=0; //这是长按只执行一次标志位 kt_1=1; //这是短按标志位,kt=1说明短按了 } if((aj2!=0)&&(kt_1==1)&&(biao_1==0))//判断 { D2=~D2;kt_1=0; } // 短按 if((cont_1 & 0x01)&&(g_1==0))//长按 { rv_1++; //长按延时 if(rv_1>200) { biao_1=1; //屏蔽短按 hm_1=1; yy+=1;//选位标志位 if(yy==1){hh=1;ba=1;aa=0;hm_1=0;} if(yy==2){hh=2;m=1;hk=0;h=0;hu=0;yz=0;yk=0;yu=0;ba=0;ca=0;ea=0;da=0;aa=0;} if(yy==3){ yy=0; //选位标志重个位开始重新选 hh=0; m=0;aa=0; } g_1=1; //只让输出一次 rv_1=0; //延时时间归零 } }//长按 } /******************************************************************* * C选位按键 ********************************************************************/ void key_3() { if(trg_2 & 0x01) //短按 { rv_2=0; //长按延时标志位防止短按到200次后长按启动 biao_2=0; //这是长按屏蔽短按标志位 g_2=0; //这是长按只执行一次标志位 kt_2=1; //这是短按标志位,kt=1说明短按了 } if((aj3!=0)&&(kt_2==1)&&(biao_2==0))//判断 { D1=~D1;kt_2=0; } // 短按 if((cont_2 & 0x01)&&(g_2==0))//长按 { rv_2++; //长按延时 if(rv_2>200) { biao_2=1; //屏蔽短按 hm_2=1; yk+=1;//选位标志位 if(yk==1){hk=1;ca=1;ff=0;hm_2=0;} if(yk==2){hk=2;m=1;h=0;hh=0;hu=0;yz=0;yy=0;yu=0;ba=0;ca=0;ea=0;da=0;ff=0;} if(yk==3){ yk=0; //选位标志重个位开始重新选 hk=0; m=0;ff=0; } g_2=1; //只让输出一次 rv_2=0; //延时时间归零 } }//长按 } /******************************************************************* * D选位按键 ********************************************************************/ void key_4() { if(trg_3 & 0x01) //短按 { rv_3=0; //长按延时标志位防止短按到200次后长按启动 biao_3=0; //这是长按屏蔽短按标志位 g_3=0; //这是长按只执行一次标志位 kt_3=1; //这是短按标志位,kt=1说明短按了 } if((aj4!=0)&&(kt_3==1)&&(biao_3==0))//判断 { D0=~D0;kt_3=0; } // 短按 if((cont_3 & 0x01)&&(g_3==0))//长按 { rv_3++; //长按延时 if(rv_3>200) { biao_3=1; //屏蔽短按 hm_3=1; yu+=1;//选位标志位 if(yu==1){hu=1;ea=1;hv=0;hm_3=0;} if(yu==2){hu=2;m=1;h=0;hh=0;hk=0;yz=0;yy=0;yk=0;ba=0;ca=0;ea=0;da=0;hv=0;} if(yu==3){ yu=0; //选位标志重个位开始重新选 hu=0; m=0;hv=0; } g_3=1; //只让输出一次 rv_3=0; //延时时间归零 } }//长按 } /******************************************************************* * 定时器配置 ********************************************************************/ void ConfigTimer0(){ TMOD=0x01;//将定时器0,1都设置为模式1 TH0=0XFC;//1ms TL0=0X66; TR0=1;//开启定时器0 ET0=1;//开定时器0的中断 EA=1;//开总中断 } /******************************************************************* * t0定时器 ********************************************************************/ void timer0() interrupt 1 { TH0=0XFC;//1ms TL0=0X66; sk++; if((t1==1)||(t2==1)||(t3==1)||(t4==1)) //闪烁一下 { dq++; if(dq==1000) { if(ra==1){deng1=0;} if(rb==1){deng2=0;} if(rc==1){deng3=0;} if(rd==1){deng4=0;} } if(dq==2500) { if(ra==1){deng1=1;t1=0;ra=0;} if(rb==1){deng2=1;t2=0;rb=0;} if(rc==1){deng3=1;t3=0;rc=0;} if(rd==1){deng4=1;t4=0;rd=0;} dq=0; } } if((t1==2)||(t2==2)||(t3==2)||(t4==2)) //闪烁两下 { dt++; if(dt==1000) { if(ra==1){deng1=0;} if(rb==1){deng2=0;} if(rc==1){deng3=0;} if(rd==1){deng4=0;} } if(dt==2500) { if(ra==1){deng1=1;} if(rb==1){deng2=1;} if(rc==1){deng3=1;} if(rd==1){deng4=1;} } if(dt==4000) { if(ra==1){deng1=0;} if(rb==1){deng2=0;} if(rc==1){deng3=0;} if(rd==1){deng4=0;} } if(dt==5500) { if(ra==1){deng1=1;t1=0;ra=0;} if(rb==1){deng2=1;t2=0;rb=0;} if(rc==1){deng3=1;t3=0;rc=0;} if(rd==1){deng4=1;t4=0;rd=0;} dt=0; } } if((t1==3)||(t2==3)||(t3==3)||(t4==3)) //闪烁三下 { dr++; if(dr==1000) { if(ra==1){deng1=0;} if(rb==1){deng2=0;} if(rc==1){deng3=0;} if(rd==1){deng4=0;} } if(dr==2500) { if(ra==1){deng1=1;} if(rb==1){deng2=1;} if(rc==1){deng3=1;} if(rd==1){deng4=1;} } if(dr==4000) { if(ra==1){deng1=0;} if(rb==1){deng2=0;} if(rc==1){deng3=0;} if(rd==1){deng4=0;} } if(dr==5500) { if(ra==1){deng1=1;} if(rb==1){deng2=1;} if(rc==1){deng3=1;} if(rd==1){deng4=1;} } if(dr==7000) { if(ra==1){deng1=0;} if(rb==1){deng2=0;} if(rc==1){deng3=0;} if(rd==1){deng4=0;} } if(dr==8500) { if(ra==1){deng1=1;t1=0;ra=0;} if(rb==1){deng2=1;t2=0;rb=0;} if(rc==1){deng3=1;t3=0;rc=0;} if(rd==1){deng4=1;t4=0;rd=0;} dr=0; } } } void system_start() //上电初始化 { AUXR=0xb5; P0=0xfe; P1=0xff; P3=0xff; key_buffer(); } void main() { system_start(); //上电初始化 ConfigTimer0(); //t0中断配置 deng1=1; deng2=1; deng3=1; deng4=1; while(1) { KeyRead(); //按键读取函数 key_1(); key_2(); key_3(); key_4(); RF_decode(); //读取信号波形分析 set_scan(); //学习按键 if((h==1)&&(ss==2)){D3=1;} //A按键点动,h为k1按键按下后h=1,ss为接收指示灯熄灭后ss=2;控制对应输出断开,形成点动 if((hh==1)&&(sn==2)){D2=1;}//B按键点动,hh为k2按键按下后hh=1,sn为接收指示灯熄灭后sn=2;控制对应输出断开,形成点动 if((hk==1)&&(sj==2)){D1=1;} //C按键点动,hk为k3按键按下后hk=1,sj为接收指示灯熄灭后sj=2;控制对应输出断开,形成点动 if((hu==1)&&(so==2)){D0=1;} //D按键点动,hu为k4按键按下后hu=1,so为接收指示灯熄灭后so=2;控制对应输出断开,形成点动 if((yz==0)&&(za==0)&&(hm==1)){t1=1;za=1;ra=1;}//A按键:主要控制对应灯闪烁,za为只执行一次闪烁标志位,t1为闪烁标志位t1=1,闪一下,t1=2闪两下,t1=3闪三下 if((yz==1)&&(za==0)){t1=2;za=1;ra=1;} //ra为对应灯输出标志位,ra=1则输出,ra=0则停止 if((yz==2)&&(za==0)){t1=3;za=1;ra=1;} if((yy==0)&&(aa==0)&&(hm_1==1)){t2=1;aa=1;rb=1;}//B按键:主要控制对应灯闪烁,aa为只执行一次闪烁标志位,t2为闪烁标志位t2=1,闪一下,t2=2闪两下,t2=3闪三下 if((yy==1)&&(aa==0)){t2=2;aa=1;rb=1;} //rb为对应灯输出标志位,rb=1则输出,rb=0则停止 if((yy==2)&&(aa==0)){t2=3;aa=1;rb=1;} if((yk==0)&&(ff==0)&&(hm_2==1)){t3=1;ff=1;rc=1;}//C按键:主要控制对应灯闪烁,ff为只执行一次闪烁标志位,t3为闪烁标志位t3=1,闪一下,t3=2闪两下,t3=3闪三下 if((yk==1)&&(ff==0)){t3=2;ff=1;rc=1;} //rc为对应灯输出标志位,rc=1则输出,rc=0则停止 if((yk==2)&&(ff==0)){t3=3;ff=1;rc=1;} if((yu==0)&&(hv==0)&&(hm_3==1)){t4=1;hv=1;rd=1;}//D按键:主要控制对应灯闪烁,hv为只执行一次闪烁标志位,t4为闪烁标志位t4=1,闪一下,t4=2闪两下,t4=3闪三下 if((yu==1)&&(hv==0)){t4=2;hv=1;rd=1;} //rd为对应灯输出标志位,rd=1则输出,rd=0则停止 if((yu==2)&&(hv==0)){t4=3;hv=1;rd=1;} } }我把上面程序中开关控制部省了,把保遥控60个改为10个,编译没有问题 ,但学习功能不能程序没反应,用表测试学习按键按下从高电平能变成低电平,就是没反应,找不问题在那,求高人指点 改的程序如下//-----------------STC8H1K08 SOP16 遥控解码程序----------------// //测试单片机:STC8H1K08 //封装:SOP16 //晶振:内部11.0592MHz //功能:2262/1527解码,遥控控制4路继电器,存储10个遥控器 #include <STC8H.H> #include <intrins.h> #define uchar unsigned char #define uint unsigned int // IO口分配(用户指定) sbit RF = P3^2; //信号输入 sbit LED = P3^5; //学习指示灯 sbit set = P3^6; //学习键 sbit D0 = P1^0; //1号继电器 sbit D1 = P1^1; //2号继电器 sbit D2 = P1^6; //3号继电器 sbit D3 = P3^7; //4号继电器 // 功能标志位 bit decode_ok; //解码成功 bit rf_ok; //收到有效数据 bit study; //学习标志 bit jmnx; //编码类型:0=2262,1=1527 uchar da1527[2][3]; //解码临时数组 uchar key_d; //遥控器按键码 uchar short_k; //窄脉冲宽度 uchar ss=0, sn=0, s=0, x=0; uint jk=0; // 存储10个遥控器(每个3字节,共30字节+1字节数量) uchar key_number[31]; // 0号单元存储数量,1-30存储遥控器数据 // 1ms延时函数 void delay_1ms(uint x) { uchar b,c; for(x;x>0;x--) { for(b=3;b>0;b--) { for(c=150;c>0;c--); } } } // 简易延时 void delay(uint ms) { while(ms--); } //================ EEPROM操作函数 ================ void IAP_Disable() { IAP_CONTR = 0; IAP_CMD = 0; IAP_TRIG = 0; IAP_ADDRH = 0; IAP_ADDRL = 0; } uchar read_add(uint addr) { IAP_DATA =0x00; IAP_CONTR =0x84; IAP_CMD = 0x01; IAP_ADDRH =addr>>8; IAP_ADDRL =addr&0xff; EA = 0; IAP_TRIG =0x5a; IAP_TRIG =0xa5; _nop_(); EA = 1; IAP_Disable(); returnIAP_DATA; } void write_add(uint addr, uchar ch) { IAP_CONTR =0x84; IAP_CMD = 0x02; IAP_ADDRH =addr>>8; IAP_ADDRL =addr&0xff; IAP_DATA = ch; EA = 0; IAP_TRIG =0x5a; IAP_TRIG =0xa5; _nop_(); EA = 1; IAP_Disable(); } void Sector_Erase(uint addr) { IAP_CONTR =0x84; IAP_CMD = 0x03; IAP_ADDRH =addr>>8; IAP_ADDRL =addr&0xff; EA = 0; IAP_TRIG =0x5a; IAP_TRIG =0xa5; _nop_(); EA = 1; } //================ 接收解码函数 ================ void RF_decode() { ucharii=0,j=0,k=0,rep=0; uint head_k=0; uchar s; short_k=0; while(RF&& j<250) { delay(1); short_k++; } while(!RF) { delay(1); head_k++; } if(((short_k*24)<head_k) && (head_k<(short_k*38))) { for(rep=0;rep<2;rep++) { for(ii=0;ii<3;ii++) { for(k=0;k<8;k++) { j=0; while(RF && j<245) { delay(1); j++; } if(j>(short_k-short_k/2-short_k/3)&&j<(short_k*1.96)) { da1527[rep][ii]&=~(1<<((7-k))); } else if(j>(short_k*1.96)&&j<(short_k*5)) da1527[rep][ii]|=(1<<(7-k)); else {return;} j=0; while(!RF && j<150){delay(2);j++;} } } j=0;while(RF && (j<200)){delay(1);j++;} head_k=0;while(!RF) {delay(1);head_k++;} if((head_k<(short_k*26)) || (head_k>(short_k*38))) {return;} } if((da1527[0][0]==da1527[1][0]) && (da1527[0][1]==da1527[1][1])&& (da1527[0][2]==da1527[1][2])) { uchari,u; rf_ok=1; for(i=0;i<3;i++) { for(u=0;u<4;u++) {if(((da1527[0]>>(u*2)) & 3)==2){i=80;break;}} if(i==80) break; } if(i==80) // 1527 { key_d=da1527[1][2] & 0x0f; da1527[0][2]=da1527[1][2]>>4; jmnx=1; } else // 2262 { key_d=0; for(i=0;i<4;i++){if(((da1527[0][2]>>(i*2))&3)==3)key_d|=1<<i;} da1527[0][2]=0x00; jmnx=0; jk++;//自锁用 } } } } //================ 遥控器学习函数 ================ void key_buffer() // 读取EEPROM到RAM { uchar n; for(n=0;n<31;n++) { key_number[n]=read_add(0x0000+n); } } void KEY_study() // 学习新遥控器 { uint d_num; if(study) { rf_ok=0; d_num=0; while(!rf_ok) { RF_decode(); d_num++; if(d_num>50000) break; } d_num=0; if(rf_ok==1) { ucharnum_rf = key_number[0]; if(num_rf>=10){num_rf=0;} // 最多存储10个 key_number[num_rf*3+1]=da1527[0][0]; key_number[num_rf*3+2]=da1527[0][1]; key_number[num_rf*3+3]=da1527[0][2]; key_number[0]=num_rf+1; Sector_Erase(0x0000); for(num_rf=0;num_rf<31;num_rf++) { write_add(0x0000+num_rf, key_number[num_rf]); } rf_ok=0; LED=1; // 学习成功 } else { for(num_rf=0;num_rf<8;num_rf++) { LED=!LED; delay_1ms(100); } LED=1; } study=0; } } void system_res() // 系统清零 { Sector_Erase(0x0000); write_add(0x0000, 0x00); key_buffer(); } void set_scan() // 学习键扫描 { uchar h=0; while(!set) { if(h>5) { study=1; h=0; LED=0; while(!set) { delay_1ms(100); h++; if(h>80) { study=0; h=0; system_res(); LED=1; while(!set); } } } delay_1ms(100); h++; } if(study) { KEY_study(); } } //================ 定时器配置 ================ void ConfigTimer0(){ TMOD=0x01; TH0=0XFC; // 1ms定时初值 TL0=0X66; TR0=1; ET0=1; EA=1; } void timer0() interrupt 1 { TH0=0XFC; TL0=0X66; if(decode_ok) // 解码有效信号 { s--; if(!s) { jk=0; decode_ok=0; } } } //================ 继电器控制逻辑(一路遥控一路) ================ void relay_control() { if(!study) // 非学习状态 { rf_ok=0; for(x=0;x<10;x++) // 检查10个遥控器 { if((da1527[0][0]==key_number[x*3+1])&& (da1527[0][1]==key_number[x*3+2])&& (da1527[0][2]==key_number[x*3+3])) { // 一路遥控控制一路继电器(取消互锁,简化逻辑) if(key_d == 0x01) {D0=~D0;} // 按键1控制D0 if(key_d == 0x02) {D1=~D1;} // 按键2控制D1 if(key_d == 0x04) {D2=~D2;} // 按键4控制D2 if(key_d == 0x08) {D3=~D3;} // 按键8控制D3 decode_ok=1; ss=1; sn=1; s=30; break; } } } } void system_start() // 上电初始化 { AUXR=0xb5; // 配置辅助寄存器,根据STC8H特性可能需要调整 P1=0xff; P3=0xff; key_buffer(); } void main() { system_start(); ConfigTimer0(); LED=1; // 初始化学习指示灯 while(1) { RF_decode(); // 读取信号波形分析 set_scan(); // 学习按键扫描 relay_control(); // 继电器控制 } } |