【鸿蒙开发】Hi3861学习笔记- NFC

00. 目录

01. NFC简介

什么是NFC

NFC(Near Field Communication,近场通信)是一种基于无线射频识别(RFID)的短距离通信技术,允许电子设备在10厘米左右的范围内进行非接触式数据传输。其特点是快速配对、低功耗和高安全性,常用于移动支付、身份识别等场景。

工作原理

  • 频率与距离:工作在13.56MHz频段,传输距离通常小于10厘米,需设备贴近或轻触。
  • 工作模式
    • 主动模式:双方设备均有电源,交替发送信号(如文件传输)。
    • 被动模式:一方无电源(如NFC标签),由主动设备供电读取数据(如扫描智能海报)。
    • 卡模拟模式:设备模拟成IC卡(如手机变公交卡)。

核心特点

  • 便捷性:无需手动配对,触碰即连接。
  • 低功耗:适合小型设备(如智能手表)。
  • 高兼容性:兼容传统RFID标准(如公交卡、门禁)。
  • 安全性:短距离降低窃听风险,支持加密通信(如SE安全芯片)。

应用场景

  • 移动支付:Apple Pay、支付宝等触碰支付。
  • 交通出行:手机NFC模拟公交卡、地铁闸机刷卡。
  • 智能家居:触碰连接音箱、快速配对蓝牙设备。
  • 信息交换:轻触手机传输联系人、照片(Android Beam)。
  • 身份识别:电子护照、企业门禁卡。
  • 营销互动:扫描NFC标签获取产品信息或优惠券。

安全性

  • 短距离防护:需极近距离通信,难以远程拦截。
  • 硬件加密:支付类应用依赖SE安全芯片存储敏感数据。
  • 风险提示:警惕恶意NFC标签诱导连接(如强制打开钓鱼网站)。

与其他技术对比

  • VS蓝牙:NFC连接更快(0.1秒)、无需配对,但传输速度慢(424kbps vs 蓝牙5.0的2Mbps),适合小数据量场景。
  • VS RFID:NFC是RFID的子集,专为双向交互设计,而RFID多为单向读取(如仓储物流)。

02. NT3H1101

NT3H1101W0FHKH(通常简称为 NT3H1101)是一款由 NXP(恩智浦)半导体公司生产的射频卡芯片,该芯片属于 NTAG I²C 系列,特

别适用于需要 NFC(近场通信)功能的各种应用场景。

在这里插入图片描述

03. 硬件设计

在这里插入图片描述

从上图可知,板载 NFC 均连接到指定 IO。

04. 软件设计

bsp_nfc.h

#ifndef BSP_NFC_H
#define BSP_NFC_H

#include "cmsis_os2.h"
#include "hi_io.h"
#include "hi_gpio.h"



#define NDEF_HEADER_SIZE 0x2 // NDEF协议的头部大小

#define NDEF_PROTOCOL_HEADER_OFFSET 0           // NDEF协议头(固定)
#define NDEF_PROTOCOL_LENGTH_OFFSET 1           // NDEF协议数据的总长度位
#define NDEF_PROTOCOL_MEG_CONFIG_OFFSET 2       // 标签的控制字节位
#define NDEF_PROTOCOL_DATA_TYPE_LENGTH_OFFSET 3 // 标签数据类型的长度位
#define NDEF_PROTOCOL_DATA_LENGTH_OFFSET 4      // 标签的数据长度位
#define NDEF_PROTOCOL_DATA_TYPE_OFFSET 6        // 标签的数据类型位
#define NDEF_PROTOCOL_VALID_DATA_OFFSET 20      // 有效数据位


//函数声明
uint32_t get_NDEFDataPackage(uint8_t *dataBuff, const uint16_t dataBuff_MaxSize);
uint32_t nfc_init(void);

#endif

bsp_nfc.c

#include "bsp_nfc.h"
#include "hi_errno.h"
#include "hi_i2c.h"
#include "NT3H.h"
#include <stdlib.h>
#include <string.h>


/**
 * @brief  从Page页中组成NDEF协议的包裹
 * @note
 * @param  *dataBuff: 最终的内容
 * @param  dataBuff_MaxSize: 存储缓冲区的长度
 * @retval
 */
