RFID射频卡与存储模块AT24X

RC522(RFID模块)实践总结

此次使用RC522模块和S50卡实现近场通讯功能(开发板与RC522通讯方式为硬件SPI),就实践过程中的一些知识点进行总结:

  • RC522模块和M1卡要点介绍;

  • 驱动代码;

  • 出现问题及解决方法;

RFID 射频卡工作原理

S50 卡内置了几组线圈,读写器向卡发一组固定频率的电磁波,卡片内有一个 LC 串联谐振电路,其频率与 读写器发射的频率相同,在电磁波的激励下,LC 谐振电路产生共振,从而使电容内有了电荷,在这个电容的另一端,接有一个单向导通的电子泵,将电容内的电荷送到另一个电容内储存,当所积累的电荷达到 2V 时,此电 容可做为电源为其它电路提供工作电压,将卡内数据发射出去或接取读写器的数据。

RFID 射频卡通信协议

RC522 模块提供了两种通信接口,分别是 I 2C 串行通信SPI 串行通信。数据传输顺序为先传高位,再传低 位。在 I 2C 串行通信模式下,支持快速模式(400Kbit/s)和高速模式(3400Kbit/s)。在 SPI 串行通信模式下,最 大的传输速度为 10Mbit/s,数据与时钟相位关系满足“空闲态时钟为低电平,在时钟上升沿同步接收和发送数据, 在下降沿数据转换”的约束关系。

本实验用的是SPI接口,时钟主频84MHZ,所以分频系数最小8分频。

原理图分析

RC522 模块通过标准的 SPI 通信接口与 MCU 进行数据传输,使用标准 SPI 通信协议对 RC522 进行操作, 就可以完成对卡片进行读取和写操作。

1. RC522模块和M1卡要点介绍:

M1卡存储结构

存储结构:

在这里插入图片描述

其中第0扇区的块0是用于存放厂商代码的,已经固化,不可更改,为32位(4Bytes);

每个扇区的块0、块1和块2位数据块,可用于存储数据,每块16个字节(只有S50卡是这样);

每个扇区的块3位控制块,包含了密码A、存取控制、密码B,具体结构如下图所示;

在这里插入图片描述


2.工作原理

原理

读写器向M1卡发一组固定频率的电磁波,卡片内有一个LC串联谐振电路,其频率与读写器发射的频率相同,在电磁波的激励下,LC谐振电路产生共振,从而使电容内有了电荷,在这个电容的另一端,接有一个单向导通的电子泵,将电容内的电荷送到另一个电容内储存,当所积累的电荷达到2V时,此电容可做为电源为其它电路提供工作电压,将卡内数据发射出去或接取读写器的数据。

3.RFID卡识别过程:

(1)寻卡

(2)防冲突

   在很多应用场合,读写器要在很短时间内尽快识别多个标签。由于读写器和标签通信共享无线信道,读写器或标签的信号可能发生冲突,使读写器不能正确识别标签,即发生了碰撞(Collision),

(3)选卡

   选择被选中的卡的序列号,并同时返回卡的容量代码。

(4)操作卡

  选定要处理的卡片之后,读写器就确定要访问的扇区号,并对该扇区密码进行密码校验,在三次相互认证之后就可以通过加密流进行通讯。(在选择另一扇区时,则必须进行另一扇区密码校验。)

4.M1射频卡与读写器的通讯

  • 复位应答(Answer to request)

      M1射频卡的通讯协议和通讯波特率是定义好的,当有卡片进入读写器的操作范围时,读写器以特定的协议与它通讯,从而 确定该卡是否为M1射频卡,即验证卡片的卡型。

  • 防冲突机制 (Anticollision Loop)

      当有多张卡进入读写器操作范围时,防冲突机制会从其中选择一张进行操作,未选中的则处于空闲模式等待下一次选卡,该过程会返回被选卡的序列号。

  • 选择卡片(Select Tag)

      选择被选中的卡的序列号,并同时返回卡的容量代码。

  • 三次互相确认(3 Pass Authentication)

      选定要处理的卡片之后,读写器就确定要访问的扇区号,并对该扇区密码进行密码校验,在三次相互认证之后就可以通过加密流进行通讯。(在选择另一扇区时,则必须进行另一扇区密码校验。)

3. 驱动代码

