当前位置: 首页 > news >正文

16、nrf52840蓝牙学习(唯一ID加密与解密)

唯一ID程序学习:

/******************** (C) COPYRIGHT 2023青风电子 ********************* 文件名  :main* 出品论坛 :www.qfv8.com        * 实验平台:青云nRF52xx蓝牙开发板* 描述    :串口输出* 作者    :青风* 店铺    :qfv5.taobao.com
**********************************************************************/#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "app_uart.h"
#include "app_error.h"
#include "nrf_delay.h"
#include "nrf.h"
#include "bsp.h"
#if defined (UART_PRESENT)
#include "nrf_uart.h"
#endif
#if defined (UARTE_PRESENT)
#include "nrf_uarte.h"
#endif//#define ENABLE_LOOPBACK_TEST  /**< if defined, then this example will be a loopback test, which means that TX should be connected to RX to get data loopback. */#define MAX_TEST_DATA_BYTES     (15U)                /**< max number of test bytes to be used for tx and rx. */
#define UART_TX_BUF_SIZE 256                         /**< UART TX buffer size. */
#define UART_RX_BUF_SIZE 256                         /**< UART RX buffer size. */void uart_error_handle(app_uart_evt_t * p_event)
{if (p_event->evt_type == APP_UART_COMMUNICATION_ERROR){APP_ERROR_HANDLER(p_event->data.error_communication);}else if (p_event->evt_type == APP_UART_FIFO_ERROR){APP_ERROR_HANDLER(p_event->data.error_code);}
}#define UART_HWFC APP_UART_FLOW_CONTROL_DISABLED/*** @brief Function for main application entry.*/
int main(void)
{uint32_t err_code;uint32_t id1,id2;id1=NRF_FICR->DEVICEID[0]; //读取id低31位id2=NRF_FICR->DEVICEID[1];//读取id高31位const app_uart_comm_params_t comm_params ={RX_PIN_NUMBER,TX_PIN_NUMBER,RTS_PIN_NUMBER,CTS_PIN_NUMBER,UART_HWFC,false,
#if defined (UART_PRESENT)NRF_UART_BAUDRATE_115200
#elseNRF_UARTE_BAUDRATE_115200
#endif};APP_UART_FIFO_INIT(&comm_params,UART_RX_BUF_SIZE,UART_TX_BUF_SIZE,uart_error_handle,APP_IRQ_PRIORITY_LOWEST,err_code);APP_ERROR_CHECK(err_code);while (1){printf("打印id:%lx%lx\r\n",id1,id2);nrf_delay_ms(1000);}}/** @} */

第一节

#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "app_uart.h"
#include "app_error.h"
#include "nrf_delay.h"
#include "nrf.h"
#include "bsp.h"
#if defined (UART_PRESENT)
#include "nrf_uart.h"
#endif
#if defined (UARTE_PRESENT)
#include "nrf_uarte.h"
#endif

这段代码主要完成以下工作:

  1. 引入必要的头文件

    #include <stdbool.h>
    #include <stdint.h>
    #include <stdio.h>
    
     

    引入标准 C 库头文件,提供基础数据类型和标准输入输出功能

  2. 引入 Nordic SDK 组件

    #include "app_uart.h"
    #include "app_error.h"
    #include "nrf_delay.h"
    #include "nrf.h"
    #include "bsp.h"
    
     
    • app_uart.h:提供 UART 应用层驱动
    • app_error.h:错误处理机制
    • nrf_delay.h:延时函数
    • nrf.h:nRF52 芯片寄存器定义
    • bsp.h:板级支持包
  3. 条件编译处理不同 UART 外设

    #if defined (UART_PRESENT)
    #include "nrf_uart.h"
    #endif
    #if defined (UARTE_PRESENT)
    #include "nrf_uarte.h"
    #endif
    
     
    • UART_PRESENT:表示芯片包含基本 UART 外设
    • UARTE_PRESENT:表示芯片包含增强型 UARTE 外设 (带硬件流控制和 DMA)

串口通信关键组件解析

1. UART vs UARTE
  • UART:基本串口通信模块
  • UARTE:增强型串口模块,相比 UART 增加了以下功能:
    • 硬件流控制 (RTS/CTS)
    • DMA 支持,减轻 CPU 负担
    • 更高的通信可靠性
2. 应用层 UART 驱动 (app_uart.h)

Nordic SDK 提供的应用层 UART 驱动具有以下特点

  • 基于事件驱动架构
  • 支持 FIFO 缓冲区
  • 提供错误回调机制
  • 兼容 UART 和 UARTE 外设
3. 错误处理机制

app_error.h 中定义的错误处理宏:

  • APP_ERROR_CHECK(err_code):检查错误码,非零则触发错误处理
  • APP_ERROR_HANDLER(error_code):错误处理函数,通常会:
    • 记录错误码
    • 点亮错误指示灯
    • 进入无限循环或复位系统


第二节

//#define ENABLE_LOOPBACK_TEST  /**< if defined, then this example will be a loopback test, which means that TX should be connected to RX to get data loopback. */#define MAX_TEST_DATA_BYTES     (15U)                /**< max number of test bytes to be used for tx and rx. */
#define UART_TX_BUF_SIZE 256                         /**< UART TX buffer size. */
#define UART_RX_BUF_SIZE 256                         /**< UART RX buffer size. */

这部分代码定义了串口通信的关键参数和测试配置,下面为你详细解释:

1. 回环测试宏定义

//#define ENABLE_LOOPBACK_TEST  /**< if defined, then this example will be a loopback test, which means that TX should be connected to RX to get data loopback. */
  • 功能:启用串口回环测试模式
  • 使用方法:取消注释该行即可启用回环测试
  • 工作原理
    • 将 TX 引脚与 RX 引脚物理连接
    • 发送的数据会被立即回收到接收缓冲区
    • 用于验证 UART 硬件和驱动是否正常工作

2. 数据传输相关宏定义

#define MAX_TEST_DATA_BYTES     (15U)                /**< max number of test bytes to be used for tx and rx. */
  • 作用:定义测试时最大发送 / 接收数据字节数
  • 典型应用场景
    uint8_t test_data[MAX_TEST_DATA_BYTES] = "Hello UART!";
    for (int i = 0; i < MAX_TEST_DATA_BYTES; i++) {app_uart_put(test_data[i]);
    }
    

3. 缓冲区大小定义

#define UART_TX_BUF_SIZE 256                         /**< UART TX buffer size. */
#define UART_RX_BUF_SIZE 256                         /**< UART RX buffer size. */

  • FIFO 缓冲区作用

    • 发送缓冲区:暂存待发送的数据,避免 CPU 等待串口发送完成
    • 接收缓冲区:暂存接收到的数据,防止数据丢失
  • 参数调整建议

    • 高速通信场景 (如 115200bps 以上):增大缓冲区
    • 空间受限设备:适当减小缓冲区,但需注意:

      // 缓冲区溢出风险示例
      if (app_uart_get(&data) == NRF_SUCCESS) {// 及时处理数据,避免缓冲区溢出
      }
      

4. 实际应用注意事项

回环测试的典型实现

#ifdef ENABLE_LOOPBACK_TEST// 发送测试数据app_uart_put('A');// 接收回环数据uint8_t received;while(app_uart_get(&received) != NRF_SUCCESS);printf("Loopback test: received %c\n", received);
#endif
缓冲区溢出处理
static void uart_event_handle(app_uart_evt_t * p_event)
{if (p_event->evt_type == APP_UART_COMMUNICATION_ERROR) {// 处理通信错误} else if (p_event->evt_type == APP_UART_FIFO_ERROR) {// 处理FIFO溢出错误}
}

5. 参数优化建议

  • 低功耗场景

    #define UART_TX_BUF_SIZE 64  // 减小发送缓冲区节省RAM
    #define UART_RX_BUF_SIZE 64  // 减小接收缓冲区节省RAM
    

  • 高速数据传输场景

    #define UART_TX_BUF_SIZE 512  // 增大发送缓冲区处理突发数据
    #define UART_RX_BUF_SIZE 512  // 增大接收缓冲区处理突发数据
    

通过合理配置这些参数,可以在资源占用和通信性能之间取得最佳平衡。


第三

void uart_error_handle(app_uart_evt_t * p_event)
{if (p_event->evt_type == APP_UART_COMMUNICATION_ERROR){APP_ERROR_HANDLER(p_event->data.error_communication);}else if (p_event->evt_type == APP_UART_FIFO_ERROR){APP_ERROR_HANDLER(p_event->data.error_code);}
}

这个函数是 UART 错误处理回调函数,用于处理 Nordic SDK 中 UART 通信过程中出现的错误。下面为你详细解析:

函数功能概述

该函数作为 UART 事件回调的一部分,专门处理两种严重错误:

  1. 通信错误(如帧错误、奇偶校验错误等)
  2. FIFO 缓冲区错误(如溢出、下溢等)

当检测到这些错误时,会调用 Nordic SDK 的错误处理宏APP_ERROR_HANDLER进行处理。

错误类型详解

1. 通信错误(APP_UART_COMMUNICATION_ERROR)

可能的错误代码包括:

  • NRF_ERROR_UART_OVERRUN:接收溢出错误(新数据覆盖未读取数据)
  • NRF_ERROR_UART_PARITY:奇偶校验错误
  • NRF_ERROR_UART_FRAMING:帧格式错误
  • NRF_ERROR_UART_BREAK:接收到 BREAK 信号
  • NRF_ERROR_UART_HW_FLOW:硬件流控制错误
2. FIFO 错误(APP_UART_FIFO_ERROR)

可能的错误代码包括:

  • NRF_ERROR_NO_MEM:FIFO 内存不足
  • NRF_ERROR_INVALID_STATE:FIFO 状态无效
  • NRF_ERROR_INVALID_PARAM:参数错误

错误处理机制

1. 错误捕获方式
// 注册错误回调函数
APP_UART_FIFO_INIT(..., uart_error_handle, ...);

当 UART 驱动检测到错误时,会调用该回调函数。

2. 错误处理流程
void uart_error_handle(app_uart_evt_t * p_event)
{if (p_event->evt_type == APP_UART_COMMUNICATION_ERROR){// 通信错误处理uint32_t error_code = p_event->data.error_communication;APP_ERROR_HANDLER(error_code);}else if (p_event->evt_type == APP_UART_FIFO_ERROR){// FIFO错误处理uint32_t error_code = p_event->data.error_code;APP_ERROR_HANDLER(error_code);}
}
3. APP_ERROR_HANDLER 宏展开

该宏通常会:

  1. 停止所有中断
  2. 点亮错误指示灯(如果有配置)
  3. 进入无限循环或触发系统复位
  4. 调试模式下可能会打印错误代码

实际应用建议

1. 增强错误处理
void uart_error_handle(app_uart_evt_t * p_event)
{switch(p_event->evt_type){case APP_UART_COMMUNICATION_ERROR:// 记录错误日志log_error("UART comm error: 0x%08lX", p_event->data.error_communication);// 尝试恢复if (p_event->data.error_communication == NRF_ERROR_UART_OVERRUN) {uart_recover(); // 自定义恢复函数} else {APP_ERROR_HANDLER(p_event->data.error_communication);}break;case APP_UART_FIFO_ERROR:// 记录错误日志log_error("UART FIFO error: 0x%08lX", p_event->data.error_code);APP_ERROR_HANDLER(p_event->data.error_code);break;default:break;}
}
2. 错误恢复策略
static void uart_recover(void)
{// 清空接收缓冲区while(app_uart_get(NULL) == NRF_SUCCESS);// 重新同步通信send_sync_sequence();
}
3. 调试建议
  • 使用调试器捕获错误代码
  • 添加错误计数统计
  • 实现条件性错误处理(某些错误允许恢复,严重错误触发复位)

通过合理扩展这个错误处理函数,可以提高系统的健壮性,减少因通信错误导致的系统崩溃。


第四

#define UART_HWFC APP_UART_FLOW_CONTROL_DISABLED/*** @brief Function for main application entry.*/
int main(void)
{uint32_t err_code;uint32_t id1,id2;id1=NRF_FICR->DEVICEID[0]; //读取id低31位id2=NRF_FICR->DEVICEID[1];//读取id高31位const app_uart_comm_params_t comm_params ={RX_PIN_NUMBER,TX_PIN_NUMBER,RTS_PIN_NUMBER,CTS_PIN_NUMBER,UART_HWFC,false,
#if defined (UART_PRESENT)NRF_UART_BAUDRATE_115200
#elseNRF_UARTE_BAUDRATE_115200
#endif};APP_UART_FIFO_INIT(&comm_params,UART_RX_BUF_SIZE,UART_TX_BUF_SIZE,uart_error_handle,APP_IRQ_PRIORITY_LOWEST,err_code);APP_ERROR_CHECK(err_code);while (1){printf("打印id:%lx%lx\r\n",id1,id2);nrf_delay_ms(1000);}}

代码详细解析

宏定义部分
#define UART_HWFC APP_UART_FLOW_CONTROL_DISABLED

这是一个预处理宏定义,作用是设置 UART 硬件流控模式。具体分析如下:

  • 宏名称UART_HWFC
  • 宏值APP_UART_FLOW_CONTROL_DISABLED,从命名可推断这是禁用硬件流控的常量
  • 功能:用于配置 UART 通信时是否启用硬件流控(RTS/CTS)机制
  • 背景知识
    • 硬件流控是通过专用引脚(RTS/CTS)控制数据传输的机制,可防止接收端缓冲区溢出
    • 当设置为禁用时,UART 将不使用 RTS/CTS 引脚进行流控管理
    • 该宏会影响后续 UART 初始化时的流控配置
int main(void)
{uint32_t err_code;uint32_t id1,id2;id1=NRF_FICR->DEVICEID[0]; //读取id低31位id2=NRF_FICR->DEVICEID[1];//读取id高31位

这段代码是程序的入口函数,首先定义了三个 32 位无符号整数变量:

  • err_code:用于存储函数执行后的错误码
  • id1id2:用于存储从芯片读取的设备 ID

接下来两行代码通过访问NRF_FICR寄存器读取设备 ID:

  • NRF_FICR是 Nordic 芯片中存储固定信息的寄存器组(Fixed Information Control Register)
  • DEVICEID是其中的一个寄存器数组,包含两个 32 位寄存器
  • id1存储低 31 位 ID(因为最高位通常为保留位)
  • id2存储高 31 位 ID
  • 组合这两个值可得到完整的 62 位设备唯一标识符
UART 配置结构体
    const app_uart_comm_params_t comm_params ={RX_PIN_NUMBER,TX_PIN_NUMBER,RTS_PIN_NUMBER,CTS_PIN_NUMBER,UART_HWFC,false,
#if defined (UART_PRESENT)NRF_UART_BAUDRATE_115200
#elseNRF_UARTE_BAUDRATE_115200
#endif};

这部分定义了一个 UART 通信参数结构体,包含以下字段:

字段说明
RX_PIN_NUMBERUART 接收引脚编号
TX_PIN_NUMBERUART 发送引脚编号
RTS_PIN_NUMBER硬件流控请求发送引脚编号
CTS_PIN_NUMBER硬件流控清除发送引脚编号
UART_HWFC硬件流控模式(使用之前定义的宏,此处为禁用)
false可能是一个使能标志位,此处设为 false 表示禁用某种功能
波特率配置根据芯片是否定义 UART_PRESENT 宏,选择不同的 UART 或 UARTE 模块波特率
  • 条件编译部分#if defined (UART_PRESENT)用于兼容不同 nRF 芯片型号
    • nRF51 系列通常使用 UART 模块
    • nRF52 系列通常使用 UARTE(增强型 UART)模块
    • 两者波特率定义在不同头文件中
UART 初始化
    APP_UART_FIFO_INIT(&comm_params,UART_RX_BUF_SIZE,UART_TX_BUF_SIZE,uart_error_handle,APP_IRQ_PRIORITY_LOWEST,err_code);APP_ERROR_CHECK(err_code);

这部分调用 API 初始化 UART FIFO 模式:

  • 函数参数说明

    1. &comm_params:指向之前定义的通信参数结构体
    2. UART_RX_BUF_SIZE:接收缓冲区大小(宏定义值)
    3. UART_TX_BUF_SIZE:发送缓冲区大小(宏定义值)
    4. uart_error_handle:UART 错误处理函数指针
    5. APP_IRQ_PRIORITY_LOWEST:中断优先级(最低优先级)
    6. err_code:用于接收函数执行结果的变量
  • 错误处理机制

    • APP_ERROR_CHECK是一个宏,用于检查函数执行是否成功
    • 如果err_code非零,通常会触发断言或错误处理流程
主循环部分
    while (1){printf("打印id:%lx%lx\r\n",id1,id2);nrf_delay_ms(1000);}

这是一个无限循环,实现以下功能:

  • printf函数:通过 UART 输出设备 ID

    • %lx格式说明符表示以 16 进制无符号长整型输出
    • 输出格式为 "打印 id:低 31 位 ID 高 31 位 ID"
    • 末尾的\r\n是串口通信中常用的换行符组合
  • nrf_delay_ms(1000)

    • 调用 Nordic SDK 提供的延时函数
    • 使程序暂停 1000 毫秒(1 秒)
    • 实现每隔 1 秒打印一次设备 ID 的功能

整体功能总结

这段代码的主要功能是:

  1. 配置 UART 通信参数,禁用硬件流控,设置 115200 波特率
  2. 从芯片固定信息寄存器中读取 62 位唯一设备 ID
  3. 初始化 UART FIFO 模式并进行错误检查
  4. 在主循环中每隔 1 秒通过 UART 打印设备 ID

技术背景补充

  • 应用场景:这段代码很可能运行在 Nordic Semiconductor 的 nRF51 或 nRF52 系列芯片上,常见于蓝牙或低功耗无线设备
  • 开发框架:使用了 Nordic 的 APP_UART API,属于 sdk_config.h 配置的标准应用接口
  • 设备 ID 用途:芯片唯一 ID 常用于设备身份识别、加密密钥生成、固件升级标识等场景
  • UART 配置:115200 波特率是嵌入式系统中常见的调试串口速率,禁用流控适用于简单调试场景

如果需要进一步了解某个具体函数或寄存器的细节,可以提供更深入的技术文档说明。这段代码是基于 Nordic nRF 系列芯片的 UART 通信及设备 ID 打印程序,以下是对代码的详细解释:

1. 宏定义解析

#define UART_HWFC APP_UART_FLOW_CONTROL_DISABLED

  • 功能:禁用硬件流控制(Hardware Flow Control, HWFC)。
  • 作用:UART 通信中,硬件流控制通过 RTS/CTS 引脚避免数据溢出,但会增加引脚开销。此处禁用后,通信仅使用 TX/RX 两根线,适用于数据量小或接收端缓冲区足够的场景。

2. 设备 ID 读取

uint32_t id1, id2;
id1 = NRF_FICR->DEVICEID[0]; // 读取ID低31位
id2 = NRF_FICR->DEVICEID[1]; // 读取ID高31位

  • NRF_FICR:芯片内部的 Factory Information Configuration Register,存储设备唯一 ID(通常为 64 位)。
  • DEVICEID[0]/[1]
    • DEVICEID[0]:低 32 位(实际有效位为低 31 位)。
    • DEVICEID[1]:高 32 位(实际有效位为低 31 位)。
  • 用途:设备 ID 常用于设备标识、加密密钥生成等。

3. UART 参数配置

const app_uart_comm_params_t comm_params = {RX_PIN_NUMBER,    // 接收引脚TX_PIN_NUMBER,    // 发送引脚RTS_PIN_NUMBER,   // 请求发送(硬件流控制)CTS_PIN_NUMBER,   // 清除发送(硬件流控制)UART_HWFC,        // 硬件流控制状态(已禁用)false,            // 不使用奇偶校验#if defined (UART_PRESENT)NRF_UART_BAUDRATE_115200#elseNRF_UARTE_BAUDRATE_115200#endif
};

  • 引脚配置
    • RX_PIN_NUMBER/TX_PIN_NUMBER:必选,用于数据收发。
    • RTS_PIN_NUMBER/CTS_PIN_NUMBER:虽定义但因UART_HWFC禁用,实际未使用。
  • 波特率:115200bps,需与接收端(如串口调试助手)匹配。
  • UART vs UARTE
    • UART_PRESENT:判断芯片是否支持传统 UART 外设。
    • UARTE:增强型 UART,支持更高性能(如 DMA)。

4. UART 初始化

APP_UART_FIFO_INIT(&comm_params,         // UART参数UART_RX_BUF_SIZE,     // 接收缓冲区大小UART_TX_BUF_SIZE,     // 发送缓冲区大小uart_error_handle,    // 错误处理函数APP_IRQ_PRIORITY_LOWEST, // 中断优先级err_code              // 错误码输出
);
APP_ERROR_CHECK(err_code); // 检查初始化是否成功

  • FIFO 缓冲区
    • UART_RX_BUF_SIZE/TX_BUF_SIZE:定义接收 / 发送缓冲区大小(通常为 32/64 字节)。
    • 作用:临时存储数据,避免中断频繁触发。
  • 错误处理
    • uart_error_handle:用户自定义函数,处理 UART 错误(如溢出、帧错误)。
    • APP_ERROR_CHECK:Nordic SDK 提供的宏,若初始化失败会触发断言或复位系统。

5. 主循环功能

while (1) {printf("打印id:%lx%lx\r\n", id1, id2); // 打印设备IDnrf_delay_ms(1000);                    // 延时1秒
}

  • printf 实现
    • 通过 UART 发送格式化字符串,依赖于 SDK 对标准库的重定向(通常重定向到app_uart_put函数)。
    • %lx:以 16 进制格式打印无符号长整型。
  • 延时机制
    • nrf_delay_ms(1000):阻塞延时 1 秒,期间 CPU 无法处理其他任务。
    • 适用于简单场景,复杂应用建议使用定时器或 RTOS 调度。

代码潜在问题

  1. 硬件流控制禁用:若数据量大,可能导致接收缓冲区溢出(需确保UART_RX_BUF_SIZE足够)。
  2. 设备 ID 有效性DEVICEID的高 31 位可能全为 0(部分芯片设计),打印时需注意格式(如补零)。
  3. 阻塞延时nrf_delay_ms会阻塞 CPU,建议在低功耗或多任务场景使用非阻塞延时。

总结

这段代码实现了:

  1. 读取芯片唯一 ID。
  2. 配置 UART 通信(禁用硬件流控制,波特率 115200)。
  3. 每秒通过串口打印一次设备 ID。

适用于设备标识测试或简单调试场景。

相关文章:

  • 百度上如何做企业网站建站系统软件有哪些
  • 百度seo营销网站长春百度seo公司
  • 落实政府网站建设网推怎么做
  • 建设网站方法seo软文是什么意思
  • 苏州网站设计聚尚网络企业管理培训机构排名前十
  • 厦门建设厅查询网站今天重大新闻事件
  • VRRP:解决路由器单点故障的终极方案
  • wpa_supplicant连接到了路由,但是 udhcpc会分配到不同网段的ip,路由器ip为192.168.0网段,板子分配ip为192.168.1的网段
  • 2025.6.24总结
  • 数组题解——​合并区间【LeetCode】
  • Python 猜数字小游戏:Tkinter 实现的互动猜数挑战
  • json.decoder.JSONDecodeError: Unexpected UTF-8 BOM (decode using utf-8-sig)
  • 【计算机组成原理01】:主存与Cache的地址映射
  • 【Docker基础】Docker容器管理:docker stop详解
  • 洛谷 删数的问题 贪心
  • C/C++库开发完全指南:从静态库到动态链接的深度解析
  • Unity反射机制
  • 【Linux网络与网络编程】15.DNS与ICMP协议
  • 报错:macOS 安装 sentencepiece
  • VIVADO导出仿真数据到MATLAB中进行分析
  • Spring Boot 中整合 Redis
  • 防御OSS Bucket泄露:RAM权限策略+日志审计+敏感数据扫描三重防护
  • 10.多进程服务器端
  • 复制 生成二维码
  • 麒麟V10操作系统离线安装Docker、Docker compose和1Panel
  • 鸿蒙 Stack 组件深度解析:层叠布局的核心应用与实战技巧