uint32_t get_NDEFDataPackage(uint8_t *dataBuff, const uint16_t dataBuff_MaxSize)
{
    if (dataBuff == NULL || dataBuff_MaxSize <= 0) 
    {
        printf("dataBuff==NULL or dataBuff_MaxSize<=0\r\n");
        return HI_ERR_FAILURE;
    }

    uint8_t userMemoryPageNum = 0; // 用户的数据操作页数

    // 算出要取多少页
    if (dataBuff_MaxSize <= NFC_PAGE_SIZE) 
    {
        userMemoryPageNum = 1; // 1页
    } 
    else 
    {
        // 需要访问多少页
        userMemoryPageNum = (dataBuff_MaxSize / NFC_PAGE_SIZE) + \
                            ((dataBuff_MaxSize % NFC_PAGE_SIZE) >= 0 ? 1 : 0);
    }

    // 内存拷贝
    uint8_t *p_buff = (uint8_t *)malloc(userMemoryPageNum * NFC_PAGE_SIZE);
    if (p_buff == NULL) 
    {
        printf("p_buff == NULL.\r\n");
        return HI_ERR_FAILURE;
    }

    // 读取数据
    for (int i = 0; i < userMemoryPageNum; i++) 
    {
        if (NT3HReadUserData(i) == true) 
        {
            memcpy_s(p_buff + i * NFC_PAGE_SIZE, userMemoryPageNum * NFC_PAGE_SIZE,
                     nfcPageBuffer, NFC_PAGE_SIZE);
        }
    }

    memcpy_s(dataBuff, dataBuff_MaxSize, p_buff, dataBuff_MaxSize);

    free(p_buff);
    p_buff = NULL;

    return HI_ERR_SUCCESS;
}

//NFC初始化
uint32_t nfc_init(void)
{
    uint32_t result;

    // gpio_9 复用为 I2C_SCL
    hi_io_set_pull(HI_IO_NAME_GPIO_9, HI_IO_PULL_UP);
    hi_io_set_func(HI_IO_NAME_GPIO_9, HI_IO_FUNC_GPIO_9_I2C0_SCL);
    // gpio_10 复用为 I2C_SDA
    hi_io_set_pull(HI_IO_NAME_GPIO_10, HI_IO_PULL_UP);
    hi_io_set_func(HI_IO_NAME_GPIO_10, HI_IO_FUNC_GPIO_10_I2C0_SDA);

    result = hi_i2c_init(HI_I2C_IDX_0, I2C_RATE_DEFAULT);
    if (result != HI_ERR_SUCCESS) 
    {
        printf("I2C nfc Init status is 0x%x!!!\r\n", result);
        return result;
    }
    printf("I2C nfc Init is succeeded!!!\r\n");

    return true;
}

template.c

#include <stdio.h>
#include <unistd.h>

#include "ohos_init.h"
#include "cmsis_os2.h"

#include "bsp_led.h"
#include "bsp_nfc.h"


//LED任务
osThreadId_t LED_Task_ID; //led任务ID

void LED_Task(void)
{
    led_init();//LED初始化

    while (1) 
    {
        LED(1); 
        usleep(200*1000); //200ms
        LED(0);
        usleep(200*1000); //200ms
    }
}
//LED任务创建
void led_task_create(void)
{
    osThreadAttr_t taskOptions;
    taskOptions.name = "LEDTask";            // 任务的名字
    taskOptions.attr_bits = 0;               // 属性位
    taskOptions.cb_mem = NULL;               // 堆空间地址
    taskOptions.cb_size = 0;                 // 堆空间大小
    taskOptions.stack_mem = NULL;            // 栈空间地址
    taskOptions.stack_size = 1024;           // 栈空间大小 单位:字节
    taskOptions.priority = osPriorityNormal; // 任务的优先级

    LED_Task_ID = osThreadNew((osThreadFunc_t)LED_Task, NULL, &taskOptions); // 创建任务1
    if (LED_Task_ID != NULL)
    {
        printf("ID = %d, Create LED_Task_ID is OK!\n", LED_Task_ID);
    }
}

//控制任务
osThreadId_t NFC_Task_ID; //任务ID