RC522.h

 #ifndef __RC522_H
 #define __RC522_H   
 #include "stm32f10x.h"
 #include "stm32f10x_spi.h"
 #include <string.h>
 #include <stdio.h>
 ​
 /*******************************
 *连线说明:
 *1--SDA  <----->PA4
 *2--SCK  <----->PA5
 *3--MOSI <----->PA7
 *4--MISO <----->PA6
 *5--悬空
 *6--GND <----->GND
 *7--RST <----->PB0
 *8--VCC <----->VCC
 ************************************/
 ​
 //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               //休眠
 ​
 #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
 ​
 //和RC522通讯时返回的M1卡状态
 #define     MI_OK                 0x26
 #define     MI_NOTAGERR           0xcc
 #define     MI_ERR                0xbb
 ​
 //和MF522通讯时返回的错误代码
 #define     SHAQU1                0X01
 #define     KUAI4                 0X04
 #define     KUAI7                 0X07
 #define     REGCARD               0xa1
 #define     CONSUME               0xa2
 #define     READCARD              0xa3
 #define     ADDMONEY              0xa4
 ​
 #define SPI_RC522_ReadByte()          SPI_RC522_SendByte(0)
 ​
 #define SET_SPI_CS  (GPIOF->BSRR=0X01)
 #define CLR_SPI_CS  (GPIOF->BRR=0X01)
 ​
 #define SET_RC522RST  GPIOF->BSRR=0X02
 #define CLR_RC522RST  GPIOF->BRR=0X02
 ​
 ​
 /***********************RC522 函数宏定义**********************/
 #define          RC522_CS_Enable()         GPIO_ResetBits ( GPIOA, GPIO_Pin_4 )
 #define          RC522_CS_Disable()        GPIO_SetBits ( GPIOA, GPIO_Pin_4 )
 ​
 #define          RC522_Reset_Enable()      GPIO_ResetBits( GPIOB, GPIO_Pin_0 )
 #define          RC522_Reset_Disable()     GPIO_SetBits ( GPIOB, GPIO_Pin_0 )
 ​
 #define          RC522_SCK_0()             GPIO_ResetBits( GPIOA, GPIO_Pin_5 )
 #define          RC522_SCK_1()             GPIO_SetBits ( GPIOA, GPIO_Pin_5 )
 ​
 #define          RC522_MOSI_0()            GPIO_ResetBits( GPIOA, GPIO_Pin_7 )
 #define          RC522_MOSI_1()            GPIO_SetBits ( GPIOA, GPIO_Pin_7 )
 ​
 #define          RC522_MISO_GET()          GPIO_ReadInputDataBit ( GPIOA, GPIO_Pin_6 )
 ​
 u8       SPI_RC522_SendByte         ( u8 byte);
 u8       ReadRawRC                  ( u8 ucAddress );
 void     WriteRawRC                 ( u8 ucAddress, u8 ucValue );
 void     SPI1_Init                  ( void );
 void     RC522_Handel               ( void );
 void     RC522_Init                 ( void );                       //初始化
 void     PcdReset                   ( void );                       //复位
 void     M500PcdConfigISOType       ( u8 type );                    //工作方式
 char     PcdRequest                 ( u8 req_code, u8 * pTagType ); //寻卡
 char     PcdAnticoll                ( u8 * pSnr);                   //防冲撞
 ​
 void     PcdAntennaOn               ( void );                 //开启天线
 void     PcdAntennaOff              ( void );                 //关闭天线
 void     SetBitMask                 ( u8 ucReg, u8 ucMask );
 void     ClearBitMask               ( u8 ucReg, u8 ucMask );
 char     PcdSelect                  ( u8 * pSnr );            //选择卡片
 char     PcdAuthState               ( u8 ucAuth_mode, u8 ucAddr, u8 * pKey, u8 * pSnr );                                              //验证密码
 char     PcdWrite                   ( u8 ucAddr, u8 * pData );
 char     PcdRead                    ( u8 ucAddr, u8 * pData );
 void     ShowID                     ( u16 x,u16 y, u8 *p, u16 charColor, u16 bkColor);   //显示卡的卡号,以十六进制显示
 char             PcdHalt            ( void );           //命令卡片进入休眠状态
 void             CalulateCRC                ( u8 * pIndata, u8 ucLen, u8 * pOutData );
 ​
 #endif
 ​


