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
  }
}

  • 2
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值