赞
踩
NT3H1x01W0FHK NFC芯片,是一款简单,低成本的NFC标签。
特点:
- 工作频率:13.56MHz;
- NT3H1101(NT3H1201)支持接触式和非接触式接口,IIC从机接口支持标准模式(100KHz)和高速模式(高达400KHz);
- 用户读写区:1904 bytes;
- SRAM:64 bytes;
- NT3H1101(NT3H1201) NFC标签可直接作为标准IIC EEPROM使用;
- 外部连接板载NFC射频天线。
NT3H1201芯片与微控制器遵循I2C通信协议,NFC协议为2型通信标准。如图所示,芯片通过PCB上射频天线从接触的有源NFC设备上获取能量,并完成数据交互。交互的数据被写入片上EEPROM用以掉电后的再次读写。另一边,经过芯片转换,NFC获得的能量被供给到外部设备,同时芯片通过I2C与板载外部设备(微控制器)通信。可以看出,NTAG芯片在过程中起到了触碰信息转移和触碰能量传递的中间介质。
POR
)后,NTAG I2C切换到空闲状态(IDLE
)。只有在这种状态下才会从NFC设备接收请求命令(REQA
)或唤醒命令(WUPA
),任何其他在这种状态下接收到的数据被解释为错误。READY 1
),NFC设备通过防碰撞选择第一层的防碰撞命令(ANTICOLLISION
)或选择命令(SELECT
)解析出UID的第一部分(3个字节)。在执行成功防碰撞选择第一层的选择命令(SELECT
)后,进入就绪状态2。READY 2
),NTAG I2C支持NFC设备通过防碰撞选择第二层的防碰撞命令(ANTICOLLISION
)解析出UID的第二部分(4个字节)。在执行成功防碰撞选择第二层的选择命令(SELECT
)后,进入激活状态。ACTIVE
)下操作。如读取16Byte操作(READ
)、快速读取操作(FAST_READ
)、写入操作(WRITE
)、扇区选择操作(SECTOR_SELECT
)、获取版本操作(GET_VERSION
)。取决于其先前的状态,NTAG I2C返回到空闲状态(IDLE
)或停止状态(HALT
)。HALT
)设置为暂停状态。在里面在防碰撞阶段,此状态有助于NFC设备区分已处理的标签和待选择的标签。NTAG I2C只能在执行唤醒命令(WUPA
)时退出此状态。NDEF(NFC data exchange format) 是在LLCP链路被激活时使用到。
NDEF spec的主要目的有:
使用场景:
上层应用产生由一个或多个文件生成的NDEF信息,该消息交由底层LLC层传送给对方,对方可以接受后直接处理或作为中间阶段写入Tag中。当其他设备接近该tag时,会读到该tag中的内容,并把读到的NDEF消息传给上层应用分析和处理。
NDEF组成:
RTD(NFC Record Type Definition)
几种常见类型:
NDEF完整封包格式如下:
如果SR为1时,对应的封包格式如下:
其中各标记说明如下:
关于TNF,具体值信息如下:
NDEF数据: D1 01 0F 54 02 65 6E 68 65 6C 6C 6F 2C 77 6F 72 6C 64 21
解析结果: hello,world!
NDEF数据: D1 01 0A 55 01 62 61 69 64 75 2E 63 6F 6D
解析结果: http://www.baidu.com
功能口 | 引脚 |
---|---|
SCL | GPIO0 |
SDA | GPIO1 |
LA&LB | 线圈 |
VSS | GND |
VCC | 3.3V |
读和写操作总要传输16个字节数据
对于读操作,在启动条件之后,总线主机发送NTAG I2C从机地址代码(SA-7位),并将读/写位(RW)重置为0。NTAG I2C从机确认这一点(A),并等待一个地址字节(MEMA),该字节应与以下存储器块(SRAM或EEPROM)的想要读的地址相对应。NTAG I2C从机通过确认响应有效地址字节(A)后总线主机可以发出停止条件。
对于写操作,在启动条件之后,总线主机发送NTAG I2C从机地址代码(SA-7位),并将读/写位(RW)重置为0。NTAG I2C从机确认这一点(A),并等待一个地址字节(MEMA),该字节应与以下存储器块(SRAM或EEPROM)的想要写的地址相对应。NTAG I2C使用确认(A),在写操作的情况下,总线主机启动传输每16个字节(D0…D15),该字节应使用在每个NTAG I²C从机确认字节(A)后。在收到NTAG I²C从机的最后一个字节确认之后,总线主机发出停止条件。
只能通过读写操作访问内存地址对应的EEPROM或SRAM。
对于NTAG I²C 1k为00h至3Ah或F8h至FBh
对于NTAG I²C 2k为00h至7Ah或F8h至FBh
编译时在业务BUILD.gn中包含路径
static_library("i2c_example") { sources = [ "nfc/NT3H.c", "nfc/nfc.c", "nfc/ndef/rtd/nfcForum.c", "nfc/ndef/rtd/rtdText.c", "nfc/ndef/rtd/rtdUri.c", "nfc/ndef/ndef.c", "i2c_example.c" ] cflags = [ "-Wno-unused-variable" ] cflags += [ "-Wno-unused-but-set-variable" ] cflags += [ "-Wno-unused-parameter" ] include_dirs = [ "//utils/native/lite/include", "//kernel/liteos_m/components/cmsis/2.0", "//base/iot_hardware/interfaces/kits/wifiiot_lite", "nfc/ndef", "nfc/ndef/rtd/", "nfc" ] }
注意这里加入以下三条语句,防止有些函数中的参数没有用到,编译报错!!!
cflags = [ "-Wno-unused-variable" ]
cflags += [ "-Wno-unused-but-set-variable" ]
cflags += [ "-Wno-unused-parameter" ]
该文件相当于 main.c 文件,主要为初始化I2C和向NFC芯片写入数据。
#include <stdio.h> #include <string.h> #include <unistd.h> #include "ohos_init.h" #include "cmsis_os2.h" #include "wifiiot_errno.h" #include "wifiiot_gpio.h" #include "wifiiot_gpio_ex.h" #include "wifiiot_i2c.h" #include "wifiiot_i2c_ex.h" #include "nfc.h" #define I2C_TASK_STACK_SIZE 1024 * 8 #define I2C_TASK_PRIO 25 #define TEXT "Welcome to BearPi-HM_Nano!" #define WEB "harmonyos.com" static void I2CTask(void) { uint8_t ret; GpioInit(); //GPIO_0复用为I2C1_SDA IoSetFunc(WIFI_IOT_IO_NAME_GPIO_0, WIFI_IOT_IO_FUNC_GPIO_0_I2C1_SDA); //GPIO_1复用为I2C1_SCL IoSetFunc(WIFI_IOT_IO_NAME_GPIO_1, WIFI_IOT_IO_FUNC_GPIO_1_I2C1_SCL); //baudrate: 400kbps I2cInit(WIFI_IOT_I2C_IDX_1, 400000); I2cSetBaudrate(WIFI_IOT_I2C_IDX_1, 400000); printf("I2C Test Start\n"); ret = storeText(NDEFFirstPos, (uint8_t *)TEXT); if (ret != 1) { printf("NFC Write Data Falied :%d ", ret); } ret = storeUrihttp(NDEFLastPos, (uint8_t *)WEB); if (ret != 1) { printf("NFC Write Data Falied :%d ", ret); } while (1) { printf("=======================================\r\n"); printf("***********I2C_NFC_example**********\r\n"); printf("=======================================\r\n"); printf("Please use the mobile phone with NFC function close to the development board!\r\n"); usleep(1000000); } } static void I2CExampleEntry(void) { osThreadAttr_t attr; attr.name = "I2CTask"; attr.attr_bits = 0U; attr.cb_mem = NULL; attr.cb_size = 0U; attr.stack_mem = NULL; attr.stack_size = I2C_TASK_STACK_SIZE; attr.priority = I2C_TASK_PRIO; if (osThreadNew((osThreadFunc_t)I2CTask, NULL, &attr) == NULL) { printf("Falied to create I2CTask!\n"); } } APP_FEATURE_INIT(I2CExampleEntry);
这部分代码为I2C初始化的代码,首先用 IoSetFunc()
函数将GPIO_0复用为I2C1_SDA,GPIO_1复用为I2C1_SCL。然后调用 I2cInit()
函数初始化I2C1端口,最后使用 I2cSetBaudrate()
函数设置I2C1的频率为400kbps。
IoSetFunc(WIFI_IOT_IO_NAME_GPIO_0, WIFI_IOT_IO_FUNC_GPIO_0_I2C1_SDA); // GPIO_0复用为I2C1_SDA
IoSetFunc(WIFI_IOT_IO_NAME_GPIO_1, WIFI_IOT_IO_FUNC_GPIO_1_I2C1_SCL); // GPIO_1复用为I2C1_SCL
I2cInit(WIFI_IOT_I2C_IDX_1, 400000); /* baudrate: 400kbps */
I2cSetBaudrate(WIFI_IOT_I2C_IDX_1, 400000);
这部分的代码是向NFC芯片写入数据,但需要写入2个记录时,第2个记录的位置需要用 NDEFLastPos
来定义;当需要写入3个记录时,第2个和第3个记录的位置分别需要用 NDEFMiddlePos
和 NDEFLastPos
来定义。
ret=storeText(NDEFFirstPos, (uint8_t *)TEXT);
if(ret != 1)
{
printf("NFC Write Data Falied :%d ",ret);
}
ret=storeUrihttp(NDEFLastPos, (uint8_t *)WEB);
if(ret != 1)
{
printf("NFC Write Data Falied :%d ",ret);
}
storeUrihttp()
和 storeText()
在 nfc.c
中实现。
#ifndef _NFC_H_ #define _NFC_H_ #include "NT3H.h" /* * The function write in the NT3H a new URI Rtd on the required position * * param: * position: where add the record * http: the address to write * */ bool storeUrihttp(RecordPosEnu position, uint8_t *http); /* * The function write in the NT3H a new Text Rtd on the required position * * param: * position: where add the record * text: the text to write * */ bool storeText(RecordPosEnu position, uint8_t *text); #endif /* NFC_H_ */
storeUrihttp()
和 storeText()
两个函数首先按照 rtdText.h
和 rtdUri.h
中 RTD 协议进行处理。然后与 ndef.h
中 NT3HwriteRecord()
进行记录写入。
#include <stdbool.h> #include "rtdText.h" #include "rtdUri.h" #include "ndef.h" #include "nfc.h" bool storeUrihttp(RecordPosEnu position, uint8_t *http){ NDEFDataStr data; prepareUrihttp(&data, position, http); return NT3HwriteRecord( &data ); } bool storeText(RecordPosEnu position, uint8_t *text){ NDEFDataStr data; prepareText(&data, position, text); return NT3HwriteRecord( &data ); }
#ifndef NFCFORUM_H_ #define NFCFORUM_H_ #include <stdbool.h> #include "rtdTypes.h" #include "NT3H.h" #define NDEF_START_BYTE 0x03 #define NDEF_END_BYTE 0xFE #define NTAG_ERASED 0xD0 typedef struct { uint8_t startByte; uint8_t payloadLength; }NDEFHeaderStr; #define BIT_MB (1<<7) #define BIT_ME (1<<6) #define BIT_CF (1<<5) #define BIT_SR (1<<4) #define BIT_IL (1<<3) #define BIT_TNF (1<<0) #define MASK_MB 0x80 #define MASK_ME 0x40 #define MASK_CF 0x20 #define MASK_SR 0x10 #define MASK_IL 0x08 #define MASK_TNF 0x07 typedef struct { uint8_t header; uint8_t typeLength; uint8_t payloadLength; RTDTypeStr type; }NDEFRecordStr; uint8_t composeRtdText(const NDEFDataStr *ndef, NDEFRecordStr *ndefRecord, uint8_t *I2CMsg); uint8_t composeRtdUri(const NDEFDataStr *ndef, NDEFRecordStr *ndefRecord, uint8_t *I2CMsg); void composeNDEFMBME(bool isFirstRecord, bool isLastRecord, NDEFRecordStr *ndefRecord); #endif /* NFCFORUM.H_H_ */
#include "nfcForum.h" #include <string.h> static void rtdHeader(uint8_t type, NDEFRecordStr *ndefRecord, uint8_t *I2CMsg) { ndefRecord->header |= 1; ndefRecord->header |= BIT_SR; I2CMsg[0] = ndefRecord->header; ndefRecord->typeLength = 1; I2CMsg[1] = ndefRecord->typeLength; ndefRecord->type.typeCode=type; I2CMsg[3] = ndefRecord->type.typeCode; } uint8_t composeRtdText(const NDEFDataStr *ndef, NDEFRecordStr *ndefRecord, uint8_t *I2CMsg) { uint8_t retLen; rtdHeader(RTD_TEXT, ndefRecord, I2CMsg); uint8_t payLoadLen = addRtdText(&ndefRecord->type.typePayload.text); memcpy(&I2CMsg[4], &ndefRecord->type.typePayload.text, payLoadLen); ndefRecord->payloadLength = ndef->rtdPayloadlength+payLoadLen; // added the typePayload I2CMsg[2]=ndefRecord->payloadLength; retLen = 3 + /*sizeof(ndefRecord->header) + sizeof(ndefRecord->typeLength) + sizeof(ndefRecord->payloadLength) +*/ 3 + //sizeof(RTDTextTypeStr)-sizeof(TextExtraDataStr) 1 /*sizeof(ndefRecord->type.typeCode)*/; return retLen; } uint8_t composeRtdUri(const NDEFDataStr *ndef, NDEFRecordStr *ndefRecord, uint8_t *I2CMsg) { rtdHeader(RTD_URI, ndefRecord, I2CMsg); uint8_t payLoadLen = addRtdUriRecord(ndef, &ndefRecord->type.typePayload.uri); memcpy(&I2CMsg[4], &ndefRecord->type.typePayload.uri, payLoadLen); ndefRecord->payloadLength = ndef->rtdPayloadlength+payLoadLen; // added the typePayload I2CMsg[2]=ndefRecord->payloadLength; return 5; /* retLen = sizeof(ndefRecord->header) + sizeof(ndefRecord->typeLength) + sizeof(ndefRecord->payloadLength) + sizeof(1) + //ndefRecord->type.typePayload.uri.type sizeof(ndefRecord->type.typeCode); */ } void composeNDEFMBME(bool isFirstRecord, bool isLastRecord, NDEFRecordStr *ndefRecord) { if (isFirstRecord) ndefRecord->header |= BIT_MB; else ndefRecord->header &= ~MASK_MB; if (isLastRecord) ndefRecord->header |= BIT_ME; else ndefRecord->header &= ~MASK_ME; }
#ifndef RTDTEXT_H_ #define RTDTEXT_H_ #include "NT3H.h" #define BIT_STATUS (1<<7) #define BIT_RFU (1<<6) #define MASK_STATUS 0x80 #define MASK_RFU 0x40 #define MASK_IANA 0b00111111 typedef struct { char *body; uint8_t bodyLength; }RtdTextUserPayload; typedef struct { uint8_t status; uint8_t language[2]; RtdTextUserPayload rtdPayload; }RtdTextTypeStr; uint8_t addRtdText(RtdTextTypeStr *typeStr); void prepareText(NDEFDataStr *data, RecordPosEnu position, uint8_t *text); #endif /* NDEFTEXT_H_ */
#include "rtdText.h" #include "rtdTypes.h" #include <string.h> uint8_t addRtdText(RtdTextTypeStr *typeStr) { // return addNDEFTextPayload(bodyLength, ndefRecord); typeStr->status=0x2; typeStr->language[0]='e'; typeStr->language[1]='n'; return 3; } void prepareText(NDEFDataStr *data, RecordPosEnu position, uint8_t *text) { data->ndefPosition = position; data->rtdType = RTD_TEXT; data->rtdPayload = text; data->rtdPayloadlength = strlen((const char *)text); }
#include "NT3H.h" #ifndef RTDURI_H_ #define RTDURI_H_ typedef enum { freeForm, //0x00 No prepending is done ... the entire URI is contained in the URI Field httpWWW, //0x01 http://www. httpsWWW, //0x02 https://www. http, //0x03 http:// https, //0x04 https:// tel, //0x05 tel: mailto, //0x06 mailto: ftpAnonymous,//0x07 ftp://anonymous:anonymous@ ftpFtp, //0x08 ftp://ftp. ftps, //0x09 ftps:// sftp, //0x0A sftp:// smb, //0x0B smb:// nfs, //0x0C nfs:// ftp, //0x0D ftp:// dav, //0x0E dav:// news, //0x0F news: telnet, //0x10 telnet:// imap, //0x11 imap: rtps, //0x12 rtsp:// urn, //0x13 urn: /* 0x14 pop: 0x15 sip: 0x16 sips: 0x17 tftp: 0x18 btspp:// 0x19 btl2cap:// 0x1A btgoep:// 0x1B tcpobex:// 0x1C irdaobex:// 0x1D file:// 0x1E urn:epc:id: 0x1F urn:epc:tag: 0x20 urn:epc:pat: 0x21 urn:epc:raw: 0x22 urn:epc: 0x23 urn:nfc: */ }UriTypeE; typedef struct { char *body; uint8_t bodyLength; void *extraData; // herre should be stored specific URI msgs }RtdUriUserPayload; typedef struct { UriTypeE type; RtdUriUserPayload userPayload; // here should be stored specific URI msgs }RTDUriTypeStr; uint8_t addRtdUriRecord(const NDEFDataStr *ndef, RTDUriTypeStr *typeStr); void prepareUrihttp(NDEFDataStr *data, RecordPosEnu position, uint8_t *text); #endif /* RTDURI_H_ */
#include "rtdUri.h" #include <string.h> #include "rtdTypes.h" RTDUriTypeStr uri; uint8_t addRtdUriRecord(const NDEFDataStr *ndef, RTDUriTypeStr *uriType) { uriType->type=((RTDUriTypeStr*) ndef->specificRtdData)->type; return 1; } void prepareUrihttp(NDEFDataStr *data, RecordPosEnu position, uint8_t *text) { data->ndefPosition = position; data->rtdType = RTD_URI; data->rtdPayload = text; data->rtdPayloadlength = strlen((const char *)text);; uri.type = httpWWW; data->specificRtdData = &uri; }
#ifndef RTDTYPES_H_ #define RTDTYPES_H_ #include "rtdText.h" #include "rtdUri.h" #define RTD_TEXT 'T' #define RTD_URI 'U' typedef union { RtdTextTypeStr text; RTDUriTypeStr uri; } RTDTypeUnion; typedef struct { uint8_t typeCode; RTDTypeUnion typePayload; }RTDTypeStr; #endif /* RTDTYPES_H_ */
#ifndef NDEF_H_
#define NDEF_H_
#include "NT3H.h"
bool NT3HwriteRecord(const NDEFDataStr *data);
#endif /* NDEF_H_ */
#include "ndef.h" #include <string.h> #include "nfcForum.h" #include "rtdTypes.h" #include "NT3H.h" typedef uint8_t (*composeRtdPtr)(const NDEFDataStr *ndef, NDEFRecordStr *ndefRecord, uint8_t *I2CMsg); static composeRtdPtr composeRtd[] = {composeRtdText,composeRtdUri}; int16_t firstRecord(UncompletePageStr *page, const NDEFDataStr *data, RecordPosEnu rtdPosition) { NDEFRecordStr record; NDEFHeaderStr header; uint8_t typeFunct=0; switch (data->rtdType){ case RTD_TEXT: typeFunct =0; break; case RTD_URI: typeFunct = 1; break; default: return -1; break; } // clear all buffers memset(&record,0,sizeof(NDEFRecordStr)); memset(nfcPageBuffer, 0, NFC_PAGE_SIZE); // this is the first record header.startByte = NDEF_START_BYTE; composeNDEFMBME(true, true, &record); // prepare the NDEF Header and payload uint8_t recordLength = composeRtd[typeFunct](data, &record, &nfcPageBuffer[sizeof(NDEFHeaderStr)]); header.payloadLength = data->rtdPayloadlength + recordLength; // write first record memcpy(nfcPageBuffer, &header, sizeof(NDEFHeaderStr)); return sizeof(NDEFHeaderStr)+recordLength; } int16_t addRecord(UncompletePageStr *pageToUse, const NDEFDataStr *data, RecordPosEnu rtdPosition) { NDEFRecordStr record; NDEFHeaderStr header={0}; uint8_t newRecordPtr, mbMe; bool ret = true; uint8_t tmpBuffer[NFC_PAGE_SIZE]; uint8_t typeFunct=0; switch (data->rtdType){ case RTD_TEXT: typeFunct =0; break; case RTD_URI: typeFunct = 1; break; default: return -1; break; } // first Change the Header of the first Record NT3HReadHeaderNfc(&newRecordPtr, &mbMe); record.header = mbMe; composeNDEFMBME(true, false, &record); // this is the first record mbMe = record.header; memset(&record,0,sizeof(NDEFRecordStr)); memset(tmpBuffer,0,NFC_PAGE_SIZE); // prepare second record uint8_t recordLength = composeRtd[typeFunct](data, &record, tmpBuffer); if (rtdPosition == NDEFMiddlePos) { // this is a record in the middle adjust it on the buffet composeNDEFMBME(false, false, &record); } else if (rtdPosition == NDEFLastPos){ // this is the last record adjust it on the buffet composeNDEFMBME(false, true, &record); } tmpBuffer[0] = record.header; header.payloadLength += data->rtdPayloadlength + recordLength; // save the new value of length on the first page NT3HWriteHeaderNfc((newRecordPtr+header.payloadLength), mbMe); // use the last valid page and start to add the new record NT3HReadUserData(pageToUse->page); if (pageToUse->usedBytes+recordLength< NFC_PAGE_SIZE) { memcpy(&nfcPageBuffer[pageToUse->usedBytes], tmpBuffer, recordLength); return recordLength+pageToUse->usedBytes; } else { uint8_t byteToCopy = NFC_PAGE_SIZE-pageToUse->usedBytes; memcpy(&nfcPageBuffer[pageToUse->usedBytes], tmpBuffer, byteToCopy); NT3HWriteUserData(pageToUse->page, nfcPageBuffer); // update the info with the new page pageToUse->page++; pageToUse->usedBytes=recordLength-byteToCopy; //copy the remain part in the pageBuffer because this is what the caller expect memcpy(nfcPageBuffer, &tmpBuffer[byteToCopy], pageToUse->usedBytes); return pageToUse->usedBytes; } } static bool writeUserPayload(int16_t payloadPtr, const NDEFDataStr *data, UncompletePageStr *addPage){ uint8_t addedPayload; bool ret=false; uint8_t finish=payloadPtr+data->rtdPayloadlength; bool endRecord = false; uint8_t copyByte=0; // if the header is less then the NFC_PAGE_SIZE, fill it with the payload if (NFC_PAGE_SIZE>payloadPtr) { if (data->rtdPayloadlength > NFC_PAGE_SIZE-payloadPtr) copyByte = NFC_PAGE_SIZE-payloadPtr; else copyByte = data->rtdPayloadlength; } // Copy the payload memcpy(&nfcPageBuffer[payloadPtr], data->rtdPayload, copyByte); addedPayload = copyByte; //if it is sufficient one send add the NDEF_END_BYTE if ((addedPayload >= data->rtdPayloadlength)&&((payloadPtr+copyByte) < NFC_PAGE_SIZE)) { nfcPageBuffer[(payloadPtr+copyByte)] = NDEF_END_BYTE; endRecord = true; } ret = NT3HWriteUserData(addPage->page, nfcPageBuffer); while (!endRecord) { addPage->page++; // move to a new register memset(nfcPageBuffer,0,NFC_PAGE_SIZE); //special case just the NDEF_END_BYTE remain out if (addedPayload == data->rtdPayloadlength) { nfcPageBuffer[0] = NDEF_END_BYTE; ret = NT3HWriteUserData(addPage->page, nfcPageBuffer); endRecord = true; if (ret == false) { errNo = NT3HERROR_WRITE_NDEF_TEXT; } goto end; } if (addedPayload < data->rtdPayloadlength) { // add the NDEF_END_BYTE if there is enough space if ((data->rtdPayloadlength-addedPayload) < NFC_PAGE_SIZE){ memcpy(nfcPageBuffer, &data->rtdPayload[addedPayload], (data->rtdPayloadlength-addedPayload)); nfcPageBuffer[(data->rtdPayloadlength-addedPayload)] = NDEF_END_BYTE; } else { memcpy(nfcPageBuffer, &data->rtdPayload[addedPayload], NFC_PAGE_SIZE); } addedPayload += NFC_PAGE_SIZE; ret = NT3HWriteUserData(addPage->page, nfcPageBuffer); if (ret == false) { errNo = NT3HERROR_WRITE_NDEF_TEXT; goto end; } } else { endRecord = true; } } end: return ret; } typedef int16_t (*addFunct_T) (UncompletePageStr *page, const NDEFDataStr *data, RecordPosEnu rtdPosition); static addFunct_T addFunct[] = {firstRecord, addRecord, addRecord}; bool NT3HwriteRecord(const NDEFDataStr *data) { uint8_t recordLength=0, mbMe; UncompletePageStr addPage; addPage.page = 0; // calculate the last used page if (data->ndefPosition != NDEFFirstPos ) { NT3HReadHeaderNfc(&recordLength, &mbMe); addPage.page = (recordLength+sizeof(NDEFHeaderStr)+1)/NFC_PAGE_SIZE; //remove the NDEF_END_BYTE byte because it will overwrite by the new Record addPage.usedBytes = (recordLength+sizeof(NDEFHeaderStr)+1)%NFC_PAGE_SIZE - 1; } // call the appropriate function and consider the pointer // within the NFC_PAGE_SIZE that need to be used int16_t payloadPtr = addFunct[data->ndefPosition](&addPage, data, data->ndefPosition); if (payloadPtr == -1) { errNo = NT3HERROR_TYPE_NOT_SUPPORTED; return false; } return writeUserPayload(payloadPtr, data, &addPage); }
从机地址为什么是 NT3H1X_SLAVE_ADDRESS 0x55
,我没在数据手册中看出来。
USER_START_REG 0x1
对于NT3H1201 即 2k 情况
CONFIG_REG 0x7A
SRAM_START_REG 0xF8
SRAM_END_REG 0xFB // just the first 8 bytes
SESSION_REG 0xFE
#ifndef NT3H_H_ #define NT3H_H_ #include "stdbool.h" #include <stdint.h> #define NT3H1X_SLAVE_ADDRESS 0x55 #define MANUFACTORING_DATA_REG 0x0 #define USER_START_REG 0x1 // NT3H1201 // for th 2K #define USER_END_REG 0x77 #define CONFIG_REG 0x7A // NT3H1101 // for th 1K // #define USER_END_REG 0x38 // just the first 8 bytes for th 1K // #define CONFIG_REG 0x3A #define SRAM_START_REG 0xF8 #define SRAM_END_REG 0xFB // just the first 8 bytes #define SESSION_REG 0xFE #define NFC_PAGE_SIZE 16 typedef enum { NT3HERROR_NO_ERROR, NT3HERROR_READ_HEADER, NT3HERROR_WRITE_HEADER, NT3HERROR_INVALID_USER_MEMORY_PAGE, NT3HERROR_READ_USER_MEMORY_PAGE, NT3HERROR_WRITE_USER_MEMORY_PAGE, NT3HERROR_ERASE_USER_MEMORY_PAGE, NT3HERROR_READ_NDEF_TEXT, NT3HERROR_WRITE_NDEF_TEXT, NT3HERROR_TYPE_NOT_SUPPORTED }NT3HerrNo; extern uint8_t nfcPageBuffer[NFC_PAGE_SIZE]; extern NT3HerrNo errNo; typedef enum { NDEFFirstPos, NDEFMiddlePos, NDEFLastPos } RecordPosEnu; /* * This strucure is used in the ADD record functionality * to store the last nfc page information, in order to continue from that point. */ typedef struct { uint8_t page; uint8_t usedBytes; } UncompletePageStr; typedef struct { RecordPosEnu ndefPosition; uint8_t rtdType; uint8_t *rtdPayload; uint8_t rtdPayloadlength; void *specificRtdData; }NDEFDataStr; void NT3HGetNxpSerialNumber(char* buffer); /* * read the user data from the requested page * first page is 0 * * the NT3H1201 has 119 PAges * the NT3H1101 has 56 PAges (but the 56th page has only 8 Bytes) */ bool NT3HReadUserData(uint8_t page); /* * Write data information from the starting requested page. * If the dataLen is bigger of NFC_PAGE_SIZE, the consecuiteve needed * pages will be automatically used. * * The functions stops to the latest available page. * first page is 0 * the NT3H1201 has 119 PAges * the NT3H1101 has 56 PAges (but the 56th page has only 8 Bytes) */ bool NT3HWriteUserData(uint8_t page, const uint8_t* data); /* * The function read the first page of user data where is stored the NFC Header. * It is important because it contains the total size of all the stored records. * * param endRecordsPtr return the value of the total size excluding the NDEF_END_BYTE * param ndefHeader Store the NDEF Header of the first record */ bool NT3HReadHeaderNfc(uint8_t *endRecordsPtr, uint8_t *ndefHeader); /* * The function write the first page of user data where is stored the NFC Header. * update the bytes that contains the payload Length and the first NDEF Header * * param endRecordsPtr The value of the total size excluding the NDEF_END_BYTE * param ndefHeader The NDEF Header of the first record */ bool NT3HWriteHeaderNfc(uint8_t endRecordsPtr, uint8_t ndefHeader); bool getSessionReg(void); bool getNxpUserData(char* buffer); bool NT3HReadSram(void); bool NT3HReadSession(void); bool NT3HReadConfiguration(uint8_t *configuration); bool NT3HEraseAllTag(void); bool NT3HReaddManufactoringData(uint8_t *manuf) ; bool NT3HResetUserData(void); #endif /* NFC_H_ */
#include <stdio.h> #include <string.h> #include <unistd.h> #include "wifiiot_i2c.h" #include "wifiiot_i2c_ex.h" #include "NT3H.h" #include "ndef.h" #include "nfc.h" #include "nfcForum.h" uint8_t nfcPageBuffer[NFC_PAGE_SIZE]; NT3HerrNo errNo; // due to the nature of the NT3H a timeout is required to // protectd 2 consecutive I2C access inline const uint8_t* get_last_ncf_page(void) { return nfcPageBuffer; } static bool writeTimeout( uint8_t *data, uint8_t dataSend) { uint32_t status = 0; WifiIotI2cData nt3h1101_i2c_data1 = {0}; nt3h1101_i2c_data1.sendBuf = data; nt3h1101_i2c_data1.sendLen = dataSend; status = I2cWrite(WIFI_IOT_I2C_IDX_1, (NT3H1X_SLAVE_ADDRESS<<1)|0x00, &nt3h1101_i2c_data1); if (status != 0) { printf("===== Error: I2C write status1 = 0x%x! =====\r\n", status); return 0; } usleep(300000); return 1; } static bool readTimeout(uint8_t address, uint8_t *block_data) { uint32_t status = 0; WifiIotI2cData nt3h1101_i2c_data = {0}; uint8_t buffer[1] = {address}; nt3h1101_i2c_data.sendBuf = buffer; nt3h1101_i2c_data.sendLen = 1; nt3h1101_i2c_data.receiveBuf = block_data; nt3h1101_i2c_data.receiveLen = NFC_PAGE_SIZE; status = I2cWriteread(WIFI_IOT_I2C_IDX_1, (NT3H1X_SLAVE_ADDRESS<<1)|0x00, &nt3h1101_i2c_data); if (status != 0) { printf("===== Error: I2C write status = 0x%x! =====\r\n", status); return 0; } return 1; } bool NT3HReadHeaderNfc(uint8_t *endRecordsPtr, uint8_t *ndefHeader) { *endRecordsPtr=0; bool ret = NT3HReadUserData(0); // read the first page to see where is the end of the Records. if (ret == true) { // if the first byte is equals to NDEF_START_BYTE there are some records // store theend of that if ((NDEF_START_BYTE == nfcPageBuffer[0]) && (NTAG_ERASED != nfcPageBuffer[2])) { *endRecordsPtr = nfcPageBuffer[1]; *ndefHeader = nfcPageBuffer[2]; } return true; } else { errNo = NT3HERROR_READ_HEADER; } return ret; } bool NT3HWriteHeaderNfc(uint8_t endRecordsPtr, uint8_t ndefHeader) { // read the first page to see where is the end of the Records. bool ret = NT3HReadUserData(0); if (ret == true) { nfcPageBuffer[1] = endRecordsPtr; nfcPageBuffer[2] = ndefHeader; ret = NT3HWriteUserData(0, nfcPageBuffer); if (ret == false) { errNo = NT3HERROR_WRITE_HEADER; } } else { errNo = NT3HERROR_READ_HEADER; } return ret; } bool NT3HEraseAllTag(void) { bool ret = true; uint8_t erase[NFC_PAGE_SIZE+1] = {USER_START_REG, 0x03, 0x03, 0xD0, 0x00, 0x00, 0xFE}; ret = writeTimeout(erase, sizeof(erase)); if (ret == false) { errNo = NT3HERROR_ERASE_USER_MEMORY_PAGE; } return ret; } bool NT3HReaddManufactoringData(uint8_t *manuf) { return readTimeout(MANUFACTORING_DATA_REG, manuf); } bool NT3HReadConfiguration(uint8_t *configuration){ return readTimeout(CONFIG_REG, configuration); } bool getSessionReg(void) { return readTimeout(SESSION_REG, nfcPageBuffer); } bool NT3HReadUserData(uint8_t page) { uint8_t reg = USER_START_REG+page; // if the requested page is out of the register exit with error if (reg > USER_END_REG) { errNo = NT3HERROR_INVALID_USER_MEMORY_PAGE; return false; } bool ret = readTimeout(reg, nfcPageBuffer); if (ret == false) { errNo = NT3HERROR_READ_USER_MEMORY_PAGE; } return ret; } bool NT3HWriteUserData(uint8_t page, const uint8_t* data) { bool ret = true; uint8_t dataSend[NFC_PAGE_SIZE +1]; // data plus register uint8_t reg = USER_START_REG+page; // if the requested page is out of the register exit with error if (reg > USER_END_REG) { errNo = NT3HERROR_INVALID_USER_MEMORY_PAGE; ret = false; goto end; } dataSend[0] = reg; // store the register memcpy(&dataSend[1], data, NFC_PAGE_SIZE); ret = writeTimeout(dataSend, sizeof(dataSend)); if (ret == false) { errNo = NT3HERROR_WRITE_USER_MEMORY_PAGE; goto end; } end: return ret; } bool NT3HReadSram(void){ bool ret=false; for (int i = SRAM_START_REG, j=0; i<=SRAM_END_REG; i++,j++) { ret = readTimeout(i, nfcPageBuffer); if (ret==false) { return ret; } //memcpy(&userData[offset], pageBuffer, sizeof(pageBuffer)); } return ret; } void NT3HGetNxpSerialNumber(char* buffer) { uint8_t manuf[16]; if (NT3HReaddManufactoringData(manuf)) { for(int i=0; i<6; i++) { buffer[i] = manuf[i]; } } }
用带NFC的手机靠近读取,会弹出识别到一个网页
• 由 Leung 写于 2021 年 10 月 20 日
• 参考:[NFC]NDEF和RTD协议介绍
NFC Forum发布NFC数据交换格式(NDEF)规范
BearPi-HM_Nano开发板基础外设开发——I2C控制NFC芯片
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。