这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 【纳芯微NS800】2、串口配置与轮询收发测试

共1条 1/1 1 跳转至

【纳芯微NS800】2、串口配置与轮询收发测试

高工
2026-05-16 19:16:19     打赏

【前言】

最近入手纳芯微NS800开发板一块。准备连载一系列的相关文档。

【芯片介绍】

NS800RTx 芯片基于 ARM 指令架构的 Cortex M7 内核,集成 eMATH 数学加速核,适用于工业和汽车领域复杂 计算场景。借助 eMATH 数学加速器,NS800RTx 具备强大的快速环路计算能力。从运算周期对比来看,eMATH 在 执行如三角函数等运算时,运算周期与C2000 硬件加速器相近。且在支持更多复杂运算(如指数、对数、滤波 器以及矩阵运算)方面具有显著优势。尤其在电力系统的谐波分析中,需频繁进行复杂的矩阵运算和滤波算法, eMATH 加速器可高效完成这些运算,确保系统能快速、准确地分析谐波情况,保障电力系统稳定运行。 其外设资源丰富,详件下图:

image.png

【UART外设使用】

UART的相关的命名

NS系列的UART有两套命名:UART与SCIB(Serial Communication Interface B)

 SCIB 是 TI 命名习惯(SCI = Serial Communication Interface,后缀 A/B/C 表示不同实例),SDK 封装为更通用的 UART* 名称,对开发者更友好。

但是为了通用,好象SDK将他又命名了UART1_4

  •      UART1 — 对应 SCIA,板级调试串口(115200,GPIO_12/GPIO_13)

  •      UART2 — 对应 SCIB,本工程示例(GPIO_38/GPIO_39,230400)

  •      UART3 — 对应 SCIC

  •      UART4 — 对应 SCID

在SDK 中使用:UART_TypeDef *uart = UART2;   // 定义指向 UART2 的指针

寄存器结构体命名

每个 UART 实例的寄存器通过结构体访问,寄存器名均为大写:

    uart->GLOBAL   — 全局控制(偏移 0x08),含 RST 软件复位位
    uart->BAUD     — 波特率寄存器(偏移 0x10)
    uart->STAT     — 状态寄存器(偏移 0x14)
    uart->CTRL     — 控制寄存器(偏移 0x18)
    uart->DATA     — 数据寄存器(偏移 0x1C)
    uart->MATCH    — 地址匹配寄存器(偏移 0x20)
    uart->MODIR    — 调制/红外寄存器(偏移 0x24)
    uart->FIFO     — FIFO 控制寄存器(偏移 0x28)
    uart->WATER    — FIFO 水位线寄存器(偏移 0x2C)

每个寄存器都有两种访问方式:

uart->BAUD.WORDVAL    // 整体 32-bit 读写
uart->BAUD.BIT.SBR    // 按位域读写(SBR = 波特率分频系数,13-bit)

API 函数命名规范

SDK 的 UART API 遵循统一前缀 UART_ + 动作 + 功能:

UART_功能:
      enableModule / disableModule    — 同时使能收发
      enableTxModule / disableTxModule  — 只控发送
      enableRxModule / disableRxModule  — 只控接收
      resetModule                     — 软件复位模块
    
      setBaud                         — 设置波特率
      setBitCountPerChar              — 数据位长度(7/8/9/10)
      setParityMode                   — 校验模式(无/奇/偶)
      setStopBitCount                 — 停止位(1或2)
      setMSB                          — 位序 MSB/LSB
    
      enableTxFifo / disableTxFifo    — TX FIFO 使能
      enableRxFifo / disableRxFifo    — RX FIFO 使能
      resetTxFifo / resetRxFifo       — FIFO 复位
      setTxFifoWatermark              — TX 水位线
      setRxFifoWatermark              — RX 水位线
    
      writeChar / readChar            — 8-bit 读写
      writeChar9 / readChar9          — 9-bit 读写(含校验位)
      writeChar10 / readChar10         — 10-bit 读写
    
      getStatusFlag                   — 读取状态标志
      clearStatusFlag                 — 清除状态标志
      clearErrorFlags                 — 批量清除错误标志
    
      enableInterrupt / disableInterrupt — 中断源使能/关闭

GPIO 引脚命名

    工程涉及的 GPIO 和复用功能命名:

