stm32之hal库串口中断和ringbuffer的结合

news2024/11/19 18:23:43

前言

  1. 结合hal库封装的中断处理函数
  2. 使用rt-thread内部的rt-ringbuffer数据结构源码
  3. 改造hal库串口部分的源码,将内部静态方法变为弱引用的函数,方便重写
  4. 标志位采用信号量或变量的两种方式,内部数据分配方式采用动态和静态两种方式

hal库部分串口调整(两个函数由外部重新修改)

vv

串口代码

头文件

/*
 * Copyright (c) 2024-2024,shchl
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2024-5-2     shchl   first version
 */

#ifndef TX_STM32_F4_DRV_UART_OS_H
#define TX_STM32_F4_DRV_UART_OS_H

#include "drv_common.h"
/*串口配置控制器个数,限制串口个数*/
// 使用os标志,来进行通讯,0表示使用内部提供的标志位
#define UART_USE_OS_FLAG (0)

// 静态分配方式; (0)表示动态分配方式
#define UART_BUF_STATIC_METHOD (1)
// 串口控制器个数
#ifndef UART_CONTROLLER_NUM
#define UART_CONTROLLER_NUM 1
#endif
#define BAUD_RATE_2400                  2400
#define BAUD_RATE_4800                  4800
#define BAUD_RATE_9600                  9600
#define BAUD_RATE_19200                 19200
#define BAUD_RATE_38400                 38400
#define BAUD_RATE_57600                 57600
#define BAUD_RATE_115200                115200
#define BAUD_RATE_230400                230400
#define BAUD_RATE_460800                460800
#define BAUD_RATE_500000                500000
#define BAUD_RATE_921600                921600
#define BAUD_RATE_2000000               2000000
#define BAUD_RATE_2500000               2500000
#define BAUD_RATE_3000000               3000000

#define DATA_BITS_5                     5
#define DATA_BITS_6                     6
#define DATA_BITS_7                     7
#define DATA_BITS_8                     8
#define DATA_BITS_9                     9

#define STOP_BITS_1                     0
#define STOP_BITS_2                     1
#define STOP_BITS_3                     2
#define STOP_BITS_4                     3

#define PARITY_NONE                     0
#define PARITY_ODD                      1
#define PARITY_EVEN                     2

#define SERIAL_FLOWCONTROL_CTSRTS     1
#define SERIAL_FLOWCONTROL_NONE       0

#define UART_FLAG_IT_TX    (1<<1)
#define UART_FLAG_IT_RX    (1<<2)
#define UART_FLAG_IT_TX_RX     (UART_FLAG_IT_TX|UART_FLAG_IT_RX)
#define UART_FLAG_DMA_TX    (1<<3)
#define UART_FLAG_DMA_RX    (1<<4)
#define UART_FLAG_DMA_TX_RX     (UART_FLAG_DMA_TX|UART_FLAG_DMA_RX)
/**
 * @brief 串口配置
 */
struct uart_configuration {
    uint32_t baud_rate;
    uint32_t data_bits: 4;
    uint32_t stop_bits: 2;
    uint32_t parity: 2;
    uint32_t flowcontrol: 1;
    uint32_t reserved: 23;
};
typedef struct stm32_uart_controller *uart_controller_t;

typedef void (*uart_rx_notify)(uart_controller_t controller, uint32_t size);

typedef void (*uart_tx_cpt_notify)(uart_controller_t controller);

/**
 * @brief 串口控制器结构体
 */
struct stm32_uart_controller {
    /*串口句柄*/
    UART_HandleTypeDef handle;
#if UART_USE_OS_FLAG

    TX_SEMAPHORE *tx_sem;
    TX_SEMAPHORE *rx_sem;
#else
    volatile uint32_t tx_sem_flag;
    volatile uint32_t rx_sem_flag;
#endif


    /* 通知回调函数 */
    uart_rx_notify rx_indicate;
    uart_tx_cpt_notify tx_complete;
    /* 缓冲区指针 */
    struct rt_ringbuffer *tx_buffer;
    struct rt_ringbuffer *rx_buffer;

};

void bsp_UartParDefaultSet(USART_TypeDef *uart);

void bsp_UartParSet(USART_TypeDef *uart, struct uart_configuration *configuration);

void bsp_UartParNotifySet(USART_TypeDef *uart, uart_rx_notify rx_notify, uart_tx_cpt_notify tx_cpt_notify);

void bsp_UartParSemSet(USART_TypeDef *uart, uint8_t rx_sem_flag, uint8_t tx_sem_flag);

void bsp_InitUart(USART_TypeDef *uart, uint16_t tx_size, uint16_t rx_size);

void bsp_DeInitUart(USART_TypeDef *uart);

uint16_t uart_read_data(USART_TypeDef *uart, uint8_t *data, uint16_t len);

uint16_t uart_write_data(USART_TypeDef *uart, uint8_t *data, uint16_t len);


#endif //TX_STM32_F4_DRV_UART_OS_H

源文件

/*
 * Copyright (c) 2024-2024,shchl
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2024-5-2     shchl   first version
 */