RC522.c

 #include "rc522.h"
 #include "./SysTick/bsp_SysTick.h"
 #include "./usart/bsp_usart.h"
 #include "stm32f10x_spi.h"
 ​
 // M1卡分为16个扇区,每个扇区由四个块(块0、块1、块2、块3)组成
 // 将16个扇区的64个块按绝对地址编号为:0~63
 // 第0个扇区的块0(即绝对地址0块),用于存放厂商代码,已经固化不可更改 
 // 每个扇区的块0、块1、块2为数据块,可用于存放数据
 // 每个扇区的块3为控制块(绝对地址为:块3、块7、块11.....)包括密码A,存取控制、密码B等
 ​
 /*******************************
 *连线说明:
 *1--SDA  <----->PA4
 *2--SCK  <----->PA5
 *3--MOSI <----->PA7
 *4--MISO <----->PA6
 *5--悬空
 *6--GND <----->GND
 *7--RST <----->PB0
 *8--VCC <----->VCC
 ************************************/
 ​
 #define   RC522_DELAY()  delay_us( 2 ) 
 ​
 /*全局变量*/
 unsigned char CT[2];            //卡类型
 unsigned char SN[4];            //卡号
 unsigned char RFID[16];             //存放RFID 
 unsigned char lxl_bit=0;
 unsigned char card1_bit=0;
 unsigned char card2_bit=0;
 unsigned char card3_bit=0;
 unsigned char card4_bit=0;
 unsigned char total=0;
 unsigned char lxl[4]={196,58,104,217};
 unsigned char card_1[4]={83,106,11,1};
 unsigned char card_2[4]={208,121,31,57};
 unsigned char card_3[4]={176,177,143,165};
 unsigned char card_4[4]={5,158,10,136};
 u8 KEY[6]={0xff,0xff,0xff,0xff,0xff,0xff};
 u8 AUDIO_OPEN[6] = {0xAA, 0x07, 0x02, 0x00, 0x09, 0xBC};
 unsigned char RFID1[16]={0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x07,0x80,0x29,0xff,0xff,0xff,0xff,0xff,0xff};
 /*函数声明*/
 unsigned char status;
 unsigned char s=0x08;
 ​
 /* 函数名:RC522_Init
  * 描述  :初始化RC522配置
  * 输入  :无
  * 返回  : 无
  * 调用  :外部调用              */
 void RC522_Init ( void )
 {
     SPI1_Init(); 
     RC522_Reset_Disable();        //将RST置高,启动内部复位阶段;
   PcdReset ();                  //复位RC522 
   PcdAntennaOff();              //关闭天线
     RC522_DELAY();                //delay 1ms
   PcdAntennaOn();               //打开天线
     M500PcdConfigISOType ( 'A' ); //设置工作方式
 }
 ​
 /* 函数名:SPI1_Init
  * 描述  :初始化SPI1的配置
  * 输入  :无
  * 返回  : 无
  * 调用  :外部调用              */
 void SPI1_Init (void)   
 {
       SPI_InitTypeDef  SPI_InitStructure; 
       GPIO_InitTypeDef GPIO_InitStructure;
       RCC_APB2PeriphClockCmd(   RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE );//PORTB时钟使能 
     
       // CS
     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;    
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;         //推挽输出
     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;        //IO口速度为50MHz
     GPIO_Init(GPIOA, &GPIO_InitStructure);                   //根据设定参数初始化PF0、PF1
     
     // SCK
     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;    
     GPIO_Init(GPIOA, &GPIO_InitStructure);
     
     // MISO
     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;    
     GPIO_Init(GPIOA, &GPIO_InitStructure);
     
     // MOSI
     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;    
     GPIO_Init(GPIOA, &GPIO_InitStructure);
     
     // RST
     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;    
     GPIO_Init(GPIOB, &GPIO_InitStructure);
         
         //置高CS口
     RC522_CS_Disable();
 ​
     //其他SPI1配置
     SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;            //全双工;
     SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                                //主机模式;
     SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;                            //传输数据为8位;
     SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;                                   //时钟极性CPOL为空闲时低电平;
     SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;                                 //时钟采样点为时钟奇数沿(上升沿);
     SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                                    //NSS引脚由软件改变;
     SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;          //预分频系数64;
     SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;                           //MSB先行模式;
     SPI_InitStructure.SPI_CRCPolynomial = 7;                                     //CRC校验;
         
    //初始化SPI1
     SPI_Init(SPI1 , &SPI_InitStructure);
         
    //使能SPI1
     SPI_Cmd(SPI1 , ENABLE); 
  }
 ​
 /* 函数名:PcdRese
  * 描述  :复位RC522 
  * 输入  :无
  * 返回  : 无
  * 调用  :外部调用              */
 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 );
     WriteRawRC ( ModeReg, 0x3D );                //定义发送和接收常用模式 和Mifare卡通讯,CRC初始值0x6363
     WriteRawRC ( TReloadRegL, 30 );              //16位定时器低位    
     WriteRawRC ( TReloadRegH, 0 );               //16位定时器高位
     WriteRawRC ( TModeReg, 0x8D );               //定义内部定时器的设置
     WriteRawRC ( TPrescalerReg, 0x3E );          //设置定时器分频系数
     WriteRawRC ( TxAutoReg, 0x40 );              //调制发送信号为100%ASK       
 }
 ​
 /* 函数名:SPI_RC522_SendByte
  * 描述  :向RC522发送1 Byte 数据
  * 输入  :byte,要发送的数据
  * 返回  : RC522返回的数据
  * 调用  :内部调用                 */
 u8 SPI_RC522_SendByte ( u8 byte )
 {
       while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);         
     SPI_I2S_SendData(SPI1, byte);                     
     while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); 
     return  SPI_I2S_ReceiveData(SPI1);
 }
 ​
 ​
 /* 函数名:ReadRawRC
  * 描述  :读RC522寄存器
  * 输入  :ucAddress,寄存器地址
  * 返回  : 寄存器的当前值
  * 调用  :内部调用                 */
 u8 ReadRawRC ( u8 ucAddress )
 {
     u8 ucAddr, ucReturn;
     ucAddr = ( ( ucAddress << 1 ) & 0x7E ) | 0x80;      
 ​
     RC522_CS_Enable();
     SPI_RC522_SendByte ( ucAddr );
     ucReturn = SPI_RC522_ReadByte ();
     RC522_CS_Disable();
     return ucReturn;
 }
 ​
 ​
  /* 函数名:WriteRawRC
  * 描述  :写RC522寄存器
  * 输入  :ucAddress,寄存器地址  、 ucValue,写入寄存器的值
  * 返回  : 无
  * 调用  :内部调用   */
 void WriteRawRC ( u8 ucAddress, u8 ucValue )
 {  
     u8 ucAddr;
     ucAddr = ( ucAddress << 1 ) & 0x7E;   
     
     RC522_CS_Enable();  
     SPI_RC522_SendByte ( ucAddr );
     SPI_RC522_SendByte ( ucValue );
     RC522_CS_Disable(); 
 }
 ​
 /* 函数名:M500PcdConfigISOType
  * 描述  :设置RC522的工作方式
  * 输入  :ucType,工作方式
  * 返回  : 无
  * 调用  :外部调用        */
 void M500PcdConfigISOType ( u8 ucType )
 {
     if ( ucType == 'A')                     //ISO14443_A
   {
         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 );
         delay_us   ( 2 );
         
         PcdAntennaOn ();//开天线
    }
 }
 ​
 /*
  * 函数名:SetBitMask
  * 描述  :对RC522寄存器置位
  * 输入  :ucReg,寄存器地址
  *         ucMask,置位值
  * 返回  : 无
  * 调用  :内部调用
  */
 void SetBitMask ( u8 ucReg, u8 ucMask )  
 {
     u8 ucTemp;
 ​
     ucTemp = ReadRawRC ( ucReg );
     WriteRawRC ( ucReg, ucTemp | ucMask );         // set bit mask
 }
 ​
 /* 函数名:ClearBitMask
  * 描述  :对RC522寄存器清位
  * 输入  :ucReg,寄存器地址
  *         ucMask,清位值
  * 返回  : 无
  * 调用  :内部调用           */
 void ClearBitMask ( u8 ucReg, u8 ucMask )  
 {
     u8 ucTemp;
     ucTemp = ReadRawRC ( ucReg );
     
     WriteRawRC ( ucReg, ucTemp & ( ~ ucMask) );  // clear bit mask
     
 }
 ​
 /* 函数名:PcdAntennaOn
  * 描述  :开启天线 
  * 输入  :无
  * 返回  : 无
  * 调用  :内部调用            */
 void PcdAntennaOn ( void )
 {
     u8 uc;
     uc = ReadRawRC ( TxControlReg );
     
     if ( ! ( uc & 0x03 ) )
             SetBitMask(TxControlReg, 0x03);
 ​
 }
 ​
 /* 函数名:PcdAntennaOff
  * 描述  :开启天线 
  * 输入  :无
  * 返回  : 无
  * 调用  :内部调用             */
 void PcdAntennaOff ( void )
 {
     ClearBitMask ( TxControlReg, 0x03 );
 }
 ​
 void ShowID(u16 x,u16 y, u8 *p, u16 charColor, u16 bkColor)  //显示卡的卡号,以十六进制显示
 {
     u8 num[9];
 ​
     printf("ID>>>%s\r\n", num);
 ​
 }
 ​
 /* 函数名:PcdComMF522
  * 描述  :通过RC522和ISO14443卡通讯
  * 输入  :ucCommand,RC522命令字
  *         pInData,通过RC522发送到卡片的数据
  *         ucInLenByte,发送数据的字节长度
  *         pOutData,接收到的卡片返回数据
  *         pOutLenBit,返回数据的位长度
  * 返回  : 状态值
  *         = MI_OK,成功
  * 调用  :内部调用              */
 char PcdComMF522 ( u8 ucCommand, u8 * pInData, u8 ucInLenByte, u8 * pOutData, u32 * pOutLenBit )        
 {
     char cStatus = MI_ERR;
     u8 ucIrqEn   = 0x00;
     u8 ucWaitFor = 0x00;
     u8 ucLastBits;
     u8 ucN;
     u32 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;
              
     }
    
     WriteRawRC ( ComIEnReg, ucIrqEn | 0x80 );       //IRqInv置位管脚IRQ与Status1Reg的IRq位的值相反 
     ClearBitMask ( ComIrqReg, 0x80 );           //Set1该位清零时,CommIRqReg的屏蔽位清零
     WriteRawRC ( CommandReg, PCD_IDLE );        //写空闲命令
     SetBitMask ( FIFOLevelReg, 0x80 );          //置位FlushBuffer清除内部FIFO的读和写指针以及ErrReg的BufferOvfl标志位被清除
     
     for ( ul = 0; ul < ucInLenByte; ul ++ )
         WriteRawRC ( FIFODataReg, pInData [ ul ] );         //写数据进FIFOdata
             
     WriteRawRC ( CommandReg, ucCommand );                   //写命令
    
     
     if ( ucCommand == PCD_TRANSCEIVE )
             SetBitMask(BitFramingReg,0x80);                 //StartSend置位启动数据发送 该位与收发命令使用时才有效
     
     ul = 1000;//根据时钟频率调整,操作M1卡最大等待时间25ms
         
     do                                                      //认证 与寻卡等待时间    
     {
          ucN = ReadRawRC ( ComIrqReg );                         //查询事件中断
          ul --;
     } while ( ( ul != 0 ) && ( ! ( ucN & 0x01 ) ) && ( ! ( ucN & ucWaitFor ) ) );       //退出条件i=0,定时器中断,与写空闲命令
         
     ClearBitMask ( BitFramingReg, 0x80 );                   //清理允许StartSend位
         
     if ( ul != 0 )
     {
         if ( ! (( ReadRawRC ( ErrorReg ) & 0x1B )) )            //读错误标志寄存器BufferOfI CollErr ParityErr ProtocolErr
         {
             cStatus = MI_OK;
             
             if ( ucN & ucIrqEn & 0x01 )                 //是否发生定时器中断
               cStatus = MI_NOTAGERR;   
                 
             if ( ucCommand == PCD_TRANSCEIVE )
             {
                 ucN = ReadRawRC ( FIFOLevelReg );           //读FIFO中保存的字节数
                 
                 ucLastBits = ReadRawRC ( ControlReg ) & 0x07;   //最后接收到得字节的有效位数
                 
                 if ( ucLastBits )
                     * pOutLenBit = ( ucN - 1 ) * 8 + ucLastBits;    //N个字节数减去1(最后一个字节)+最后一位的位数 读取到的数据总位数
                 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;
 }
 ​
 ​
 /* 函数名:PcdRequest
  * 描述  :寻卡
  * 输入  :ucReq_code,寻卡方式
  *                     = 0x52,寻感应区内所有符合14443A标准的卡
  *                     = 0x26,寻未进入休眠状态的卡
  *         pTagType,卡片类型代码
  *                   = 0x4400,Mifare_UltraLight
  *                   = 0x0400,Mifare_One(S50)
  *                   = 0x0200,Mifare_One(S70)
  *                   = 0x0800,Mifare_Pro(X))
  *                   = 0x4403,Mifare_DESFire
  * 返回  : 状态值
  *         = MI_OK,成功
  * 调用  :外部调用            */
 char PcdRequest ( u8 ucReq_code, u8 * pTagType )
 {
     char cStatus;  
     u8 ucComMF522Buf [ MAXRLEN ]; 
     u32 ulLen;
 ​
     ClearBitMask ( Status2Reg, 0x08 );  //清理指示MIFARECyptol单元接通以及所有卡的数据通信被加密的情况
     WriteRawRC ( BitFramingReg, 0x07 ); //  发送的最后一个字节的 七位
     SetBitMask ( TxControlReg, 0x03 );  //TX1,TX2管脚的输出信号传递经发送调制的13.56的能量载波信号
 ​
     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;
 }
 ​
 /* 函数名:PcdAnticoll
  * 描述  :防冲撞
  * 输入  :pSnr,卡片序列号,4字节
  * 返回  : 状态值
  *         = MI_OK,成功
  * 调用  :外部调用           */
 char PcdAnticoll ( u8 * pSnr )
 {
     char cStatus;
     u8 uc, ucSnr_check = 0;
     u8 ucComMF522Buf [ MAXRLEN ]; 
       u32 ulLen;
 ​
     ClearBitMask ( Status2Reg, 0x08 );      //清MFCryptol On位 只有成功执行MFAuthent命令后,该位才能置位
     WriteRawRC ( BitFramingReg, 0x00);      //清理寄存器 停止收发
     ClearBitMask ( CollReg, 0x80 );         //清ValuesAfterColl所有接收的位在冲突后被清除
    
     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;
 }
 ​
 /* 函数名:PcdSelect
  * 描述  :选定卡片
  * 输入  :pSnr,卡片序列号,4字节
  * 返回  : 状态值
  *         = MI_OK,成功
  * 调用  :外部调用         */
 char PcdSelect ( u8 * pSnr )
 {
     char ucN;
     u8 uc;
       u8 ucComMF522Buf [ MAXRLEN ]; 
     u32  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; 
 }
 ​
 /* 函数名:CalulateCRC
  * 描述  :用RC522计算CRC16
  * 输入  :pIndata,计算CRC16的数组
  *         ucLen,计算CRC16的数组字节长度
  *         pOutData,存放计算结果存放的首地址
  * 返回  : 无
  * 调用  :内部调用              */
 void CalulateCRC ( u8 * pIndata, u8 ucLen, u8 * pOutData )
 {
     u8 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 );
     
 }
 ​
 /* 函数名:PcdAuthState
  * 描述  :验证卡片密码
  * 输入  :ucAuth_mode,密码验证模式
  *                     = 0x60,验证A密钥
  *                     = 0x61,验证B密钥
  *         u8 ucAddr,块地址
  *         pKey,密码
  *         pSnr,卡片序列号,4字节
  * 返回  : 状态值
  *         = MI_OK,成功
  * 调用  :外部调用          */
 char PcdAuthState ( u8 ucAuth_mode, u8 ucAddr, u8 * pKey, u8 * pSnr )
 {
     char cStatus;
     u8 uc, ucComMF522Buf [ MAXRLEN ];
     u32 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;    
 }
 ​
 /* 函数名:PcdWrite
  * 描述  :写数据到M1卡一块
  * 输入  :u8 ucAddr,块地址
  *         pData,写入的数据,16字节
  * 返回  : 状态值
  *         = MI_OK,成功
  * 调用  :外部调用           */
 char PcdWrite ( u8 ucAddr, u8 * pData )
 {
     char cStatus;
       u8 uc, ucComMF522Buf [ MAXRLEN ];
     u32 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;
     
 }
 ​
 /* 函数名:PcdRead
  * 描述  :读取M1卡一块数据
  * 输入  :u8 ucAddr,块地址
  *         pData,读出的数据,16字节
  * 返回  : 状态值
  *         = MI_OK,成功
  * 调用  :外部调用             */
 char PcdRead ( u8 ucAddr, u8 * pData )
 {
     char cStatus;
       u8 uc, ucComMF522Buf [ MAXRLEN ]; 
     u32 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;
 ​
 }
 ​
 /* 函数名:PcdHalt
  * 描述  :命令卡片进入休眠状态
  * 输入  :无
  * 返回  : 状态值
  *         = MI_OK,成功
  * 调用  :外部调用        */
 char PcdHalt( void )
 {
     u8 ucComMF522Buf [ MAXRLEN ]; 
     u32  ulLen;
 ​
     ucComMF522Buf [ 0 ] = PICC_HALT;
     ucComMF522Buf [ 1 ] = 0;
 ​
     CalulateCRC ( ucComMF522Buf, 2, & ucComMF522Buf [ 2 ] );
     PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 4, ucComMF522Buf, & ulLen );
 ​
     return MI_OK;   
 }
  • SPI传输速率设置问题:SPI口例程中的预分频默认为4,而RC522中的SPI最高速率为10MHz/S,计算可知,预分频指数至少为8,所以适当升高预分频数,据反馈,预分频为8也容易出错,所以建议32或者64甚至为256;

  • SPI时序问题:根据文档中的时序图,仔细设置SPI_InitStructure.SPI_CPOL和SPI_InitStructure.SPI_CPHA这两个参数;

  • SPI口的GPIO模式设置:我以前在设计TM1638芯片为核心的灯、按键模组时也出现过这个问题,后来一般全部设置为推挽输出就基本不在出现这个问题;

  • 天线在复位时需要先关闭再开启;

