RFID
一,硬件选择
STM32F407ZGT6主控芯片
开发环境
正点原子探索者开发板
基于RC522的RFID
原理图
EPPROM 24C02
原理图
二,通信方式
一,SPI通信
1.什么是SPI?
SPI是 串行外设接口( Serial Peripheral Interface) , 是一种高速的,全双工,同步的通信总线
2、SPI优点
支持全双工通信
通信简单
数据传输速率块
3、缺点
没有指定的流控制,没有应答机制确认是否接收到数据,所以跟IIC总线协议比较在数据
可靠性上有一定的缺陷。
4、SPI模式
CPOL:时钟极性
CPHA:时钟相位
SPI_MODE
MODE0:CPOL=0;CPHA=0;
MODE1:CPOL=0;CPHA=1;
MODE2:CPOL=1;CPHA=0;
MODE3:CPOL=1;CPHA=1;
CPOL=0,CPHA=0:此时空闲态时,SCLK处于低电平,数据采集是在第1个边沿,也就是SCLK由低电平到高电平的跳变,所以数据采样是在上升沿,数据发送是在下降沿。
CPOL=0,CPHA=1:此时空闲态时,SCLK处于低电平,数据采集是在第2个边沿,也就是SCLK由低电平到高电平的跳变,所以数据采样是在下降沿,数据发送是在上升沿。
CPOL=1,CPHA=0:此时空闲态时,SCLK处于高电平,数据采集是在第1个边沿,也就是SCLK由高电平到低电平的跳变,所以数据采集是在下降沿,数据发送是在上升沿。
CPOL=1,CPHA=1:此时空闲态时,SCLK处于高电平,数据采集是在第2个边沿,也就是SCLK由高电平到低电平的跳变,所以数据采集是在上升沿,数据发送是在下降沿。
RC522手册提及MOSI上的数据在时钟上升沿保持不变,在时钟的下降沿改变,(上升沿采集,下降沿发送)即其SPI模式为MODE0
5、C代码初始化
void SPI3_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能GPIOA时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);//使能GPIOC时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE);//使能SPI3时钟
//SDA RST
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_PinSource6;//
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化
//CLK MISO MOSI
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化
GPIO_PinAFConfig(GPIOC,GPIO_PinSource12,GPIO_AF_SPI3);
GPIO_PinAFConfig(GPIOC,GPIO_PinSource11,GPIO_AF_SPI3);
GPIO_PinAFConfig(GPIOC,GPIO_PinSource10,GPIO_AF_SPI3);
//这里只针对SPI口初始化
RCC_APB1PeriphResetCmd(RCC_APB1Periph_SPI3,ENABLE);//复位SPI3
RCC_APB1PeriphResetCmd(RCC_APB1Periph_SPI3,DISABLE);//停止复位SPI3
MYRC522_CS = 1;
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
//设置SPI工作模式: 设置为主SPI
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
//设置SPI的数 据大小:SPI发送接收8位帧结构
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
//串行同步时钟的空闲状态 为低电平
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
//串行同步时钟的第一个跳变沿(上升或下降)数据被采样
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
//NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32; //定义波特率预分频的值:波特率预分频值为32
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
//指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
SPI_InitStructure.SPI_CRCPolynomial = 7;
//CRC值计算的多项式
SPI_Init(SPI3, &SPI_InitStructure);
//根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
SPI_Cmd(SPI3, ENABLE); //使能SPI外设
SPIWriteByte(0xff);//启动传输
}
二,IIC通信
1.什么为IIC?
IIC(Inter-Integrated Circuit)总线是一种由 PHILIPS 公司开发的两线式串行线,用于连接微控制器及其外围设备。它是由数据线 SDA 和时钟 SCL 构成的串行总线,可发送和接收数据。在 CPU 与被控 IC 之间、 IC 与 IC 之间进行双向传送, 高速 IIC 总线一般可达 400kbps 以上。
2.优点
只需SDA ,SCL即可实现通信,且可以有应答信号!
3.缺点
是半双工,速度慢
4.IIC通信流程
总线空闲状态 :
SDA :高电平
SCL :高电平
起始位:SCL为高电平期间 SDA出现下降沿
终止位:SCL为高电平期间 SDA出现上升沿
数据传输 :SDA的数据在SCL高电平期间被写入从机。所以SDA的数据变化要发生在SCL低电平期间。
5.C语言代码初始化
void IIC_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
//使能GPIOB时钟
//GPIOB8,B9初始化设置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
IIC_SCL=1;
IIC_SDA=1;
}
二,硬件连接
RC522 --> SPI3接口
SDA --> GPIOA4
RST --> GPIOA6
CLK --> GPIOC10
MISO --> GPIOC11
MOSI --> GPIOC12
三,代码讲解
一,RC522读写代码讲解
/
//功 能:读RC632寄存器
//参数说明:Address[IN]:寄存器地址
//返 回:读出的值
/
u8 ReadRawRC(u8 Address)
{
u8 ucAddr;
u8 ucResult=0;
MYRC522_CS=0;
ucAddr = ((Address<<1)&0x7E)|0x80;
SPIWriteByte(ucAddr);
ucResult=SPIReadByte();
MYRC522_CS=1;
return ucResult;
}
/
//功 能:写RC632寄存器
//参数说明:Address[IN]:寄存器地址
// value[IN]:写入的值
/
void WriteRawRC(u8 Address, u8 value)
{
u8 ucAddr;
MYRC522_CS=0;
ucAddr = ((Address<<1)&0x7E);
SPIWriteByte(ucAddr);
SPIWriteByte(value);
MYRC522_CS=1;
}
/
//功 能:置RC522寄存器位
//参数说明:reg[IN]:寄存器地址
// mask[IN]:置位值
/
void SetBitMask(u8 reg,u8 mask)
{
char tmp = 0x0;
tmp = ReadRawRC(reg);
WriteRawRC(reg,tmp | mask); // set bit mask
}
/
//功 能:清RC522寄存器位
//参数说明:reg[IN]:寄存器地址
// mask[IN]:清位值
/
void ClearBitMask(u8 reg,u8 mask)
{
char tmp = 0x0;
tmp = ReadRawRC(reg);
WriteRawRC(reg, tmp & ~mask); // clear bit mask
}
RC522手册读写地址规则为第七位MSB为1则为读,MSB为0则为写,即地址是从第1位开始的,第0位需位0,则写地址ucAddr = ((Address<<1)&0x7E);读地址ucAddr = ((Address<<1)&0x7E)|0x80;
二,RC522识别卡号
/
//功 能:读RFID卡号
//返 回:考号赋给全局SN[]
/
void ReadRC522()
{
uint8_t status;
uint8_t j;
uint8_t xieka[16]={1,2,3,4};
do{
status = PcdRequest(PICC_REQALL,CT);/*扫描卡*/
status = PcdAnticoll(SN);/*防冲撞*/
}while(status != MI_OK);
if(status == MI_OK){
for(j=0;j<4;j++){
LCD_ShowNum(0+j*30,350,SN[j],3,16);
}
status = PcdWrite(0x02,xieka);
}
}
下面有关函数全部基于此函数为基础
先通过寻卡函数PcdRequest搜索感应区的卡,然后防冲撞后选择卡片再对卡片进行操作,其中SN被赋予了卡号序列号
三,RC522添加卡号并存储到24C02
/
//功 能:写RFID卡号到24C02
//实现逻辑:一个卡号总共有5位,第一位是Y/N,第二位至第五位为卡号,起始地址为0x03
//判断其首位可知是否有卡号存储,如是Y,即偏移5,为N,则可写入
//返 回:
/
void AddRC522()
{
uint8_t j=0;
unsigned char DisFlag[1]='N';
unsigned char EnFlag[1]='Y';
unsigned char FLAG[1];
ReadRC522();
j=0;
LCD_ShowString(0,320,110,16,16,"ADD CARD");
GPIO_ResetBits(GPIOF,GPIO_Pin_9);
//蜂鸣器对应引脚GPIOF8拉低,
do
{
AT24CXX_Read((SIZE-1)+5*j,FLAG,1);
j++;
}while(FLAG[0]!='N');
AT24CXX_Write((SIZE-1)+5*(j-1),(unsigned char*)EnFlag,1);
AT24CXX_Write((SIZE)+5*(j-1),(unsigned char*)SN,SIZE);
AT24CXX_Write((SIZE-1)+5*(j),(unsigned char*)DisFlag,1);
LCD_ShowString(0,360,110,16,16,"WRITE CARD");
j=0;
}
通过判断是否为N来写入卡号
三,RC522从24C02删除卡号
/
//功 能:删除RFID卡号
//实现逻辑:1.寻找相同卡号,2.循环下一位卡号对上一位卡号进行覆盖,最开始覆盖的
// 卡号为相同卡号,3.对最后一个[Y]赋[N]
//返 回:
/
void DelRC522()
{
unsigned char DelFlag[1];
unsigned char Del[1];
uint8_t j=0;
uint8_t flag=0;
unsigned char DisFlag[1]='N';
u8 t,len;
LCD_ShowString(0,340,110,16,16,"DEL CARD");
ReadRC522();
j=0;
do{
AT24CXX_Read((SIZE-1)+5*j,DelFlag,1);
if(j>0)
{
AT24CXX_Read(SIZE+5*(j-1),datatemp,SIZE);
for(int i=0;i<4;i++)
{
if(datatemp[i]!=SN[i])
{
i=4;
}
if(i==3)
{
if(datatemp[i]==SN[i])
{
flag=j;
/* ****删除库卡号**** */
do{
AT24CXX_Read((SIZE-1)+5*flag,Del,1);
if(flag>j)
{
AT24CXX_Read(SIZE+5*(flag-1),DelAddData,SIZE);
AT24CXX_Write(SIZE+5*(flag-2),DelAddData,SIZE);
}
flag++;
}while(Del[0]=='Y');
AT24CXX_Write(SIZE-1+5*(flag-2),DisFlag,SIZE);
//DelFlag[0]='N'
}
}
}
}
j++;
}while(DelFlag[0]!='N');
j=0;
}
循环查找24C02存储的相应卡号并且删除移位
四,判断识别卡号是否存在24C02
//功 能:验证RFID卡号是否在库中
//返 回:
void RecRC522()
{
uint8_t j=0;
unsigned char ReadEnflag[1];
GPIO_ResetBits(GPIOF,GPIO_Pin_9); //蜂鸣器对应引脚GPIOF8拉低,
printf("success recognize card number:");
LCD_ShowString(0,320,110,16,16,"card number:");
ReadRC522();
do{
AT24CXX_Read((SIZE-1)+5*j,ReadEnflag,1);
//读取验证位;Y:即有卡号;N:即没有卡号
if(j>0)
{
AT24CXX_Read(SIZE+5*(j-1),datatemp,SIZE);
//读取24C02的Y后面的卡号赋予datatemp
for(int i=0;i<4;i++)
{
if(SN[i]!=datatemp[i])//卡号错误,跳出循环
{
i=4;
}
if(i==3)
{
if(SN[i]==datatemp[i])//卡号正确,进入函数
{
//RFID卡存在库中/
OneNet_SendData(datatemp);
ESP8266_Clear();
printf("THE CARD already exist this library,and exist in group");
LCD_ShowString(0,320,110,16,16,"card exist library");
}
}
}
}
j++;
}while(ReadEnflag[0]=='Y');
//判断为Y:继续循环;为N:退出循环
j=0;
}
循环查找卡号,发现卡号发送卡号到ONENET平台
{
//RFID卡存在库中/
OneNet_SendData(datatemp);
ESP8266_Clear();
printf("THE CARD already exist this library,and exist in group");
LCD_ShowString(0,320,110,16,16,"card exist library");
}
}
}
}
j++;
}while(ReadEnflag[0]=='Y');
//判断为Y:继续循环;为N:退出循环
j=0;
}
**循环查找卡号,发现卡号发送卡号到ONENET平台**