AB1601之125K ID卡读写代码

#include "DoorIdReader.h"




/*
#define ID_HALF_PERIOD_MAX 256//unit:us
#define ID_ONE_PERIOD_MAX     512
#define ID_WAIT_MAX         1000
#define ID_CARD_TIME       1000
*/


/*
#define ID_HALF_PERIOD_MAX (25+5)//unit:us
#define ID_ONE_PERIOD_MAX     (50+10)
#define ID_WAIT_MAX         (100+10)
#define ID_CARD_TIME       (100+10)
*/


///*
#define ID_HALF_PERIOD_MAX CLOCK_SYS_CLOCK_1US*(25+5)*10//unit:us
#define ID_ONE_PERIOD_MAX     CLOCK_SYS_CLOCK_1US*(50+10)*10
#define ID_WAIT_MAX         CLOCK_SYS_CLOCK_1US*(100+10)*10
#define ID_CARD_TIME       CLOCK_SYS_CLOCK_1US*(100+10)*10
//*/


/*
#define ID_HALF_PERIOD_MAX CLOCK_SYS_CLOCK_1US*(25+5)*15//unit:us
#define ID_ONE_PERIOD_MAX     CLOCK_SYS_CLOCK_1US*(50+10)*15
#define ID_WAIT_MAX         CLOCK_SYS_CLOCK_1US*(100+10)*15
#define ID_CARD_TIME       CLOCK_SYS_CLOCK_1US*(100+10)*15
*/


/*
#define ID_HALF_PERIOD_MAX CLOCK_SYS_CLOCK_1US*(25+5)*20//unit:us
#define ID_ONE_PERIOD_MAX     CLOCK_SYS_CLOCK_1US*(50+10)*20
#define ID_WAIT_MAX         CLOCK_SYS_CLOCK_1US*(100+10)*20
#define ID_CARD_TIME       CLOCK_SYS_CLOCK_1US*(100+10)*20
*/




/*
#define ID_HALF_PERIOD_MAX (256+10)//unit:us
#define ID_ONE_PERIOD_MAX     (512+20)
#define ID_WAIT_MAX         (1000+100)
#define ID_CARD_TIME       (1000+100)
*/




/*
#define ID_HALF_PERIOD_MAX (256+50)//unit:us
#define ID_ONE_PERIOD_MAX     (512+100)
#define ID_WAIT_MAX         (1000+100)
#define ID_CARD_TIME       (1000+100)
*/






#define ID_RFIN_PIN GPIO_GP23 //ok










static U32 RfBeginTime = 0;
static U8 Rf125kCardReadFlag = 0;








void SetRf125kCardReadFlag(U8 flag)
{
Rf125kCardReadFlag = flag;
}








U8 GetRf125kCardReadFlag(void)
{
return Rf125kCardReadFlag;
}








void DoorRfIoInit(void)
{


}






static U8 DoorGetRfIoState(void)
{
U8 ioValue;
U32 ioOriginState;
ioOriginState = gpio_read(ID_RFIN_PIN);
if(ioOriginState == 0x00000000)
{
ioValue = 0;
}
else
{
ioValue = 1;
}
return ioValue;
}










static U32 GetCounterCurrentValue(void)
{
U32 currentValue;
currentValue = clock_time();
return currentValue;
}








static U32 GetRfWaitedTime(void)
{
U32 currentValue;
currentValue = GetCounterCurrentValue();
if(currentValue >= RfBeginTime)
{
return  currentValue - RfBeginTime;
}
else
{
return (0xffffffff-RfBeginTime) + currentValue;
}
}




static U8 TestFlag1 = 0;
static U8 TestFlag2 = 0;