低功耗

查阅资料没明白这个低功耗应该怎么设置,翻阅了一个前辈的方法。

1,使用RTC,定时唤醒读卡。

2,添加外部检测卡的传感器,单片机正常情况下处于断电模式(这是终极省电),由外部的检测部分唤醒,然后运行程序;在程序的最开始判断是被那个部分唤醒的,然后进行响应的处理。

采用一个检测卡的传感器,一旦扫描到卡就将信号传出去通过或门电路唤醒单片机,单片机自锁上电信号,判断到卡片。然后开始寻卡

- 如果没有扫到卡,就关闭自锁信号,再次关机,回到低功耗模式

关于RC522刷卡低功耗解决方案 - 简书 (jianshu.com)

EEPROM规格

项目中使用AT24C02存储了RFID识别的卡号以及绑定的手机号数据

卡号数据:4位

在项目中,卡号与手机号绑定,即

typedef struct {      

    uint8_t icCardNumber[4];    //IC卡号

    uint8_t phoneNumber[12];    //绑定手机号

} Part1Data;

AT24C04的每页有16字节空间,刚好够一页。

读写数据代码:


/*
****************************************************************************************
* INCLUDES (头文件包含)
****************************************************************************************
*/
#include "at24c04.h"
#include "iic3.h"
#include "delay.h"
#include "stdio.h"
#include <string.h>

