打造一个通用性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

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

本产品带有 2 个通用 UART 模块(UART0/1),支持半双工和全双工传输;支持 8bit、9bit 数据格式;
支持 Mode0/1/2/3 四种不同传输模式; UART0 的波特率可以由 TIM10 产生或者自动波特率发生器产
生,UART1 的波特率可以由 TIM11 产生或者自动波特率发生器产生;支持多机通讯模式;支持自动
地址识别;支持给定地址和广播地址。
通用 UART(UART0/1)只有一个时钟输入 PCLK, 寄存器配置逻辑和数据收发逻辑都工作在该时钟域。
在这里插入图片描述

工作模式

Mode 0(同步模式,半双工)
当工作在 Mode0 时,UART 工作在同步模式,其波特率为固定的 PCLK 时钟的 1/12。UART 接收数据由 RXD 输入、UART 发送数据由 RXD 输出,RXD 此时为输入输出端口。UART 同步移位时钟由TXD 输出,TXD 此时为输出端口。注意,本模式只能作为主机发送同步移位时钟,不可以作为从机从外部接收移位时钟。该模式下,传输的数据位宽只能是 8 位的,没有起始位和结束位。
将 UARTx_SCON.SM0 和 UARTx_SCON.SM1 清零,可进入 Mode0 工作模式。

Mode 1(异步模式,全双工)
当工作在 Mode1 时,发送数据通过 TXD 发送,接收数据通过 RXD 接收。该数据由 10 位组成:起始位“0”开始,紧接着 8 位数据位(低位在先,高位在后),最后是结束位“1”。该模式下,波特率可以由可 编 程 定 时 器 模 块 产 生 , 也 可 以 由 模 块 内 部 的 自 动 波 特 率 发 生 器 产 生 。 当UARTx_BAUDCR.SELF_BRG 为 0 时,选择由定时器产生波特率时,UART0 的波特率由 TIM10 产生,UART1 的波特率由 TIM11 产生;当 UARTx_BAUDCR.SELF_BRG 置 1 时,UART0、UART1的波特率都由各自内部的自动波特率发生器产生。波特率产生公式请参考 21.3.5.2 节 Mode1/3。
将 UARTx_SCON.SM0 清 0,UARTx_SCON.SM1 置 1,可进入 Mode1 工作模式。

Mode 2(异步模式,全双工)
当工作在 Mode2 时,发送数据通过 TXD 发送,接收数据通过 RXD 接收。该数据由 11 位组成:起始位“0”开始,接着是 8 个数据位,1 个 TB8 位和结束位。额外的 TB8 位是用来在多机通讯环境下使用,当 TB8=1,表明所接收的是地址帧;当 TB8=0,表明所接收的是数据帧。当不需要多机通讯时,此位也可以作为奇偶校验位来使用。该模式下,波特率可以独立产生,不需要外部定时器模块产生。 将 UARTx_SCON.SM0 置 1,UARTx_SCON.SM1 清 0,可进入 Mode2 工作模式。

Mode 3(异步模式,全双工)
Mode3 的数据格式,传输时序以及操作方式都与 Mode2 相同,唯一的区别是 Mode3 的波特率选择由可编程定时器产生或者内部自动波特率发生器产生,而不是像 Mode2 只由设备自己独立产生。
Mode3 的波特率是可编程的,波特率生成方式与 Mode1 相同。
将 UARTx_SCON.SM0 置 1,UARTx_SCON.SM1 置 1,可进入 Mode3 工作模式。

/********************************************************************************
* @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

/********************************************************************************
* @file    bsp_uart.c
* @author  jianqiang.xue
* @version V1.0.0
* @date    2021-04-13
* @brief   uart驱动
********************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>

#include "RTE_Components.h"
#include CMSIS_device_header

#include "bsp_gpio.h"
#include "bsp_exti.h"
#include "bsp_uart.h"

/* Private Includes ----------------------------------------------------------*/
#include "business_gpio.h"
#include "business_function.h"
/* Private Define ------------------------------------------------------------*/
/* External Variables --------------------------------------------------------*/
/* Private Typedef -----------------------------------------------------------*/
typedef void(*bsp_uart_callback)(void);

