UART —通用异步接收/发送器
功能描述
这里列出了UART的主要特性。
UART实现了对以下特性的支持:
- 全双工操作
- 自动流量控制
- 第9位数据位校验和生成
如图160所示:第531页的UART配置,UART直接使用TXD和RXD寄存器来发送和接收数据。 UART使用一个停止位。
引脚的配置
不同的信号RXD, CTS (Clear To Send, active low), RTS (Request To Send, active low)和TXD与UART相关联,分别根据PSELRXD, PSELCTS, PSELRTS和PSELTXD寄存器中指定的配置映射到物理引脚。
如果在这些寄存器中指定了0xFFFFFFFF值,则关联的UART信号将不会连接到任何物理引脚。 PSELRXD、PSELCTS、PSELRTS和PSELTXD寄存器及其配置仅在UART启用时使用,并且仅在设备处于ON模式时保留。 PSELRXD、PSELCTS、PSELRTS和PSELTXD只能在禁用UART的情况下配置。
当系统处于OFF模式时,为了确保UART在引脚上的正确信号电平,必须按照第531页引脚配置中的描述在GPIO外围设备中配置引脚。
一次只能指定一个外设来驱动特定的GPIO管脚。 不这样做可能会导致不可预测的行为。
表128:GPIO配置
UART pin | Direction | Output value |
---|---|---|
RXD | Input | Not applicable |
CTS | Input | Not applicable |
RTS | Output | 1 |
TXD | Output | 1 |
共享资源
UART与与UART具有相同ID的其他外围设备共享寄存器和其他资源。 因此,在配置和使用UART之前,必须禁用与UART ID相同的所有外围设备。 禁用与UART具有相同ID的外设将不会重置与UART共享的任何寄存器。 因此,显式配置所有相关的UART寄存器以确保其正确操作非常重要。
有关外围设备及其id的详细信息,请参阅第24页Instantiation中的Instantiation表。
接收
通过触发STARTRX任务来启动UART接收序列。
UART接收器链实现了一个FIFO,能够在数据出现之前存储6个传入RXD字节覆盖。 字节是通过读取RXD寄存器从这个FIFO中提取的。 当一个字节被提取在FIFO中一个新的字节将被移动到RXD寄存器。 UART将生成每当一个新字节移动到RXD寄存器时,RXDRDY事件。
当流量控制启用时,UART将在只有4个空间时停用RTS信号更多的字节在接收器先进先出。 对应的发射机因此能够发送最多四个字节后在数据被覆盖之前,RTS信号被停用。 为了防止在FIFO中覆盖数据,对等的UART发送器必须因此确保停止传输数据在四个字节后RTS线路失效。
暂停UART
可以通过触发SUSPEND任务来挂起UART。 暂停会影响UART接收端和UART发送端,即发送端停止发送,接收端停止接收。 UART的发送和接收在暂停后可以通过触发STARTTX和STARTRX来恢复。
在SUSPEND任务之后,正在进行的TXD字节传输将在UART挂起之前完成。
当SUSPEND任务被触发时,UART接收器的行为与STOPRX任务被触发时的行为相同。
错误条件
如果在帧中没有检测到有效的停止位,将生成一个以帧错误形式出现的ERROR事件。 如果RXD线保持低电平的时间超过数据帧的长度,将生成另一个以中断条件形式出现的ERROR事件。 实际上,总是在中断条件发生之前生成帧错误。
使用没有流控制的UART
如果没有启用流量控制,接口将表现为CTS和RTS线路一直处于活动状态。
奇偶校验配置
当使能奇偶校验时,TXD和RXD的奇偶校验将自动生成用于发送和接收的奇偶校验。
/********************************************************************************
* @file bsp_uart.c
* @author jianqiang.xue
* @version V1.0.0
* @date 2021-04-13
* @brief uart驱动
********************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "RTE_Components.h"
#include CMSIS_device_header
#include "nrf_uart.h"
#include "app_uart.h"
#include "bsp_gpio.h"
#include "bsp_uart.h"
/* Private Define ------------------------------------------------------------*/
#include "business_gpio.h"
#include "business_function.h"
/* External Variables --------------------------------------------------------*/
/* Private Typedef -----------------------------------------------------------*/
typedef void(*bsp_uart_callback)(void);
/* Private Variables ---------------------------------------------------------*/
#if BS_UART0_EN
#define BSP_UART0_IRQ_HANDLER uart0_event_handle
// 定义串口缓存区
uint8_t bsp_uart0_tx_buff[BS_UART0_CACHE_SIZE] = {0};
uint8_t bsp_uart0_rx_buff[BS_UART0_CACHE_SIZE] = {0};
// 定义串口初始化标记位 0--未初始化 1--初始化完成
bool g_uart0_init = false;
// 定义串口发送标记位 0--free闲 1--bus忙
bool g_uart0_send_lock = false;
uint16_t bsp_uart0_rx_buff_position = 0;
static bsp_uart_callback uart0_irq_rx_callback;
// 定义串口信息初始化结构体
static app_uart_comm_params_t uart0_comm_params =
{
.rx_pin_no = BS_UART0_RX_PIN,
.tx_pin_no = BS_UART0_TX_PIN,
.rts_pin_no = RTS_PIN_NUMBER,
.cts_pin_no = CTS_PIN_NUMBER,
.flow_control = APP_UART_FLOW_CONTROL_DISABLED,
.use_parity = false,
.baud_rate = NRF_UART_BAUDRATE_460800
};
#endif
/* Private Function Prototypes -----------------------------------------------*/
/**
* @brief Rx Transfer completed callbacks.
* @note NULL
* @param p_event: Struct containing events from the UART module.
* @retval None
*/
static void BSP_UART0_IRQ_HANDLER(app_uart_evt_t * p_event)
{
if (p_event->evt_type == APP_UART_DATA_READY)
{
app_uart_get(&bsp_uart0_rx_buff[bsp_uart0_rx_buff_position]);
if (bsp_uart0_rx_buff_position < (BS_UART0_CACHE_SIZE - 1))
{
bsp_uart0_rx_buff_position++;
}
if (uart0_irq_rx_callback)
{
uart0_irq_rx_callback();
}
}
}
/* Public Function Prototypes ------------------------------------------------*/
/**
* @brief 设置串口波特率
* @note NULL
* @param uart: 串口组号
* @param baud: 波特率
* @retval None
*/
void biz_uart_set_baud_rate(bsp_uart_t uart, uint32_t baud)
{
if (uart == BSP_UART_0)
{
#if BS_UART0_EN
if (baud == 19200)
{
uart0_comm_params.baud_rate = NRF_UART_BAUDRATE_19200;
}
else if (baud == 115200)
{
uart0_comm_params.baud_rate = NRF_UART_BAUDRATE_115200;
}
else if (baud == 460800)
{
uart0_comm_params.baud_rate = NRF_UART_BAUDRATE_460800;
}
#endif
}
return;
}
/**
* @brief 串口初始化
* @note None
* @param uart: 串口组号
* @retval None
*/
void bsp_uart_init(bsp_uart_t uart)
{
if (uart == BSP_UART_0)
{
#if BS_UART0_EN
if (g_uart0_init)
{
return;
}
uint32_t err_code;
APP_UART_FIFO_INIT(&uart0_comm_params,
BS_UART0_CACHE_SIZE,
BS_UART0_CACHE_SIZE,
uart0_event_handle,
APP_IRQ_PRIORITY_LOWEST,
err_code);
APP_ERROR_CHECK(err_code);
bsp_uart0_rx_buff_position = 0;
g_uart0_init = true;
#endif
}
}
/**
* @brief 串口反注册 关闭串口时钟并复位引脚
* @note NULL
* @param uart: 串口组号
* @retval None
*/
void bsp_uart_deinit(bsp_uart_t uart)
{
if (uart == BSP_UART_0)
{
#if BS_UART0_EN
if (!g_uart0_init)
{
return;
}
app_uart_close();
g_uart0_init = false;
#endif
}
}
/**
* @brief 注册串口接收回调函数
* @note NULL
* @param uart: 串口组号
* @param event: 事件回调函数
* @retval 0--失败 1--成功
*/
bool bsp_uart_rx_irq_callback(bsp_uart_t uart, void *event)
{
if (uart == BSP_UART_0)
{
#if BS_UART0_EN
if (uart0_irq_rx_callback != NULL)
{
return true;
}
else
{
uart0_irq_rx_callback = (bsp_uart_callback)event;
}
#endif
}
return false;
}
/************************************[uart] 使用函数************************************/
/**
* @brief 发送一个字节
* @note NULL
* @param uart: 串口组号
* @param data: 字节值
* @retval None
*/
void bsp_uart_send_byte(bsp_uart_t uart, uint8_t data)
{
if (uart == BSP_UART_0)
{
#if BS_UART0_EN
if (!g_uart0_init)
{
return;
}
app_uart_put(data);
#endif
}
return;
}
/**
* @brief 发送多个字节(堵塞)
* @note NULL
* @param uart: 串口组号
* @param *data: 数据头指针
* @param len: 数据长度
* @retval None
*/
void bsp_uart_send_nbyte(bsp_uart_t uart, uint8_t *data, uint16_t len)
{
if (uart == BSP_UART_0)
{
#if BS_UART0_EN
if (!g_uart0_init)
{
return;
}
if (g_uart0_send_lock)
{
return;
}
g_uart0_send_lock = true;
if (data != NULL)
{
for (uint16_t i = 0; i < len; i++)
{
app_uart_put(data[i]);
}
}
else
{
for (uint16_t i = 0; i < len; i++)
{
app_uart_put(bsp_uart0_tx_buff[i]);
}
}
g_uart0_send_lock = false;
#endif
}
return;
}
/**
* @brief 发送多个字节(非堵塞) 一般DMA方式
* @note NULL
* @param uart: 串口组号
* @param *data: 数据头指针
* @param len: 数据长度
* @retval None
*/
void bsp_uart_send_nbyte_nowait(bsp_uart_t uart, uint8_t *data, uint16_t len)
{
if (uart == BSP_UART_0)
{
#if BS_UART0_EN
bsp_uart_send_nbyte(uart, data, len);
#endif
}
return;
}
/**
* @brief 得到txbuff头指针
* @note NULL
* @param uart: 串口组号
* @retval None
*/
uint8_t *bsp_uart_get_txbuff(bsp_uart_t uart)
{
if (uart == BSP_UART_0)
{
#if BS_UART0_EN
if (g_uart0_send_lock == false)
{
return bsp_uart0_tx_buff;
}
return NULL;
#endif
}
return NULL;
}
/**
* @brief 得到rxbuff头指针
* @note NULL
* @param uart: 串口组号
* @retval None
*/
uint8_t *bsp_uart_get_rxbuff(bsp_uart_t uart)
{
if (uart == BSP_UART_0)
{
#if BS_UART0_EN
return bsp_uart0_rx_buff;
#endif
}
return NULL;
}
/**
* @brief [串口信息] 返回串口缓存指针位置,即当前缓存数量(byte)
* @note NULL
* @param uart: 串口号
* @retval 串口缓存指针位置
*/
uint16_t bsp_uart_get_rxbuff_position(bsp_uart_t uart)
{
if (uart == BSP_UART_0)
{
#if BS_UART0_EN
return bsp_uart0_rx_buff_position;
#endif
}
return NULL;
}
/**
* @brief 得到rxbuff大小
* @note NULL
* @param uart: 串口组号
* @retval 字节大小
*/
uint16_t bsp_uart_get_rxbuff_size(bsp_uart_t uart)
{
if (uart == BSP_UART_0)
{
#if BS_UART0_EN
return BS_UART0_CACHE_SIZE;
#endif
}
return 0;
}
/**
* @brief [串口操作] 关闭串口接收:关闭串口中断,终止接收中断回调
* @note 由于无DMA,只能先关闭,再处理数据,防止数据错乱。然后重新读取。
* @param uart: 串口号
* @retval None
*/
void bsp_uart_rx_close(bsp_uart_t uart)
{
if (uart == BSP_UART_0)
{
#if BS_UART0_EN
if (!g_uart0_init)
{
return;
}
app_uart_close();
#endif
}
return;
}
/**
* @brief [串口操作] 打开串口接收:打开串口中断,设置接收中断回调
* @note 由于无DMA,只能先关闭,再处理数据,防止数据错乱。然后重新读取。
* @param uart: 串口号
* @retval None
*/
void bsp_uart_rx_open(bsp_uart_t uart)
{
if (uart == BSP_UART_0)
{
#if BS_UART0_EN
bsp_uart_init(uart);
#endif
}
return;
}
/**
* @brief [串口操作] 复位接收缓存指针
* @note NULL
* @param uart: 串口号
* @retval None
*/
void bsp_uart_reset_rxbuff(bsp_uart_t uart)
{
if (uart == BSP_UART_0)
{
#if BS_UART0_EN
bsp_uart0_rx_buff_position = 0;
#endif
}
return;
}
/********************************************************************************
* @file bsp_uart.h
* @author jianqiang.xue
* @version V1.0.0
* @date 2021-04-13
* @brief NULL
********************************************************************************/
#ifndef __BSP_UART_H
#define __BSP_UART_H
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>
/* Public enum ---------------------------------------------------------------*/
typedef enum
{
BSP_UART_0 = 0,
BSP_UART_1 = 1,
BSP_UART_2 = 2,
} bsp_uart_t;
/* Public Function Prototypes ------------------------------------------------*/
// uart基础功能
void bsp_uart_init(bsp_uart_t uart);
void bsp_uart_deinit(bsp_uart_t uart);
void biz_uart_set_baud_rate(bsp_uart_t uart, uint32_t baud);
void bsp_uart_rx_close(bsp_uart_t uart);
void bsp_uart_rx_open(bsp_uart_t uart);
bool bsp_uart_rx_irq_callback(bsp_uart_t uart, void *event);
// uart发送函数
void bsp_uart_send_byte(bsp_uart_t uart, uint8_t data);
void bsp_uart_send_nbyte(bsp_uart_t uart, uint8_t *data, uint16_t len);
void bsp_uart_send_nbyte_nowait(bsp_uart_t uart, uint8_t *data, uint16_t len);
// 获得tx/rx缓冲区首指针
uint8_t *bsp_uart_get_txbuff(bsp_uart_t uart);
uint8_t *bsp_uart_get_rxbuff(bsp_uart_t uart);
uint16_t bsp_uart_get_rxbuff_position(bsp_uart_t uart);
void bsp_uart_set_rxbuff_position(bsp_uart_t uart, uint16_t val);
void bsp_uart_add_rxbuff_position(bsp_uart_t uart);
uint16_t bsp_uart_get_rxbuff_size(bsp_uart_t uart);
void bsp_uart_reset_rxbuff(bsp_uart_t uart);
#endif
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· Vue3状态管理终极指南:Pinia保姆级教程