STM32CUBEIDE(MX续)学习笔记(七)——FREERTOS+DMA+队列+循环数组方式进行串口收发

2023-05-16

一、收发主要逻辑

1、接收:利用DMA和空闲中断一次接收一帧的不定长数据,接收到数据后“暂停”(之后分析为何要暂停而不是停止)DMA,快速利用结构体存储接收到数据的地址和长度,再利用队列能够传递结构体的特点,将所收数据的地址和长度入队,然后打开DMA接收。数据处理任务检测队列状态,只要队列中有有效数据就开始数据处理。
2.发送:先将要发送的数据存入循环数组(伪)中,再利用队列将数据的地址和长度入队,利用一个串口输出的守护任务来保证数据传输的完整性,这个守护任务对地址和长度出队并使用DMA传输。

二、接收代码

接收和发送结构体

typedef struct
{
	uint8_t	lenth;
	uint8_t	offset_last;
}Usart3RXTempTypedef;

typedef struct
{
	uint8_t	lenth;
	uint8_t offset_last;
	uint8_t *addr;
}Usart3TxTypedef;

1.中断

void USART3_IRQHandler(void)
{
  /* USER CODE BEGIN USART3_IRQn 0 */
	uint32_t tmp_flag = 0;
	uint16_t temp;
	portBASE_TYPE xHigherPriorityTaskWoken= pdFALSE;
	tmp_flag =__HAL_UART_GET_FLAG(&huart3,UART_FLAG_IDLE);
	if((tmp_flag != RESET))
	{
		__HAL_UART_CLEAR_IDLEFLAG(&huart3);
		temp = huart3.Instance->SR;
		temp = huart3.Instance->DR;
		HAL_UART_DMAPause(&huart3);
		temp  = hdma_usart3_rx.Instance->CNDTR;

		if(temp	>=	(USART3_RxBuffer_Size - Usart3Temp.offset_last))//判断是否到达循环数组终点
			Usart3Temp.lenth =  2*USART3_RxBuffer_Size - temp - Usart3Temp.offset_last;
		else
			Usart3Temp.lenth =  USART3_RxBuffer_Size - temp - Usart3Temp.offset_last;
		Usart3Temp.offset_last = USART3_RxBuffer_Size - temp;
		xQueueSendFromISR(QueueUsart3RevHandle,(void *)&Usart3Temp,&xHigherPriorityTaskWoken);
		HAL_UART_DMAResume(&huart3);
	}
  /* USER CODE END USART3_IRQn 0 */
  HAL_UART_IRQHandler(&huart3);
  /* USER CODE BEGIN USART3_IRQn 1 */

  /* USER CODE END USART3_IRQn 1 */
}

这里DMA操作要使用HAL_UART_DMAPauseDMA暂停和HAL_UART_DMAResumeDMA恢复。
如果使用HAL_UART_DMAStopDMA停止和HAL_UART_Receive_DMADMA接收启用,会导致DMA一直从循环数组的开头存放数据。
这里Usart3Temp.offset_last是本次数据的尾地址偏移量。
当然,DMA参数配置中要把模式设置为循环模式。
在这里插入图片描述
2.接收数据任务:数据处理方式为收到数据后原样返回

