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_FLAGTX_SEMAPHORE *tx_sem;TX_SEMAPHORE *rx_sem;
#elsevolatile 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 2048static 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};
#endifstatic 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
};
#endifstatic 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_returnreturn -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;elsecontrollers[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_DISABLEcontrollers[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_FLAGif (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);}
#elsecontrollers[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_METHODcontrollers[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);
#elsecontrollers[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_METHODcontrollers[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);
#elsecontrollers[idx].rx_buffer = tx_malloc(sizeof(struct rt_ringbuffer));buf = tx_malloc(tx_size);rt_ringbuffer_init(controllers[idx].rx_buffer, buf, rx_size);
#endifif (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
#elseif (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_FLAGif (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);}
#endifmemset(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;
#endifrt_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_FLAGif (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库状态标识位来判断是否传输完成*/}
#elsewhile (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_DISABLEHAL_UART_IRQHandler(&controllers[UART1_IDX].handle);/* leave interrupt */TX_RESTORE
}void USART2_IRQHandler(void) {TX_INTERRUPT_SAVE_AREA/* enter interrupt */TX_DISABLEHAL_UART_IRQHandler(&controllers[UART2_IDX].handle);/* leave interrupt */TX_RESTORE
}void USART3_IRQHandler(void) {TX_INTERRUPT_SAVE_AREA/* enter interrupt */TX_DISABLEHAL_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_FLAGif (control->rx_sem) {tx_semaphore_put(control->rx_sem);}
#elsecontrol->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 0static 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);}
#elsestatic 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);}
#endifreturn 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);}
#elsecontrol->tx_sem_flag = SEM_NOTIFY_FLAG;
#endifif (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);}
#elsecontrol->rx_sem_flag = SEM_NOTIFY_FLAG;
#endifif (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);}
#elsecontrol->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_TXPA10 ------> 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 ConfigurationPA2     ------> USART2_TXPA3     ------> 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.rhkb.cn/news/321387.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

开箱子咸鱼之王H5游戏源码_内购修复优化_附带APK完美运营无bug最终版__GM总运营后台_附带安卓版本

内容目录 一、详细介绍二、效果展示2.效果图展示 三、学习资料下载 一、详细介绍 1.包括原生打包APK&#xff0c;资源全部APK本地化&#xff0c;基本上不跑服务器宽带 2.优化后端&#xff0c;基本上不再一直跑内存&#xff0c;不炸服响应快&#xff01; 3.优化前端&#xff0c…

【再探】设计模式—适配器、装饰及外观模式

结构型设计模式是用于设计对象和类之间关系的一组设计模式。一共有7种&#xff1a;适配器模式、装饰器模式、外观模式、桥接模式、组合模式、享元模式及代理模式。 1 适配器模式 需求&#xff1a;在软件维护阶段&#xff0c;已存在的方法与目标接口不匹配&#xff0c;需要个中…

【DeepLearning.AI】吴恩达系列课程——使用ChatGPT API构建系统(持续更新中——)

目录 前言一、Language Models, the Chat Format and Tokens&#xff08;LLM&#xff0c;交互形式&#xff09;1-1、加载api-key1-2、使用辅助函数&#xff08;即指令调整LLM&#xff09;1-2、使用辅助函数&#xff08;聊天格式&#xff09;1-3、辅助函数修改&#xff08;输出字…

2024年船舶、机械制造与海洋科学国际会议(ICSEMMS2024)

2024年船舶、机械制造与海洋科学国际会议&#xff08;ICSEMMS2024&#xff09; 会议简介 我们诚挚邀请您参加将在重庆隆重举行的2024年国际造船、机械制造和海洋科学大会&#xff08;ICSEMMS024&#xff09;。作为一项跨学科和跨学科的活动&#xff0c;本次会议旨在促进造船…

北京大学-知存科技存算一体联合实验室揭牌,开启知存科技产学研融合战略新升级

5月5日&#xff0c;“北京大学-知存科技存算一体技术联合实验室”在北京大学微纳电子大厦正式揭牌&#xff0c;北京大学集成电路学院院长蔡一茂、北京大学集成电路学院副院长鲁文高及学院相关负责人、知存科技创始人兼CEO王绍迪、知存科技首席科学家郭昕婕博士及企业研发相关负…

深入Django:用户认证与权限控制实战指南

title: 深入Django&#xff1a;用户认证与权限控制实战指南 date: 2024/5/7 18:50:33 updated: 2024/5/7 18:50:33 categories: 后端开发 tags: AuthDecoratorsPermissionsGuardianRESTAuthSessionMgmtMFA 第1章&#xff1a;入门Django与设置 1.1 Django安装与环境配置 在…

大数据分析入门之10分钟掌握GROUP BY语法

前言 书接上回大数据分析入门10分钟快速了解SQL。 本篇将会进一步介绍group by语法。 基本语法 SELECT column_name, aggregate_function(column_name) FROM table_name GROUP BY column_name HAVING condition假设我们有students表&#xff0c;其中有id,grade_number,class…

Golang | Leetcode Golang题解之第70题爬楼梯

题目&#xff1a; 题解&#xff1a; func climbStairs(n int) int {sqrt5 : math.Sqrt(5)pow1 : math.Pow((1sqrt5)/2, float64(n1))pow2 : math.Pow((1-sqrt5)/2, float64(n1))return int(math.Round((pow1 - pow2) / sqrt5)) }

docker jenkins 部署springboot项目

1、创建jenkins容器 1&#xff0c;首先&#xff0c;我们需要创建一个 Jenkins 数据卷&#xff0c;用于存储 Jenkins 的配置信息。可以通过以下命令创建一个数据卷&#xff1a; docker volume create jenkins_data启动 Jenkins 容器并挂载数据卷&#xff1a; docker run -dit…

【区块链】智能合约简介

智能合约起源 智能合约这个术语至少可以追溯到1995年&#xff0c;是由多产的跨领域法律学者尼克萨博&#xff08;NickSzabo&#xff09;提出来的。他在发表在自己的网站的几篇文章中提到了智能合约的理念。他的定义如下&#xff1a;“一个智能合约是一套以数字形式定义的承诺&a…

上位机图像处理和嵌入式模块部署(树莓派4b镜像烧录经验总结)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 陆陆续续也烧录了好多次树莓派的镜像了&#xff0c;这里面有的时候很快&#xff0c;有的时候很慢。特别是烧录慢的时候&#xff0c;也不知道是自己…

基于FPGA的DDS波形发生器VHDL代码Quartus仿真

名称&#xff1a;基于FPGA的DDS波形发生器VHDL代码Quartus仿真&#xff08;文末获取&#xff09; 软件&#xff1a;Quartus 语言&#xff1a;VHDL 代码功能&#xff1a; DDS波形发生器VHDL 1、可以输出正弦波、方波、三角波 2、可以控制输出波形的频率 DDS波形发生器原理…

用Docker 创建并运行一个MySQL容器

可以在DockerHub官网上荡:mysql - Official Image | Docker Hub 指令是:docker pull mysql; 因为文件比较大可能时间比较长&#xff0c;我是跟着黑马的课走的 课程提供的有文件&#xff0c;我就用已有的资源了。 在tmp目录里放入mysql.tar包 然后cd进去 输入指令:docker lo…

STM32——WWDG(窗口看门狗)

技术笔记&#xff01; 1.WWDG&#xff08;窗口看门狗&#xff09;简介 本质&#xff1a;能产生系统复位信号和提前唤醒中断的计数器。 特性&#xff1a; 递减的计数器&#xff1b; 当递减计数器值从 0x40减到0x3F时复位&#xff08;即T6位跳变到0&#xff09;&#xff1b; …

FTP协议与工作原理

一、FTP协议 FTP&#xff08;FileTransferProtocol&#xff09;文件传输协议&#xff1a;用于Internet上的控制文件的双向传输&#xff0c;是一个应用程序&#xff08;Application&#xff09;。基于不同的操作系统有不同的FTP应用程序&#xff0c;而所有这些应用程序都遵守同…

update_min_vruntime()流程图

linux kernel scheduler cfs的update_min_vruntime() 看起来还挺绕的。含义其实也简单&#xff0c;总一句话&#xff0c;将 cfs_rq->min_vruntime 设置为&#xff1a; max( cfs_rq->vruntime, min(leftmost_se->vruntime, cfs_rq->curr->vruntime) )。 画个流…

超疏水TiO₂纳米纤维网膜的良好性能

超疏水TiO₂纳米纤维网膜是一种具有特殊性能的材料&#xff0c;它结合了TiO₂的光催化性能和超疏水表面的自清洁、防腐、防污等特性。这种材料在防水、自清洁、油水分离等领域具有广阔的应用前景。 制备超疏水TiO₂纳米纤维网膜的过程中&#xff0c;通过精确控制纺丝溶液的成分…

2010NOIP普及组真题 2. 接水问题

线上OJ&#xff1a; 一本通&#xff1a;http://ybt.ssoier.cn:8088/problem_show.php?pid1950 解法一、朴素模拟 核心思想&#xff1a; 朴素模拟&#xff1a; 1、先给每个b[i]水龙头分配一个人a[i]&#xff0c;b[i] 表示水龙头的剩余时间。同时标记该水龙头为 used 使用中 2…

深度学习之基于Resnet50卷积神经网络脊柱骨折CT影像图片诊断系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景 脊柱骨折是骨科中一种常见的损伤类型&#xff0c;准确的诊断对于患者的治疗和康复至关重要。传统的脊…

QT:小项目:登录界面 (下一个连接数据库)

一、效果图 登录后&#xff1a; 二、项目工程结构 三、登录界面UI设计 四主界面 四、源码设计 login.h #ifndef LOGIN_H #define LOGIN_H#include <QDialog>namespace Ui { class login; }class login : public QDialog {Q_OBJECTpublic:explicit login(QWidge…