Files
Leakage-Control/calib_board/usr/bsp/bsp_uart.c
2026-01-30 17:04:39 +08:00

490 lines
12 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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);
}
}