Funpack2-6 nRF7002 模拟NFC卡片
本项目将使用板卡的NFC功能,模拟信息卡片。信息主要分为两大类,一类是应用APP的文字介绍,另一类是相应的APP软件包名。手机接受到文字介绍后,5s内的下一次触碰将自动跳转到对应APP。
标签
Funpack活动
Funpack2-6
nRF7002
Kadam
更新2023-10-13
325

项目描述

  1. 项目介绍

    本项目将使用板卡的NFC功能,模拟信息卡片。信息主要分为两大类,一类是应用APP的文字介绍,另一类是相应的APP软件包名。板卡使用定时器持续、轮流播放4个APP的文字介绍,当用户使用带NFC功能的手机靠近板卡的NFC天线后,板卡自动将NFC转为跳转对应APP的功能。用户可以使用按键1直接跳转到下一条APP信息,使用按键2开关板卡的NFC功能。当NFC靠近或者按下按键时,LED会有相应的提示。

  2. 设计思路

    本项目的设计思路为:

    1. 使用板卡的NFC功能模拟一个存储多条信息(包括APP的文字介绍与对应的安装包)的卡片

    2. 利用板卡的定时器与按键的功能,实现多条信息、APP文字介绍与对应安装包的切换。

    3. 使用LED进行卡片靠近、远离或按键操作的指示。

  3. 简单的硬件介绍

    • nRF7002-DK开发板

      • nRF7002 DK是nRF7002 Wi-Fi 6协同IC的开发评估板,它包含了在单板上开发所需要的所有元器件。开发板采用nRF5340多协议SoC作为主处理器,配合nRF7002 Wi-Fi协同芯片。可以同时支持低功耗蓝牙和Wi-Fi 应用的开发,并实现如 OFDMA、波束成形和目标唤醒时间等多项 Wi-Fi 6 功能。

        nRF7002是Nordic的Wi-Fi产品系列中的首款器件,符合802.11ax标准,可提供双频段(2.4和5GHz)连接,支持Matter中使用的全部无线协议,可以为产品中添加最新的Wi-Fi 6技术,该芯片还具有帮助保护用户数据的先进安全功能。并与Nordic现有的超低功率技术无缝结合,可延长电池使用寿命。它提供快速、可靠的连接,具有先进的安全功能,并且方便集成到各个应用当中。

    • nRF5340芯片

      • nRF5340 是世界上第一款配备两个 Arm® Cortex-M33® 处理器的无线 SoC。板上的nRF5340是支持低功耗蓝牙、蓝牙Mesh、NFC、Thread和Zigbee的双核蓝牙5.3 SoC,并且蓝牙测向可实现所有到达角(AoA)和出发角(AoD)的测量功能。此外,它支持低功耗蓝牙音频,2 Mbps高吞吐量、广播扩展和长距离。像蓝牙Mesh、Thread和Zigbee这样的Mesh协议可以与低功耗蓝牙同时运行,从而使智能手机能够配网、入网、配置和控制Mesh节点。还支持NFC、ANT、802.15.4和2.4 GHz专有协议。

    • 外接NFC天线

      • 该开发板配送了一条外接的NFC天线,使用时要将该天线插入对应位置,注意插的方向。

    • LED灯

      • LED灯是嵌入式开发中常用的人机交互器件。在本项目中,我将使用LED1指示是否有NFC在读取信息,有则亮灯,无则熄灭。使用LED2指示按键是否被按下,当按键按下时,LED亮起否则熄灭。

    • 定时器

      • 使用板卡内置的定时器,主要用于定时,周期性切换卡片信息。

    使用上述的硬件是本次项目的基本硬件。

  4. 项目遇到的问题

    总体而言,本项目较为简单,NORDIC公司提供了相关的DEMO。但因为初次接触该公司的开发板,在配置开发环境上遇到了不少问题,如网络连接问题、开发环境需要手动下载不同安装包,还需要在VS Code相关插件中进行配置,对新手较为不友好。

    尽管提供了相对完整的DEMO,但进行学习时,需要去理解DEMO中代码的作用。因为是第一次接触到NFC开发板和NORDIC公司的开发环境,阅读代码时存在一定的障碍,如编码NFC信息时,DEMO使用了一个较为复杂的宏定义;不熟悉其API的命名方式,缺少注释的话很难一下子理解代码的作用,如nfc_t2t_payload_set中的“t2t”.

    但上述问题都是小问题,只要花费一点时间与保持耐心就能够利用这块资源丰富的开发板学习到许多有意思、有用的新知识。

