当前位置:   article > 正文

RFID射频卡与存储模块AT24X_mf522寄存器定义

mf522寄存器定义

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

  1.  #ifndef __RC522_H
  2.  #define __RC522_H
  3.  #include "stm32f10x.h"
  4.  #include "stm32f10x_spi.h"
  5.  #include <string.h>
  6.  #include <stdio.h>
  7.  ​
  8.  /*******************************
  9.  *连线说明:
  10.  *1--SDA <----->PA4
  11.  *2--SCK <----->PA5
  12.  *3--MOSI <----->PA7
  13.  *4--MISO <----->PA6
  14.  *5--悬空
  15.  *6--GND <----->GND
  16.  *7--RST <----->PB0
  17.  *8--VCC <----->VCC
  18.  ************************************/
  19.  ​
  20.  //MF522命令代码
  21.  #define PCD_IDLE             0x00               //取消当前命令
  22.  #define PCD_AUTHENT           0x0E               //验证密钥
  23.  #define PCD_RECEIVE           0x08               //接收数据
  24.  #define PCD_TRANSMIT         0x04               //发送数据
  25.  #define PCD_TRANSCEIVE       0x0C               //发送并接收数据
  26.  #define PCD_RESETPHASE       0x0F               //复位
  27.  #define PCD_CALCCRC           0x03               //CRC计算
  28.  ​
  29.  //Mifare_One卡片命令代码
  30.  #define PICC_REQIDL           0x26               //寻天线区内未进入休眠状态
  31.  #define PICC_REQALL           0x52               //寻天线区内全部卡
  32.  #define PICC_ANTICOLL1       0x93               //防冲撞
  33.  #define PICC_ANTICOLL2       0x95               //防冲撞
  34.  #define PICC_AUTHENT1A       0x60               //验证A密钥
  35.  #define PICC_AUTHENT1B       0x61               //验证B密钥
  36.  #define PICC_READ             0x30               //读块
  37.  #define PICC_WRITE           0xA0               //写块
  38.  #define PICC_DECREMENT       0xC0               //扣款
  39.  #define PICC_INCREMENT       0xC1               //充值
  40.  #define PICC_RESTORE         0xC2               //调块数据到缓冲区
  41.  #define PICC_TRANSFER         0xB0               //保存缓冲区中数据
  42.  #define PICC_HALT             0x50               //休眠
  43.  ​
  44.  #define DEF_FIFO_LENGTH       64                 //FIFO size=64byte
  45.  #define MAXRLEN 18
  46.  ​
  47.  //MF522寄存器定义
  48.  ​
  49.  // PAGE 0
  50.  #define     RFU00                 0x00    
  51.  #define     CommandReg           0x01    
  52.  #define     ComIEnReg             0x02    
  53.  #define     DivlEnReg             0x03    
  54.  #define     ComIrqReg             0x04    
  55.  #define     DivIrqReg             0x05
  56.  #define     ErrorReg             0x06    
  57.  #define     Status1Reg           0x07    
  58.  #define     Status2Reg           0x08    
  59.  #define     FIFODataReg           0x09
  60.  #define     FIFOLevelReg         0x0A
  61.  #define     WaterLevelReg         0x0B
  62.  #define     ControlReg           0x0C
  63.  #define     BitFramingReg         0x0D
  64.  #define     CollReg               0x0E
  65.  #define     RFU0F                 0x0F
  66.  // PAGE 1    
  67.  #define     RFU10                 0x10
  68.  #define     ModeReg               0x11
  69.  #define     TxModeReg             0x12
  70.  #define     RxModeReg             0x13
  71.  #define     TxControlReg         0x14
  72.  #define     TxAutoReg             0x15
  73.  #define     TxSelReg             0x16
  74.  #define     RxSelReg             0x17
  75.  #define     RxThresholdReg       0x18
  76.  #define     DemodReg             0x19
  77.  #define     RFU1A                 0x1A
  78.  #define     RFU1B                 0x1B
  79.  #define     MifareReg             0x1C
  80.  #define     RFU1D                 0x1D
  81.  #define     RFU1E                 0x1E
  82.  #define     SerialSpeedReg       0x1F
  83.  // PAGE 2    
  84.  #define     RFU20                 0x20  
  85.  #define     CRCResultRegM         0x21
  86.  #define     CRCResultRegL         0x22
  87.  #define     RFU23                 0x23
  88.  #define     ModWidthReg           0x24
  89.  #define     RFU25                 0x25
  90.  #define     RFCfgReg             0x26
  91.  #define     GsNReg               0x27
  92.  #define     CWGsCfgReg           0x28
  93.  #define     ModGsCfgReg           0x29
  94.  #define     TModeReg             0x2A
  95.  #define     TPrescalerReg         0x2B
  96.  #define     TReloadRegH           0x2C
  97.  #define     TReloadRegL           0x2D
  98.  #define     TCounterValueRegH     0x2E
  99.  #define     TCounterValueRegL     0x2F
  100.  // PAGE 3      
  101.  #define     RFU30                 0x30
  102.  #define     TestSel1Reg           0x31
  103.  #define     TestSel2Reg           0x32
  104.  #define     TestPinEnReg         0x33
  105.  #define     TestPinValueReg       0x34
  106.  #define     TestBusReg           0x35
  107.  #define     AutoTestReg           0x36
  108.  #define     VersionReg           0x37
  109.  #define     AnalogTestReg         0x38
  110.  #define     TestDAC1Reg           0x39  
  111.  #define     TestDAC2Reg           0x3A  
  112.  #define     TestADCReg           0x3B  
  113.  #define     RFU3C                 0x3C  
  114.  #define     RFU3D                 0x3D  
  115.  #define     RFU3E                 0x3E  
  116.  #define     RFU3F 0x3F
  117.  ​
  118.  //和RC522通讯时返回的M1卡状态
  119.  #define MI_OK                 0x26
  120.  #define MI_NOTAGERR           0xcc
  121.  #define MI_ERR               0xbb
  122.  ​
  123.  //和MF522通讯时返回的错误代码
  124.  #define   SHAQU1               0X01
  125.  #define KUAI4             0X04
  126.  #define KUAI7             0X07
  127.  #define   REGCARD             0xa1
  128.  #define CONSUME             0xa2
  129.  #define     READCARD         0xa3
  130.  #define     ADDMONEY         0xa4
  131.  ​
  132.  #define SPI_RC522_ReadByte()     SPI_RC522_SendByte(0)
  133.  ​
  134.  #define SET_SPI_CS (GPIOF->BSRR=0X01)
  135.  #define CLR_SPI_CS (GPIOF->BRR=0X01)
  136.  ​
  137.  #define SET_RC522RST GPIOF->BSRR=0X02
  138.  #define CLR_RC522RST GPIOF->BRR=0X02
  139.  ​
  140.  ​
  141.  /***********************RC522 函数宏定义**********************/
  142.  #define         RC522_CS_Enable()         GPIO_ResetBits ( GPIOA, GPIO_Pin_4 )
  143.  #define         RC522_CS_Disable()       GPIO_SetBits ( GPIOA, GPIO_Pin_4 )
  144.  ​
  145.  #define         RC522_Reset_Enable()     GPIO_ResetBits( GPIOB, GPIO_Pin_0 )
  146.  #define         RC522_Reset_Disable()     GPIO_SetBits ( GPIOB, GPIO_Pin_0 )
  147.  ​
  148.  #define         RC522_SCK_0()             GPIO_ResetBits( GPIOA, GPIO_Pin_5 )
  149.  #define         RC522_SCK_1()             GPIO_SetBits ( GPIOA, GPIO_Pin_5 )
  150.  ​
  151.  #define         RC522_MOSI_0()           GPIO_ResetBits( GPIOA, GPIO_Pin_7 )
  152.  #define         RC522_MOSI_1()           GPIO_SetBits ( GPIOA, GPIO_Pin_7 )
  153.  ​
  154.  #define         RC522_MISO_GET()         GPIO_ReadInputDataBit ( GPIOA, GPIO_Pin_6 )
  155.  ​
  156.  u8       SPI_RC522_SendByte         ( u8 byte);
  157.  u8       ReadRawRC                 ( u8 ucAddress );
  158.  void     WriteRawRC                 ( u8 ucAddress, u8 ucValue );
  159.  void     SPI1_Init                 ( void );
  160.  void     RC522_Handel               ( void );
  161.  void     RC522_Init                 ( void );                       //初始化
  162.  void     PcdReset                   ( void );                       //复位
  163.  void     M500PcdConfigISOType       ( u8 type );                    //工作方式
  164.  char     PcdRequest                 ( u8 req_code, u8 * pTagType ); //寻卡
  165.  char     PcdAnticoll               ( u8 * pSnr);                   //防冲撞
  166.  ​
  167.  void     PcdAntennaOn               ( void );                 //开启天线
  168.  void     PcdAntennaOff             ( void );                 //关闭天线
  169.  void     SetBitMask                 ( u8 ucReg, u8 ucMask );
  170.  void     ClearBitMask               ( u8 ucReg, u8 ucMask );
  171.  char     PcdSelect                 ( u8 * pSnr );            //选择卡片
  172.  char     PcdAuthState               ( u8 ucAuth_mode, u8 ucAddr, u8 * pKey, u8 * pSnr );                                              //验证密码
  173.  char     PcdWrite                   ( u8 ucAddr, u8 * pData );
  174.  char     PcdRead                   ( u8 ucAddr, u8 * pData );
  175.  void     ShowID                     ( u16 x,u16 y, u8 *p, u16 charColor, u16 bkColor); //显示卡的卡号,以十六进制显示
  176.  char             PcdHalt           ( void );           //命令卡片进入休眠状态
  177.  void             CalulateCRC               ( u8 * pIndata, u8 ucLen, u8 * pOutData );
  178.  ​
  179.  #endif
  180.  ​
  181. RC522.c
  182.  #include "rc522.h"
  183.  #include "./SysTick/bsp_SysTick.h"
  184.  #include "./usart/bsp_usart.h"
  185.  #include "stm32f10x_spi.h"
  186.  ​
  187.  // M1卡分为16个扇区,每个扇区由四个块(块0、块1、块2、块3)组成
  188.  // 将16个扇区的64个块按绝对地址编号为:0~63
  189.  // 第0个扇区的块0(即绝对地址0块),用于存放厂商代码,已经固化不可更改
  190.  // 每个扇区的块0、块1、块2为数据块,可用于存放数据
  191.  // 每个扇区的块3为控制块(绝对地址为:块3、块7、块11.....)包括密码A,存取控制、密码B等
  192.  ​
  193.  /*******************************
  194.  *连线说明:
  195.  *1--SDA <----->PA4
  196.  *2--SCK <----->PA5
  197.  *3--MOSI <----->PA7
  198.  *4--MISO <----->PA6
  199.  *5--悬空
  200.  *6--GND <----->GND
  201.  *7--RST <----->PB0
  202.  *8--VCC <----->VCC
  203.  ************************************/
  204.  ​
  205.  #define   RC522_DELAY() delay_us( 2 )
  206.  ​
  207.  /*全局变量*/
  208.  unsigned char CT[2];            //卡类型
  209.  unsigned char SN[4];            //卡号
  210.  unsigned char RFID[16];    //存放RFID
  211.  unsigned char lxl_bit=0;
  212.  unsigned char card1_bit=0;
  213.  unsigned char card2_bit=0;
  214.  unsigned char card3_bit=0;
  215.  unsigned char card4_bit=0;
  216.  unsigned char total=0;
  217.  unsigned char lxl[4]={196,58,104,217};
  218.  unsigned char card_1[4]={83,106,11,1};
  219.  unsigned char card_2[4]={208,121,31,57};
  220.  unsigned char card_3[4]={176,177,143,165};
  221.  unsigned char card_4[4]={5,158,10,136};
  222.  u8 KEY[6]={0xff,0xff,0xff,0xff,0xff,0xff};
  223.  u8 AUDIO_OPEN[6] = {0xAA, 0x07, 0x02, 0x00, 0x09, 0xBC};
  224.  unsigned char RFID1[16]={0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x07,0x80,0x29,0xff,0xff,0xff,0xff,0xff,0xff};
  225.  /*函数声明*/
  226.  unsigned char status;
  227.  unsigned char s=0x08;
  228.  ​
  229.  /* 函数名:RC522_Init
  230.   * 描述 :初始化RC522配置
  231.   * 输入 :无
  232.   * 返回 : 无
  233.   * 调用 :外部调用             */
  234.  void RC522_Init ( void )
  235.  {
  236.   SPI1_Init();
  237.   RC522_Reset_Disable();      //将RST置高,启动内部复位阶段;
  238.    PcdReset ();                  //复位RC522
  239.    PcdAntennaOff();              //关闭天线
  240.   RC522_DELAY();                //delay 1ms
  241.    PcdAntennaOn();               //打开天线
  242.   M500PcdConfigISOType ( 'A' ); //设置工作方式
  243.  }
  244.  ​
  245.  /* 函数名:SPI1_Init
  246.   * 描述 :初始化SPI1的配置
  247.   * 输入 :无
  248.   * 返回 : 无
  249.   * 调用 :外部调用             */
  250.  void SPI1_Init (void)
  251.  {
  252.    SPI_InitTypeDef  SPI_InitStructure;
  253.    GPIO_InitTypeDef GPIO_InitStructure;
  254.    RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE );//PORTB时钟使能
  255.  
  256.    // CS
  257.      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
  258.      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
  259.      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
  260.      GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化PF0、PF1
  261.      
  262.      // SCK
  263.      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
  264.      GPIO_Init(GPIOA, &GPIO_InitStructure);
  265.      
  266.      // MISO
  267.      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
  268.      GPIO_Init(GPIOA, &GPIO_InitStructure);
  269.      
  270.      // MOSI
  271.      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
  272.      GPIO_Init(GPIOA, &GPIO_InitStructure);
  273.      
  274.      // RST
  275.      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  276.      GPIO_Init(GPIOB, &GPIO_InitStructure);
  277.  
  278.   //置高CS口
  279.   RC522_CS_Disable();
  280.  ​
  281.      //其他SPI1配置
  282.   SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;            //全双工;
  283.      SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                                //主机模式;
  284.      SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;                            //传输数据为8位;
  285.      SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;                                   //时钟极性CPOL为空闲时低电平;
  286.      SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;                                 //时钟采样点为时钟奇数沿(上升沿);
  287.      SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                                    //NSS引脚由软件改变;
  288.      SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;          //预分频系数64;
  289.      SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;                           //MSB先行模式;
  290.      SPI_InitStructure.SPI_CRCPolynomial = 7;                                     //CRC校验;
  291.  
  292.     //初始化SPI1
  293.      SPI_Init(SPI1 , &SPI_InitStructure);
  294.  
  295.     //使能SPI1
  296.   SPI_Cmd(SPI1 , ENABLE);
  297.   }
  298.  ​
  299.  /* 函数名:PcdRese
  300.   * 描述 :复位RC522
  301.   * 输入 :无
  302.   * 返回 : 无
  303.   * 调用 :外部调用             */
  304.  void PcdReset ( void )
  305.  {
  306.      RC522_Reset_Disable();
  307.      delay_us ( 1 );
  308.      RC522_Reset_Enable();
  309.      delay_us ( 1 );
  310.      RC522_Reset_Disable();
  311.      delay_us ( 1 );
  312.      WriteRawRC ( CommandReg, 0x0f );
  313.  ​
  314.      while ( ReadRawRC ( CommandReg ) & 0x10 );
  315.  
  316.      delay_us ( 1 );
  317.      WriteRawRC ( ModeReg, 0x3D );                //定义发送和接收常用模式 和Mifare卡通讯,CRC初始值0x6363
  318.      WriteRawRC ( TReloadRegL, 30 );              //16位定时器低位    
  319.      WriteRawRC ( TReloadRegH, 0 );     //16位定时器高位
  320.      WriteRawRC ( TModeReg, 0x8D ); //定义内部定时器的设置
  321.      WriteRawRC ( TPrescalerReg, 0x3E ); //设置定时器分频系数
  322.      WriteRawRC ( TxAutoReg, 0x40 ); //调制发送信号为100%ASK
  323.  }
  324.  ​
  325.  /* 函数名:SPI_RC522_SendByte
  326.   * 描述 :向RC522发送1 Byte 数据
  327.   * 输入 :byte,要发送的数据
  328.   * 返回 : RC522返回的数据
  329.   * 调用 :内部调用                 */
  330.  u8 SPI_RC522_SendByte ( u8 byte )
  331.  {
  332.    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);        
  333.      SPI_I2S_SendData(SPI1, byte);                    
  334.      while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
  335.      return SPI_I2S_ReceiveData(SPI1);
  336.  }
  337.  ​
  338.  ​
  339.  /* 函数名:ReadRawRC
  340.   * 描述 :读RC522寄存器
  341.   * 输入 :ucAddress,寄存器地址
  342.   * 返回 : 寄存器的当前值
  343.   * 调用 :内部调用                 */
  344.  u8 ReadRawRC ( u8 ucAddress )
  345.  {
  346.   u8 ucAddr, ucReturn;
  347.   ucAddr = ( ( ucAddress << 1 ) & 0x7E ) | 0x80;      
  348.  ​
  349.   RC522_CS_Enable();
  350.   SPI_RC522_SendByte ( ucAddr );
  351.   ucReturn = SPI_RC522_ReadByte ();
  352.   RC522_CS_Disable();
  353.   return ucReturn;
  354.  }
  355.  ​
  356.  ​
  357.   /* 函数名:WriteRawRC
  358.   * 描述 :写RC522寄存器
  359.   * 输入 :ucAddress,寄存器地址 、 ucValue,写入寄存器的值
  360.   * 返回 : 无
  361.   * 调用 :内部调用   */
  362.  void WriteRawRC ( u8 ucAddress, u8 ucValue )
  363.  {  
  364.   u8 ucAddr;
  365.   ucAddr = ( ucAddress << 1 ) & 0x7E;  
  366.  
  367.   RC522_CS_Enable();
  368.   SPI_RC522_SendByte ( ucAddr );
  369.   SPI_RC522_SendByte ( ucValue );
  370.   RC522_CS_Disable();
  371.  }
  372.  ​
  373.  /* 函数名:M500PcdConfigISOType
  374.   * 描述 :设置RC522的工作方式
  375.   * 输入 :ucType,工作方式
  376.   * 返回 : 无
  377.   * 调用 :外部调用       */
  378.  void M500PcdConfigISOType ( u8 ucType )
  379.  {
  380.   if ( ucType == 'A')                     //ISO14443_A
  381.   {
  382.   ClearBitMask ( Status2Reg, 0x08 );
  383.  ​
  384.      WriteRawRC ( ModeReg, 0x3D );//3F
  385.   WriteRawRC ( RxSelReg, 0x86 );//84
  386.   WriteRawRC ( RFCfgReg, 0x7F );   //4F
  387.   WriteRawRC ( TReloadRegL, 30 );//tmoLength);// TReloadVal = 'h6a =tmoLength(dec)
  388.   WriteRawRC ( TReloadRegH, 0 );
  389.   WriteRawRC ( TModeReg, 0x8D );
  390.   WriteRawRC ( TPrescalerReg, 0x3E );
  391.   delay_us   ( 2 );
  392.  
  393.   PcdAntennaOn ();//开天线
  394.     }
  395.  }
  396.  ​
  397.  /*
  398.   * 函数名:SetBitMask
  399.   * 描述 :对RC522寄存器置位
  400.   * 输入 :ucReg,寄存器地址
  401.   *         ucMask,置位值
  402.   * 返回 : 无
  403.   * 调用 :内部调用
  404.   */
  405.  void SetBitMask ( u8 ucReg, u8 ucMask )  
  406.  {
  407.      u8 ucTemp;
  408.  ​
  409.      ucTemp = ReadRawRC ( ucReg );
  410.      WriteRawRC ( ucReg, ucTemp | ucMask );         // set bit mask
  411.  }
  412.  ​
  413.  /* 函数名:ClearBitMask
  414.   * 描述 :对RC522寄存器清位
  415.   * 输入 :ucReg,寄存器地址
  416.   *         ucMask,清位值
  417.   * 返回 : 无
  418.   * 调用 :内部调用           */
  419.  void ClearBitMask ( u8 ucReg, u8 ucMask )  
  420.  {
  421.      u8 ucTemp;
  422.      ucTemp = ReadRawRC ( ucReg );
  423.  
  424.      WriteRawRC ( ucReg, ucTemp & ( ~ ucMask) );  // clear bit mask
  425.  
  426.  }
  427.  ​
  428.  /* 函数名:PcdAntennaOn
  429.   * 描述 :开启天线
  430.   * 输入 :无
  431.   * 返回 : 无
  432.   * 调用 :内部调用           */
  433.  void PcdAntennaOn ( void )
  434.  {
  435.      u8 uc;
  436.      uc = ReadRawRC ( TxControlReg );
  437.  
  438.      if ( ! ( uc & 0x03 ) )
  439.   SetBitMask(TxControlReg, 0x03);
  440.  ​
  441.  }
  442.  ​
  443.  /* 函数名:PcdAntennaOff
  444.   * 描述 :开启天线
  445.   * 输入 :无
  446.   * 返回 : 无
  447.   * 调用 :内部调用             */
  448.  void PcdAntennaOff ( void )
  449.  {
  450.      ClearBitMask ( TxControlReg, 0x03 );
  451.  }
  452.  ​
  453.  void ShowID(u16 x,u16 y, u8 *p, u16 charColor, u16 bkColor)  //显示卡的卡号,以十六进制显示
  454.  {
  455.      u8 num[9];
  456.  ​
  457.      printf("ID>>>%s\r\n", num);
  458.  ​
  459.  }
  460.  ​
  461.  /* 函数名:PcdComMF522
  462.   * 描述 :通过RC522和ISO14443卡通讯
  463.   * 输入 :ucCommand,RC522命令字
  464.   *         pInData,通过RC522发送到卡片的数据
  465.   *         ucInLenByte,发送数据的字节长度
  466.   *         pOutData,接收到的卡片返回数据
  467.   *         pOutLenBit,返回数据的位长度
  468.   * 返回 : 状态值
  469.   *         = MI_OK,成功
  470.   * 调用 :内部调用             */
  471.  char PcdComMF522 ( u8 ucCommand, u8 * pInData, u8 ucInLenByte, u8 * pOutData, u32 * pOutLenBit )
  472.  {
  473.      char cStatus = MI_ERR;
  474.      u8 ucIrqEn   = 0x00;
  475.      u8 ucWaitFor = 0x00;
  476.      u8 ucLastBits;
  477.      u8 ucN;
  478.      u32 ul;
  479.  ​
  480.      switch ( ucCommand )
  481.     {
  482.         case PCD_AUTHENT: //Mifare认证
  483.            ucIrqEn   = 0x12; //允许错误中断请求ErrIEn 允许空闲中断IdleIEn
  484.            ucWaitFor = 0x10; //认证寻卡等待时候 查询空闲中断标志位
  485.            break;
  486.  
  487.         case PCD_TRANSCEIVE: //接收发送 发送接收
  488.            ucIrqEn   = 0x77; //允许TxIEn RxIEn IdleIEn LoAlertIEn ErrIEn TimerIEn
  489.            ucWaitFor = 0x30; //寻卡等待时候 查询接收中断标志位与 空闲中断标志位
  490.            break;
  491.  
  492.         default:
  493.           break;
  494.  
  495.     }
  496.    
  497.      WriteRawRC ( ComIEnReg, ucIrqEn | 0x80 ); //IRqInv置位管脚IRQ与Status1Reg的IRq位的值相反
  498.      ClearBitMask ( ComIrqReg, 0x80 ); //Set1该位清零时,CommIRqReg的屏蔽位清零
  499.      WriteRawRC ( CommandReg, PCD_IDLE ); //写空闲命令
  500.      SetBitMask ( FIFOLevelReg, 0x80 ); //置位FlushBuffer清除内部FIFO的读和写指针以及ErrReg的BufferOvfl标志位被清除
  501.      
  502.      for ( ul = 0; ul < ucInLenByte; ul ++ )
  503.   WriteRawRC ( FIFODataReg, pInData [ ul ] );   //写数据进FIFOdata
  504.  
  505.      WriteRawRC ( CommandReg, ucCommand ); //写命令
  506.    
  507.      
  508.      if ( ucCommand == PCD_TRANSCEIVE )
  509.   SetBitMask(BitFramingReg,0x80); //StartSend置位启动数据发送 该位与收发命令使用时才有效
  510.      
  511.      ul = 1000;//根据时钟频率调整,操作M1卡最大等待时间25ms
  512.  
  513.      do //认证 与寻卡等待时间
  514.     {
  515.           ucN = ReadRawRC ( ComIrqReg ); //查询事件中断
  516.           ul --;
  517.     } while ( ( ul != 0 ) && ( ! ( ucN & 0x01 ) ) && ( ! ( ucN & ucWaitFor ) ) ); //退出条件i=0,定时器中断,与写空闲命令
  518.  
  519.      ClearBitMask ( BitFramingReg, 0x80 ); //清理允许StartSend位
  520.  
  521.      if ( ul != 0 )
  522.     {
  523.   if ( ! (( ReadRawRC ( ErrorReg ) & 0x1B )) ) //读错误标志寄存器BufferOfI CollErr ParityErr ProtocolErr
  524.   {
  525.   cStatus = MI_OK;
  526.  
  527.   if ( ucN & ucIrqEn & 0x01 ) //是否发生定时器中断
  528.    cStatus = MI_NOTAGERR;  
  529.  
  530.   if ( ucCommand == PCD_TRANSCEIVE )
  531.   {
  532.   ucN = ReadRawRC ( FIFOLevelReg ); //读FIFO中保存的字节数
  533.  
  534.   ucLastBits = ReadRawRC ( ControlReg ) & 0x07; //最后接收到得字节的有效位数
  535.  
  536.   if ( ucLastBits )
  537.   * pOutLenBit = ( ucN - 1 ) * 8 + ucLastBits;   //N个字节数减去1(最后一个字节)+最后一位的位数 读取到的数据总位数
  538.   else
  539.   * pOutLenBit = ucN * 8;   //最后接收到的字节整个字节有效
  540.  
  541.   if ( ucN == 0 )
  542.                      ucN = 1;    
  543.  
  544.   if ( ucN > MAXRLEN )
  545.   ucN = MAXRLEN;  
  546.  
  547.   for ( ul = 0; ul < ucN; ul ++ )
  548.    pOutData [ ul ] = ReadRawRC ( FIFODataReg );  
  549.   }
  550.         }
  551.   else
  552.   cStatus = MI_ERR;  
  553.     }
  554.    
  555.     SetBitMask ( ControlReg, 0x80 );           // stop timer now
  556.     WriteRawRC ( CommandReg, PCD_IDLE );
  557.  
  558.     return cStatus;
  559.  }
  560.  ​
  561.  ​
  562.  /* 函数名:PcdRequest
  563.   * 描述 :寻卡
  564.   * 输入 :ucReq_code,寻卡方式
  565.   *                     = 0x52,寻感应区内所有符合14443A标准的卡
  566.   *                     = 0x26,寻未进入休眠状态的卡
  567.   *         pTagType,卡片类型代码
  568.   *                   = 0x4400,Mifare_UltraLight
  569.   *                   = 0x0400,Mifare_One(S50)
  570.   *                   = 0x0200,Mifare_One(S70)
  571.   *                   = 0x0800,Mifare_Pro(X))
  572.   *                   = 0x4403,Mifare_DESFire
  573.   * 返回 : 状态值
  574.   *         = MI_OK,成功
  575.   * 调用 :外部调用           */
  576.  char PcdRequest ( u8 ucReq_code, u8 * pTagType )
  577.  {
  578.      char cStatus;  
  579.      u8 ucComMF522Buf [ MAXRLEN ];
  580.      u32 ulLen;
  581.  ​
  582.      ClearBitMask ( Status2Reg, 0x08 ); //清理指示MIFARECyptol单元接通以及所有卡的数据通信被加密的情况
  583.      WriteRawRC ( BitFramingReg, 0x07 ); // 发送的最后一个字节的 七位
  584.      SetBitMask ( TxControlReg, 0x03 ); //TX1,TX2管脚的输出信号传递经发送调制的13.56的能量载波信号
  585.  ​
  586.      ucComMF522Buf [ 0 ] = ucReq_code; //存入 卡片命令字
  587.  ​
  588.      cStatus = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 1, ucComMF522Buf, & ulLen ); //寻卡  
  589.  ​
  590.      if ( ( cStatus == MI_OK ) && ( ulLen == 0x10 ) ) //寻卡成功返回卡类型
  591.     {    
  592.         * pTagType = ucComMF522Buf [ 0 ];
  593.         * ( pTagType + 1 ) = ucComMF522Buf [ 1 ];
  594.     }
  595.      
  596.      else
  597.       cStatus = MI_ERR;
  598.  ​
  599.      return cStatus;
  600.  }
  601.  ​
  602.  /* 函数名:PcdAnticoll
  603.   * 描述 :防冲撞
  604.   * 输入 :pSnr,卡片序列号,4字节
  605.   * 返回 : 状态值
  606.   *         = MI_OK,成功
  607.   * 调用 :外部调用           */
  608.  char PcdAnticoll ( u8 * pSnr )
  609.  {
  610.      char cStatus;
  611.      u8 uc, ucSnr_check = 0;
  612.      u8 ucComMF522Buf [ MAXRLEN ];
  613.    u32 ulLen;
  614.  ​
  615.      ClearBitMask ( Status2Reg, 0x08 ); //清MFCryptol On位 只有成功执行MFAuthent命令后,该位才能置位
  616.      WriteRawRC ( BitFramingReg, 0x00); //清理寄存器 停止收发
  617.      ClearBitMask ( CollReg, 0x80 ); //清ValuesAfterColl所有接收的位在冲突后被清除
  618.    
  619.      ucComMF522Buf [ 0 ] = 0x93; //卡片防冲突命令
  620.      ucComMF522Buf [ 1 ] = 0x20;
  621.    
  622.      cStatus = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 2, ucComMF522Buf, & ulLen);//与卡片通信
  623.  
  624.      if ( cStatus == MI_OK) //通信成功
  625.     {
  626.   for ( uc = 0; uc < 4; uc ++ )
  627.         {
  628.              * ( pSnr + uc )  = ucComMF522Buf [ uc ]; //读出UID
  629.              ucSnr_check ^= ucComMF522Buf [ uc ];
  630.         }
  631.  
  632.          if ( ucSnr_check != ucComMF522Buf [ uc ] )
  633.         cStatus = MI_ERR;    
  634.  
  635.     }
  636.      
  637.      SetBitMask ( CollReg, 0x80 );
  638.  ​
  639.      return cStatus;
  640.  }
  641.  ​
  642.  /* 函数名:PcdSelect
  643.   * 描述 :选定卡片
  644.   * 输入 :pSnr,卡片序列号,4字节
  645.   * 返回 : 状态值
  646.   *         = MI_OK,成功
  647.   * 调用 :外部调用         */
  648.  char PcdSelect ( u8 * pSnr )
  649.  {
  650.      char ucN;
  651.      u8 uc;
  652.        u8 ucComMF522Buf [ MAXRLEN ];
  653.      u32  ulLen;
  654.  ​
  655.      ucComMF522Buf [ 0 ] = PICC_ANTICOLL1;
  656.      ucComMF522Buf [ 1 ] = 0x70;
  657.      ucComMF522Buf [ 6 ] = 0;
  658.      
  659.      for ( uc = 0; uc < 4; uc ++ )
  660.     {
  661.          ucComMF522Buf [ uc + 2 ] = * ( pSnr + uc );
  662.          ucComMF522Buf [ 6 ] ^= * ( pSnr + uc );
  663.     }
  664.          
  665.      CalulateCRC ( ucComMF522Buf, 7, & ucComMF522Buf [ 7 ] );
  666.      ClearBitMask ( Status2Reg, 0x08 );
  667.      ucN = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 9, ucComMF522Buf, & ulLen );
  668.      
  669.      if ( ( ucN == MI_OK ) && ( ulLen == 0x18 ) )
  670.        ucN = MI_OK;  
  671.      else
  672.        ucN = MI_ERR;    
  673.  ​
  674.      return ucN;
  675.  }
  676.  ​
  677.  /* 函数名:CalulateCRC
  678.   * 描述 :用RC522计算CRC16
  679.   * 输入 :pIndata,计算CRC16的数组
  680.   *         ucLen,计算CRC16的数组字节长度
  681.   *         pOutData,存放计算结果存放的首地址
  682.   * 返回 : 无
  683.   * 调用 :内部调用             */
  684.  void CalulateCRC ( u8 * pIndata, u8 ucLen, u8 * pOutData )
  685.  {
  686.      u8 uc, ucN;
  687.  ​
  688.      ClearBitMask(DivIrqReg,0x04);
  689.      WriteRawRC(CommandReg,PCD_IDLE);
  690.      SetBitMask(FIFOLevelReg,0x80);
  691.      
  692.      for ( uc = 0; uc < ucLen; uc ++)
  693.          WriteRawRC ( FIFODataReg, * ( pIndata + uc ) );  
  694.  ​
  695.      WriteRawRC ( CommandReg, PCD_CALCCRC );
  696.      uc = 0xFF;
  697.  ​
  698.      do {
  699.          ucN = ReadRawRC ( DivIrqReg );
  700.          uc --;}
  701.      while ( ( uc != 0 ) && ! ( ucN & 0x04 ) );
  702.          
  703.      pOutData [ 0 ] = ReadRawRC ( CRCResultRegL );
  704.      pOutData [ 1 ] = ReadRawRC ( CRCResultRegM );
  705.      
  706.  }
  707.  ​
  708.  /* 函数名:PcdAuthState
  709.   * 描述 :验证卡片密码
  710.   * 输入 :ucAuth_mode,密码验证模式
  711.   *                     = 0x60,验证A密钥
  712.   *                     = 0x61,验证B密钥
  713.   *         u8 ucAddr,块地址
  714.   *         pKey,密码
  715.   *         pSnr,卡片序列号,4字节
  716.   * 返回 : 状态值
  717.   *         = MI_OK,成功
  718.   * 调用 :外部调用         */
  719.  char PcdAuthState ( u8 ucAuth_mode, u8 ucAddr, u8 * pKey, u8 * pSnr )
  720.  {
  721.      char cStatus;
  722.      u8 uc, ucComMF522Buf [ MAXRLEN ];
  723.      u32 ulLen;
  724.  ​
  725.      ucComMF522Buf [ 0 ] = ucAuth_mode;
  726.      ucComMF522Buf [ 1 ] = ucAddr;
  727.      
  728.      for ( uc = 0; uc < 6; uc ++ )
  729.          ucComMF522Buf [ uc + 2 ] = * ( pKey + uc );  
  730.      
  731.      for ( uc = 0; uc < 6; uc ++ )
  732.          ucComMF522Buf [ uc + 8 ] = * ( pSnr + uc );  
  733.  ​
  734.      cStatus = PcdComMF522 ( PCD_AUTHENT, ucComMF522Buf, 12, ucComMF522Buf, & ulLen );
  735.      
  736.      if ( ( cStatus != MI_OK ) || ( ! ( ReadRawRC ( Status2Reg ) & 0x08 ) ) ){
  737.              cStatus = MI_ERR;
  738.     }
  739.  
  740.      return cStatus;    
  741.  }
  742.  ​
  743.  /* 函数名:PcdWrite
  744.   * 描述 :写数据到M1卡一块
  745.   * 输入 :u8 ucAddr,块地址
  746.   *         pData,写入的数据,16字节
  747.   * 返回 : 状态值
  748.   *         = MI_OK,成功
  749.   * 调用 :外部调用           */
  750.  char PcdWrite ( u8 ucAddr, u8 * pData )
  751.  {
  752.      char cStatus;
  753.        u8 uc, ucComMF522Buf [ MAXRLEN ];
  754.      u32 ulLen;
  755.  ​
  756.      ucComMF522Buf [ 0 ] = PICC_WRITE;
  757.      ucComMF522Buf [ 1 ] = ucAddr;
  758.      
  759.      CalulateCRC ( ucComMF522Buf, 2, & ucComMF522Buf [ 2 ] );
  760.  
  761.      cStatus = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 4, ucComMF522Buf, & ulLen );
  762.  ​
  763.      if ( ( cStatus != MI_OK ) || ( ulLen != 4 ) || ( ( ucComMF522Buf [ 0 ] & 0x0F ) != 0x0A ) )
  764.        cStatus = MI_ERR;  
  765.          
  766.      if ( cStatus == MI_OK )
  767.     {
  768.        memcpy(ucComMF522Buf, pData, 16);
  769.        for ( uc = 0; uc < 16; uc ++ )
  770.                ucComMF522Buf [ uc ] = * ( pData + uc );  
  771.              
  772.        CalulateCRC ( ucComMF522Buf, 16, & ucComMF522Buf [ 16 ] );
  773.  ​
  774.        cStatus = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 18, ucComMF522Buf, & ulLen );
  775.              
  776.              if ( ( cStatus != MI_OK ) || ( ulLen != 4 ) || ( ( ucComMF522Buf [ 0 ] & 0x0F ) != 0x0A ) )
  777.          cStatus = MI_ERR;  
  778.              
  779.     }
  780.  ​
  781.      return cStatus;
  782.      
  783.  }
  784.  ​
  785.  /* 函数名:PcdRead
  786.   * 描述 :读取M1卡一块数据
  787.   * 输入 :u8 ucAddr,块地址
  788.   *         pData,读出的数据,16字节
  789.   * 返回 : 状态值
  790.   *         = MI_OK,成功
  791.   * 调用 :外部调用             */
  792.  char PcdRead ( u8 ucAddr, u8 * pData )
  793.  {
  794.      char cStatus;
  795.        u8 uc, ucComMF522Buf [ MAXRLEN ];
  796.      u32 ulLen;
  797.  ​
  798.      ucComMF522Buf [ 0 ] = PICC_READ;
  799.      ucComMF522Buf [ 1 ] = ucAddr;
  800.      
  801.      CalulateCRC ( ucComMF522Buf, 2, & ucComMF522Buf [ 2 ] );
  802.    
  803.      cStatus = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 4, ucComMF522Buf, & ulLen );
  804.      
  805.      if ( ( cStatus == MI_OK ) && ( ulLen == 0x90 ) )
  806.     {
  807.              for ( uc = 0; uc < 16; uc ++ )
  808.          * ( pData + uc ) = ucComMF522Buf [ uc ];  
  809.     }
  810.          
  811.      else
  812.        cStatus = MI_ERR;  
  813.      
  814.      return cStatus;
  815.  ​
  816.  }
  817.  ​
  818.  /* 函数名:PcdHalt
  819.   * 描述 :命令卡片进入休眠状态
  820.   * 输入 :无
  821.   * 返回 : 状态值
  822.   *         = MI_OK,成功
  823.   * 调用 :外部调用       */
  824.  char PcdHalt( void )
  825.  {
  826.      u8 ucComMF522Buf [ MAXRLEN ];
  827.      u32  ulLen;
  828.  ​
  829.      ucComMF522Buf [ 0 ] = PICC_HALT;
  830.      ucComMF522Buf [ 1 ] = 0;
  831.  ​
  832.      CalulateCRC ( ucComMF522Buf, 2, & ucComMF522Buf [ 2 ] );
  833.      PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 4, ucComMF522Buf, & ulLen );
  834.  ​
  835.      return MI_OK;  
  836.  }
  • 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位

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

  1. typedef struct {      
  2.     uint8_t icCardNumber[4];    //IC卡号
  3.     uint8_t phoneNumber[12];    //绑定手机号
  4. } Part1Data;

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

