STM32单片机串口数据接收处理框架

在使用STM32单片机串口接收不固定长度数据包时,采用了每个字节中断,然后接收存储的方式,前面一直会有错误,尤其是波特率比较高(可能相对于该款单片机的主频,其他中断任务过多),甚至到后面没法接收到数据的情况。所以,修改整理了串口处理流程如下,以备后面需要时套用框架:

1 初始化

...
	MX_USART4_UART_Init();
	if (huart4.gState == HAL_UART_STATE_READY)HAL_UART_Receive_IT(&huart4, &rec_ch_uart4,1);
	_cdcCmd.rawVal=0;
...
static void MX_USART4_UART_Init(void)
{
  huart4.Instance = USART4;
  huart4.Init.BaudRate = 57600; 
  huart4.Init.WordLength = UART_WORDLENGTH_8B;
  huart4.Init.StopBits = UART_STOPBITS_1;
  huart4.Init.Parity = UART_PARITY_NONE;
  huart4.Init.Mode = UART_MODE_TX_RX;
  huart4.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart4.Init.OverSampling = UART_OVERSAMPLING_16;
  huart4.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  huart4.Init.ClockPrescaler = UART_PRESCALER_DIV1;
  huart4.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  if (HAL_UART_Init(&huart4) != HAL_OK)
  {
    Error_Handler();
  }

}

MX_USART4_UART_Init(void)是设置后参数后,CubeMX自动生成的

2 错误处理中断回调函数重载

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{

    if (huart->Instance == USART4) {  
    	if (huart->ErrorCode & HAL_UART_ERROR_ORE) {
    	        // 处理溢出错误
    	        __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_OREF);
    	    }
    	    if (huart->ErrorCode & HAL_UART_ERROR_FE) {
    	        // 处理帧错误
    	        __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_FEF);
    	    }
    	HAL_UART_AbortReceive(&huart4); // 重启接收
        HAL_UART_Receive_IT(&huart4, &rec_ch_uart4,1);
    }
}

3 接收中断回调重载

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
	if(huart->Instance == USART4){
		if(rec_counter_uart4<MAX_LEN_USART4){
			Uart4_RxBuffer[rec_counter_uart4]=rec_ch_uart4;
			rec_counter_uart4++;
			usartIdleCounter=UsartIdleMax; 
		}
		if (huart4.gState == HAL_UART_STATE_READY) HAL_UART_Receive_IT(&huart4, &rec_ch_uart4,1);
	}
}

保存收到的字节到缓存区,重启接收(1字节中断)
usartIdleCounter计数变成10(或20)ms

4 ms中断处理(systick)

void _embed_ms_loop()
{
	msCounter++;
	if(msCounter>=1000)
	{
		if(TTL)
		{
			_cdcCmd.bits.ReportStateCmd=1;
			TTL--;
		}else{
			TTL=20;  //Only for debug
		}
		msCounter=0;
	}
	if(usartIdleCounter)
	{
		usartIdleCounter--;
	}else{
		_cdcCmd.bits.PackageReady=1;
	}
}

如果usartIdleCounter减到0,说明有段时间没有收到字节了,可以处理缓存区里的包

5 主循环

void baidu_interface_embed_main_loop()
{
	if(_cdcCmd.bits.PackageReady)
	{
		parseCDCPackage();
		_cdcCmd.bits.PackageReady=0;
	}
	if(_cdcCmd.bits.SetExtrasCmd)
	{
		SetSurcharge();
		_cdcCmd.bits.SetExtrasCmd=0;
	}
	if(_cdcCmd.bits.ReportStateCmd)
	{
		toCDC_reportState();
		_cdcCmd.bits.ReportStateCmd=0;
	}
	if(_cdcCmd.bits.SimpleRspCmd)
	{
		Respond2Cmd(RspCmd,RspErrCode);
		_cdcCmd.bits.SimpleRspCmd=0;
	}
	if(_cdcCmd.bits.SetRtcCmd)
	{
		rtc_set();
		_cdcCmd.bits.SetRtcCmd=0;
	}

}

所有任务主体都在主循环里处理,中断里面只是做些命令置位、清零、缓存、计数等动作以避免长时间在中断内执行。

解析包子函数

void parseCDCPackage()  
{
	uint8_t packageLen;
	if(	rec_counter_uart4>6)  //7 is the least length of a package
	{
		if((Uart4_RxBuffer[0]==0xFF) && (Uart4_RxBuffer[1]==0xCD)) //Correct Header and device
		{
			packageLen=Uart4_RxBuffer[3]+7;
			if(rec_counter_uart4>=packageLen)// enough length.
			{
					//copy package
					memcpy(packageBuff,(unsigned char*)(&Uart4_RxBuffer[2]),Uart4_RxBuffer[3]+2);
					//check CRC and tail byte
					uint8_t ucReadCRC_L=Uart4_RxBuffer[Uart4_RxBuffer[3]+4];
					uint8_t ucReadCRC_H=Uart4_RxBuffer[Uart4_RxBuffer[3]+5];
					uint16_t ReadCRC = ((uint16_t)ucReadCRC_H<< 8)+ ucReadCRC_L;
					uint16_t calc_CRC=Get_CRC(packageBuff,Uart4_RxBuffer[3]+2);
					if(calc_CRC==ReadCRC && Uart4_RxBuffer[Uart4_RxBuffer[3]+6]==0xEF)
					{
						UseCOMData(packageBuff,Uart4_RxBuffer[3]+2);//apply the command;
					}
			}
		}
		rec_counter_uart4=0; //clear buffer
	}
	else
	{
		HAL_UART_AbortReceive(&huart4); // 重启接收
		HAL_UART_DeInit(&huart4);
		HAL_UART_Init(&huart4);
		rec_counter_uart4=0; //clear buffer
		HAL_UART_Receive_IT(&huart4, &rec_ch_uart4,1);
	}
	usartIdleCounter=250;
}

解析完一个包后,把usartIdleCounter设置为大些(根据需要),那么长时间接收不到包,也会重启串口模块。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

code .

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值