RX 引脚:
      GPIO_39           — GPIO 编号(芯片引脚索引)
      GPIO_39_SCIB_RX   — 复用功能名(将该引脚配置为 SCIB 的 RX)
      GPIO_DIR_MODE_IN  — 方向:输入
      GPIO_QUAL_SYNC    — 输入同步采样(1次)
    
    TX 引脚:
      GPIO_38           — GPIO 编号
      GPIO_38_SCIB_TX   — 复用功能名(SCIB 的 TX)
      GPIO_DIR_MODE_OUT — 方向:输出
      GPIO_DRV_MAX      — 最大驱动能力
      GPIO_PIN_TYPE_STD — 标准驱动(无上拉)

 状态标志命名(STAT 寄存器位)

UART_FRAME_ERR        — 帧错误(FE)
    UART_NOISE_DETECT     — 噪声检测(NF)
    UART_PARITY_ERR       — 校验错误(PF)
    UART_RX_OVERRUN       — 接收溢出(OR)
    UART_IDLE_LINE_DETECT — 空闲线检测(IDLE)
    UART_TX_COMPLETE      — 发送完成(TC)
    UART_TX_DATA_REG_EMPTY — 发送寄存器空(TDRE)
    UART_RX_DATA_REG_FULL  — 接收寄存器满(RDRF)
    UART_RX_ACTIVE        — 接收进行中(RAF)

命名体系与 STM32 HAL 风格接近,上下文清晰的缩写(如 TE=Transmitter Enable, RE=Receiver Enable)减少了长命名带来的冗余。

学习以上的一些知识后,开始配置工程。此次实验采用uart2来进行。因为uart1是日志打印。

实现功能

  • UART2 轮询(Polling)模式收发数据

  • 波特率 230400,8N1(8数据位、无校验、1停止位)

  • 收发各 10 字节随机数据,循环运行

【整体初始化流程】

int main(void)
{
    Device_init();              
// 1. 初始化设备时钟和外设
    Device_unlockPeriphReg();   
// 2. 解锁外设寄存器锁
    Board_init();               
// 3. 初始化板级资源(LED、按键、串口引脚等)
    uart_init(uart);            
// 4. UART2 初始化
    ...
}

Device_init()

系统级外设初始化,具体实现位于 SDK 内部 CMSIS 层,负责时钟管理和外设使能。

Device_unlockPeriphReg()

NS800RT7P65 某些外设寄存器有锁保护,调用此函数解除锁定后才能配置。

Board_init()

板级初始化,在 board.c 中定义,会依次调用:

PinMux_init() — 配置引脚复用
LED_init() — 初始化 LED(GPIO_68 / GPIO_69)
Switch_init() — 初始化按键(GPIO_41)
SerialCOM_init() — 初始化调试串口(UART1,波特率 115200)

【UART2 引脚配置】

NS800RT7P65 的 UART2(SCIB)使用两组引脚,本工程选用:

image.png

RX 引脚配置(GPIO_39)

GPIO_setPinConfig(GPIO_39_SCIB_RX);       // 配置为 SCIB_RX 复用功能
GPIO_setAnalogMode(GPIO_39, GPIO_ANALOG_DISABLED);  
// 关闭模拟功能(数字模式)
GPIO_setPadConfig(GPIO_39, GPIO_PIN_TYPE_PULLUP);    
// 上拉电阻
GPIO_setQualificationMode(GPIO_39, GPIO_QUAL_SYNC);  
// 同步采样(1次)
GPIO_setDirectionMode(GPIO_39, GPIO_DIR_MODE_IN);     
// 方向为输入

配置解释:

• GPIO_QUAL_SYNC:输入信号经过 1 次同步采样过滤噪声

• GPIO_PIN_TYPE_PULLUP:使能内部上拉,悬空时保持确定电平

【TX 引脚配置】

GPIO_setPinConfig(GPIO_38_SCIB_TX);       // 配置为 SCIB_TX 复用功能
GPIO_setAnalogMode(GPIO_38, GPIO_ANALOG_DISABLED);  
// 关闭模拟功能
GPIO_setPadConfig(GPIO_38, GPIO_PIN_TYPE_STD);       
// 标准驱动(无上拉)
GPIO_setDriveLevel(GPIO_38, GPIO_DRV_MAX);           
// 最大驱动强度
GPIO_setDirectionMode(GPIO_38, GPIO_DIR_MODE_OUT);   
// 方向为输出

