EM4095与Manchester解码

 

 

/****************************************************************************************** 检测方法 1).EM4095的数据格式为:9bit起始位+40bit数据位+10bit行校验位+4bit列校验位+1bit停止位 2).本程序时针对STC12C5A60S2单片机的,与80C51完全兼容,但是大部分指令时单周期指令,也就是 说比普通80C51大约快12倍 3).确定起始位,首先要正确找到数据1,按规则下跳为1,上跳为0. 可检测高电平并等其变低, 但这会把0错检为1,因为0也存在高电平。但是如果检测到一个周期的高电平(数据01)则可 确定找到了数据1,找到1后就可以同步了,因为EM4095卡最后一位数据就是0正好可以利用 作为判断的特征。 4).对于数据的确定,由于有了同步则可在同步后延时384us即3/4个码元周期,再判断接收段电平, 如为高则置数据为1,并一直等到低电平的出现,相反则等高电平的出现,并在此之间插入超时 判断。这样,一个完整的数据判断就完成了,并确保数据的准确性,另外这种方法的抗干扰性 会非常好,而如果采用定时同步的话则会因信号的畸变而引起数据出错,整体会导致读卡几率降低 但是此程序也有其缺点,因为采用纯延时判断的手段,因此其占用单片机的运行时间比较大。 5).同步后开始接收同步数据即9个1,这一部分用一个循环做,如果出错则放弃接收 6).同步数据接收完后,则开始接收数据,数据分11行5列接收,以利于校验位的判断 如有出错则放弃数据 7).如一切正常则返回卡号,如因尝试读卡次数到了则返回0,表示没有卡 8).码元频率是载波频率的64分频,因此码元周期为:T=64/125000= 0.000512s=512us,因此3T/4=384us ********************************************************************************************/ #include #include //空操作指令需要此头文件 #define DELAYVAL 384 #define TIMEOUT 3000 //定义错误代码 #define ERR_NO 0x00 #define ERR_125KNOTFOUND 0x01 //控制EM4095的引脚 sbit MOD = P2^1; sbit SHD = P2^0; sbit DEMOD_OUT = P3^3; sbit RDY_CLK = P3^4; sbit BEEPLED = P1^5; //延时n*1us函数 void stc12_Delay1us(unsigned short n) { while(--n) { _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); } } //读取卡号, unsigned char decode_125kCard(unsigned char *buf) { unsigned char i=0; //起始为的计数值 unsigned short timeCount; //时间溢出的计数值 unsigned char timeOutFlag; //时间溢出标志 unsigned char row,col; //行列寄存器 unsigned char row_parity; //行校验寄存器 unsigned char col_parity[5]; //列校验寄存器 unsigned char dat; //数据寄存器 unsigned char searchCount=0; //搜索次数寄存器 unsigned char j; while(1) { timeCount=0; while(0==DEMOD_OUT)//等高电平 { if(timeCount==TIMEOUT) break;//超时退出 else timeCount++; } if(timeCount==1200) return ERR_125KNOTFOUND; else timeCount=0; stc12_Delay1us(DELAYVAL);//延时3/4码元,使电平判断时间正好处于高电平的中间 if(DEMOD_OUT)//寻找真正的起始位1,利用01的波形确定1起始位,即最后一位加第一位起始位 { for(i=0;i<8;i++)//判断是否是真的起始位,9个字节的1,因为前面已经判断了1位,因此此处只需判断8位即可 { timeCount=0; //限定等待时间 while(1==DEMOD_OUT)//等低电平,延时掉后面1/4码元的高电平 { if(timeCount==TIMEOUT) { timeOutFlag=1;//时间超时 break; //退出 } else { timeCount++; } } if(timeOutFlag)//如果高电平超时则退出 { break; } else { stc12_Delay1us(DELAYVAL); //延时至下一码元 if( 0==DEMOD_OUT ) break; } } if(timeOutFlag)//因时间溢出造成的本次主循环退出 { timeOutFlag=0; return ERR_125KNOTFOUND; } if(i==8) //起始位接收完并且正确后开始接收数据 { timeOutFlag=0; timeCount=0; //限定等待时间 while(1==DEMOD_OUT)//等低电平,延时掉第9bit起始位的后面1/4码元的高电平 { if(timeCount==TIMEOUT) { timeOutFlag=1; break; //时间溢出造成的出? } else { timeCount++; } if(timeOutFlag) { timeOutFlag=0; return ERR_125KNOTFOUND; } } //所有列校验清零 col_parity[0]=col_parity[1]=col_parity[2]=col_parity[3]=col_parity[4]=0; for(row=0;row<11;row++) //共11行数据 { row_parity = 0; j = row>>1;//每两行作为一个字节的数据 for(col=0,row_parity=0;col<5;col++)//共5列数据 { stc12_Delay1us(DELAYVAL); //延时至下一码元 if(DEMOD_OUT) dat=1; //数据为1 else dat=0; //数据为0 if(col<4&&row<10) //数据区的接受,后四个字节 { buf[j] <<= 1; buf[j] |= dat; } row_parity += dat; //行校验加入数据 col_parity[col] += dat; //相应列校验加入,虽最后一列没有校验但为了方便也加上 timeCount=0; //限定等待时间清零 while(DEMOD_OUT==(bit)dat) { if(timeCount==TIMEOUT) //由于时间溢出造成的数据出错 { timeOutFlag=1; break; //退出本while循环 } else { timeCount++; } } if(timeOutFlag)break; //出错退出内层for循环 } if(row<10)//最后一行没有校验所以要加限制 { if((row_parity&0x01)||timeOutFlag) //行校验出错或时间超时 { timeOutFlag=1; break; //退出 } } } //对最后接收的列校验进行判断,及对来自上面数据error_flag处理以结束本次主循环 //if(timeOutFlag||((col_parity[0]&0x01)&&(col_parity[1]&0x01)&&(col_parity[2]&0x01)&&(col_parity[3]&0x01))) if( timeOutFlag||(col_parity[0]&0x01)||(col_parity[1]&0x01)||(col_parity[2]&0x01)||(col_parity[3]&0x01) ) { //最后一列没有校验 timeOutFlag=0; return ERR_125KNOTFOUND; } else { return ERR_NO; } }//end if(i==8) return ERR_125KNOTFOUND; }//end if(DEMOD_OUT) } }

 

你可能感兴趣的:(EM4095与Manchester解码)