【复习笔记】FreeRTOS(四) 列表项的插入和删除

本文是FreeRTOS复习笔记的第四节,列表项的插入和删除。

上一篇文章: 【复习笔记】FreeRTOS(三)任务挂起和恢复

文章目录

  • 一、列表和列表项
    • 1.1. 列表
    • 1.2. 列表项
    • 1.3. 迷你列表项
  • 二、实验目的
  • 三、测试例程
  • 四、实验效果


一、列表和列表项

列表和列表项是FreeRTOS的一个数据结构,FreeRTOS大量使用到了列表和列表项,它是FreeRTOS的基石。

1.1. 列表

列表是FreeRTOS中的一个数据结构,与链表类似,列表被用来跟踪FreeRTOS中的任务。
其结构体 List_t 在 list.h 文件中被定义:

typedef struct xLIST
{
    /* 列表内有效列表项个数 */
    configLIST_VOLATILE UBaseType_t uxNumberOfItems;
    /* 记录当前列表项索引号,用于遍历列表 */
    ListItem_t * configLIST_VOLATILE pxIndex;           
    /* 列表中最后一个列表项,表示列表结束 */
    MiniListItem_t xListEnd;                            
} List_t;

1.2. 列表项

列表项就是存放在列表中的项目,FreeRTOS提供两种类型的列表项:列表项和迷你列表项。
列表项的结构体 ListItem_t 在 list.h 文件中被定义:

静态创建任务函数包含了7个参数:

struct xLIST_ITEM
{
    /* 列表项值 */
    configLIST_VOLATILE TickType_t xItemValue;          
    /* 指向下一个列表项值 */
    struct xLIST_ITEM * configLIST_VOLATILE pxNext;     
    /* 指向上一个列表项值 */
    struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;
    /* 当前列表项的拥有者 */
    void * pvOwner;                                     
    /* 当前列表项归属的列表 */
    void * configLIST_VOLATILE pvContainer;             
};
typedef struct xLIST_ITEM ListItem_t;

1.3. 迷你列表项

有些情况下不需要列表项这么全的功能,为了避免造成内存浪费,定义了迷你列表项。
迷你列表项的结构体 MiniListItem_t 在 list.h 文件中被定义:

struct xMINI_LIST_ITEM
{
    /* 列表项值 */
    configLIST_VOLATILE TickType_t xItemValue;
    /* 指向下一个列表项值 */
    struct xLIST_ITEM * configLIST_VOLATILE pxNext;
    /* 指向上一个列表项值 */
    struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;
};
typedef struct xMINI_LIST_ITEM MiniListItem_t;

二、实验目的

学习列表项的插入和删除。

三、测试例程

主函数 main.c代码如下:

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "timer.h"
#include "key.h"
#include "FreeRTOS.h"
#include "task.h"
#include "Lcd_Driver.h"
#include "LCD_Config.h"
#include "TFT_demo.h"

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

#define LED_TASK_PRIO		2 //任务优先级
#define LED_STK_SIZE 		128  //任务堆栈大小	
TaskHandle_t LEDTask_Handler; //任务句柄
void LED_task(void *p_arg); //任务函数

#define List_TASK_PRIO		3 //任务优先级
#define List_STK_SIZE 		128  //任务堆栈大小	
TaskHandle_t ListTask_Handler; //任务句柄
void List_task(void *p_arg); //任务函数

//定义一个测试用的列表和3个列表项
List_t TestList;		//测试用列表
ListItem_t ListItem1;	//测试用列表项1
ListItem_t ListItem2;	//测试用列表项2
ListItem_t ListItem3;	//测试用列表项3

int main(void)
{ 
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
	delay_init(168);		//初始化延时函数
	uart_init(115200);     	//初始化串口
	Lcd_Init();
	LED_Init();		        //初始化LED端口
	Lcd_Clear(GRAY0);
	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();          //开启任务调度
}
 
/**
  * @brief  开始任务任务函数
  * @param  None
  * @retval None  
  */
void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           //进入临界区

    xTaskCreate((TaskFunction_t )LED_task,     
                (const char*    )"LED_task",   
                (uint16_t       )LED_STK_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )LED_TASK_PRIO,
                (TaskHandle_t*  )&LEDTask_Handler);  

	xTaskCreate((TaskFunction_t )List_task,     
                (const char*    )"List_task",   
                (uint16_t       )List_STK_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )List_TASK_PRIO,
                (TaskHandle_t*  )&ListTask_Handler);  
				
    vTaskDelete(StartTask_Handler); //删除自身开始任务
    taskEXIT_CRITICAL();            //退出临界区
}

/**
  * @brief  任务1,LED 0.5s闪烁
  * @param  None
  * @retval None  
  */
void LED_task(void *pvParameters)
{
	while(1)
	{
		LED0=~LED0;
        vTaskDelay(500);
    }
}
	

/**
  * @brief  列表项控制函数
  * @param  None
  * @retval None  
  */