/*
****************************************************************************************
* Function: At24c04Init
* Description: At24c04初始化
* Input: None
* Output: None
* Return: None
****************************************************************************************
*/
void At24c02Init(void)
{
	IIC3_Pin_Init( );
}

/*
****************************************************************************************
* Function: At24c02WriteByte
* Description: -----------------------------------------------------写1字节数据到At24c02
* Input: addr内部地址(0~255)  data待写入的数据
* Output: None
* Return: 0成功写入  其他:错误码
****************************************************************************************
*/
uint8_t At24c04WriteByte(uint16_t addr,uint8_t data)
{
	uint8_t ack;
	
	/* 1,发送起始信号  */
	IIC3_Start( );        
	
	/*   2,发送写操作  并等待应答信号    */
	ack=IIC3_Send_Byte(AT24C02_ADDR_W);
	if(ack)
	{
		IIC3_Stop( );
		return WRITE_ERR1;
	}
	Delay_nms(10);
	/* 发送内存地址  并等待应答信号  */
	ack=IIC3_Send_Byte(addr);
	if(ack)
	{
		IIC3_Stop( );
		return WRITE_ERR2;
	}
	Delay_nms(10);
	/* 发送写入数据  并等待应答信号 */
	ack=IIC3_Send_Byte(data);
	if(ack)
	{
		IIC3_Stop( );
		return WRITE_ERR3;
	}
	/* 发送停止信号      */
	IIC3_Stop( );
	/* 等待eeprom的写入完成     要求5ms */
	Delay_nms(10);
	
	return 0;
}

