00. 目录

01. 概述

掌握FreeRTOS中列表和列表项相关函数的使用。

02. 任务设计

3 个任务:start_task、task1_task 和task2_task,这三个任务的任务功能如下:

start_task:用来创建其他2 个任务。

task1_task:应用任务1,控制LED0 闪烁,用来提示系统正在运行。

task2_task: 列表和列表项操作任务,调用列表和列表项相关的API 函数,并且通过串口输出相应的信息来观察这些API 函数的运行过程。

需要用到KEY_UP 按键,用于控制任务的运行。

03. 相关设置

任务优先级和堆栈大小设置

//任务优先级
#define START_TASK_PRIO		1
//任务堆栈大小	
#define START_STK_SIZE 		128  
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);

//任务优先级
#define TASK1_TASK_PRIO		2
//任务堆栈大小	
#define TASK1_STK_SIZE 		50  
//任务句柄
TaskHandle_t Task1Task_Handler;
//任务函数
void task1_task(void *pvParameters);

//任务优先级
#define TASK2_TASK_PRIO		3
//任务堆栈大小	
#define TASK2_STK_SIZE 		50  
//任务句柄
TaskHandle_t Task2Task_Handler;
//任务函数
void task2_task(void *pvParameters);

列表和列表项定义

//列表和列表项定义
List_t list;
ListItem_t listItem1;
ListItem_t listItem2;
ListItem_t listItem3;

04. 程序设计

main.c文件

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h"
#include "FreeRTOS.h"
#include "task.h"


//任务优先级
#define START_TASK_PRIO		1
//任务堆栈大小	
#define START_STK_SIZE 		128  
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);

//任务优先级
#define TASK1_TASK_PRIO		2
//任务堆栈大小	
#define TASK1_STK_SIZE 		50  
//任务句柄
TaskHandle_t Task1Task_Handler;
//任务函数
void task1_task(void *pvParameters);

//任务优先级
#define TASK2_TASK_PRIO		3
//任务堆栈大小	
#define TASK2_STK_SIZE 		50  
//任务句柄
TaskHandle_t Task2Task_Handler;
//任务函数
void task2_task(void *pvParameters);

//列表和列表项定义
List_t list;
ListItem_t listItem1;
ListItem_t listItem2;
ListItem_t listItem3;


//主函数
int main(void)
{ 
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
	delay_init(168);		//初始化延时函数
	uart_init(115200);     	//初始化串口
	LED_Init();		        //初始化LED端口
	KEY_Init();  			//按键初始化
	
	//创建开始任务
    xTaskCreate((TaskFunction_t )start_task,            //任务函数
                (const char*    )"start_task",          //任务名称
                (uint16_t       )START_STK_SIZE,        //任务堆栈大小
                (void*          )NULL,                  //传递给任务函数的参数
                (UBaseType_t    )START_TASK_PRIO,       //任务优先级
                (TaskHandle_t*  )&StartTask_Handler);   //任务句柄              
    vTaskStartScheduler();          //开启任务调度
}
 
//开始任务任务函数
void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           //进入临界区
	
    //创建TASK1任务
    xTaskCreate((TaskFunction_t )task1_task,     	
                (const char*    )"task1_task",   	
                (uint16_t       )TASK1_STK_SIZE, 
                (void*          )NULL,				
                (UBaseType_t    )TASK1_TASK_PRIO,	
                (TaskHandle_t*  )&Task1Task_Handler);   
    //创建TASK2任务
    xTaskCreate((TaskFunction_t )task2_task,     
                (const char*    )"task2_task",   
                (uint16_t       )TASK2_STK_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )TASK2_TASK_PRIO,
                (TaskHandle_t*  )&Task2Task_Handler);        

    vTaskDelete(StartTask_Handler); //删除开始任务
				
    taskEXIT_CRITICAL();            //退出临界区
}

//任务1  不停的闪烁表示系统正在正常运行
void task1_task(void *pvParameters)
{
	while(1)
	{

		LED0 = !LED0;
		
		//延时1秒 1000个时钟节拍
		vTaskDelay(1000);
	}
}

