挡球板游戏框架优化优化图如下图所示,核心思路为:
对于不同控制器创建不同的队列,由队列集统一接收提交给上层进行数据处理,然后将处理过的数据交给挡球板任务,挡球板任务根据接收到的数据进行对应移动。

使用红外遥控控制挡球板时可以使用中断函数完成,这是因为红外遥控是通过多个中断之间的的绝对时间差来判断具体数据的,不涉及到硬件层的传输协议。
使用旋转编码器控制挡球板时,也可以使用中断函数完成,这是因为旋转编码器是通过读取A相与B相的高低电平来判断具体数据的,不涉及到硬件层的传输协议。具体规则如下图:

但是对于MPU6050姿态传感器而言,MPU6050需要通过I2C完成数据传输,I2C的传输时间对于一个中断而言过长了,因此我们不能使用中断获取姿态数据。
我们可以通过创建一个任务:MPU6050Task,在任务中使用while(1)轮询读取数据,并使用vTaskDelay在未读取到数据时释放CPU资源。
注意,使用这种方法时,需要确保g_xQueueMPU6050(姿态队列)加入队列集后再创建MPU6050Task,否则会出现姿态控制失效的情况,这是因为:
- 上电后,在MPU6050的初始化函数中创建了g_xQueueMPU6050。
- MPU6050Task创建完成,但此时g_xQueueMPU6050还没有加入队列集。
- MPU6050Task一经创建便开始获取姿态数据,并在解析数据后写入g_xQueueMPU6050中,这个过程是非常快的。
- 在获得等同于g_xQueueMPU6050容量上限的数据后,g_xQueueMPU6050无法被写入,除非g_xQueueMPU6050中的数据被读出。
- 现在,g_xQueueMPU6050加入了队列集,InputTask(输入任务)开始运行,通过while(1)轮询读取队列集,得到对应的队列句柄。(为了方便理解,下面附上InputTask的代码)
- 红外队列与旋转队列此时均为空,当中断产生时,会将数据写入队列中,同时将对应的队列句柄写入队列集,队列集得到队列句柄就可以分析数据了。
- 根据代码我们可以知道:如果g_xQueueMPU6050已经满了,那么MPU6050Task无法将新获得的数据写入g_xQueueMPU6050,也就无法同时将g_xQueueMPU6050写入队列集中。xQueueSelectFromSet得到的队列句柄将不可能是g_xQueueMPU6050,那么ProcessMPU6050Data()也就不可能执行了。
1 | static void InputTask(void *params) |
如果在g_xQueueMPU6050加入队列集后再创建MPU6050Task,那么MPU6050Task获取姿态数据,并在解析数据后写入g_xQueueMPU6050后,会顺带把g_xQueueMPU6050的队列句柄写入队列集中,这样xQHandle = xQueueSelectFromSet(g_xQueueSetInput, portMAX_DELAY);
语句就可以正常执行了,我们也就可以在后续的ProcessMPU6050Data();
语句中读取g_xQueueMPU6050的数据了。