STM32开发 数据包环形队列

2023-05-16

目录

  • 前言
  • 一、构建环形队列结构体
  • 二、队列初始化
  • 三、读写数据
    • 1、队列满判断
    • 2、队列空判断
    • 3、队列写入数据
    • 4、队列读取数据
  • 四、实际使用


前言

环形队列的理论知识网上有很多文章,这里我就仅通过代码分享一下使用经验,在我的驱动中,队列内容是一包一包的待处理数据包,而不是一个个的字节。


一、构建环形队列结构体

队列中头部位置和尾部位置的指示是必须的,另外为了使用方便,加入数据包计数cnt,写入一包数据时cnt++,读取一包数据时cnt–,需要判断队列空或满时,就看cnt是否为0或最大值。
*注意:因为在驱动中,队列中放置的是一包一包的待处理数据包,所以又加入了每个数据包的有效长度lenth,读取到数据包后,还返回此包的数据长度。

首先需要定义队列大小:队列中最多存放多少数据包、单包的最大长度
//队列中数据包个数最大值:64包
#define Queue_Packet_MaxNumber	64
//队列中单包最大长度
#define Queue_Packet_MaxLenth	256

//定义队列结构体
typedef struct{
	int front;		//队列当前头位置
	int rear;		//队列当前尾位置
	int	counter;	//队列数据包计数
	uint8_t  data[Queue_Packet_MaxNumber][Queue_Packet_MaxLenth];	//存放数据包内容
	uint16_t lenth[Queue_Packet_MaxNumber];							//数据包对应的长度
}xQueue_Typedef;

二、队列初始化

1.定义一个队列

//串口接收队列
xQueue_Typedef Usart_Receive_Queue;

//初始化一个队列
void xQueue_Init(xQueue_Typedef *Queue)
{	
	Queue->front=0;
	Queue->rear=0;
	Queue->counter=0;
	memset(&Queue->data[0][0],0,Queue_Packet_MaxLenth*Queue_Packet_MaxNumber);
}

2.队列初始化,调用上面的函数即可,会把传入的队列清空

xQueue_Init(&Usart_Receive_Queue);

三、读写数据

1、队列满判断

读取队列内容前,要先判断队列是否为空,如果为空,读取失败。
队列写入数据前,要先判断队列是否已满,如果已满,写入失败。

//队列满判断
//返回:1:队列已满、0:队列未满
uint8_t xQueue_FullJudge(xQueue_Typedef *Queue)
{
	//队列中数据包个数已为最大值,队列已满
	if(Queue->counter==Queue_Packet_MaxNumber)
	{
		return 1;
	}else
	{
		return 0;
	}
}

2、队列空判断

//队列空判断
//返回:1:队列已空、0:队列未空
uint8_t xQueue_EmptyJudge(xQueue_Typedef *Queue)
{
	if(Queue->counter==0)
	{
		return 1;
	}else
	{
		return 0;
	}
}

3、队列写入数据

//存入一包数据
//返回0:队列已满,写入失败、返回1:写入成功
//函数内部不判断写入的长度是否会超过单包最大值,调用函数前应该自行判断
uint8_t xQueue_WriteData(xQueue_Typedef *Queue,uint8_t *Data,uint16_t Lenth)
{
	//判断是否为满
	if(xQueue_FullJudge(Queue))
	{
		return 0;
	}else
	{
		//队列当前数据量++
		Queue->counter++;	
		//写入一包数据
		memcpy(&Queue->data[Queue->rear][0],&Data[0],Lenth);
		//记录此包数据的长度
		Queue->lenth[Queue->rear]=Lenth;
		//包尾位置++
		Queue->rear=(Queue->rear+1)%Queue_Packet_MaxNumber;
		return 1;
	}
}

4、队列读取数据

//读出一包数据
//返回0:队列为空,读取失败、返回非0:读取的数据包长度
uint16_t xQueue_ReadData(xQueue_Typedef *Queue,uint8_t *Data)
{
	uint16_t Lenth;
	//判断是否为空
	if(xQueue_EmptyJudge(Queue))
	{
		return 0;
	}else
	{
		//当前数据量--
		Queue->counter--;
		//此包长度
		Lenth=Queue->lenth[Queue->front];	
		//读出一包数据
		memcpy(&Data[0],&Queue->data[Queue->front][0],Lenth);
		//包头位置++
		Queue->front=(Queue->front+1)%Queue_Packet_MaxNumber;
		return Lenth;
	}
}

四、实际使用

