打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033

LiSun

打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

UART —通用异步接收/发送器

图160: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 pinDirectionOutput value
RXDInputNot applicable
CTSInputNot applicable
RTSOutput1
TXDOutput1

共享资源

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

posted on 2022-08-13 11:00  xuejianqiang  阅读(66)  评论(0编辑  收藏  举报
打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033