U8 DoorIdReadEm4001(U8 *serialNumber)
{
U8 i,j;
U8 retryCnt = 0;
U8 rfIoState;
U8 rfIoStateTmp;
U32 rfWaitedTime;
U8 dataB0;
U8 dataB1;
U8 dataB2;
U8 dataB3;
U8 dataB4;
U8 dataB5;
U8 dataB6;
U8 dataB7;
U8 lrcB0;
U8 lrcB1;
U8 lrcB2;
U8 lrcB3;
U8 checkSum;
U8 codedValueBit;
U8 tmpData;
rfIoState = DoorGetRfIoState();//记录口线历史状态
begin:
RfBeginTime = GetCounterCurrentValue();//设置时间基准
while(1)
{
rfIoStateTmp = DoorGetRfIoState();//获取口线实时状态
if(rfIoStateTmp == 1)
{


}
else
{
break;//等待低电平出现
}
rfWaitedTime = GetRfWaitedTime();//获取等待了的时间
if(rfWaitedTime > ID_ONE_PERIOD_MAX)//超时处理
{
TestFlag1 = 0xAA;
return 0;
}
TestFlag1 = 1;
}


rfIoState = DoorGetRfIoState();//记录口线历史状态(此时一定为低电平)
RfBeginTime = GetCounterCurrentValue();//设置时间基准
for(i=0; i<16; i++)//8个1,16个跳变,ID卡的头共9个1
{
while(1)
{
rfIoStateTmp = DoorGetRfIoState();//获取口线实时状态
if(rfIoStateTmp == rfIoState)
{


}
else
{
break;//发现跳变
}
rfWaitedTime = GetRfWaitedTime();//获取等待了的时间
if(rfWaitedTime > ID_ONE_PERIOD_MAX)//超时处理
{
TestFlag2 = 0xAA;
return 0;
}
}
rfWaitedTime = GetRfWaitedTime();//获取等待了的时间
if(rfWaitedTime > ID_HALF_PERIOD_MAX)//没有发现空跳变,则认为不是连续的9个1
{
retryCnt++;//找同步包头失败次数计数
if(retryCnt >= 64)
{
TestFlag2 = 0xAB;
return 0;
}
else
{
TestFlag2 = 0xAC;
goto begin;
}
}
rfIoState = DoorGetRfIoState();//记录口线历史状态
RfBeginTime = GetCounterCurrentValue();//设置时间基准
}


if(i == 16)
{


}
else
{
TestFlag2 = 0xAD;
return 0;
}



TestFlag2 = 0x01;




lrcB0 = 0;//第一列纵向校验和
lrcB1 = 0;
lrcB2 = 0;
lrcB3 = 0;
codedValueBit = 1;//预设下一个解码出来的数据位为1(前一个位的状态)
for(i=0; i<5; i++)//0 1 2 3 4(每行前4位是数据,最后1位为校验和)
{
tmpData = 0x00;
for(j=0; j<10; j++)//共10行
{
while(1)
{
rfIoStateTmp = DoorGetRfIoState();//获取口线实时状态
if(rfIoStateTmp == rfIoState)
{


}
else
{
break;//发现跳变
}
rfWaitedTime = GetRfWaitedTime();//获取等待了的时间
if(rfWaitedTime > ID_ONE_PERIOD_MAX)//超时处理
{
//printf("return 777777......\n");
return 0;
}
}
rfWaitedTime = GetRfWaitedTime();//获取等待了的时间
if(rfWaitedTime > ID_HALF_PERIOD_MAX)//没有空跳变,则跟预设值相反
{
codedValueBit = (~codedValueBit) & 0x01;
}
else//有空跳变,则跟预设值相同
{
rfIoState = DoorGetRfIoState();//记录口线历史状态
RfBeginTime = GetCounterCurrentValue();//设置时间基准
while(1)
{
rfIoStateTmp = DoorGetRfIoState();//获取口线实时状态
if(rfIoStateTmp == rfIoState)
{


}
else
{
break;//发现跳变
}
rfWaitedTime = GetRfWaitedTime();//获取等待了的时间
if(rfWaitedTime > ID_ONE_PERIOD_MAX)//超时处理
{
//printf("return 888888......\n");
return 0;
}
}
rfWaitedTime = GetRfWaitedTime();//获取等待了的时间
if(rfWaitedTime > ID_HALF_PERIOD_MAX)//超时处理
{
//printf("return 999999:%d %d......\n", i*5+j, rfWaitedTime);
//printf("%02x\n", tmpData);
return 0;
}
}
if(j==4 || j==9)//校验和处理
{
dataB0 = (tmpData >> 0) & 0x01;
dataB1 = (tmpData >> 1) & 0x01;
dataB2 = (tmpData >> 2) & 0x01;
dataB3 = (tmpData >> 3) & 0x01;
dataB4 = (tmpData >> 4) & 0x01;
dataB5 = (tmpData >> 5) & 0x01;
dataB6 = (tmpData >> 6) & 0x01;
dataB7 = (tmpData >> 7) & 0x01;
checkSum = (dataB0^dataB1^dataB2^dataB3) & 0x01;
if(checkSum == codedValueBit)
{


}
else//校验和出错
{
//printf("return aaaaaa......\n");
return 0;
}
}
else//数据位处理
{
tmpData = tmpData << 1;
tmpData = tmpData | codedValueBit;
}
rfIoState = DoorGetRfIoState();//记录口线历史状态
RfBeginTime = GetCounterCurrentValue();//设置时间基准
}//for(j....)
lrcB0 = (lrcB0 ^ dataB0 ^ dataB4) & 0x01;//计算纵向校验和
lrcB1 = (lrcB1 ^ dataB1 ^ dataB5) & 0x01;
lrcB2 = (lrcB2 ^ dataB2 ^ dataB6) & 0x01;
lrcB3 = (lrcB3 ^ dataB3 ^ dataB7) & 0x01;
serialNumber[i] = tmpData;
}//for(i....)






if(i == 5)
{


}
else
{
//printf("return xxxxxx......\n");
return 0;
}
tmpData = 0;
for(i=0; i<5; i++)//4个纵向校验和与结束位(0)
{
while(1)
{
rfIoStateTmp = DoorGetRfIoState();//获取口线实时状态
if(rfIoStateTmp == rfIoState)
{


}
else
{
break;//发现跳变
}
rfWaitedTime = GetRfWaitedTime();//获取等待了的时间
if(rfWaitedTime > ID_ONE_PERIOD_MAX)//超时处理
{
//printf("return xxxxxx111......\n");
return 0;
}
}


rfWaitedTime = GetRfWaitedTime();//计算等待了的时间
if(rfWaitedTime > ID_HALF_PERIOD_MAX)//没有空跳变,则跟预设值相反
{
codedValueBit = (~codedValueBit) & 0x01;
}
else//有空跳变,则跟预设值相同
{
rfIoState = DoorGetRfIoState();//记录口线历史状态
RfBeginTime = GetCounterCurrentValue();//设置时间基准
while(1)
{
rfIoStateTmp = DoorGetRfIoState();//获取口线实时状态
if(rfIoStateTmp == rfIoState)
{


}
else
{
break;//发现跳变
}
rfWaitedTime = GetRfWaitedTime();//获取等待了的时间
if(rfWaitedTime > ID_ONE_PERIOD_MAX)//超时处理
{
//printf("return xxxxxx222......\n");
return 0;
}
}
rfWaitedTime = GetRfWaitedTime();//获取等待了的时间
if(rfWaitedTime > ID_HALF_PERIOD_MAX)//超时处理
{
//printf("return xxxxxx333......\n");
return 0;
}
}
if(i == 4)//结束位检查是否为0
{
if(codedValueBit == 0)
{


}
else
{
//printf("return xxxxxx444......\n");
return 0;
}
dataB0 = (tmpData >> 0) & 0x01;
dataB1 = (tmpData >> 1) & 0x01;
dataB2 = (tmpData >> 2) & 0x01;
dataB3 = (tmpData >> 3) & 0x01;
dataB4 = (tmpData >> 4) & 0x01;
dataB5 = (tmpData >> 5) & 0x01;
dataB6 = (tmpData >> 6) & 0x01;
dataB7 = (tmpData >> 7) & 0x01;
}
else//校验位
{
tmpData = tmpData << 1;
tmpData = tmpData | codedValueBit;
}
rfIoState = DoorGetRfIoState();//记录口线历史状态
RfBeginTime = GetCounterCurrentValue();//设置时间基准
}//for(i.....)
if( (lrcB0 == dataB0) &&
(lrcB1 == dataB1) &&
(lrcB2 == dataB2) &&
(lrcB3 == dataB3))
{


}
else//纵向校验出错
{
//printf("return xxxxxx555......\n");
return 0;
}
//printf("return yyyyyy......\n");


if( (serialNumber[0] == 0x00) &&
(serialNumber[1] == 0x00) &&
(serialNumber[2] == 0x00) &&
(serialNumber[3] == 0x00) &&
(serialNumber[4] == 0x00))
{
//printf("return zzzzzz......\n");
return 0;//失败
}
else
{
/*
U32 cardNumber;
printf("125k card serial number:%02x %02x %02x %02x %02x \n", serialNumber[0], serialNumber[1], serialNumber[2], serialNumber[3], serialNumber[4]);
cardNumber = serialNumber[1];
cardNumber = (cardNumber << 8) | serialNumber[2];
cardNumber = (cardNumber << 8) | serialNumber[3];
cardNumber = (cardNumber << 8) | serialNumber[4];
printf("125k card number:%lu\n\n", cardNumber);
*/
return 1;//成功读出卡号
}
}






