当前位置: 首页 > news >正文

【FreeRTOS】第七课(3):任务间的通信——使用队列集优化程序架构

目录

一、前言

二、使用队列集的程序框架

三、队列集介绍

1.简介

2.用到的函数原型

四、使用实例

1.顶层部分

 1)游戏函数(创建队列集)

2)中间数据转换函数(使用队列集)

2.红外遥控器部分

1)创建原始数据接收队列

2)存储原始数据

3.)创建句柄返回函数

旋转编码器部分

1) 创建原始数据接收队列

2)存储原始数据

3)创建句柄返回函数

3.MPU6050部分

1)创建原始数据接收队列

2)将原始数据写入设备队列

3)创建句柄返回函数

五、程序小bug(处理方式见后文)


一、前言

根据上一节课写出的程序可以看出:旋转编码器的解耦性更好

推荐程序架构:代码之间耦合性低

二、使用队列集的程序框架

三、队列集介绍

1.简介

队列集的本质也是队列,只不过里面存放的是“队列句柄”。使用过程如下:

  • 创建队列A,它的长度是n1,存放的是原始数据
  • 创建队列B,它的长度是n2,存放的是原始数据
  • 创建队列集S,它的长度是“n1+n2”,存放的是队列的句柄
  • 把队列A、B加入队列集S
  • 队列A每被写入一个数据,就会把自己的句柄写入队列集S
  • 队列B每被写入一个数据,就会把自己的句柄写入队列集S
  • 读取队列集S,返回值是一个队列句柄,通过句柄可以知道是哪个队列的数据,再通过句柄调用对应的队列数据处理函数,将原始数据处理为可直接使用的数据

2.用到的函数原型

创建队列集函数原型如下:

QueueSetHandle_t xQueueCreateSet( const UBaseType_t uxEventQueueLength )
参数说明
uxQueueLength队列集长度,最多能存放多少个数据(队列句柄)
返回值非0:成功,返回句柄,以后使用句柄来操作队列NULL:失败,因为内存不足

将队列加入队列集函数原型如下:

BaseType_t xQueueAddToSet( QueueSetMemberHandle_t xQueueOrSemaphore,QueueSetHandle_t xQueueSet );
参数说明
xQueueOrSemaphore队列句柄,这个队列要加入队列集
xQueueSet队列集句柄
返回值pdTRUE:成功pdFALSE:失败

读队列集函数原型如下:

QueueSetMemberHandle_t xQueueSelectFromSet( QueueSetHandle_t xQueueSet,TickType_t const xTicksToWait );
参数说明
xQueueSet队列集句柄
xTicksToWait如果队列集空则无法读出数据,可以让任务进入阻塞状态,xTicksToWait表示阻塞的最大时间(Tick Count)。如果被设为0,无法读出数据时函数会立刻返回;如果被设为portMAX_DELAY,则会一直阻塞直到有数据可写
返回值NULL:失败,队列句柄:成功

四、使用实例

1.顶层部分

 1)游戏函数(创建队列集)

static QueueHandle_t g_xQueuePlatform;    /* 接收创建挡球板队列函数返回值的变量(也可称为句柄) */
static QueueSetHandle_t g_xQueueSetInput; /* 接收创建队列集函数返回值的变量(也可称为句柄) */void game1_task(void *params)
{		    /* 创建挡球板数据队列 */g_xQueuePlatform = xQueueCreate(10, sizeof(struct input_data));/* 创建队列集,长度为写入队列集的所有队列的长度之和 */g_xQueueSetInput = xQueueCreateSet(IR_QUEUE_LEN + ROTARY_QUEUE_LEN + MPU6050_QUEUE_LEN);/* 得到各设备原始数据队列的句柄 */ g_xQueueIR = GetQueueIR();g_xQueueRotary = GetQueueRotary();g_xQueueMPU6050 = GetQueueMPU6050();/* 将原始数据队列添加进队列集 */xQueueAddToSet(g_xQueueIR, g_xQueueSetInput);xQueueAddToSet(g_xQueueRotary, g_xQueueSetInput);xQueueAddToSet(g_xQueueMPU6050, g_xQueueSetInput);/* 创建MPU6050任务 */xTaskCreate(MPU6050_Task, "MPU6050Task", 128, NULL, osPriorityNormal, NULL);/* 创建数据处理任务InputTask */xTaskCreate(InputTask, "InputTask", 128, NULL, osPriorityNormal, NULL);/* 其他代码 */...
}

