物联网之RFID三(NFC)

内容提纲

1、NFC的概念-熟悉

2、NFC和RFID区别-掌握

3、NFC的工作模式-掌握

nfc概述

NFC (Near Field Communication)近场通信,这个技术由非接触式射频识别(RFID)演变而来,由飞利浦半导体(现恩智浦半导体公司)、诺基亚和索尼共同研制开发,其基础是RFID及互连技术。NFC是一种短距离高频的无线电技术,在13.56Mhz频率运行于20cm距离内。其传输速度有106Kbit/s,212Kbit/s或者424Kbit/s三种。目前近场通信已通过并成为ISO/IEC IS 18092国际标准、ECMA-340标准与ETSI TS 102 190标准。NFC采用主动和被动两种读取模式。

Nfc工作模式

卡模式:这个模式其实就是相当于一张采用RFID技术的IC卡。可以替代大量的IC卡(包括信用卡)场合商场刷卡、公交卡、门禁管制,车票,门票等等。此种方式下,有一个极大的优点,那就是卡片通过非接触读卡器的RF域来供电,即便是寄主设备(如手机)没电也可以工作。

读写器模式:这个模式可以模拟读读卡器功能,读取MIFARE和FeliCa卡的信息

点对点模式:这个模式和红外线差不多,可用于数据交换,只是传输距离较短,传输创建速度较快,传输速度可快些,功耗低(蓝牙也类似)。将两个具备NFC功能的设备链接,能实现数据点对点传输,如下载音乐、交换图片或者同步设备地址簿。一次通过NFC,多个设备如数码相机、PDA、计算机和手机之间都可以交换资料或者服务

物联网之RFID三(NFC)_第1张图片

NFC与RFID区别

• 第一、NFC将非接触读卡器、非接触卡和点对点功能整合进一块单芯片,而rfid必须有阅读器和标签组成。RFID只能实现信息的读取以及判定,而NFC技术则强调的是信息交互。通俗的说NFC就是RFID的演进版本,双方可以近距离交换信息。NFC手机内置NFC芯片,组成RFID模块的一部分,可以当作RFID无源标签使用进行支付费用;也可以当作RFID读写器,用作数据交换与采集,还可以进行NFC手机之间的数据通信。

• 第二、NFC传输范围比RFID小,RFID的传输范围可以达到几米、甚至几十米,但由于NFC采取了独特的信号衰减技术,相对于RFID来说NFC具有距离近、带宽高、能耗低等特点。

• 第三、应用方向不同。NFC看更多的是针对于消费类电子设备相互通讯,有源RFID则更擅长在长距离识别。

NFC与BLE区别

物联网之RFID三(NFC)_第2张图片

内容提纲

1、PN532介绍-了解

2、PN532帧格式-掌握

PN532概述

• 随着互联网的普及,手机作为互联网最直接的智能终端,必将会引起一场技术上的革命,如同以前蓝牙、USB、GPS等标配,NFC将成为日后手机最重要的标配,通过NFC技术,手机支付、看电影、坐地铁都能实现,将在我们的日常生活中发挥更大的作用。

• 我们这里使用的NFC芯片为PN532,它是一款高度集成的非接触式通讯收发模块,基于8051单片机核心。它支持6个不同的操作模式:ISO/IEC14443A/MIFARE 读/写器、FeliCa 读/写器、ISO/IEC 14443B 读/写器、ISO/IEC14443A MIFARE卡模拟模式、FeliCa卡模拟模式、ISO/IEC 18092 ECMA 340点对点;这款芯片提供3中和主机通信的接口:SPI\I2C\USART

SPI\I2C\USART三种通信方式有该芯片的P16引脚和P17引脚配置:

                            P16                 P17

UART                0(GND)            0(GND)

I2C                    1(DVDD)          0(GND)

SPI                    0(GND)            1(DVDD)

PN532普通帧(P9)(普通格式最大发送255个字节,而长格式(下面有讲解)可以发送更多的字节)

