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

Nordic nRF52832 寄存器级 UARTE 发送实现

目录

概述

1 nRF52832的UART寄存器

1.1 寄存器列表

 1.2 寄存器介绍

 1.2.1 使能控制 (ENABLE)

1.2.2  波特率设置 (BAUDRATE)

1.2.3  配置寄存器 (CONFIG)

 1.2.4 引脚配置寄存器

1.2.5  数据传输寄存器

1.2.6 状态与事件寄存器

1.2.6.1 事件寄存器 (EVENTS)

1.2.6.2  错误状态 (ERRORSRC)

1.2.7 中断控制

 2 完整实现代码

3 关键操作解析

3.1 UARTE 初始化流程

3.2 数据发送流程

4 低功耗优化技巧

4.1 动态电源管理

4.2  发送超时机制

4.3 中断驱动实现

5 常见问题解决


概述

本文将展示如何在 nRF52832 上直接通过寄存器操作实现 UARTE 发送功能,无需 SDK 或 HAL 库。这种底层实现适用于对功耗和时序有严格要求的场景。

1 nRF52832的UART寄存器

1.1 寄存器列表

nRF52832 使用 UARTE (UART with EasyDMA) 外设实现高效串行通信。关键寄存器:

寄存器地址功能描述
UARTE_ENABLE0x40002000UARTE 使能控制
UARTE_BAUDRATE0x40002004波特率设置
UARTE_CONFIG0x4000205C数据格式配置
UARTE_PSEL.TXD0x4000210CTX 引脚选择
UARTE_TXD.PTR0x40002530发送数据指针
UARTE_TXD.MAXCNT0x40002538发送数据长度
UARTE_TASKS_STARTTX0x40002508启动发送任务
UARTE_EVENTS_ENDTX0x40002510发送完成事件

 1.2 寄存器介绍

 1.2.1 使能控制 (ENABLE)

  • 地址0x400020500

  • 功能: 全局 UART 使能

  • 位配置:

    0: Disabled (复位状态)
    4: Enabled  // 必须设置为4才能工作

    操作:

    NRF_UARTE0->ENABLE = 4;  // 启用UART

1.2.2  波特率设置 (BAUDRATE)

  • 地址0x40002524

  • 常用值 (32-bit):

    0x0004F000: 9600 baud
    0x0009D000: 19200 baud
    0x0013B000: 38400 baud
    0x00275000: 57600 baud
    0x004EA000: 115200 baud (默认)
    0x009D5000: 230400 baud
    0x01D20000: 921600 baud

    示例:

    NRF_UARTE0->BAUDRATE = 0x004EA000; // 115200 bps

1.2.3  配置寄存器 (CONFIG)

  • 地址0x4000256C

  • 关键位域:

    位域名称功能
    [1:0]HWFC0禁用硬件流控
    1仅使能RTS
    2仅使能CTS
    3使能RTS+CTS
    [4:2]PARITY0无校验
    1偶校验
    2奇校验
    [6:5]STOP01位停止位
    12位停止位
  • 配置示例 (8N1):
    NRF_UARTE0->CONFIG = 0; // 无流控, 无校验, 1位停止位

 1.2.4 引脚配置寄存器

引脚选择 (PSEL)

  • 寄存器组:

    寄存器地址功能
    PSEL.RTS0x40002508RTS 引脚选择
    PSEL.TXD0x4000250CTX 引脚选择
    PSEL.CTS0x40002510CTS 引脚选择
    PSEL.RXD0x40002514RX 引脚选择
  • 操作 (配置 TX=P0.06, RX=P0.08):
    NRF_UARTE0->PSEL.TXD = 6; 
    NRF_UARTE0->PSEL.RXD = 8;
    NRF_UARTE0->PSEL.CTS = 0xFFFFFFFF; // 禁用CTS
    NRF_UARTE0->PSEL.RTS = 0xFFFFFFFF; // 禁用RTS

1.2.5  数据传输寄存器

