STM32HAL库,无DMA的串口,实现不定长空闲中断

前言

项目上需要5个串口,于是选型了STM32F103RCTx,编写代码的时候发现UART5没有DMA,于是自己写了一个驱动,来模拟DMA串口不定长空闲中断接收(关于DMA空闲中断另外一篇博文有所描述:https://blog.csdn.net/tiantangmoke/article/details/94438536

CUBEMX配置

配置基本串口参数
在这里插入图片描述
打开中断
在这里插入图片描述

修改工程代码实现单字节接收中断

1、定义数据缓冲区
uint8_t RxUart5[1]; //单字节接收缓冲区
volatile uint16_t DMA_Usart5_RxSize=0;  //虚拟DMA缓冲区接收数据的大小
volatile uint8_t recv_end_flag=0;  //接收完成标志位
uint8_t RxDMABuf_5[RXBUF_5_SIZE];   //虚拟DMA缓冲区
volatile uint8_t RxBuf_5_LOCK = 0; //处理数据时锁定缓冲区标志位
uint8_t RxBuf_5[RXBUF_5_SIZE];     //待处理接收数据缓冲区
volatile uint16_t RxBufSize_5 = 0; //待处理接收数据缓冲区内接收数据的大小
volatile uint16_t Uart5_Idle_Cnt = 0;  //空闲计时计数
2、修改MX_UART5_Init

后面加上:
HAL_UART_Receive_IT(&huart5, (uint8_t*)RxUart5, 1);
__HAL_UART_ENABLE_IT(&huart5, UART_IT_RXNE);

RxUart5 是单字节接收的缓冲区

uint8_t RxUart5[1];

/* UART5 init function */
void MX_UART5_Init(void)
{

  huart5.Instance = UART5;
  huart5.Init.BaudRate = 115200;
  huart5.Init.WordLength = UART_WORDLENGTH_8B;
  huart5.Init.StopBits = UART_STOPBITS_1;
  huart5.Init.Parity = UART_PARITY_NONE;
  huart5.Init.Mode = UART_MODE_TX_RX;
  huart5.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart5.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart5) != HAL_OK)
  {
    Error_Handler();
  }
	
	HAL_UART_Receive_IT(&huart5, (uint8_t*)RxUart5, 1);
	__HAL_UART_ENABLE_IT(&huart5, UART_IT_RXNE);
	
}
3、修改HAL_UART_RxCpltCallback

HAL_UART_RxCpltCallback是一个虚函数,我们这里重定义,当接收到一个字节的时候,中断回调函数会调用这个虚函数

RxDMABuf_5这个是我们模拟DMA的缓冲区
每次接收到一个字节,就重置Uart5_Idle_Cnt,这个是空闲中断的计时,当为0则认为一帧接收完成,进而处理数据

//重定义虚函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef * huart)
{
	if(huart->Instance == UART5 && (RxBuf_5_LOCK == 0))
	{
		
		RxDMABuf_5[DMA_Usart5_RxSize] = RxUart5[0];
		DMA_Usart5_RxSize ++;
		Uart5_Idle_Cnt = 20; //20毫秒没有接收到数据认为接收完成
		
    

    HAL_UART_Receive_IT(&huart5, (uint8_t*)RxUart5, 1);
	}
}
4、处理空闲计数

这个函数处理2个东西,
一个是串口死机时复位,HAL的串口有时会出错,然后一直无反应,这样可以增加可靠性。
一个是空闲中断的虚拟判断。通过Uart5_Idle_Cnt的倒计时实现,Uart5_Idle_Cnt在每次接收一个字节的数据都会置位。长时间每接收到字节数据,将会触发处理数据。

static void Uart5_Reset()
{
	memset(&huart5,0,sizeof(UART_HandleTypeDef) );

	HAL_UART_MspDeInit(&huart5);	
	MX_UART5_Init();
}



void Uart_Reset_Idle_Task_1ms()
{
  if(huart5.ErrorCode != 0)
	{
		UartErrCnt ++;
		Uart5_Reset();

	}
	
	if(Uart5_Idle_Cnt > 0)
	{
		Uart5_Idle_Cnt --;
		if(Uart5_Idle_Cnt == 0)
		{
			RxBuf_5_LOCK = 1;  //防止这边正在传输数据,中断改变了数据
			RxBufSize_5 = DMA_Usart5_RxSize;
			
			memcpy(RxBuf_5,RxDMABuf_5,DMA_Usart5_RxSize);
			DMA_Usart5_RxSize = 0;
			RxBuf_5_LOCK = 0;
		}
	}
	
}
5、编写对外接口函数

所有数据都在后台处理好了,我们的应用软件只需简单调用这两个函数即可实现非阻塞式的收发数据。

uint16_t Uart_GetRxSize(UART_HandleTypeDef *huart,uint8_t *buf , uint16_t DstBufSize)
uint8_t Uart_SendData(UART_HandleTypeDef *huart,uint8_t *buf,uint16_t Size)

uint16_t Uart_GetRxSize(UART_HandleTypeDef *huart,uint8_t *buf , uint16_t DstBufSize)
{
	uint16_t Size = 0;

	if(huart->Instance == UART5)
	{

		if(RxBufSize_5 > 0)
		{
			Size = RxBufSize_5;
			if(DstBufSize <	RxBufSize_5)
					RxBufSize_5 = DstBufSize;
			memcpy(buf,RxBuf_5,RxBufSize_5);
			RxBufSize_5 = 0;
		}

	}
	return Size;
}

uint8_t Uart_SendData(UART_HandleTypeDef *huart,uint8_t *buf,uint16_t Size)
{

	if(Size == 0 )
		return 0;

	if(huart->Instance == UART5 &&  Size <TXBUF_5_SIZE )
	{
		HAL_UART_Transmit_IT(&huart5,buf,Size);
		return 1;
	}
	return 0;
}

收发数据示例

void UART5_TEST_10ms()
{

    uint8_t rxBuf[100] = {0};
    uint8_t rxSize = 0;

    rxSize = Uart_GetRxSize(DEBUG_UART,rxBuf,100);
    if(rxSize == 0)
        return;

    Uart_SendData(DEBUG_UART,rxBuf,(uint8_t)rxSize );
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值