初学libnfc,简单的nfc读写c++程序,串口通信
我在学习的过程中,在网上找不到window系统下的libnfc库下nfc卡读写的例子,所以在我做完这个例子后上传到网上,希望以后能帮到和我同样初学libnfc的人。PN532支持多种工作模式,包括读写模式、卡模拟模式和点对点模式等,我这次只使用了读写模式。使用的环境是libnfc1.7,这个资源网上也有,直接在vs上运行即可。所使用的硬件:一个pn532模块+usb转接器。例子用到的卡,一个mif
·
我在学习的过程中,在网上找不到window系统下的libnfc库下nfc卡读写的例子,所以在我做完这个例子后上传到网上,希望以后能帮到和我同样初学libnfc的人。
所使用的硬件:一个pn532模块+usb转接器

PN532支持多种工作模式,包括读写模式、卡模拟模式和点对点模式等,我这次只使用了读写模式
例子用到的卡,一个mifare卡

使用的环境是libnfc1.7,这个资源网上也有,直接在vs上运行即可
里面的端口号是usb插入的端口号
#include <iostream>
#include <windows.h> // 提供 Sleep 函数
#include <nfc.h> // libnfc库头文件
#include <cstdint>
#include <vector>
#include <algorithm>
#include <string>
// 延时函数(Windows API)
void delayMs(int ms = 5) {
Sleep(ms);
}
// 等待用户输入1
void waitForUserInput() {
int input;
do {
std::cout << "请输入1继续下一步操作: ";
std::cin >> input;
} while (input != 1);
}
// MIFARE Classic默认密钥A(出厂默认值FF FF FF FF FF FF)
const uint8_t DEFAULT_KEY[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
/**
* @brief 打印块数据
*/
void printBlockData(uint8_t sector, uint8_t block, const uint8_t* data) {
printf("Sector %2d, Block %2d: ", sector, block);
for (int i = 0; i < 16; i++) {
printf("%02X ", data[i]);
if (i == 7) printf(" "); // 每8字节用空格分隔
}
printf("\n");
}
/**
* @brief 认证扇区
*/
bool authenticateSector(nfc_device* pnd, uint8_t block,
const uint8_t* uid, uint8_t uid_len, bool useKeyA = true) {
// 1. 增加认证前延时(500ms)
delayMs(100);
uint8_t auth_cmd[] = {
useKeyA ? 0x60 : 0x61, block, // 0x60=KeyA, 0x61=KeyB
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 默认密钥 FFFFFFFFFFFF
uid[0], uid[1], uid[2], uid[3] // UID 后4字节
};
uint8_t response[256];
int res = nfc_initiator_transceive_bytes(pnd, auth_cmd, sizeof(auth_cmd),
response, sizeof(response), 1000);
// 2. 增加认证后延时(500ms)
delayMs(100);
if (res < 0) {
printf("认证失败: %s\n", nfc_strerror(pnd));
return false;
}
// printf("认证成功!\n");
return true;
}
/**
* @brief 读取块数据
*/
bool readBlock(nfc_device* pnd, uint8_t block, uint8_t* data) {
uint8_t read_cmd[] = { 0x30, block }; // 读命令+块号
uint8_t response[256];
//printf("尝试读取块数据...\n");
delayMs(100); // 发送前延时
int res = nfc_initiator_transceive_bytes(pnd, read_cmd, sizeof(read_cmd),
response, sizeof(response), NULL);
delayMs(100); // 发送后延时
if (res == 16) {
memcpy(data, response, 16);
//printf("读取成功!\n");
return true;
}
printf("读取失败! 返回码: %d\n", res);
return false;
}
/**
* @brief 写入数据到指定块
* @param pnd NFC设备句柄
* @param block 绝对块号(0~63)
* @param data 要写入的16字节数据
* @return 是否写入成功
*/
bool writeblock(nfc_device* pnd, uint8_t block, const uint8_t* data) {
// MIFARE Classic 写命令格式: 0xA0 + 块号 + 16字节数据
uint8_t write_cmd[18] = { 0xA0, block };
memcpy(write_cmd + 2, data, 16); // 填充数据
//printf("尝试写入块 %d...\n", block);
delayMs(100); // 写入前延时
uint8_t response[256];
int res = nfc_initiator_transceive_bytes(pnd, write_cmd, sizeof(write_cmd),
response, sizeof(response), 1000);
delayMs(100); // 写入后延时
if (res < 0) {
printf("写入失败! 错误: %s\n", nfc_strerror(pnd));
return false;
}
// printf("写入成功!\n");
return true;
}
/**
* @brief 读取指定扇区
*/
void readSector(nfc_device* pnd, nfc_target& target, int sectorToRead) {
printf("\n=========== 正在读取扇区 %2d ===========\n", sectorToRead);
for (uint8_t blockInSector = 0; blockInSector < 4; blockInSector++) {
uint8_t currentBlock = sectorToRead * 4 + blockInSector;
uint8_t data[16] = { 0 };
printf("\n---- 块 %d ----\n", blockInSector);
// 认证当前块
//std::cout << "认证中...";
if (!authenticateSector(pnd, currentBlock, target.nti.nai.abtUid, target.nti.nai.szUidLen, true)) {
std::cout << "认证失败!跳过此块\n";
continue;
}
// 读取块数据
//std::cout << "读取中...";
if (readBlock(pnd, currentBlock, data)) {
printBlockData(sectorToRead, blockInSector, data);
}
else {
std::cout << "读取失败\n";
}
delayMs(100); // 块操作间隔
}
std::cout << "\n=========== 扇区 " << sectorToRead << " 读取完成 ===========\n";
}
/**
* @brief 写入指定扇区块
*/
void writeSectorBlock(nfc_device* pnd, nfc_target& target)
{
// 选择要写入的扇区和块
int writeSector, writeBlock;
do {
std::cout << "请输入要写入的扇区号(0-15): ";
std::cin >> writeSector;
if (writeSector < 0 || writeSector > 15) {
std::cout << "无效的扇区号!\n";
}
} while (writeSector < 0 || writeSector > 15);
do {
std::cout << "请输入要写入的块号(0-3): ";
std::cin >> writeBlock;
if (writeBlock < 0 || writeBlock > 3) {
std::cout << "无效的块号!\n";
}
} while (writeBlock < 0 || writeBlock > 3);
// 检查是否是扇区尾块(块3)
if (writeBlock == 3) {
std::cout << "警告:这是扇区尾块,包含密钥和访问控制位!\n";
std::cout << "确定要写入吗?(1=是, 0=否): ";
char confirm;
std::cin >> confirm;
if (confirm != '1') {
std::cout << "已取消写入尾块操作\n";
return;
}
}
// 输入要写入的数据
uint8_t writeData[16] = { 0 };
std::cout << "\n请输入16字节十六进制数据(用空格分隔,示例: 01 02 03...):\n";
std::cout << "示例数据: 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10\n";
std::cout << "你的输入: ";
for (int i = 0; i < 16; i++) {
unsigned int byte;
std::cin >> std::hex >> byte;
writeData[i] = static_cast<uint8_t>(byte);
}
// 执行写入
uint8_t currentBlock = writeSector * 4 + writeBlock;
std::cout << "\n准备写入扇区 " << writeSector << " 块 " << writeBlock
<< " (绝对块号 " << (int)currentBlock << ")\n";
waitForUserInput();
// 认证
if (authenticateSector(pnd, currentBlock, target.nti.nai.abtUid, target.nti.nai.szUidLen)) {
// 写入
if (writeblock(pnd, currentBlock, writeData)) {
// 验证写入
uint8_t verifyData[16];
if (readBlock(pnd, currentBlock, verifyData)) {
std::cout << "\n写入验证:\n";
std::cout << "原始数据: ";
for (int i = 0; i < 16; i++) printf("%02X ", writeData[i]);
std::cout << "\n卡片数据: ";
for (int i = 0; i < 16; i++) printf("%02X ", verifyData[i]);
std::cout << "\n";
if (memcmp(writeData, verifyData, 16) == 0) {
std::cout << "验证成功: 数据匹配!\n";
}
else {
std::cout << "验证失败: 数据不匹配!\n";
}
}
}
}
}
int main() {
nfc_device* pnd;
nfc_context* context;
std::string a ="pn532_uart:COM";
std::string b;
// 初始化NFC库
std::cout << "正在初始化NFC库..." << std::endl;
nfc_init(&context);
if (!context) {
std::cerr << "错误: 初始化NFC上下文失败" << std::endl;
return 1;
}
std::cout << "NFC库初始化成功!" << std::endl;
waitForUserInput();
// 打开PN532设备(通过COM1串口)
std::cout << "请输入使用的端口号" << std::endl;
std::cin >> b;
a = a + b+":115200";
std::cout << "正在尝试打开"<<a<<"..." << std::endl;
const char* c_str_a = a.c_str();
pnd = nfc_open(context, c_str_a);
if (!pnd) {
std::cerr << "错误: 找不到NFC设备 - " << nfc_strerror(pnd) << std::endl;
nfc_exit(context);
return 1;
}
std::cout << "NFC设备打开成功!" << std::endl;
waitForUserInput();
delayMs(1000);
// 配置读卡器参数
std::cout << "正在配置读卡器参数..." << std::endl;
nfc_initiator_init(pnd);
nfc_device_set_property_int(pnd, NP_TIMEOUT_COMMAND, 2000); // 1秒超时
nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true); // 启用CRC校验
std::cout << "读卡器参数配置完成!" << std::endl;
waitForUserInput();
std::cout << "等待检测MIFARE Classic卡片..." << std::endl;
// 检测卡片(ISO14443A协议)
nfc_target target;
std::cout << "正在尝试检测卡片..." << std::endl;
// 1. 确保天线已开启(某些PN532固件可能需要手动开启)
nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, true); // 开启RF场
delayMs(1000); // 等待天线稳定,卡片上电(关键!)
const nfc_modulation nm = { NMT_ISO14443A, NBR_106 };
int res = nfc_initiator_select_passive_target(pnd, nm, nullptr, 0, &target);
if (res > 0) {
std::cout << "卡片检测成功!" << std::endl;
waitForUserInput();
delayMs(100); // 卡片初始化延时(重要!)
printf("卡片信息:\n");
printf("ATQA: %02X %02X\n", target.nti.nai.abtAtqa[0], target.nti.nai.abtAtqa[1]);
printf("SAK: %02X\n", target.nti.nai.btSak);
std::cout << "UID: ";
for (uint8_t i = 0; i < target.nti.nai.szUidLen; i++) {
printf("%02X", target.nti.nai.abtUid[i]);
if (i < target.nti.nai.szUidLen - 1) printf(":");
}
std::cout << "\n\n";
waitForUserInput();
// 主操作循环
int operation = 0;
while (operation != 3) {
std::cout << "\n请选择操作:\n";
std::cout << "1. 读卡\n";
std::cout << "2. 写卡\n";
std::cout << "3. 退出\n";
std::cout << "请输入选择(1-3): ";
std::cin >> operation;
switch (operation) {
case 1: {
// 读卡操作
int sectorToRead;
do {
std::cout << "请输入要读取的扇区号(0-15): ";
std::cin >> sectorToRead;
if (sectorToRead < 0 || sectorToRead > 15) {
std::cout << "无效的扇区号,请输入0-15之间的数字!\n";
}
} while (sectorToRead < 0 || sectorToRead > 15);
readSector(pnd, target, sectorToRead);
waitForUserInput();
break;
}
case 2: {
// 写卡操作
writeSectorBlock(pnd, target);
waitForUserInput();
break;
}
case 3: {
// 退出
std::cout << "正在退出程序...\n";
break;
}
default: {
std::cout << "无效的选择,请重新输入!\n";
break;
}
}
}
std::cout << "正在取消选择目标..." << std::endl;
nfc_initiator_deselect_target(pnd);
std::cout << "目标取消选择成功!" << std::endl;
}
else {
std::cout << "未检测到卡片! 错误码: " << res << std::endl;
}
// 释放资源
std::cout << "正在关闭NFC设备..." << std::endl;
nfc_close(pnd);
std::cout << "正在释放NFC上下文..." << std::endl;
nfc_exit(context);
std::cout << "NFC操作完成!" << std::endl;
return 0;
}
更多推荐
所有评论(0)