#include "drv_common.h"
#include "drv_uart_os.h"

#define SEM_NOTIFY_FLAG (1)
#define SET_UN_NOTIFY_FLAG (0)

// 串口索引检查
#define uart_idx_check(uart) do{idx = stm32_uart_controller_idx_get(uart);if (idx < 0 || idx >= UART_CONTROLLER_NUM) return;}while(0)

enum {
    UART1_IDX,
    UART2_IDX,
    UART3_IDX,
    UART4_IDX,
    UART5_IDX,
    UART6_IDX,
};
#if(UART_BUF_STATIC_METHOD)


#if(UART_CONTROLLER_NUM >= 1)

#define COM1_TX_LEN 2048
#define COM1_RX_LEN 2048


static uint8_t buf_0_tx[COM1_TX_LEN], buf_0_rx[COM1_RX_LEN];
static struct rt_ringbuffer ringbuffer_tx_0 = {.buffer_size=COM1_TX_LEN};
static struct rt_ringbuffer ringbuffer_rx_0 = {.buffer_size=COM1_RX_LEN};
#endif
#if(UART_CONTROLLER_NUM >= 2)
#define COM2_TX_LEN 1024
#define COM2_RX_LEN 1024
static uint8_t buf_1_tx[COM2_TX_LEN], buf_1_rx[COM2_RX_LEN];
static struct rt_ringbuffer ringbuffer_tx_1={.buffer_size=COM2_TX_LEN};
static struct rt_ringbuffer ringbuffer_rx_1={.buffer_size=COM2_RX_LEN};
#endif
#if(UART_CONTROLLER_NUM >= 3)
#define COM3_TX_LEN 1024
#define COM3_RX_LEN 1024
static uint8_t buf_2_tx[COM3_TX_LEN], buf_2_rx[COM3_RX_LEN];
static struct rt_ringbuffer ringbuffer_tx_2={.buffer_size=COM3_TX_LEN};
static struct rt_ringbuffer ringbuffer_rx_2={.buffer_size=COM3_RX_LEN};
#endif
#if(UART_CONTROLLER_NUM >= 4)

#define COM4_TX_LEN 1024
#define COM4_RX_LEN 1024
static uint8_t buf_3_tx[COM4_TX_LEN], buf_3_rx[COM4_RX_LEN];
static struct rt_ringbuffer ringbuffer_tx_3={.buffer_size=COM4_TX_LEN};
static struct rt_ringbuffer ringbuffer_rx_3={.buffer_size=COM4_RX_LEN};
#endif

static uint8_t *uart_static_buf[][4] = {
#define buf_item(tx, rx, tx_buf, rx_buf) (uint8_t *) &(tx),(uint8_t *)&(rx), tx_buf,rx_buf
#if(UART_CONTROLLER_NUM >= 1)
        {buf_item(ringbuffer_tx_0, ringbuffer_rx_0, buf_0_tx, buf_0_rx)},
#endif
#if(UART_CONTROLLER_NUM >= 2)
        {buf_item(ringbuffer_tx_1, ringbuffer_rx_1, buf_1_tx, buf_1_rx)},
#endif
#if(UART_CONTROLLER_NUM >= 3)
        {buf_item(ringbuffer_tx_2, ringbuffer_rx_2, buf_2_tx, buf_2_rx)},
#endif
#if(UART_CONTROLLER_NUM >= 4)
        {buf_item(ringbuffer_tx_3, ringbuffer_rx_2, buf_3_tx, buf_3_rx)},
#endif
};
#endif


static struct stm32_uart_controller controllers[UART_CONTROLLER_NUM] = {0};

/**
 * @brief 下标获取,每个串口对应唯一值(从0开始,默认是连续的)
 * @param uart
 * @return
 */
static inline int stm32_uart_controller_idx_get(USART_TypeDef *uart) {
#define idx_return(val) {return val;}
    switch ((uint32_t) uart) {
        case (uint32_t) USART1: idx_return(UART1_IDX)
        case (uint32_t) USART2: idx_return(UART2_IDX)
        case (uint32_t) USART3: idx_return(UART3_IDX)
        case (uint32_t) UART4: idx_return(UART4_IDX)
        case (uint32_t) UART5: idx_return(UART5_IDX)
        case (uint32_t) USART6: idx_return(UART6_IDX)
    }
#undef idx_return
    return -1;
}

static inline void stm32_uart_irq_enable_cnf(USART_TypeDef *uart) {

#define uart_irq_cnf(irq, pp, sp)  {HAL_NVIC_SetPriority(irq, pp, sp);HAL_NVIC_EnableIRQ(irq);}
    switch ((uint32_t) uart) {
        case (uint32_t) USART1: uart_irq_cnf(USART1_IRQn, 0, 0)
        case (uint32_t) USART2: uart_irq_cnf(USART2_IRQn, 0, 0)
        case (uint32_t) USART3: uart_irq_cnf(USART3_IRQn, 0, 0)
        case (uint32_t) UART4: uart_irq_cnf(UART4_IRQn, 0, 0)
        case (uint32_t) UART5: uart_irq_cnf(UART5_IRQn, 0, 0)
        case (uint32_t) USART6: uart_irq_cnf(USART6_IRQn, 0, 0)
    }
#undef uart_irq_cnf


}