软件流程图及各功能对应的主要代码片段及说明

  • 软件流程图

  • 主要代码及说明

    • 编码APP介绍文字信息

      • 这段代码主要将B站的中文介绍转换成的UTF16字符串组编码进NFC载荷信息里

      • 一个汉字对应一个UTF16编码,但在此处需要分开为2个8位的数据。如“哔”的UTF16为“\ud454”,需要转为 '\x54','\xd4'。

      • 该数组的生成可以借助python语言,进行快速转变,不需要手动调整。

      /*哔哩哔哩(bilibili.com)是国内知名的视频弹幕网站,这里有及时的动漫新番,活跃的ACG氛围,有创意的Up主。 (UTF16编码)*/
      static const uint8_t zh_bilibili[] = { '\x54','\xd4','\x54','\xe9','\x54','\xd4','\x54','\xe9','\xff','\x8','\x0','\x62',
      	'\x0','\x69','\x0','\x6c','\x0','\x69','\x0','\x62','\x0','\x69','\x0','\x6c','\x0','\x69','\x0','\x2e','\x0','\x63',
      	'\x0','\x6f','\x0','\x6d','\x0','\x29','\x66','\x2f','\x56','\xfd','\x51','\x85','\x77','\xe5','\x54','\xd','\x76',
      '\x84','\x89','\xc6','\x98','\x91','\x5f','\x39','\x5e','\x55','\x7f','\x51','\x7a','\xd9','\xff','\xc','\x8f','\xd9',
      '\x91','\xcc','\x67','\x9','\x53','\xca','\x65','\xf6','\x76','\x84','\x52','\xa8','\x6f','\x2b','\x65','\xb0','\x75',
      '\x6a','\xff','\xc','\x6d','\x3b','\x8d','\xc3','\x76','\x84','\x0','\x41','\x0','\x43','\x0','\x47','\x6c','\x1b','\x56','\xf4','\xff','\xc','\x67','\x9','\x52','\x1b','\x61','\xf','\x76','\x84','\x0','\x55','\x0','\x70','\x4e','\x3b','\x30','\x2'};
      
      /*B站描述信息*/
      static int msg_bilibili_encode(uint8_t *buffer, uint32_t *len)
      {
      	int err;
      	NFC_NDEF_TEXT_RECORD_DESC_DEF(nfc_zh_text_rec,
      					UTF_16,  // UTF16编码
      					zh_code,
      					sizeof(zh_code),
      					zh_bilibili,
      					sizeof(zh_bilibili));
      
      	/* 创建NFC NDEF消息描述 */
      	NFC_NDEF_MSG_DEF(nfc_text_msg, MAX_REC_COUNT);
      
      	/* 添加信息 */
      	err = nfc_ndef_msg_record_add(&NFC_NDEF_MSG(nfc_text_msg),
      				   &NFC_NDEF_TEXT_RECORD_DESC(nfc_zh_text_rec));
      	if (err < 0) {
      		printk("Cannot add record!\n");
      		return err;
      	}
      
      	/* 将信息编码 */
      	err = nfc_ndef_msg_encode(&NFC_NDEF_MSG(nfc_text_msg),buffer,len);
      	if (err < 0) {
      		printk("Cannot encode message!\n");
      	}
      
      	return err;
      }
       
    • 编码APP软件包信息

      • 这段代码主要是将APP的软件包信息编码

      • 其中,软件包名需要再网上进行检索,如B站的软件包名为“tv.danmaku.bili”

      • 且需要将格式转变为下面代码所示,也可以借助python语言来快速完成。

      static const uint8_t bilibili_pkg_name[] = {
      	 't', 'v', '.', 'd', 'a', 'n', 'm', 'a', 'k', 'u', '.', 'b', 'i', 'l', 'i'
          };
      
      /*B站安装包编码*/
      int app_bilibili_encode()
      {
      	int len = NDEF_MSG_BUF_SIZE;
      	int err = nfc_launchapp_msg_encode(bilibili_pkg_name,
      				       sizeof(bilibili_pkg_name),
      				       NULL,
      				       0,
      				       launch_app_msg_buf,
      				       &len);
      	if (err) {
      		printk("Cannot encode message!\n");
      	}
      
      	/* 设置NFC载荷 */
      	err = nfc_t2t_payload_set(launch_app_msg_buf, len);
      	if (err) {
      		printk("Cannot set payload!\n");
      	}
      
      	/* 开始NFC卡片模拟*/
      	err = nfc_t2t_emulation_start();
      	if (err) {
      		printk("Cannot start emulation!\n");
      	}
      }

       

    • 设置NFC回调函数

      该段代码主要用于指示当前NFC卡片是否被读取,正在被读取则LED亮,否则灭。若被读取,且当前展示的不是APP软件包信息,则切换到对应的软件包信息。

      /*NFC事件回调函数*/
      static void nfc_callback(void *context,
      			 nfc_t2t_event_t event,
      			 const uint8_t *data,
      			 size_t data_length)
      {
      	ARG_UNUSED(context);
      	ARG_UNUSED(data);
      	ARG_UNUSED(data_length);
      
      	switch (event) {
      	case NFC_T2T_EVENT_FIELD_ON:
      		printk("NFC_T2T_EVENT_FIELD_ON\r\n");
      		dk_set_led_on(NFC_FIELD_LED);          // 亮起LED1 
      		if(show_app != 1){                     // 如果不是现在展示的不是APP软件包信息
      			printk("show app%d\r\n",msg_id);
      			k_timer_stop(&my_timer);           // 关闭定时器
      			switch_app(msg_id);                // 展示APP软件包信息
      			show_app = 1;                      // 更改状态
      			timer_start();                     // 开启定时器
      		}
      		break;
      	case NFC_T2T_EVENT_FIELD_OFF:
      		printk("NFC_T2T_EVENT_FIELD_OFF\r\n");
      		dk_set_led_off(NFC_FIELD_LED);          //LED灭
      		break;
      	default:
      		break;
      	}
      }
    • 按键回调事件

      • 按键1的功能是切换到下一条APP文字介绍信息

      • 按键2的功能是开关板卡的NFC功能

      /*按键事件回调函数*/
      button_handler_t button_cb(uint32_t button_state, uint32_t has_changed)
      {
      	switch (button_state)
      	{
      		case DK_BTN1 + 1 : //下一个NFC信息卡片
      			printk("button1 next NFC card\r\n");
      			dk_set_led_on(DK_LED2);
      
      			
      			nfc_t2t_emulation_stop(); // 关闭模拟
      			msg_id ++;
      			if(msg_id > 3){
      				msg_id = 0;
      			}
      
      			uint32_t len = sizeof(ndef_msg_buf);
      			if (switch_msg(ndef_msg_buf, &len, msg_id) < 0) {
      				printk("Cannot encode message!\n");
      			}
      
      			nfc_t2t_payload_set(ndef_msg_buf, len);
      			
      			if (nfc_t2t_emulation_start() < 0) {
      				printk("Cannot start emulation!\n");
      			}
      			show_app = 0;
      			printk("update timer\r\n");
      			k_timer_stop(&my_timer);         // 关闭定时器
      			timer_start();                    // 开启定时器
      
      			break;
      
      		case DK_BTN2 + 1  : //开启或停止NFC功能
      			printk("button2  ");
      			dk_set_led_on(DK_LED2);
      
      
      			if(is_nfc_on == 0)
      			{
      				printk("open nfc\r\n");
      				is_nfc_on = 1;             // NFC已开启
      				nfc_t2t_emulation_start(); // 开启模拟
      				timer_start();             // 开启定时器
      			}
      			else
      			{
      				printk("close nfc\r\n");
      				is_nfc_on = 0;            // NFC已关闭
      				nfc_t2t_emulation_stop(); // 关闭模拟
      				k_timer_stop(&my_timer);  // 关闭定时器
      			}
      			break; 
      		default: //松开按键
      			dk_set_led_off(DK_LED2);
      			break;
      	}
      }
    • 切换APP介绍文字

      • 该函数用于切换APP介绍文字

      • 包含了四款常用的app

        • B站

        • 美团

        • 微信

        • 京东

      • 主要通过switch函数来进行一个选择

      /*更换卡片信息*/
      int switch_msg(uint8_t *buffer, uint32_t *len,int msg_id)
      {
      	printk("change NFC msg to %d\r\n",msg_id);
      	switch (msg_id)
      	{
      		case 0:
      			msg_bilibili_encode(buffer,len);
      			break;
      		case 1:
      			msg_meituan_encode(buffer,len);
      			break;
      		case 2:
      			msg_wechat_encode(buffer,len);
      			break;
      		case 3:
      			msg_jingdong_encode(buffer,len);
      			break;
      		default:
      			break;
      	}
      	return 1;
      }

       

    • 切换APP安装包

      • 该函数用于切换APP安装包

      • 主要通过switch函数来进行一个选择

      /*APP选择*/
      int switch_app(int app_id)
      {
      	k_sleep(K_SECONDS(1)); //延时1s,以免过快覆盖卡片信息。
      	nfc_t2t_emulation_stop();
      	switch (app_id)
      	{
      		case 0:
      			app_bilibili_encode();
      			printk("bilibili\r\n");
      			break;
      		case 1:
      			app_meituan_encode();
      			printk("meituan!\r\n");
      			break;
      		case 2:
      			app_wechat_encode();
      			printk("wechat!\r\n");
      			break;
      		case 3:
      			app_jingdong_encode();
      			printk("jingdong!\r\n");
      			break;
      		default:
      			int err = nfc_t2t_emulation_start();
      			if (err) {
      				printk("Cannot start emulation!\n");
      			}
      			break;
      	}
      	return 0;
      }

       

    • 定时器回调事件

      • 定时器用于周期性的切换卡片信息。

      /*定时器回调函数*/
      void my_expiry_function(struct k_timer *timer_id)
      {
      	printk("timer update\r\n");
      	nfc_t2t_emulation_stop(); // 关闭模拟
      	msg_id ++;
      	if(msg_id > 3){
      		msg_id = 0;  //只有4组数据进行循环
      	}
      
      	uint32_t len = sizeof(ndef_msg_buf);
      	if (switch_msg(ndef_msg_buf, &len, msg_id) < 0) {
      		printk("Cannot encode message!\r\n");
      	}
      
      	nfc_t2t_payload_set(ndef_msg_buf, len); 
      	
      	if (nfc_t2t_emulation_start() < 0) {
      		printk("Cannot start emulation!\r\n");
      	}
      	show_app = 0;
      }

       

    • 主程序启动

      该段代码是主程序代码,主要用于各组件的一个初始化,如LED、button与NFC.

      int main(void)
      {
      	int err;
      	size_t len = sizeof(launch_app_msg_buf);
      
      	printk("Starting NFC Launch app example\r\n");
      
      	/* 初始化LED */
      	err = dk_leds_init();
      	if (err) {
      		printk("Cannot init LEDs!\r\n");
      		goto fail;
      	}
      
      	/* 初始化按键*/
      	if (dk_buttons_init(button_cb) < 0){
      		printk("Cannot init buttons!\r\n");
      		goto fail;
      	}
      
      	/* 设置NFC */
      	err = nfc_t2t_setup(nfc_callback, NULL);
      	if (err) {
      		printk("Cannot setup NFC T2T library!\r\n");
      		goto fail;
      	}
      	printk("NFC configuration done\r\n");
      	printk("timer start\r\n");
      
      	k_timer_init(&my_timer, my_expiry_function, NULL); /*初始化定时器*/
      	timer_start(); /*开启定时器*/
      	return 0;
      
      fail:
      #if CONFIG_REBOOT
      	sys_reboot(SYS_REBOOT_COLD);
      #endif /* CONFIG_REBOOT */
      
      	return err;
      } 

       