//任务2  列表和列表项相关操作
void task2_task(void *pvParameters)
{
	
	//第一步:初始化列表和列表项
	vListInitialise(&list);
	vListInitialiseItem(&listItem1);
	vListInitialiseItem(&listItem2);
	vListInitialiseItem(&listItem3);
	
	listItem1.xItemValue=40;			//ListItem1列表项值为40
	listItem2.xItemValue=60;			//ListItem2列表项值为60
	listItem3.xItemValue=50;			//ListItem3列表项值为50
	
	//第二步:打印列表和其他列表项的地址
	printf("/*******************列表和列表项地址*******************/\r\n");
	printf("项目                              地址				    \r\n");
	printf("TestList                          %#x					\r\n",(int)&list);
	printf("TestList->pxIndex                 %#x					\r\n",(int)list.pxIndex);
	printf("TestList->xListEnd                %#x					\r\n",(int)(&list.xListEnd));
	printf("ListItem1                         %#x					\r\n",(int)&listItem1);
	printf("ListItem2                         %#x					\r\n",(int)&listItem2);
	printf("ListItem3                         %#x					\r\n",(int)&listItem3);
	printf("/************************结束**************************/\r\n");
	printf("按下KEY_UP键继续!\r\n\r\n\r\n");
	while(Key_Scan()!=WK_UP_PRESS) delay_ms(10);					//等待KEY_UP键按下
	
	
	//第三步:向列表TestList添加列表项ListItem1,并通过串口打印所有
	//列表项中成员变量pxNext和pxPrevious的值,通过这两个值观察列表
	//项在列表中的连接情况。
	vListInsert(&list,&listItem1);		//插入列表项ListItem1
	printf("/******************添加列表项ListItem1*****************/\r\n");
	printf("项目                              地址				    \r\n");
	printf("TestList->xListEnd->pxNext        %#x					\r\n",(int)(list.xListEnd.pxNext));
	printf("ListItem1->pxNext                 %#x					\r\n",(int)(listItem1.pxNext));
	printf("/*******************前后向连接分割线********************/\r\n");
	printf("TestList->xListEnd->pxPrevious    %#x					\r\n",(int)(list.xListEnd.pxPrevious));
	printf("ListItem1->pxPrevious             %#x					\r\n",(int)(listItem1.pxPrevious));
	printf("/************************结束**************************/\r\n");
	printf("按下KEY_UP键继续!\r\n\r\n\r\n");
	while(Key_Scan()!=WK_UP_PRESS) delay_ms(10);					//等待KEY_UP键按下	
	
	
	//第四步:向列表TestList添加列表项ListItem2,并通过串口打印所有
	//列表项中成员变量pxNext和pxPrevious的值,通过这两个值观察列表
	//项在列表中的连接情况。
	vListInsert(&list,&listItem2);	//插入列表项ListItem2
	printf("/******************添加列表项ListItem2*****************/\r\n");
	printf("项目                              地址				    \r\n");
	printf("TestList->xListEnd->pxNext        %#x					\r\n",(int)(list.xListEnd.pxNext));
	printf("ListItem1->pxNext                 %#x					\r\n",(int)(listItem1.pxNext));
	printf("ListItem2->pxNext                 %#x					\r\n",(int)(listItem2.pxNext));
	printf("/*******************前后向连接分割线********************/\r\n");
	printf("TestList->xListEnd->pxPrevious    %#x					\r\n",(int)(list.xListEnd.pxPrevious));
	printf("ListItem1->pxPrevious             %#x					\r\n",(int)(listItem1.pxPrevious));
	printf("ListItem2->pxPrevious             %#x					\r\n",(int)(listItem2.pxPrevious));
	printf("/************************结束**************************/\r\n");
	printf("按下KEY_UP键继续!\r\n\r\n\r\n");
	while(Key_Scan()!=WK_UP_PRESS) delay_ms(10);					//等待KEY_UP键按下	
	
	//第五步:向列表TestList添加列表项ListItem3,并通过串口打印所有
	//列表项中成员变量pxNext和pxPrevious的值,通过这两个值观察列表
	//项在列表中的连接情况。
	vListInsert(&list,&listItem3);	//插入列表项ListItem3
	printf("/******************添加列表项ListItem3*****************/\r\n");
	printf("项目                              地址				    \r\n");
	printf("TestList->xListEnd->pxNext        %#x					\r\n",(int)(list.xListEnd.pxNext));
	printf("ListItem1->pxNext                 %#x					\r\n",(int)(listItem1.pxNext));
	printf("ListItem3->pxNext                 %#x					\r\n",(int)(listItem3.pxNext));
	printf("ListItem2->pxNext                 %#x					\r\n",(int)(listItem2.pxNext));
	printf("/*******************前后向连接分割线********************/\r\n");
	printf("TestList->xListEnd->pxPrevious    %#x					\r\n",(int)(list.xListEnd.pxPrevious));
	printf("ListItem1->pxPrevious             %#x					\r\n",(int)(listItem1.pxPrevious));
	printf("ListItem3->pxPrevious             %#x					\r\n",(int)(listItem3.pxPrevious));
	printf("ListItem2->pxPrevious             %#x					\r\n",(int)(listItem2.pxPrevious));
	printf("/************************结束**************************/\r\n");
	printf("按下KEY_UP键继续!\r\n\r\n\r\n");
	while(Key_Scan()!=WK_UP_PRESS) delay_ms(10);					//等待KEY_UP键按下	
	

	//第六步:删除ListItem2,并通过串口打印所有列表项中成员变量pxNext和
	//pxPrevious的值,通过这两个值观察列表项在列表中的连接情况。
	uxListRemove(&listItem2);						//删除ListItem2
	printf("/******************删除列表项ListItem2*****************/\r\n");
	printf("项目                              地址				    \r\n");
	printf("TestList->xListEnd->pxNext        %#x					\r\n",(int)(list.xListEnd.pxNext));
	printf("ListItem1->pxNext                 %#x					\r\n",(int)(listItem1.pxNext));
	printf("ListItem3->pxNext                 %#x					\r\n",(int)(listItem3.pxNext));
	printf("/*******************前后向连接分割线********************/\r\n");
	printf("TestList->xListEnd->pxPrevious    %#x					\r\n",(int)(list.xListEnd.pxPrevious));
	printf("ListItem1->pxPrevious             %#x					\r\n",(int)(listItem1.pxPrevious));
	printf("ListItem3->pxPrevious             %#x					\r\n",(int)(listItem3.pxPrevious));
	printf("/************************结束**************************/\r\n");
	printf("按下KEY_UP键继续!\r\n\r\n\r\n");
	while(Key_Scan()!=WK_UP_PRESS) delay_ms(10);					//等待KEY_UP键按下	
	
	//第七步:插入ListItem2,并通过串口打印所有列表项中成员变量pxNext和
	//pxPrevious的值,通过这两个值观察列表项在列表中的连接情况。
	list.pxIndex=list.pxIndex->pxNext;			//pxIndex向后移一项,这样pxIndex就会指向ListItem1。
	vListInsertEnd(&list,&listItem2);				//列表末尾添加列表项ListItem2
	printf("/***************在末尾添加列表项ListItem2***************/\r\n");
	printf("项目                              地址				    \r\n");
	printf("TestList->pxIndex                 %#x					\r\n",(int)list.pxIndex);
	printf("TestList->xListEnd->pxNext        %#x					\r\n",(int)(list.xListEnd.pxNext));
	printf("ListItem2->pxNext                 %#x					\r\n",(int)(listItem2.pxNext));
	printf("ListItem1->pxNext                 %#x					\r\n",(int)(listItem1.pxNext));
	printf("ListItem3->pxNext                 %#x					\r\n",(int)(listItem3.pxNext));
	printf("/*******************前后向连接分割线********************/\r\n");
	printf("TestList->xListEnd->pxPrevious    %#x					\r\n",(int)(list.xListEnd.pxPrevious));
	printf("ListItem2->pxPrevious             %#x					\r\n",(int)(listItem2.pxPrevious));
	printf("ListItem1->pxPrevious             %#x					\r\n",(int)(listItem1.pxPrevious));
	printf("ListItem3->pxPrevious             %#x					\r\n",(int)(listItem3.pxPrevious));
	printf("/************************结束**************************/\r\n\r\n\r\n");
	while(1)
	{
		LED1=!LED1;
        vTaskDelay(1000);                           //延时1s,也就是1000个时钟节拍	
	}
	
}