2)中间数据转换函数(使用队列集)

/* 红外遥控器数据转换函数 */
static void ProcessIRData(void)
{/* 将红外遥控器原始数据转换成挡球板控制数据 */.../* 写挡球板队列 */xQueueSend(g_xQueuePlatform, &input, 0);
}/* 旋转编码器数据转换函数 */
static void ProcessRotaryData(void)
{/* 将旋转编码器原始数据转换成挡球板控制数据 */.../* 写挡球板队列 */xQueueSend(g_xQueuePlatform, &input, 0);
}/* MPU6050数据转换函数 */
static void ProcessRotaryData(void)
{/* 将MPU6050原始数据转换成挡球板控制数据 */.../* 写挡球板队列 */xQueueSend(g_xQueuePlatform, &input, 0);
}/********************输入任务,检测多个输入设备并调用对应处理函数********************/
static void InputTask(void *params)
{/* 接收不同句柄,选择不同处理方式 */QueueSetMemberHandle_t xQueueHandle;while (1){/* 读队列集, 得到有数据的队列句柄 */xQueueHandle = xQueueSelectFromSet(g_xQueueSetInput, portMAX_DELAY);if (xQueueHandle){/* 读队列句柄得到数据,处理数据 */if (xQueueHandle == g_xQueueIR){ProcessIRData();}else if (xQueueHandle == g_xQueueRotary){ProcessRotaryData();}			else if (xQueueHandle == g_xQueueMPU6050){ProcessMPU6050Data();}			}}
}

2.红外遥控器部分

1)创建原始数据接收队列

/************************************** 一些参数 **************************************/
#define IR_QUEUE_LEN 10static QueueHandle_t g_xQueueIR; /* 接收创建红外遥控器队列函数返回值的变量(也可称为句柄) */struct ir_data {                 /* 红外遥控器数据结构体 */uint32_t dev;uint32_t val;
};/*************************** 初始化,顺便创建设备原始数据队列 ***************************/
void IRReceiver_Init(void)
{/* 其他代码 */.../* 创建红外遥控器数据队列 */g_xQueueIR = xQueueCreate(IR_QUEUE_LEN, sizeof(struct ir_data));
}

2)存储原始数据

/*************************** 处理原始数据并存入自己的队列 ***************************/
static int IRReceiver_IRQTimes_Parse(void)
{/* 前置代码 */.../* 写红外遥控原始数据队列 */struct ir_data data;data.dev = dev;data.val = val;xQueueSendFromISR(g_xQueueIR, &idata, NULL);
}/*************************** 采集原始数据,回调数据处理函数 ***************************/
void IRReceiver_IRQ_Callback(void)
{/* 前置代码 */...IRReceiver_IRQTimes_Parse();
}

3.)创建句柄返回函数

/***************************句柄返回函数,用于队列集使用***************************/
QueueHandle_t GetQueueIR(void)
{return g_xQueueIR;
}

旋转编码器部分

1) 创建原始数据接收队列

/************************************** 一些参数 **************************************/
#define ROTARY_QUEUE_LEN 10struct rotary_data {                             /* 旋转编码器数据结构体 */int32_t cnt;int32_t speed;
};static QueueHandle_t g_xQueueRotary;             /* 接收创建旋转编码器队列函数返回值的变量(也可称为句柄) */    
static StaticQueue_t g_xQueueRotaryStaticStruct; /* 实例化FreeRTOS给出的结构体 */ 
static uint8_t g_ucQueueRotaryBuf[ROTARY_QUEUE_LEN*sizeof(struct rotary_data)]; /* 静态创建开辟的空间 */ /*************************** 初始化,顺便创建设备原始数据队列 ***************************/
void RotaryEncoder_Init(void)
{/* 前置代码 */.../* 静态创建旋转编码器数据队列 */g_xQueueRotary   = xQueueCreateStatic(ROTARY_QUEUE_LEN, sizeof(struct rotary_data), g_ucQueueRotaryBuf, &g_xQueueRotaryStaticStruct);
}

