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

news2024/11/30 20:45:46

本文是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;

二、实验目的

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

三、测试例程

程序上主要用到xTaskCreate()函数,使用动态的方法创建任务,以及使用vTaskDelete()删除任务。程序上主要是创建两个任务,task1负责闪烁LED,task2负责按键控制,当按键按下时删除任务task1,任务的状态显示到TFT显示屏和串口上。
主函数 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等信息。

在这里插入图片描述
在这里插入图片描述

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/625697.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Dubbo 注册,调用,通信,容错

Dubbo简化模型 3种开发方式 开发方式 举例 特点 XML配置 等 业务代码零侵入 扩展修改方便 注解方式 EnableDubbo DubboService DubboReference 扩展修改方便 修改需要重新编译代码 API编程 DubboBootstrap ServiceConfig ReferenceConfig应用 业务侵入性大 修改复杂…

【前端学习】React学习资料

React 是一种开源的 JavaScript 库,用于构建用户界面。它由 Facebook 开发并维护,已经成为了当今最流行的前端库之一。与其他框架不同,React 主要专注于视图层(View),旨在通过声明式、组件化的方式来构建复…

Pagination分页(antd-design组件库)展示所有配置选项和onChange的作用

1.Pagination分页 采用分页的形式分隔长列表,每次只加载一个页面。 2.何时使用 当加载/渲染所有数据将花费很多时间时; 可切换页码浏览数据。 组件代码来自: 分页 Pagination - Ant Design 3.本地验证前的准备 参考文章【react项目antd组件-d…

redis到底是怎么样进行渐进式hash的

Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。那么redis的底层是如何来存储数据的呢? 一、redis如何在存储大量的key时候,查询速度还能接近O(1)呢&#xf…

分布式事务方案学习

第100篇文章啦!分布式事务在面试中分布式事务也是十分重要的点,所以学习完分布式锁后我们就来学习分布式事务吧。 事务表示的是我们在业务逻辑中对数据库进行操作的一组单元,需要同时成功或同时失败,不了解的小伙伴们可以看一下下…

Linux编译器-gcc/g++(动静态链接)

目录 一、Linux编译器-gcc/g的使用1.1 背景知识1.2 预处理,编译,汇编,链接1.3 动静态链接 二、补充sudo设置 一、Linux编译器-gcc/g的使用 1.1 背景知识 我们为什么能在windows或者linux下进行C/C或者其它形式的开发呢?前提条件…

我在VScode学Java(Java一维数组、二维数组、JVM中的堆和栈)重制版

​ 我的个人博客主页:如果’真能转义1️⃣说1️⃣的博客主页 关于Java基本语法学习---->可以参考我的这篇博客:《我在VScode学Java》 Java一维数组、二维数组 零._.在Java中_什么是数组Java 数组是一种数据结构,存储一组相同类型的数据。引…

Docker网络模型(七)使用 IPvlan 网络

使用 IPvlan 网络 IPvlan 驱动为用户提供了全面控制 IPv4 和 IPv6 寻址的能力。 IPvlan 让操作者能完全操控二层(数据链路层)网络的 vlan 标签,甚至也提供了三层(网络传输层)路由控制给感兴趣的用户。对于抽象出物理限…

【SpringSecurity】CSRF、环境配置、授权、认证功能、记住我功能实现

SpringSecurity 文章目录 SpringSecurityCSRF跨站请求伪造攻击开发环境搭建认证直接认证使用数据库认证自定义登录界面 授权基于角色的授权基于权限的授权使用注解判断权限 记住我SecurityContext SpringSecurity是一个基于Spring开发的非常强大的权限验证框架,其核…

Java快速安装以及入门指南

安装 Java 环境教程 Java 是一种广泛应用于软件开发、Web 应用程序和移动应用程序等领域的编程语言。如果您要使用 Java 进行开发或运行需要 Java 程序,您需要先在计算机上安装 Java 环境。 本教程将向您介绍如何在 Windows 操作系统上安装和验证 Java 环境。还将…

第2章 可行性研究

文章目录 第2章 可行性研究2.1 可行性研究的任务2.2 可行性研究过程2.3 系统流程图2.3.1符号2.3.3 分层 2.4 数据流图2.4.1 符号1. 数据源点或终点2. 数据加工(变换数据的处理)3. 数据存储4.数据流数据流与数据加工之间的关系 2.4.2绘制数据流图的例子顶…

chatgpt赋能python:Python3.6.5到Python3.7.5:升级指南

Python 3.6.5到Python 3.7.5:升级指南 Python是一种广泛使用的编程语言,拥有强大的库和框架,能够开发各种类型的应用程序。在Python的发行版中,版本更新是常见的过程,以提供更好的性能和新的功能。 本文将介绍如何将…

手记系列之六 ----- 分享个人使用kafka经验

前言 本篇文章主要介绍的关于本人从刚工作到现在使用kafka的经验,内容非常多,包含了kafka的常用命令,在生产环境中遇到的一些场景处理,kafka的一些web工具推荐等等。由于kafka这块的记录以及经验是从我刚开始使用kafka&#xff0…

chatgpt赋能python:Python怎么一行一行读文本?

Python怎么一行一行读文本? 在Python中,要一行一行地读取文本文件,我们可以使用Python内置函数readline()。它每次读取一行文本,并且会自动把文本的换行符\n去掉。下面我们来详细了解如何使用readline()函数读取文本文件。 读取…

4.卡尔曼滤波原理及实战

欢迎访问个人网络日志🌹🌹知行空间🌹🌹 文章目录 0.关于卡尔曼1.卡尔曼滤波算法2.卡尔曼滤波算法的应用一个简单例子一个复杂的例子参考 0.关于卡尔曼 卡尔曼,匈牙利数学家,1930年出生于匈牙利首都布达佩斯…

chatgpt赋能python:Python数据分析:Vlookup函数在Python中的实现

Python数据分析:Vlookup函数在Python中的实现 简介 Vlookup是一种常见的数据分析函数,用于在两个数据表/数据集中查找并关联相应的数据。这个函数是在Excel中非常常见的,但是当我们进行大型数据分析时,我们可以使用Python来实现…

2023.6.8小记——嵌入式系统初识、什么是ARM架构?

今天还挺充实的,早上在图书馆本来想学一下notion,结果看李沐老师的动手深度学习看到十点半,在电脑上配置了李沐老师的d2l和jupyter,等后续有时间的时候再继续学。 下午看了一下notion的使用方法,这玩意初学者用起来是…

chatgpt赋能python:Python如何一行输出五个星号

Python如何一行输出五个星号 Python是一种流行的编程语言,它被广泛用于各种领域,包括Web开发,数据科学和机器学习。在这篇文章中,我们将探讨如何使用Python在一行中输出五个星号。 输出五个星号的方法 Python提供了几种方法来在…

牛客网语法刷题(C语言) — 输出格式化

🤩本文作者:大家好,我是paperjie,感谢你阅读本文,欢迎一建三连哦。 🥰内容专栏:这里是《C语言—语法篇》专栏,笔者用重金(时间和精力)打造,基础知识一网打尽,…

从字符串中读写的方法:c语言中的sscanf、sprintf函数,c++中的I/O流strstream、stringstream

一、sscanf、sprintf函数 众所周知,c语言中我们常使用的标准输入输出流函数为scanf()、printf(),默认从键盘上输入数据、向屏幕输出数据。此外,c语言中还提供了另一组库函数sscanf()、sprintf()函数,它们的功能与前者相同&#x…