在ARM板上通过防碰撞指令获取高频RFID卡的卡号
高频RFID一般频率在13.56MHz左右,识别距离可扩展至1.5米,具有防碰撞特性,可以同时读取多个电子标签。标签可以存储少量数据,多用于需要存储数据、近距离的识别应用,如:图书馆管理系统、场地通道安全管理系统等。
mifare522模块的数据帧格式
gec6818开发板读取卡号完整代码(直接运行即可):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h> //串口配置需要的头文件
/*
* init_serial:自定义的用来打开串口文件并对串口进行初始化的函数
* arg:
* @fild:串口设备文件名,指定您要使用的串口
* @baudrate:整数,指定您要配置的串口的通信波特率
* 9600/115200/19200
* 配置的串口协议:数据位8,停止位1,不要校验,不要硬件控制流
* return:
* 成功,返回打开 并初始化好的 串口的文件描述符,后期根据该返回值来与链接在该串口上的传感器进行通信
* 失败返回-1
**/
unsigned int card_ID;
int init_serial(const char *file, int baudrate)
{
int fd;
fd = open(file, O_RDWR);
if (fd == -1)
{
perror("open device error:");
return -1;
}
struct termios myserial;
//清空结构体
memset(&myserial, 0, sizeof (myserial));
//O_RDWR
myserial.c_cflag |= (CLOCAL | CREAD);
//设置控制模式状态,本地连接,接受使能
//设置 数据位
myserial.c_cflag &= ~CSIZE; //清空数据位
myserial.c_cflag &= ~CRTSCTS; //无硬件流控制
myserial.c_cflag |= CS8; //数据位:8
myserial.c_cflag &= ~CSTOPB;// //1位停止位
myserial.c_cflag &= ~PARENB; //不要校验
//myserial.c_iflag |= IGNPAR; //不要校验
//myserial.c_oflag = 0; //输入模式
//myserial.c_lflag = 0; //不激活终端模式
switch (baudrate)
{
case 9600:
cfsetospeed(&myserial, B9600); //设置波特率
cfsetispeed(&myserial, B9600);
break;
case 115200:
cfsetospeed(&myserial, B115200); //设置波特率
cfsetispeed(&myserial, B115200);
break;
case 19200:
cfsetospeed(&myserial, B19200); //设置波特率
cfsetispeed(&myserial, B19200);
break;
}
/* 刷新输出队列,清除正接受的数据 */
tcflush(fd, TCIFLUSH);
/* 改变配置 */
tcsetattr(fd, TCSANOW, &myserial);
return fd;
}
unsigned char CalBCC(unsigned char *buf, int n)
{
int i;
unsigned char bcc=0;
for(i=0;i<n;i++)
{
bcc ^=*(buf+i);
}
return (~bcc);
}
int PiccRequest (int fd)
{
unsigned char WBuf[10];
unsigned char RBuf[10];
memset(WBuf,0,sizeof(WBuf));
memset(RBuf,0,sizeof(RBuf));
WBuf[0] = 0x07; //帧长= 7 Byte
WBuf[1] = 0x02; //包号= 0,命令类型= 0x02
WBuf[2] ='A' ;//命令= 'A'
WBuf[3] = 0x01; //信息长度= 1
WBuf[4] = 0x52; //请求模式:ALL=0x52
WBuf[5] = CalBCC(WBuf,5);//校验和
WBuf[6] = 0x03; //结束标志
write(fd,WBuf, 7) ; //发送命令
usleep (100000) ; //延时等待
int ret = read(fd, RBuf,8);//接收回复数据
if(ret == 8)
{
return RBuf[2];//返回状态值,若为0,表示请求成功
}
else
{
printf ("read error, ret:%d\n",ret) ;
return -1 ;
}
}
int PiccAnticoll(int fd)
{
unsigned char RBuf[10];
unsigned char WBuf[10];
memset(WBuf,0,sizeof(WBuf));
memset(RBuf,0,sizeof(RBuf));
WBuf[0] = 0x08; //帧长= 8 Byte
WBuf[1] = 0x02; //包号= 0,命令类型= 0x02
WBuf[2] = 'B'; //命令= 'B '
WBuf[3] = 0x02; //信息长度= 2
WBuf[4] = 0x93; //防碰撞0x93 --- - 级防碰撞
WBuf[5] = 0x00; //位计数0
WBuf[6] = CalBCC (WBuf,6) ; //校验和
WBuf[7] = 0x03 ;//结束标志
write (fd, WBuf,8);
usleep(50000) ;
int ret = read(fd,RBuf,10) ;
if (RBuf[2] == 0x00) //应答帧状态部分为0则获取ID成功
{
card_ID = (RBuf[7]<<24)| (RBuf[6]<<16) | (RBuf[5]<<8) | RBuf[4] ;
printf ("PiccAnticoll The card ID is %u\n",card_ID) ;
return 0 ;
}
}
int main(int argc, char const *argv[])
{
int uart1_fd = init_serial("/dev/ttySAC1" ,9600) ;//打开并初始化串口
while (1){
if (PiccRequest (uart1_fd) )//请求天线范围的卡
{
printf("The Request Failed!\n");
continue;
}
if (PiccAnticoll (uart1_fd))//进行防碰撞,获取天线范围内最大的ID
{
printf("2 RFID PicCAnticoll Failed!\n");
break;
}
printf("card ID is %u \n" ,card_ID);
break;
}
close (uart1_fd) ;
if(card_ID == 2773529475)
return 1;
else
return -1;
}
关于RFID高频读卡器的模块资料我都打包好了,放在下载资源里面,想认真学习的可自行下载,里面包括了读卡案例代码和可执行文件等详细资料。
stm32驱动代码实例:
代码太多,以下提供了一些常用操作指令代码,这些代码可移植性很强,方便大家直接调用。你们也可以结合自己的需要去使用。比如搞一个门禁系统,校园卡,图书管理系统,智能家居系统,车辆管理系统等
串口通信代码:
int init_serial(const char *file, int baudrate)
{
int fd;
fd = open(file, O_RDWR);
if (fd == -1)
{
perror("open device error:");
return -1;
}
struct termios myserial;
//清空结构体
memset(&myserial, 0, sizeof (myserial));
//O_RDWR
myserial.c_cflag |= (CLOCAL | CREAD);
//设置控制模式状态,本地连接,接受使能
//设置 数据位
myserial.c_cflag &= ~CSIZE; //清空数据位
myserial.c_cflag &= ~CRTSCTS; //无硬件流控制
myserial.c_cflag |= CS8; //数据位:8
myserial.c_cflag &= ~CSTOPB;// //1位停止位
myserial.c_cflag &= ~PARENB; //不要校验
//myserial.c_iflag |= IGNPAR; //不要校验
//myserial.c_oflag = 0; //输入模式
//myserial.c_lflag = 0; //不激活终端模式
switch (baudrate)
{
case 9600:
cfsetospeed(&myserial, B9600); //设置波特率
cfsetispeed(&myserial, B9600);
break;
case 115200:
cfsetospeed(&myserial, B115200); //设置波特率
cfsetispeed(&myserial, B115200);
break;
case 19200:
cfsetospeed(&myserial, B19200); //设置波特率
cfsetispeed(&myserial, B19200);
break;
}
/* 刷新输出队列,清除正接受的数据 */
tcflush(fd, TCIFLUSH);
/* 改变配置 */
tcsetattr(fd, TCSANOW, &myserial);
return fd;
}
常用操作代码:
#include "stm32f10x.h"
#include "usart3.h"
#include "usart.h"
#include "rfid.h"
#include "stdio.h"
unsigned char Uart3RxBuf[UART3_RX_BUF_LEN];
unsigned char Uart3RxDataConut = 0;
unsigned char Rx3Flag = 0;
unsigned char Cmd_Read_Id[8] = {0x01,0x08,0xa1,0x20,0x00,0x00,0x00,0x00};
unsigned char Cmd_Read_Block[8] = {0x01,0x08,0xa3,0x20,0x00,0x00,0x00,0x00};
unsigned char Cmd_Write_Block[23] = {0x01,0x17,0xa4,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
unsigned char WBlockData[16] = {0x11,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
//CircularBuffer *Uart2_Circular_Buffer;
unsigned char Cmd_Write_RFID[0x0B]={0x03, 0x0B, 0xC5, 0x20, 0x05, 0x12, 0x34, 0x56, 0x78, 0x09, 0x16};
// 命令类型 包长度 命令 设备地址 起始地址 数据长度 保留 校验和
unsigned char Cmd_Read_RFID[]={0x02, 0x08, 0xB5, 0x20, 0x03, 0x06, 0x00, 0x65};
//延时,10000000大约为1S
void Delay(__IO unsigned int nCount)
{
for (; nCount != 0; nCount--);
}
void Uart3_Send_Data(unsigned char *buf,unsigned char num)
{
unsigned char i;
for(i=0;i<num;i++)
{
USART_SendData(USART3, buf[i]);
while (USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET);
}
}
unsigned char RxCheckSum(unsigned char *ptr,unsigned char len) //计算校验值
{
unsigned char i;
unsigned char checksum;
checksum = 0;
for(i=0;i<(len-1);i++)
{
checksum ^= ptr[i];
}
checksum = ~checksum;
if(ptr[len-1] == checksum)
return STATUS_OK;
else
return STATUS_ERR;
}
void TxCheckSum(unsigned char *ptr,unsigned char len)
{
unsigned char i;
unsigned char checksum;
checksum = 0;
for(i=0;i<(len-1);i++)
{
checksum ^= ptr[i];
}
checksum = ~checksum;
ptr[len-1] = checksum;
}
//ReadId():读IC卡ID号(卡号)
//参数:*idout,读取的卡号保存到它所指向的存储空间
//返回值:0:成功读取卡号,1:读卡号失败
unsigned char ReadId(void)
{
unsigned char status;
unsigned char i;
unsigned char idout[6];
Cmd_Read_Id[5] = 0x01;//开启蜂鸣器提示
//Cmd_Read_Id[5] = 0x00;//关闭蜂鸣器提示
TxCheckSum(Cmd_Read_Id,Cmd_Read_Id[1]); //计算校验和
Uart3_Send_Data(Cmd_Read_Id,Cmd_Read_Id[1]); //发送读卡号ID命令
Delay(2000000);//等待模块返回数据,大于150MS
if(Rx3Flag == 1)
{
Rx3Flag = 0;
status = RxCheckSum(Uart3RxBuf,Uart3RxBuf[1]);//对接收到的数据校验
if(status != STATUS_OK) //判断校验和是否正确
{
return STATUS_ERR;
}
status = Uart3RxBuf[4];
if(status != STATUS_OK) //判断是否正确的读到卡
{
return STATUS_ERR;
}
if((Uart3RxBuf[0] == 0x01)&&(Uart3RxBuf[2] == 0xa1))//判断是否为读卡号返回的数据包
{
for(i=0;i<6;i++)//获取卡号ID,6字节
{
idout[i] = Uart3RxBuf[i+5];//从数组的第5个字节开始为卡号,长度为6字节
}
for(i=0;i<6;i++)
{
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET); //Ñ»··¢ËÍ,Ö±µ½·¢ËÍÍê±Ï
USART_SendData(USART1,idout[i]);
}
return STATUS_OK; //成功返回0
}
}
return STATUS_ERR; //失败返回1
}
//ReadId():读IC卡数据块
//参数:*idout,读取的数据保存到它所指向的存储空间
//参数:block,块号
//返回值:0:成功读取,1:读读取失败
unsigned char ReadDataFromBlock(unsigned char *dataout,unsigned char block)
{
unsigned char status;
unsigned char i;
Cmd_Read_Block[4] = block;
Cmd_Read_Block[5] = 0x01;//开启蜂鸣器提示
// Cmd_Read_Block[5] = 0x00;//关闭蜂鸣器提示
TxCheckSum(Cmd_Read_Block,Cmd_Read_Block[1]); //数据校验
Uart3_Send_Data(Cmd_Read_Block,Cmd_Read_Block[1]); //发送读数据块命令
Delay(2000000);//等待模块返回数据,大于150MS
if(Rx3Flag == 1)
{
Rx3Flag = 0;
status = RxCheckSum(Uart3RxBuf,Uart3RxBuf[1]);//对接收到的数据校验
if(status != STATUS_OK) //判断校验和是否正确
{
return STATUS_ERR;
}
status = Uart3RxBuf[4]; //获取返回包状态
if(status != STATUS_OK) //判断是否正确的读到卡
{
return STATUS_ERR;
}
if((Uart3RxBuf[0] == 0x01)&&(Uart3RxBuf[2] == 0xa3))//判断是否为读块数据返回的数据包
{
for(i=0;i<16;i++)//获取块数据,16字节 ,一个数据块的大小为16字节
{
dataout[i] = Uart3RxBuf[i+5];//从数组的第5个字节开始为数据,长度为16字节
}
return STATUS_OK; //成功返回0
}
}
return STATUS_ERR; //失败返回1
}
//ReadId():写数据到指定的数据块
//参数:*idout,指向要写入数据的缓冲区
//参数:block,块号
//返回值:0:写入成功,1:写入失败
unsigned char WriteDataToBlock(unsigned char *datain,unsigned char block)
{
unsigned char status;
unsigned char i;
Cmd_Write_Block[4] = block;
for(i=0;i<16;i++)
{
Cmd_Write_Block[6+i] = datain[i];
}
TxCheckSum(Cmd_Write_Block,Cmd_Write_Block[1]); //数据校验
Uart3_Send_Data(Cmd_Write_Block,Cmd_Write_Block[1]); //发送写命令
Delay(2000000);//等待模块返回数据,大于150MS
if(Rx3Flag == 1)
{
Rx3Flag = 0;
status = RxCheckSum(Uart3RxBuf,Uart3RxBuf[1]);//对返回的数据进行校验
if(status != STATUS_OK) //判断校验是否通过
{
return STATUS_ERR;
}
status = Uart3RxBuf[4];
if(status != STATUS_OK) //判断校验是否通过
{
return STATUS_ERR;
}
if((Uart3RxBuf[0] == 0x01)&&(Uart3RxBuf[2] == 0xa4))//判断是否为写块数据返回的数据包
{
return STATUS_OK; //成功返回0
}
}
return STATUS_ERR; //失败返回1
}
//读RFID用户空间
unsigned char Read_RFID(unsigned char addr,unsigned char len)
{
unsigned char status;
unsigned char i;
Cmd_Read_RFID[4]=addr;
Cmd_Read_RFID[5]=len;
TxCheckSum(Cmd_Read_RFID,Cmd_Read_RFID[1]); //计算校验和
Uart3_Send_Data(Cmd_Read_RFID,Cmd_Read_RFID[1]); //发送读用户数据命令
Delay(2000000);//等待模块返回数据,大于150MS
if(Rx3Flag == 1)
{
Rx3Flag = 0;
status = RxCheckSum(Uart3RxBuf,Uart3RxBuf[1]);//对接收到的数据校验
if(status != STATUS_OK) //判断校验和是否正确
{
return STATUS_ERR;
}
status = Uart3RxBuf[4];
if(status != STATUS_OK) //判断是否正确的读到卡
{
return STATUS_ERR;
}
if((Uart3RxBuf[0] == 0x02)&&(Uart3RxBuf[2] == 0xB5))//判断是否为读RFID用户信息返回的数据包
{
for(i=0;i<Cmd_Read_RFID[5];i++) //将读取的RFID打印到串口
{
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);
USART_SendData(USART1,Uart3RxBuf[i+5]);
}
return STATUS_OK; //成功返回0
}
}
return STATUS_ERR;
}
//写RFID 用户空间
unsigned char Write_RFID(unsigned char addr,unsigned char * data,unsigned char len)
{
unsigned char status;
unsigned char i;
unsigned char cmd[22]={0x03, 0x0B, 0xC5, 0x20};
cmd[4] =addr;//地址
cmd[1]=6+len;//长度
for(i=0;i<len;i++)
{
cmd[5+i] = data[i];
}
TxCheckSum(cmd,cmd[1]); //数据校验
Uart3_Send_Data(cmd,cmd[1]); //发送写命令
Delay(2000000);//等待模块返回数据,大于150MS
if(Rx3Flag == 1)
{
Rx3Flag = 0;
status = RxCheckSum(Uart3RxBuf,Uart3RxBuf[1]);//对返回的数据进行校验
if(status != STATUS_OK) //判断校验是否通过
{
return STATUS_ERR;
}
status = Uart3RxBuf[4];
if(status != STATUS_OK) //判断校验是否通过
{
return STATUS_ERR;
}
if((Uart3RxBuf[0] == 0x03)&&(Uart3RxBuf[2] == 0xc5))//判断是否为写块数据返回的数据包
{
for(i=0;i<len;i++) //将写入的数据打印到串口
{
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);
USART_SendData(USART1,cmd[i+5]);
}
return STATUS_OK; //成功返回0
}
}
return STATUS_ERR; //失败返回1
}