配置解释:

• GPIO_DRV_MAX:TX 引脚使用最大驱动能力,确保长距离通信信号完整性

• GPIO_DIR_MODE_OUT:TX 为输出信号

【UART2 通信参数配置】

1、模块复位

UART_resetModule(uart);   // 复位 UART2 模块

在配置波特率和其他参数之前,建议先复位模块,确保寄存器处于已知状态。

 2、波特率设置

UART_setBaud(uart, 230400);   // 波特率 230400 bps

SDK 通过内部算法根据系统时钟自动计算 BAUD 寄存器的分频系数。

3、数据位长度

// 无校验时(8N1)
UART_setBitCountPerChar(uart, UART_8_BITS_PER_CHAR, 
false
);

// 有校验时(8位数据 + 1位奇偶校验 = 9位)
UART_setBitCountPerChar(uart, UART_8_BITS_PER_CHAR, 
true
);

第二个参数 true 表示使能校验位传输(共 9 位),false 表示无校验(共 8 位)

4、 校验模式(条件编译)

#if ENABLE_PARITY
    UART_setParityMode(uart, UART_PAR_ODD);   // 奇校验#else
    // 无校验模式#endif

本次 ENABLE_PARITY = 0,默认不使能校验。

5、停止位

UART_setStopBitCount(uart, UART_ONE_STOP_BIT);  // 1 位停止位

可选 UART_TWO_STOP_BIT(2 位停止位)。

6 、位序(MSB/LSB)

UART_setMSB(uart, false);  // false = LSB 先发,true = MSB 先发

默认 LSB 低位优先,符合大多数 UART 通信习惯。

7、 FIFO 配置(条件编译)

#if ENABLE_FIFO
    UART_enableTxFifo(uart);
    UART_resetTxFifo(uart);
    UART_setTxFifoWatermark(uart, UART_FIFO_TX6);  
// 6/16 深度触发中断

    UART_enableRxFifo(uart);
    UART_resetRxFifo(uart);
    UART_setRxFifoWatermark(uart, UART_FIFO_RX6);
    UART_setRxIdleCharacter(uart, UART_IDLE_CHARACTER_CNT1);
#endif

本次 ENABLE_FIFO = 0,不使能 FIFO,采用直接寄存器收发。

8 、收发使能

UART_enableTxModule(uart);   // 使能发送器
UART_enableRxModule(uart);   // 使能接收器

【轮询模式数据收发】

1、 接收函数 UART_receiveDataPolling()

1. UART_resetRxFifo(uart)        // 清空接收 FIFO/Buffer
2. UART_clearErrorFlags(...)      // 清除错误标志(溢出、噪声、帧错误、校验错误)
3. UART_enableRxModule(uart)      // 使能接收器
4. 循环等待 UART_FIFO_RX0 变为非空(RX FIFO 有数据)
5. UART_readChar(uart)           // 读取一个字节
6. 检查各类错误标志,异常时退出
7. 返回 0 表示成功,返回 1 表示失败

关键状态标志检查:

• UART_FRAME_ERR — 帧错误(停止位不符)

• UART_NOISE_DETECT — 噪声检测

• UART_PARITY_ERR — 校验错误

• UART_RX_OVERRUN — 接收溢出(数据覆盖)

2、 发送函数 UART_sendDataPolling()

1. UART_resetTxFifo(uart)              // 清空发送 FIFO
2. UART_enableTxModule(uart)          // 使能发送器
3. 循环 length 次:
   a. 等待 UART_TX_DATA_REG_EMPTY(非空表示发送寄存器有空间)
   b. UART_writeChar(uart, array[i])   // 写入一个字节
4. 等待 UART_TX_COMPLETE(发送完毕)
5. UART_disableTxModule(uart)         // 关闭发送器节省功耗

【测试代码】

/**
 * @file       main.c
 * @author     yangjun
 * @brief      main function file for NS800RT7xxx.
 *
 * <h2><center>&copy; Copyright (c) 2024 Novosense Limited.
 * All rights reserved.</center></h2>
 */

#include "main.h"


/*******************************************************************************
 * Definitions
 ******************************************************************************/
