当前位置: 首页 > 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;
}

相关文章:

  • Python中的多线程与协程:程序、线程、进程之间的关联关系
  • 发布:大彩DN系列3.2寸全视角IPS串口屏发布!
  • MySQL(基础篇)
  • Django 零基础起步:开发你的网站第一步
  • 阿里推出 R1-Omni:将强化学习与可验证奖励(RLVR)应用于全模态大语言模型
  • 如何将 Memfault 固件 SDK 集成到使用 Nordic 的 nRF Connect SDK(NCS)的项目中
  • LlamaIndex基础概念与核心架构
  • Linux中部署Jenkins保姆间教程
  • [mcp-servers] docs | AI客户端-MCP服务器-AI 架构
  • WPF 实现自定义弹窗输入功能
  • 第一章-人工智能概述-深度学习与AI发展(2/36)
  • 星型模式(Star Schema)
  • 代码随想录|图论|05岛屿数量(深搜DFS)
  • 重建与数字子序列匹配的最小数字序列的有效方法
  • element-plus 按钮 展开/隐藏
  • css 颜色与字体
  • Flux.create
  • Mac电脑如何搭建基于java后端的开发的各种工具服务
  • WebSocket 与 HTTP 的区别及 Spring Boot 实战应用
  • FANUC机器人教程:用户坐标系标定及其使用方法