STM32+PN532写UltraLight标签

 

第一次写博客记录下日常开发,最近公司一个项目需要用到NFC模块,所以开始了解NFC相关的一些知识,并在此MARK一下。

 

1、项目背景:

需要一个NFC模块为一个Mifare UltraLight的NFC标签写入一个蓝牙MAC地址,让手持设备接触到NFC标签后可以自动连接一个终端的蓝牙。

2、Mifare UltraLight 介绍:

1、  容量512bit,分为16个page,每个page占4byte

2、  每个page可以通过编程的方式锁定为只读功能

3、  384位(从page4往后)用户读写区域

4、  唯一7字节物理号(page0前3个byte加page1)

详细可以百度下Mifare UltraLight卡。

3、模块选型

NFC模块:上百度和淘宝搜索了解,发现PN532模块非常受欢迎、资料十分多并且用途非常广泛,于是淘宝一个回来试试。

单片机:使用比较熟悉和通用的STM32F103VET6。

4、方案设计

因项目设计上希望NFC标签一直贴近NFC模块, 所以通过触发单片机控制NFC模块对标签进行单次烧写。

PN532操作步骤为:

唤醒->寻卡->写卡->读卡并校验数据->锁卡(变成只读)。

5、PN532串口驱动代码

PN532有多种硬件接口的通讯方式,我这边是选择了最简单的串口通讯方式,串口通讯主要是使用PN532手册提供的串口通讯命令。

a. 唤醒命令:

const uint8_t wake_up_buf[] = {0x55,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
0xFF,0x03,0xFD,0xD4,0x14,0x01,0x17,0x00};

 

int WakeUpPN532(t_NFC_Ops *nfc_ops){
		
	int ret = nfc_ops->uart_ops->SerialComWrite(wake_up_buf,sizeof(wake_up_buf));
	return ret;
}

唤醒命令格式固定,所以定义为const直接,发送成功后PN532模块会被唤醒。

b. 寻卡命令:

int FindNFCCard(t_NFC_Ops *nfc_ops){

	int ret = 0;
	unsigned char buf[48] = {0};
	
	buf[7] = d_FIND_NFCCARD_MAXNUM;
	buf[8] = E_106K_PROTOCOL;
	int len = NFC_CmdPackage(FIND_CARD,buf,2);
	ret = nfc_ops->uart_ops->SerialComWrite(buf,len);
	
	memset(buf,0,sizeof(buf));
	ret = ReadAParseNFCCmd(nfc_ops,FIND_CARD_ACK,buf,d_NFC_RW_TIMEOUT);
	
	return ret;
}

d_FIND_NFCCARD_MAXNUM: 为最大寻卡数

E_106K_PROTOCOL: 使用106K协议

FIND_CARD_ACK:寻卡应答

NFC_CmdPackage()(打包命令到buf,同时计算长度和校验)

ReadAParseNFCCmd()(读取NFC模块返回数据,检查是否收到期望的命令应答)

发送寻卡命令后,若PN532检测到NFC卡,会返回应答(包含卡ID)。

 ps:具体函数实现可以下载代码进行查看

 

c.写卡命令

int WriteNFCCard_4B(t_NFC_Ops *nfc_ops,int block_num,unsigned char* data_buf,int size){

	int ret = 0;
	unsigned char buf[48] = {0};
	
	if (size > d_WRITE_MAX_SIZE){
		printf("write over size\r\n");
		return -1;
	}
	
	buf[7] = 1;
	buf[8] = WRITE_4BYTE;
	buf[9] = (unsigned char)block_num;
	memcpy(buf+10,data_buf,size);
	int len = NFC_CmdPackage(CTL_CARD,buf,3+size);
	
	ret = nfc_ops->uart_ops->SerialComWrite(buf,len);
	Print_hex("Send: ",buf,len);
	
	memset(buf,0,sizeof(buf));
	ret = ReadAParseNFCCmd(nfc_ops,RW_DATA_ACK,buf,d_NFC_RW_TIMEOUT);
	if (ret < 0){
		return -1;
	}
	
	if (0 == buf[0]){  /* ¼ì²éдÊý¾ÝÊÇ·ñ³É¹¦ */
		ret = 0;
	}else{
		ret = -1;
	}
	
	return ret;
}

PN532模块每个块有4个字节空间,使用串口命令每次只能单块写入(一次写4字节)。

根据块号,数据,数据长度对NFC卡进行数据烧写,每次发送命令写入数据后必须读取返回值确定是否写入成功。

d.读卡命令

int ReadNFCCard_16B(t_NFC_Ops *nfc_ops,uint32_t block_num,uint8_t* data_buf,uint32_t size){

	int ret = 0;
	unsigned char buf[64] = {0};
	
	if (size > d_READ_MAX_SIZE){
		printf("read over size\r\n");
		return -1;
	}
	
	buf[7] = 1;
	buf[8] = READ_16BYTE;
	buf[9] = (unsigned char)block_num;

	int len = NFC_CmdPackage(CTL_CARD,buf,3);
	ret = nfc_ops->uart_ops->SerialComWrite(buf,len);
	Print_hex("Send: ",buf,len);
	
	memset(buf,0,sizeof(buf));
	ret = ReadAParseNFCCmd(nfc_ops,RW_DATA_ACK,buf,d_NFC_RW_TIMEOUT);
	if (ret < 0){
		return -1;
	}
	
	if (0 == buf[0]){  /* ¼ì²é¶ÁÊý¾ÝÊÇ·ñ³É¹¦ */
		ret = 0;
		memcpy(data_buf,buf+1,size);  /* ·µ»Ø¿éÇøÊý¾Ý */
	}else{
		ret = -1;
	}
	
	return ret;
}

PN532模块使用串口命令每次读可以连续读4个块(16字节)。

e.锁卡命令

const uint8_t lock_cmd[] = {0x8A,0x48,0xFF,0xFF};
int LockNFCCard(t_NFC_Ops *nfc_ops){
	
	int ret = WriteNFCCard(nfc_ops,d_LOCK_ADD,lock_cmd,sizeof(lock_cmd));
	return ret;
}

d_ LOCK_ADD等于2,Mifare UltraLight卡的块区2的后两个字节可以控制数据区的16个块区变成只读。

6、小结

目前已实现所需功能,不过还有一些不足的地方。如:

1、因PN532和标签隔了产品外壳并且标签比较小,近距离接时没有对得很准不一定能寻找到标签,有时需更加贴近才能寻卡成功。

2、代码方面在烧写标签耗时相对较长(每次发命令都串口阻塞等待100毫秒来获取应答结果)。

关于问题1,看了一下芯片手册没有找到有说明改变NFC灵敏度和功率的寄存器,不知道有没有其他大神知道如何通过更改配置来提高灵敏度。同时笔者目前正在调试PN5180这个高频模块,看能不能更换5180解决灵敏度问题。

PS: 网上有树莓派使用nfc库控制PN532的帖子,本人并未测试验证过,不知道NFC库是否支持更复杂的模块配置,例如可以配置灵敏度之类的方法,若有希望留言指点。

代码地址https://download.csdn.net/download/u012636124/10804862

有需要的可以去下载,初次写文章各种不足和没有说明白的,欢迎指点和交流。

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值