05. 实验结果

/*******************列表和列表项地址*******************/
项目                              地址				    
TestList                          0x200000bc					
TestList->pxIndex                 0x200000c4					
TestList->xListEnd                0x200000c4					
ListItem1                         0x200000d0					
ListItem2                         0x200000e4					
ListItem3                         0x200000f8					
/************************结束**************************/
按下KEY_UP键继续!


/******************添加列表项ListItem1*****************/
项目                              地址				    
TestList->xListEnd->pxNext        0x200000d0					
ListItem1->pxNext                 0x200000c4					
/*******************前后向连接分割线********************/
TestList->xListEnd->pxPrevious    0x200000d0					
ListItem1->pxPrevious             0x200000c4					
/************************结束**************************/
按下KEY_UP键继续!


/******************添加列表项ListItem2*****************/
项目                              地址				    
TestList->xListEnd->pxNext        0x200000d0					
ListItem1->pxNext                 0x200000e4					
ListItem2->pxNext                 0x200000c4					
/*******************前后向连接分割线********************/
TestList->xListEnd->pxPrevious    0x200000e4					
ListItem1->pxPrevious             0x200000c4					
ListItem2->pxPrevious             0x200000d0					
/************************结束**************************/
按下KEY_UP键继续!


/******************添加列表项ListItem3*****************/
项目                              地址				    
TestList->xListEnd->pxNext        0x200000d0					
ListItem1->pxNext                 0x200000f8					
ListItem3->pxNext                 0x200000e4					
ListItem2->pxNext                 0x200000c4					
/*******************前后向连接分割线********************/
TestList->xListEnd->pxPrevious    0x200000e4					
ListItem1->pxPrevious             0x200000c4					
ListItem3->pxPrevious             0x200000d0					
ListItem2->pxPrevious             0x200000f8					
/************************结束**************************/
按下KEY_UP键继续!