static inline void stm32_uart_irq_disable_cnf(USART_TypeDef *uart) {
#define uart_irq_disable_cnf(irq)  {HAL_NVIC_DisableIRQ(irq);}
    switch ((uint32_t) uart) {
        case (uint32_t) USART1: uart_irq_disable_cnf(USART1_IRQn)
        case (uint32_t) USART2: uart_irq_disable_cnf(USART2_IRQn)
        case (uint32_t) USART3: uart_irq_disable_cnf(USART3_IRQn)
        case (uint32_t) UART4: uart_irq_disable_cnf(UART4_IRQn)
        case (uint32_t) UART5: uart_irq_disable_cnf(UART5_IRQn)
        case (uint32_t) USART6: uart_irq_disable_cnf(USART6_IRQn)
    }
#undef uart_irq_disable_cnf

}

/**
 * @brief 串口默认设置
 * @param uart
 */
void bsp_UartParDefaultSet(USART_TypeDef *uart) {
    struct uart_configuration default_cnf = {
            .baud_rate=BAUD_RATE_115200,
            .parity=PARITY_NONE,
            .data_bits=DATA_BITS_8,
            .flowcontrol=SERIAL_FLOWCONTROL_NONE,
            .stop_bits = STOP_BITS_1
    };
    bsp_UartParSet(uart, &default_cnf);
    bsp_UartParSemSet(uart, 1, 1);
}

/**
 * @brief 串口参数设置
 * @param uart 
 * @param configuration 
 */
void bsp_UartParSet(USART_TypeDef *uart, struct uart_configuration *cfg) {
    int idx;
    uart_idx_check(uart);
    if (cfg == NULL) return;
    controllers[idx].handle.Instance = uart;
    controllers[idx].handle.Init.BaudRate = cfg->baud_rate;
    controllers[idx].handle.Init.Mode = UART_MODE_TX_RX;
    controllers[idx].handle.Init.OverSampling = UART_OVERSAMPLING_16;
    // 参数配置
    {
        switch (cfg->flowcontrol) {
            case SERIAL_FLOWCONTROL_NONE:
                controllers[idx].handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
                break;
            case SERIAL_FLOWCONTROL_CTSRTS:
                controllers[idx].handle.Init.HwFlowCtl = UART_HWCONTROL_RTS_CTS;
                break;
            default:
                controllers[idx].handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
                break;
        }
        switch (cfg->data_bits) {
            case DATA_BITS_8:
                if (cfg->parity == PARITY_ODD || cfg->parity == PARITY_EVEN)
                    controllers[idx].handle.Init.WordLength = UART_WORDLENGTH_9B;
                else
                    controllers[idx].handle.Init.WordLength = UART_WORDLENGTH_8B;
                break;
            case DATA_BITS_9:
                controllers[idx].handle.Init.WordLength = UART_WORDLENGTH_9B;
                break;
            default:
                controllers[idx].handle.Init.WordLength = UART_WORDLENGTH_8B;
                break;
        }
        switch (cfg->stop_bits) {
            case STOP_BITS_1:
                controllers[idx].handle.Init.StopBits = UART_STOPBITS_1;
                break;
            case STOP_BITS_2:
                controllers[idx].handle.Init.StopBits = UART_STOPBITS_2;
                break;
            default:
                controllers[idx].handle.Init.StopBits = UART_STOPBITS_1;
                break;
        }
        switch (cfg->parity) {
            case PARITY_NONE:
                controllers[idx].handle.Init.Parity = UART_PARITY_NONE;
                break;
            case PARITY_ODD:
                controllers[idx].handle.Init.Parity = UART_PARITY_ODD;
                break;
            case PARITY_EVEN:
                controllers[idx].handle.Init.Parity = UART_PARITY_EVEN;
                break;
            default:
                controllers[idx].handle.Init.Parity = UART_PARITY_NONE;
                break;
        }
    }
}

/**
 * @brief 串口参数通知回调参数设置
 * @param uart 串口
 * @param rx_notify
 * @param tx_cpt_notify
 */
void bsp_UartParNotifySet(USART_TypeDef *uart, uart_rx_notify rx_notify, uart_tx_cpt_notify tx_cpt_notify) {
    int idx;
    uart_idx_check(uart);
    // 为了保证在任意时刻调用,进行中断禁用的方式
    TX_INTERRUPT_SAVE_AREA
    /* enter interrupt */
    TX_DISABLE
    controllers[idx].rx_indicate = rx_notify;
    controllers[idx].tx_complete = tx_cpt_notify;
    TX_RESTORE
}

/**
 * @brief 串口信号量设置
 * @param uart
 * @param rx_sem_flag 是否创建接收完成信号量
 * @param tx_sem_flag 是否创建发送完成信号量
 */