U8 DoorIdIntervalTime = 0x00;


U8 serialNumber[8];
static U8 DoorRdIdErrCnt = 100;
void DoorIdReadEm4001Test(void)
{
U8 ret;
//U8 serialNumber[8];
if(DoorIdIntervalTime == 0x00)
{


}
else
{
return;
}
ret = DoorIdReadEm4001(serialNumber);
if(ret == 1)
{
//if(DoorRdIdErrCnt >= 1)
{
LightOnlyTipsMode2();
}
DoorRdIdErrCnt = 0x00;
DoorIdIntervalTime = 100;//1s
}
else
{
//printf("err11...\n");
if(DoorRdIdErrCnt < 0xff)
{
DoorRdIdErrCnt++;
}
DoorIdIntervalTime = 1;//10ms
return;
}
}












static U8 OldIdSerialNumber[8] = {0x00, 0x00, 0x00, 0x00, 0x00,};
static U8 DoorIdSerialNumberCmp(U8 *currentIdSerialNumber)
{
U8 i;
for(i=0; i<5; i++)
{
if(OldIdSerialNumber[i] == currentIdSerialNumber[i])
{
continue;
}
return 0;
}
return 1;
}








static void DoorIdSerialNumberSave(U8 *currentIdSerialNumber)
{
U8 i;
for(i=0; i<5; i++)
{
OldIdSerialNumber[i] = currentIdSerialNumber[i];
}
}








