关于只开串口接收中断,完成数据分包,缓存到FIFO

博主用stm32的串口空闲中断分包,有概率出现了难以描述的bug,卡在串口中断服务函数中,出不来了,所以后续用了别的办法分包。
分包有两种,一种是时间间隔,一种是数据帧格式(如Modbus)。时间间隔,要根据实际一包数据的通信速度和数据长度去调整。

直接上,stm32串口初始化代码

#include "bsp_uart.h"

#define UART1_PORT			GPIOB
#define UART1_TX_PIN		GPIO_PIN_6
#define UART1_RX_PIN		GPIO_PIN_7

UART_HandleTypeDef  UART1_Handler;
uint8_t gUART1FIFO[256],Res;			// 最大一包数据长度256
volatile  uint8_t gUART1POS = 0;		// 一包数据长度
/**
  * @brief  UART1 IRQ Handler
  * @param  None
  * @retval None
  */
void USART1_IRQHandler(void)
{
	if((__HAL_UART_GET_FLAG(&UART1_Handler,UART_FLAG_RXNE)!=RESET))
	{
		HAL_UART_Receive(&UART1_Handler,&Res,1,10);		
		gUART1FIFO[gUART1POS] = Res;
		++gUART1POS;//没有数组越结判断,因为最大也就是255,不会溢出
	}	
	HAL_UART_IRQHandler(&UART1_Handler);
}

/**
  * @brief  UART1 initialize
  * @param  None
  * @retval None
  */
void BSP_UART1_Init(void)
{
	GPIO_InitTypeDef  GPIO_InitStruct;
	
	//Enable GPIO and USART clock
	__HAL_RCC_GPIOB_CLK_ENABLE();
	__HAL_RCC_USART1_CLK_ENABLE();
	
	//UART TX GPIO pin configuration
	GPIO_InitStruct.Pin       = UART1_TX_PIN | UART1_RX_PIN;
	GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
	GPIO_InitStruct.Pull      = GPIO_PULLUP;
	GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_HIGH;
	GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
	HAL_GPIO_Init(UART1_PORT, &GPIO_InitStruct);
	
	UART1_Handler.Instance        = USART1;
	UART1_Handler.Init.BaudRate   = 115200;
	UART1_Handler.Init.WordLength = UART_WORDLENGTH_8B;
	UART1_Handler.Init.StopBits   = UART_STOPBITS_1;
	UART1_Handler.Init.Parity     = UART_PARITY_NONE;
	UART1_Handler.Init.HwFlowCtl  = UART_HWCONTROL_NONE;
	UART1_Handler.Init.Mode       = UART_MODE_TX_RX;
	HAL_UART_Init(&UART1_Handler);
	
	__HAL_UART_ENABLE_IT(&UART1_Handler, UART_IT_RXNE);
	HAL_NVIC_SetPriority(USART1_IRQn,3,0);
	HAL_NVIC_EnableIRQ(USART1_IRQn);
}

/**
  * @brief  Send one character via UART1. used for printf().
  * @param  [in] ch: A character which to be sent.  
  * @param  [in] f: Point to a file.
  * @retval character to be sent.
  *			-1:  		fail.
  *			others:  	character to be sent.
  */
int fputc(int ch, FILE *f)
{
  HAL_UART_Transmit(&UART1_Handler, (uint8_t *)&ch, 1, 0xff);
  // while((USART1->SR&0X40)==0);//循环发送,直到发送完毕 
  // USART1->DR = (u8) ch; 
  return ch;
}

#define RINGBUFF_LEN 4096
#define PACKET_LEN 10

typedef struct
{
    uint16_t Head;           
    uint16_t Tail;
    uint8_t Ring_Buff[RINGBUFF_LEN];
}RingBuff_t;

RingBuff_t ringBuff = {0};
uint8_t r_index = 0;
uint8_t w_index = 0;
uint8_t count = 0;
uint16_t Packet_len[PACKET_LEN];

