IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 关于只开串口接收中断,完成数据分包,缓存到FIFO -> 正文阅读

[嵌入式]关于只开串口接收中断,完成数据分包,缓存到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 2550
#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;
volatile uint8_t count;
uint16_t Packet_len[PACKET_LEN];

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

int8_t Read_RingBuff(uint8_t *rData,uint16_t *len)
{
	if(count == 0) 
	{
		return -1;
	}
	*len = Packet_len[r_index];
	r_index = (r_index + 1) % PACKET_LEN;
	uint16_t i;
	for(i = 0; i < *len; i++)
	{
		*(rData + i) = ringBuff.Ring_Buff[ringBuff.Head];
		ringBuff.Head = (ringBuff.Head+1)%RINGBUFF_LEN;
	}
	--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;	
	}
}
  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-07-28 07:59:49  更:2021-07-28 08:00:41 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/5 19:32:11-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码