/*
****************************************************************************************
* Function: At24c02readByte
* Description: -----------------------------------------------------读1字节数据到At24c02
* Input: addr内部地址(0~255)  
* Output: None
* Return: 读的数据
****************************************************************************************
*/
uint8_t At24c02readByte(uint16_t addr)
{
	uint8_t ack;
	uint8_t rec=2;
	
	/* 1,发送起始信号  */
	IIC3_Start( );        
	
	/* 2,发送写操作  并等待应答信号  */
	ack=IIC3_Send_Byte(AT24C02_ADDR_W);
	if(ack)
	{
		IIC3_Stop( );
		return WRITE_ERR1;
	}
	Delay_nms(10);
	/* 发送内存地址  并等待应答信号  */
	ack=IIC3_Send_Byte(addr);
	if(ack)
	{
		IIC3_Stop( );
		return WRITE_ERR2;
	}
	Delay_nms(10);
	/* 发送起始信号  */
	IIC3_Start( );  
	
	/*   2,发送读操作  并等待应答信号    */
	ack=IIC3_Send_Byte(AT24C02_ADDR_R);
	if(ack)
	{
		IIC3_Stop( );
		return WRITE_ERR3;
	}
	Delay_nms(10);
	rec = IIC3_Revice_Byte(0);     //  获取数据地址就行,不需要应答    0非应答   1应答  
	Delay_nms(10);
	/* 发送停止信号      */
	IIC3_Stop( );
	
	return rec;
}

