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

前言

  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方式即可)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

GDPU JavaWeb 猜字母游戏

他在对你重定向打卡的大饼与立即跳转到你面前的谎言之间反复横跳。 sendRedirect与forward sendRedirect与forward区别 sendRedirect用于将请求重定向到另一个资源&#xff0c;可以是同一个应用程序内的其他 Servlet&#xff0c;也可以是其他 Web 应用程序的资源&#xff0c;…

R语言数据探索与分析-运用时间序列预测模型对成都市API进行预测分析

一、研究背景 “绿水青山就是金山银山&#xff0c;要让绿水青山变成金山银山”让人们深刻的意识到环境的重要性。与此同时&#xff0c;由于现代生活水平的不断提高&#xff0c;所带来的环境污染也不断增多&#xff0c;空气以及环境的污染带来了越来越多的疾病&#xff0c;深刻…

基于node.js+css+html+mysql博客系统

博主介绍&#xff1a; 大家好&#xff0c;本人精通Java、Python、Php、C#、C、C编程语言&#xff0c;同时也熟练掌握微信小程序、Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我有丰富的成品Java、Python、C#毕设项目经验&#xff0c;能够为学生提供各类…

Docker 加持的安卓手机:随身携带的知识库(一)

这篇文章聊聊&#xff0c;如何借助 Docker &#xff0c;尝试将一台五年前的手机&#xff0c;构建成一个随身携带的、本地化的知识库。 写在前面 本篇文章&#xff0c;我使用了一台去年从二手平台购入的五年前的手机&#xff0c;K20 Pro。 为了让它能够稳定持续的运行&#xf…

Elasticsearch:对 Java 对象的 ES|QL 查询

作者&#xff1a;Laura Trotta ES|QL 是 Elasticsearch 引入的一种新的查询语言&#xff0c;它将简化的语法与管道操作符结合起来&#xff0c;使用户能够直观地推断和操作数据。官方 Java 客户端的新版本 8.13.0 引入了对 ES|QL 查询的支持&#xff0c;提供了一个新的 API&…

【简单介绍下Lisp的学习历程】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

【文献阅读】 The ITS Irregular Terrain Model(Longely-Rice模型)海上电波传播模型

前言 因为最近在做海上通信的一个项目&#xff0c;所以需要对海上的信道进行建模&#xff0c;所以才阅读到了这一篇文献&#xff0c;下面的内容大部分是我的个人理解&#xff0c;如有错误&#xff0c;请见谅。欢迎在评论区和我一起讨论。 Longely-Rice模型介绍 频率介于 20 …

深度学习:基于TensorFlow、Keras,使用长短期记忆神经网络模型(LSTM)对Microsoft股票进行预测分析

前言 系列专栏&#xff1a;机器学习&#xff1a;高级应用与实践【项目实战100】【2024】✨︎ 在本专栏中不仅包含一些适合初学者的最新机器学习项目&#xff0c;每个项目都处理一组不同的问题&#xff0c;包括监督和无监督学习、分类、回归和聚类&#xff0c;而且涉及创建深度学…

Python 植物大战僵尸

文章目录 效果图项目结构实现思路源代码 效果图 项目结构 实现思路 下面是代码的实现思路&#xff1a; 导入必要的库和模块&#xff1a;首先&#xff0c;我们导入了Python的os、time库以及pygame库&#xff0c;还有植物大战僵尸游戏中用到的各个植物和僵尸的类。 初始化游戏和…

基于Python的LSTM网络实现单特征预测回归任务(TensorFlow)

目录 一、数据集 二、任务目标 三、代码实现 1、从本地路径中读取数据文件 2、数据归一化 3、创建配置类&#xff0c;将LSTM的各个超参数声明为变量&#xff0c;便于后续使用 4、创建时间序列数据 5、划分数据集 6、定义LSTM网络 &#xff08;1&#xff09;创建顺序模…

【深度学习】第一门课 神经网络和深度学习 Week 4 深层神经网络

&#x1f680;Write In Front&#x1f680; &#x1f4dd;个人主页&#xff1a;令夏二十三 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd; &#x1f4e3;系列专栏&#xff1a;深度学习 &#x1f4ac;总结&#xff1a;希望你看完之后&#xff0c;能对…

G1 - 生成对抗网络(GAN)

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 目录 理论知识生成器判别器基本原理 环境步骤环境设置数据准备模型设计模型训练模型效果展示 总结与心得体会 理论知识 生成对抗网络&#xff08;Generative …

Jenkins流水线部署springboot项目

文章目录 Jenkins流水线任务介绍Jenkins流水线任务构建Jenkins流水线任务Groovy脚本Jenkinsfile实现 Jenkins流水线任务实现参数化构建拉取Git代码构建代码制作自定义镜像并发布 Jenkins流水线任务介绍 之前采用Jenkins的自由风格构建的项目&#xff0c;每个步骤流程都要通过不…

二维数组的鞍点(C语言)

一、鞍点解释&#xff1b; 鞍点就是该位置上的元素在该行上最大、在该列上最小&#xff1b; 二、N-S流程图&#xff1b; 三、运行结果&#xff1b; 四、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值&#xff…

Java_JVM_JVMs

JVM 官方文档说明文档目录 官方文档 JVM Specification 说明 以Java SE 17为标准 文档目录 2&#xff1a;JVM 结构 class文件数据类型 基本数据类型引用数据类型 运行时数据区 栈帧 其他内容 对象的表示浮点数运算特殊方法 初始化方法【实例、类】多态方法 3&#xff…

AI代理架构的发展:从单一到多代理系统的演进及其影响分析

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Python中无法pip的解决办法和pip的介绍

什么是pip&#xff1f; PIP是通用的Python包管理工具&#xff0c;提供了对 Python 包的查找、下载、安装、卸载、更新等功能。安装诸如Pygame、Pymysql、requests、Django等Python包时&#xff0c;都要用到pip。 注意&#xff1a;在Python3.4&#xff08;一说是3.6&#xff09…

自动化滇医通

###我已经将数据爬取出来### 现在开源集合大家的思路一起研究 &#xff08;请更换ip 以及 暂停时间 不然会提示违规操作&#xff09; 脚本读取预约信息后开始随机抢一家的&#xff0c;qiang方法里面请自行修改抓包数据参数&#xff01;&#xff01; 现在开源大家一起讨论 pyt…

富文本编辑器 iOS

https://gitee.com/klkxxy/WGEditor-mobile#wgeditor-mobile 采用iOS系统浏览器做的一款富文本编辑器工具。 原理就是使用WKWebView加载一个本地的一个html文件&#xff0c;从而达到编辑器功能的效果&#xff01; 由于浏览器的一些特性等&#xff0c;富文本编辑器手机端很难做…

【开源物联网平台】window环境下搭建调试监控设备环境

&#x1f308; 个人主页&#xff1a;帐篷Li &#x1f525; 系列专栏&#xff1a;FastBee物联网开源项目 &#x1f4aa;&#x1f3fb; 专注于简单&#xff0c;易用&#xff0c;可拓展&#xff0c;低成本商业化的AIOT物联网解决方案 目录 一、使用docker脚本部署zlmediakit 1.1 …