433遥控插座。STC15单片机,PCB文件使用PADS打开。程序用keil打开。
单片机源程序如下:
- #include <stc15.h>
- #include <intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
-
- //sbit RF = P0^5; //信号输入
- //sbit LED = P3^4; //学习指示灯
- //sbit set = P1^4; //学习按键
- //sbit D0 = P4^2; //解码输出
- //sbit D1 = P3^7;
- //sbit D2 = P4^1;
- sbit RF = P3^0; //信号输入
- sbit LED = P3^2; //学习指示灯
- sbit set = P3^3; //学习按键
- sbit D0 = P3^4; //解码输出
- int KB;
- int kk;///定时器初始值
- int nn; ///定时器溢出寄存器
- 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 idata key_number[60]; //遥控器编码数组,存放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++;
- 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 && short_k<255) //检测头信号前一个高脉冲的宽度
- {
- 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*2))
- {
- da1527[rep][ii]&=~(1<<((7-k)));
- }
- else if(j>(short_k*2)&&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][i]>>(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]=00; //2262无后4位地址,全为0
- jmnx=0; //为0是2262,1是1527
- }
-
- 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; //取得按键码
- // D0=key_d&0x04;
- // D0=key_d&0x02;
- // D0=key_d&0x01;
- if(key_d==0x04)
- {
- D0=0;
- LED=0;
- } else if(key_d==0x08)
- {
- D0=1;
- LED=1;
- }
-
- decode_ok=1;
- //VT=0;
- s=100;
- break;
- }
-
- }
-
-
- }
-
- }
-
- }
- if(decode_ok) //解码有效信号,类似2272 PT脚
- {
- s--;
- if(!s)
- {
- decode_ok=0;
- //VT=1;
- }
- }
-
-
- }
- void key_buffer() //把遥控器码从 EEPROM 复制到DATA
- {
- uchar n;
- for(n=0;n<60;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<60;num_rf++)
- {
- write_add(0x0000+num_rf,key_number[num_rf]);
-
- }
- rf_ok=0;
- LED=1; //学习成功
- EA=0; //允许总中断
- TR0=0; //启动定时器0
- }
- else
- {
- rf_ok=0;
- for(num_rf=0;num_rf<8;num_rf++) //操作超时
- {
- LED=!LED;
- delay_1ms(100);
- }
- LED=0;
-
- }
- d_num=0;
- study=0;
- }
- }
- void system_res() //系统清零
- {
-
- Sector_Erase(0x0000);
- write_add(0x0000,0x00);
- Sector_Erase(0x0200);
- write_add(0x0200,0x00);
- Sector_Erase(0x0400);
- key_buffer();
- delay_1ms(2000);
- IAP_CONTR=0x20;
- }
- void set_scan() //判断学习键状态
- {
- uchar h=0;
-
-
-
- while(!set)
- {
-
- if(h>5 && h< 60)
- {
- study=0;
- LED=!LED;
- D0=!D0;
- h=0;
-
- while(!set)
- {
- delay_1ms(300);
- h++;
- if(h >60 && h<100)
-
- {
- kk=20;
-
- EA=1; //允许总中断
- TR0=1; //启动定时器0
- if(set==1)
- {
- study=1;
- }
- }
-
- // KEY_study();
-
-
- if(h > 150)
- {
-
- kk=90;
- delay_1ms(20000);
- study=0;
- h=0;
- system_res();
- LED=0;
- D0=0;
- // delay_1ms(2000);
- while(!set);
- }
-
- }
- }
-
-
-
-
-
- delay_1ms(100);
- h++;
- }
-
- if(study)
- {
- KEY_study();
- }
- }
- void system_start() //上电初始化
- {
- TMOD &= 0xF0; //定时器0运行在模式0 ,13位计数器
- // GATE0=0; C/T0#=0; M1=0; M0=0;
- TH0 = 0x00; //设置初值0x00,所以计数值为8192,若是时钟频率为12MHz
- TL0 = 0x00; //则8192μs中断一次
- ET0=1; //允许定时器0中断
- AUXR=0x95;
- P3M0=0x14;
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
所有资料51hei提供下载:
遥控插座.rar
(117.85 KB, 下载次数: 636)
遥控插座程序.rar
(46.34 KB, 下载次数: 608)
|