UART + FIFO 实现中断发送与接收
UART + FIFO 实现中断发送与接收
思路
1.发送:
将数据写入发送FIFO中,并开启发送完成中断,若发送FIFO不为空则继续开启发送中断,直到数据发送完成。
2.接收:
初始化开启接收寄存器非空中断,再中断中将数据写入接收FIFO中。待用户处理。
FIFO 实现
FIFO 结构体 与 操作接口:
typedef struct bsp_fifo_ops bsp_fifo_ops_t;
typedef struct //fifo 信息结构体
{
const bsp_fifo_ops_t *ops; //ops
uint8_t *buff; //fifo 数据buff
volatile uint8_t is_full; //fifo 是否 满的标志位
volatile uint32_t max_length; //固定长度 fifo大小
volatile uint32_t read_index; //fifo 读位置
volatile uint32_t write_index; //fifo 写位置
} bsp_cycle_fifo_t;
struct bsp_fifo_ops
{
void (*clear)(bsp_cycle_fifo_t *hfifo); //清空fifo
uint8_t (*is_empty)(bsp_cycle_fifo_t *hfifo); //判断是否为空
uint32_t (*get_current_data_count)(bsp_cycle_fifo_t *hfifo); //获取当前fifo中的数据数量
uint8_t (*is_full)(bsp_cycle_fifo_t *hfifo); //判断是否为满
uint8_t (*push)(bsp_cycle_fifo_t *hfifo, uint8_t data); //向fifo中写入1个数据
uint8_t (*pop)(bsp_cycle_fifo_t *hfifo, uint8_t *data); //从fifo中取出1个数据
uint32_t (*push_n)(bsp_cycle_fifo_t *hfifo, uint8_t *data, uint32_t length); //向fifo中写入N个数据
uint32_t (*pop_n)(bsp_cycle_fifo_t *hfifo, uint8_t *buff, uint32_t length); //从fifo中取出N个数据
};
//初始化 fifo 接口
void bsp_fifo_init(bsp_cycle_fifo_t *hfifo, uint8_t *buff, uint32_t length);
FIFO 接口实现:
/**
* @brief fifo清空
*
* @param hfifo
* @return void
*/
__inline static void bsp_fifo_clear(bsp_cycle_fifo_t *hfifo)
{
memset(hfifo->buff, 0, hfifo->max_length);
hfifo->is_full = 0;
hfifo->read_index = 0;
hfifo->write_index = 0;
}
/**
* @brief 检查fifo是否为空
*
* @param hfifo 需要检查的fifo的句柄结构体
* @return uint8_t 0/1 0:非空 1:空
*/
__inline static uint8_t bsp_fifo_empty(bsp_cycle_fifo_t *hfifo)
{
if (hfifo->read_index == hfifo->write_index && hfifo->is_full == 0)
return 1;
else
return 0;
}
/**
* @brief 检查fifo是否为满
*
* @param hfifo 需要检查的fifo结构体
* @return uint8_t 0/1 0:非满 1:满
*/
__inline static uint8_t bsp_fifo_full(bsp_cycle_fifo_t *hfifo)
{
if (hfifo->read_index == hfifo->write_index && hfifo->is_full == 1)
return 1;
else
return 0;
}
/**
* @brief 获取fifo当前拥有的数据个数
*
* @param hfifo 需要检查的句柄结构体
* @return uint32_t 返回数据个数
*/
uint32_t bsp_fifo_get_current_data_count(bsp_cycle_fifo_t *hfifo)
{
uint32_t ret;
if (bsp_fifo_empty(hfifo))
return 0;
else if (bsp_fifo_full(hfifo))
return hfifo->max_length;
else
(hfifo->read_index < hfifo->write_index) ? (ret = hfifo->write_index - hfifo->read_index) : (ret = hfifo->max_length - hfifo->read_index + hfifo->write_index);
return ret;
}
/**
* @brief 将一个数据写入fifo中
*
* @param hfifo 要进行操作的fifo结构体
* @param data 要写入的数据
* @return uint8_t 返回写入是否成功, 成功 return 1, 失败 return 0
*/
uint8_t bsp_fifo_push(bsp_cycle_fifo_t *hfifo, uint8_t data)
{
uint32_t ret = 0;
if (hfifo->is_full == 1)
{
ret = 0; // fifo 满了
}
else
{
hfifo->buff[hfifo->write_index] = data;
hfifo->write_index++; //写入数据后 写位置加1
if ((hfifo->write_index % hfifo->max_length) == 0)
hfifo->write_index = 0; //若写位置为末尾则 置为初始位置 构成循环
if (hfifo->write_index == hfifo->read_index)
hfifo->is_full = 1; //写入后如果读写位置相等则满
ret = 1;
}
return ret;
}
/**
* @brief 从fifo中读取一个数据
*
* @param hfifo 要进行操作的fifo结构体
* @param data 读取数据的buff指针
* @return uint8_t 读取是否成功 0:失败 1:成功
*/
uint8_t bsp_fifo_pop(bsp_cycle_fifo_t *hfifo, uint8_t *data)
{
if (hfifo->read_index == hfifo->write_index && hfifo->is_full == 0) //说明空
{
return 0;
}
else
{
*data = hfifo->buff[hfifo->read_index]; //从读位置取一个数据
hfifo->read_index++; //改变读位置
if ((hfifo->read_index % hfifo->max_length) == 0) //若读的位置为末尾则置为 0
hfifo->read_index = 0;
hfifo->is_full = 0; //如果满 则置为非满
return 1;
}
}
/**
* @brief 将n个数据写入fifo中
*
* @param hfifo 要进行操作的句柄结构体
* @param data 要写入的数据buff指针
* @param length 写入长度
* @return uint32_t 返回写入成功个数
*/
uint32_t bsp_fifo_push_n(bsp_cycle_fifo_t *hfifo, uint8_t *data, uint32_t length)
{
uint32_t i = 0;
uint32_t ret = 0;
for (i = 0; i < length; i++)
{
if (bsp_fifo_push(hfifo, data[i]))
ret++;
else
return ret;
}
return ret;
}
/**
* @brief 从fifo中读取n个数据
*
* @param hfifo 要进行操作的句柄结构体
* @param buff 保存读取数据的buff指针
* @param length 读取长度
* @return uint32_t 读取成功的数据个数
*/
uint32_t bsp_fifo_pop_n(bsp_cycle_fifo_t *hfifo, uint8_t *buff, uint32_t length)
{
uint32_t i = 0;
uint32_t ret = 0;
if (length > hfifo->max_length)
length = hfifo->max_length;
if (length > bsp_fifo_get_current_data_count(hfifo))
length = bsp_fifo_get_current_data_count(hfifo);
for (i = 0; i < length; i++)
{
if (bsp_fifo_pop(hfifo, &buff[i]))
ret++;
else
;
}
return ret;
}
static const bsp_fifo_ops_t bsp_cycle_ops = //这个变量不可变
{
.clear = bsp_fifo_clear,
.is_empty = bsp_fifo_empty,
.get_current_data_count = bsp_fifo_get_current_data_count,
.is_full = bsp_fifo_full,
.push = bsp_fifo_push,
.pop = bsp_fifo_pop,
.push_n = bsp_fifo_push_n,
.pop_n = bsp_fifo_pop_n,
};
/**
* @brief fifo 结构体初始化,设置buff数组和fifo长度
*
* @param hfifo 操作的fifo的句柄结构体指针
* @param buff 此fifo使用的数据buff数组
* @param length 缓冲区长度
*/
void bsp_fifo_init(bsp_cycle_fifo_t *hfifo, uint8_t *buff, uint32_t length)
{
hfifo->ops = &bsp_cycle_ops; //赋值ops 必要
hfifo->buff = buff; //fifo 数据buff
hfifo->is_full = 0; //fifo设置为空
hfifo->max_length = length; //设置fifo最大长度
hfifo->read_index = 0; //读数据位置为0
hfifo->write_index = 0; //写数据位置为0
}
使用 FIFO 实现 UART 中断发送与接收(以STM32H7 HAL 库 为例)
串口接口:
#define BSP_ENABLE_RS485_CONTROL 0
typedef struct
{
UART_HandleTypeDef hal_huart;
bsp_cycle_fifo_t tx_fifo;
bsp_cycle_fifo_t rx_fifo;
uint8_t uart_tx_byte;
uint8_t uart_rx_byte;
#if BSP_ENABLE_RS485_CONTROL
void (*rs485_tx_enable)(void); // low
void (*rs485_rx_enable)(void); // high
#endif
} bsp_uart_config_t;
void bsp_hal_uart_init(bsp_uart_config_t *bsp_hsart);
uint32_t bsp_uart_send(bsp_uart_config_t *bsp_huart, uint8_t *buff, uint32_t length);
uint32_t bsp_uart_receive(bsp_uart_config_t *huart, uint8_t *buff, uint32_t length);
uint32_t bsp_uart_received_number(bsp_uart_config_t *huart);
#if BSP_ENABLE_RS485_CONTROL
void bsp_uart_rs485_tx_enable_register(bsp_uart_config_t *bsp_huart, void (*rs485_rx)(void));
void bsp_uart_rs485_rx_enable_register(bsp_uart_config_t *bsp_huart, void (*rs485_rx)(void));
#endif
接口实现:
void bsp_hal_uart_init(bsp_uart_config_t *bsp_huart)
{
if (bsp_huart == &bsp_huart1)
{
bsp_huart->hal_huart.Instance = USART1;
bsp_huart->hal_huart.Init.BaudRate = 115200;
bsp_huart->hal_huart.Init.WordLength = UART_WORDLENGTH_8B;
bsp_huart->hal_huart.Init.StopBits = UART_STOPBITS_1;
bsp_huart->hal_huart.Init.Parity = UART_PARITY_NONE;
bsp_huart->hal_huart.Init.Mode = UART_MODE_TX_RX;
bsp_huart->hal_huart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
bsp_huart->hal_huart.Init.OverSampling = UART_OVERSAMPLING_16;
bsp_huart->hal_huart.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
bsp_huart->hal_huart.Init.ClockPrescaler = UART_PRESCALER_DIV1;
bsp_huart->hal_huart.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&bsp_huart->hal_huart) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetTxFifoThreshold(&bsp_huart->hal_huart, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetRxFifoThreshold(&bsp_huart->hal_huart, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_DisableFifoMode(&bsp_huart->hal_huart) != HAL_OK)
{
Error_Handler();
}
}
}
/**
* @brief UART 初始化函数
*
* @param huart
*/
int uart_init(void)
{
bsp_hal_uart_init(&bsp_huart1);
bsp_fifo_init(&bsp_huart1.tx_fifo, uart1_tx_fifo_buff, UART1_TX_BUFF_LENGTH);
bsp_fifo_init(&bsp_huart1.rx_fifo, uart1_rx_fifo_buff, UART1_RX_BUFF_LENGTH);
HAL_UART_Receive_IT(&bsp_huart1.hal_huart, &bsp_huart1.uart_rx_byte, 1);
#if BSP_ENABLE_RS485_CONTROL
bsp_uart_rs485_rx_enable_register(&bsp_huart1, uart1_rs485_rx_enable);
bsp_uart_rs485_tx_enable_register(&bsp_huart1, uart1_rs485_tx_enable);
bsp_huart1.rs485_rx_enable();
#endif
return 0;
}
/**
* @brief uart 发送 接口
*
* @param bsp_huart 串口 bsp结构体
* @param buff 数据buff
* @param length 长度
* @return uint32_t 发送成功的长度
*/
uint32_t bsp_uart_send(bsp_uart_config_t *bsp_huart, uint8_t *buff, uint32_t length)
{
uint32_t ret = 0;
#if BSP_ENABLE_RS485_CONTROL
if (bsp_huart->rs485_tx_enable)
{
bsp_huart->rs485_tx_enable();
}
#endif
for (uint32_t i = 0; i < length; i++)
{
while (!(bsp_huart->tx_fifo.ops->push(&(bsp_huart->tx_fifo), buff[i]))) //if 写入不成功 则循环
{
if (0 == ((READ_REG(bsp_huart->hal_huart.Instance->CR1)) & USART_CR1_TCIE)) //如果写入时中断为启动则启动中断
{
bsp_huart->tx_fifo.ops->pop(&bsp_huart->tx_fifo, &bsp_huart->uart_tx_byte);
HAL_UART_Transmit_IT(&bsp_huart->hal_huart, &bsp_huart->uart_tx_byte, 1);
}
}
ret++;
}
if (0 == ((READ_REG(bsp_huart->hal_huart.Instance->CR1)) & USART_CR1_TCIE)) //如果写入时中断未启动
{
bsp_huart->tx_fifo.ops->pop(&bsp_huart->tx_fifo, &bsp_huart->uart_tx_byte);
HAL_UART_Transmit_IT(&bsp_huart->hal_huart, &bsp_huart->uart_tx_byte, 1); //启动中断
}
return ret;
}
/**
* @brief uart 接收
*
* @param bsp_huart 串口 bsp结构体
* @param buff 数据buff
* @param length 长度
* @return uint32_t 提取的数据长度
*/
uint32_t bsp_uart_receive(bsp_uart_config_t *bsp_huart, uint8_t *buff, uint32_t length) //从fifo中提取数据
{
uint32_t ret = 0;
ret = bsp_huart->rx_fifo.ops->pop_n(&bsp_huart->rx_fifo, buff, length);
return ret;
}
/**
* @brief 查看结构 fifo 中的数据个数
*
* @param bsp_huart
* @return uint32_t 接收fifo中的数据数量
*/
__inline uint32_t bsp_uart_received_number(bsp_uart_config_t *bsp_huart)
{
return bsp_huart->rx_fifo.ops->get_current_data_count(&bsp_huart->rx_fifo);
}
#if BSP_ENABLE_RS485_CONTROL
/**
* @brief uart1 rx 使能函数
*
*/
void uart1_rs485_rx_enable(void)
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
}
/**
* @brief uart1 tx 使能函数
*
*/
void uart1_rs485_tx_enable(void)
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
}
#endif
/**
* @brief 接收完成中断 回调函数
*
* @param huart hal层的 串口 结构体指针
*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
bsp_uart_config_t *bsp_huart = (bsp_uart_config_t *)huart;
bsp_huart->rx_fifo.ops->push(&(bsp_huart->rx_fifo), bsp_huart->uart_rx_byte);
HAL_UART_Receive_IT(&bsp_huart->hal_huart, &bsp_huart->uart_rx_byte, 1);
}
/**
* @brief 发送完成中断 回调函数
*
* @param huart hal层的 串口 结构体指针
*/
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
bsp_uart_config_t *bsp_huart = (bsp_uart_config_t *)huart;
if (!(bsp_huart->tx_fifo.ops->is_empty(&bsp_huart->tx_fifo)))
{
bsp_huart->tx_fifo.ops->pop(&bsp_huart->tx_fifo, &bsp_huart->uart_tx_byte);
HAL_UART_Transmit_IT(&bsp_huart->hal_huart, &bsp_huart->uart_tx_byte, 1);
}
else
{
#if BSP_ENABLE_RS485_CONTROL
if (bsp_huart->rs485_rx_enable)
{
bsp_huart->rs485_rx_enable();
}
#endif
}
}