void usart3RxTask(void const * argument)
{
  /* USER CODE BEGIN usart3RxTask */
  /* Infinite loop */
  for(;;)
  {
	  uint16_t	i;
	  uint8_t	RevCnt;
	  Usart3RxTypedef Usart3TempRev;
	  Usart3TxTypedef	Usart3Tx;
		/* Infinite loop */
		for(;;)
		{
			xQueueReceive(QueueUsart3RevHandle,(void*)&Usart3TempRev,portMAX_DELAY);
			if(Usart3TempRev.offset_last>=Usart3TempRev.lenth)
			{
				RevCnt=0;
				for(i=(Usart3TempRev.offset_last-Usart3TempRev.lenth);i<Usart3TempRev.offset_last;i++)
				{
					Usart3RevBuf[RevCnt] = USART3_Rx_Buffer[i];
					RevCnt++;
				}
			}
			else
			{
				RevCnt=0;
				for(i=(USART3_RxBuffer_Size	- (Usart3TempRev.lenth - Usart3TempRev.offset_last));i<USART3_RxBuffer_Size;i++)
				{
					Usart3RevBuf[RevCnt] = USART3_Rx_Buffer[i];
					RevCnt++;
				}
				for(i=0;i<Usart3TempRev.offset_last;i++)
				{
					Usart3RevBuf[RevCnt] = USART3_Rx_Buffer[i];
					RevCnt++;
				}
			}
			//将接收到的信息�?�过循环数组送出
			if((Usart3Tx.offset_last + RevCnt) > USART3_TxBuffer_Size)//如果溢出,则从数组的第一个地�?�?始储�?
				Usart3Tx.offset_last = 0;
			for(i=0;i<RevCnt;i++)
			{
				USART3_Tx_Buffer[Usart3Tx.offset_last]	= Usart3RevBuf[i];
				Usart3Tx.offset_last++;
			}
			Usart3Tx.lenth = RevCnt;
			xQueueSend(QueueUsart3TxHandle,&Usart3Tx,0);
			osThreadYield();
		}
  }
  /* USER CODE END usart3RxTask */
}

ps:队列操作函数使用xQueueReceivexQueueSend而不是osMessageGetosMessagePut的原因:
由于os封装的队列函数传递队列时只能传输uint32_t 类型的数据,明明定义结构体时定义了.v和.p还有.signal三中类型的数据接收

typedef struct  {
  osStatus                 status;     ///< status code: event or error information
  union  {
    uint32_t                    v;     ///< message as 32-bit value
    void                       *p;     ///< message or mail as void pointer
    int32_t               signals;     ///< signal flags
  } value;                             ///< event value
  union  {
    osMailQId             mail_id;     ///< mail id obtained by \ref osMailCreate
    osMessageQId       message_id;     ///< message id obtained by \ref osMessageCreate
  } def;                               ///< event definition
} osEvent;

到了队列出队函数封装里却只使用了.v来存储出队数据(虽然省去了区分xQueueReceiveFromISR在xQueueReceive的问题,但感觉过于鸡肋)

osEvent osMessageGet (osMessageQId queue_id, uint32_t millisec)
{
  portBASE_TYPE taskWoken;
  TickType_t ticks;
  osEvent event;
  
  event.def.message_id = queue_id;
  event.value.v = 0;
  
  if (queue_id == NULL) {
    event.status = osErrorParameter;
    return event;
  }
  
  taskWoken = pdFALSE;
  
  ticks = 0;
  if (millisec == osWaitForever) {
    ticks = portMAX_DELAY;
  }
  else if (millisec != 0) {
    ticks = millisec / portTICK_PERIOD_MS;
    if (ticks == 0) {
      ticks = 1;
    }
  }
  
  if (inHandlerMode()) {
    if (xQueueReceiveFromISR(queue_id, &event.value.v, &taskWoken) == pdTRUE) {
      /* We have mail */
      event.status = osEventMessage;
    }
    else {
      event.status = osOK;
    }
    portEND_SWITCHING_ISR(taskWoken);
  }
  else {
    if (xQueueReceive(queue_id, &event.value.v, ticks) == pdTRUE) {
      /* We have mail */
      event.status = osEventMessage;
    }
    else {
      event.status = (ticks == 0) ? osOK : osEventTimeout;
    }
  }
  
  return event;
}

3.发送数据守护任务
使用一个唯一的串口输出守护任务进行输出,任何任务的输出都需要将数据地址和长度通过结构体传入输出队列。
在这里插入图片描述DMA模式要选择普通模式
守护任务:USART3_Tx_Buffer为串口发送缓存数组