#define DELAY_1S            (1000UL)
#define UART_DATA_LENGTH    (10UL)
#define ENABLE_PARITY       (0UL)
#define ENABLE_FIFO         (0UL)
#define STATUS_NO_ERROR     (0xFF)

/*******************************************************************************
 * Variables
 ******************************************************************************/
UART_TypeDef *uart = UART2;

uint8_t txBuff[UART_DATA_LENGTH];
uint8_t rxBuff[UART_DATA_LENGTH];


/*******************************************************************************
 * Functions Declaration
 ******************************************************************************/
static void uart_init(UART_TypeDef *uart);
static uint32_t UART_receiveDataPolling(UART_TypeDef* uart, uint8_t *const array, uint16_t length);
static void UART_sendDataPolling(UART_TypeDef* uart, const uint8_t *array, uint16_t length);


/*******************************************************************************
 * Functions
 ******************************************************************************/

/**
 * @brief   Main function
 * @return  int  Force return 0
 */
int main(void)
{
    /* Initialize device clock and peripherals */
    Device_init();
    /* Disable peripheral register locks */
    Device_unlockPeriphReg();
    /* Board Initialization
       Setup LED pins, Key pins and Serial Communication Interface pins
     */
    Board_init();
    /* UART Initialization */
    uart_init(uart);

    /* Debug information printing */
    printf("UART ex1 send and receive data by polling mode!\n");

    /* Loop indefinitely */
    while (1)
    {
        printf("UART receive data :\n");
        // UART_readCharArray(uart, rxBuff, UART_DATA_LENGTH);
        if (UART_receiveDataPolling(uart, rxBuff, UART_DATA_LENGTH) == 0)
        {
            printf("receive success: ");
            for (uint32_t i = 0U; i < UART_DATA_LENGTH; i++)
            {
                printf("0x%02X, ", rxBuff[i]);
            }
            printf("\n");
        }
        else
        {
            printf("receive fail!\n");
        }

        printf("UART will transmit data :\n");
        for (uint32_t i = 0U; i < UART_DATA_LENGTH; i++)
        {
            txBuff[i] = (uint8_t)rand();
            printf("0x%02X, ", txBuff[i]);
        }
        printf("\n");
        // UART_writeCharArray(uart, txBuff, UART_DATA_LENGTH);
        UART_sendDataPolling(uart, txBuff, UART_DATA_LENGTH);
    }
}

/**
 * @brief   Initialize uart function
 */
static void uart_init(UART_TypeDef *uart)
{
    /* UART2 RX pinmux control */
    GPIO_setPinConfig(GPIO_39_SCIB_RX);
    GPIO_setAnalogMode(GPIO_39, GPIO_ANALOG_DISABLED);
    GPIO_setPadConfig(GPIO_39, GPIO_PIN_TYPE_PULLUP);
    GPIO_setQualificationMode(GPIO_39, GPIO_QUAL_SYNC);
    GPIO_setDirectionMode(GPIO_39, GPIO_DIR_MODE_IN);

    /* UART2 TX pinmux control */
    GPIO_setPinConfig(GPIO_38_SCIB_TX);
    GPIO_setAnalogMode(GPIO_38, GPIO_ANALOG_DISABLED);
    GPIO_setPadConfig(GPIO_38, GPIO_PIN_TYPE_STD);
    GPIO_setDriveLevel(GPIO_38, GPIO_DRV_MAX);
    GPIO_setDirectionMode(GPIO_38, GPIO_DIR_MODE_OUT);

    /* Reset uart before configure it */
    UART_resetModule(uart);

    /* Set baudrate */
    UART_setBaud(uart, 230400);

#if ENABLE_PARITY
    /* Set the number of bits per char in UART controller */
    UART_setBitCountPerChar(uart, UART_8_BITS_PER_CHAR, true);

    /* Sets the type of parity */
    UART_setParityMode(uart, UART_PAR_ODD);
#else
    /* Set the number of bits per char in UART controller */
    UART_setBitCountPerChar(uart, UART_8_BITS_PER_CHAR, false);
#endif

    /* Set the number of stop bits */
    UART_setStopBitCount(uart, UART_ONE_STOP_BIT);

    /* Set MSB bit reverses the order of the bits */
    UART_setMSB(uart, false);

#if ENABLE_FIFO
    /* Config tx fifo */
    UART_enableTxFifo(uart);
    UART_resetTxFifo(uart);
    UART_setTxFifoWatermark(uart, UART_FIFO_TX6);

    /* Config rx fifo */
    UART_enableRxFifo(uart);
    UART_resetRxFifo(uart);
    UART_setRxFifoWatermark(uart, UART_FIFO_RX6);
    UART_setRxIdleCharacter(uart, UART_IDLE_CHARACTER_CNT1);
#endif

    /* Enable transmitter */
    UART_enableTxModule(uart);

    /* Enable receiver */
    UART_enableRxModule(uart);
}

