使用队列传递复合数据类型

一个任务从单个队列中接收来自多个发送源的数据是经常的事。通常接收方收到数据后,需要知道数据的来源,并根据数据的来源决定下一步如何处理。一个简单的方式就是利用队列传递结构体,结构体成员中就包含了数据信息和来源信息,下图对这一方案进行了展现。

从图中可以看出:

  1. 创建一个队列用于保存类型为 xData 的结构体数据单元。结构体成员包括了一个数据值和表示数据含义的编码,两者合为一个消息可以一次性发送到队列。
  2. 中央控制任务用于完成主要的系统功能。 其必须对队列中传来的输入和其它系统状态的改变作出响应。
  3. CAN 总线任务用于封装 CAN 总线的接口功能。当 CAN 总线任务收到并解码一个消息后,其将把解码后的消息放到 xData 结构体中发往控制任务。结构体的 iMeaning成员用于让中央控制任务知道这个数据是用来干什么的— 从图中的描述可以看出,这个数据表示电机速度。结构体的 iValue 成员可以让中央控制任务知道电机的实际速度值。
  4. 人机接口(HMI)任务用于对所有的人机接口功能进行封装。设备操作员可能通过各种方式进行命令输入和参数查询,人机接口任务需要对这些操作进行检测并解析。当接收到一个新的命令后,人机接口任务通过 xData 结构将命令发送到中央控制任务。结构体的 iMeaning 成员用于让中央控制任务知道这个数据是用来干什么的 — 从图中的描述可以看出,这个数据表示一个新的参数设置。结构体的 iValue 成员可以让中央控制任务知道具体的设置值。

本例内容:

任务1、任务2优先级osPriorityLow(低)
任务3 优先级 osPriorityIdle(高)
写队列任务具有最高优先级,所以队列正常情况下一直是处于满状态。这是因为一旦读队列任务从队列中读走一个数据单元,某个写队列任务就会立即抢占读队列任务,把刚刚读走的位置重新写入,之后便又转入阻塞态以等待队列空间有效。
写队列任务指定了 100 毫秒的阻塞超时时间,以便在队列满时转入阻塞态以等待队列空间有效。进入阻塞态后,一旦队列空间有效,或是等待超过了 100 毫秒队列空间尚无效,其将解除阻塞。在本例中,将永远不会出现 100 毫秒超时的情况,因为读队列任务在不停地从队列中读出数据从而腾出队列数据空间。

代码实现

宏定义与变量

/* USER CODE END Header *//* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD *//* USER CODE END PTD *//* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */#define mainSENDER_1 0x01
#define mainSENDER_2 0x02/* USER CODE END PD *//* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM *//* USER CODE END PM *//* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */extern osEvent event;typedef struct
{unsigned char ucValue;unsigned char ucSource;
} xData;static const xData xStructsToSend[ 2 ] =
{{ 100, mainSENDER_1 }, /* Used by Sender1. */{ 200, mainSENDER_2 }  /* Used by Sender2. */
};/* USER CODE END Variables */
osThreadId myTask01Handle;
osThreadId myTask02Handle;
osThreadId myTask03Handle;
osMessageQId myQueue01Handle;/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes *//* USER CODE END FunctionPrototypes */void StartTask01(void const * argument);
void StartTask02(void const * argument);
void StartTask03(void const * argument);void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) *//*** @brief  FreeRTOS initialization* @param  None* @retval None*/
void MX_FREERTOS_Init(void) {/* USER CODE BEGIN Init *//* USER CODE END Init *//* USER CODE BEGIN RTOS_MUTEX *//* add mutexes, ... *//* USER CODE END RTOS_MUTEX *//* USER CODE BEGIN RTOS_SEMAPHORES *//* add semaphores, ... *//* USER CODE END RTOS_SEMAPHORES *//* USER CODE BEGIN RTOS_TIMERS *//* start timers, add new ones, ... *//* USER CODE END RTOS_TIMERS *//* Create the queue(s) *//* definition and creation of myQueue01 */osMessageQDef(myQueue01, 16, uint16_t);myQueue01Handle = osMessageCreate(osMessageQ(myQueue01), NULL);/* USER CODE BEGIN RTOS_QUEUES *//* add queues, ... *//* USER CODE END RTOS_QUEUES *//* Create the thread(s) *//* definition and creation of myTask01 */osThreadDef(myTask01, StartTask01, osPriorityLow, 0, 128);myTask01Handle = osThreadCreate(osThread(myTask01), NULL);/* definition and creation of myTask02 */osThreadDef(myTask02, StartTask02, osPriorityLow, 0, 128);myTask02Handle = osThreadCreate(osThread(myTask02), NULL);/* definition and creation of myTask03 */osThreadDef(myTask03, StartTask03, osPriorityIdle, 0, 128);myTask03Handle = osThreadCreate(osThread(myTask03), NULL);/* USER CODE BEGIN RTOS_THREADS *//* add threads, ... *//* USER CODE END RTOS_THREADS */}