后续有时间了更新一篇STM32串口使用总结:CubeMX配置、接收中断逐字节处理、空闲中断整包处理、空闲中断+DMA接收、串口阻塞发送与DMA发送等等

//定义队列
xQueue_Typedef Usart_Receive_Queue;

int main()
{
	/* code begin*/
	
	//数据队列初始化
	xQueue_Init(&Usart_Receive_Queue);

	/* code end*/

	return 0;
}

//串口1中断服务程序
void USART1_IRQHandler(void)                	
{
	HAL_UART_IRQHandler(&UART1_Handler);
	//空闲中断到
	if(__HAL_UART_GET_FLAG(&UART1_Handler,UART_FLAG_IDLE) != RESET)
	{
		//清中断
		__HAL_UART_CLEAR_IDLEFLAG(&UART1_Handler);	
		//DMA停止
		HAL_UART_DMAStop(&UART1_Handler);

		//获取数据包长度
		Receive_Frame_Len_Usart=RECEIVE_MAX_LENTH-__HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
		//写入队列,Receive_Buff_Usart是接收的缓冲区,写入队列时没有判断长度
		xQueue_WriteData(&Usart_Receive_Queue,Receive_Buff_Usart,Receive_Frame_Len_Usart);
		
		//重新指定DMA接收的缓冲区
		HAL_UART_Receive_DMA(&UART1_Handler,Receive_Buff_Usart,RECEIVE_MAX_LENTH);		
	}
}