/*
****************************************************************************************
* Function: At24c02PageWrite
* Description: ---------------------------------------------------------------页写At24c02
* Input: addr内部地址(0~255)  num待写入的数据个数  p指向待写入的数据
* Output: None
* Return: 0成功写入  其他:错误码
****************************************************************************************
*/
uint8_t At24c02PageWrite(uint16_t addr,uint8_t num,uint8_t *p)
{
	uint8_t ack=0;
	
	//起始地址---addr
	//结束地址---addr+num-1
	
//	if(addr/8 != (addr+num-1)/8)
//	{
//		return NOT_IN_SAME_PAGE;
//	}
	
	IIC3_Start( );
	
	ack=IIC3_Send_Byte(AT24C02_ADDR_W);//发送器件地址+写方向
	if(ack)
	{
		IIC3_Stop( );
		return WRITE_ERR4;
	}
	
	ack=IIC3_Send_Byte(addr);//发送内部地址
	if(ack)
	{
		IIC3_Stop( );
		return WRITE_ERR5;
	}
	
	while(num--)
	{
		ack=IIC3_Send_Byte(*p);//发送数据
		if(ack)
		{
			IIC3_Stop( );
			return WRITE_ERR3;
		}
		p++;
	}
	
	IIC3_Stop( );
	
	Delay_nms(5);//写周期!!!!!!!!!!!!!!!!
	
	return 0;
}