/* Private Variables ---------------------------------------------------------*/
#if BS_UART0_EN
#define BSP_UART0                                UART0
#define BSP_UART0_APBX_CLOCK()                   __HAL_RCC_UART0_CLK_ENABLE()
#define BSP_UART0_IRQN                           UART0_IRQn

// 定义串口缓存区
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;

static bsp_uart_callback uart0_irq_rx_callback;

// 定义串口信息初始化结构体
UART_HandleTypeDef huart0 =
{
    .Instance        = BSP_UART0,
    .Init.BaudRate   = BS_UART0_BAUD_RATE,
    .Init.BaudDouble = UART_BAUDDOUBLE_ENABLE,
    .Init.WordLength = UART_WORDLENGTH_8B,
    .Init.Parity     = UART_PARITY_NONE,
    .Init.Mode       = UART_MODE_TX_RX,
    .pRxBuffPtr      = bsp_uart0_rx_buff,
    .RxXferSize      = BS_UART0_CACHE_SIZE,
    .pTxBuffPtr      = bsp_uart0_tx_buff,
    .TxXferSize      = BS_UART0_CACHE_SIZE
};
#endif

/* 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
        huart0.Init.BaudRate = baud;
#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;
        }
        bsp_exit_set(BSP_UART0_IRQN, 0);
        BS_UART0_RX_GPIO_CLK_ENABLE();
        BS_UART0_TX_GPIO_CLK_ENABLE();
        bsp_gpio_init_uart(BS_UART0_TX_GPIO_PORT, BS_UART0_TX_PIN, GPIO_AF5_UART0_TXD);
        bsp_gpio_init_uart(BS_UART0_RX_GPIO_PORT, BS_UART0_RX_PIN, GPIO_AF5_UART0_RXD);

        BSP_UART0_APBX_CLOCK();

        /* Configure USART0 */
        HAL_UART_Init(&huart0);
        HAL_UART_Receive_IT(&huart0, bsp_uart0_rx_buff, BS_UART0_CACHE_SIZE);
        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;
        }
        HAL_UART_DeInit(&huart0);
        bsp_gpio_deinit(BS_UART0_TX_GPIO_PORT, BS_UART0_TX_PIN);
        bsp_gpio_deinit(BS_UART0_RX_GPIO_PORT, BS_UART0_RX_PIN);
        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;
}

/**
  * @brief  Rx Transfer completed callbacks.
  * @param  huart: pointer to a UART_HandleTypeDef structure that contains
  *                the configuration information for the specified UART module.
  * @retval None
  */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if (huart->Instance == BSP_UART0)
    {
#if BS_UART0_EN
        if (uart0_irq_rx_callback)
        {
            uart0_irq_rx_callback();
        }
#endif
    }
}

/************************************[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;
        }
        Uart_Send_Byte(&huart0, 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)
        {
            Uart_Send_nByte(&huart0, data, len);
        }
        else
        {
            Uart_Send_nByte(&huart0, bsp_uart0_tx_buff, len);
        }
        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
        if (data != NULL)
        {
            HAL_UART_Transmit_IT(&huart0, data, len);
        }
        else
        {
            HAL_UART_Transmit_IT(&huart0, huart0.pTxBuffPtr, 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 BS_UART0_CACHE_SIZE - huart0.RxXferCount;
#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;
        }
        HAL_UART_AbortReceive(&huart0);
#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
        HAL_UART_Receive_IT(&huart0, bsp_uart0_rx_buff, BS_UART0_CACHE_SIZE);
#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
        huart0.pRxBuffPtr = bsp_uart0_rx_buff;
        huart0.RxXferCount = BS_UART0_CACHE_SIZE;
        memset(bsp_uart0_rx_buff, 0, BS_UART0_CACHE_SIZE);
        HAL_UART_Receive_IT(&huart0, bsp_uart0_rx_buff, BS_UART0_CACHE_SIZE);
#endif
    }
    return;
}

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