U8 GetOk_F(void)
{
return 0;
}






void CarNoMsg(u8 *CarNo)
{


}












void DoorIdReadEm4001Deal(void)
{
U8 ret;
U8 cmpFlag;
U8 serialNumber[8];
    U8 UID[4];
    if(GetOk_F())
return;
ret = DoorIdReadEm4001(serialNumber);




/*
DOOR_PRINT("DoorIdReadEm4001:%d\n", ret);


//only for test
{
if(ret == 1)
{
U32 cardNumber;
DOOR_PRINT("125k card serial number:%02x %02x %02x %02x %02x \n", serialNumber[0], serialNumber[1], serialNumber[2], serialNumber[3], serialNumber[4]);
cardNumber = serialNumber[1];
cardNumber = (cardNumber << 8) | serialNumber[2];
cardNumber = (cardNumber << 8) | serialNumber[3];
cardNumber = (cardNumber << 8) | serialNumber[4];
DOOR_PRINT("125k card number:%lu\n\n", cardNumber);
}
}
return;
*/








if(ret == 1)
{
   DoorRdIdErrCnt = 0x00; 
cmpFlag = DoorIdSerialNumberCmp(serialNumber);
if(cmpFlag == 1)//THE SAME AS LAST TIME
{
/*if(DoorRdIdErrCnt >= 3)
{
goto READ_ID_OK;
}
else
{
return;
}*/
return;  
}
else
{
//DoorRdIdErrCnt = 0x00;
DoorIdSerialNumberSave(serialNumber);
}


//READ_ID_OK:
//DoorRdIdErrCnt = 0x00;
//LightOnlyTipsMode2();
//VoiceOnlyTipsMode2();


/*
memrecpy(UID,serialNumber,4);
DoorRs485SetNewSerialNumber(serialNumber+1);//第一个字节不是卡号
//only for test
{
U32 cardNumber;
DOOR_PRINT("125k card serial number:%02x %02x %02x %02x %02x \n", serialNumber[0], serialNumber[1], serialNumber[2], serialNumber[3], serialNumber[4]);
cardNumber = serialNumber[1];
cardNumber = (cardNumber << 8) | serialNumber[2];
cardNumber = (cardNumber << 8) | serialNumber[3];
cardNumber = (cardNumber << 8) | serialNumber[4];
DOOR_PRINT("125k card number:%lu\n\n", cardNumber);
}
*/

        CarNoMsg(UID);
}
else
{
//printf("err11...\n");
DoorRdIdErrCnt++;
if(DoorRdIdErrCnt >50)
{
   DoorRdIdErrCnt=0;
   memset(serialNumber,0,5);
   DoorIdSerialNumberSave(serialNumber);
}
return;
}
}



  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RFID模块原理图是ORCAD的,有PDF预览,PCB是PADS的,还有BOM烧写说明,标注图等。其中UART输出是量产过的 韦根输出的只是看示波器波形是对的,没有实际应用;里面有源代码,编写前提是是CODE小于1K RAM小于64字节。 原理图原理就是CD4060产生125KHZ的方波,经过推挽电路进行功率放大,高频电流进入LC串联谐振电路,345uH和4.7NF的谐振频率正好是125KHZ,这时电容两端电压会到十几伏,如果用CBB电容,会到二十多伏,这时读距离会到10CM以上。当有接近线圈时,线圈两端会有曼彻斯特编码的调幅波。通过二极管以及电容的检波和滤波,产生的小信号送入LM358进行放大和整形,变成单片机可以读取的曼彻斯特编码信号。 关于硬件电路设计上,CD4060在3.3V时 4M以下的晶振都可以起振,但2M的晶振体积很大,所以用了4M。实验发现ATTINY13的频率随着工作电压的变化会有很大的变化,所以不能用RC校准了,正好CD4060会输出4M,所以用来当系统时钟,保证时序的精确性。这样模块在3.3V 5V都能工作。 ATTINY13接不了无缘晶振 只能接有源的~ 它只有一个CLKIN脚~有源晶振价格就贵了。 另外ATTINY13只有5个IO口 1个用于中断 1个用于UART输出 1个用于CLKIN 1个用于上电波特率配置 1个用于曼彻斯特编码输入 正好用完了 RFID模块 模块正反面 串口收到5个字节 前4个字节就是号 程序中,根据曼彻斯特原理,找到长电平和短电平,根据跳变沿分析出0数据还是1数据。然后寻找消息头,后面的数据进行 行 列奇偶校验,从而分析出号。 程序上电时,通过ADC引脚读取外部电阻的分压配置,从而初始化出4中波特率。然后进行读操作。实际应用中,要保证读的稳定,当靠近线圈时,要只发一次数据。要很好的去抖。代码不能超过1K。现在代码正好1024个字节。关于奇偶校验算法,异或和要比对2取余简洁,但我测试时发现异或和代码长度大于对2取余,所以用了对2取余。 RFID模块原理图+PCB+代码+调试至附件下载
