下面我们使用在零知平台上使用PN532进行读写卡操作。
PN532 | 零知-标准板 |
GND | GND |
VCC | 3.3V |
TXD | 0 |
RXD | 1 |
/**********************************************************
* 文件: pn532-testing.ino by 零知实验室([url]www.lingzhilab.com[/url])
* -^^- 零知开源,让电子制作变得更简单! -^^-
* 时间: 2018/11/26 15:15
* 说明:
************************************************************/
#define SerialNFC Serial1 //使用Serial1接口连接PN532
//#define DEBUG_PRINT //调试
int8_t nfc_wakeUp();//唤醒操作
int8_t nfc_scaning(uint8_t []);//寻卡操作
int8_t nfc_vertify(int block, uint8_t key[], uint8_t uuid[]);//验证
int8_t nfc_readBlock(int block, uint8_t *data); //读取某一个块
int8_t nfc_writeBlock(int block, uint8_t *data);//写入数据到某个块
#define RECV_BUFF_LEN 255
uint8_t recv_buff[RECV_BUFF_LEN] = {0};//NFC串口返回的数据
void PrintHex(const uint8_t *data, const uint32_t numBytes)
{
for (uint8_t i = 0; i < numBytes; i++) {
if (data[i] < 0x10) {
Serial.print(" 0");
} else {
Serial.print(' ');
}
Serial.print(data[i], HEX);
}
Serial.println("");
}
// 复位或上电后运行一次:
void setup() {
//在这里加入初始化相关代码,只运行一次:
Serial.begin(9600);
SerialNFC.begin(115200);
Serial.println("PN532 NFC HSU Mode");
//唤醒
if(nfc_wakeUp() == 0)
{
Serial.println("wake up success...");
}else{
Serial.println("wake up failed...");
while(1);
}
uint8_t uuid[4] = {0};
//开始寻卡
Serial.println("scan...");
if(nfc_scaning(uuid) == 0)
{
Serial.print("Fond card, UUID:");
PrintHex(uuid,4);
}else{
Serial.println("No card found...");
while(1);
}
uint8_t keys[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
//验证:第7块
if( nfc_vertify(7, keys, uuid) == 0)
{
Serial.println("verify ok");
}else{
Serial.println("verify failed");
while(1);
}
//读取第6块数据
uint8_t read_data[16] = {0};
int block = 6;
int8_t ret = nfc_readBlock(block, read_data);
Serial.print("read block ");Serial.print(block);
if(ret == 0)
{
Serial.print(",data:");
PrintHex(read_data,16);
}
else
{
Serial.println("error...");
}
//向第6块中写入数据
uint8_t write_data[16] = {0};
//写入数据为 0x10 ~ 0x1f
for(int i=0; i<16;i++)
write_data[i] = 0x10+i;
ret = nfc_writeBlock(block,write_data);
Serial.print("write block ");Serial.print(block);
Serial.print(",data:");
PrintHex(write_data,16);
if(ret == 0)
{
Serial.println(" Write success...");
memset(read_data,0,16);
nfc_readBlock(block, read_data);
Serial.print("read back :");
PrintHex(read_data,16);
}else{
Serial.println("write failed");
}
}
//一直循环执行:
void loop() {
// 在这里加入主要程序代码,重复执行:
}
具体的实现代码如下
#ifdef DEBUG_PRINT
#define DMSG(args...) Serial.println(args)
#define DMSG_STR(str) Serial.println(str)
#define DMSG_HEX(num) Serial.println(num, HEX)
#define DMSG_INT(num) Serial.println(num)
#else
#define DMSG(args...)
#define DMSG_STR(str)
#define DMSG_HEX(num)
#define DMSG_INT(num)
#endif
#define PN532_PREAMBLE (0x00)
#define PN532_STARTCODE1 (0x00)
#define PN532_STARTCODE2 (0xFF)
#define PN532_POSTAMBLE (0x00)
#define PN532_HOSTTOPN532 (0xD4)
#define PN532_PN532TOHOST (0xD5)
#define PN532_ACK_WAIT_TIME (10) // ms, timeout of waiting for ACK
#define PN532_INVALID_ACK (-1)
#define PN532_TIMEOUT (-2)
#define PN532_INVALID_FRAME (-3)
#define PN532_NO_SPACE (-4)
uint8_t command;
int8_t writeCommand(const uint8_t *header, uint8_t hlen, const uint8_t *body, uint8_t blen)
{
/** dump serial buffer */
if(SerialNFC.available()){
DMSG("Dump serial buffer: ");
}
while(SerialNFC.available()){
uint8_t ret = SerialNFC.read();
DMSG_HEX(ret);
}
command = header[0];
SerialNFC.write(PN532_PREAMBLE);
SerialNFC.write(PN532_STARTCODE1);
SerialNFC.write(PN532_STARTCODE2);
uint8_t length = hlen + blen + 1; // length of data field: TFI + DATA
SerialNFC.write(length);
SerialNFC.write(~length + 1); // checksum of length
SerialNFC.write(PN532_HOSTTOPN532);
uint8_t sum = PN532_HOSTTOPN532; // sum of TFI + DATA
DMSG("\nWrite: ");
SerialNFC.write(header, hlen);
for (uint8_t i = 0; i < hlen; i++) {
sum += header[i];
DMSG_HEX(header[i]);
}
SerialNFC.write(body, blen);
for (uint8_t i = 0; i < blen; i++) {
sum += body[i];
DMSG_HEX(body[i]);
}
uint8_t checksum = ~sum + 1; // checksum of TFI + DATA
SerialNFC.write(checksum);
SerialNFC.write(PN532_POSTAMBLE);
return readAckFrame();
}
int16_t readResponse(uint8_t buf[], uint8_t len, uint16_t timeout)
{
uint8_t tmp[3];
delay(100);
DMSG("\nRead: ");
/** Frame Preamble and Start Code */
if(receive(tmp, 3, timeout)<=0){
return PN532_TIMEOUT;
}
if(0 != tmp[0] || 0!= tmp[1] || 0xFF != tmp[2]){
DMSG("Preamble error");
return PN532_INVALID_FRAME;
}
/** receive length and check */
uint8_t length[2];
if(receive(length, 2, timeout) <= 0){
return PN532_TIMEOUT;
}
if( 0 != (uint8_t)(length[0] + length[1]) ){
DMSG("Length error");
return PN532_INVALID_FRAME;
}
length[0] -= 2;
if( length[0] > len){
return PN532_NO_SPACE;
}
/** receive command byte */
uint8_t cmd = command + 1; // response command
if(receive(tmp, 2, timeout) <= 0){
return PN532_TIMEOUT;
}
if( PN532_PN532TOHOST != tmp[0] || cmd != tmp[1]){
DMSG("Command error");
return PN532_INVALID_FRAME;
}
if(receive(buf, length[0], timeout) != length[0]){
return PN532_TIMEOUT;
}
uint8_t sum = PN532_PN532TOHOST + cmd;
for(uint8_t i=0; i<length[0]; i++){
sum += buf[i];
}
/** checksum and postamble */
if(receive(tmp, 2, timeout) <= 0){
return PN532_TIMEOUT;
}
if( 0 != (uint8_t)(sum + tmp[0]) || 0 != tmp[1] ){
DMSG("Checksum error");
return PN532_INVALID_FRAME;
}
return length[0];
}
int8_t readAckFrame()
{
const uint8_t PN532_ACK[] = {0, 0, 0xFF, 0, 0xFF, 0};
uint8_t ackBuf[sizeof(PN532_ACK)];
delay(100);
DMSG("\nAck: ");
if( receive(ackBuf, sizeof(PN532_ACK), PN532_ACK_WAIT_TIME) <= 0 ){
DMSG("Timeout\n");
return PN532_TIMEOUT;
}
if( memcmp(ackBuf, PN532_ACK, sizeof(PN532_ACK)) ){
DMSG("Invalid\n");
return PN532_INVALID_ACK;
}
DMSG("OK\n");
return 0;
}
/**
@brief receive data .
@param buf --> return value buffer.
len --> length expect to receive.
timeout --> time of reveiving
@retval number of received bytes, 0 means no data received.
*/
int8_t receive(uint8_t *buf, int len, uint16_t timeout)
{
int read_bytes = 0;
int ret;
unsigned long start_millis;
while (read_bytes < len) {
start_millis = millis();
do {
ret = SerialNFC.read();
if (ret >= 0) {
break;
}
delay(10);
} while((timeout == 0) || ((millis()- start_millis ) < timeout));
if (ret < 0) {
if(read_bytes){
return read_bytes;
}else{
return PN532_TIMEOUT;
}
}
buf[read_bytes] = (uint8_t)ret;
read_bytes++;
}
return read_bytes;
}
int8_t nfc_wakeUp()
{
const uint8_t cmd_wake_up[] = {
0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0xfd, 0xd4,
0x14, 0x01, 0x17, 0x00};
const uint8_t wake_up_resp[] = {0x00 ,0x00 ,0xFF ,0x00 ,0xFF ,
0x00 ,0x00 ,0x00 ,0xFF ,0x02 ,0xFE ,0xD5 ,0x15 ,0x16 ,0x00};
for(int i=0; i<sizeof(cmd_wake_up); i++)
{
SerialNFC.write(cmd_wake_up[i]);
}
int getLen = receive(recv_buff,15,1000);
for(int i=0; i<getLen; i++)
{
if(wake_up_resp[i]!=recv_buff[i]){
return -1;
}
}
return 0;
}
int8_t nfc_scaning(uint8_t uuid[])
{
uint8_t cmd_head[1] = {0x4a};
uint8_t cmd_body[2] = {0x02,0x00};
if(writeCommand(cmd_head, 1, cmd_body, 2) == 0)
{
// Serial.println("wr cmd ok");
}
memset(recv_buff,0,RECV_BUFF_LEN);
int8_t ret = 0;
if( (ret = readResponse(recv_buff, 13, 6000)) >=0)
{
// PrintHex(recv_buff,13);
for(int i=0; i<4; i++)
uuid[i] = recv_buff[i+6];
return 0;
}else{
return -1;
}
}
int8_t nfc_vertify(int block, uint8_t key[], uint8_t uuid[])
{
//40 01 60 07 FF FF FF FF FF FF 90 1F 2A A4
uint8_t cmd_head[3] = {0x40,0x01,0x60};
uint8_t cmd_body[1+6+4] = {0};
cmd_body[0] = block;
for(int i=0; i<6; i++)
{
cmd_body[i+1] = key[i];
}
for(int i=0; i<4; i++)
{
cmd_body[i+7] = uuid[i];
}
if(writeCommand(cmd_head, 3, cmd_body, 11) == 0)
{
// Serial.println("wr cmd ok");
}
memset(recv_buff,0,RECV_BUFF_LEN);
int8_t ret = readResponse(recv_buff, 1, 1000);
if(ret >= 0){
if(recv_buff[0] == 0x00)
return 0;
}
return -1;
}
int8_t nfc_readBlock(int block, uint8_t *data)
{
uint8_t cmd_head[2] = {0x40,0x01};
uint8_t cmd_body[2] = {0x30, block};
writeCommand(cmd_head, 2, cmd_body, 2);
memset(recv_buff,0,RECV_BUFF_LEN);
int ret = readResponse(recv_buff, 17, 1000);
if(ret >=0)
{
for(int i=0; i<ret; i++)
{
data[i] = recv_buff[i+1];
}
return 0;
}else{
return -1;
}
// Serial.println(ret);
// PrintHex(recv_buff, 17);
}
int8_t nfc_writeBlock(int block, uint8_t *data)
{
uint8_t cmd_head[4] = {0x40,0x01,0xa0,block};
uint8_t cmd_body[16] = {0};
for(int i=0; i<16; i++)
cmd_body[i] = data[i];
writeCommand(cmd_head, 4, cmd_body, 16);
memset(recv_buff,0,RECV_BUFF_LEN);
int ret = readResponse(recv_buff, 1, 1000);
if(ret >=0)
{
if(recv_buff[0] == 0)
return 0;
}else{
return -1;
}
}
完整工程