你是否想过,只需要把手机轻轻贴近一张卡片,就能自动打开音乐 App 并播放指定歌曲?本项目基于 nRF5340 + Zephyr RTOS,利用芯片自带的 NFC 功能,将一段 URL Scheme 写入 NFC 标签,实现了一键拉起网易云音乐并播放固定歌曲的效果。
在这个过程中,不仅涉及 NFC NDEF 消息的构建、URI 标签的编码,还完整体验了 Zephyr 工程结构与 Nordic NFC 库的使用方法。本文将从原理、代码修改到完整实现,带你一步步完成一张真正“可用”的 NFC 音乐播放卡。
项目简介
NFC音乐播放卡是一个基于Near Field Communication(NFC)技术的项目,旨在通过使用NFC标签,使用户能够轻松地通过NFC功能启动手机上的网易云音乐并播放指定的音乐。
项目特点
1.NFC标签触发播放: 项目利用NFC标签,用户只需将手机靠近NFC标签,即可拉起网易云音乐App,并播放音乐。
2.自定义NFC标签: 用户可以自定义NFC标签上的信息,包括要播放的音乐。
3.跨平台兼容性: 该项目支持多个平台,包括Android和iOS。用户可以在支持NFC功能的智能手机上使用该功能。
NFC音乐播放器项目旨在为用户提供一种简便的方式,通过NFC标签触发并播放他们最喜爱的音乐,提升音乐欣赏体验。
硬件介绍
nRF7002 DK是用于nRF7002 Wi-Fi 6协同IC的开发套件,在单一电路板上包含了启动开发工作所需要的一切。这款DK带有一个nRF5340多协议系统级芯片(SoC),用作nRF7002的主处理器。
nRF5340主芯片采用了双核架构,包括一个Arm Cortex-M33应用核心和一个Arm Cortex-M33网络核心。这两个核心可以分别运行不同的应用程序,或者协同工作以提高性能。这款SoC支持多种通信协议,包括蓝牙、Thread和Zigbee等,使其非常适合物联网和无线通信应用。
该芯片集成了丰富的外设,包括GPIO引脚、SPI、I2C、UART等,以支持各种外部设备的连接和控制。nRF5340芯片具有内置的 NFC 功能,该功能使其能够支持短距离无线通信和数据交换。芯片可以模拟NFC卡,使其可以被其他NFC设备读取,用于实现诸如门禁卡、交通卡和身份认证卡等应用。
工作流程图

图1:NFC音乐播放卡工作流程图,展示了手机通过NFC与开发板交互并最终拉起App的全过程。
NFC拉起手机App的原理解析
通过搜索引擎,可以找到网易云音乐通过NFC拉起的规则,具体支持的功能如下:

图2:网易云音乐App支持的URL Scheme格式,用于打开特定专辑、歌单、歌曲或歌手。
如果我们需要唤起网易云音乐App并播放歌曲《アイドル》,就需要将NFC标签里的URI信息修改为 orpheus://song/2034742057。
那么,为什么手机扫描NFC标签获取到这一段URI信息就能唤起App播放音乐呢?这就要提到URL Scheme了。简单来说,URL Scheme是一种在操作系统中用于识别并启动相关应用程序的链接协议。它是一种自定义协议,通常与特定应用程序或服务相关联,允许您通过特定的URL来打开相关的应用程序。这对于实现深层链接和跨应用程序交互非常有用。
orpheus://song/2034742057 这段信息就是告诉操作系统,需要调用 orpheus 这个应用(通常由App向操作系统注册),并打开 song 页面,播放ID为 2034742057 的歌曲。
所以,URL Scheme 是一种特殊的 URL,它不是用于访问 Web 页面的,而是用于唤起移动应用程序并传递参数。
主要代码实现
本工程使用了 nrf/samples/nfc/record_launch_app 项目作为模板项目,将原有的App拉起功能修改成URI标签功能,从而实现了一键拉起网易云音乐和播放固定歌曲。
主要修改内容如下:
- 调整头文件内容:引入
nfc/ndef/uri_msg.h 头文件,替换掉原有的 nfc/ndef/launchapp_msg.h。
- 修改URI链接:将 universal_link 数组的内容修改为上文提到的
orpheus://song/2034742057,并删除原有的 android_pkg_name 定义。
- 修改核心编码函数:将
nfc_launchapp_msg_encode 函数调用修改为 nfc_ndef_uri_msg_encode,并调整对应的参数。
以下是详细的代码修改diff文件:
@@ -8,23 +8,15 @@
#include <zephyr/sys/reboot.h>
#include <nfc_t2t_lib.h>
-#include <nfc/ndef/launchapp_msg.h>
+#include <nfc/ndef/uri_msg.h>
#include <dk_buttons_and_leds.h>
#define NDEF_MSG_BUF_SIZE 256
#define NFC_FIELD_LED DK_LED1
-/** .. include_startingpoint_pkg_def_launchapp_rst */
-/* Package: no.nordicsemi.android.nrftoolbox */
-static const uint8_t android_pkg_name[] = {
- ‘n‘, ‘o‘, ‘.‘, ‘n‘, ‘o‘, ‘r‘, ‘d‘, ‘i‘, ‘c‘, ‘s‘, ‘e‘, ‘m‘, ‘i‘, ‘.‘, ‘a‘, ‘n‘, ‘d‘, ‘r‘,
- ‘o‘, ‘i‘, ‘d‘, ‘.‘, ‘n‘, ‘r‘, ‘f‘, ‘t‘, ‘o‘, ‘o‘, ‘l‘, ‘b‘, ‘o‘, ‘x‘ };
-
-/* URI nrf-toolbox://main/ */
static const uint8_t universal_link[] = {
- ‘n‘, ‘r‘, ‘f‘, ‘-‘, ‘t‘, ‘o‘, ‘o‘, ‘l‘, ‘b‘, ‘o‘, ‘x‘, ‘:‘, ‘/‘, ‘/‘, ‘m‘, ‘a‘, ‘i‘, ‘n‘,
- ‘/‘};
+ “orpheus://song/2034742057“};
/** .. include_endpoint_pkg_def_launchapp_rst */
/* Buffer used to hold an NFC NDEF message. */
@@ -74,10 +66,9 @@ int main(void)
}
/* Encode launch app data */
- err = nfc_launchapp_msg_encode(android_pkg_name,
- sizeof(android_pkg_name),
+ err = nfc_ndef_uri_msg_encode(NFC_URI_NONE,
universal_link,
- sizeof(universal_link),
+ sizeof(universal_link) - 1,
ndef_msg_buf,
&len);
if (err) {
4. 配置项目:
使用 menuconfig 工具,启用 CONFIG_NFC_NDEF_URI_MSG 配置选项,如下图所示:

图3:在Zephyr项目配置中,启用NFC NDEF URI消息生成库。
保存配置后,直接使用 west build 命令编译即可,编译完成后烧录到开发板就可以使用了。

图4:在终端中使用west工具完成项目的构建与链接过程。
完整代码
以下是修改完成后的主程序代码:
/*
* Copyright (c) 2021 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/
#include <zephyr/kernel.h>
#include <zephyr/sys/reboot.h>
#include <nfc_t2t_lib.h>
#include <nfc/ndef/uri_msg.h>
#include <dk_buttons_and_leds.h>
#define NDEF_MSG_BUF_SIZE 256
#define NFC_FIELD_LED DK_LED1
/* URI nrf-toolbox://main/ */
static const uint8_t universal_link[] = “orpheus://song/2034742057“;
/** .. include_endpoint_pkg_def_launchapp_rst */
/* Buffer used to hold an NFC NDEF message. */
static uint8_t ndef_msg_buf[NDEF_MSG_BUF_SIZE];
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:
dk_set_led_on(NFC_FIELD_LED);
break;
case NFC_T2T_EVENT_FIELD_OFF:
dk_set_led_off(NFC_FIELD_LED);
break;
default:
break;
}
}
int main(void)
{
int err;
size_t len = sizeof(ndef_msg_buf);
printk(“Starting NFC Launch app example\n“);
/* Configure LED-pins as outputs */
err = dk_leds_init();
if (err) {
printk(“Cannot init LEDs!\n“);
goto fail;
}
/* Set up NFC */
err = nfc_t2t_setup(nfc_callback, NULL);
if (err) {
printk(“Cannot setup NFC T2T library!\n“);
goto fail;
}
/* Encode launch app data */
err = nfc_ndef_uri_msg_encode(NFC_URI_NONE,
universal_link,
sizeof(universal_link) - 1,
ndef_msg_buf,
&len);
if (err) {
printk(“Cannot encode message!\n“);
goto fail;
}
/* Set created message as the NFC payload */
err = nfc_t2t_payload_set(ndef_msg_buf, len);
if (err) {
printk(“Cannot set payload!\n“);
goto fail;
}
/* Start sensing NFC field */
err = nfc_t2t_emulation_start();
if (err) {
printk(“Cannot start emulation!\n“);
goto fail;
}
printk(“NFC configuration done\n“);
return 0;
fail:
#if CONFIG_REBOOT
sys_reboot(SYS_REBOOT_COLD);
#endif /* CONFIG_REBOOT */
return err;
}
心得体会
通过本次项目实践,我深入学习了Zephyr RTOS的项目结构和常见用法,也掌握了 NFC近场通讯 的基本原理及其在 嵌入式系统 中的调用方式。借助NFC开发,我不仅提升了在无线通信领域的技术能力,还更深刻地体会到了这项技术在改善用户体验和推动物联网应用发展方面的巨大潜力。期待未来能在云栈社区与更多开发者继续探索这个令人兴奋的技术领域。

图5:项目完成!