125kHZ低频读器功能概述: 本资源中包含读器原理图及PCB文件、读器源程序和电脑端上位机源程序。读器可以直接制作使用,可以使用附件中的上位机与读器进行通信,控制读器对T5557类片进行读写操作。对T5557片的配置必须为(RF/32,曼侧斯特编码),这也是国内T5557的常用配置。要对其他配置的T5557片或其他低频片(EM4305类和EMID片)进行读写,硬件上是支持的,只需根据片文档修改读器源程序,下载更新便可。为方便程序更新,硬件电路上已经实现自动下载,使用串口下载程序时无需手动设置BOOT0和BOOT1。 应用场景: 低频RFID主要用在短距离、低成本的应用中,如门禁控制、校园、煤气表、水表等。 在相关领域的开发中,可以使用该读器作为前台管理的设备,对客户进行管理。也可以将读器改成终端设备,如RFID门锁上的读器,用来验证片信息并控制门锁;或煤气表、水表上的读器,根据片内的余量信息控制煤气和水的供应。另外,也可以作为学习曼彻斯特解码的学习工具。 设计思路: 使用STM32F103R8T6输出125kHZ的PWM信号作为载波信号,将信号输入到功率放大电路,在线圈上产生125kHZ的正弦信号。T5557片从125kHZ信号中获取能量和控制命令,并根据命令将要传回的信息使用曼彻斯特编码对载波信号进行调制。读器端的检波电路和滤波放大电路将被调制信号提取处理成单片机能识别的数字信号,输入到STM32F103R8T6的输入捕获功能引脚,再通过STM32F103R8T6将捕获的信号进行曼彻斯特解码,最后将解码信息根据自己设定的通讯协议进行数据打包,发送到电脑上位机。 系统框图: 硬件平台: 1.主控制器:STM32F103R8T6 2.USB转TTL:CH340G 3.模拟电路:LM358 AMS1117-3.3V 125kHZ谐振线圈(345UH线圈搭配4700PF电容)谐振频率在线计算工具 4.蜂鸣器: 3V供电 软件平台: 开发工具:Keil uVision5 上位机编写工具:Microsoft Visual C# 学习版 成本估算: 芯片询价和在线购买链接https://www.bom2buy.com/元器件估算价格约为30元 项目进度: 1.能对AT5557/55567/5577片(配置为RF/32,曼彻斯特编码)进行整页读,密码读和密码写操作; 2.有相应的上位机,方便读写指令的发送和数据解读; 3.上位机与读器之间通讯加入了数据校验,提高了通讯的可靠性。 未来更新: 1.加入EM4305类和EMID片的读写功能; 2.加上触摸显示屏和电池,做成便携版 3.做成袖珍版,加入与手机通讯的接口(OTG或蓝牙)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值