1)发送控制 (TXD)

  • PTR 寄存器 (TXD.PTR):

    • 地址0x40002544

    • 功能: 设置发送数据缓冲区地址 (DMA模式)

  • MAXCNT 寄存器 (TXD.MAXCNT):

    • 地址0x40002548

    • 功能: 设置发送数据长度

  • 任务启动 (TASKS_STARTTX):

    • 地址0x40002508

    • 触发: 写入1启动发送

2) 接收控制 (RXD)

  • PTR 寄存器 (RXD.PTR):

    • 地址0x40002534

    • 功能: 设置接收数据缓冲区地址

  • MAXCNT 寄存器 (RXD.MAXCNT):

    • 地址0x40002538

    • 功能: 设置接收缓冲区大小

  • 任务启动 (TASKS_STARTRX):

    • 地址0x40002500

    • 触发: 写入1启动接收

1.2.6 状态与事件寄存器

1.2.6.1 事件寄存器 (EVENTS)
事件地址触发条件
EVENTS_CTS0x40002100CTS 引脚状态变化
EVENTS_NCTS0x40002104CTS 引脚释放
EVENTS_RXDRDY0x40002108接收到数据 (每字节触发)
EVENTS_ENDRX0x40002110完成DMA接收 (整个缓冲区)
EVENTS_TXDRDY0x4000211C发送完成 (每字节)
EVENTS_ENDTX0x40002120完成DMA发送
EVENTS_ERROR0x40002124帧/奇偶校验错误
EVENTS_RXTO0x40002144接收超时

事件清除:

NRF_UARTE0->EVENTS_RXDRDY = 0; // 写0清除事件
1.2.6.2  错误状态 (ERRORSRC)

  • 地址0x40002488

  • 位掩码:

    0x01: Overflow error   // 溢出错误
    0x02: Parity error     // 奇偶校验错误
    0x04: Framing error    // 帧错误
    0x08: Break error      // 线路断开

 错误清除:

NRF_UARTE0->ERRORSRC = NRF_UARTE0->ERRORSRC; // 读取即清除

1.2.7 中断控制

 中断使能 (INTEN)

  • 地址0x40002300

  • 关键中断位:

    #define UARTE_INTEN_RXDRDY_Msk  (1 << 2)  // 接收中断
    #define UARTE_INTEN_TXDRDY_Msk  (1 << 7)  // 发送中断
    #define UARTE_INTEN_ERROR_Msk   (1 << 9)  // 错误中断
    #define UARTE_INTEN_RXTO_Msk    (1 << 17) // 超时中断

 2 完整实现代码