void bsp_UartParSemSet(USART_TypeDef *uart, uint8_t rx_sem_flag, uint8_t tx_sem_flag) {
    int idx;
    uart_idx_check(uart);
#if UART_USE_OS_FLAG
    if (tx_sem_flag) {
        controllers[idx].tx_sem = tx_malloc(sizeof(TX_SEMAPHORE));
        tx_semaphore_create(controllers[idx].tx_sem, "tx_sem", 1);
    }
    if (rx_sem_flag) {
        controllers[idx].rx_sem = tx_malloc(sizeof(TX_SEMAPHORE));
        tx_semaphore_create(controllers[idx].rx_sem, "rx_sem", 1);
    }
#else
    controllers[idx].tx_sem_flag = SET_UN_NOTIFY_FLAG;
    controllers[idx].rx_sem_flag = SET_UN_NOTIFY_FLAG;
#endif
}

/**
 * @brief 初始化串口对象(必须调用)
 * @param uart 串口
 * @param tx_size 发送缓冲区大小,0,表示使用阻塞模式
 * @param rx_size 接收数据缓冲区大小,0:表示使用阻塞模式
 */
void bsp_InitUart(USART_TypeDef *uart, uint16_t tx_size, uint16_t rx_size) {
    int idx;
    uart_idx_check(uart);
    void *buf;
    HAL_UART_Init(&(controllers[idx].handle));
    if (tx_size != 0 || rx_size != 0) {
        stm32_uart_irq_enable_cnf(uart); /*开启串口中断*/
    }
    if (tx_size != 0) {
#if UART_BUF_STATIC_METHOD
        controllers[idx].tx_buffer = (struct rt_ringbuffer *) uart_static_buf[idx][0];
        rt_ringbuffer_init(controllers[idx].tx_buffer, uart_static_buf[idx][2],
                           controllers[idx].tx_buffer->buffer_size);
#else
        controllers[idx].tx_buffer = tx_malloc(sizeof(struct rt_ringbuffer));
        buf = tx_malloc(tx_size);
        rt_ringbuffer_init(controllers[idx].tx_buffer, buf, tx_size);
#endif
    }
    if (rx_size != 0) {
#if UART_BUF_STATIC_METHOD
        controllers[idx].rx_buffer = (struct rt_ringbuffer *) uart_static_buf[idx][1];
        rt_ringbuffer_init(controllers[idx].rx_buffer, uart_static_buf[idx][3],
                           controllers[idx].rx_buffer->buffer_size);
#else
        controllers[idx].rx_buffer = tx_malloc(sizeof(struct rt_ringbuffer));
        buf = tx_malloc(tx_size);
        rt_ringbuffer_init(controllers[idx].rx_buffer, buf, rx_size);
#endif

        if (controllers[idx].handle.Init.Parity != UART_PARITY_NONE) {
            /* Enable the UART Parity Error Interrupt */
            __HAL_UART_ENABLE_IT(&controllers[idx].handle, UART_IT_PE);
        }
        /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
        __HAL_UART_ENABLE_IT(&controllers[idx].handle, UART_IT_ERR);
        /* Enable the UART Data Register not empty Interrupt */
        __HAL_UART_ENABLE_IT(&controllers[idx].handle, UART_IT_RXNE);
    }
}

/**
 * @brief 复位串口
 * @param uart
 */
void bsp_DeInitUart(USART_TypeDef *uart) {
    int idx;
    uart_idx_check(uart);
    if (controllers[idx].rx_buffer || controllers[idx].tx_buffer) {
        stm32_uart_irq_disable_cnf(uart);
    }
    HAL_UART_DeInit(&(controllers[idx].handle));
#if UART_BUF_STATIC_METHOD
#else
    if (controllers[idx].rx_buffer)tx_free(controllers[idx].rx_buffer);
    if (controllers[idx].tx_buffer)tx_free(controllers[idx].tx_buffer);
#endif
#if UART_USE_OS_FLAG
    if (controllers[idx].rx_sem) {
        tx_semaphore_delete(controllers[idx].rx_sem);
        tx_free(controllers[idx].rx_sem);
    }
    if (controllers[idx].tx_sem) {
        tx_semaphore_delete(controllers[idx].tx_sem);
        tx_free(controllers[idx].tx_sem);
    }
#endif
    memset(controllers + idx, 0, sizeof(struct stm32_uart_controller));
}

/**
 * @brief 读取数据
 * @param uart 串口
 * @param data 保存数据位置
 * @param len 读取数据长度
 * @return 实际读取数据长度(数据长度,以返回值为准)
 */
uint16_t uart_read_data(USART_TypeDef *uart, uint8_t *data, uint16_t len) {
    int idx;
    idx = stm32_uart_controller_idx_get(uart);
    if (idx < 0 || idx >= UART_CONTROLLER_NUM) return 0;
    if (controllers[idx].rx_buffer) {

        return rt_ringbuffer_get(controllers[idx].rx_buffer, data, len);

    }
    HAL_UART_Receive(&(controllers[idx].handle), data, len, HAL_MAX_DELAY);
    return len;
}

/**
 * @brief 写入数据(阻塞或中断方式,根据初始化的方式决定)
 * @param uart
 * @param data
 * @param len
 * @return
 */