物联网之RFID三(NFC)_第3张图片

对于PN532的控制,只需要按照帧格式写入数据就可以了

0x00, 前序

0x00, 0xff, 包头

LEN, 数据长度,包含TFIPD

LCS, 长度校验和,LEN + LCS = 0x00;

TFI, 传输方向,0xd4传到卡片,0xd5卡片返回

PD0, 数据

PD1, 数据

PDn, 数据

DCS, 数据校验和,DCS+TFI+PD0+…+PDn = 0x00;

长格式帧(P10)

物联网之RFID三(NFC)_第4张图片

0x00, 前序

0x00, 0xff, 包头                                                 

0xff, 0xff   短格式中的长度和校验           (普通格式最大发送255个字节,而长格式可以发送更多的字节)

LENH, 数据长度高字节,包含TFIPD

LENL, 数据长度低字节,包含TFIPD

LCS, 长度校验和,LENH + LENL + LCS = 0x00;

TFI, 传输方向,0xd4传到卡片,0xd5卡片返回

PD0, 数据

PD1, 数据

PDn, 数据

      DCS, 数据校验和,DCS+TFI+PD0+…+PDn = 0x00;

以上帧格式可用一个数据结构表示,方便写代码:

/* PN532操作命令结构定义 */
struct Pn532Cmd{
	uint8_t Preamble;             //前序 
	uint8_t StartCode[2];         //包头 
	uint8_t LEN;         	      //包长 TFI+PD0...PDn
	uint8_t LCS;                  //长度校验 LEN + LCS = 0x00
	uint8_t TFI;                  //命令帧识别位 (0xD4:input) (0xD5:output)
	uint8_t *data;                //数据域
	uint8_t DCS;                  //数据校验 [TFI + PD0 + PD1 + ... + PDn + DCS] = 0x00
	uint8_t Postamble;            //后序 
};

struct Pn532Cmd cmd ={
	.Preamble = 0x00,
	.StartCode[0] = 0x00,
	.StartCode[1] = 0xff,
	.TFI = 0xd4,                  //传输方向,0xd4传到卡片,0xd5卡片返回
	.Postamble = 0x00,
};