任务1代码

/* USER CODE BEGIN Header_StartTask01 */
/*** @brief  Function implementing the myTask01 thread.* @param  argument: Not used * @retval None*/
/* USER CODE END Header_StartTask01 */
void StartTask01(void const * argument)
{/* USER CODE BEGIN StartTask01 *//* Infinite loop */portBASE_TYPE xStatus;const portTickType xTicksToWait = 100/portTICK_RATE_MS;for(;;){xStatus = xQueueSendToBack( myQueue01Handle, &( xStructsToSend[0]), xTicksToWait );if(xStatus != pdPASS){printf("Could not send to the queue.\r\n");}taskYIELD();}/* USER CODE END StartTask01 */
}

任务2代码

/* USER CODE BEGIN Header_StartTask02 */
/**
* @brief Function implementing the myTask02 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTask02 */
void StartTask02(void const * argument)
{/* USER CODE BEGIN StartTask02 *//* Infinite loop */portBASE_TYPE xStatus;const portTickType xTicksToWait = 100/portTICK_RATE_MS;for(;;){xStatus = xQueueSendToBack( myQueue01Handle, &( xStructsToSend[1]), xTicksToWait);if(xStatus != pdPASS){printf("Could not send to the queue.\r\n");}taskYIELD();}/* USER CODE END StartTask02 */
}

任务3代码

/* USER CODE BEGIN Header_StartTask03 */
/**
* @brief Function implementing the myTask03 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTask03 */
void StartTask03(void const * argument)
{/* USER CODE BEGIN StartTask03 *//* Infinite loop */xData xReceivedStructure;portBASE_TYPE xStatus;for(;;){if( osMessageWaiting( myQueue01Handle ) != 16 ){printf( "Queue should have been empty!\r\n" );}xStatus = xQueueReceive( myQueue01Handle, &xReceivedStructure, 0 );if(xStatus == pdPASS){if(xReceivedStructure.ucSource == mainSENDER_1){printf("From Sender 1 = %d\r\n",xReceivedStructure.ucValue);}else if(xReceivedStructure.ucSource == mainSENDER_2){printf("From Sender 2 = %d\r\n",xReceivedStructure.ucValue);}}else{printf( "Could not receive from the queue.\r\n" );}}/* USER CODE END StartTask03 */
}

主程序代码

