求助,STM8S105读写RC522,写金额时,偶尔不正常,偶尔金额.

2019-12-22 13:48发布

硬件环境:
使用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();
}

求大神帮忙分析一下原因
       
0条回答

一周热门 更多>