前情提要
FreeRTOS ~(四)同步互斥与通信 ~ (1/3)同步的缺陷
举例子说明:利用队列解决前述的"同步的缺陷"问题
static int sum = 0; /* sum存放计算的结果 */
static volatile int flagCalcEnd = 0; /* 标志位,用于逻辑分析仪抓取代码执行时长 */
static QueueHandle_t xQueueCalcHandle; /* 队列句柄 */
void Task1Function(void * param)
{
/* 这里故意加上 volatile 防止系统优化掉 */
volatile int i = 0;
while(1)
{
for(i = 0; i < 10000000; i++)
sum++;
/* 计算完成,将计算结果写入队列,传入的是地址
portMAX_DELAY的意思是阻塞的时长,下文介绍这个函数时会详解 */
xQueueSend(xQueueCalcHandle, &sum, portMAX_DELAY);
/* 这里设置sum为1,想要说明的是,上面传入的sum值不会由于后面的赋值而更改 */
sum = 1;
}
}
void Task2Function(void * param)
{
/* 用于接收sum的值 */
int val;
while(1)
{
/* 这里利用flag的目的是:利用逻辑分析仪查看Task2等待队列读取数据耗时
这个耗时也几乎是Task1完成那个复杂计算的时长,
FreeRTOS在这里优点就是:
使用了队列读取数据,当队列中有数据的时候,才会唤醒Task2来进行读取操作 */
flagCalcEnd = 0;
xQueueReceive(xQueueCalcHandle, &val, portMAX_DELAY);
flagCalcEnd = 1;
printf("sum = %d\r\n", val);
}
}
int main( void )
{
TaskHandle_t xHandleTask1;
prvSetupHardware();
/* 创建队列,队列中有2个Item,每个Item的大小是sizeof(int)
具体以实际需要为准,这里由于sum是int类型的,队列想要传输的也是sum的值
这里的2并不是只能是2个,而是只要大于等于1个就可以,根据具体需求选择大小 */
xQueueCalcHandle = xQueueCreate(2, sizeof(int));
if (xQueueCalcHandle == NULL)
{
printf("can not create queue\r\n");
}
xTaskCreate(Task1Function,"Task1",100,NULL,1,&xHandleTask1);
xTaskCreate(Task2Function,"Task2",100,NULL,1,NULL);
/* Start the scheduler. */
vTaskStartScheduler();
return 0;
}
逻辑分析仪抓取波形如下:
这里用到了三个函数:
1.创建队列 --- 动态分配内存
--- 函数原型:
QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength, UBaseType_t uxItemSize );
--- 参数:
uxQueueLength :队列长度,最多能存放多少个数据(item).
uxItemSize :每个数据(item)的大小:以字节为单位.
--- 返回值:
非 0 :成功,返回句柄,以后使用句柄来操作队列.
NULL :失败,因为内存不足.
2.写队列
--- 函数原型:
BaseType_t xQueueSend( QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait );
--- 参数:
xQueue :队列句柄,要写哪个队列.
pvItemToQueue :数据指针,这个数据的值会被复制进队列,复制多大的数据?在创建队列时已经指定了数据大小.
xTicksToWait :如果队列满则无法写入新数据,可以让任务进入阻塞状态,
xTicksToWait 表示阻塞的最大时间(Tick Count).
如果被设为 0,无法写入数据时函数会立刻返回;
如果被设为 portMAX_DELAY,则会一直阻塞直到有空间可写.
--- 返回值 :pdPASS :数据成功写入了队列.
errQUEUE_FULL :写入失败,因为队列满了.
/* 等同于 xQueueSendToBack 往队列尾部写入数据,如果没有空间,阻塞时间为 xTicksToWait */
3.读队列
--- 函数原型:
BaseType_t xQueueReceive( QueueHandle_t xQueue,void * const pvBuffer,TickType_t xTicksToWait );
--- 参数:
xQueue :队列句柄,要读哪个队列.
pvBuffer :bufer 指针,队列的数据会被复制到这个buffer,复制多大的数据?在创建队列时已经指定了数据大小.
xTicksToWait :如果队列空则无法读出新数据,可以让任务进入阻塞状态,
xTicksToWait 表示阻塞的最大时间(Tick Count).
如果被设为 0,无法读取数据时函数会立刻返回;
如果被设为 portMAX_DELAY,则会一直阻塞直到有数据可读.
--- 返回值 :pdPASS :从队列读取数据成功.
errQUEUE_EMPTY:读取失败,因为队列空了.
后面会把队列相关的函数统一做一个整理.