uint16_t uart_write_data(USART_TypeDef *uart, uint8_t *data, uint16_t len) {
    int idx;
    idx = stm32_uart_controller_idx_get(uart);
    if (idx < 0 || idx >= UART_CONTROLLER_NUM) return 0;
    if (controllers[idx].tx_buffer) {
#if (UART_USE_OS_FLAG == 0)
        controllers[idx].tx_sem_flag = SEM_NOTIFY_FLAG;
#endif

        rt_ringbuffer_put(controllers[idx].tx_buffer, data, len);
//        HAL_UART_Transmit_IT(&controllers[idx].handle, data, len);
        __HAL_UART_ENABLE_IT(&(controllers[idx].handle), UART_IT_TXE);
#if UART_USE_OS_FLAG
        if (controllers[idx].tx_sem) {
            tx_semaphore_get((controllers[idx].tx_sem), TX_WAIT_FOREVER);
        } else {
            while (controllers[idx].handle.gState != HAL_UART_STATE_READY); /*使用hal库状态标识位来判断是否传输完成*/
        }
#else
        while (controllers[idx].tx_sem_flag != SEM_NOTIFY_FLAG) {
        }
#endif
    } else {
        HAL_UART_Transmit(&controllers[idx].handle, data, len, HAL_MAX_DELAY);
    }
    return len;
}


void USART1_IRQHandler(void) {
    TX_INTERRUPT_SAVE_AREA
    /* enter interrupt */
    TX_DISABLE
    HAL_UART_IRQHandler(&controllers[UART1_IDX].handle);
    /* leave interrupt */
    TX_RESTORE
}

void USART2_IRQHandler(void) {
    TX_INTERRUPT_SAVE_AREA
    /* enter interrupt */
    TX_DISABLE
    HAL_UART_IRQHandler(&controllers[UART2_IDX].handle);
    /* leave interrupt */
    TX_RESTORE
}

void USART3_IRQHandler(void) {
    TX_INTERRUPT_SAVE_AREA
    /* enter interrupt */
    TX_DISABLE
    HAL_UART_IRQHandler(&controllers[UART3_IDX].handle);
    /* leave interrupt */
    TX_RESTORE
}

HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart) {
    uint8_t pdata8bits;
    uint16_t pdata16bits;
    rt_size_t (*write_call)(struct rt_ringbuffer *rb, const rt_uint8_t *ptr, rt_uint32_t length);
    write_call = rt_ringbuffer_put;
    struct stm32_uart_controller *control = rt_container_of(huart, struct stm32_uart_controller, handle);
    // 判断是否数据已满,如果已满,换成覆盖数据函数
    if (rt_ringbuffer_data_len(control->rx_buffer) == control->rx_buffer->buffer_size) {
        write_call = rt_ringbuffer_put_force;
    }
    if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE)) {
        pdata16bits = (uint16_t) (huart->Instance->DR & (uint16_t) 0x01FF);
        write_call(control->rx_buffer, (const rt_uint8_t *) &pdata16bits, 2);
    } else {
        if ((huart->Init.WordLength == UART_WORDLENGTH_9B) ||
            ((huart->Init.WordLength == UART_WORDLENGTH_8B) && (huart->Init.Parity == UART_PARITY_NONE))) {
            pdata8bits = (uint8_t) (huart->Instance->DR & (uint8_t) 0x00FF);
        } else {
            pdata8bits = (uint8_t) (huart->Instance->DR & (uint8_t) 0x007F);
        }
        write_call(control->rx_buffer, (const rt_uint8_t *) &pdata8bits, 1);
    }
    uint32_t data_len = rt_ringbuffer_data_len(control->rx_buffer);
    if (data_len == control->rx_buffer->buffer_size) {
        // 通知接收缓冲区已满
#if UART_USE_OS_FLAG
        if (control->rx_sem) {
            tx_semaphore_put(control->rx_sem);
        }
#else
        control->rx_sem_flag = SEM_NOTIFY_FLAG;
#endif

    }
    if (data_len && control->rx_indicate) {
        control->rx_indicate(control, data_len);
    }

    return HAL_OK;
}

/**
  * @brief  Sends an amount of data in non blocking mode.
  * @param  huart  Pointer to a UART_HandleTypeDef structure that contains
  *                the configuration information for the specified UART module.
  * @retval HAL status
  */