void NFC_Task(void)
{
    uint8_t ret, num = 0;
    uint8_t ndefLen = 0;      // ndef包的长度
    uint8_t ndef_Header = 0;  // ndef消息开始标志位-用不到
    uint32_t result_code = 0; // 函数的返回值
    uint8_t i=0;
    
    nfc_init();

    // 读整个数据的包头部分,读出整个数据的长度
    if (result_code = NT3HReadHeaderNfc(&ndefLen, &ndef_Header) != true) 
    {
        printf("NT3HReadHeaderNfc is failed. result_code = %d\r\n", result_code);
        return;
    }

    ndefLen += NDEF_HEADER_SIZE; // 加上头部字节
    if (ndefLen <= NDEF_HEADER_SIZE) 
    {
        printf("ndefLen <= 2\r\n");
        return;
    }
    uint8_t *ndefBuff = (uint8_t *)malloc(ndefLen + 1);
    if (ndefBuff == NULL) 
    {
        printf("ndefBuff malloc is Falied!\r\n");
        return;
    }

    if (result_code = get_NDEFDataPackage(ndefBuff, ndefLen) != HI_ERR_SUCCESS) 
    {
        printf("get_NDEFDataPackage is failed. result_code = %d\r\n", result_code);
        return;
    }

    printf("start print ndefBuff.\r\n");
    for (i = 0; i < ndefLen; i++) 
    {
        printf("0x%x ", ndefBuff[i]);
    }
    
    while (1) 
    {
        usleep(10*1000); //10ms
    }
}
//任务创建
void nfc_task_create(void)
{
    osThreadAttr_t taskOptions;
    taskOptions.name = "nfcTask";       // 任务的名字
    taskOptions.attr_bits = 0;               // 属性位
    taskOptions.cb_mem = NULL;               // 堆空间地址
    taskOptions.cb_size = 0;                 // 堆空间大小
    taskOptions.stack_mem = NULL;            // 栈空间地址
    taskOptions.stack_size = 1024*5;           // 栈空间大小 单位:字节
    taskOptions.priority = osPriorityNormal; // 任务的优先级

    NFC_Task_ID = osThreadNew((osThreadFunc_t)NFC_Task, NULL, &taskOptions); // 创建任务
    if (NFC_Task_ID != NULL)
    {
        printf("ID = %d, NFC_Task_ID Create OK!\n", NFC_Task_ID);
    }
}

/**
 * @description: 初始化并创建任务
 * @param {*}
 * @return {*}
 */
static void template_demo(void)
{
    printf("-Hi3861开发板--NFC实验\r\n");
    led_task_create();
    nfc_task_create();//任务创建
}
SYS_RUN(template_demo);

05. 实验现象

实验现象:通过手机 NFC 标签助手 APP 向 NFC 标签中写入数据,并且读取 NFC 标签中的数据,通过串口助手输出。

06. 附录

imx6ul应用开发资料。卷序列号为 A899-5E01 H:. │ FCU1101嵌入式控制单元支持功能项列表-2018.10.18.xlsx │ 文件夹目录.txt │ 文件夹目录名批列出.bat │ ├─Linux │ ├─应用 │ │ │ 系统常用命令.pdf │ │ │ │ │ ├─485 │ │ │ 485-test │ │ │ 485-test.c │ │ │ │ │ ├─lora-EC32-TTL-100 │ │ │ │ E32_Demo.zip │ │ │ │ E32_Usermanual_CN_1.40.pdf │ │ │ │ lora.pdf │ │ │ │ RF_Setting.Form1.resources │ │ │ │ RF_Setting.Properties.Resources.resources │ │ │ │ RF_Setting3.47.exe │ │ │ │ RF_Setting3.47.zip │ │ │ │ SX1278无线模块LoRa扩频技术文档(433M亿佰特E32-TTL-100) (1).pdf │ │ │ │ │ │ │ └─Sscom32 │ │ │ sscom.ini │ │ │ sscom32.exe │ │ │ 注意事项.txt │ │ │ │ │ ├─modbus │ │ │ │ libmodbus-3.1.2.tar.gz │ │ │ │ ul-modbus测试.txt │ │ │ │ │ │ │ ├─库文件 │ │ │ │ m3.tar.bz2 │ │ │ │ │ │ │ └─测试程序 │ │ │ unit-test-client │ │ │ unit-test-server │ │ │ │ │ ├─mosquitto │ │ │ │ mosquitto-1.5.tar.gz │ │ │ │ mqtt协议移植总结.pdf │ │ │ │ openssl-1.0.2h.tar.gz │ │ │ │ │ │ │ └─移植到开发板上 │ │ │ install_mosquitto.tar.bz2 │ │ │ install_openssl.tar.bz2 │ │ │ │ │ ├─socket │ │ │ │ build.sh │ │ │ │ eth0_server.c │ │ │ │ eth1_server.c │ │ │ │ Makefile │ │ │ │ Makefile.arm │ │ │ │ socket_client.c │ │ │ │ socket测试.pdf │ │ │ │ │ │ │ ├─bin │ │ │ │ └─arm │ │ │ │ client │ │ │ │ client.sh │ │ │ │ server.sh │ │ │ │ server1 │ │ │ │ server2 │ │ │ │ │ │ │ └─源码 │ │ │ build.sh │ │ │ eth0_server.c │ │ │ eth1_server.c │ │ │ Makefile │ │ │ Makefile.arm │ │ │ socket_client.c │ │ │ │ │ ├─tcpdump │ │ │ │ libpcap-1.8.1.tar.gz │ │ │ │ tcpdump-4.9.2.tar.gz │ │ │ │ │ │ │ └─移植到开发板 │ │ │ tcpdump.tar.bz2 │ │ │ │ │ ├─TFTP与NFS服务器搭建 │ │ │ TFTP与NFS服务器搭
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沧海一笑-dj

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值