void List_task(void *pvParameters)
{
	/*第1步:初始化列表和列表项*/
	vListInitialise(&TestList);
	vListInitialiseItem(&ListItem1);
	vListInitialiseItem(&ListItem2);
	vListInitialiseItem(&ListItem3);
	
	ListItem1.xItemValue=10;			//ListItem1列表项值为10
	ListItem2.xItemValue=20;			//ListItem2列表项值为20
	ListItem3.xItemValue=15;			//ListItem3列表项值为15

    /*第2步:打印列表和其他列表项的地址*/
	printf("/*******************2.列表和列表项地址*******************/\r\n");
	printf("项目                              地址				    \r\n");
	printf("TestList                          %#x					\r\n",(int)&TestList);
	printf("TestList->pxIndex                 %#x					\r\n",(int)TestList.pxIndex);
	printf("TestList->xListEnd                %#x					\r\n",(int)(&TestList.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("按下K1键继续\r\n\r\n\r\n");
	while(KEY_Scan(0)!=WKUP_PRES) delay_ms(10);		

    /*第3步:向列表TestList添加列表项ListItem1,并通过串口打印所有列表项中成员变量pxNext和pxPrevious的值,
	通过这两个值观察列表项在列表中的连接情况。*/
	vListInsert(&TestList,&ListItem1);		//插入列表项ListItem1
	printf("/******************3.添加列表项ListItem1*****************/\r\n");
	printf("项目                              地址				    \r\n");
	printf("TestList->xListEnd->pxNext        %#x					\r\n",(int)(TestList.xListEnd.pxNext));
	printf("ListItem1->pxNext                 %#x					\r\n",(int)(ListItem1.pxNext));
	printf("/*******************前后向连接分割线********************/\r\n");
	printf("TestList->xListEnd->pxPrevious    %#x					\r\n",(int)(TestList.xListEnd.pxPrevious));
	printf("ListItem1->pxPrevious             %#x					\r\n",(int)(ListItem1.pxPrevious));
	printf("/************************结束**************************/\r\n");
	printf("按下K1键继续\r\n\r\n\r\n");
	while(KEY_Scan(0)!=WKUP_PRES) delay_ms(10);					
	
	/*第4步:向列表TestList添加列表项ListItem2,并通过串口打印所有列表项中成员变量pxNext和pxPrevious的值,
	通过这两个值观察列表项在列表中的连接情况。*/
	vListInsert(&TestList,&ListItem2);	//插入列表项ListItem2
	printf("/******************4.添加列表项ListItem2*****************/\r\n");
	printf("项目                              地址				    \r\n");
	printf("TestList->xListEnd->pxNext        %#x					\r\n",(int)(TestList.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)(TestList.xListEnd.pxPrevious));
	printf("ListItem1->pxPrevious             %#x					\r\n",(int)(ListItem1.pxPrevious));
	printf("ListItem2->pxPrevious             %#x					\r\n",(int)(ListItem2.pxPrevious));
	printf("/************************结束**************************/\r\n");
	printf("按下K1键继续\r\n\r\n\r\n");
	while(KEY_Scan(0)!=WKUP_PRES) delay_ms(10);					

    /*第5步:向列表TestList添加列表项ListItem3,并通过串口打印所有列表项中成员变量pxNext和pxPrevious的值,
	通过这两个值观察列表项在列表中的连接情况。*/
	vListInsert(&TestList,&ListItem3);	//插入列表项ListItem3
	printf("/******************5.添加列表项ListItem3*****************/\r\n");
	printf("项目                              地址				    \r\n");
	printf("TestList->xListEnd->pxNext        %#x					\r\n",(int)(TestList.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)(TestList.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("按下K1键继续\r\n\r\n\r\n");
	while(KEY_Scan(0)!=WKUP_PRES) delay_ms(10);					
	
	/*第6步:删除ListItem2,并通过串口打印所有列表项中成员变量pxNext和pxPrevious的值,
	通过这两个值观察列表项在列表中的连接情况。*/
	uxListRemove(&ListItem2);						//删除ListItem2
	printf("/******************6.删除列表项ListItem2*****************/\r\n");
	printf("项目                              地址				    \r\n");
	printf("TestList->xListEnd->pxNext        %#x					\r\n",(int)(TestList.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)(TestList.xListEnd.pxPrevious));
	printf("ListItem1->pxPrevious             %#x					\r\n",(int)(ListItem1.pxPrevious));
	printf("ListItem3->pxPrevious             %#x					\r\n",(int)(ListItem3.pxPrevious));
	printf("/************************结束**************************/\r\n");
	printf("按下K1键继续\r\n\r\n\r\n");
	while(KEY_Scan(0)!=WKUP_PRES) delay_ms(10);					//等待KEY_UP键按下
	
	/*第7步:删除ListItem2,并通过串口打印所有列表项中成员变量pxNext和pxPrevious的值,
	通过这两个值观察列表项在列表中的连接情况。*/
	TestList.pxIndex=TestList.pxIndex->pxNext;			//pxIndex向后移一项,这样pxIndex就会指向ListItem1。
	vListInsertEnd(&TestList,&ListItem2);				//列表末尾添加列表项ListItem2
	printf("/***************7.在末尾添加列表项ListItem2***************/\r\n");
	printf("项目                              地址				    \r\n");
	printf("TestList->pxIndex                 %#x					\r\n",(int)TestList.pxIndex);
	printf("TestList->xListEnd->pxNext        %#x					\r\n",(int)(TestList.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)(TestList.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)
	{
		Fullscreen_showimage(gImage_XHR128);
		 vTaskDelay(1500);
    }
}

四、实验效果

实验效果如下:
首先是可以看到LED引脚电平500ms改变一次,一闪一闪的。然后按一下,再按一下,显示屏显示一个图案。


接上串口,按一下复位键,会打印任务里第2步的列表和列表项地址,按一下按键k1,会打印任务里第3步到第5步的添加列表项ListItem1/2/3信息,接着按一下按键k1,会打印删除列表项ListItem2,在末尾添加列表项ListItem2等信息。

【复习笔记】FreeRTOS(四) 列表项的插入和删除_第1张图片
【复习笔记】FreeRTOS(四) 列表项的插入和删除_第2张图片

当按下按键时,LED停止闪烁,显示屏显示“task1:stopping”下行显示“task2 Delete task1”。如果接上串口,就能看到提示内容。

好了,本节主要是学习和掌握任务创建以及 vTaskDelete() 任务删除函数的使用。
完整程序放在gitee上:程序下载地址。

你可能感兴趣的:(笔记,单片机,stm32)