硬件环境:
使用STM8S105K6的SPI连接一块RC522的天线板。
天线板如下图。比较常见的天线板。
QQ截图20170929155723.jpg (73.54 KB, 下载次数: 0)
下载附件
2017-9-29 15:57 上传
没有上拉电阻、下拉电阻、电容等,直连的。MCU板与天线板的连接线大概有5CM。
实现功能:
在while(1)里面,每1秒钟扣1分钱。
还有其它的功能,与刷卡无关。
程序上,使用的坛里下载的,模拟的SPI也尝试过。网上流传的硬件SPI的通信也尝试过。但都未能解决如下两个问题:
1:写金额时,偶尔会把数据写零,这个概率比较低。可能和卡片质量有关。
2:在读写过程中,偶尔感应不到卡片。因为有显示屏,无卡时显示欢迎,有卡时,显示余额。结果就是偶尔的时候欢迎和余额一直跳。
因为,不是经常性的存在,可能读10秒,才会返回一次欢迎界面,也可能全程没有返回。也可能一秒跳一次。所以不好调。
个人经常跟踪,发现,主要问题是,PcdWrite写数据后,返回的不是MI_OK,认为写失败,然后返回欢迎界面。但经过检查,返回的写失败的状态,其实的写成功的。扣过款的。
对比了一下坛里的一位大神的程序。
发现他在PcdRequest前面,没有PcdReset,而我加上了,即每一次都PcdReset。如果不加,感应不到IC卡。
附上程序:求大神帮忙分析一下原因。
main里面的初始化:
SPIInit();//SPI初始化,RC522
RC522_Config();
PcdReset();
PcdAntennaOff();
Msec(1000);
PcdAntennaOn();
while(1)
{
status2=PcdRequest(0x52,CT);//寻卡,输出为卡类型
if(status2==MI_OK) //寻卡成功
{
status2 = PcdAnticoll(SN); //防冲撞处理,输出卡片序列号,4字节--第0扇区第0块前4个字节是UID(序列号)
}
if(status2==MI_OK) //防冲撞成功
{
status2 = PcdSelect(SN); //选卡
}
if(status2==MI_OK) //选卡成功
{
status2 = PcdAuthState(0x60, 5, Card_KEY, SN);//验证卡
}
if(status2==MI_OK) //验证卡成功
{
if(PcdRead(__USER_CARD_BLOCK__,pucCardData) == MI_OK)//读取块正常
{
pucCardData[0] = ((u8*)(&uiUserValue))[0];
pucCardData[1] = ((u8*)(&uiUserValue))[1];
pucCardData[15] = 0x5A;
if(PcdWrite(__USER_CARD_BLOCK__,pucCardData) == MI_OK)
{
}
}
}
SPI初始化程序:
void SPIInit(void)
{
GPIO_Init(GPIOC, GPIO_PIN_2|GPIO_PIN_3, GPIO_MODE_OUT_PP_LOW_SLOW);
SPI_DeInit();
SPI_Init(SPI_FIRSTBIT_MSB, SPI_BAUDRATEPRESCALER_64, SPI_MODE_MASTER,
SPI_CLOCKPOLARITY_LOW, SPI_CLOCKPHASE_1EDGE, SPI_DATADIRECTION_2LINES_FULLDUPLEX,
SPI_NSS_SOFT, 0x07);
SPI_Cmd(ENABLE);
}
//SPI接收
u8 RcvSPIByte(void)
{
//Wait to receive a byte
while(SPI_GetFlagStatus(SPI_FLAG_TXE) == RESET);
//Return the byte read from the SPI bus
SPI_SendData(0);
//Wait to receive a byte
while(SPI_GetFlagStatus(SPI_FLAG_RXNE) == RESET);
//Return the byte read from the SPI bus
return SPI_ReceiveData();
}
//SPI发送
void SPISend(u8 SendValue)
{
//Wait to receive a byte
while(SPI_GetFlagStatus(SPI_FLAG_TXE) == RESET);
//Return the byte read from the SPI bus
SPI_SendData(SendValue);
//Wait to receive a byte
while(SPI_GetFlagStatus(SPI_FLAG_RXNE) == RESET);
//Return the byte read from the SPI bus
SPI_ReceiveData();
}
RC522的驱动程序:
u8 PcdRequest(u8 req_code, u8 *pTagType)
{
u8 status;
u16 unLen;
u8 ucComMF522Buf[MAXRLEN];
PcdReset();//复位RC522
ClearBitMask(Status2Reg, 0x08);
WriteRawRC(BitFramingReg, 0x07);
SetBitMask(TxControlReg, 0x03);
memset(ucComMF522Buf, 0x00, MAXRLEN);
ucComMF522Buf[0] = req_code;
status = PcdComMF522(PCD_TRANSCEIVE, ucComMF522Buf, 1, ucComMF522Buf,&unLen);
if ((status == MI_OK) && (unLen == 0x10))
{
*pTagType = ucComMF522Buf[0];
*(pTagType + 1) = ucComMF522Buf[1];
}
else
{
status = MI_ERR;
}
return status;
}
/////////////////////////////////////////////////////////////////////
//功 能:防冲撞
//参数说明: pSnr[OUT]:卡片序列号,4字节
//返 回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
u8 PcdAnticoll(u8 *pSnr)
{
u8 status;
u8 i, snr_check = 0;
u16 unLen;
u8 ucComMF522Buf[MAXRLEN];
ClearBitMask(Status2Reg, 0x08);
WriteRawRC(BitFramingReg, 0x00);
ClearBitMask(CollReg, 0x80);
memset(ucComMF522Buf, 0x00, MAXRLEN);
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
;
snr_check ^= ucComMF522Buf;
}
if (snr_check != ucComMF522Buf)
{
status = MI_ERR;
}
}
else
{
status = MI_ERR;
}
SetBitMask(CollReg, 0x80);
return status;
}
////////////////////////////////////////////////////////////////////
//功 能:选定卡片
//参数说明: pSnr[IN]:卡片序列号,4字节
//返 回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
u8 PcdSelect(u8 *pSnr)
{
u8 status;
u8 i;
u16 unLen;
u8 ucComMF522Buf[MAXRLEN];
ClearBitMask(Status2Reg, 0x08);
memset(ucComMF522Buf, 0x00, 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]);
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
/////////////////////////////////////////////////////////////////////
u8 PcdAuthState(u8 auth_mode, u8 addr, u8 *pKey, u8 *pSnr)
{
u8 status;
u16 unLen;
u8 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
/////////////////////////////////////////////////////////////////////
u8 PcdRead(u8 addr, u8 *pData)
{
u8 status;
u16 unLen;
u8 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;
}
}
else
{
status = MI_ERR;
}
return status;
}
/////////////////////////////////////////////////////////////////////
//功 能:写数据到M1卡一块
//参数说明: addr[IN]:块地址
// p [IN]:写入的数据,16字节
//返 回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
u8 PcdWrite(u8 addr, u8 *pData)
{
u8 status;
u16 unLen;
u8 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 = 0x04;
}
if (status == MI_OK)
{
for (i = 0; i < 16; i++)
{
ucComMF522Buf = *(pData + i);
}
CalulateCRC(ucComMF522Buf, 16, &ucComMF522Buf[16]);
status = PcdComMF522(PCD_TRANSCEIVE, ucComMF522Buf, 18, ucComMF522Buf,&unLen);
if (status != MI_OK)
{
status = 0x05;
}
else if(unLen != 4)
{
status = 0x06;
}
else if((ucComMF522Buf[0] & 0x0F) != 0x0A)
{
status = 0x07;
}
}
return status;
}
/////////////////////////////////////////////////////////////////////
//用MF522计算CRC16函数
/////////////////////////////////////////////////////////////////////
void CalulateCRC(u8 *pIndata, u8 len,u8 *pOutData)
{
u8 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
/////////////////////////////////////////////////////////////////////
u8 PcdReset(void)
{
RfRSTHigh(); //RST522_1;RST522_1;
Msec(15); //_NOP();_NOP();
RfRSTLow(); //RST522_0;
Msec(15); //_NOP();_NOP();
RfRSTHigh(); //RST522_1;RST522_1;
Msec(15); //_NOP();_NOP();
WriteRawRC(CommandReg, PCD_RESETPHASE);
Msec(15); //_NOP();_NOP();
WriteRawRC(ModeReg, 0x3D); //?Mifare???,CRC???0x6363
WriteRawRC(TModeReg, 0x8D);
WriteRawRC(TReloadRegL, 0x30); //?30?????
WriteRawRC(TReloadRegH, 0);
WriteRawRC(TPrescalerReg, 0x3E);
WriteRawRC(TxAutoReg, 0x40);
Pcb=0x00;
return MI_OK;
}
/////////////////////////////////////////////////////////////////////
//功 能:读RC632寄存器
//参数说明:Address[IN]:寄存器地址
//返 回:读出的值
/////////////////////////////////////////////////////////////////////
u8 ReadRawRC(u8 Address)
{
u8 RcvData,ucAddr;
ucAddr = ((Address << 1) & 0x7E) | 0x80;
RfNSSLow();
SPISend(ucAddr);
RcvData=RcvSPIByte();
RfNSSHigh();
return(RcvData);
}
void WriteRawRC(u8 Address, u8 value)
{
unsigned char ucAddr;
unsigned char i;
ucAddr = ((Address << 1) & 0x7E);
RfNSSLow();
SPISend(ucAddr);
SPISend(value);
RfNSSHigh();
}
void SetBitMask(u8 reg, u8 mask)
{
u8 tmp = 0x0;
tmp = ReadRawRC(reg);
WriteRawRC(reg, tmp | mask); // set bit mask
}
/////////////////////////////////////////////////////////////////////
//功 能:清RC522寄存器位
//参数说明:reg[IN]:寄存器地址
// mask[IN]:清位值
/////////////////////////////////////////////////////////////////////
void ClearBitMask(u8 reg, u8 mask)
{
u8 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]:返回数据的位长度
/////////////////////////////////////////////////////////////////////
u8 PcdComMF522(u8 Command,u8 *pInData,u8 InLenByte,u8 *pOutData,u16 *pOutLenBit)
{
s8 status = MI_ERR;
u8 irqEn = 0x00;
u8 waitFor = 0x00;
u8 lastBits;
u8 n;
u16 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); // 清除FIFO中的读写指针
for (i=0; i<InLenByte; i++)
{
WriteRawRC(FIFODataReg, pInData); //数据写入FIFO
}
WriteRawRC(CommandReg, Command); //写入命令,将缓冲区中的数据发送到天线,并激活自动接收器
TrigWatchDog();
if (Command == PCD_TRANSCEIVE) //如果命令为0C
{
SetBitMask(BitFramingReg,0x80); //相当于启动发送STARTSENG
}
i = 1200; //根据时钟频率调整,操作M1卡最大等待时间=600,操作CPU卡最大等待时间=2000
do
{
n = ReadRawRC(ComIrqReg); //读取中断标志,检查数据返回
i--;
}
while ((i!=0) && !(n&0x01) && !(n&waitFor)); //XX??XX
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; //pOutLenBit记录总共收到的位数
}
else
{
*pOutLenBit = n*8; //接收完整位数
}
if (n == 0) //假如没有中断产生
{
n = 1; //
}
if (n > MAXRLEN) //
{
n = MAXRLEN; //超出最大长度,只接受最大长度的值
}
for (i=0; i<n; i++)
{
pOutData = ReadRawRC(FIFODataReg); //从FIFO读取数据
}
}
}
else
{
status = MI_ERR; //有错误
}
}
SetBitMask(ControlReg,0x80); //停止定时器
WriteRawRC(CommandReg,PCD_IDLE); //清空指令
return status; //返回状态
}
//开启天线
//每次启动或关闭天险发射之间应至少有1ms的间隔
void PcdAntennaOn(void)
{
u8 i;
i = ReadRawRC(TxControlReg);
if (!(i & 0x03))
{
SetBitMask(TxControlReg, 0x03);
}
}
//关闭天线
void PcdAntennaOff(void)
{
ClearBitMask(TxControlReg, 0x03);
}
void RC522_Config(void)
{
ClearBitMask(Status2Reg, 0x08); //状态2寄存器
WriteRawRC(ModeReg, 0x3D); //和Mifare卡通讯,CRC初始值0x6363 //3F
WriteRawRC(RxSelReg, 0x86);//XX??XX 10//选择内部接收器设置,内部模拟部分调制信号,发送数据后,延时6个位时钟,接收 10
WriteRawRC(RFCfgReg, 0x7F);//配置接收器,48dB最大增益
WriteRawRC(TReloadRegL, 0x30); ////定时器的低8位数据
WriteRawRC(TReloadRegH, 0);//定时器的高8位数据,实际值是0xD3E这部分主要是设置定时器寄存器
WriteRawRC(TModeReg, 0x8D); //实际值是0X0D3E这部分主要是设置定时器寄存器TPrescaler 分频数为0xD0 //8D
WriteRawRC(TPrescalerReg, 0x3E);//????XXXX
Msec(1000);
PcdAntennaOn();
}
求大神帮忙分析一下原因
一周热门 更多>