/*** @brief  The application entry point.* @retval int*/
int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_USART1_UART_Init();/* USER CODE BEGIN 2 *//* USER CODE END 2 *//* Call init function for freertos objects (in freertos.c) */MX_FREERTOS_Init();/* Start scheduler */osKernelStart();/* We should never get here as control is now taken by the scheduler *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}

结果

写队列任务在每次循环中都主动进行任务切换,所以两个数据会被轮翻地写入到队列中。

不足之处请指出,有点帮助请鼓励!

cubeMX+STM32+Freertos 向队列写结构体相关推荐

  1. 用vector写结构体

    用vector写结构体 首先你要知道的是,结构体不是普通变量,不像 int 型 可以直接的 push_back() 结构体需要一个中间的变量,先给这个变量赋值之后. 再 push_back()那个中间 ...

  2. linux 写结构体到文件

    将整数写入到文件 #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include& ...

  3. Goland写结构体方法时,带不带(*)区别和影响

    这里我定义一个   定义一个拥有值类型属性的A结构体 并给与相应的方法f1 在主函数中 初始化A, n=0 ,并调用f1 想通过 绑定方法f1修改 主函数 A的n值, 而结果是 这是因为A结构体是值类 ...

  4. STM32通用定时器(原理、结构体、库函数、定时器中断每秒闪烁一次灯) —— 时钟源、分频值、重装载值

    参考:stm32定时器与定时器中断 作者:打酱油的 发布时间: 2021-04-11 01:04:09 网址:https://blog.csdn.net/weixin_46098612/article ...

  5. STM32编程中枚举和结构体的结合

    01.结构体定义 基本定义:结构体,通俗讲就像是打包封装,把一些有共同特征(比如同属于某一类事物的属性,往往是某种业务相关属性的聚合)的变量封装在内部,通过一定方法访问修改内部变量. 结构体的定义: ...

  6. 【STM32多级界面】-LCD结构体多级图形界面框架

    STM32多级界面搭建 在实际的项目之中,需要用单片机在LCD/OLED中搭建一个3级的图形界面.本文的工程文件我将上次传到百度网盘,链接在最后的部分. STM32多级界面搭建 一.方案选择 二.实现 ...

  7. c++队列指针 结构体指针

    RevData中如果放的是对象数据,不是char* int,可以用如下方式: RevData *recvD =new RevData; recvD.size = i; strcpy(recvD.dat ...

  8. c++ map嵌套队列(队列嵌套结构体指针)ok

    map中嵌套队列,队列中是结构体,有一个问题,结构体中的值不更新 #include <iostream> #include <queue> #include<map> ...

  9. IAR在写结构体时不提示_智能物流装车系统的结构优化与改进

    文|滇西应用技术大学管理学院 鄢良国.姚敏.孙荷琴.杨晓 滇西应用技术大学基础实验实训中心 朱丹 智能物流装车系统主要用于烟草生产基地和物流配送中心之间往返运输的自动化装车业务中.本文针对智能物流装车 ...

最新文章

  1. wcf返回datatable必须给tablename赋值
  2. VTK:PolyData之SurfaceContourLineInterpolator
  3. redis 启动加载mysql_Redis分析系列:启动加载过程
  4. C++基础学习-20120516
  5. Python入门教程丨1300多行代码,让你轻松掌握基础知识点
  6. python URLError,HTTPError 的异常处理
  7. latex IEEE 模板 使用bib BibTeX
  8. android中RecyclerView添加下划线
  9. 解除应用计算机仿真,语音识别中计算机仿真的应用
  10. 笔记本无法连接WiFi
  11. 互联网产品上线前,做些什么——产品、开发、测试的视角(转载)
  12. ACM-ICPC 2018 焦作赛区网络预赛(A B E F G H I K L)
  13. python scrapy 爬取妹子图的照片
  14. 一秒钟看懂SaaS、CRM、OA、ERP、HR、进销存
  15. System Reliability - One Crash per Thousand Server Years
  16. [Unity3D]Unity3D游戏开发之MatchTarget实现角色攀爬效果
  17. 微软CEO鲍尔默的一天(组图)
  18. 【服务器数据恢复】Zfs文件系统误删除数据的数据恢复案例
  19. 简易天体运动—— sun earth moon(计算机图形学)
  20. 拆分体提示工具未形成相交_Revit 模型布局:地形表面的拆分、合并、创建子面域和平整区域...

热门文章

  1. java 全局变量 局部变量的区别_java中全局变量和局部变量的区别是什么?
  2. int与Integer的区别详细介绍(包括128陷阱)
  3. c语言python字典结构_C语言解析Python字典的代码实例
  4. 心平气和的解决mysql 的root密码不知道的麻烦
  5. 基于Vue+ElementUI的大数据分析前后端分离框架
  6. java socket调用接口_Java中socket接口调用
  7. java的System.exit(0)的作用以及和System.exit(1)区别。
  8. JavaScript自执行函数,自执行函数是什么,存在的意义?
  9. C# 多线程CPU占用高 简单优化
  10. The Enchanted Forest(思维/前缀和)