读写数据代码:

  1. /*
  2. ****************************************************************************************
  3. * INCLUDES (头文件包含)
  4. ****************************************************************************************
  5. */
  6. #include "at24c04.h"
  7. #include "iic3.h"
  8. #include "delay.h"
  9. #include "stdio.h"
  10. #include <string.h>
  11. /*
  12. ****************************************************************************************
  13. * Function: At24c04Init
  14. * Description: At24c04初始化
  15. * Input: None
  16. * Output: None
  17. * Return: None
  18. ****************************************************************************************
  19. */
  20. void At24c02Init(void)
  21. {
  22. IIC3_Pin_Init( );
  23. }
  24. /*
  25. ****************************************************************************************
  26. * Function: At24c02WriteByte
  27. * Description: -----------------------------------------------------写1字节数据到At24c02
  28. * Input: addr内部地址(0~255) data待写入的数据
  29. * Output: None
  30. * Return: 0成功写入 其他:错误码
  31. ****************************************************************************************
  32. */
  33. uint8_t At24c04WriteByte(uint16_t addr,uint8_t data)
  34. {
  35. uint8_t ack;
  36. /* 1,发送起始信号 */
  37. IIC3_Start( );
  38. /* 2,发送写操作 并等待应答信号 */
  39. ack=IIC3_Send_Byte(AT24C02_ADDR_W);
  40. if(ack)
  41. {
  42. IIC3_Stop( );
  43. return WRITE_ERR1;
  44. }
  45. Delay_nms(10);
  46. /* 发送内存地址 并等待应答信号 */
  47. ack=IIC3_Send_Byte(addr);
  48. if(ack)
  49. {
  50. IIC3_Stop( );
  51. return WRITE_ERR2;
  52. }
  53. Delay_nms(10);
  54. /* 发送写入数据 并等待应答信号 */
  55. ack=IIC3_Send_Byte(data);
  56. if(ack)
  57. {
  58. IIC3_Stop( );
  59. return WRITE_ERR3;
  60. }
  61. /* 发送停止信号 */
  62. IIC3_Stop( );
  63. /* 等待eeprom的写入完成 要求5ms */
  64. Delay_nms(10);
  65. return 0;
  66. }
  67. /*
  68. ****************************************************************************************
  69. * Function: At24c02readByte
  70. * Description: -----------------------------------------------------读1字节数据到At24c02
  71. * Input: addr内部地址(0~255)
  72. * Output: None
  73. * Return: 读的数据
  74. ****************************************************************************************
  75. */
  76. uint8_t At24c02readByte(uint16_t addr)
  77. {
  78. uint8_t ack;
  79. uint8_t rec=2;
  80. /* 1,发送起始信号 */
  81. IIC3_Start( );
  82. /* 2,发送写操作 并等待应答信号 */
  83. ack=IIC3_Send_Byte(AT24C02_ADDR_W);
  84. if(ack)
  85. {
  86. IIC3_Stop( );
  87. return WRITE_ERR1;
  88. }
  89. Delay_nms(10);
  90. /* 发送内存地址 并等待应答信号 */
  91. ack=IIC3_Send_Byte(addr);
  92. if(ack)
  93. {
  94. IIC3_Stop( );
  95. return WRITE_ERR2;
  96. }
  97. Delay_nms(10);
  98. /* 发送起始信号 */
  99. IIC3_Start( );
  100. /* 2,发送读操作 并等待应答信号 */
  101. ack=IIC3_Send_Byte(AT24C02_ADDR_R);
  102. if(ack)
  103. {
  104. IIC3_Stop( );
  105. return WRITE_ERR3;
  106. }
  107. Delay_nms(10);
  108. rec = IIC3_Revice_Byte(0); // 获取数据地址就行,不需要应答 0非应答 1应答
  109. Delay_nms(10);
  110. /* 发送停止信号 */
  111. IIC3_Stop( );
  112. return rec;
  113. }
  114. /*
  115. ****************************************************************************************
  116. * Function: At24c02PageWrite
  117. * Description: ---------------------------------------------------------------页写At24c02
  118. * Input: addr内部地址(0~255) num待写入的数据个数 p指向待写入的数据
  119. * Output: None
  120. * Return: 0成功写入 其他:错误码
  121. ****************************************************************************************
  122. */
  123. uint8_t At24c02PageWrite(uint16_t addr,uint8_t num,uint8_t *p)
  124. {
  125. uint8_t ack=0;
  126. //起始地址---addr
  127. //结束地址---addr+num-1
  128. // if(addr/8 != (addr+num-1)/8)
  129. // {
  130. // return NOT_IN_SAME_PAGE;
  131. // }
  132. IIC3_Start( );
  133. ack=IIC3_Send_Byte(AT24C02_ADDR_W);//发送器件地址+写方向
  134. if(ack)
  135. {
  136. IIC3_Stop( );
  137. return WRITE_ERR4;
  138. }
  139. ack=IIC3_Send_Byte(addr);//发送内部地址
  140. if(ack)
  141. {
  142. IIC3_Stop( );
  143. return WRITE_ERR5;
  144. }
  145. while(num--)
  146. {
  147. ack=IIC3_Send_Byte(*p);//发送数据
  148. if(ack)
  149. {
  150. IIC3_Stop( );
  151. return WRITE_ERR3;
  152. }
  153. p++;
  154. }
  155. IIC3_Stop( );
  156. Delay_nms(5);//写周期!!!!!!!!!!!!!!!!
  157. return 0;
  158. }
  159. /*
  160. ****************************************************************************************
  161. * Function: At24c02WriteBytes
  162. * Description: -------------------------------------------------------------随机写At24c02
  163. * Input: addr内部地址(0~511) num要写入的数据个数(1~256) p指向数据存储空间
  164. * Output: None
  165. * Return: 0成功写入 其他:错误码
  166. * Others: 起始地址跟结束地址在同一页
  167. ****************************************************************************************
  168. */
  169. uint8_t At24c02WriteBytes(uint16_t addr,uint16_t num,uint8_t *p)
  170. {
  171. uint8_t ret=0;
  172. uint8_t less_addr=0;//当前页还剩下多少个地址空间可以写
  173. while(1)
  174. {
  175. less_addr=8-addr%8;
  176. if(less_addr>=num)//本页可以写完
  177. {
  178. less_addr=num;
  179. }
  180. ret=At24c02PageWrite(addr,less_addr,p);
  181. if(ret)
  182. {
  183. return ret;
  184. }
  185. if(less_addr==num)
  186. {
  187. return 0;
  188. }
  189. addr=addr+less_addr;//下一页的起始地址
  190. num=num-less_addr;//还剩下多少个数据没写
  191. p=p+less_addr;//偏移到还没写的数据
  192. }
  193. }
  194. /*
  195. ****************************************************************************************
  196. * Function: At24c02ReadBytes
  197. * Description:--------------------------------------------------------------随机读At24c02
  198. * Input: addr内部地址(0~255) num要读取的数据个数 p指向数据存储空间
  199. * Output: None
  200. * Return: 0成功写入 其他:错误码
  201. * Others: 起始地址跟结束地址在同一页
  202. ****************************************************************************************
  203. */
  204. uint8_t At24c02ReadBytes(uint16_t addr,uint16_t num,uint8_t *p)
  205. {
  206. uint8_t ack=0;
  207. IIC3_Start( );
  208. ack=IIC3_Send_Byte(AT24C02_ADDR_W);//发送器件地址+写方向
  209. if(ack)
  210. {
  211. IIC3_Stop( );
  212. return READ_ERR1;
  213. }
  214. ack=IIC3_Send_Byte(addr);//发送内部地址
  215. if(ack)
  216. {
  217. IIC3_Stop( );
  218. return READ_ERR2;
  219. }
  220. IIC3_Start( );//重复起始条件
  221. ack=IIC3_Send_Byte(AT24C02_ADDR_R);//发送器件地址+读方向
  222. if(ack)
  223. {
  224. IIC3_Stop( );
  225. return READ_ERR3;
  226. }
  227. while(num)
  228. {
  229. num--;//还剩下多少个字节没有读
  230. if(num==0)
  231. {
  232. *p=IIC3_Revice_Byte(1);
  233. break;
  234. }
  235. *p++=IIC3_Revice_Byte(0);
  236. }
  237. IIC3_Stop( );
  238. return 0;
  239. }
  240. /*
  241. ****************************************************************************************
  242. * Function: At24c02ChipErase
  243. * Description:--------------------------------------------------------------擦除At24c02
  244. * Input:
  245. * Output:
  246. * Return:
  247. * Others:
  248. ****************************************************************************************
  249. */
  250. void At24c02ChipErase()
  251. {
  252. // 将所有字节设置为 0xFF(擦除状态)
  253. uint8_t eraseData[256];
  254. for (int i = 0; i < sizeof(eraseData); i++) {
  255. eraseData[i] = 0xFF;
  256. }
  257. // 逐页写入擦除数据
  258. int pageNum = 256/8; // 每页包含 16 字节
  259. for (int page = 0; page < pageNum; page++) {
  260. int address = page * 8;
  261. if (At24c02WriteBytes(address, sizeof(eraseData), eraseData) != 0) {
  262. printf("整体擦除失败\r\n");
  263. return;
  264. }
  265. }
  266. printf("整体擦除成功\r\n");
  267. }
  268. int HuiFuChuChangSheZhi()
  269. {
  270. uint8_t GL_MiMa[6]={'0','0','0','0','0','0'}; // 出厂——管理员密码
  271. uint8_t KM_MiMa[6]={'1','2','3','4','5','6'}; //出厂------开门密码
  272. // 将所有字节设置为 0x00(擦除状态)
  273. uint8_t eraseData[256];
  274. memset(eraseData, 0x00, sizeof(eraseData));
  275. // 逐页写入擦除数据
  276. int pageNum = 256/8; // 每页包含 16 字节
  277. for (int page = 0; page < pageNum; page++)
  278. {
  279. int address = page * 8;
  280. if (At24c02WriteBytes(address, sizeof(eraseData), eraseData) != 0)
  281. {
  282. printf("整体擦除失败\r\n");
  283. return 0;
  284. }
  285. }
  286. printf("整体擦除成功\r\n");
  287. //将初始化开门密码与管理员密码写入指定位置
  288. if (At24c02WriteBytes(240,sizeof(KM_MiMa),KM_MiMa)!=0) //在指定位置240(31页的前6字节)存开门密码
  289. {
  290. return 0;
  291. }
  292. if (At24c02WriteBytes(232,sizeof(GL_MiMa),GL_MiMa)!=0) //在指定位置232(30页的前6字节)存管理员密码
  293. {
  294. return 0;
  295. }
  296. return 1;
  297. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/205824
推荐阅读
相关标签
  

闽ICP备14008679号