2)存储原始数据

/*************************** 采集原始数据存入自己的队列 ***************************/
void RotaryEncoder_IRQ_Callback(void)
{/* 其他代码 */...struct rotary_data rdata;rdata.cnt   = cnt;rdata.speed = speed;xQueueSendFromISR(g_xQueueRotary, &rdata, NULL);
}

3)创建句柄返回函数

/*************************** 句柄返回函数,用于队列集使用 ***************************/
QueueHandle_t GetQueueRotary(void)
{return g_xQueueRotary;
}

3.MPU6050部分

1)创建原始数据接收队列

/************************************** 一些参数 **************************************/
#define MPU6050_QUEUE_LEN 10static QueueHandle_t g_xQueueMPU6050; /* 接收创建MPU6050原始数据队列函数返回值的变量(也可称为句柄) */struct mpu6050_data {                 /* MPU6050数据结构体 */int32_t angle_x;
};/*************************** 初始化,顺便创建设备原始数据队列 ***************************/
void IRReceiver_Init(void)
{/* 其他代码 */.../* 创建MPU6050数据队列 */g_xQueueMPU6050 = xQueueCreate(MPU6050_QUEUE_LEN, sizeof(struct mpu6050_data));
}

2)将原始数据写入设备队列

void MPU6050_Task(void *params)
{	int16_t AccX;struct mpu6050_data result;int ret;extern volatile int bInUsed;while (1){    /* 读数据 */while (bInUsed);bInUsed = 1;ret = MPU6050_ReadData(&AccX, NULL, NULL, NULL, NULL, NULL);bInUsed = 0;if (0 == ret){/* 解析数据 */MPU6050_ParseData(AccX, 0, 0, 0, 0, 0, &result);/* 写队列 */xQueueSend(g_xQueueMPU6050, &result, 0);}/* delay */vTaskDelay(50);}
}

3)创建句柄返回函数

/***************************句柄返回函数,用于队列集使用***************************/
QueueHandle_t GetQueueMPU6050(void)
{return g_xQueueMPU6050;
}

五、程序小bug(处理方式见后文)

程序 bug ,屏幕和MPU6050使用了同一个 IIC ,长时间使用会导致屏幕显示出现问题

解决方法:

使用全局变量作为能否使用IIC的标志位

增加互斥操作让两个外设不能同时使用,保证通信时序的正常(或者使用两个IIC)

http://www.dtcms.com/a/412325.html

相关文章:

  • SQL语句详细使用说明 - 适合小白入门
  • 天水网站建设惠普网站暂时关闭 seo
  • 做网站如何对接支付gpu服务器租用价格
  • 检查一个字符串是否包含所有长度为K的二进制子串
  • 做网站需要多少空间芜湖网站建设兼职
  • 森动网网站建设好吗自己开发app要钱吗
  • 携程网站建设在阿里巴巴上做网站需要什么条件
  • 北京建设部网站职称网站建设硬件投入表
  • 视频防录屏软件为什么受欢迎?---以点盾云为例
  • 开源AI工具Mobile-Use
  • 做课件ppt网站上海十大网站建设
  • 新乡网站建设策划ftp网站怎么看后台的代码
  • numpy谨慎升级
  • 微信公众号登录wordpress网站吗免费自助小型网站
  • 站长之家官网做co的网站
  • 网站开发语言哪个好聊天网站模板
  • 河南省住房城乡和建设厅网站首页货代到哪个网站开发客户
  • 一元夺宝网站建设2017安徽安庆怎么样
  • 个人网站建设费用做植物提取物的专业网站
  • 做网站的周记10个免费的黑科技网站
  • python做网站好吗app多少钱能做一个
  • 各网站收录常用网站建设软件有哪些
  • 做网站订金为什么需要交那么多职业生涯规划大赛获奖作品
  • 电子商务网站需要做那些准备工作淄博张店外贸建站公司
  • 肇庆网站上排名做网站用html还是python好
  • 怎么网站建设易企推
  • 一级a视网站 做爰片公司网站建设 阜阳
  • 河北婚庆网站建设定制wordpress更改域名后
  • PE文件格式
  • 做网站充值微信必须是企业机关网站建设总结