#include <stdint.h>// UARTE0 寄存器基地址
#define UARTE0_BASE 0x40002000UL// 寄存器定义
#define UARTE_ENABLE    (*(volatile uint32_t*)(UARTE0_BASE + 0x000)
#define UARTE_BAUDRATE  (*(volatile uint32_t*)(UARTE0_BASE + 0x004)
#define UARTE_CONFIG    (*(volatile uint32_t*)(UARTE0_BASE + 0x05C)
#define UARTE_PSEL_TXD  (*(volatile uint32_t*)(UARTE0_BASE + 0x10C)
#define UARTE_TXD_PTR   (*(volatile uint32_t*)(UARTE0_BASE + 0x530)
#define UARTE_TXD_MAXCNT (*(volatile uint32_t*)(UARTE0_BASE + 0x538)
#define UARTE_TASKS_STARTTX (*(volatile uint32_t*)(UARTE0_BASE + 0x508)
#define UARTE_EVENTS_ENDTX (*(volatile uint32_t*)(UARTE0_BASE + 0x510)// 波特率定义 (nRF52832 特定值)
#define BAUD_9600     0x00275000
#define BAUD_115200   0x01D7E000
#define BAUD_230400   0x03AFB000
#define BAUD_1000000  0x10000000// 配置位定义
#define CONFIG_HWFC_ENABLED   (0x1UL << 0)
#define CONFIG_PARITY_EXCLUDED (0x0UL << 1)
#define CONFIG_PARITY_INCLUDED (0x7UL << 1) // 奇偶校验
#define CONFIG_STOP_1BIT     (0x0UL << 4)
#define CONFIG_STOP_2BIT     (0x1UL << 4)/*** 初始化 UARTE* * @param tx_pin    TX引脚编号 (0-31)* @param baud_rate 波特率 (使用预定义常量)*/
void uarte_init(uint8_t tx_pin, uint32_t baud_rate) {// 1. 禁用UARTEUARTE_ENABLE = 0;// 2. 配置波特率UARTE_BAUDRATE = baud_rate;// 3. 配置数据格式: 8数据位, 1停止位, 无奇偶校验UARTE_CONFIG = CONFIG_PARITY_EXCLUDED | CONFIG_STOP_1BIT;// 4. 配置TX引脚UARTE_PSEL_TXD = tx_pin;// 5. 使能UARTEUARTE_ENABLE = 4; // 4 = 启用UARTE
}/*** 通过寄存器直接发送数据* * @param data  要发送的数据指针* @param len   数据长度*/
void uarte_send(const uint8_t *data, uint32_t len) {// 1. 设置发送数据指针UARTE_TXD_PTR = (uint32_t)data;// 2. 设置发送数据长度UARTE_TXD_MAXCNT = len;// 3. 清除发送完成事件标志UARTE_EVENTS_ENDTX = 0;// 4. 启动发送任务UARTE_TASKS_STARTTX = 1;// 5. 等待发送完成while (UARTE_EVENTS_ENDTX == 0) {// 忙等待 - 实际应用中可替换为中断驱动}// 6. 清除事件标志UARTE_EVENTS_ENDTX = 0;
}/*** 发送单个字符* * @param c  要发送的字符*/
void uarte_putchar(char c) {uarte_send((const uint8_t*)&c, 1);
}/*** 发送字符串* * @param str  要发送的字符串*/
void uarte_puts(const char *str) {uint32_t len = 0;const char *p = str;// 计算字符串长度while (*p++) len++;// 发送数据uarte_send((const uint8_t*)str, len);
}// 示例使用
int main(void) {// 初始化UART: TX引脚P0.06, 波特率115200uarte_init(6, BAUD_115200);// 发送字符串uarte_puts("Hello, nRF52832!\r\n");// 发送单个字符uarte_putchar('A');// 发送缓冲区数据uint8_t data[] = {0xAA, 0xBB, 0xCC, 0xDD};uarte_send(data, sizeof(data));while(1) {// 主循环}
}

3 关键操作解析

3.1 UARTE 初始化流程

// 禁用UARTE
UARTE_ENABLE = 0;// 设置波特率 (115200)
UARTE_BAUDRATE = 0x01D7E000;// 配置数据格式: 8N1
UARTE_CONFIG = (0 << 0) |  // HWFC 禁用(0 << 1) |  // 奇偶校验禁用(0 << 4);   // 1停止位// 设置TX引脚 (P0.06)
UARTE_PSEL_TXD = 6;// 启用UARTE
UARTE_ENABLE = 4;

3.2 数据发送流程

// 设置数据地址
UARTE_TXD_PTR = (uint32_t)tx_buffer;// 设置数据长度
UARTE_TXD_MAXCNT = data_length;// 清除发送完成事件
UARTE_EVENTS_ENDTX = 0;// 启动发送
UARTE_TASKS_STARTTX = 1;// 等待发送完成
while (UARTE_EVENTS_ENDTX == 0);

4 低功耗优化技巧

4.1 动态电源管理

void uarte_sleep() {// 禁用UARTEUARTE_ENABLE = 0;// 配置GPIO为低功耗模式// (假设使用P0.06)*(volatile uint32_t*)0x50000000 = 0; // PIN_CNF[6].DIR = 输入*(volatile uint32_t*)0x50000718 = 0x000C0000; // PIN_CNF[6]: INPUT=连接, PULL=上拉
}void uarte_wake() {// 重新初始化UARTuarte_init(6, BAUD_115200);
}

4.2  发送超时机制

#define UART_TIMEOUT 10000 // 10ms超时bool uarte_send_timeout(const uint8_t *data, uint32_t len) {UARTE_TXD_PTR = (uint32_t)data;UARTE_TXD_MAXCNT = len;UARTE_EVENTS_ENDTX = 0;UARTE_TASKS_STARTTX = 1;uint32_t timeout = UART_TIMEOUT;while (UARTE_EVENTS_ENDTX == 0) {if (--timeout == 0) {// 超时处理UARTE_TASKS_STOPTX = 1;return false; // 发送失败}}return true; // 发送成功
}

