前情提要
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;
}
逻辑分析仪抓取波形如下:

FreeRTOS ~(五)队列的常规使用 ~ (1/5)队列解决同步缺陷-LMLPHP

这里用到了三个函数:

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:读取失败,因为队列空了.


后面会把队列相关的函数统一做一个整理.
07-07 06:45