HAL_StatusTypeDef UART_Transmit_IT(UART_HandleTypeDef *huart) {


    struct stm32_uart_controller *control = rt_container_of(huart, struct stm32_uart_controller, handle);
    /* Check that a Tx process is ongoing */
//    if (huart->gState == HAL_UART_STATE_BUSY_TX)
    {
#if 0
        static uint8_t tmp;
        if (rt_ringbuffer_getchar((control->tx_buffer), (rt_uint8_t *) &tmp)) {
            huart->Instance->DR = tmp;
        } else {
            __HAL_UART_DISABLE_IT(huart, UART_IT_TXE);
            __HAL_UART_ENABLE_IT(huart, UART_IT_TC);
        }
#else
        static uint16_t tmp;
        static uint8_t read_cnt;
        if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE)) {
            read_cnt = 2;
        } else {
            read_cnt = 1;
        }
        if (rt_ringbuffer_get(control->tx_buffer, (rt_uint8_t *) &tmp, read_cnt) == read_cnt) {

            huart->Instance->DR = read_cnt == 2
                                  ? (uint16_t) (tmp & (uint16_t) 0x01FF)
                                  : (uint8_t) (tmp & (uint8_t) 0x00FF);
        } else {
            __HAL_UART_DISABLE_IT(huart, UART_IT_TXE);
            __HAL_UART_ENABLE_IT(huart, UART_IT_TC);
        }
#endif
        return HAL_OK;
    }
//    else {
//        return HAL_BUSY;
//    }
}

/**
  * @brief  Tx 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_TxCpltCallback(UART_HandleTypeDef *huart) {
    struct stm32_uart_controller *control = rt_container_of(huart, struct stm32_uart_controller, handle);

    if (huart->hdmatx == NULL) { // 发送采用中断方式
#if UART_USE_OS_FLAG
        // 通知
        if (control->tx_sem) {
            tx_semaphore_put(control->tx_sem);
        }
#else
        control->tx_sem_flag = SEM_NOTIFY_FLAG;
#endif
        if (control->tx_complete) {
            control->tx_complete(control);
        }
    } else { // 发送采用dma的方式




    }


}

/**
  * @brief  Tx Half 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_TxHalfCpltCallback(UART_HandleTypeDef *huart) {
    /* Prevent unused argument(s) compilation warning */
    UNUSED(huart);
    /* NOTE: This function should not be modified, when the callback is needed,
             the HAL_UART_TxHalfCpltCallback could be implemented in the user file
     */
}

/**
  * @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->hdmarx != NULL) { // 使用DMA方式
    }
}

/**
  * @brief  Rx Half 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_RxHalfCpltCallback(UART_HandleTypeDef *huart) {
    /* Prevent unused argument(s) compilation warning */
    UNUSED(huart);
    /* NOTE: This function should not be modified, when the callback is needed,
             the HAL_UART_RxHalfCpltCallback could be implemented in the user file
     */
}

/**
  * @brief  UART error callbacks.
  * @param  huart  Pointer to a UART_HandleTypeDef structure that contains
  *                the configuration information for the specified UART module.
  * @retval None
  */
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) {
    /* Prevent unused argument(s) compilation warning */
    UNUSED(huart);
    // 重新开启接收
    struct stm32_uart_controller *control = rt_container_of(huart, struct stm32_uart_controller, handle);
    if (huart->hdmarx == NULL) {


#if UART_USE_OS_FLAG
        // 通知
        if (control->rx_sem) {
            tx_semaphore_put(control->rx_sem);
        }
#else
        control->rx_sem_flag = SEM_NOTIFY_FLAG;
#endif

        if (huart->Init.Parity != UART_PARITY_NONE) {
            /* Enable the UART Parity Error Interrupt */
            __HAL_UART_ENABLE_IT(huart, UART_IT_PE);
        }
        /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
        __HAL_UART_ENABLE_IT(huart, UART_IT_ERR);
        /* Enable the UART Data Register not empty Interrupt */
        __HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);
    }

    if (huart->hdmatx == NULL) {
#if UART_USE_OS_FLAG
        // 通知
        if (control->tx_sem) {
            tx_semaphore_put(control->tx_sem);
        }
#else
        control->tx_sem_flag = SEM_NOTIFY_FLAG;
#endif
    }

}

/**
  * @brief  UART Abort Complete callback.
  * @param  huart UART handle.
  * @retval None
  */
void HAL_UART_AbortCpltCallback(UART_HandleTypeDef *huart) {
    /* Prevent unused argument(s) compilation warning */
    UNUSED(huart);

    /* NOTE : This function should not be modified, when the callback is needed,
              the HAL_UART_AbortCpltCallback can be implemented in the user file.
     */
}

/**
  * @brief  UART Abort Complete callback.
  * @param  huart UART handle.
  * @retval None
  */
void HAL_UART_AbortTransmitCpltCallback(UART_HandleTypeDef *huart) {
    /* Prevent unused argument(s) compilation warning */
    UNUSED(huart);

    /* NOTE : This function should not be modified, when the callback is needed,
              the HAL_UART_AbortTransmitCpltCallback can be implemented in the user file.
     */
}

/**
  * @brief  UART Abort Receive Complete callback.
  * @param  huart UART handle.
  * @retval None
  */
void HAL_UART_AbortReceiveCpltCallback(UART_HandleTypeDef *huart) {
    /* Prevent unused argument(s) compilation warning */
    UNUSED(huart);

    /* NOTE : This function should not be modified, when the callback is needed,
              the HAL_UART_AbortReceiveCpltCallback can be implemented in the user file.
     */
}