/*******************************************************************************
* Function Name  	: GetCmd
* Description    	: 拿到命令包,在buf中存放一个完整的数据包
* Input          	: 命令,命令长度
* Output         	: none
* Return         	: none
* date			: 
* modify		:
*******************************************************************************/
void GetCmd(uint8_t *data, uint8_t l)
{
	uint8_t temp=0;
	len = 0;
	memset(buf,0,100);
	cmd.LEN = l+1;		//计算长度,包括数据长度和传输标志
	cmd.LCS = 0-cmd.LEN;	//长度校验和
	cmd.data = data;
	for(int i=0; i

PN532应答(P9)

物联网之RFID三(NFC)_第5张图片

0x00, 前序

0x00, 0xff, 包头

00, 数据长度, 这里没有任何数据

ff, 长度校验和,LEN + LCS = 0x00;

传输方向,0xd4传到卡片,0xd5卡片返回

数据

数据

PDn, 数据

DCS, 数据校验和,DCS+TFI+PD0+…+PDn = 0x00;

00, 尾序

内容提纲

1、唤醒-掌握

2、扫卡-掌握

3、认证-掌握

4、读写-掌握

唤醒芯片(P23,P99)

0x55,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,(这些字符就是唤醒头)

0x00,0x00,0xFF,0x03,0xFD,0xD4,0x14,0x01,0x17,0x00(在唤醒头后面加上了一个普通帧)

从手册可以看出,唤醒命令要在原有的数据包之前加入唤醒头,这个比较特殊一点

0xd4代表主机向PN532写入数据

0x14,0x01代表选择了普通模式

物联网之RFID三(NFC)_第6张图片

应答:0x00,0x00,0xff,0x02,0xfe,0xd5(方向:0xd5卡片返回数据到单片机),0x15(应答码,在发送的基础上加1,因为唤醒命令中使用的是0x14所以这里加1变成0x15),0x16,0x00

命令格式(P35)

• 扫描卡片

    0x4a, 0x02, 0x00   //扫描命令,卡片个数(2个),波特率

uint8_t SCAN[3] = {0x4a, 0x02, 0x00}; 	//扫描指令,卡片个数,波特率

• 应答

    0x4b, 应答码

    0x02, 卡片个数

    0x01, 第一个卡片

    0x04, 0x00, 卡片类型

    0x08, 卡片容量

    0x04, id长度

    0x01, 0x02, 0x03, 0x04 卡片id(该环节已经拿到了卡片ID,所以不需要同RFID一样再增加一个防冲突环节)

uint8_t WAKE[24] = {0x55,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x03,
                                      0xFD,0xD4,0x14,0x01,0x17,0x00};           //唤醒模块
uint8_t WAKEBACK[9]		 = {0x00,0x00,0xFF,0x02,0xFE,0xD5,0x15,0x16,0x00};  //应答

• 认证卡片

    0x40, 0x01, 0x60, 0x02,  数据交换命令,1号卡片,A认证(认证A密码是0x60,认证B密码是0x61),2地址

    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 秘钥

    0x01, 0x02, 0x03, 0x04 卡片id

• 应答

    0x41, 0x00   无错

uint8_t AUTHOR[14] = {0x40,0x01,0x60,0x02,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x02,0x03,0x04};/*交换数据,
                                                                 1卡,认证命令,2地址,key,id*/
/*41 0  应答,无措*/

• 读卡

    0x40, 0x01, 0x30, 0x02   //交换数据,1号卡,读取块,2地址

• 应答

    0x41, 0x00, 16bytes  应答,无错,16个数据

uint8_t READ[4] = {0x40, 0x01, 0x30, 0x02};//交换数据,1号卡,读取块,2地址
/*41, 0, 16bytes  应答,无错,16个数据*/

• 写卡

    0x40, 0x01, 0xa0, 0x02,   交换数据,1号卡,写入块,2地址

    1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6 数据

• 应答

    0x41, 0x00 应答,无错

uint8_t WRITE[20] = {0x40, 0x01, 0xa0, 0x02, 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6};//交换数据,1号卡,写入块,2地址,数据
/*41, 0 应答,无错*/

• 充值

    0x40, 0x01, 0xc1, 0x02, 1,0,0,0 //交换数据,1号卡,充值,2地址,数据

    0x40, 0x01, 0xB0, 0x02;//交换数据,1号卡,保存,2地址

• 应答

    0x41, 0x00   应答,无错

uint8_t INCREMENT[8] = {0x40, 0x01, 0xc1, 0x02, 1,0,0,0};//交换数据,1号卡,充值,2地址,数据
uint8_t TRANSFER[4] = {0x40, 0x01, 0xB0, 0x02};//交换数据,1号卡,保存,2地址
/*41, 0 应答,无错*/

• 扣款

    0x40, 0x01, 0xc0, 0x02, 1,0,0,0;//交换数据,1号卡,扣款,2地址,数据

    0x40, 0x01, 0xB0, 0x02;//交换数据,1号卡,保存,2地址

• 应答

    0x41, 0x00 应答,无错

uint8_t DECREMENT[8] = {0x40, 0x01, 0xc0, 0x02, 1,0,0,0};//交换数据,1号卡,扣款,2地址,数据
uint8_t TRANSFER[4] = {0x40, 0x01, 0xB0, 0x02};//交换数据,1号卡,保存,2地址
/*41, 0 应答,无错*/

注意:充值或者扣款操作一定要加上保存动作

读写卡片(P35,P33)

读写卡片的每一条命令都要按照帧格式

• 唤醒芯片,将芯片设置为普通模式

• 扫描卡片,一次最多2张。成功可以得到ID

• 认证,需要发送秘钥和ID。注意这里没有防冲突环节,因为在扫描的时候已经拿到卡片的ID,在认证的时候指明ID就可以了

• 读、写、充值、扣款

PN532读取卡片的过程要比MFRC522简单很多

修改S50卡片秘钥:控制秘钥位共四个字节,但是只有三个字节是有效的,Byte9不起作用,可以不用管

物联网之RFID三(NFC)_第7张图片

每个字节的bit7控制block3,Bit6控制block2,Bit5控制block1

Bit4控制block0,Bit3~0其实就是bit7~4取反的结果

Block3出厂默认 ff ff ff ff ff ff    ff 07 80 69    ff ff ff ff ff ff

S50控制字注意_b结尾的位取反之后才是最终的控制模式

物联网之RFID三(NFC)_第8张图片

每个字节的bit7控制block3,Bit6控制block2,Bit5控制block1

Bit4控制block0,Bit3~0其实就是bit7~4取反的结果

Block3出厂默认 ff ff ff ff ff ff    ff 07 80 69    ff ff ff ff ff ff

秘钥区控制(block3)

物联网之RFID三(NFC)_第9张图片

Block3由bit7控制,出厂默认的是001控制

秘钥A永远不可读,读出来的是0x00

修改秘钥A的过程:

第6、7、8字节最高位(第7位)出厂时分别为0 0 1,则控制模式如下所示:需要修改秘钥A,需要先传入最初的秘钥A

物联网之RFID三(NFC)_第10张图片

1、唤醒

2、扫描卡片

3、认证(此时必须传入秘钥A,才能修改秘钥A)

4、修改秘钥A(16bytes,注意,不要修改本密码以外的其他地方

5、保存修改

6、重新认证

7、数据的读写

内容提纲

1、读写卡流程-掌握

2、读卡(BLOCK0)实战-掌握

3、写卡(BLOCK3)实战-掌握

命令格式(P35,P33)

• 唤醒

• 扫描

• 认证

• 读卡

• 唤醒

• 扫描

• 认证

• 写卡

唤醒芯片(P23,P99)

0x55,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

0x00,0x00,0xFF,0x03,0xFD,0xD4,0x14,0x01,0x17,0x00

从手册可以看出,唤醒命令要在原有的数据包之前加入唤醒头,这个比较特殊一点

0xd4代表主机向PN532写入数据

0x14,0x01代表选择了普通模式

物联网之RFID三(NFC)_第11张图片

命令格式(P35)

• 扫描卡片

    0x4a, 0x02, 0x00   //扫描命令,卡片个数,波特率

• 应答

    0x4b, 应答码

    0x02, 卡片个数

    0x01, 第一个卡片

    0x04, 0x00, 卡片类型

    0x08, 卡片容量

    0x04, id长度

    0x01, 0x02, 0x03, 0x04 卡片id

• 认证卡片

    0x40, 0x01, 0x60, 0x02,  数据交换命令,1号卡片,A认证,2地址

    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 秘钥

    0x01, 0x02, 0x03, 0x04 卡片id

• 应答

    0x41, 0x00   无错

• 读卡

    0x40, 0x01, 0x30, 0x02   //交换数据,1号卡,读取块,2地址

• 应答

    0x41, 0x00, 16bytes  应答,无错,16个数据

• 写卡

    0x40, 0x01, 0xa0, 0x02,   交换数据,1号卡,写入块,2地址

    1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6 数据

• 应答

    0x41, 0x00 应答,无错

读写卡片(P35,P33) 

读写卡片的每一条命令都要按照帧格式

• 唤醒芯片,将芯片设置为普通模式

• 扫描卡片,一次最多2张。成功可以得到ID

• 认证,需要发送秘钥和ID。注意这里没有防冲突环节,因为在扫描的时候已经拿到卡片的ID,在认证的时候指明ID就可以了

• 读、写、充值、扣款

• PN532读取卡片的过程要比MFRC522简单很多

内容提纲

1、S50值段-掌握

2、充值操作-掌握

3、扣款-掌握

S50存储结构

值段

值段可以实现电子钱包的功能 有效的命令有 读 写 增 减 恢复 发送
值段有一个固定的数据格式 可以进行错误检测和纠正并备份管理
值段只能在值段格式的写操作时产生 

• 值 表示一个带符号 4 字节值 这个值的最低一个字节保存在最低的地址中 取反的字节以标准2 的格式保存 为了保证数据的正确性和保密性 值被保存了 3 次 两次不取反保存 一次取反保存 

• Adr 表示一个 1 字节地址 当执行强大的备份管理时用于保存存储段的地址 地址字节保存了 4次 取反和不取反各保存两次 在执行增 减 恢复 传送操作时 地址保持不变 它只能通过写命令改变 

• 初始化为固定的格式(使用Write_Card函数初始化)

   以 block1(地址为1)为例:        00,00,00,00,           ff,ff,ff,ff,    00,00,00,00,                1,fe,1,fe
                                                      值:初始化为0           值取反           值             两次写地址,两次地址取反

• 唤醒

• 扫描

• 认证

命令格式(P35,P33)

• 充值

    0x40, 0x01, 0xc1, 0x02, 1,0,0,0 //交换数据,1号卡,充值,2地址,数据

    0x40, 0x01, 0xB0, 0x02;//交换数据,1号卡,保存,2地址

• 应答

    0x41, 0x00   应答,无错

• 扣款

    0x40, 0x01, 0xc0, 0x02, 1,0,0,0;//交换数据,1号卡,扣款,2地址,数据

    0x40, 0x01, 0xB0, 0x02;//交换数据,1号卡,保存,2地址

• 应答

    0x41, 0x00 应答,无错

注意:充值或者扣款操作一定要加上保存动作

  充值框架(扣款类似操作):

  //while(1)
  uint8_ t value[4]= {0xff, 0x00, 0x00, 0x00};
  uint8_ t data[16]= {0x0a, 0x00, 0x00, 0x00, 0xf5, 0xff,0xff, 0xff, 0x0a, 0x00, 0x00, 0x00, 0x01, 0xfe, 0x0l, 0xfe};
  uint8_ t key[6]= {0xff, 0xff,0xff, 0xff, 0xff,0xff};
  HAL_Delay(l000) ; 
  Wake_Card();//唤醒
  Scan_Card();  //扫描
  author(1, key) ; //地址1认证
  write(1, data) ;  //地址1初始化为充值付款的固定格式
  increment(1, value);  //地址1充值
  transfer(1);   //地址1保存
  read(1) ;  //读取地址1的数据

如下为全部相关参考代码: 

532.c  功能:掌握NFC的操作流程和相关功能函数

#include "PN532.h"
#include "stm32f0xx_hal.h"
#include "dma.h"
#include "i2c.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
#include "lcd.h"
#include "string.h"
#include "logo.h"

#include "stdlib.h"
#include "stdio.h"

#define BUFFER_SIZE 128

uint8_t buf[100];
uint8_t len = 0;
uint8_t write_data[16];
uint8_t write_value[4];
uint8_t ID[4];
uint8_t KEY_A[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
extern uint8_t rx_buffer[128];

uint8_t WAKE[24] = {0x55,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x03,0xFD,0xD4,0x14,0x01,0x17,0x00};           //唤醒模块
uint8_t WAKEBACK[9]		 = {0x00,0x00,0xFF,0x02,0xFE,0xD5,0x15,0x16,0x00};
/* PN532操作命令结构定义 */
struct Pn532Cmd{
	uint8_t Preamble;         	  //前序 
	uint8_t StartCode[2];         //包头 
	uint8_t LEN;         					//包长 TFI+PD0...PDn
	uint8_t LCS;                  //长度校验 LEN + LCS = 0x00
	uint8_t TFI;                  //命令帧识别位 (0xD4:input) (0xD5:output)
	uint8_t *data;                //数据域
	uint8_t DCS;                  //数据校验 [TFI + PD0 + PD1 + ... + PDn + DCS] = 0x00
	uint8_t Postamble;            //后序 
};

struct Pn532Cmd cmd ={
	.Preamble = 0x00,
	.StartCode[0] = 0x00,
	.StartCode[1] = 0xff,
	.TFI = 0xd4,
	.Postamble = 0x00,
};

uint8_t SCAN[3] = {0x4a, 0x02, 0x00}; 	//扫描指令,卡片个数,波特率
/*
4B 应答
02 目标个数
01 第一个目标
04 00 选卡应答
08	防冲突应答
04	id长度
12 67 58 32  id
02  
44 00
00
08
88 04 B6 E4 00 00 00 00
*/
uint8_t AUTHOR[14] = {0x40,0x01,0x60,0x02,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x02,0x03,0x04};//交换数据,1卡,认证命令,2地址,key,id
/*41 0  应答,无措*/
uint8_t READ[4] = {0x40, 0x01, 0x30, 0x02};//交换数据,1号卡,读取块,2地址
/*41, 0, 16bytes  应答,无错,16个数据*/
uint8_t WRITE[20] = {0x40, 0x01, 0xa0, 0x02, 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6};//交换数据,1号卡,写入块,2地址,数据
/*41, 0 应答,无错*/
uint8_t INCREMENT[8] = {0x40, 0x01, 0xc1, 0x02, 1,0,0,0};//交换数据,1号卡,充值,2地址,数据
uint8_t DECREMENT[8] = {0x40, 0x01, 0xc0, 0x02, 1,0,0,0};//交换数据,1号卡,扣款,2地址,数据
uint8_t TRANSFER[4] = {0x40, 0x01, 0xB0, 0x02};//交换数据,1号卡,保存,2地址
/*******************************************************************************
* Function Name  	: GetCmd
* Description    	: 拿到命令包,在buf中存放一个完整的数据包
* Input          	: 命令,命令长度
* Output         	: none
* Return         	: none
* date				: 2016.12.28
* modify			:
*******************************************************************************/
void GetCmd(uint8_t *data, uint8_t l)
{
	uint8_t temp=0;
	len = 0;
	memset(buf,0,100);
	cmd.LEN = l+1;			//计算长度,包括数据长度和传输标志
	cmd.LCS = 0-cmd.LEN;	//长度校验和
	cmd.data = data;
	for(int i=0; i
main.c文件  对nfc做具体操作实验

#include "stm32f0xx_hal.h"
#include "dma.h"
#include "i2c.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
#include "stdlib.h"
#include "string.h"
#include "stdio.h"

#include "PN532.h"

void SystemClock_Config(void);
void Error_Handler(void);

extern uint8_t KEY2_FLAG;
extern uint8_t KEY3_FLAG;

unsigned char cmd_dat[16];//卡片要写的数据
unsigned char aRxBuffer[2];
unsigned char cmd_buf[100];	//串口数据缓冲区
unsigned char count = 0;
unsigned char cmd_type;	//命令类型,读或者写,r/w
unsigned char cmd_addr;	//操作的地址0~63
unsigned char cmd_check;//二级命令,0正常区域,1改秘钥,2充值,3扣款,4改控制字
unsigned char KEY_B[6];//秘钥B
unsigned char CMD_OVER = 0;	
unsigned char DATA_OVER = 0;
unsigned char error = 0;
int main(void)
{
	uint8_t j;

  HAL_Init();

  SystemClock_Config();

  MX_GPIO_Init();
  MX_DMA_Init();
  MX_I2C1_Init();
  MX_TIM6_Init();
  MX_USART1_UART_Init();
  MX_USART2_UART_Init();

	BoardInit();//开机初始化
	PN532_Read();

//在中断里接收串口数据
	HAL_UART_Receive_IT(&huart1,aRxBuffer,1);

    while (1)
    {
		if(error)
		{
			printf("指令错误\n");
			error = 0;
			continue;
		}
		if(CMD_OVER)
		{
			if(cmd_type == 'r')
			{
				if(cmd_addr<=63 && cmd_addr>=0)
					PN532_Read();
				else
					printf("地址不对\n");
				CMD_OVER = 0;
				cmd_type = 0;
			}
			else if(cmd_type == 'w')
			{
				if(DATA_OVER)
				{
					printf("data over\n");
					j = Write_Check();
					printf("j = %d\n", j);
					if(j==0)
					{
						if(cmd_check==0||cmd_check==1)
							PN532_Write();
						else if(cmd_check==2)
							PN532_Value(0xc1);
						else if(cmd_check==3)
							PN532_Value(0xc0);
					}
					else if(j==1)
						printf("要写入的地址不对\n");
					else if(j==2)
						printf("要写入的控制字不对\n");
					CMD_OVER = 0;
					DATA_OVER = 0;
					cmd_type = 0;
					cmd_check = 0;
					
				}
			}
		}
    }

}

/*******************************************************************************
* Function Name  	:
* Description    	: 串口接收回调函数,串口接收中断最终会调用这里
* Input          	:
* Output         	: 
* Return         	: 
* date				: 2016.12.27
* modify			:
*******************************************************************************/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
//	printf("r");
    if (huart == &huart1)
    {
        cmd_buf[count] = USART1->RDR;
		count++;
		if(cmd_buf[count-2]==0x0d && cmd_buf[count-1]==0x0a)	//结束符
		{
			if(cmd_buf[0]=='c' && count==18)				//命令
			{
				cmd_type = cmd_buf[1];		//获取命令 读/写
				cmd_check = cmd_buf[2];		//获取命令级别 写普通区还是特殊区 或者是充值
				cmd_addr = cmd_buf[3];		//获取操作地址
				memcpy(KEY_A, &cmd_buf[4], 6);//获取秘钥A
				memcpy(KEY_B, &cmd_buf[10], 6);//获取秘钥B
				CMD_OVER = 1;
			}
			else if(cmd_buf[0]=='d' && count==19)		//数据
			{
				memcpy(cmd_dat, &cmd_buf[1], 16);
				DATA_OVER = 1;
			}
			else if(cmd_buf[0]=='d' && count==7)		//数据
			{
				memcpy(cmd_dat, &cmd_buf[1], 4);
				DATA_OVER = 1;
			}
			else
				error = 1;		//格式完全不正确
			
			count = 0;
			memset(cmd_buf, 0, 100);
		}
    }
	HAL_UART_Receive_IT(&huart1,aRxBuffer,1);
}
/*******************************************************************************
* Function Name  	: Write_Check()
* Description    	: 卡片写入检测函数,目前暂不支持控制字的修改
* Input          	: none
* Output         	: none
* Return         	: 成功0,地址错误1,控制字错误2
* date				: 2016.12.27
* modify			:
*******************************************************************************/
uint8_t Write_Check()
{
	if(cmd_addr>=0 && cmd_addr<=63)
	{
		if(cmd_check==0 || cmd_check==2 || cmd_check==3)	//普通写入,不包含block3,因此要检测地址
		{
			if(cmd_addr!=0 && (cmd_addr+1)%4!=0)
				return 0;
			else
				return 1;
		}
		else if(cmd_check==1)	//修改秘钥A,控制区不可以改动
		{
			if(cmd_addr==0 || (cmd_addr+1)%4!=0)	//地址不正确
				return 1;
			if(cmd_dat[6]!=0xff || cmd_dat[7]!=0x07 || cmd_dat[8]!=0x80 || cmd_dat[9]!=0x69) //控制字不正确
				return 2;
			else 
				return 0;
		}
	}
	else
		return 1; //地址不正确
}

void SystemClock_Config(void)
{
    ...
}

int fputc(int ch, FILE *f)
{     
	while((USART1->ISR&0X40)==0);
	USART1->TDR = (uint8_t) ch;      
	return ch;
}

#ifdef USE_FULL_ASSERT

#endif

 

你可能感兴趣的:(物联网之RFID(射频识别技术,))