/**
 * @brief   Receive multiple bytes of data using polling method.
 * @return  Return 0 if reception is successful, 1 if reception fails.
 */
uint32_t UART_receiveDataPolling(UART_TypeDef* uart, uint8_t *const array, uint16_t length)
{
    uint16_t i;
    uint32_t status = STATUS_NO_ERROR;
    uint32_t retval = 0;

    /* Flush receive FIFO/Buffer */
    UART_resetRxFifo(uart);

    /* Clear the error flags */
    UART_clearErrorFlags(uart, UART_STAT_OR_M | UART_STAT_NF_M | UART_STAT_FE_M | UART_STAT_PF_M);

    /* Enable receiver */
    UART_enableRxModule(uart);

    for (i = 0; i < length; i++)
    {
        /* Wait until a character is available in UART receiver */
        while (UART_getRxFifoStatus(uart) == UART_FIFO_RX0);

        /* Read a character from UART receiver */
        array[i] = UART_readChar(uart);

        if (UART_getStatusFlag(uart, UART_FRAME_ERR))
        {
            status = UART_FRAME_ERR;

            /* Disable the UART receiver */
            UART_disableRxModule(uart);

            /* Clear the flag */
            UART_clearStatusFlag(uart, UART_FRAME_ERR);
        }
        if (UART_getStatusFlag(uart, UART_NOISE_DETECT))
        {
            status = UART_NOISE_DETECT;

            /* Disable the UART receiver */
            UART_disableRxModule(uart);

            /* Clear the flag */
            UART_clearStatusFlag(uart, UART_NOISE_DETECT);
        }
        if (UART_getStatusFlag(uart, UART_PARITY_ERR))
        {
            status = UART_PARITY_ERR;

            /* Disable the UART receiver */
            UART_disableRxModule(uart);

            /* Clear the flag */
            UART_clearStatusFlag(uart, UART_PARITY_ERR);
        }
        if (UART_getStatusFlag(uart, UART_RX_OVERRUN))
        {
            status = UART_RX_OVERRUN;

            /* Disable the UART receiver */
            UART_disableRxModule(uart);

            /* Clear the flag */
            UART_clearStatusFlag(uart, UART_RX_OVERRUN);
        }

        if (status != 0xFF)
        {
            break;
        }
    }

    if ((i == length) && ((status == UART_RX_OVERRUN) || status == STATUS_NO_ERROR))
    {
        retval = 0;
        /* Disable the UART receiver */
        UART_disableRxModule(uart);
    }
    else
    {
        retval = 1;
    }

    /* Read dummy to clear RDRF flag */
    while (UART_getStatusFlag(uart, UART_RX_DATA_REG_FULL))
    {
        (void)UART_readChar(uart);
    }

    return retval;
}

/**
 * @brief  Send out multiple bytes of data using polling method.
 */
void UART_sendDataPolling(UART_TypeDef* uart, const uint8_t *array, uint16_t length)
{
    /* Flush transmit FIFO/Buffer */
    UART_resetTxFifo(uart);

    /* Enable the UART transmitter */
    UART_enableTxModule(uart);

    for (uint16_t i = 0; i < length; i++)
    {
        /* Wait until space is available in UART transmitter */
        while (!UART_getStatusFlag(uart, UART_TX_DATA_REG_EMPTY));

        /* Send a character to UART transmitter */
        UART_writeChar(uart, array[i]);
    }

    /* Wait until transmission completes */
    while (!UART_getStatusFlag(uart, UART_TX_COMPLETE));

    /* Disable the UART transmitter */
    UART_disableTxModule(uart);
}

【测试】

使用一个TTL转USB接到开发板的GPIO38 GPIO39,打开串口助手:

image.png

可以看到通过UART2一次发送10字符,在UART1上打印,并回传给UART2。




关键词: NS800     串口     轮询     收发    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]