void Usart3TxTask(void const * argument)
{
  /* USER CODE BEGIN Usart3TxTask */
	Usart3TxTypedef	Usart3Tx;
  /* Infinite loop */
  for(;;)
  {
	  xQueueReceive(QueueUsart3TxHandle,&Usart3Txtemp,portMAX_DELAY);
	  HAL_UART_Transmit_DMA(&huart3,(uint8_t*)(USART3_Tx_Buffer	+ Usart3Txtemp.offset_last - Usart3Txtemp.lenth),Usart3Txtemp.lenth);
	  osThreadYield();
  }
  /* USER CODE END Usart3TxTask */
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32CUBEIDE(MX续)学习笔记(七)——FREERTOS+DMA+队列+循环数组方式进行串口收发 的相关文章

  • OpenCV笔记4.3

    C 43 43 读取目录下所有文件名称 1 包含头文件 96 span class token macro property span class token directive hash span span class token dir
  • 半小时内实现Esp32-Cam模型训练和图像识别

    Esp32 Cam图像识别 一 网页显示视频流1 Linux式例程2 MicroPython式例程步骤1 下载Thonny步骤2 烧录Esp32 Cam固件步骤3 运行相应代码 3 Arduino式例程步骤1 下载Arduino步骤2 安装
  • MANIFOLD 2-G开发 之 利用ROS话题编程实现UART1串口通讯

    目录 MANIFOLD 2 G开发笔记1 项目描述2 遇到的问题3 解决方案4 示例代码5 注意事项6 资源附件6 运行与调试 MANIFOLD 2 G开发笔记 本博客内容将记录MANIFOLD 2 G 开发过程中遇到的问题及解决方案 xf
  • ONOS源码笔记--机制

    app注册 private ApplicationId appId appId 61 coreService registerApplication 34 org onosproject fwd 34 注册应用 xff0c 一般在activ
  • git 本地分支与远程分支关联

    github上已经有master分支 和dev分支 在本地 git checkout b dev 新建并切换到本地dev分支 git pull origin dev 本地分支与远程分支相关联 github上没有dev分支 git check
  • 做设计师还是程序员?一张图你就明白!

    平时大家相安无事 xff0c 可一旦项目滑了水 栽了坑 二重奏就开始没完没了的唱起来了 请看下图 xff1a 你的桌子是有什么 小编反手一摸 xff0c 还好小编的头发还再 你头发呢 xff1f 相信这里有很多学习java的朋友 xff0c
  • 【ROS】动态链接库(.so文件)的生成和调用

    ROS 动态链接库 xff08 so文件 xff09 的生成和使用 引言 xff11 生成so文件 xff12 调用so文件 xff13 运行结果结语 引言 由于项目有涉及到源代码是否交付的选项 xff0c 想着如果不交付源代码 xff0c
  • 用TortoiseGit删除git仓库中的文件/文件夹

    用TortoiseGit删除git仓库中的文件 文件夹 点击删除后出现弹框 xff0c 点击删除 删除后会显示移除一个文件 xff1b 想要还原可以在当前文件夹中右键选择TortoiseGit gt 还原 xff08 revert xff0
  • 02-Jetson Xavier NX 训练自己的yolov4-tiny模型并利用TensorRT完成部署(Python API)

    记录原因 xff1a 因前面完成了yolov4 tiny源码的部署 xff0c 可以跑到50FPS 但那个跑的是别人的模型 xff0c 可以识别80类 xff0c 但是在特定的情况下比如识别螺丝螺帽 xff0c 只需要两种 xff0c 在训
  • RPLIDAR在ROS下快速上手教程

    本教程由 臭皮匠机器人 原创 转载请注明出处 收到一个RPLidar后 xff0c 干的第一件事应该是先让雷达跑起来 xff0c 边做边学是最高效的 之前写了一篇在windows底下的 RPLIDAR十分钟极速入门教程 xff0c 今天将教
  • RPLIDAR的坐标系问题

    本教程由 臭皮匠机器人 原创 转载请注明出处 RPLIDAR自身的坐标系 RPLIDAR给出来的数据是角度和距离 xff0c 也就是极坐标系 转换成直角坐标系的话应该照转换公式计算 xff0c 假设r是距离 xff0c theta是角度 x
  • Makefile模板(取自vscode)

    文章目录 Makefile模板vscode插件 xff1a 单一目标编译多个目标 Makefile模板 vscode插件 xff1a 单一目标 最近在学习Makefile写法 xff0c 但是总觉得自己写的太烂了 xff0c 找到了vsco
  • 使用docker-compose配置mysql数据库并且配置用户密码

    下面要求环境 xff1a 一定要安装docker ce和docker compose才能进行下面步骤 linux找到你要放mysql的目录 创建一个docker compose yml 以下配置了外部数据卷 外部配置文件 外部初始化文件 x
  • 使用ONOS的REST API来下发流表

    1 启动ONOS后 xff0c 浏览器进入doc http 10 109 247 211 8181 onos v1 docs 2 找到Flow xff0c 并打开POST 3 可以直接在这个上面编辑flow stream里面模拟GET获得的
  • 形态学处理

    原文链接 xff1a https blog csdn net qq 40732350 article details 116718329 spm 61 1001 2014 3001 5506 形态学处理 0 前言1 腐蚀与膨胀1 1 结构元
  • leetcode用到的函数汇总

    reverse isalnum tolower
  • Keil MDK-ARM软件官网最新版本的下载方法

    我之前的几篇博客讲的都是关于Keil MDK5 ARM软件的一些配置方法 xff0c 但是我居然忘了说一下如何去下载这个软件了 xffe3 xffe3 xff5c xff5c xff0c 今天这篇博客就把这个小知识点补上 第一步 xff0c
  • 给Word文档中的公式自动编号的方法

    最近在做毕业设计 xff0c 然后需要翻译一篇英文文献 xff0c 我在翻译英文文献的时候 xff0c 需要对公式进行编号 xff0c 而且需要使编号显示在最右侧 xff0c 而公式居中 xff0c 像下图这样 xff1a 如果一个个手动添
  • PHP如何使用strrev()函数反转字符串?(代码示例)

    反转字符串是最基本的字符串操作之一 xff0c 在PHP中可以使用内置函数strrev 来实现字符串的反转 下面本篇文章就来带大家了解一下PHP strrev 函数怎么用 xff0c 希望对大家有所帮助 PHP strrev 函数 strr
  • 离线安装Linux包的方法--以imblearn为例

    包的 whl文件直接在https pypi org 上搜索下载就好 xff0c 注意要搜索全名scikit learn xff01 你搜sklearn是找不到合适的包的 如图 xff0c 选择第一个就好 xff1a 接着要匹配你的系统架构和

随机推荐

  • px4 EKF中Q、R阵设置的思考

    关于Q R的讨论 Q阵 xff0c 状态转移误差矩阵 xff0c 代表从Xt 1到Xt过程中 xff0c 状态转移和真实过程之间的误差 xff0c 具体其中变量可能是对状态转移有影响的变量 xff0c 比如在有一些场景下 xff0c 可能为
  • Ubuntu查看硬盘信息

    lsscsi包默认是不安装的 xff0c 可以使用以下命令安装lsscsi span class token function sudo span span class token function apt get span span cl
  • 在Python3环境中使用ROS的cv_bridge

    之前使用ROS的时候只用了C 43 43 xff0c 没有发现cv bridge这个坑 xff0c 最近增加了一个使用tensorflow2的节点 xff0c 为此使用Anaconda配置了一个只有Python3 7的环境 xff0c 运行
  • 解决mac安装完torch_geometric,import的时候报错的问题。

    问题描述 使用torch geometric官方的命令安装好了torch geometric xff0c 安装的过程非常丝滑流畅 xff0c 但是安装好了import的时候就报错OSerror 注意事项 不要用他生成的命令安装 xff1a
  • CXF内容总结

    CXF 61 XFire webservice框架 43 Celtrix ESB框架 http cxf apache org 内置jettyweb服务器 服务器端 xff1a 1 开发webservice接口 xff0c 要用 64 web
  • Could NOT find UV (missing: UV_LIBRARY UV_INCLUDE_DIR)

    cd var tmp git clone https github com libuv libuv git cd libuv autogen sh configure make make install 注 xff1a 下不来直接去网页下载
  • 【STM32】HAL库开发教程(四)—串口FIFO使用

    前言 不必害怕未知 xff0c 无需恐惧犯错 xff0c 做一个Creator xff01 本文主要介绍STM32 HAL库开发中串口 FIFO的使用 一 开发步骤 1 Cubemx配置 在左侧引脚配置栏选择目标串口号在串口模式处配置串口模
  • 【STM32】串口数据帧接收与分析处理算法

    基于对串口FIFO的通信数据帧进行接收和分析处理 xff08 关于串口FIFO使用可以参见作者另一篇博文 xff09 算法流程 xff1a 串口中断函数接收数据到FIFO 根据通信协议GetInterUARTMessage 函数对数据帧进行
  • 【STM32】HAL库开发教程(三)—定时器使用

    前言 不必害怕未知 xff0c 无需恐惧犯错 xff0c 做一个Creator xff01 本文主要介绍STM32 HAL库开发中定时器的使用 一 开发步骤 1 STM32CubeMX配置 在左侧引脚配置处勾选TIM2进行配置在TIM2模式
  • 直立车想节能——2020全国大学生智能车车竞赛经验记录之我想要直立(平衡小车串级pid调参经验)

    平衡车我相信很多电赛测控的入门的玩家都也玩过 xff0c 很多朋友们也都听说过平衡小车之家这家淘宝店铺 而串级PID也是一个经典且牛批的方案而广为人知 xff0c 所以在这样的比赛结束之后作为俩套方案都试过的我 xff0c 谈一谈平衡小车之
  • 慎用apt autoremove

    1 remove 卸载软件包 2 autoremove 卸载所有自动安装且不再使用的软件包 3 purge 卸载并清除软件包的配置 平时经常会卸载或删除一些东西 xff0c 系统也会友好提示你进行自动删除一些相关的文件 xff0c 但是有可
  • 推送镜像到DockerHub报无访问权限

    推送镜像到DockerHub 我们推送镜像到DockerHub时会遇到没有访问资源权限的问题 requested access to the resource is deni ed 这是因为dockerhub不知道是谁推送的镜像 xff0c
  • mysql5主从配置教程

    mysql5主从配置 同学们会有mysql主从配置的需求吗 xff1f 这里我给大家讲一下mysql5 7的主从配置教程 我们通过docker来安装mysql 这样会方便很多 拉取镜像 docker pull docker pull mys
  • 解决ubuntu下kazam录制视频无法在windows播放问题

    记录贴 Kazam是ubuntu下一个功能性截屏软件 xff0c 但是在使用的过程中 xff0c 发现Kazam录屏的视频能够在QQ发送 xff0c 但是只能播放 xff0c 不能下载 xff0c window下也不能播放 查找了一些资料发
  • 深入理解以太网PHY自协商及调试心得

    最近调某个phy芯片 xff0c 心态爆炸 xff0c 不过好歹最后有个好结果 自协商基本原理 自动协商模式是端口根据另一端设备的连接速度和双工模式 xff0c 自动把它的速度调节到最高的公共水平 xff0c 即线路两端能具有的最快速度和双
  • 平衡小车的资料

    根据网上平衡小车之家的资料引脚需要用 xff1a LED PA12 Key PA15 OLED RST Clr PC13 RS Clr PB4 SCLK Clr PC15 SDIN Clr PC14 ADC PA4 TIM3 PB0 PB1
  • 注解

    好处 把问题暴露在编译时期 xff1b 增强程序健壮性 xff1b 可以让JVM检查除了语法错误以外的其他的自定义检查 xff1b 位置 可以加到包 xff0c 类 xff0c 方法 xff0c 字段 xff0c 局部变量等位置 xff1b
  • 【知识图谱】课程笔记1---知识图谱简介

    1 知识图谱 知识图谱是一种基于图的数据结构 由节点 point 和边 Edge 组成 每个节点表示一个 实体 每条边为实体与实体之间的 关系 知识图谱本质上是语义网络 通过这种先验的知识网络 xff0c 让机器像人类一样可以联想 推理 它
  • 特征检测+SIFT点匹配+PNP位姿确定

    SIFT特征检测 43 FLANN点匹配 43 PNP位姿确定 软件环境 windows 10 vs2013 opencv3 1 0 43 opencv3 1 0 contrib 基本原理 1 SIFT 特征点检测 43 匹配 2 PNP位
  • STM32CUBEIDE(MX续)学习笔记(七)——FREERTOS+DMA+队列+循环数组方式进行串口收发

    一 收发主要逻辑 1 接收 xff1a 利用DMA和空闲中断一次接收一帧的不定长数据 xff0c 接收到数据后 暂停 xff08 之后分析为何要暂停而不是停止 xff09 DMA xff0c 快速利用结构体存储接收到数据的地址和长度 xff