4.3 中断驱动实现

// 在头文件中定义中断处理函数原型
void UARTE0_UART0_IRQHandler(void);// 启用UARTE中断
void uarte_enable_interrupts() {// 启用ENDTX中断*(volatile uint32_t*)(UARTE0_BASE + 0x304) = (1 << 4); // INTENSET = ENDTX// 设置中断优先级并使能NVIC_SetPriority(UARTE0_UART0_IRQn, 6);NVIC_EnableIRQ(UARTE0_UART0_IRQn);
}// 中断处理函数
volatile bool tx_complete = false;void UARTE0_UART0_IRQHandler(void) {if (UARTE_EVENTS_ENDTX) {UARTE_EVENTS_ENDTX = 0; // 清除事件tx_complete = true;      // 设置完成标志}
}// 中断方式发送
void uarte_send_async(const uint8_t *data, uint32_t len) {tx_complete = false;UARTE_TXD_PTR = (uint32_t)data;UARTE_TXD_MAXCNT = len;UARTE_EVENTS_ENDTX = 0;UARTE_TASKS_STARTTX = 1;// 现在可以在主循环中检查tx_complete标志
}

5 常见问题解决

1) 波特率不匹配

症状: 接收端数据错误
验证: 检查波特率寄存器值是否正确:

// 常用波特率寄存器值
switch (baud_rate) {case 9600:   return 0x00275000;case 115200: return 0x01D7E000;case 230400: return 0x03AFB000;case 1000000: return 0x10000000;default: return 0x01D7E000; // 默认为115200
}

2) 低功耗配置冲突

症状: 系统无法进入低功耗模式
解决: 在睡眠前禁用 UARTE:

void prepare_for_sleep() {// 停止所有UART操作UARTE_TASKS_STOPTX = 1;while (UARTE_EVENTS_ENDTX == 0); // 等待停止完成// 禁用UARTEUARTE_ENABLE = 0;
}

http://www.lqws.cn/news/529093.html

相关文章:

  • Android-Layout Inspector使用手册
  • R语言机器学习算法实战系列(二十六)基于tidymodels的XGBoost二分类器全流程实战
  • ubuntu22.04系统kubeadm部署k8s高可用集群
  • 手机屏像素缺陷修复及相关液晶线路激光修复原理
  • 简单使用python
  • Milvus 资源调度系统的核心部分:「查询节点」「资源组」「数据库」
  • gitlab https链接转为ssh链接
  • Docker 网络——AI教你学Docker
  • Vue 2 项目中内嵌 md 文件
  • Windows 下使用 nvm 管理 Node.js 多版本 —— 完整指南
  • 动态规划之01背包问题
  • 互联网医院系统源码解析:如何实现视频问诊、电子处方等核心功能?
  • 焊接与热切割作业证用途有哪些
  • 【SpringBoot】Spring Boot + RESTful 技术实战指南
  • 数据结构进阶 - 第二章 线性表
  • 缓存与加速技术实践-MongoDB数据库应用
  • React:利用计算属性名特点更新表单值
  • Spark SQL to_json 函数介绍
  • LLM复杂记忆存储-多会话隔离案例实战
  • Flink Oracle CDC 总结
  • Spring 框架
  • Python+selenium自动化生成测试报告
  • 在一个成熟产品中,如何设计数据库架构以应对客户字段多样化,确保系统的可维护性、可扩展性和高性能。
  • 智慧城市云计算大数据中心项目设计方案
  • 技术调研:时序数据库(一)
  • ASP.NET Core Web API 实现 JWT 身份验证
  • 【人工智能与机器人研究】基于ROS的多传感器融合巡检机器人系统研究
  • Android 16系统源码_无障碍辅助(二)Android 的无障碍框架
  • 人工智能中的集成学习:从原理到实战
  • PDF Kit 使用示例(HarmonyOS)