功能展示及说明

  • 板卡会周期性的循环切换4个APP介绍文字信息,当前设置的间隔是5秒

    Fgha3zu4Gx1zF4lDgKgipuv7ykD_

  • 使用手机接触到板卡NFC天线时,会显示出APP的介绍文字,再次使用手机接触NFC天线后,将打开对应APP页面

FqZmgbgkTfkbLtwFA75Tm0s_VdaqFiCE-gzTicufaWnzcOPfHPAhAQ1E

使用按键1,可以直接切换到下一APP介绍文字

  • 从时间戳可以看到两条msg切换时,有button1的日志输出,且间隔小于5s

         FoDinzOAnjogMSWCjn0X0l23jf3U

  • 使用按键2,可以开启或关闭板卡NFC功能

    • Fuwq57uoHdobbJf7LQmGo6B3Ncfy

对本活动的心得体会

非常感谢硬禾学堂联合Digi-Key发起的Funpack第二季第六期活动,让我接触到了这一款非常优秀的开发板。它较为丰富的例程,给初次接触的我留下来深刻的印象。虽然日常生活中,我也经常使用NFC,但是第一次接触到相关开发板,给了我很多的震撼。非常感谢硬禾学堂举办这么好玩的活动,我将继续在这块多功能的开发板上进行学习,后续也会继续参加相关活动。

 

附件下载
record_launch_app.zip
团队介绍
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号