/**
  * @brief  中断空闲方式和dma 空闲方式共用
  * @param  huart UART handle
  * @param  Size  Number of data available in application reception buffer (indicates a position in
  *               reception buffer until which, data are available)
  * @retval None
  */
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) {
    /* Prevent unused argument(s) compilation warning */
    UNUSED(huart);
    UNUSED(Size);

    /* NOTE : This function should not be modified, when the callback is needed,
              the HAL_UARTEx_RxEventCallback can be implemented in the user file.
     */
}



硬件初始化

//
// Created by shchl on 2024/3/11.
// 串口硬件初始化
#include "drv_common.h"
/**
  * @brief  UART MSP Init.
  * @param  huart  Pointer to a UART_HandleTypeDef structure that contains
  *                the configuration information for the specified UART module.
  * @retval None
  */
void HAL_UART_MspInit(UART_HandleTypeDef *huart) {
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    switch ((uint32_t) huart->Instance) {
        case (uint32_t) USART1:
            __HAL_RCC_USART1_CLK_ENABLE();
            __HAL_RCC_GPIOA_CLK_ENABLE();
            /**USART1 GPIO配置
           PA9 ------> USART1_TX
           PA10 ------> USART1_RX
           */
            GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_10;
            GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
            GPIO_InitStruct.Pull = GPIO_NOPULL;
            GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
            GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
            HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
            break;
        case (uint32_t) USART2:
            __HAL_RCC_USART2_CLK_ENABLE();
            /* Peripheral clock enable */
            __HAL_RCC_USART2_CLK_ENABLE();
            __HAL_RCC_GPIOA_CLK_ENABLE();
            /**USART2 GPIO Configuration
            PA2     ------> USART2_TX
            PA3     ------> USART2_RX
            */
            GPIO_InitStruct.Pin = GPIO_PIN_2 | GPIO_PIN_3;
            GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
            GPIO_InitStruct.Pull = GPIO_NOPULL;
            GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
            GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
            HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
            break;


        default:
            // todo 按理不会执行到此处
            break;
    }


}


测试

    // 设置串口
    bsp_UartParDefaultSet(USART1);
    // 静态分配,后面两个参数无效
    bsp_UartParSemSet(USART1,0,1);
    // 静态分配,后面两个参数无效
    bsp_InitUart(USART1, 2048, 2048);

结果(测试ok,方便移植)

在这里插入图片描述

说明

  1. 如果是裸机的话,只需要改动hal库源码,把对应的函数改成弱引用,由外部重写。并使用静态分配的方式和内部变量的标志位。
  2. 驱动依赖了一个缓冲数据结构体,将hal库内部的数据指针的部分替换为使用循环缓冲区进行存取,驱动只涉及到中断的方式,dma的方式,可通过对应的回调函数中进行添加(dma和中断共用一套回调函数,通过判断串口内部dma指针的引用是否为NULL进行推断使用的是中断还是dma方式即可)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1642126.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

qt嵌入并控制外部程序

一、流程 1、调用Window接口模拟鼠标&#xff0c;键盘事件 POINT point; LPPOINT lpppoint &point; GetCursorPos(lpppoint);//获取鼠标位置 SetCursorPos(point.x, point.y);//设置鼠标位置//鼠标左键按下 mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, poi…

.单链表.