//处理数据
int UnpackModule_Periodic_Handle()
{
	uint8_t Data[Queue_Packet_MaxLenth];
	uint16_t Lenth;
	
	/*code begin*/
	
	//读取队列中的数据
	Lenth=xQueue_ReadData(&Usart_Receive_Queue,Data);
	//长度非0,内容有效
	if(Lenth)
	{
		//判断包头包尾
		if(Data[0] != 0x55 || Data[Lenth-] != 0xAA)
		{
			return 0;
		}

		switch(Data[2])
		{
			default:break;
		}
	}

	/* code end*/
	
	return 0;
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32开发 数据包环形队列 的相关文章

  • 处理器指令周期执行时间

    我的猜测是 no operation 内在 ARM 指令应花费 1 168 MHz 来执行 前提是每个NOP在一个时钟周期内执行 我想通过文档验证这一点 有关处理器指令周期执行时间的信息是否有标准位置 我试图确定 STM32f407IGh6
  • 如何更改闪存的起始地址?

    我正在使用 STM32F746ZG 和 FreeRTOS Flash的起始地址是0x08000000 但我想把它改成0x08040000 我通过谷歌搜索了这个问题 但没有找到解决方案 我更改了链接器脚本 如下所示 MEMORY RAM xr
  • c项目makefile多重定义错误

    这个问题是一个对应于创建的repexthis问题 在我的嵌入式 C 项目中 我有两个独立的板 我想为每个板创建两个 c 文件 master c 和 Slave c 其中包含自己的特定main 功能 我使用 stm32cumbemx 生成带有
  • 在 MCU 内部 FLASH 中从一个固件跳转到另一个固件

    我目前正在开发针对 STM32F030C8 的引导加载程序固件应用程序 我在分散文件中指定引导加载程序应用程序将占用主内存位置 0x08000000 到 0x08002FFF 扇区 0 到扇区 2 我还编写了一个主固件应用程序 存储在0x0
  • CMSIS 库是否应该包含在版本控制中? [复制]

    这个问题在这里已经有答案了 通常 我曾经在版本控制中包含芯片供应商 ST 提供的设备特定标头和源以及 CMSIS Core 标头 数量不多 也没有更新的习惯 我使用STM32微控制器 但我不使用立方体框架 or the 标准外设库 最近 我
  • Push_back() 导致程序在进入 main() 之前停止

    我正在为我的 STM32F3 Discovery 板使用 C 进行开发 并使用 std deque 作为队列 在尝试调试我的代码 直接在带有 ST link 的设备上或在模拟器中 后 代码最终在 main 中输入我的代码之前在断点处停止 然
  • STM32F4 通过软复位跳转到引导加载程序,无需 BOOT0 和 BOOT1 引脚

    我问这个问题是因为可以在这里找到类似问题的答案 通过应用程序跳转到 STM32 中的引导加载程序 即从用户闪存在引导模式下使用引导 0 和引导 1 引脚 用户 JF002 JF002回答 当我想跳转到引导加载程序时 我在其中一个备份寄存器中
  • STM32 GPIO工作原理详解

    STM32 GPIO介绍 1 STM32引脚说明 GPIO是通用输入 输出端口的简称 是STM32可控制的引脚 GPIO的引脚与外部硬件设备连接 可实现与外部通讯 控制外部硬件或者采集外部硬件数据的功能 以STM32F103ZET6芯片为例
  • [屏驱相关]【SWM166-SPI-Y1.28C1测评】+ 有点惊艳的开箱

    耳闻华芯微特许久了 看到论坛得评测活动赶紧上了末班车 毕竟对有屏幕得板子也是很喜欢得 京东快递小哥客客气气 微笑着把快递给了我 好评 直接拆了包 在此之前没看过视频号 所以这个圆盘盘得模具还是有点惊喜的 正面照如下 开机有灯光秀 还有动画
  • [MM32硬件]搭建灵动微MM32G0001A6T的简易开发环境

    作为学习单片机的经典 自然是通过GPIO点亮LED 或者是响应按钮的外部中断例程 这我们看看SOP8封装的芯片MM32G0001A6T得引脚 除了VDD和GND固定外 我们可以使用PA14 PA1 PA13 PA15 PA2 PA3这六个G
  • VS Code 有没有办法导入 Makefile 项目?

    正如标题所说 我可以从现有的 Makefile 自动填充 c cpp properties json 吗 Edit 对于其他尝试导入 makefile 的人 我找到了一组脚本 它们完全可以实现我想要实现的目标 即通过 VS Code 管理
  • 最终启动顺序错误 - STM32L476 的 Eclipse System Workbench 调试

    我正在尝试调试和运行 STM32L476 的简单汇编代码 我已经设置了 Eclipse Oxygen 在 Eclipse 中安装了最新版本的 System Workbench 插件并安装了 ST Link 驱动程序 IDE 成功构建了程序
  • 擦除后无法写入闪存

    所以我不能在擦除后直接写入内部闪存 如果写操作之前没有擦除操作 那么我可以 有什么想法吗 编程函数返回 成功写入 值 但查看内存时 没有写入任何数据 这是代码 uint32 t pageAddress 0x08008000 uint16 t
  • 1.69寸SPI接口240*280TFT液晶显示模块使用中碰到的问题

    1 69寸SPI接口240 280TFT液晶显示模块使用中碰到的问题说明并记录一下 在网上买了1 69寸液晶显示模块 使用spi接口 分辨率240 280 给的参考程序是GPIO模拟的SPI接口 打算先移植到FreeRtos测试 再慢慢使用
  • Freertos低功耗管理

    空闲任务中的低功耗Tickless处理 在整个系统运行得过程中 其中大部分时间都是在执行空闲任务的 空闲任务之所以执行 因为在系统中的其他任务处于阻塞或者被挂起时才会执行 因此可以将空闲任务的执行时间转换成低功耗模式 在其他任务解除阻塞而准
  • systick定时器

    systick定时器 文章目录 前言 一 前期疑惑 二 解答 1 关于systick是阻塞的吗 2 非阻塞 三 软件编写 总结 前言 这边记录systick相关知识点 一 前期疑惑 在学习systick志气啊 其实对于systick还是一脸
  • Cortex-M3与M4权威指南

    处理器类型 所有的ARM Cortex M 处理器是32位的精简指令集处理器 它们有 32位寄存器 32位内部数据路径 32位总线接口 除了32位数据 Cortex M处理器也可以有效地处理器8位和16位数据以及支持许多涉及64位数据的操作
  • 从没有中断引脚并且在测量准备好之前需要一些时间的传感器读取数据的最佳方法

    我正在尝试将压力传感器 MS5803 14BA 与我的板 NUCLEO STM32L073RZ 连接 根据 第 3 页 压力传感器需要几毫秒才能准备好读取测量值 对于我的项目 我对需要大约 10 毫秒来转换原始数据的最高分辨率感兴趣 不幸的
  • STM32 上的位置无关代码 - 指针

    我已成功在 STM32 上构建并运行位置无关的代码 向量表和 GOT 已修补 一切正常 但我对这样的代码有问题 double myAdd double x return x 0 1 double ptrmyAdd double myAdd
  • 当端点和 PMA 地址均更改时,CubeMX 生成的 USB HID 设备发送错误数据

    我正在调试我正在创建的复合设备的问题 并在新生成的仅 CubeMX 代码中重新创建了该问题 以使其更容易解决 我添加了少量代码main 让我发送 USB HID 鼠标点击 并在按下蓝色按钮时使 LED 闪烁 uint8 t click re

随机推荐