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. 禁用UARTE
    UARTE_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. 使能UARTE
    UARTE_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, 波特率115200
    uarte_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() {
    // 禁用UARTE
    UARTE_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() {
    // 重新初始化UART
    uarte_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); // 等待停止完成
    
    // 禁用UARTE
    UARTE_ENABLE = 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值