#include "bsp_uart.h" #include "string.h" /* RS485控制宏定义 */ #define RS485_RX HAL_GPIO_WritePin(RS485_EN_GPIO_Port, RS485_EN_Pin, GPIO_PIN_SET) #define RS485_TX HAL_GPIO_WritePin(RS485_EN_GPIO_Port, RS485_EN_Pin, GPIO_PIN_SET) /* 缓冲收发区大小 */ #define RX_TEMP_BUFF_NUM (3000U) /* UART缓冲区大小定义 */ #define UART1_TX_LEN (3000U) #define UART1_RX_LEN (3000U) #define UART2_TX_LEN (3000U) #define UART2_RX_LEN (3000U) #define UART4_TX_LEN (3000U) #define UART4_RX_LEN (3000U) /* 全局缓冲区变量 */ u8 uart1_tx_buff[UART1_TX_LEN]; u8 uart1_rx_buff[UART1_RX_LEN]; u8 uart2_tx_buff[UART2_TX_LEN]; u8 uart2_rx_buff[UART2_RX_LEN]; u8 uart4_tx_buff[UART4_TX_LEN]; u8 uart4_rx_buff[UART4_RX_LEN]; u8 rx_temp_buff[RX_TEMP_BUFF_NUM]; /* 函数声明 */ static void bsp_uart_init(bsp_uart_t *p_uart); static void bsp_uart_send(bsp_uart_t *p_uart, u8 *p_data, u16 len); static void bsp_uart_rx_idle_int(bsp_uart_t *p_uart); static void bsp_uart_rx_time_increment(bsp_uart_t *p_uart, u16 time); static void bsp_uart_rx_task(bsp_uart_t *p_uart); static void bsp_uart_rx_time_start(bsp_uart_t *p_uart); static void bsp_uart_tx_dma_tc_int(bsp_uart_t *p_uart); static void bsp_uart_dma_send(bsp_uart_t *p_uart, u8 *p_data, u16 len); /* 外部HAL句柄声明 */ extern UART_HandleTypeDef huart1; extern UART_HandleTypeDef huart2; extern UART_HandleTypeDef huart4; extern DMA_HandleTypeDef hdma_usart1_rx; extern DMA_HandleTypeDef hdma_usart1_tx; extern DMA_HandleTypeDef hdma_usart2_rx; extern DMA_HandleTypeDef hdma_usart2_tx; extern DMA_HandleTypeDef hdma_uart4_rx; extern DMA_HandleTypeDef hdma_uart4_tx; /****************************************** * 结构体: com_uart1 * 功能: UART1控制实例 * 描述: 定义UART1的硬件参数和回调函数 *******************************************/ bsp_uart_t com_uart1 = { .rx_queue = queue(u8, UART1_RX_LEN), .uart = &huart1, .tx_dma = &hdma_usart1_tx, .rx_dma = &hdma_usart1_rx, .tx_dma_len = UART1_TX_LEN, .rx_dma_len = UART1_RX_LEN, .tx_addr = &uart1_tx_buff[0], .rx_addr = &uart1_rx_buff[0], .tx_dma_complete_flag = 1, .rx_time_over = 0, .relay.uart = NULL, .init = bsp_uart_init, .send = bsp_uart_send, .tx_dma_tc_int = bsp_uart_tx_dma_tc_int, .rx_idle_int = bsp_uart_rx_idle_int, .rx_time_increment_int = bsp_uart_rx_time_increment, .rx_data_analysis = NULL, .rx_task = bsp_uart_rx_task, }; /****************************************** * 结构体: com_uart2 * 功能: UART2控制实例 * 描述: 定义UART2的硬件参数和回调函数 *******************************************/ bsp_uart_t com_uart2 = { .rx_queue = queue(u8, UART2_RX_LEN), .uart = &huart2, .tx_dma = &hdma_usart2_tx, .rx_dma = &hdma_usart2_rx, .tx_dma_len = UART2_TX_LEN, .rx_dma_len = UART2_RX_LEN, .tx_addr = &uart2_tx_buff[0], .rx_addr = &uart2_rx_buff[0], .tx_dma_complete_flag = 1, .rx_time_over = 0, .relay.uart = &com_uart4, .init = bsp_uart_init, .send = bsp_uart_send, .tx_dma_tc_int = bsp_uart_tx_dma_tc_int, .rx_idle_int = bsp_uart_rx_idle_int, .rx_time_increment_int = bsp_uart_rx_time_increment, .rx_data_analysis = NULL, .rx_task = bsp_uart_rx_task, }; /****************************************** * 结构体: com_uart4 * 功能: UART4控制实例 * 描述: 定义UART4的硬件参数和回调函数 *******************************************/ bsp_uart_t com_uart4 = { .rx_queue = queue(u8, UART4_RX_LEN), .uart = &huart4, .tx_dma = &hdma_uart4_tx, .rx_dma = &hdma_uart4_rx, .tx_dma_len = UART4_TX_LEN, .rx_dma_len = UART4_RX_LEN, .tx_addr = &uart4_tx_buff[0], .rx_addr = &uart4_rx_buff[0], .tx_dma_complete_flag = 1, .rx_time_over = 0, .relay.uart = NULL, .init = bsp_uart_init, .send = bsp_uart_send, .tx_dma_tc_int = bsp_uart_tx_dma_tc_int, .rx_idle_int = bsp_uart_rx_idle_int, .rx_time_increment_int = bsp_uart_rx_time_increment, .rx_data_analysis = NULL, .rx_task = bsp_uart_rx_task, }; /****************************************** * 函数: bsp_uart_init * 功能: UART初始化 * 参数: p_uart - 指向UART结构体的指针 * 返回: 无 * 描述: 初始化UART,使能空闲中断和DMA接收 *******************************************/ static void bsp_uart_init(bsp_uart_t *p_uart) { /* 启用空闲中断 */ __HAL_UART_ENABLE_IT(p_uart->uart, UART_IT_IDLE); /* 重新启动接收,使用空闲中断模式 */ HAL_UARTEx_ReceiveToIdle_DMA(p_uart->uart, p_uart->rx_addr, p_uart->rx_dma_len); } /****************************************** * 函数: bsp_uart_dma_send * 功能: DMA发送函数 * 参数: p_uart - 指向UART结构体的指针 * p_data - 要发送的数据指针 * len - 要发送的数据长度 * 返回: 无 * 描述: 使用DMA发送数据,带有超时检测 *******************************************/ static void bsp_uart_dma_send(bsp_uart_t *p_uart, u8 *p_data, u16 len) { u32 tick_start, tick; p_uart->tx_dma_complete_flag = 0; /* 如果请求发送的长度大于缓冲区长度,则截断 */ if(p_uart->tx_dma_len < len) len = p_uart->tx_dma_len; /* 拷贝数据到发送缓冲区 */ memcpy(p_uart->tx_addr, p_data, len); /* 启动DMA发送 */ HAL_UART_Transmit_DMA(p_uart->uart, p_uart->tx_addr, len); /* 等待发送完成,带超时检测 */ tick_start = HAL_GetTick(); while(!p_uart->tx_dma_complete_flag) { tick = HAL_GetTick(); if((tick - tick_start) > 200) /* 200ms超时 */ { p_uart->tx_dma_complete_flag = 1; break; } } } /****************************************** * 函数: bsp_uart_send * 功能: UART发送函数 * 参数: p_uart - 指向UART结构体的指针 * p_data - 要发送的数据指针 * len - 要发送的数据长度 * 返回: 无 * 描述: 大数据量发送函数,支持分块发送 *******************************************/ static void bsp_uart_send(bsp_uart_t *p_uart, u8 *p_data, u16 len) { u16 i, send_num; /* RS485切换到发送模式 */ if(p_uart == &com_uart4) RS485_TX; /* 计算需要发送的次数 */ send_num = len / p_uart->tx_dma_len; /* 分块发送数据 */ for(i = 0; i < send_num; i++) { bsp_uart_dma_send(p_uart, &p_data[p_uart->tx_dma_len * i], p_uart->tx_dma_len); } /* 发送剩余数据 */ len -= p_uart->tx_dma_len * i; if(0 == len) { return; } else { bsp_uart_dma_send(p_uart, &p_data[p_uart->tx_dma_len * i], len); } } /****************************************** * 函数: bsp_uart_tx_dma_tc_int * 功能: DMA发送完成中断处理 * 参数: p_uart - 指向UART结构体的指针 * 返回: 无 * 描述: 在DMA发送完成中断中调用,设置发送完成标志 *******************************************/ static void bsp_uart_tx_dma_tc_int(bsp_uart_t *p_uart) { p_uart->tx_dma_complete_flag = 1; } /****************************************** * 函数: bsp_uart_rx_idle_int * 功能: 空闲中断处理 * 参数: p_uart - 指向UART结构体的指针 * 返回: 无 * 描述: 处理UART空闲中断,将接收到的数据存入队列 *******************************************/ static void bsp_uart_rx_idle_int(bsp_uart_t *p_uart) { u16 rx_length, i; /* 停止接收 */ HAL_UART_DMAStop(p_uart->uart); /* 计算接收到的数据长度 */ rx_length = p_uart->rx_dma_len - __HAL_DMA_GET_COUNTER(p_uart->rx_dma); /* 如果长度为0,直接返回 */ if (rx_length == 0) { return; } /* 将接收到的数据存入队列 */ for (i = 0; i < rx_length; i++) { queue_push_back(p_uart->rx_queue, (void *)&p_uart->rx_addr[i]); } /* 开始接收超时计时 */ bsp_uart_rx_time_start(p_uart); /* 重新启动接收 */ HAL_UARTEx_ReceiveToIdle_DMA(p_uart->uart, p_uart->rx_addr, p_uart->rx_dma_len); } /****************************************** * 函数: bsp_uart_rx_time_increment * 功能: 接收超时时间递增 * 参数: p_uart - 指向UART结构体的指针 * time - 增加的时间值 * 返回: 无 * 描述: 在中断中调用,递增接收超时计数器 *******************************************/ static void bsp_uart_rx_time_increment(bsp_uart_t *p_uart, u16 time) { /* 如果已经开始计数,则增加时间 */ if(1 == p_uart->rx_start_flag) { p_uart->rx_time_count += time; } } /****************************************** * 函数: bsp_uart_rx_time_start * 功能: 启动接收超时计时 * 参数: p_uart - 指向UART结构体的指针 * 返回: 无 * 描述: 开始接收超时计数 *******************************************/ static void bsp_uart_rx_time_start(bsp_uart_t *p_uart) { p_uart->rx_start_flag = 1; p_uart->rx_time_count = 0; } /****************************************** * 函数: bsp_uart_rx_time_stop * 功能: 停止接收超时计时 * 参数: p_uart - 指向UART结构体的指针 * 返回: 无 * 描述: 停止接收超时计数 *******************************************/ static void bsp_uart_rx_time_stop(bsp_uart_t *p_uart) { p_uart->rx_start_flag = 0; p_uart->rx_time_count = 0; } /****************************************** * 函数: bsp_uart_rx_task * 功能: UART接收任务 * 参数: p_uart - 指向UART结构体的指针 * 返回: 无 * 描述: 检查接收超时,处理接收到的数据帧 *******************************************/ static void bsp_uart_rx_task(bsp_uart_t *p_uart) { /* 检查是否超时,接收到一帧数据 */ if(p_uart->rx_time_over < p_uart->rx_time_count) { /* 获取队列中数据长度 */ p_uart->rx_len = queue_size(p_uart->rx_queue); /* 停止计时 */ bsp_uart_rx_time_stop(p_uart); /* 检查数据长度是否有效 */ if(p_uart->rx_len <= p_uart->rx_dma_len && (0 != p_uart->rx_len)) { /* 如果数据长度超过临时缓冲区大小,则清空队列 */ if(RX_TEMP_BUFF_NUM < p_uart->rx_len) { queue_clear(p_uart->rx_queue); } else { /* 从队列中取出数据到临时缓冲区 */ for(u16 i = 0; i < p_uart->rx_len; i++) { queue_pop(p_uart->rx_queue, &rx_temp_buff[i]); } /* 如果有数据解析函数,则调用解析函数 */ if(NULL != p_uart->rx_data_analysis) { p_uart->rx_data_analysis(rx_temp_buff, p_uart->rx_len, p_uart); } } } } } // 错误回调函数中处理ORE void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) { bsp_uart_t *p_uart = NULL; if (huart->Instance == USART1) { p_uart = &com_uart1; } else if (huart->Instance == USART2) { p_uart = &com_uart2; } else if (huart->Instance == UART4) { p_uart = &com_uart4; } // 检查具体错误类型 if(huart->ErrorCode & HAL_UART_ERROR_NE) { // 处理噪声错误 __HAL_UART_CLEAR_NEFLAG(huart); } if(huart->ErrorCode & HAL_UART_ERROR_FE) { // 处理帧错误 __HAL_UART_CLEAR_FEFLAG(huart); } // 其他错误处理... if (__HAL_UART_GET_FLAG(huart, UART_FLAG_ORE) != RESET) { __HAL_UART_CLEAR_OREFLAG(huart); // 清除ORE标志 } if (__HAL_UART_GET_FLAG(huart, UART_FLAG_FE) != RESET) { __HAL_UART_CLEAR_FEFLAG(huart); // 清除ORE标志 } // if(p_uart != NULL) { // HAL_UART_DeInit(huart); // HAL_UART_Init(huart); // HAL_UART_DMAStop(p_Uart->Uart); HAL_UARTEx_ReceiveToIdle_DMA(p_uart->uart, p_uart->rx_addr, p_uart->rx_dma_len); } } // 实现空闲中断回调 void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) { if (huart->Instance == USART1) { bsp_uart_rx_idle_int(&com_uart1); } else if (huart->Instance == USART2) { bsp_uart_rx_idle_int(&com_uart2); } else if (huart->Instance == UART4) { bsp_uart_rx_idle_int(&com_uart4); } } /* 串口接收完成回调函数 - 处理空闲中断 */ void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { // if (__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE)) // { // __HAL_UART_CLEAR_IDLEFLAG(huart); // if (huart->Instance == USART1) // { // bsp_Uart_Rx_IdleInt(&COM_Uart1); // } // else if (huart->Instance == USART2) // { // bsp_Uart_Rx_IdleInt(&COM_Uart2); // } // else if (huart->Instance == UART4) // { // bsp_Uart_Rx_IdleInt(&COM_Uart4); // } // } } void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) { if (huart->Instance == USART1) { bsp_uart_tx_dma_tc_int(&com_uart1); } else if (huart->Instance == USART2) { bsp_uart_tx_dma_tc_int(&com_uart2); } else if (huart->Instance == UART4) { bsp_uart_tx_dma_tc_int(&com_uart2); } }