// 滚动码实验 //--------------------------------------------- // 文件名: send.c // 版本: V1.0 // 日期: 13/12/06 // 功能: 发送滚动码 // 编译环境: HiTech PIC C compiler v.8.05 // 使用MCU: PIC16F877 //+++++++++++++++++++++++++++++++++++++++++++++ // 发码说明 //+++++++++++++++++++++++++++++++++++++++++++++ /* (一)定义逻辑单元格式,引导码和同步头: 1,定义一个逻辑单元=3TE (TE=400um为一个单位)。 2 ,定义逻辑0为:高电平=2TE,低电平=1TE; 定义逻辑1为:高电平=1TE,低电平=2TE, 3 ,引导码为:3TE的高电平。 4 ,同步头为:10TE的低电平。 (二)32位固定码格式定义 RVOOKKKK I I I I I I I I I I I I I I I I I I I I I I I I I=S/N -> 序列号 (24 BIT) K=KEY -> 按键 (4 BIT) R=Rept -> 重复/首次 (1 BIT) // 暂时不使用 V=Vlow -> 低电 (1 BIT) // 暂时不使用 O= -> 保留位 (2 BIT) (三)32位跳码格式定义 KKKKDDDD SSSSSSSS SSSSSSSS DDDDDDDD // S=Sync -> 同步计数器 (16 BIT) //暂时使用16位 // D=Disc -> 识别码 ( 8 BIT) //暂时使用 8位 (四)发射和接收拥有相同的32位厂家码(MA) */ //--------------------------------------------- #include //--------------------------------------------- //--------------------------------------------- // 常量定义 //--------------------------------------------- #define TE 400 // TE=400,基本时间单元 #define Period 200 // TIME2 200us中断一次 #define On 1 // 键盘按值,高有效 #define Work_Main0 0xa1 // 厂商ID定义 #define Work_Main1 0xb2 #define Work_Main2 0xc3 #define Work_Main3 0xd4 #define Key0 RA0 // 键盘定义 #define Key1 RA1 #define Key2 RA2 #define Key3 RA3 #define RFout RB2 // 信号输出 //测试位是否为1的两种方法 #define Test(byte,bite) (((byte)&(1<<(bite)))!=0) //测试位是否为1,为1则返回1,0则返回0 #define STATUSIT(avr,s) ((unsigned)(&avr)*8+(s)) //绝对寻址定义 static bit C @ STATUSIT(STATUS,0); //对进位位进行定义 //--------------------------------------------- // 内存定义 //--------------------------------------------- unsigned char SendBar[8]; //发送数组 #define Keyboard SendBar[0] //发送码[0],固定码,低四位是键值 #define SNH SendBar[1] //发送码[1],固定码,序列号高位 #define SNM SendBar[2] //发送码[2],固定码,序列号中位 #define SNL SendBar[3] //发送码[3],固定码,序列号低位 #define Roll0 SendBar[4] //发送码[4],滚动码,指针加密的高4位是键值,低四位是指针高四位(暂时不用) #define Roll1 SendBar[5] //发送码[5],滚动码,指针的中8位加密 #define Roll2 SendBar[6] //发送码[5],滚动码,指针的低8位加密 #define Roll3 SendBar[7] //发送码[5],滚动码,识别码,8位,是序列号的低8位加密 unsigned char TrueBar[4]; //真实码,用来加密的 #define KeyID TrueBar[0] //键值 #define CounterH TrueBar[1] //指针高8位 #define CounterL TrueBar[2] //指针低8位,可以用它的低四位对高四位进行编码 #define ID TrueBar[3] //识别码,是序列号的最低8位,变化比较大 bank1 unsigned char Encode[4]; //编码密码 bit KeyFlage; //键盘消抖允许 bit Wait; //发送等待允许 unsigned char KeyCounter; //键盘消抖定时器 unsigned char SendCounter; //中断次数计数器 unsigned char WaitCounter; //电平等待时间缓存 unsigned char ByteCount; //字节计数函数 unsigned char BitCount; //比特计数函数 unsigned char Waiter; //输出反转定时计数器,用于低电平延时 unsigned char aa; unsigned char Etemp; //编码中用来存储CounterL值 unsigned char Esave; union //联合体,指针 { unsigned int Finger; unsigned char Pointer[2]; }Rfinger; #define PointerL Rfinger.Pointer[0] #define PointerH Rfinger.Pointer[1] //--------------------------------------------- // 定义函数类型 //--------------------------------------------- void Picint(void); //初始化函数 void KeyScan(void); //键盘扫描 void interrupt SDI(void); //中断函数 void Work0(void); //事件处理函数 void Work1(void); void Work2(void); void Work3(void); void Send(void) ; //数据发送函数 void PointerAdd(void); //指针加计数 unsigned char ReadEeprom(unsigned char E_Addr); //读EEPROM void WriteEeprom(unsigned char E_Addr,unsigned char E_Data); //写EEPROM void GetEncode(void); //产生编码密码 void Encoder(void); //产生编码 //--------------------------------------------- // EEPROM定义 //--------------------------------------------- #define M_SNL 0x00 // 序列号24位,存入EEPROM中 #define M_SNM 0x01 // #define M_SNH 0x02 // #define M_CounterL 0x03 // 存储旧的指针16位 #define M_CounterH 0x04 // //********************************************* // main函数 //********************************************* void main() { Picint(); WriteEeprom(M_SNL,0xad); //写序列号手,柄序列号,24位,上电写入,这块仅用于实验,实际应该是编程写入, //比如可以用串口线通过上位机写入序列号,这部分只需在写入前加上串口接收程序! WriteEeprom(M_SNM,0xb2); WriteEeprom(M_SNH,0xc3); //测试时用,实际时应初始化写入一次,后自行加计数,在编程前把EEPROM改为00 WriteEeprom(M_CounterL,0x00);//初始化指针计数器 WriteEeprom(M_CounterH,0x00); SNL= ReadEeprom(M_SNL); //读出序列号 SNM= ReadEeprom(M_SNM); SNH= ReadEeprom(M_SNH); //设置识别码,变化最大的部分 KeyFlage=0; //键盘不扫描 Wait=0; //发送不等待 while(1) { KeyScan(); //键盘扫描,等待任务 } } //********************************************* // 中断函数 //********************************************* void interrupt SDI() { if(TMR2IF&TMR2IE) //确定是定时器2中断 { SendCounter++; //高电平计数 TMR2=256-Period+5; //重载常数 TMR2IF=0; //清中断标志 if(KeyFlage) //如果键盘等待延时开,则 { KeyCounter++; } if(Wait==1) //发送等待允许 { if(SendCounter>=Waiter) //低电平等待时间,sendcounter在发送时进行数值初始化 { Wait=0; //等待信号 } } } } //********************************************* // 键盘扫描 //********************************************* void KeyScan() { KeyFlage=1; //允许消抖 if(Key0==On) //是否有按键按下 { KeyCounter=0; //清除计数器 TMR2ON=1; //开启定时器2,准备延时 while(KeyCounter<100) //延时20MS消抖 {} TMR2ON=0; //停止定时器 if(Key0==On) //判断按键是否真正按下 { while(Key0==On) //等待按键释放 {} //键盘处理事件 Work0(); } } //----------------------------------------------- if(Key1==On) //是否有按键按下 { KeyCounter=0; //清除计数器 TMR2ON=1; //开启定时器2,准备延时 while(KeyCounter<100) //延时20MS消抖 {} TMR2ON=0; //关闭定时器 if(Key1==On) { while(Key1==On) //等待按键释放 {} //键盘处理事件 Work1(); } } //----------------------------------------------- if(Key2==On) //是否有按键按下 { KeyCounter=0; //清除计数器 TMR2ON=1; //开启定时器2,准备延时 while(KeyCounter<100) //延时20MS消抖 {} TMR2ON=0; //关闭定时器 if(Key2==On) { while(Key2==On) //等待按键释放 {} //键盘处理事件 Work2(); } } //----------------------------------------------- if(Key3==On) //是否有按键按下 { KeyCounter=0; //清除计数器 TMR2ON=1; //开启定时器2,准备延时 while(KeyCounter<100) //延时20MS消抖 {} TMR2ON=0; //关闭定时器 if(Key3==On) { while(Key3==On) //等待按键释放 {} //键盘处理事件 Work3(); } } KeyFlage=0; //键盘消抖禁止 } //********************************************* // 877初始化 //********************************************* void Picint() { INTCON=0; // 清中断源 GIE=1; // 开总中断 PEIE=1; // 开外部中断 ADCON1=0x07; // 定义A口为数字ioput模 // TRISA= 0xFF; // 定义端口输入输出模式 TRISB2=0; // 信号输出端口 TRISA0=1; // 键盘输入端口 TRISA1=1; TRISA2=1; TRISA3=1; PORTA=0; // 初始化端口 PORTB=0; T2CON=0x00; // 初始化,定时器2 TMR2IF=0; // 清中断标志 TMR2IE=1; // 开定时器2中断 TMR2=256-Period; // 加载时间常数 } //********************************************* // WORK //********************************************* void Work0() { //Keyboard&=0xf0; // 屏蔽掉低四位 Keyboard=0x01; // 键值写入低四位 KeyID=0x10; // 发送真实码中写入键值 PointerAdd(); // 指针加函数,并把指针取出到发送缓冲序列 GetEncode(); Encoder(); //编码 Send(); } void Work1() { //Keyboard&=0xf0; // 写键值,固定码部分 Keyboard=0x02; KeyID=0x20; // 发送真实码中写入键值 PointerAdd(); GetEncode(); Encoder(); Send(); } void Work2() { //Keyboard&=0xf0; // 写键值,固定码部分 Keyboard=0x04; KeyID=0x40; // 发送真实码中写入键值 PointerAdd(); GetEncode(); Encoder(); Send(); } void Work3() { //Keyboard&=0xf0; //写键值,固定码部分 Keyboard=0x08; KeyID=0x80; //发送真实码中写入键值 PointerAdd(); GetEncode(); Encoder(); Send(); } //********************************************* // 编码函数 //********************************************* void Encoder() { Roll2=CounterL^Encode[0]; //首先进行异或操作,对CountL进行加密 Esave=CounterL; switch(Esave=Esave&0x0F) //用CounterL的低四位对CounterL的高四位进行跳码(非线性)编码 { case 0: Roll2^=0xF0; break; case 1: Roll2^=0xE0; break; case 2: Roll2^=0xD0; break; case 3: Roll2^=0xC0; break; case 4: Roll2^=0xB0; break; case 5: Roll2^=0xA0; break; case 6: Roll2^=0x90; break; case 7: Roll2^=0x80; break; case 8: Roll2^=0x70; break; case 9: Roll2^=0x60; break; case 10: Roll2^=0x50; break; case 11: Roll2^=0x40; break; case 12: Roll2^=0x30; break; case 13: Roll2^=0x20; break; case 14: Roll2^=0x10; break; case 15: Roll2^=0x00; break; default: break; } Etemp=CounterL; //用指针的低四位对其他的高四位进行编码 asm("swapf _Etemp,f"); //这部分可以改进比如,可以进行随机移位运算,当然,这个随机数 //要在发送字节中发送,或者规定范围,在解码时依次进行尝试 Roll0=Encode[2]^KeyID^CounterL^Etemp; //解码时从上往下解 Roll1=Encode[3]^CounterH^CounterL^KeyID^Etemp; Roll3=Encode[1]^ID^CounterH^CounterL^KeyID^Etemp; } //********************************************* // 数据发送函数 //********************************************* void Send() { //首先发送引导码 为3TE的高电平,同步头10TE的低电平,最后肯定以低电平结束! // +--------+ +-- //__| 3TE |____________10TE_____________| // unsigned char dd; //实验用 TMR2ON=0; RFout=1; // 定时器初始化 SendCounter=0; // 计数器清0 TMR2=256-Period+85; // 定时器初始化,计数值经示波器纠正,保证脉冲宽度 Wait=0; // 不等待 TMR2ON=1; // 开启定时器 while(SendCounter<6) {} TMR2ON=0; // 停止定时器 RFout=0; // 输出低电平 Wait=1; // 低等待允许 Waiter=20; // 10个低电平的同步头 SendCounter=0; TMR2=256-Period+100; // 定时器初始化 TMR2ON=1; // 开启定时器 //-------------------send---------------------- //ByteCount=0; // 字节与字符计数器,初始化 //BitCount=0; asm("bcf _STATUS,0"); for(ByteCount=0;ByteCount<8;ByteCount++)//发送8个字节的数据 { aa=SendBar[ByteCount]; for(BitCount=0;BitCount<8;BitCount++) { asm("RRF _aa,f"); if(C) //测试位是否为1 { // +-----+ + //逻辑1发送 // | TE |____2TE_____| while(Wait==1) {} TMR2ON=0; RFout=1; //高电平 SendCounter=0; //清计数器 TMR2=256-Period+55; //定时器初始化 //Wait=0; TMR2ON=1; while(SendCounter<2) {} TMR2ON=0; RFout=0; SendCounter=0; //清计数器 TMR2=256-Period+80; //定时器初始化 Wait=1; Waiter=4; //2TE的低电平 TMR2ON=1; //开启定时器 } else { //+------------+ + //逻辑0发送 //| 2TE |___TE___| while(Wait==1) {} TMR2ON=0; RFout=1; SendCounter=0; //清计数器 TMR2=256-Period+75; //定时器初始化 TMR2ON=1; while(SendCounter<4) {} TMR2ON=0; RFout=0; SendCounter=0; //清计数器 TMR2=256-Period+60; //定时器初始化 Wait=1; Waiter=2; //1TE的低电平 TMR2ON=1; //开启定时器 } } } while(Wait) {} TMR2ON=0; RFout=1; //高电平 SendCounter=0; TMR2=256-Period+75; TMR2ON=1; while(SendCounter<4) {} RFout=0; TMR2ON=0; } //********************************************* // 指针加 //********************************************* void PointerAdd() { PointerL=ReadEeprom(M_CounterL); //读出指针低位 PointerH=ReadEeprom(M_CounterH); //读出指针高位 CounterL=PointerL; //指针读出到发送真实码中 CounterH=PointerH; Rfinger.Finger++; //指针加1 WriteEeprom(M_CounterL,PointerL); //把修改后的指针写入EEPROM WriteEeprom(M_CounterH,PointerH); } //********************************************* // 产生编码密码 //********************************************* void GetEncode() { Encode[0]=SNL^Work_Main0; //产生编码密码 Encode[1]=SNM^Work_Main1; Encode[2]=SNH^Work_Main2; Encode[3]=ID^ Work_Main3; } //********************************************* // 读EEPROM函数 //********************************************* unsigned char ReadEeprom(unsigned char E_Addr) { unsigned char E_Data; EEADR=E_Addr; EEPGD=0; RD=1; E_Data=EEDATA; return E_Data; //返回值 } //********************************************* // 写EEPROM函数 //********************************************* void WriteEeprom(unsigned char E_Addr,unsigned char E_Data) { unsigned char GIE_flage; //GIE开关标志! EEADR=E_Addr; EEDATA=E_Data; if(GIE) { GIE=0; GIE_flage=1; } EEPGD=0; WREN=1; EECON2=0x55; //规定写入 EECON2=0xAA; WR=1; while(EEIF==0) { } EEIF=0; if(GIE_flage) { GIE=1; GIE_flage=0; } }