项目代码
1.SPI配置函数
cs
#include "stm32f10x.h"
#include "spi.h"
static void SPI_RCC_Configuration(SPI_TypeDef* SPIx)
{
if (SPIx == SPI1)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1 | RCC_APB2Periph_GPIOA, ENABLE);
}
else
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);
}
}
static void SPI_GPIO_Configuration(SPI_TypeDef* SPIx)
{
GPIO_InitTypeDef GPIO_InitStructure;
if(SPIx == SPI1)
{
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_Init(GPIOA,&GPIO_InitStructure);
}
else
{
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_Init(GPIOB,&GPIO_InitStructure);
}
}
void SPI_Configuration(SPI_TypeDef* SPIx)
{
SPI_InitTypeDef SPI_InitStructure;
SPI_RCC_Configuration(SPIx);
SPI_GPIO_Configuration(SPIx);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;
SPI_Init(SPIx,&SPI_InitStructure);
SPI_SSOutputCmd(SPIx,ENABLE);
SPI_Cmd(SPIx,ENABLE);
}
int32_t SPI_WriteByte(SPI_TypeDef* SPIx,uint16_t TxData )
{
uint8_t retry = 0;
while(SPI_I2S_GetFlagStatus(SPIx,SPI_I2S_FLAG_TXE) == RESET)
{
retry ++;
if(retry >= 200)
return -1;
}
SPI_I2S_SendData(SPIx,TxData);
retry = 0;
while(SPI_I2S_GetFlagStatus(SPIx,SPI_I2S_FLAG_RXNE) == RESET)
{
retry ++;
if(retry >= 200)
return -1;
}
SPI_I2S_ReceiveData(SPIx);
return 0;
}
int32_t SPI_ReadByte(SPI_TypeDef* SPIx,uint16_t* p_RxData)
{
uint8_t retry = 0;
while(SPI_I2S_GetFlagStatus(SPIx,SPI_I2S_FLAG_TXE) == RESET)
{
retry ++;
if(retry >= 200)
return -1;
}
SPI_I2S_SendData(SPIx,0xFF);
retry = 0;
while(SPI_I2S_GetFlagStatus(SPIx,SPI_I2S_FLAG_RXNE) == RESET)
{
retry ++;
if(retry >= 200)
return -1;
}
*p_RxData = SPI_I2S_ReceiveData(SPIx);
return 0;
}
int32_t SPI_WriteNBytes(SPI_TypeDef* SPIx,uint8_t* p_TxData,uint32_t SendDataNum)
{
uint8_t retry = 0;
while(SendDataNum--)
{
while(SPI_I2S_GetFlagStatus(SPIx,SPI_I2S_FLAG_TXE) == RESET)
{
retry ++;
if(retry >= 200000)
return -1;
}
SPI_I2S_SendData(SPIx,*p_TxData++);
retry = 0;
while(SPI_I2S_GetFlagStatus(SPIx,SPI_I2S_FLAG_RXNE) == RESET)
{
retry ++;
if(retry >= 200000)
return -1;
}
SPI_I2S_ReceiveData(SPIx);
}
return 0;
}
int32_t SPI_ReadNBytes(SPI_TypeDef* SPIx,uint8_t* p_RxData,uint32_t ReadDataNum)
{
uint8_t retry = 0;
while(ReadDataNum--)
{
while(SPI_I2S_GetFlagStatus(SPIx,SPI_I2S_FLAG_TXE) == RESET)
{
retry ++;
if(retry >= 200)
return -1;
}
SPI_I2S_SendData(SPIx,0xFF);
retry = 0;
while(SPI_I2S_GetFlagStatus(SPIx,SPI_I2S_FLAG_RXNE) == RESET)
{
retry ++;
if(retry >= 200)
return -1;
}
*p_RxData++ = SPI_I2S_ReceiveData(SPIx);
}
return 0;
}
/*
void SPI2_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI2,&SPI_InitStructure);
}
u8 SPI2_ReadWriteByte(u8 data)
{
u8 i;
i = 0;
while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_TXE) == RESET)
{
i++;
if(i >= 200)
{
return 0;
}
}
SPI_I2S_SendData(SPI2, data);
i = 0;
while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_RXNE) == RESET)
{
i++;
if(i >= 200)
{
return 0;
}
}
return SPI_I2S_ReceiveData(SPI2);
}
void SPI2_SetSpeed(uint16_t SPI_BaudRatePrescaler)
{
assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));
SPI2->CR1 &= 0Xffc7;
SPI2->CR1 |= SPI_BaudRatePrescaler;
SPI_Cmd(SPI2,ENABLE);
}
*/
SPI_SSOutputCmd(SPIx,ENABLE);
SPI_Cmd(SPIx,ENABLE);
顺序不能颠倒!
2.RC522配置
选PA11为复位引脚
cs
#include "stm32f10x.h"
#include "rc522.h"
#include "systick.h"
#include "spi.h"
#include "stm32f10x_spi.h"
void RC522_IO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //开启AFIO时钟
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); //关闭JTAG因为要使用PB3和4
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_4;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStruct);
SPI_Configuration(SPI1);
}
/*
/////////////////////////////////////////////////////////////////////
//功 能:写RC632寄存器
//参数说明:Address[IN]:寄存器地址
// value[IN]:写入的值
/////////////////////////////////////////////////////////////////////
void WriteRawRC(unsigned char Address, unsigned char value)
{
unsigned char i, ucAddr;
RC522_SCK_RESET(); //MF522_SCK = 0;
RC522_NSEL_RESET(); //MF522_NSS = 0;
ucAddr = ((Address<<1)&0x7E);
RC522_Delay(10);
for(i=8;i>0;i--)
{
//MF522_SI = ((ucAddr&0x80)==0x80);
if((ucAddr&0x80)==0x80)
{
RC522_MOSI_SET();
}
else
{
RC522_MOSI_RESET();
}
RC522_SCK_SET(); //MF522_SCK = 1;
ucAddr <<= 1;
RC522_Delay(10);
RC522_SCK_RESET(); //MF522_SCK = 0;
RC522_Delay(10);
}
for(i=8;i>0;i--)
{
//MF522_SI = ((value&0x80)==0x80);
if((value&0x80)==0x80)
{
RC522_MOSI_SET();
}
else
{
RC522_MOSI_RESET();
}
RC522_SCK_SET(); //MF522_SCK = 1;
value <<= 1;
RC522_Delay(10);
RC522_SCK_RESET(); //MF522_SCK = 0;
RC522_Delay(10);
// MF522_SCK = 1;
// value <<= 1;
// MF522_SCK = 0;
}
RC522_NSEL_SET(); //MF522_NSS = 1;
RC522_SCK_SET(); //MF522_SCK = 1;
}
/////////////////////////////////////////////////////////////////////
//功 能:读RC632寄存器
//参数说明:Address[IN]:寄存器地址
//返 回:读出的值
/////////////////////////////////////////////////////////////////////
unsigned char ReadRawRC(unsigned char Address)
{
unsigned char i, ucAddr;
unsigned char ucResult=0;
RC522_SCK_RESET(); //MF522_SCK = 0;
RC522_NSEL_RESET(); //MF522_NSS = 0;
ucAddr = ((Address<<1)&0x7E)|0x80;
RC522_Delay(10);
for(i=8;i>0;i--)
{
// MF522_SI = ((ucAddr&0x80)==0x80);
// MF522_SCK = 1;
// ucAddr <<= 1;
// MF522_SCK = 0;
if((ucAddr&0x80)==0x80)
{
RC522_MOSI_SET();
}
else
{
RC522_MOSI_RESET();
}
RC522_SCK_SET(); //MF522_SCK = 1;
ucAddr <<= 1;
RC522_Delay(10);
RC522_SCK_RESET(); //MF522_SCK = 0;
RC522_Delay(10);
}
for(i=8;i>0;i--)
{
RC522_SCK_SET(); //MF522_SCK = 1;
ucResult <<= 1;
RC522_Delay(10);
//ucResult|=(bit)MF522_SO;
// if(RC522_MISO_STATUS==1)
// {
// ucResult|=0x01;
// }
// else
// {
// ucResult&=~0x01;
// }
ucResult |=RC522_MISO_STATUS;
RC522_SCK_RESET(); //MF522_SCK = 0;
RC522_Delay(10);
}
RC522_NSEL_SET(); //MF522_NSS = 1;
RC522_SCK_SET(); //MF522_SCK = 1;
return ucResult;
}
*/
//#define MAXRLEN 18
/////////////////////////////////////////////////////////////////////
//功 能:寻卡
//参数说明: req_code[IN]:寻卡方式
// 0x52 = 寻感应区内所有符合14443A标准的卡
// 0x26 = 寻未进入休眠状态的卡
// pTagType[OUT]:卡片类型代码
// 0x4400 = Mifare_UltraLight
// 0x0400 = Mifare_One(S50)
// 0x0200 = Mifare_One(S70)
// 0x0800 = Mifare_Pro(X)
// 0x4403 = Mifare_DESFire
//返 回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
char PcdRequest(unsigned char req_code,unsigned char *pTagType)
{
char status;
unsigned int unLen;
unsigned char ucComMF522Buf[MAXRLEN];
ClearBitMask(Status2Reg,0x08); //清RC522寄存位
WriteRawRC(BitFramingReg,0x07); //写RC623寄存器
SetBitMask(TxControlReg,0x03); //置RC522寄存位
//
ucComMF522Buf[0] = req_code;
status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,1,ucComMF522Buf,&unLen);
// UART_send_byte(status);
if ((status == MI_OK) && (unLen == 0x10))
{
*pTagType = ucComMF522Buf[0];
*(pTagType+1) = ucComMF522Buf[1];
}
else
{ status = MI_ERR; }
return status;
}
/////////////////////////////////////////////////////////////////////
//功 能:防冲撞
//参数说明: pSnr[OUT]:卡片序列号,4字节
//返 回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
char PcdAnticoll(unsigned char *pSnr)
{
char status;
unsigned char i,snr_check=0;
unsigned int unLen;
unsigned char ucComMF522Buf[MAXRLEN];
ClearBitMask(Status2Reg,0x08);
WriteRawRC(BitFramingReg,0x00);
ClearBitMask(CollReg,0x80);
ucComMF522Buf[0] = PICC_ANTICOLL1;
ucComMF522Buf[1] = 0x20;
status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,2,ucComMF522Buf,&unLen);
if (status == MI_OK)
{
for (i=0; i<4; i++)
{
*(pSnr+i) = ucComMF522Buf[i];
snr_check ^= ucComMF522Buf[i];
}
if (snr_check != ucComMF522Buf[i])
{ status = MI_ERR; }
}
SetBitMask(CollReg,0x80);
return status;
}
/////////////////////////////////////////////////////////////////////
//功 能:选定卡片
//参数说明: pSnr[IN]:卡片序列号,4字节
//返 回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
char PcdSelect(unsigned char *pSnr)
{
char status;
unsigned char i;
unsigned int unLen;
unsigned char ucComMF522Buf[MAXRLEN];
ucComMF522Buf[0] = PICC_ANTICOLL1;
ucComMF522Buf[1] = 0x70;
ucComMF522Buf[6] = 0;
for (i=0; i<4; i++)
{
ucComMF522Buf[i+2] = *(pSnr+i);
ucComMF522Buf[6] ^= *(pSnr+i);
}
CalulateCRC(ucComMF522Buf,7,&ucComMF522Buf[7]);
ClearBitMask(Status2Reg,0x08);
status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,9,ucComMF522Buf,&unLen);
if ((status == MI_OK) && (unLen == 0x18))
{ status = MI_OK; }
else
{ status = MI_ERR; }
return status;
}
/////////////////////////////////////////////////////////////////////
//功 能:验证卡片密码
//参数说明: auth_mode[IN]: 密码验证模式
// 0x60 = 验证A密钥
// 0x61 = 验证B密钥
// addr[IN]:块地址
// pKey[IN]:密码
// pSnr[IN]:卡片序列号,4字节
//返 回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
char PcdAuthState(unsigned char auth_mode,unsigned char addr,unsigned char *pKey,unsigned char *pSnr)
{
char status;
unsigned int unLen;
unsigned char i,ucComMF522Buf[MAXRLEN];
ucComMF522Buf[0] = auth_mode;
ucComMF522Buf[1] = addr;
for (i=0; i<6; i++)
{ ucComMF522Buf[i+2] = *(pKey+i); }
for (i=0; i<6; i++)
{ ucComMF522Buf[i+8] = *(pSnr+i); }
status = PcdComMF522(PCD_AUTHENT,ucComMF522Buf,12,ucComMF522Buf,&unLen);
if ((status != MI_OK) || (!(ReadRawRC(Status2Reg) & 0x08)))
{ status = MI_ERR; }
return status;
}
/////////////////////////////////////////////////////////////////////
//功 能:读取M1卡一块数据
//参数说明: addr[IN]:块地址
// p [OUT]:读出的数据,16字节
//返 回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
char PcdRead(unsigned char addr,unsigned char *pData)
{
char status;
unsigned int unLen;
unsigned char i,ucComMF522Buf[MAXRLEN];
ucComMF522Buf[0] = PICC_READ;
ucComMF522Buf[1] = addr;
CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);
if ((status == MI_OK) && (unLen == 0x90))
{
for (i=0; i<16; i++)
{ *(pData+i) = ucComMF522Buf[i]; }
}
else
{ status = MI_ERR; }
return status;
}
/////////////////////////////////////////////////////////////////////
//功 能:写数据到M1卡一块
//参数说明: addr[IN]:块地址
// p [IN]:写入的数据,16字节
//返 回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
char PcdWrite(unsigned char addr,unsigned char *pData)
{
char status;
unsigned int unLen;
unsigned char i,ucComMF522Buf[MAXRLEN];
ucComMF522Buf[0] = PICC_WRITE;
ucComMF522Buf[1] = addr;
CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);
if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
{ status = MI_ERR; }
if (status == MI_OK)
{
for (i=0; i<16; i++)
{ ucComMF522Buf[i] = *(pData+i); }
CalulateCRC(ucComMF522Buf,16,&ucComMF522Buf[16]);
status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,18,ucComMF522Buf,&unLen);
if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
{ status = MI_ERR; }
}
return status;
}
/////////////////////////////////////////////////////////////////////
//功 能:扣款和充值
//参数说明: dd_mode[IN]:命令字
// 0xC0 = 扣款
// 0xC1 = 充值
// addr[IN]:钱包地址
// pValue[IN]:4字节增(减)值,低位在前
//返 回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
char PcdValue(unsigned char dd_mode,unsigned char addr,unsigned char *pValue)
{
char status;
unsigned int unLen;
unsigned char i,ucComMF522Buf[MAXRLEN];
ucComMF522Buf[0] = dd_mode;
ucComMF522Buf[1] = addr;
CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);
if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
{ status = MI_ERR; }
if (status == MI_OK)
{
for (i=0; i<16; i++)
{ ucComMF522Buf[i] = *(pValue+i); }
CalulateCRC(ucComMF522Buf,4,&ucComMF522Buf[4]);
unLen = 0;
status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,6,ucComMF522Buf,&unLen);
if (status != MI_ERR)
{ status = MI_OK; }
}
if (status == MI_OK)
{
ucComMF522Buf[0] = PICC_TRANSFER;
ucComMF522Buf[1] = addr;
CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);
if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
{ status = MI_ERR; }
}
return status;
}
/////////////////////////////////////////////////////////////////////
//功 能:备份钱包
//参数说明: sourceaddr[IN]:源地址
// goaladdr[IN]:目标地址
//返 回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
char PcdBakValue(unsigned char sourceaddr, unsigned char goaladdr)
{
char status;
unsigned int unLen;
unsigned char ucComMF522Buf[MAXRLEN];
ucComMF522Buf[0] = PICC_RESTORE;
ucComMF522Buf[1] = sourceaddr;
CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);
if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
{ status = MI_ERR; }
if (status == MI_OK)
{
ucComMF522Buf[0] = 0;
ucComMF522Buf[1] = 0;
ucComMF522Buf[2] = 0;
ucComMF522Buf[3] = 0;
CalulateCRC(ucComMF522Buf,4,&ucComMF522Buf[4]);
status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,6,ucComMF522Buf,&unLen);
if (status != MI_ERR)
{ status = MI_OK; }
}
if (status != MI_OK)
{ return MI_ERR; }
ucComMF522Buf[0] = PICC_TRANSFER;
ucComMF522Buf[1] = goaladdr;
CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);
if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
{ status = MI_ERR; }
return status;
}
/////////////////////////////////////////////////////////////////////
//功 能:命令卡片进入休眠状态
//返 回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
char PcdHalt(void)
{
//char status;
unsigned int unLen;
unsigned char ucComMF522Buf[MAXRLEN];
ucComMF522Buf[0] = PICC_HALT;
ucComMF522Buf[1] = 0;
CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
//status =
PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);
return MI_OK;
}
/////////////////////////////////////////////////////////////////////
//用MF522计算CRC16函数
/////////////////////////////////////////////////////////////////////
void CalulateCRC(unsigned char *pIndata,unsigned char len,unsigned char *pOutData)
{
unsigned char i,n;
ClearBitMask(DivIrqReg,0x04);
WriteRawRC(CommandReg,PCD_IDLE);
SetBitMask(FIFOLevelReg,0x80);
for (i=0; i<len; i++)
{ WriteRawRC(FIFODataReg, *(pIndata+i)); }
WriteRawRC(CommandReg, PCD_CALCCRC);
i = 0xFF;
do
{
n = ReadRawRC(DivIrqReg);
i--;
}
while ((i!=0) && !(n&0x04));
pOutData[0] = ReadRawRC(CRCResultRegL);
pOutData[1] = ReadRawRC(CRCResultRegM);
}
/////////////////////////////////////////////////////////////////////
//功 能:复位RC522
//返 回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
char PcdReset(void)
{
RC522_RESET_SET(); //RST522_1;
delay_us(10); //_NOP();
RC522_RESET_RESET(); //RST522_0;
delay_ms(60); //_NOP();_NOP();
RC522_RESET_SET(); //RST522_1;RST522_1;
delay_us(500); //_NOP();_NOP();
WriteRawRC(CommandReg,PCD_RESETPHASE);
delay_ms(2); //_NOP();_NOP();
WriteRawRC(ModeReg,0x3D); //?Mifare???,CRC???0x6363
WriteRawRC(TReloadRegL,30); //?30?????
WriteRawRC(TReloadRegH,0);
WriteRawRC(TModeReg,0x8D);
WriteRawRC(TPrescalerReg,0x3E);
WriteRawRC(TxAutoReg,0x40);
ClearBitMask(TestPinEnReg, 0x80);//off MX and DTRQ out
WriteRawRC(TxAutoReg,0x40);
return MI_OK;
}
/////////////////////////////////////////////////////////////////////
//功 能:读RC632寄存器
//参数说明:Address[IN]:寄存器地址
//返 回:读出的值
/////////////////////////////////////////////////////////////////////
unsigned char ReadRawRC(unsigned char Address)
{
unsigned char ucAddr;
unsigned char ucResult=0;
ucAddr = ((Address<<1)&0x7E)|0x80;
delay_ms(1);
RC522_ENABLE;
SPI_WriteNBytes(SPI1,&ucAddr,1); //向总线写多个数据
SPI_ReadNBytes(SPI1,&ucResult,1); //向总线读多个数据
RC522_DISABLE;
return ucResult;
}
/////////////////////////////////////////////////////////////////////
//功 能:写RC632寄存器
//参数说明:Address[IN]:寄存器地址
// value[IN]:写入的值
/////////////////////////////////////////////////////////////////////
void WriteRawRC(unsigned char Address, unsigned char value)
{
unsigned char ucAddr;
uint8_t write_buffer[2]={0};
ucAddr = ((Address<<1)&0x7E);
write_buffer[0] = ucAddr;
write_buffer[1] = value;
delay_ms(1);
RC522_ENABLE;
SPI_WriteNBytes(SPI1,write_buffer,2);
RC522_DISABLE;
}
/////////////////////////////////////////////////////////////////////
//功 能:置RC522寄存器位
//参数说明:reg[IN]:寄存器地址
// mask[IN]:置位值
/////////////////////////////////////////////////////////////////////
void SetBitMask(unsigned char reg,unsigned char mask)
{
char tmp = 0x0;
tmp = ReadRawRC(reg); //读RC632寄存器
WriteRawRC(reg,tmp | mask); // set bit mask
}
/////////////////////////////////////////////////////////////////////
//功 能:清RC522寄存器位
//参数说明:reg[IN]:寄存器地址
// mask[IN]:清位值
/////////////////////////////////////////////////////////////////////
void ClearBitMask(unsigned char reg,unsigned char mask)
{
char tmp = 0x0;
tmp = ReadRawRC(reg);
WriteRawRC(reg, tmp & ~mask); // clear bit mask
}
/////////////////////////////////////////////////////////////////////
//功 能:通过RC522和ISO14443卡通讯
//参数说明:Command[IN]:RC522命令字
// pIn [IN]:通过RC522发送到卡片的数据
// InLenByte[IN]:发送数据的字节长度
// pOut [OUT]:接收到的卡片返回数据
// *pOutLenBit[OUT]:返回数据的位长度
/////////////////////////////////////////////////////////////////////
char PcdComMF522(unsigned char Command,
unsigned char *pInData,
unsigned char InLenByte,
unsigned char *pOutData,
unsigned int *pOutLenBit)
{
char status = MI_ERR;
unsigned char irqEn = 0x00;
unsigned char waitFor = 0x00;
unsigned char lastBits;
unsigned char n;
unsigned int i;
switch (Command)
{
case PCD_AUTHENT:
irqEn = 0x12;
waitFor = 0x10;
break;
case PCD_TRANSCEIVE:
irqEn = 0x77;
waitFor = 0x30;
break;
default:
break;
}
WriteRawRC(ComIEnReg,irqEn|0x80);
ClearBitMask(ComIrqReg,0x80);
WriteRawRC(CommandReg,PCD_IDLE);
SetBitMask(FIFOLevelReg,0x80);
for (i=0; i<InLenByte; i++)
{ WriteRawRC(FIFODataReg, pInData[i]); }
WriteRawRC(CommandReg, Command);
if (Command == PCD_TRANSCEIVE)
{ SetBitMask(BitFramingReg,0x80); }
i = 800 ; //600;//????????,??M1???????25ms
do
{
n = ReadRawRC(ComIrqReg);
i--;
}
while ((i!=0) && !(n&0x01) && !(n&waitFor));
ClearBitMask(BitFramingReg,0x80);
if (i!=0)
{
if(!(ReadRawRC(ErrorReg)&0x1B))
{
status = MI_OK;
if (n & irqEn & 0x01)
{ status = MI_NOTAGERR; }
if (Command == PCD_TRANSCEIVE)
{
n = ReadRawRC(FIFOLevelReg);
lastBits = ReadRawRC(ControlReg) & 0x07;
if (lastBits)
{ *pOutLenBit = (n-1)*8 + lastBits; }
else
{ *pOutLenBit = n*8; }
if (n == 0)
{ n = 1; }
if (n > MAXRLEN)
{ n = MAXRLEN; }
for (i=0; i<n; i++)
{ pOutData[i] = ReadRawRC(FIFODataReg); }
}
}
else
{ status = MI_ERR; }
}
SetBitMask(ControlReg,0x80); // stop timer now
WriteRawRC(CommandReg,PCD_IDLE);
return status;
}
/////////////////////////////////////////////////////////////////////
//开启天线
//每次启动或关闭天险发射之间应至少有1ms的间隔
/////////////////////////////////////////////////////////////////////
void PcdAntennaOn(void)
{
unsigned char i;
i = ReadRawRC(TxControlReg);
if (!(i & 0x03))
{
SetBitMask(TxControlReg, 0x03);
}
}
/////////////////////////////////////////////////////////////////////
//关闭天线
/////////////////////////////////////////////////////////////////////
void PcdAntennaOff(void)
{
ClearBitMask(TxControlReg, 0x03);
}
void RC522_Config(unsigned char Card_Type)
{
ClearBitMask(Status2Reg,0x08);
WriteRawRC(ModeReg,0x3D);//3F
WriteRawRC(RxSelReg,0x86);//84
WriteRawRC(RFCfgReg,0x7F); //4F
WriteRawRC(TReloadRegL,30);//tmoLength);// TReloadVal = 'h6a =tmoLength(dec)
WriteRawRC(TReloadRegH,0);
WriteRawRC(TModeReg,0x8D);
WriteRawRC(TPrescalerReg,0x3E);
// WriteRawRC(TxAutoReg,0x40);//???
delay_ms(5);//delay_10ms(1);
PcdAntennaOn();
}
3.检查卡号函数
cs
#include "stm32f10x.h"
#include "Check_Card_Id.h"
#include <stdio.h>
extern uint8_t Run_flag;
extern uint8_t Lock_flag;
uint8_t Err_Count = 0;
uint8_t Check_Card_Id(uint8_t *value)
{
uint8_t i = 0,flag = 0;
uint8_t ave = 0;
int num = 0;
for(i = 0;i < 4;i++)
{
printf("card_id=%d\t",value[i]);
num += value[i]*(i+1);
}
printf("\r\n");
printf("num=%d\r\n",num);
ave = num/4;
printf("ave = %d\r\n",ave);
switch(ave)
{
case 218:flag = 1;break;
default:
flag = 0; Err_Count++;
}
if(Err_Count == 5)
{
Run_flag = 0;
Lock_flag = 1;
}
return flag;
}
num+=value[i]*(i+1); 加权求和算法
num = value[0] × 1 + value[1] × 2 + value[2] × 3 + value[3] × 4
假设一张卡的UID是:value[] = {100, 200, 50, 150}
第1字节:100 × 1 = 100
第2字节:200 × 2 = 400
第3字节:50 × 3 = 150
第4字节:150 × 4 = 600
总和:num = 100 + 400 + 150 + 600 = 1250
平均值:ave = 1250 / 4 = 312
目的1:区分不同字节的重要性
- 不同位置的字节有不同的权重
- 第4字节的权重最高(×4),第1字节最低(×1)
- 这样即使字节值相同,位置不同也会产生不同结果
目的2:简单的特征提取
目的3:降低碰撞概率
算法的优缺点
优点:
- 简单快速:计算量小,适合嵌入式系统
- 一定程度区分:能区分字节顺序不同的卡片
- 代码简洁:几行代码实现
缺点:
碰撞仍然可能:不同UID可能算出相同值
4.mian函数
cs
#include "stm32f10x.h"
#include "main.h"
#include "led.h"
#include "buzzer.h"
#include "key.h"
#include "Relay.h"
#include "Shake.h"
#include "Exti.h"
#include "usart.h"
#include "stdio.h"
#include "Time.h"
#include "sg90.h"
#include "systick.h"
#include "I2C_soft.h"
#include "dht11.h"
#include "spi.h"
#include "dma.h"
#include "car_driver.h"
#include "rc522.h"
#include "Check_Card_Id.h"
#include "IWDG.h"
uint8_t Card_Type1[2];
uint8_t Card_ID[4];
uint8_t status;
uint8_t flag;
uint8_t Run_flag=1;
uint8_t Lock_flag=0;
int main()
{
Card_Type1[0]=0x04;
Card_Type1[1]=0x00;
initSysTick();
my_usart1_init();
BEEP_Init();
OLED_Init();
SG90_Init();
Time2_IWDG_Init(9999,7199);
printf("\r\n***************************** 串口测试 *****************************\r\n");
RC522_IO_Init();
PcdReset();
PcdAntennaOff();
delay_ms(100);
PcdAntennaOn();
OLED_Clear();
OLED_ShowString(0,0,"ClockSystem");
SG90_run(0);
delay_ms(500);
printf("\r\n***************************** 智能门锁 *****************************\r\n");
while(Run_flag)
{
if(PcdRequest(0x52,Card_Type1) == MI_OK)
{
uint16_t Card_Type = (Card_Type1[0]<<8 |Card_Type1[1]);
printf("Card TYpe:0x%04x\r\n",Card_Type);
TIM_Cmd(TIM2,DISABLE);
switch(Card_Type)
{
case 0x4400:
printf("Mifare UltraLight\r\n");
break;
case 0x0400:
printf("Mifare One(S50)\r\n");
break;
case 0x0200:
printf("Mifare One(S70)\r\n");
break;
case 0x0800:
printf("Mifare Pro(X)\r\n");
break;
case 0x4403:
printf("Mifare DESFire\r\n");
break;
default:
printf("Unknown Card\r\n");
break;
}
status = PcdAnticoll(Card_ID);
if(status != MI_OK)
{
printf("Anticoll Fault!\r\n");
}
else
{
printf("Card Id = %d %d %d %d\r\n",Card_ID[0],Card_ID[1],Card_ID[2],Card_ID[3]);
flag = Check_Card_Id(Card_ID);
printf("flag = %d\r\n",flag);
if(flag != 0)
{
OLED_ShowString(0,2,"OpenDoor");
SG90_run(90);
BEEP_SUC();
delay_ms(5000);
OLED_ShowString(0,2," ");
SG90_run(0);
}
else
{
printf("flag fault\r\n");
BEEP_FAIL();
delay_ms(5000);
}
}
status = PcdSelect(Card_ID);
if(status != MI_OK)
{
printf("Select Fault!\r\n");
}
else
{
printf("Select Success!\r\n");
}
status = PcdHalt();
if(status != MI_OK)
{
printf("PcdHalt Fault!\r\n");
}
else
{
printf("PcdHalt Success!\r\n");
}
printf("****************************************************************\r\n");
TIM_Cmd(TIM2,ENABLE);
}
}
delay_ms(500);
PcdAntennaOff(); //关闭天线
//错误次数太多
while(Lock_flag)
{
printf("Most Error,Please wait 1 minutes\r\n");
delay_ms(5000);
}
}
1.代码逻辑
- 首先查找卡的类型0x4000,成功返回MI_OK,并打印卡的类型
- 然后防冲撞,并返回卡号放到数组里,并返回MI_OK,并打印卡号,4个字节
- 然后检查卡是否被收入,收入执行开锁,未收入报警,报警六次,Run_flag=0;Lock_flag=1;
- 进入锁定状态,等待看门狗复位
2.Card_Type1[0]=0x04; Card_Type1[1]=0x00;
设置 寻卡请求(PICC Request)的命令参数,用于告诉RC522模块寻找哪种类型的RFID卡。
5.看门狗
cs
#include "Time.h"
#include "stm32f10x.h"
#include "systick.h"
#include "IWDG.h"
int tim_count;
u8 sec = 0;
//u8 min = 0;
void Time2_IWDG_Init(uint16_t arr,uint16_t psc)
{
TIM_TimeBaseInitTypeDef Time_Initstructure;
NVIC_InitTypeDef NVIC_Initstructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
Time_Initstructure.TIM_ClockDivision = TIM_CKD_DIV1;
Time_Initstructure.TIM_CounterMode = TIM_CounterMode_Up;
Time_Initstructure.TIM_Period = arr;
Time_Initstructure.TIM_Prescaler = psc;
Time_Initstructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2,&Time_Initstructure);
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
TIM_Cmd(TIM2,ENABLE);
NVIC_Initstructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_Initstructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Initstructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_Initstructure.NVIC_IRQChannelSubPriority = 0;
NVIC_Init(&NVIC_Initstructure);
}
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
sec++;
if(sec == 30)
{
sec = 0;
IWDG_Init(4,2000);
}
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
}
}
cs
#include "stm32f10x.h"
#include "IWDG.h"
void IWDG_Init(u8 prer,u16 rlr)
{
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
IWDG_SetPrescaler(prer);
IWDG_SetReload(rlr);
IWDG_ReloadCounter();
IWDG_Enable();
}
void IWDG_Feed(void)
{
IWDG_ReloadCounter();
}
实现的功能是
TIM2定时器计一万个数为1s,每记一个数(每一秒),执行一次中断,sec++,一分钟后初始化看门狗,重新复位程序。
一、简介
(原文链接:https://blog.csdn.net/QF_7777777/article/details/126537162)
STM32F10xxx内置两个看门狗,提供了更高的安全性、时间的精确性和使用的灵活性。两个看门狗设备(独立看门狗和窗口看门狗)可用来检测和解决由软件错误引起的故障;当计数器达到给
定的超时值时,触发一个中断(仅适用于窗口型看门狗)或产生系统复位。
独立看门狗(IWDG)由专用的40kHz的低速时钟驱动,即使主时钟发生故障它也仍然有效。窗口看门狗由从APB1时钟分频后得到的时钟驱动,通过可配置的时间窗口来检测应用程序非正常的
过迟或过早的操作。
IWDG最适合应用于那些需要看门狗作为一个在主程序之外,能够完全独立工作,并且对时间精度要求较低的场合。 WWDG最适合那些要求看门狗在精确计时窗口起作用的应用程序。
二、为什么需要看门狗
在由单片机构成的微型计算机系统中,由于单片机的工作常常会受到来自外界电磁场的干扰,造成程序的跑飞,而陷入死循环,程序的正常运行被打断,单片机控制的系统无法继续工作,会造成整个系统陷入停滞状态,发生不可预料的后果,所以出于对单片机运行状态进行实时监测的考虑,便产生了一种专门用于检测单片机程序运行状态的模块或者芯片,俗称"看门狗"。
三、独立看门狗
1、独立看门狗功能描述
- 在键值寄存器(IWDG_KR)中写入0xCCCC,开始启用独立看门狗。此时计数器开始从其复位值0xFFF递减,当计数器值计数到尾值0x000时会产生一个复位信号(IWDG_RESET)。
- 无论何时,只要在键值寄存器IWDG_KR中写入0xAAAA(通常说的喂狗),自动重装载寄存器IWDG_RLR的值就会重新加载到计数器,从而避免看门狗复位。
- 如果程序异常,就无法正常喂狗,从而系统复位。
2、独立看门狗框图

3、独立看门狗超时时间
溢出时间(Overflow Time)指的是定时器从开始计数到计数值达到最大值后归零(溢出)所需要的时间。
溢出时间计算:
Tout = ((4*2^prer)*rlr )/ 40
时钟频率LSI = 40K,一个看门狗时钟周期就是最短超时时间。
最长超时时间 = (IWDG_RLR寄存器最大值)* 看门狗时钟周期。
// 你的配置
TIME2_IWDG_Init(9999, 7199)计算:
- ARR = 9999
- PSC = 7199
- 时钟频率 = 72 MHz
IWDG_Init(4, 2000); // prer=4, rlr=2000
// 计算:
预分频系数 = 64 4*2^4
重载值 = 2000
频率 = 40kHz = 40000Hz
溢出时间 T = (64 × 2000) / 40000 = 128000 / 40000 = 3.2秒
4、独立看门狗操作步骤
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable)
作用:启用对IWDG预分频器(PR)和重装载寄存器(RLR)的写访问
- IWDG的配置寄存器默认是写保护的
- 必须先调用此函数解锁,才能配置预分频器和重装载值
- 参数可以是
IWDG_WriteAccess_Enable(使能写访问)或IWDG_WriteAccess_Disable(禁止写访问)
IWDG_SetPrescaler(prer)
作用:设置IWDG的预分频值
- 决定看门狗计数器的时钟频率
- 参数
prer可选值:
IWDG_Prescaler_4(4分频)IWDG_Prescaler_8(8分频)IWDG_Prescaler_16(16分频)IWDG_Prescaler_32(32分频)IWDG_Prescaler_64(64分频)IWDG_Prescaler_128(128分频)IWDG_Prescaler_256(256分频)
IWDG_SetReload(rlr)
作用:设置IWDG的重装载值
- 决定看门狗超时时间
- 参数
rlr范围:0x000-0xFFF(0-4095)- 超时时间计算公式:
Tout = (4 × 2^prer × rlr) / LSI- 其中LSI是内部低速RC振荡器频率(约40kHz,具体以芯片手册为准)
IWDG_ReloadCounter()
作用:重装载看门狗计数器(俗称"喂狗")
- 将重装载寄存器(RLR)的值重新加载到计数器
- 必须在超时前定期调用此函数,防止系统复位
- 这是应用程序中需要周期性调用的函数
IWDG_Enable()
作用:启动独立看门狗
- 一旦使能,看门狗就开始递减计数
- 使能后无法被软件禁用,只有复位才能停止看门狗
- 必须在所有配置完成后最后调用
注意事项
1.static
主要含义:将函数的作用域限制在当前源文件内,使其成为文件内部的"私有"函数。
具体作用和优点:
- 限制作用域
- 该函数只能在定义它的
.c文件中被访问 - 其他源文件无法调用此函数
- 避免了命名冲突的可能性
- 信息隐藏(封装性)
- 只暴露必要的接口函数给外部
- 隐藏内部实现细节
- 提高代码的模块化和可维护性
2.SPI1
在STM32标准库中:SPI1本质上是一个已经定义好的指针常量
SPI_TypeDef* SPIx // SPIx是一个指针
// 函数声明
static void SPI_RCC_Configuration(SPI_TypeDef* SPIx)
// 函数调用
SPI_RCC_Configuration(SPI1);
// 实际相当于:
SPI_TypeDef* SPIx = SPI1; // SPIx现在指向SPI1的地址
if(SPIx == SPI1)
这里比较的是指针的值(地址),不是指针指向的内容。
3.片选NSS引脚
SPI的片选引脚有两种使用方式:
方式一:硬件自动控制
GPIO_Mode_AF_PP // 复用推挽输出
- SPI硬件自动控制片选信号
- 传输开始时自动拉低,传输结束时自动拉高
- 缺点:通常只支持单主模式,灵活性差
方式二:软件手动控制(常用)
GPIO_Mode_Out_PP // 推挽输出
- 软件手动控制片选电平
- 传输前手动拉低,传输后手动拉高
- 优点:灵活,支持多从设备、可控制时序
3.SPI主模式的SS输出管理
void SPI_SSOutputCmd(SPI_TypeDef* SPIx, FunctionalState NewState);
- 功能说明
这个函数控制SPI主设备是否输出SS(NSS)信号。
- ENABLE: SPI主设备会在它的NSS引脚上输出低电平信号
- DISABLE: SPI主设备的NSS引脚不输出信号(高阻态)
SPI_SSOutputCmd是STM32 SPI硬件NSS功能的关键部分。要使硬件NSS正常工作,需要:
- GPIO配置为复用功能(
AF_PP) - SPI配置为
SPI_NSS_Hard - 调用
SPI_SSOutputCmd(SPIx, ENABLE)
注意:必须在SPI_SSOutputCmd之后进行SPI_Cmd!!