单链表就是将所要求得的数据呈现在一条链上进行求解。(用一种链式结构存储数据&#xff0c;这种结构就称之为链表) 题目&#xff1a; 实现一个单链表&#xff0c;链表初始为空&#xff0c;支持三种操作&#xff1a; 向链表头插入一个数&#xff1b;删除第 k&#x1d458; 个插…

Mysql报错红温集锦(一)(ipynb配置、pymysql登录、密码带@、to_sql如何加速、触发器SIGNAL阻止插入数据)

一、jupyter notebook无法使用%sql来添加sql代码 可能原因&#xff1a; 1、没装jupyter和notebook库、没装ipython-sql库 pip install jupyter notebook ipython-sql 另外如果是vscode的话还需要安装一些相关的插件 2、没load_ext %load_ext sql 3、没正确的登录到mysql…

Hibernate入门学习

目录 1、ORM思想概述 2、自定义ORM框架 3、第一个Hibernate程序开发步骤&#xff08;重要&#xff09; 1&#xff09;下载完整包 2&#xff09;创建项目&#xff0c;导入所需jar包 3&#xff09;建立student表 4&#xff09;创建和student表对应的Student实体类 5&…

Sarcasm detection论文解析 |A2Text-Net:一种用于讽刺检测的新型深度神经网络

论文地址 论文地址&#xff1a;A2Text-Net: A Novel Deep Neural Network for Sarcasm Detection | IEEE Conference Publication | IEEE Xplore github:lliyuan1117/A2Text-Net (github.com) 论文首页 A2Text-Net&#xff1a;一种用于讽刺检测的新型深度神经网络 &#x1f4c5…

Gradle 进阶学习 之 build.gradle 文件

build.gradle 是什么&#xff1f; 想象一下&#xff0c;你有一个大型的乐高项目&#xff0c;你需要一个清单来列出所有的乐高积木和它们如何组合在一起。在软件开发中&#xff0c;build.gradle 就是这个清单&#xff0c;它告诉计算机如何构建&#xff08;组合&#xff09;你的软…

阿里低代码引擎学习记录

官网 一、关于设计器 1、从设计器入手进行低代码开发 设计器就是我们用拖拉拽的方法&#xff0c;配合少量代码进行页面或者应用开发的在线工具。 阿里官方提供了以下八个不同类型的设计器Demo&#xff1a; 综合场景Demo&#xff08;各项能力相对完整&#xff0c;使用Fusion…

掌握JavaScript面向对象编程核心密码:深入解析JavaScript面向对象机制对象概念、原型模式与继承策略全面指南,高效创建高质量、可维护代码

ECMAScript&#xff08;简称ES&#xff0c;是JavaScript的标准规范&#xff09;支持面向对象编程&#xff0c;通过构造函数模拟类&#xff0c;原型链实现继承&#xff0c;以及ES6引入的class语法糖简化面向对象开发。对象可通过构造函数创建&#xff0c;使用原型链共享方法和属…

16、ESP32 Web

Web 服务器具有移动响应能力&#xff0c;可以使用本地网络上的任何设备作为浏览器进行访问。 示例功能&#xff1a; 构建 Web 服务器控制连接到 ESP32 的 LED在本地网络的浏览器上输入 ESP32 IP 地址访问 Web 服务器通过单击 Web 服务器上的按钮&#xff0c;更改 LED 状态 //…

C#语言基础

一、复杂数据类型 1. 枚举 1.1 基本概念 1.1.1 枚举是什么 枚举是一个被命名的整型常量的集合&#xff0c;一般用它来表示状态、类型等等 1.1.2 申明枚举和申明枚举变量 申明枚举和申明枚举变量是两个概念 申明枚举&#xff1a;相当于是创建一个自定义的枚举类型 申明枚…

C#实战—代码实现收发文件智能化

在信息化的今天&#xff0c;收发电子文档几乎是每个朋友都要经历的事情。比如班级学委和班长需要收发作业&#xff0c;企业管理者需要收发工作文件。但是&#xff01;&#xff01;&#xff01; 每到要交结果时&#xff0c;往往会发现总会有一些人没有即使交上&#xff0c;50个…

【Leetcode每日一题】 综合练习 - 全排列 II(难度⭐⭐)(71)

1. 题目解析 题目链接&#xff1a;47. 全排列 II 这个问题的理解其实相当简单&#xff0c;只需看一下示例&#xff0c;基本就能明白其含义了。 2.算法原理 算法思路梳理 为了生成给定数组nums的全排列&#xff0c;同时避免由于重复元素导致的重复排列&#xff0c;我们可以遵…

面试中算法(2的整数次幂)

判断一个正整数是否是2的整数次幂&#xff08;如16是2的4次方&#xff0c;返回true;18不是2的整数次幂&#xff0c;则返回false&#xff09;&#xff0c;要求性能尽可能高。 使用一个整型变量&#xff0c;让它从1开始不断乘以2&#xff0c;将每一次乘2的结果和 目标整数进行比较…

【python的魅力】:教你如何用几行代码实现文本语音识别

文章目录 引言一、运行效果二、文本转换为语音2.1 使用pyttsx32.2 使用SAPI实现文本转换语音2.3 使用 SpeechLib实现文本转换语音 三、语音转换为文本3.1 使用 PocketSphinx实现语音转换文本 引言 语音识别技术&#xff0c;也被称为自动语音识别&#xff0c;目标是以电脑自动将…

【网站项目】社区互助平台

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

Object Desktop - Stardock 软件开发商系列套件

Windows 的一大优势在于可高度自定义&#xff0c;能让我们把它打造成一个最符合自己需求的工作和娱乐工具。 在桌面增强工具套件 Object Desktop 中&#xff0c;包含了 Stardock 旗下 10 款生产力和美化工具&#xff0c;可帮助我们打造出美观、实用、高效的 Windows 系统。 St…

Leetcode—163. 缺失的区间【简单】Plus

2024每日刷题&#xff08;126&#xff09; Leetcode—163. 缺失的区间 实现代码 class Solution { public:vector<vector<int>> findMissingRanges(vector<int>& nums, int lower, int upper) {int n nums.size();vector<vector<int>> an…

文件(夹)批量重命名数字、字母、日期、中文数字大写小写

首先&#xff0c;需要用到的这个工具&#xff1a; 度娘网盘 提取码&#xff1a;qwu2 蓝奏云 提取码&#xff1a;2r1z 目标是重命名下面5个文件&#xff08;也可以是文件夹等&#xff0c;任意&#xff09;&#xff0c;从大写中文数字“贰”开始 打开工具&#xff0c;找到“文…

SNR: Signal to Noise Ratio

https://www.xx.com/watch?vmyrZ_R6xIZA Fang, Y., Armin, A., Meredith, P. et al. Accurate characterization of next-generation thin-film photodetectors. Nature Photon 13, 1–4 (2019). https://doi.org/10.1038/s41566-018-0288-z Wang, F., Zhang, T., Xie, R. e…