FreeRTOS 数据传输方法(环形buffer,队列的本质)队列实验—多设备玩游戏

ops/2024/10/30 18:37:57/

 数据传输方法

环形buffer

环形buffer的本质就是一个循环队列,但是有一些不同 

  1. :当头指针和尾指针相等时,表示缓冲区为空。
  2. :当尾指针的下一个位置等于头指针时,表示缓冲区已满(在环形结构中,尾指针要循环到数组的开始位置)。

队列

队列的本质

在嵌入式中队列运行就像一个流水线工作,其中有两个工人

A的作用

(1)写队列

(2)如果队列已满则可以进行对任务A处理(具体是把任务A放入SenderList链表以及阻塞Block链表

(3)任务B如何被唤醒,要么由任务A唤醒任务B,要么结束阻塞,通过Tick中断唤醒B,把任务B放入ReadyList

B的作用

(1)查看流水线有无任务(产品),没有的话将进行阻塞(眯一会)(相当于把任务放入Receiverlist链表以及阻塞Block链表

(2)读队列

(3)任务B读队列,唤醒任务A,通过Tick中断唤醒A,把任务A放入ReadyList

队列的阻塞访问

只要知道队列的句柄,谁都可以读、写该队列。任务、ISR 都可读、写队列。可以多个
任务读写队列。
任务读写队列时,简单地说:如果读写不成功,则阻塞;可以指定超时时间。口语化地
说,就是可以定个闹钟:如果能读写了就马上进入就绪态,否则就阻塞直到超时。
某个任务读队列时,如果队列没有数据,则该任务可以进入阻塞状态:还可以指定阻塞
的时间。如果队列有数据了,则该阻塞的任务会变为就绪态。如果一直都没有数据,则时间
到之后它也会进入就绪态。
既然读取队列的任务个数没有限制,那么当多个任务读取空队列时,这些任务都会进入
阻塞状态:有多个任务在等待同一个队列的数据。当队列中有数据时,哪个任务会进入就绪
态?
优先级最高的任务
如果大家的优先级相同,那等待时间最久的任务会进入就绪态
跟读队列类似,一个任务要写队列时,如果队列满了,该任务也可以进入阻塞状态:还
可以指定阻塞的时间。如果队列有空间了,则该阻塞的任务会变为就绪态。如果一直都没有
空间,则时间到之后它也会进入就绪态。
既然写队列的任务个数没有限制,那么当多个任务写 " 满队列 " 时,这些任务都会进入阻
塞状态:有多个任务在等待同一个队列的空间。当队列中有空间时,哪个任务会进入就绪态?
优先级最高的任务
如果大家的优先级相同,那等待时间最久的任务会进入就绪态

队列函数

创建

队列的创建有两种方法:动态分配内存、静态分配内存

动态分配内存
动态分配内存: xQueueCreate ,队列的内存在函数内部动态分配
QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength, UBaseType_t uxItemSize );

参数说明:

  1. uxQueueLength:队列中可以存放的最大项数(队列长度)。
  2. uxItemSize:每个队列项的大小(以字节为单位)。如果要存储的项是结构体或者其他数据类型,确保传入正确的大小。

返回值:

  • 返回一个队列句柄(QueueHandle_t),如果创建成功,句柄有效;如果失败,返回 NULL
静态分配内存
静态分配内存: xQueueCreateStatic ,队列的内存要事先分配好
QueueHandle_t xQueueCreateStatic(UBaseType_t uxQueueLength,UBaseType_t uxItemSize,uint8_t *pucQueueStorageBuffer,StaticQueue_t *pxQueueBuffer);

参数说明:

  1. uxQueueLength:队列可以存放的最大项数(队列长度)。
  2. uxItemSize:每个队列项的大小(以字节为单位)。
  3. pucQueueStorageBuffer:指向用于存储队列项的缓冲区的指针。这个缓冲区的大小应该为 uxQueueLength * uxItemSize
  4. pxQueueBuffer:指向一个 StaticQueue_t 结构体的指针,用于存储队列的控制结构。此结构体在 FreeRTOS 中被用于管理队列的状态。

返回值:

  • 返回一个队列句柄(QueueHandle_t),如果创建成功,句柄有效;如果失败,返回 NULL
写队列
/* 等同于xQueueSendToBack
* 往队列尾部写入数据,如果没有空间,阻塞时间为xTicksToWait
*/
BaseType_t xQueueSend(QueueHandle_t xQueue,const void *pvItemToQueue,TickType_t xTicksToWait);
/* 
* 往队列尾部写入数据,如果没有空间,阻塞时间为xTicksToWait
*/
BaseType_t xQueueSendToBack(QueueHandle_t xQueue,const void *pvItemToQueue,TickType_t xTicksToWait);
/* 
* 往队列尾部写入数据,此函数可以在中断函数中使用,不可阻塞
*/
BaseType_t xQueueSendToBackFromISR(QueueHandle_t xQueue,const void *pvItemToQueue,BaseType_t *pxHigherPriorityTaskWoken);
/* 
* 往队列头部写入数据,如果没有空间,阻塞时间为xTicksToWait
*/
BaseType_t xQueueSendToFront(QueueHandle_t xQueue,const void *pvItemToQueue,TickType_t xTicksToWait);
/* 
* 往队列头部写入数据,此函数可以在中断函数中使用,不可阻塞
*/
BaseType_t xQueueSendToFrontFromISR(QueueHandle_t xQueue,const void *pvItemToQueue,BaseType_t *pxHigherPriorityTaskWoken);

 

参数说明:

  1. xQueue:要发送项的队列句柄。
  2. pvItemToQueue:指向要发送到队列的项的指针。此项的数据类型应与队列在创建时指定的数据类型匹配。
  3. xTicksToWait:如果队列已满,调用任务将等待的时间(以滴答数为单位)。可以使用 portMAX_DELAY 表示无限等待,或使用 0 表示不等待。

返回值:

  • 返回值为 BaseType_t,表示发送操作的结果。可能的返回值包括:
    • pdPASS:成功将项发送到队列。
    • errQUEUE_FULL:队列已满,未能发送项(且没有设置等待时间或等待时间已到)。
static int IRReceiver_IRQTimes_Parse(void)
{uint64_t time;int i;int m, n;unsigned char datas[4];unsigned char data = 0;int bits = 0;int byte = 0;struct input_data idata;/* 1. 判断前导码 : 9ms的低脉冲, 4.5ms高脉冲  */time = g_IRReceiverIRQ_Timers[1] - g_IRReceiverIRQ_Timers[0];if (time < 8000000 || time > 10000000){return -1;}time = g_IRReceiverIRQ_Timers[2] - g_IRReceiverIRQ_Timers[1];if (time < 3500000 || time > 55000000){return -1;}/* 2. 解析数据 */for (i = 0; i < 32; i++){m = 3 + i*2;n = m+1;time = g_IRReceiverIRQ_Timers[n] - g_IRReceiverIRQ_Timers[m];data <<= 1;bits++;if (time > 1000000){/* 得到了数据1 */data |= 1;}if (bits == 8){datas[byte] = data;byte++;data = 0;bits = 0;}}/* 判断数据正误 */datas[1] = ~datas[1];datas[3] = ~datas[3];if ((datas[0] != datas[1]) || (datas[2] != datas[3])){g_IRReceiverIRQ_Cnt = 0;return -1;}//PutKeyToBuf(datas[0]);//PutKeyToBuf(datas[2]);/* 写队列 */idata.dev = datas[0];if (datas[2] == 0xe0)idata.val = UPT_MOVE_LEFT;else if (datas[2] == 0x90)idata.val = UPT_MOVE_RIGHT;elseidata.val = UPT_MOVE_NONE;g_last_val = idata.val;xQueueSendFromISR(g_xQueuePlatform, &idata, NULL);return 0;
}

读队列
BaseType_t xQueueReceive( QueueHandle_t xQueue,void * const pvBuffer,TickType_t xTicksToWait );
BaseType_t xQueueReceiveFromISR(QueueHandle_t xQueue,void *pvBuffer,BaseType_t *pxTaskWoken);
1. xQueueReceive

参数说明

  • xQueue:要从中接收数据的队列句柄。
  • pvBuffer:指向接收数据存储位置的指针。接收到的数据将存储在这里。
  • xTicksToWait:如果队列为空,任务等待的最大时间(以滴答为单位)。可以使用 portMAX_DELAY 表示无限等待。

返回值

  • 如果成功接收数据,返回 pdPASS;如果超时或发生错误,返回 errQUEUE_EMPTY
2. xQueueReceiveFromISR

参数说明

  • xQueue:要从中接收数据的队列句柄。
  • pvBuffer:指向接收数据存储位置的指针。
  • pxTaskWoken:指向 BaseType_t 类型的指针,如果接收数据后需要唤醒一个任务,设置为 pdTRUE,否则设置为 pdFALSE

返回值

  • 与 xQueueReceive 相似,成功时返回 pdPASS,失败时返回 errQUEUE_EMPTY
/* 挡球板任务 */
static void platform_task(void *params)
{byte platformXtmp = platformX;    uint8_t dev, data, last_data;struct input_data idata;// Draw platformdraw_bitmap(platformXtmp, g_yres - 8, platform, 12, 8, NOINVERT, 0);draw_flushArea(platformXtmp, g_yres - 8, 12, 8);while (1){//if (0 == IRReceiver_Read(&dev, &data))xQueueReceive(g_xQueuePlatform, &idata, portMAX_DELAY);uptMove = idata.val;// Hide platformdraw_bitmap(platformXtmp, g_yres - 8, clearImg, 12, 8, NOINVERT, 0);draw_flushArea(platformXtmp, g_yres - 8, 12, 8);// Move platformif(uptMove == UPT_MOVE_RIGHT)platformXtmp += 3;else if(uptMove == UPT_MOVE_LEFT)platformXtmp -= 3;uptMove = UPT_MOVE_NONE;// Make sure platform stays on screenif(platformXtmp > 250)platformXtmp = 0;else if(platformXtmp > g_xres - PLATFORM_WIDTH)platformXtmp = g_xres - PLATFORM_WIDTH;// Draw platformdraw_bitmap(platformXtmp, g_yres - 8, platform, 12, 8, NOINVERT, 0);draw_flushArea(platformXtmp, g_yres - 8, 12, 8);platformX = platformXtmp;            		}
}

注意

写队列就是在中断中写取数据,在进行复杂的操作时,连接一个中间的任务处理数据然后再提交

/* 挡球板任务 */
static void platform_task(void *params)
{byte platformXtmp = platformX;    uint8_t dev, data, last_data;struct input_data idata;// Draw platformdraw_bitmap(platformXtmp, g_yres - 8, platform, 12, 8, NOINVERT, 0);draw_flushArea(platformXtmp, g_yres - 8, 12, 8);while (1){//if (0 == IRReceiver_Read(&dev, &data))xQueueReceive(g_xQueuePlatform, &idata, portMAX_DELAY);uptMove = idata.val;// Hide platformdraw_bitmap(platformXtmp, g_yres - 8, clearImg, 12, 8, NOINVERT, 0);draw_flushArea(platformXtmp, g_yres - 8, 12, 8);// Move platformif(uptMove == UPT_MOVE_RIGHT)platformXtmp += 3;else if(uptMove == UPT_MOVE_LEFT)platformXtmp -= 3;uptMove = UPT_MOVE_NONE;// Make sure platform stays on screenif(platformXtmp > 250)platformXtmp = 0;else if(platformXtmp > g_xres - PLATFORM_WIDTH)platformXtmp = g_xres - PLATFORM_WIDTH;// Draw platformdraw_bitmap(platformXtmp, g_yres - 8, platform, 12, 8, NOINVERT, 0);draw_flushArea(platformXtmp, g_yres - 8, 12, 8);platformX = platformXtmp;            		}
}static void RotaryEncoderTask(void *params)
{struct rotary_data rdata;struct input_data idata;int left;int i, cnt;while (1){/* 读旋转编码器队列 */xQueueReceive(g_xQueueRotary, &rdata, portMAX_DELAY);/* 处理数据 *//* 判断速度: 负数表示向左转动, 正数表示向右转动 */if (rdata.speed < 0){left = 1;rdata.speed = 0 - rdata.speed;}else{left = 0;}//cnt = rdata.speed / 10;//if (!cnt)//	cnt = 1;if (rdata.speed > 100)cnt = 4;else if (rdata.speed > 50)cnt = 2;elsecnt = 1;/* 写挡球板队列 */idata.dev = 1;idata.val = left ? UPT_MOVE_LEFT : UPT_MOVE_RIGHT;for (i = 0; i < cnt; i++){xQueueSend(g_xQueuePlatform, &idata, 0);}}
}


http://www.ppmy.cn/ops/129660.html

相关文章

【界面改版】JimuReport 积木报表 v1.9.0 版本发布,填报优化和大屏能力

项目介绍 积木报表JimuReport&#xff0c;是一款免费的数据可视化报表&#xff0c;含报表、仪表盘和大屏设计&#xff0c;像搭建积木一样完全在线设计&#xff01;功能涵盖&#xff1a;数据报表、打印设计、图表报表、门户设计、大屏设计等&#xff01; Web版报表设计器&#x…

怎么理解ES6 Proxy

Proxy 可以理解成&#xff0c;在目标对象之前架设一层 “拦截”&#xff0c;外界对该对象的访问&#xff0c;都必须先通过这层拦截&#xff0c;因此提供了一种机制&#xff0c;可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理&#xff0c;用在这里表示由它来 “代理…

Stream 的使用和基本原理

&#xff08;2023年3月公司内部培训&#xff09; Stream 的定义 Stream将要处理的元素集合看作一种流&#xff0c;在流的过程中&#xff0c;借助Stream API对流中的元素进行操作&#xff0c;比如&#xff1a;筛选、排序、聚合等。 对流的操作 Stream可以由数组或集合创建&am…

【Hive复杂数据类型和函数】全网总结最全的Hive函数

文章目录 一、复杂数据类型的建表语句1、array2、map3、struct 二、Hive函数1、炸裂函数explode&#xff08;行转列&#xff09;2、日期函数3、字符串函数4、类型转换函数5、其他函数6、窗口函数7、序列函数8、排名函数9、自定义函数 一、复杂数据类型的建表语句 1、array cr…

聊聊Web3D 发展趋势

随着 Web 技术的不断演进&#xff0c;Web3D 正逐渐成为各行业数字化的重要方向。Web3D 是指在网页中展示 3D 内容的技术集合。近年来&#xff0c;由于 WebGL、WebGPU 等技术的发展&#xff0c;3D 内容已经能够直接在浏览器中渲染&#xff0c;为用户提供更加沉浸、互动的体验。以…

【AIGC】2024-arXiv-Lumiere:视频生成的时空扩散模型

2024-arXiv-Lumiere: A Space-Time Diffusion Model for Video Generation Lumiere&#xff1a;视频生成的时空扩散模型摘要1. 引言2. 相关工作3. Lumiere3.1 时空 U-Net (STUnet)3.2 空间超分辨率的多重扩散 4. 应用4.1 风格化生成4.2 条件生成 5. 评估和比较5.1 定性评估5.2 …

力扣周赛Q1.出现在屏幕上字符串序列

给你一个字符串 target。 Alice 将会使用一种特殊的键盘在她的电脑上输入 target&#xff0c;这个键盘 只有两个 按键&#xff1a; 按键 1&#xff1a;在屏幕上的字符串后追加字符 a。 按键 2&#xff1a;将屏幕上字符串的 最后一个 字符更改为英文字母表中的 下一个 字符。例…

卷积神经网络实验三:模型优化(1)

作者有话说&#xff1a; 这篇文章写的还是比混乱的。因为本人也是第一次做这样的尝试&#xff0c;虽然接触深度学习有一年了&#xff0c;但是对于模型的优化仅仅是局限于理论上。通过这一次的实验&#xff0c;我对于模型的理解也更深了几分。我不期望这篇文章能帮你能解决多大问…