/******************删除列表项ListItem2*****************/
项目                              地址				    
TestList->xListEnd->pxNext        0x200000d0					
ListItem1->pxNext                 0x200000f8					
ListItem3->pxNext                 0x200000c4					
/*******************前后向连接分割线********************/
TestList->xListEnd->pxPrevious    0x200000f8					
ListItem1->pxPrevious             0x200000c4					
ListItem3->pxPrevious             0x200000d0					
/************************结束**************************/
按下KEY_UP键继续!


/***************在末尾添加列表项ListItem2***************/
项目                              地址				    
TestList->pxIndex                 0x200000d0					
TestList->xListEnd->pxNext        0x200000e4					
ListItem2->pxNext                 0x200000d0					
ListItem1->pxNext                 0x200000f8					
ListItem3->pxNext                 0x200000c4					
/*******************前后向连接分割线********************/
TestList->xListEnd->pxPrevious    0x200000f8					
ListItem2->pxPrevious             0x200000c4					
ListItem1->pxPrevious             0x200000e4					
ListItem3->pxPrevious             0x200000d0					
/************************结束**************************/

06. 附录

6.1 【STM32】STM32系列教程汇总

网址:【STM32】STM32系列教程汇总

07. 参考

《FreeRTOS Reference Manual》

《Using the FreeRTOS Real Time Kernel -A Practical Guide》

《The Definitive Guide to ARM Cortex-M3 and Cortex-M4 Processors,3rd Edition》