/*
****************************************************************************************
* Function: At24c02WriteBytes
* Description: -------------------------------------------------------------随机写At24c02
* Input: addr内部地址(0~511)  num要写入的数据个数(1~256)  p指向数据存储空间
* Output: None
* Return: 0成功写入  其他:错误码
* Others: 起始地址跟结束地址在同一页
****************************************************************************************
*/
uint8_t At24c02WriteBytes(uint16_t addr,uint16_t num,uint8_t *p)
{
	uint8_t ret=0;
	uint8_t less_addr=0;//当前页还剩下多少个地址空间可以写
	
	while(1)
	{
		less_addr=8-addr%8;
		if(less_addr>=num)//本页可以写完
		{
			less_addr=num;
		}
			
		ret=At24c02PageWrite(addr,less_addr,p);
		if(ret)
		{
			return ret;
		}
		
		if(less_addr==num)
		{
			return 0;
		}
		
		addr=addr+less_addr;//下一页的起始地址
		num=num-less_addr;//还剩下多少个数据没写
		p=p+less_addr;//偏移到还没写的数据
	}
	
}

/*
****************************************************************************************
* Function: At24c02ReadBytes
* Description:--------------------------------------------------------------随机读At24c02
* Input: addr内部地址(0~255)  num要读取的数据个数  p指向数据存储空间
* Output: None
* Return: 0成功写入  其他:错误码
* Others: 起始地址跟结束地址在同一页
****************************************************************************************
*/
uint8_t At24c02ReadBytes(uint16_t addr,uint16_t num,uint8_t *p)
{
	uint8_t ack=0;
	
	IIC3_Start( );
	
	ack=IIC3_Send_Byte(AT24C02_ADDR_W);//发送器件地址+写方向
	if(ack)
	{
		IIC3_Stop( );
		return READ_ERR1;
	}
	
	ack=IIC3_Send_Byte(addr);//发送内部地址
	if(ack)
	{
		IIC3_Stop( );
		return READ_ERR2;
	}
	
	IIC3_Start( );//重复起始条件
	
	ack=IIC3_Send_Byte(AT24C02_ADDR_R);//发送器件地址+读方向
	if(ack)
	{
		IIC3_Stop( );
		return READ_ERR3;
	}
	
	while(num)
	{
		num--;//还剩下多少个字节没有读
		if(num==0)
		{
			*p=IIC3_Revice_Byte(1);
			break;
		}
		*p++=IIC3_Revice_Byte(0);
		
	}
	
	IIC3_Stop( );
	
	return 0;
}

/*
****************************************************************************************
* Function: At24c02ChipErase
* Description:--------------------------------------------------------------擦除At24c02
* Input: 
* Output: 
* Return: 
* Others: 
****************************************************************************************
*/
void At24c02ChipErase() 
{
    // 将所有字节设置为 0xFF(擦除状态)
    uint8_t eraseData[256];
    for (int i = 0; i < sizeof(eraseData); i++) {
        eraseData[i] = 0xFF;
    }

    // 逐页写入擦除数据
    int pageNum = 256/8;  // 每页包含 16 字节
    for (int page = 0; page < pageNum; page++) {
        int address = page * 8;
        if (At24c02WriteBytes(address, sizeof(eraseData), eraseData) != 0) {
            printf("整体擦除失败\r\n");
            return;
        }
    }

    printf("整体擦除成功\r\n");
}


int HuiFuChuChangSheZhi() 
{
    uint8_t GL_MiMa[6]={'0','0','0','0','0','0'};         // 出厂——管理员密码
    uint8_t KM_MiMa[6]={'1','2','3','4','5','6'};         //出厂------开门密码
 // 将所有字节设置为 0x00(擦除状态)
    uint8_t eraseData[256];
    memset(eraseData, 0x00, sizeof(eraseData));

    // 逐页写入擦除数据
    int pageNum = 256/8;  // 每页包含 16 字节
 
    for (int page = 0; page < pageNum; page++) 
	{
        int address = page * 8;
        if (At24c02WriteBytes(address, sizeof(eraseData), eraseData) != 0) 
		{
            printf("整体擦除失败\r\n");
            return 0;
		}
    }
    printf("整体擦除成功\r\n");	
//将初始化开门密码与管理员密码写入指定位置		
	if (At24c02WriteBytes(240,sizeof(KM_MiMa),KM_MiMa)!=0) //在指定位置240(31页的前6字节)存开门密码
	{
		return 0;
	}
	if (At24c02WriteBytes(232,sizeof(GL_MiMa),GL_MiMa)!=0)  //在指定位置232(30页的前6字节)存管理员密码
	{
		return 0;
	}                		
		return 1;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值