概述
RFID标签读写
同样是重点内容
今天比较累了,不太想写太多
RFID读写器和RFID标签
程序仍然为野火的例程进行移植
例程中使用的是 SPI 通信协议进行RFID标签读写
但是并未使用硬件 SPI
而是直接使用 软件模拟SPI
里面打开了7个GPIO引脚
硬件连接如下
stm32cubemx
对应上面打开这几个引脚的GPIO
其中有作为输出的 GPIO_OUTPUT
有作为输入的 GPIO_INPUT 注意分别
直接打开对应引脚就行了
不要硬件上做SPI
软件来实现
由于外设对时序要求比较严格,所以我们这里采用TIM定时器
实现us级别的延迟
ms延迟,可以直接调用 HAL_Delay()函数进行实现
选用定时器1
clock source选 内部时钟
下面的配置就是需要有一点基本定时器的知识
这里不解释了
keil5
直接上代码,不解释了
同样新建一下文件夹,顺便新建一下延迟函数的文件
同样是 .c文件和对应的 .h文件
delay.c
#include "delay.h"
extern TIM_HandleTypeDef htim1;
//us延迟
void Delay_us(uint32_t nus)
{
uint16_t differ = 0xffff - nus - 5;
//设置定时器2的技术初始值
__HAL_TIM_SetCounter(&htim1, differ);
//开启定时器
HAL_TIM_Base_Start(&htim1);
while (differ < 0xffff - 5)
{
differ = __HAL_TIM_GetCounter(&htim1);
};
//关闭定时器
HAL_TIM_Base_Stop(&htim1);
}
delay.h
#ifndef __DELAY_H
#define __DELAY_H
#include "bsp_system.h"
void Delay_us(uint32_t nus);
#endif /* __DELAY_H */
rc522_config.h
#ifndef __RC522_CONFIG_H
#define __RC522_CONFIG_H
#include "bsp_system.h"
/
//MF522命令字
/
#define PCD_IDLE 0x00 //取消当前命令
#define PCD_AUTHENT 0x0E //验证密钥
#define PCD_RECEIVE 0x08 //接收数据
#define PCD_TRANSMIT 0x04 //发送数据
#define PCD_TRANSCEIVE 0x0C //发送并接收数据
#define PCD_RESETPHASE 0x0F //复位
#define PCD_CALCCRC 0x03 //CRC计算
/
//Mifare_One卡片命令字
/
#define PICC_REQIDL 0x26 //寻天线区内未进入休眠状态
#define PICC_REQALL 0x52 //寻天线区内全部卡
#define PICC_ANTICOLL1 0x93 //防冲撞
#define PICC_ANTICOLL2 0x95 //防冲撞
#define PICC_AUTHENT1A 0x60 //验证A密钥
#define PICC_AUTHENT1B 0x61 //验证B密钥
#define PICC_READ 0x30 //读块
#define PICC_WRITE 0xA0 //写块
#define PICC_DECREMENT 0xC0 //扣款
#define PICC_INCREMENT 0xC1 //充值
#define PICC_RESTORE 0xC2 //调块数据到缓冲区
#define PICC_TRANSFER 0xB0 //保存缓冲区中数据
#define PICC_HALT 0x50 //休眠
/
//MF522 FIFO长度定义
/
#define DEF_FIFO_LENGTH 64 //FIFO size=64byte
#define MAXRLEN 18
/
//MF522寄存器定义
/
// PAGE 0
#define RFU00 0x00
#define CommandReg 0x01
#define ComIEnReg 0x02
#define DivlEnReg 0x03
#define ComIrqReg 0x04
#define DivIrqReg 0x05
#define ErrorReg 0x06
#define Status1Reg 0x07
#define Status2Reg 0x08
#define FIFODataReg 0x09
#define FIFOLevelReg 0x0A
#define WaterLevelReg 0x0B
#define ControlReg 0x0C
#define BitFramingReg 0x0D
#define CollReg 0x0E
#define RFU0F 0x0F
// PAGE 1
#define RFU10 0x10
#define ModeReg 0x11
#define TxModeReg 0x12
#define RxModeReg 0x13
#define TxControlReg 0x14
#define TxAutoReg 0x15
#define TxSelReg 0x16
#define RxSelReg 0x17
#define RxThresholdReg 0x18
#define DemodReg 0x19
#define RFU1A 0x1A
#define RFU1B 0x1B
#define MifareReg 0x1C
#define RFU1D 0x1D
#define RFU1E 0x1E
#define SerialSpeedReg 0x1F
// PAGE 2
#define RFU20 0x20
#define CRCResultRegM 0x21
#define CRCResultRegL 0x22
#define RFU23 0x23
#define ModWidthReg 0x24
#define RFU25 0x25
#define RFCfgReg 0x26
#define GsNReg 0x27
#define CWGsCfgReg 0x28
#define ModGsCfgReg 0x29
#define TModeReg 0x2A
#define TPrescalerReg 0x2B
#define TReloadRegH 0x2C
#define TReloadRegL 0x2D
#define TCounterValueRegH 0x2E
#define TCounterValueRegL 0x2F
// PAGE 3
#define RFU30 0x30
#define TestSel1Reg 0x31
#define TestSel2Reg 0x32
#define TestPinEnReg 0x33
#define TestPinValueReg 0x34
#define TestBusReg 0x35
#define AutoTestReg 0x36
#define VersionReg 0x37
#define AnalogTestReg 0x38
#define TestDAC1Reg 0x39
#define TestDAC2Reg 0x3A
#define TestADCReg 0x3B
#define RFU3C 0x3C
#define RFU3D 0x3D
#define RFU3E 0x3E
#define RFU3F 0x3F
/
//和MF522通讯时返回的错误代码
/
#define MI_OK 0x26
#define MI_NOTAGERR 0xcc
#define MI_ERR 0xbb
/*********************************** RC522 引脚定义 *********************************************/
//RC522模块有除了电源还有6个数据引脚,其中IRQ不需要使用,悬空即可,剩下的5个数据引脚连接如下:
//如果RC522需要修改与STM32的连接,则修改这些IO即可,但必须连接到STM32的SPI引脚
//片选,即RC522模块的SDA引脚,PA4 output pp
//#define RC522_GPIO_CS_CLK_FUN RCC_APB2PeriphClockCmd
//#define RC522_GPIO_CS_CLK RCC_APB2Periph_GPIOA
#define RC522_GPIO_CS_PORT GPIOA
#define RC522_GPIO_CS_PIN GPIO_PIN_4
//#define RC522_GPIO_CS_Mode GPIO_Mode_Out_PP
//时钟,即RC522模块的SCK引脚,接STM32的SPI的SCK引脚 PA5 output pp
//#define RC522_GPIO_SCK_CLK_FUN RCC_APB2PeriphClockCmd
//#define RC522_GPIO_SCK_CLK RCC_APB2Periph_GPIOA
#define RC522_GPIO_SCK_PORT GPIOA
#define RC522_GPIO_SCK_PIN GPIO_PIN_5
//#define RC522_GPIO_SCK_Mode GPIO_Mode_Out_PP
// 数据输入,即即RC522模块的MOSI引脚,接STM32的SPI的MOSI引脚 PA7 output pp
//#define RC522_GPIO_MOSI_CLK_FUN RCC_APB2PeriphClockCmd
//#define RC522_GPIO_MOSI_CLK RCC_APB2Periph_GPIOA
#define RC522_GPIO_MOSI_PORT GPIOA
#define RC522_GPIO_MOSI_PIN GPIO_PIN_7
//#define RC522_GPIO_MOSI_Mode GPIO_Mode_Out_PP
// 数据输出,即即RC522模块的MISO引脚,接STM32的SPI的MISO引脚 PA6 input floating
//#define RC522_GPIO_MISO_CLK_FUN RCC_APB2PeriphClockCmd
//#define RC522_GPIO_MISO_CLK RCC_APB2Periph_GPIOA
#define RC522_GPIO_MISO_PORT GPIOA
#define RC522_GPIO_MISO_PIN GPIO_PIN_6
//#define RC522_GPIO_MISO_Mode GPIO_Mode_IN_FLOATING
//复位,即即RC522模块的RST引脚,接STM32的普通IO即可 PB0 output pp
//#define RC522_GPIO_RST_CLK_FUN RCC_APB2PeriphClockCmd
//#define RC522_GPIO_RST_CLK RCC_APB2Periph_GPIOB
#define RC522_GPIO_RST_PORT GPIOB
#define RC522_GPIO_RST_PIN GPIO_PIN_0
//#define RC522_GPIO_RST_Mode GPIO_Mode_Out_PP
/*********************************** RC522 函数宏定义*********************************************/
#define RC522_CS_Enable() HAL_GPIO_WritePin ( RC522_GPIO_CS_PORT, RC522_GPIO_CS_PIN , GPIO_PIN_RESET)
#define RC522_CS_Disable() HAL_GPIO_WritePin ( RC522_GPIO_CS_PORT, RC522_GPIO_CS_PIN , GPIO_PIN_SET)
#define RC522_Reset_Enable() HAL_GPIO_WritePin( RC522_GPIO_RST_PORT, RC522_GPIO_RST_PIN, GPIO_PIN_RESET )
#define RC522_Reset_Disable() HAL_GPIO_WritePin( RC522_GPIO_RST_PORT, RC522_GPIO_RST_PIN, GPIO_PIN_SET )
#define RC522_SCK_0() HAL_GPIO_WritePin( RC522_GPIO_SCK_PORT, RC522_GPIO_SCK_PIN, GPIO_PIN_RESET )
#define RC522_SCK_1() HAL_GPIO_WritePin( RC522_GPIO_SCK_PORT, RC522_GPIO_SCK_PIN, GPIO_PIN_SET )
#define RC522_MOSI_0() HAL_GPIO_WritePin( RC522_GPIO_MOSI_PORT, RC522_GPIO_MOSI_PIN, GPIO_PIN_RESET )
#define RC522_MOSI_1() HAL_GPIO_WritePin( RC522_GPIO_MOSI_PORT, RC522_GPIO_MOSI_PIN, GPIO_PIN_SET )
#define RC522_MISO_GET() HAL_GPIO_ReadPin ( RC522_GPIO_MISO_PORT, RC522_GPIO_MISO_PIN )
/*********************************** 函数 *********************************************/
void RC522_Init ( void );
#endif /* __RC522_CONFIG_H */
rc522_config.c
#include "rc522_config.h"
/**
* @brief RC522_Init
* @param 无
* @retval 无
*/
void RC522_Init(void)
{
RC522_Reset_Disable();
RC522_CS_Disable();
}
rc522function.h
#ifndef __RC522_FUNCTION_H
#define __RC522_FUNCTION_H
//#include "stm32f10x_it.h"
#include "bsp_system.h"
#include "rc522_config.h"
#define macDummy_Data 0x00
#define RC522_DELAY() Delay_us(2)
void IC_test ( void );
void PcdReset ( void ); //复位
void M500PcdConfigISOType ( u8 type ); //工作方式
char PcdRequest ( u8 req_code, u8 * pTagType ); //寻卡
char PcdAnticoll ( u8 * pSnr); //读卡号
char PcdHalt ( void );
char PcdSelect ( uint8_t * pSnr );
char PcdAuthState ( uint8_t ucAuth_mode, uint8_t ucAddr, uint8_t * pKey, uint8_t * pSnr );
char WriteAmount ( uint8_t ucAddr, uint32_t pData );
char ReadAmount ( uint8_t ucAddr, uint32_t *pData );
#endif /* __RC522_FUNCTION_H */
rc522_function.c
#include "rc522_function.h"
extern UART_HandleTypeDef huart1;
extern unsigned char temp;
uint8_t KeyValue[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; // 卡A密钥
uint32_t writeValue = 100;
void IC_test(void)
{
uint32_t readValue = 0;
uint8_t send_value[64] = {0};
uint8_t cStr[30] = {0};
uint8_t ucArray_ID[4] = {0}; /*先后存放IC卡的类型和UID(IC卡序列号)*/
uint8_t ucStatusReturn = 0; /*返回状态*/
if( temp == 'A')
{
/*寻卡*/
if ((ucStatusReturn = PcdRequest(PICC_REQIDL, ucArray_ID)) != MI_OK)
/*若失败再次寻卡*/
ucStatusReturn = PcdRequest(PICC_REQIDL, ucArray_ID);
if (ucStatusReturn == MI_OK)
{
/*防冲撞(当有多张卡进入读写器操作范围时,防冲突机制会从其中选择一张进行操作)*/
if (PcdAnticoll(ucArray_ID) == MI_OK)
{
PcdSelect(ucArray_ID);
PcdAuthState(PICC_AUTHENT1A, 0x11, KeyValue, ucArray_ID); //校验密码
WriteAmount(0x11, writeValue); //写入金额
if (ReadAmount(0x11, &readValue) == MI_OK) //读取金额
{
writeValue += 100;
sprintf((char *)cStr, "The Card ID is: %02X%02X%02X%02Xn", ucArray_ID[0], ucArray_ID[1], ucArray_ID[2], ucArray_ID[3]);
HAL_UART_Transmit(&huart1, cStr, sizeof(cStr), 100);
//printf ( "%srn",cStr ); //打印卡片ID
//printf ("余额为:%drn",readValue);
sprintf((char *)send_value, "余额为:%dn", readValue);
HAL_UART_Transmit(&huart1, send_value, sizeof(send_value), 100);
PcdHalt();
}
}
}
}
//HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_5);
//HAL_Delay(200);
}
/**
* @brief 向RC522发送1 Byte 数据
* @param byte,要发送的数据
* @retval RC522返回的数据
*/
void SPI_RC522_SendByte(uint8_t byte)
{
uint8_t counter;
for (counter = 0; counter < 8; counter++)
{
if (byte & 0x80)
RC522_MOSI_1();
else
RC522_MOSI_0();
RC522_DELAY();
RC522_SCK_0();
RC522_DELAY();
RC522_SCK_1();
RC522_DELAY();
byte <<= 1;
}
}
/**
* @brief 从RC522发送1 Byte 数据
* @param 无
* @retval RC522返回的数据
*/
uint8_t SPI_RC522_ReadByte(void)
{
uint8_t counter;
uint8_t SPI_Data;
for (counter = 0; counter < 8; counter++)
{
SPI_Data <<= 1;
RC522_SCK_0();
RC522_DELAY();
if (RC522_MISO_GET() == 1)
SPI_Data |= 0x01;
RC522_DELAY();
RC522_SCK_1();
RC522_DELAY();
}
return SPI_Data;
}
/**
* @brief 读RC522寄存器
* @param ucAddress,寄存器地址
* @retval 寄存器的当前值
*/
uint8_t ReadRawRC(uint8_t ucAddress)
{
uint8_t ucAddr, ucReturn;
ucAddr = ((ucAddress << 1) & 0x7E) | 0x80;
RC522_CS_Enable();
SPI_RC522_SendByte(ucAddr);
ucReturn = SPI_RC522_ReadByte();
RC522_CS_Disable();
return ucReturn;
}
/**
* @brief 写RC522寄存器
* @param ucAddress,寄存器地址
* @param ucValue,写入寄存器的值
* @retval 无
*/
void WriteRawRC(uint8_t ucAddress, uint8_t ucValue)
{
uint8_t ucAddr;
ucAddr = (ucAddress << 1) & 0x7E;
RC522_CS_Enable();
SPI_RC522_SendByte(ucAddr);
SPI_RC522_SendByte(ucValue);
RC522_CS_Disable();
}
/**
* @brief 对RC522寄存器置位
* @param ucReg,寄存器地址
* @param ucMask,置位值
* @retval 无
*/
void SetBitMask(uint8_t ucReg, uint8_t ucMask)
{
uint8_t ucTemp;
ucTemp = ReadRawRC(ucReg);
WriteRawRC(ucReg, ucTemp | ucMask); // set bit mask
}
/**
* @brief 对RC522寄存器清位
* @param ucReg,寄存器地址
* @param ucMask,清位值
* @retval 无
*/
void ClearBitMask(uint8_t ucReg, uint8_t ucMask)
{
uint8_t ucTemp;
ucTemp = ReadRawRC(ucReg);
WriteRawRC(ucReg, ucTemp & (~ucMask)); // clear bit mask
}
/**
* @brief 开启天线
* @param 无
* @retval 无
*/
void PcdAntennaOn(void)
{
uint8_t uc;
uc = ReadRawRC(TxControlReg);
if (!(uc & 0x03))
SetBitMask(TxControlReg, 0x03);
}
/**
* @brief 关闭天线
* @param 无
* @retval 无
*/
void PcdAntennaOff(void)
{
ClearBitMask(TxControlReg, 0x03);
}
/**
* @brief 复位RC522
* @param 无
* @retval 无
*/
void PcdReset(void)
{
RC522_Reset_Disable();
Delay_us(1);
RC522_Reset_Enable();
Delay_us(1);
RC522_Reset_Disable();
Delay_us(1);
WriteRawRC(CommandReg, 0x0f);
while (ReadRawRC(CommandReg) & 0x10)
;
Delay_us(1);
//定义发送和接收常用模式 和Mifare卡通讯,CRC初始值0x6363
WriteRawRC(ModeReg, 0x3D);
WriteRawRC(TReloadRegL, 30); //16位定时器低位
WriteRawRC(TReloadRegH, 0); //16位定时器高位
WriteRawRC(TModeReg, 0x8D); //定义内部定时器的设置
WriteRawRC(TPrescalerReg, 0x3E); //设置定时器分频系数
WriteRawRC(TxAutoReg, 0x40); //调制发送信号为100%ASK
}
/**
* @brief 设置RC522的工作方式
* @param ucType,工作方式
* @retval 无
*/
void M500PcdConfigISOType(uint8_t ucType)
{
if (ucType == 'A') //ISO14443_A
{
ClearBitMask(Status2Reg, 0x08);
WriteRawRC(ModeReg, 0x3D); //3F
WriteRawRC(RxSelReg, 0x86); //84
WriteRawRC(RFCfgReg, 0x7F); //4F
WriteRawRC(TReloadRegL, 30);
WriteRawRC(TReloadRegH, 0);
WriteRawRC(TModeReg, 0x8D);
WriteRawRC(TPrescalerReg, 0x3E);
Delay_us(2);
PcdAntennaOn(); //开天线
}
}
/**
* @brief 通过RC522和ISO14443卡通讯
* @param ucCommand,RC522命令字
* @param pInData,通过RC522发送到卡片的数据
* @param ucInLenByte,发送数据的字节长度
* @param pOutData,接收到的卡片返回数据
* @param pOutLenBit,返回数据的位长度
* @retval 状态值= MI_OK,成功
*/
char PcdComMF522(uint8_t ucCommand,
uint8_t *pInData,
uint8_t ucInLenByte,
uint8_t *pOutData,
uint32_t *pOutLenBit)
{
char cStatus = MI_ERR;
uint8_t ucIrqEn = 0x00;
uint8_t ucWaitFor = 0x00;
uint8_t ucLastBits;
uint8_t ucN;
uint32_t ul;
switch (ucCommand)
{
case PCD_AUTHENT: //Mifare认证
ucIrqEn = 0x12; //允许错误中断请求ErrIEn 允许空闲中断IdleIEn
ucWaitFor = 0x10; //认证寻卡等待时候 查询空闲中断标志位
break;
case PCD_TRANSCEIVE: //接收发送 发送接收
ucIrqEn = 0x77; //允许TxIEn RxIEn IdleIEn LoAlertIEn ErrIEn TimerIEn
ucWaitFor = 0x30; //寻卡等待时候 查询接收中断标志位与 空闲中断标志位
break;
default:
break;
}
//IRqInv置位管脚IRQ与Status1Reg的IRq位的值相反
WriteRawRC(ComIEnReg, ucIrqEn | 0x80);
//Set1该位清零时,CommIRqReg的屏蔽位清零
ClearBitMask(ComIrqReg, 0x80);
//写空闲命令
WriteRawRC(CommandReg, PCD_IDLE);
//置位FlushBuffer清除内部FIFO的读和写指针以及ErrReg的BufferOvfl标志位被清除
SetBitMask(FIFOLevelReg, 0x80);
for (ul = 0; ul < ucInLenByte; ul++)
WriteRawRC(FIFODataReg, pInData[ul]); //写数据进FIFOdata
WriteRawRC(CommandReg, ucCommand); //写命令
if (ucCommand == PCD_TRANSCEIVE)
//StartSend置位启动数据发送 该位与收发命令使用时才有效
SetBitMask(BitFramingReg, 0x80);
ul = 1000; //根据时钟频率调整,操作M1卡最大等待时间25ms
do //认证 与寻卡等待时间
{
ucN = ReadRawRC(ComIrqReg); //查询事件中断
ul--;
} while ((ul != 0) && (!(ucN & 0x01)) && (!(ucN & ucWaitFor)));
ClearBitMask(BitFramingReg, 0x80); //清理允许StartSend位
if (ul != 0)
{
//读错误标志寄存器BufferOfI CollErr ParityErr ProtocolErr
if (!(ReadRawRC(ErrorReg) & 0x1B))
{
cStatus = MI_OK;
if (ucN & ucIrqEn & 0x01) //是否发生定时器中断
cStatus = MI_NOTAGERR;
if (ucCommand == PCD_TRANSCEIVE)
{
//读FIFO中保存的字节数
ucN = ReadRawRC(FIFOLevelReg);
//最后接收到得字节的有效位数
ucLastBits = ReadRawRC(ControlReg) & 0x07;
if (ucLastBits)
//N个字节数减去1(最后一个字节)+最后一位的位数 读取到的数据总位数
*pOutLenBit = (ucN - 1) * 8 + ucLastBits;
else
*pOutLenBit = ucN * 8; //最后接收到的字节整个字节有效
if (ucN == 0)
ucN = 1;
if (ucN > MAXRLEN)
ucN = MAXRLEN;
for (ul = 0; ul < ucN; ul++)
pOutData[ul] = ReadRawRC(FIFODataReg);
}
}
else
cStatus = MI_ERR;
}
SetBitMask(ControlReg, 0x80); // stop timer now
WriteRawRC(CommandReg, PCD_IDLE);
return cStatus;
}
/**
* @brief 寻卡
* @param ucReq_code,寻卡方式 = 0x52,寻感应区内所有符合14443A标准的卡;
寻卡方式= 0x26,寻未进入休眠状态的卡
* @param pTagType,卡片类型代码
= 0x4400,Mifare_UltraLight
= 0x0400,Mifare_One(S50)
= 0x0200,Mifare_One(S70)
= 0x0800,Mifare_Pro(X))
= 0x4403,Mifare_DESFire
* @retval 状态值= MI_OK,成功
*/
char PcdRequest(uint8_t ucReq_code, uint8_t *pTagType)
{
char cStatus;
uint8_t ucComMF522Buf[MAXRLEN];
uint32_t ulLen;
//清理指示MIFARECyptol单元接通以及所有卡的数据通信被加密的情况
ClearBitMask(Status2Reg, 0x08);
//发送的最后一个字节的 七位
WriteRawRC(BitFramingReg, 0x07);
//TX1,TX2管脚的输出信号传递经发送调制的13.56的能量载波信号
SetBitMask(TxControlReg, 0x03);
ucComMF522Buf[0] = ucReq_code; //存入 卡片命令字
cStatus = PcdComMF522(PCD_TRANSCEIVE,
ucComMF522Buf,
1,
ucComMF522Buf,
&ulLen); //寻卡
if ((cStatus == MI_OK) && (ulLen == 0x10)) //寻卡成功返回卡类型
{
*pTagType = ucComMF522Buf[0];
*(pTagType + 1) = ucComMF522Buf[1];
}
else
cStatus = MI_ERR;
return cStatus;
}
/**
* @brief 防冲撞
* @param pSnr,卡片序列号,4字节
* @retval 状态值= MI_OK,成功
*/
char PcdAnticoll(uint8_t *pSnr)
{
char cStatus;
uint8_t uc, ucSnr_check = 0;
uint8_t ucComMF522Buf[MAXRLEN];
uint32_t ulLen;
//清MFCryptol On位 只有成功执行MFAuthent命令后,该位才能置位
ClearBitMask(Status2Reg, 0x08);
//清理寄存器 停止收发
WriteRawRC(BitFramingReg, 0x00);
//清ValuesAfterColl所有接收的位在冲突后被清除
ClearBitMask(CollReg, 0x80);
ucComMF522Buf[0] = 0x93; //卡片防冲突命令
ucComMF522Buf[1] = 0x20;
cStatus = PcdComMF522(PCD_TRANSCEIVE,
ucComMF522Buf,
2,
ucComMF522Buf,
&ulLen); //与卡片通信
if (cStatus == MI_OK) //通信成功
{
for (uc = 0; uc < 4; uc++)
{
*(pSnr + uc) = ucComMF522Buf[uc]; //读出UID
ucSnr_check ^= ucComMF522Buf[uc];
}
if (ucSnr_check != ucComMF522Buf[uc])
cStatus = MI_ERR;
}
SetBitMask(CollReg, 0x80);
return cStatus;
}
/**
* @brief 用RC522计算CRC16
* @param pIndata,计算CRC16的数组
* @param ucLen,计算CRC16的数组字节长度
* @param pOutData,存放计算结果存放的首地址
* @retval 无
*/
void CalulateCRC(uint8_t *pIndata,
uint8_t ucLen,
uint8_t *pOutData)
{
uint8_t uc, ucN;
ClearBitMask(DivIrqReg, 0x04);
WriteRawRC(CommandReg, PCD_IDLE);
SetBitMask(FIFOLevelReg, 0x80);
for (uc = 0; uc < ucLen; uc++)
WriteRawRC(FIFODataReg, *(pIndata + uc));
WriteRawRC(CommandReg, PCD_CALCCRC);
uc = 0xFF;
do
{
ucN = ReadRawRC(DivIrqReg);
uc--;
} while ((uc != 0) && !(ucN & 0x04));
pOutData[0] = ReadRawRC(CRCResultRegL);
pOutData[1] = ReadRawRC(CRCResultRegM);
}
/**
* @brief 选定卡片
* @param pSnr,卡片序列号,4字节
* @retval 状态值= MI_OK,成功
*/
char PcdSelect(uint8_t *pSnr)
{
char ucN;
uint8_t uc;
uint8_t ucComMF522Buf[MAXRLEN];
uint32_t ulLen;
ucComMF522Buf[0] = PICC_ANTICOLL1;
ucComMF522Buf[1] = 0x70;
ucComMF522Buf[6] = 0;
for (uc = 0; uc < 4; uc++)
{
ucComMF522Buf[uc + 2] = *(pSnr + uc);
ucComMF522Buf[6] ^= *(pSnr + uc);
}
CalulateCRC(ucComMF522Buf, 7, &ucComMF522Buf[7]);
ClearBitMask(Status2Reg, 0x08);
ucN = PcdComMF522(PCD_TRANSCEIVE,
ucComMF522Buf,
9,
ucComMF522Buf,
&ulLen);
if ((ucN == MI_OK) && (ulLen == 0x18))
ucN = MI_OK;
else
ucN = MI_ERR;
return ucN;
}
/**
* @brief 验证卡片密码
* @param ucAuth_mode,密码验证模式= 0x60,验证A密钥,
密码验证模式= 0x61,验证B密钥
* @param uint8_t ucAddr,块地址
* @param pKey,密码
* @param pSnr,卡片序列号,4字节
* @retval 状态值= MI_OK,成功
*/
char PcdAuthState(uint8_t ucAuth_mode,
uint8_t ucAddr,
uint8_t *pKey,
uint8_t *pSnr)
{
char cStatus;
uint8_t uc, ucComMF522Buf[MAXRLEN];
uint32_t ulLen;
ucComMF522Buf[0] = ucAuth_mode;
ucComMF522Buf[1] = ucAddr;
for (uc = 0; uc < 6; uc++)
ucComMF522Buf[uc + 2] = *(pKey + uc);
for (uc = 0; uc < 6; uc++)
ucComMF522Buf[uc + 8] = *(pSnr + uc);
cStatus = PcdComMF522(PCD_AUTHENT,
ucComMF522Buf,
12,
ucComMF522Buf,
&ulLen);
if ((cStatus != MI_OK) || (!(ReadRawRC(Status2Reg) & 0x08)))
cStatus = MI_ERR;
return cStatus;
}
/**
* @brief 写数据到M1卡一块
* @param uint8_t ucAddr,块地址
* @param pData,写入的数据,16字节
* @retval 状态值= MI_OK,成功
*/
char PcdWrite(uint8_t ucAddr, uint8_t *pData)
{
char cStatus;
uint8_t uc, ucComMF522Buf[MAXRLEN];
uint32_t ulLen;
ucComMF522Buf[0] = PICC_WRITE;
ucComMF522Buf[1] = ucAddr;
CalulateCRC(ucComMF522Buf, 2, &ucComMF522Buf[2]);
cStatus = PcdComMF522(PCD_TRANSCEIVE,
ucComMF522Buf,
4,
ucComMF522Buf,
&ulLen);
if ((cStatus != MI_OK) || (ulLen != 4) ||
((ucComMF522Buf[0] & 0x0F) != 0x0A))
cStatus = MI_ERR;
if (cStatus == MI_OK)
{
//memcpy(ucComMF522Buf, pData, 16);
for (uc = 0; uc < 16; uc++)
ucComMF522Buf[uc] = *(pData + uc);
CalulateCRC(ucComMF522Buf, 16, &ucComMF522Buf[16]);
cStatus = PcdComMF522(PCD_TRANSCEIVE,
ucComMF522Buf,
18,
ucComMF522Buf,
&ulLen);
if ((cStatus != MI_OK) || (ulLen != 4) ||
((ucComMF522Buf[0] & 0x0F) != 0x0A))
cStatus = MI_ERR;
}
return cStatus;
}
/**
* @brief 读取M1卡一块数据
* @param ucAddr,块地址
* @param pData,读出的数据,16字节
* @retval 状态值= MI_OK,成功
*/
char PcdRead(uint8_t ucAddr, uint8_t *pData)
{
char cStatus;
uint8_t uc, ucComMF522Buf[MAXRLEN];
uint32_t ulLen;
ucComMF522Buf[0] = PICC_READ;
ucComMF522Buf[1] = ucAddr;
CalulateCRC(ucComMF522Buf, 2, &ucComMF522Buf[2]);
cStatus = PcdComMF522(PCD_TRANSCEIVE,
ucComMF522Buf,
4,
ucComMF522Buf,
&ulLen);
if ((cStatus == MI_OK) && (ulLen == 0x90))
{
for (uc = 0; uc < 16; uc++)
*(pData + uc) = ucComMF522Buf[uc];
}
else
cStatus = MI_ERR;
return cStatus;
}
/**
* @brief 命令卡片进入休眠状态
* @param 无
* @retval 状态值= MI_OK,成功
*/
char PcdHalt(void)
{
uint8_t ucComMF522Buf[MAXRLEN];
uint32_t ulLen;
ucComMF522Buf[0] = PICC_HALT;
ucComMF522Buf[1] = 0;
CalulateCRC(ucComMF522Buf, 2, &ucComMF522Buf[2]);
PcdComMF522(PCD_TRANSCEIVE,
ucComMF522Buf,
4,
ucComMF522Buf,
&ulLen);
return MI_OK;
}
/
//功 能:写入钱包金额
//参数说明: ucAddr[IN]:块地址
// pData:写入的金额
//返 回: 成功返回MI_OK
/
char WriteAmount(uint8_t ucAddr, uint32_t pData)
{
char status;
uint8_t ucComMF522Buf[16];
ucComMF522Buf[0] = (pData & ((uint32_t)0x000000ff));
ucComMF522Buf[1] = (pData & ((uint32_t)0x0000ff00)) >> 8;
ucComMF522Buf[2] = (pData & ((uint32_t)0x00ff0000)) >> 16;
ucComMF522Buf[3] = (pData & ((uint32_t)0xff000000)) >> 24;
ucComMF522Buf[4] = ~(pData & ((uint32_t)0x000000ff));
ucComMF522Buf[5] = ~(pData & ((uint32_t)0x0000ff00)) >> 8;
ucComMF522Buf[6] = ~(pData & ((uint32_t)0x00ff0000)) >> 16;
ucComMF522Buf[7] = ~(pData & ((uint32_t)0xff000000)) >> 24;
ucComMF522Buf[8] = (pData & ((uint32_t)0x000000ff));
ucComMF522Buf[9] = (pData & ((uint32_t)0x0000ff00)) >> 8;
ucComMF522Buf[10] = (pData & ((uint32_t)0x00ff0000)) >> 16;
ucComMF522Buf[11] = (pData & ((uint32_t)0xff000000)) >> 24;
ucComMF522Buf[12] = ucAddr;
ucComMF522Buf[13] = ~ucAddr;
ucComMF522Buf[14] = ucAddr;
ucComMF522Buf[15] = ~ucAddr;
status = PcdWrite(ucAddr, ucComMF522Buf);
return status;
}
/
//功 能:读取钱包金额
//参数说明: ucAddr[IN]:块地址
// *pData:读出的金额
//返 回: 成功返回MI_OK
/
char ReadAmount(uint8_t ucAddr, uint32_t *pData)
{
char status = MI_ERR;
uint8_t j;
uint8_t ucComMF522Buf[16];
status = PcdRead(ucAddr, ucComMF522Buf);
if (status != MI_OK)
return status;
for (j = 0; j < 4; j++)
{
if ((ucComMF522Buf[j] != ucComMF522Buf[j + 8]) && (ucComMF522Buf[j] != ~ucComMF522Buf[j + 4])) //验证一下是不是钱包的数据
break;
}
if (j == 4)
{
status = MI_OK;
*pData = ucComMF522Buf[0] + (ucComMF522Buf[1] << 8) + (ucComMF522Buf[2] << 16) + (ucComMF522Buf[3] << 24);
}
else
{
status = MI_ERR;
*pData = 0;
}
return status;
}
main.c
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "i2c.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "bsp_system.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
uint8_t send_date[64] = "test123n";
extern unsigned char temp;
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_I2C1_Init();
MX_TIM1_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
OLED_Init();
OLED_CLS();
//OLED_ShowStr(0,0,(unsigned char*)"Hello world",2);
OLED_ON();
RC522_Init ();
//复位RC522
PcdReset ();
/*设置工作方式*/
M500PcdConfigISOType ( 'A' );
while (1)
{
//Key_Scan();
//Display_Change();
IC_test ();
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
bsp_system.h
#ifndef __BSP_SYSTEM_H
#define __BSP_SYSTEM_H
#include "stm32f1xx_hal.h"
#include "stm32f1xx_hal_exti.h"
#include "stm32f1xx_hal_gpio.h"
#include "stm32f1xx_hal_i2c.h"
#include "stm32f1xx_hal_tim.h"
#include "stm32f1xx_hal_uart.h"
#include "stm32f1xx_hal_dma.h"
#include "stdio.h"
#include "OLED_I2C.h"
#include "keyboard.h"
#include "rc522_config.h"
#include "rc522_function.h"
#include "delay.h"
#endif /* __BSP_SYSTEM_H */
效果图
这样贴代码确实很蠢
所以后面代码会全部开源在github上
这样做只是为了给大家提供一点思路而已
点个赞吧
最后
以上就是无心丝袜为你收集整理的RFID防伪设计(物联网工程课程设计)DAY2---RFID标签读写的全部内容,希望文章能够帮你解决RFID防伪设计(物联网工程课程设计)DAY2---RFID标签读写所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复