公司需要做刷卡模块,因此选了RC522做demo程序。下面就RC522知识做简要的总结。
本人使用stm32的硬件spi接口搭建工程,相关的配置如下:
spi配置:
引脚配置
SDA -------PA4
SCLK ----PB13
MOSI -------PB15
MISO ------PB14
IRQ —没接
RST ---- PB0
//PB12--NSS PB13--SCK PB14--MISO PB15--MOSI
void SPI2_Init(void)
{ RCC->APB2ENR |= 1 << 3; //开启PORT b端口时钟 RCC->APB1ENR |= 1 << 14; //开启SPI2时钟 // PB13,PB14 PB15复用输出 GPIOB->CRH &= 0X000FFFFF; GPIOB->CRH |= 0XBBB00000; GPIOB->ODR |= 7 << 13; SPI2->CR1 |= 0<<10; //全双工模式SPI2->CR1 |= 1<<9; //启用软件管理SPI2->CR1 |= 1<<8; //ssi = 1SPI2->CR1 |= 1<<2; // 主设备SPI2->CR1 |= 0<<11; //8 bitSPI2->CR1 |= 1<<1; //SCK空闲为高SPI2->CR1 |= 1<<0; //上升沿采样SPI2->CR1 |= 7<<3; //256分频SPI2->CR1 |= 0<<7; //先发MSBSPI2->CR1 |= 1<<6; //开启SPI SPI2->CR2 |= 1 << 2;//SPI2_ReadWriteByte(0xff);
} void SPI2_SetSpeed(u8 SpeedSet)
{SPI2->CR1 &= 0XFFC7;if(SpeedSet==SPI_SPEED_2){SPI2->CR1|=0<<3;}else if(SpeedSet==SPI_SPEED_8) {SPI2->CR1|=2<<3;}else if(SpeedSet==SPI_SPEED_16){SPI2->CR1|=3<<3;}else {SPI2->CR1|=7<<3; }SPI2->CR1|=1<<6;
} u8 SPI2_ReadWriteByte(u8 TxData)
{ u8 retry=0; while((SPI2->SR&1<<1)==0){retry++;if(retry>200)return 0;} SPI2->DR=TxData; retry=0;while((SPI2->SR&1<<0)==0) {retry++;if(retry>200)return 0;} return SPI2->DR;
}
RC522相关接口初始化:
由于spi的cs由软件控制,所以,这里设置PA4为CS,PB0为rst
void RCC52_init(void)
{RCC->APB2ENR |= 1 << 3; RCC->APB2ENR |= 1 << 2;GPIOB->CRL &= 0XFFFFFFF0; GPIOB->CRL |= 0X00000003; GPIOB->ODR |= 1 << 0; GPIOA->CRL &= 0XFFF0FFFF; GPIOA->CRL |= 0X00030000; GPIOA->ODR |= 1 << 4;
}
rc522的识别过程:
寻卡---------->防冲突---------->寻卡--------->验证密码--------->存储操作
卡的操作包括:
读 (Read):读一个块;
写 (Write):写一个块;
加(Increment):对数值块进行加值;
减(Decrement):对数值块进行减值;
存储(Restore):将块中的内容存到数据寄存器中;
传输(Transfer):将数据寄存器中的内容写入块中;
中止(Halt):将卡置于暂停工作状态;
存储器组织
下面是识别卡过程的主函数
#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "led.h"
#include "key.h"
#include "exti.h"
#include "wdg.h"
#include "timer.h"
#include "lcd.h"
#include "rtc.h"
#include "wkup.h"
#include "adc.h"
#include "dma.h"
#include "24cxx.h"
#include "flash.h"
#include "RC522.h"
#include "spi2.h"
#include <string.h>
unsigned char DefaultKey[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
unsigned char data[16] = {0};
//4字节金额(低字节在前)+4字节金额取反+4字节金额+1字节块地址+1字节块地址取反+1字节块地址+1字节块地址取反
unsigned char bull[16] = {0x01,0x00,0x00,0x00,0xFE,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x01,0x02,0xFD,0x02,0xFD};
unsigned char value[4] = {0X00,0x00,0x00,0x0A};
int main(void)
{ unsigned char ucArray_ID [ 4 ]; /*先后存放IC卡的类型和UID(IC卡序列号)*/ unsigned char ucStatusReturn = MI_ERR; /*返回状态 */ char cStr [ 30 ]; int i = 0;unsigned char addr = 2;Stm32_Clock_Init(9);//系统时钟设置delay_init(72); //延时初始化uart_init(72,9600); //串口1初始化 LED_Init(); //LED初始化RCC52_init ();//PB12--NSS PB13--SCK PB14--MISO PB15--MOSISPI2_Init() ;
// SPIx_SetSpeed(256);if( MI_OK == PcdReset()){printf("RESET OK\n");}else{printf("reset failed\n");while(1);}PcdConfigISOType();PcdAntennaOff();delay_ms(10);PcdAntennaOn();while(1){ucStatusReturn = PcdRequest(PICC_REQALL,ucArray_ID );if(MI_OK != ucStatusReturn){ // printf("yanzheng fial\n");PcdAntennaOff();delay_ms(10);PcdAntennaOn();continue; }if(ucStatusReturn == MI_OK){/*防冲撞(当有多张卡进入读写器操作范围时,防冲突机制会从其中选择一张进行操作)*/if ( PcdAnticoll ( ucArray_ID ) == MI_OK ) {sprintf ( cStr, "The Card ID is: %02X%02X%02X%02X",ucArray_ID [ 0 ],ucArray_ID [ 1 ],ucArray_ID [ 2 ],ucArray_ID [ 3 ] );printf ( "%s\r\n",cStr ); } }ucStatusReturn = PcdSelect(ucArray_ID);if(ucStatusReturn != MI_OK)continue;
#if 0 ucStatusReturn = PcdAuthState(PICC_AUTHENT1A, 1, DefaultKey, ucArray_ID);//验证卡片密码if(ucStatusReturn != MI_OK)continue;ucStatusReturn = PcdRead(1,data);if(ucStatusReturn == MI_OK){for(i = 0; i < 16; i++){printf("0x%x ",data[i]);}}printf("\n");ucStatusReturn = PcdAuthState(PICC_AUTHENT1A, 1, DefaultKey, ucArray_ID);//验证卡片密码if(ucStatusReturn != MI_OK)continue;data[14] = 0x11;data[15] = 0x13;ucStatusReturn = PcdWrite(1,data);if(ucStatusReturn == MI_OK){for(i = 0; i < 16; i++){printf("0x%x ",data[i]);}}printf("\n");
#else//初始化钱包ucStatusReturn = PcdAuthState(PICC_AUTHENT1A, 2, DefaultKey, ucArray_ID);//验证卡片密码if(ucStatusReturn != MI_OK)continue;ucStatusReturn = PcdWrite(2,bull);if(ucStatusReturn != MI_OK)continue;//查询钱包ucStatusReturn = PcdAuthState(PICC_AUTHENT1A, 2, DefaultKey, ucArray_ID);//验证卡片密码if(ucStatusReturn != MI_OK)continue;ucStatusReturn = PcdRead(2,bull);if(ucStatusReturn == MI_OK){for(i = 0; i < 16; i++){printf("0x%x ",bull[i]);}}printf("\n");//扣值ucStatusReturn = PcdAuthState(PICC_AUTHENT1A, addr, DefaultKey, ucArray_ID);//验证卡片密码if(ucStatusReturn != MI_OK)continue;ucStatusReturn = PcdValue(PICC_INCREMENT,addr,value) ;if(ucStatusReturn != MI_OK){printf("decre fial\n");continue;}ucStatusReturn = PcdAuthState(PICC_AUTHENT1A, 2, DefaultKey, ucArray_ID);//验证卡片密码if(ucStatusReturn != MI_OK)continue;//显示余额ucStatusReturn = PcdRead(2,bull);if(ucStatusReturn == MI_OK){for(i = 0; i < 16; i++){printf("0x%x ",bull[i]);}}printf("\n");
#endifdelay_ms(1000);}
}
大概过程就是这样。其中,充值,减值的电子钱包功能测试没有通过,没时间研究了,毕竟跟工作关系不大。相关代码已经上传了。
参考:
https://blog.csdn.net/liujianhua1989/article/details/72639307
https://blog.csdn.net/a827415225/article/details/51898897
https://blog.csdn.net/txf1984/article/details/46560261