void Write_RingBuff(uint8_t *data,uint16_t len)
{	
	if(count >= 10) 
	{
		printf("the packet is full!\r\n");
		return ;
	} 
	uint8_t *p = data;	
	Packet_len[w_index] = len;
	if(++w_index >= PACKET_LEN) w_index = 0;
	uint16_t i;
	if(ringBuff.Tail + len < RINGBUFF_LEN)
	{	
		for(i = 0; i < len; ++i)
		{
			ringBuff.Ring_Buff[ringBuff.Tail] = *p;
			++ringBuff.Tail;
			++p;
		}
	}
	else
	{
		uint16_t size = RINGBUFF_LEN - ringBuff.Tail;	
		for(i = 0; i < size; ++i)
		{
			ringBuff.Ring_Buff[ringBuff.Tail] = *p;
			++ringBuff.Tail;
			++p;
		}
		ringBuff.Tail = 0;		
		for(i = size; i < len; ++i)
		{
			ringBuff.Ring_Buff[ringBuff.Tail] = *p;
			++ringBuff.Tail;
			++p;
		}
	}	
	++count;
}

int8_t Read_RingBuff(uint8_t *rData,uint16_t *len)
{
	if(count == 0) 
	{
		return -1;
	}
	uint8_t *p = rData;
	*len = Packet_len[r_index];
	if(++r_index >= PACKET_LEN) r_index = 0;
	uint16_t i;
	
	if(ringBuff.Head + *len < RINGBUFF_LEN)
	{		
		for(i = 0; i < *len; ++i)
		{
			*p = ringBuff.Ring_Buff[ringBuff.Head];
			++ringBuff.Head;
			++p;
		}	
	}	
	else
	{	
		uint16_t size = RINGBUFF_LEN - ringBuff.Head;		
		for(i = 0; i < size; ++i)
		{
			*p = ringBuff.Ring_Buff[ringBuff.Head];
			++ringBuff.Head;
			++p;
		}	
		ringBuff.Head = 0;
		for(i = size; i < *len; ++i)
		{
			*p = ringBuff.Ring_Buff[ringBuff.Head];
			++ringBuff.Head;
			++p;
		}
	}
	--count;
	return 0;
}

头文件

#ifndef __BSP_UART_H__
#define __BSP_UART_H__

#include <stdio.h>
#include "stm32l4xx.h"
#include "stm32l4xx_hal.h"

void BSP_UART1_Init(void);
extern volatile  uint8_t gUART1POS;
extern uint8_t gUART1FIFO[256];
void Write_RingBuff(uint8_t *data,uint16_t len);
int8_t Read_RingBuff(uint8_t *rData,uint16_t *len);
#endif 

那么怎么分包使用呢?二种办法。
第一种,相对间隔不太严格,但是简单。
在程序运行种,上操作系统的话,放到优先级高的任务。裸机最好就用第二种办法。
优先级高的任务,每100ms执行一次,如下

static void Priority_Thread(void *argument)
{
	while(1)
	{
		if(gUART1POS)
		{	
			Write_RingBuff(gUART1FIFO,gUART1POS);	
			gUART1POS = 0;	
		}
		osDelay(100);	
	}
}

分析数据包任务如下

static void Factory_Testing_Thread(void *argument)
{
	uint8_t uart1_rx_buff[200];
	uint16_t rx_len;
	for(;;)
	{
		if(0==Read_RingBuff(uart1_rx_buff,&rx_len))
		{	
			printf("%.*s\r\n",rx_len,uart1_rx_buff);
			//......
		}
	}
	osDelay(100);
}		
		

第二种是在串口服务函数中,开启一个别的定时器计数,每次进入串口服务函数将计数值清零,比如30ms超时,等没有数据接收时候,定时器的服务函数中去分包。
写个伪代码,定时器初始化好中断时间,flag 开始为1

void USART1_IRQHandler(void)
{
	//if(falg) 开启定时器6 flag = 0;
	if((__HAL_UART_GET_FLAG(&UART1_Handler,UART_FLAG_RXNE)!=RESET))
	{
		HAL_UART_Receive(&UART1_Handler,&Res,1,10);		
		gUART1FIFO[gUART1POS] = Res;
		++gUART1POS;//没有数组越结判断,因为最大也就是255,不会溢出
	}
	//定时器6的计数清零	
	HAL_UART_IRQHandler(&UART1_Handler);
}

void TIM6_IRQHandler(void)
{
	flag = 1;
	//关闭定时器6
	if(gUART1POS)
	{	
		Write_RingBuff(gUART1FIFO,gUART1POS);	
		gUART1POS = 0;	
	}
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值