6、FreeRTOS临界段代码保护
6.1 临界段代码保护简介
什么是临界段:临界段代码也叫临界区,指那些必须完整运行,不能够被打断的代码段。
应用于何种场合?
1、外设:严格按照时序初始化的外设,IIC、SPI等等
2、系统:系统自身需求
3、用户:用户需求
FreeRTOS在进入临界段代码的时候需要关闭中断,当处理完临界段代码以后再开启中断。(其本质就是开关中断)
临界段代码保护函数:
任务级临界区调用格式:
中断级临界区调用格式:
7、任务调度器的挂起和恢复
7.1 任务调度器的挂起
挂起与恢复函数:
与临界区不一样的是,挂起任务调度器未关闭中断。
仅防止了任务之间的资源争夺,中断照样直接响应。
适用于临界区位于任务与任务之间,既不用延时中断,又能够做到临界区的安全。
在系统内部,实际上是通过一个变量实现调度器的挂起。
恢复调度器时,将上面说的变量进行--,
8、列表和列表项(重点)
8.1 列表和列表项的简介
列表是FreeRTOS中的一个数据结构,概念上与链表相似,列表被用来跟踪FreeRTOS中的任务
列表项就是存放在列表中的项目。
多个列表项组成了一个环形链表。同时列表项又组成了双向链表。
FreeRTOS中的列表就是一个双向环形链表
列表的特点:列表项的地址是非连续的,是人为连接到一起的,这一点与数组有很大不同,列表项的数目是由后期添加的个数所决定的,随时可以改变。
一个列表项可以对应一个任务,这样,在任务总数不确定的情况下,通过增删列表项,就能实现任务的增减。
数组的特点:数组成员地址是连续的,在最初确定了成员数量后后期无法改变。
首先来看一下在list.h中的列表相关结构体:
1、在该结构体中, 包含了两个宏,这两个宏是确定的已知常量, FreeRTOS通过检查这两个常量的值, 来判断列表的数据在程序运行过程中,是否遭到破坏 ,该功能一般用于调试, 默认是不开启的
2、成员uxNumberOfItems,用于记录列表中列表项的个数(不包含 xListEnd)
3、成员 pxIndex 用于指向列表中的某个列表项,一般用于遍历列表中的所有列表项
4、成员变量 xListEnd 是一个迷你列表项,排在最末尾
列表项是列表中用于存放数据的地方,相关结构体定义如下:
1、成员变量 xItemValue 为列表项的值,这个值多用于按升序对列表中的列表项进行排序
2、成员变量 pxNext 和 pxPrevious 分别用于指向列表中列表项的下一个列表项和上一个列表项
3、成员变量 pxOwner 用于指向包含列表项的对象(通常是任务控制块)
4、成员变量 pxContainer 用于指向列表项所在列表
迷你列表项:
同样是列表项,但仅用于标记列表的末尾和挂载其他插入列表中的列表项。
迷你列表项只用于标记列表的末尾和挂载其他插入列表中的列表项,所以不需要成员变量pxOwner以及pxContainer,以节省内存开销。
8.2 列表相关API函数介绍
初始化列表vListInitialize():
函数vListInitializeItem():
函数vListInsert():
用于将待插入列表的列表项按照列表项值升序进行排序,有序地插入到列表中
函数vListInsertEnd():
实际上可以理解为,就是将待插入的列表项插入到pxList->pxIndex前,这是一种无序的插入方式。
函数uxListRemove():
8.3 编程实战
列表项的互指:可以看到,当将列表项1插入列表后,列表项1的指向上一个指向的是末尾列表项,下一个也同样,末尾列表项同理。
在上面的基础上,在插入值为60的列表项2,此时可以看到,列表项1的指向下一个指向的是列表项2,列表项2的指向下一个是末尾列表项。
继续插入列表项3,但列表项3的值为50,此时可以看到,列表项1的指向下一个指向的是列表项3,列表项2的指向下一个是末尾列表项,列表项3的指向下一个是列表项2,这就实现了列表项的升序排列。
使用列表项移除函数,移除列表项2, 可以看到此时列表项3的指向下一个就指向了末尾列表项。
最后,通过使用末尾项插入函数,将列表项2重新插入列表中,可以看到,此时的现象与第五部一模一样。
freertos_demo.c:
/**
****************************************************************************************************
* @file freertos.c
* @author 正点原子团队(ALIENTEK)
* @version V1.4
* @date 2022-01-04
* @brief FreeRTOS 移植实验
* @license Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
****************************************************************************************************
* @attention
*
* 实验平台:正点原子 精英F103开发板
* 在线视频:www.yuanzige.com
* 技术论坛:www.openedv.com
* 公司网址:www.alientek.com
* 购买地址:openedv.taobao.com
*
****************************************************************************************************
*/
#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./SYSTEM/delay/delay.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
/******************************************************************************************************/
/*FreeRTOS配置*/
/* START_TASK 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define START_TASK_STACK_SIZE 128
#define START_TASK_PRIORITY 1
TaskHandle_t Start_Task_Handler;
void start_task( void * pvParameters );
/* Task1 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK1_STACK_SIZE 128
#define TASK1_PRIORITY 2
TaskHandle_t Task1_Handler;
void task1( void * pvParameters );
/* Task2 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK2_STACK_SIZE 128
#define TASK2_PRIORITY 3
TaskHandle_t Task2_Handler;
void task2( void * pvParameters );
/******************************************************************************************************/
List_t TestList; /*定义测试列表*/
ListItem_t ListItem1; /*定义测试列表项1*/
ListItem_t ListItem2; /*定义测试列表项2*/
ListItem_t ListItem3; /*定义测试列表项3*/
/*
* @brief FreeRTOS例程入口函数
* @param 无
* @retval 无
*/
void freertos_demo(void)
{
xTaskCreate(( TaskFunction_t ) start_task,
(char * ) "start_task",
(configSTACK_DEPTH_TYPE) START_TASK_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) START_TASK_PRIORITY,
(TaskHandle_t * ) &Start_Task_Handler );
vTaskStartScheduler();//开启任务调度器
}
void start_task( void * pvParameters )
{
taskENTER_CRITICAL(); /* 进入临界区 */
/*创建任务1*/
xTaskCreate(( TaskFunction_t ) task1,
(char * ) "task1",
(configSTACK_DEPTH_TYPE) TASK1_STACK_SIZE,
(void * ) NULL,
( UBaseType_t ) TASK1_PRIORITY,
(TaskHandle_t * ) &Task1_Handler );
/*创建任务2*/
xTaskCreate(( TaskFunction_t ) task2,
(char * ) "task2",
(configSTACK_DEPTH_TYPE) TASK2_STACK_SIZE,
(void * ) NULL,
( UBaseType_t ) TASK2_PRIORITY,
(TaskHandle_t * ) &Task2_Handler );
vTaskDelete(NULL);//删除开始任务
taskEXIT_CRITICAL(); /* 退出临界区 */
}
/*任务一,实现LED每500ms翻转一次*/
void task1( void * pvParameters )
{
while(1)
{
printf("LED0翻转\r\n");
LED0_TOGGLE();
vTaskDelay(500);
}
}
/*任务二,实现列表项的插入和删除*/
void task2( void * pvParameters )
{
vListInitialise(&TestList); /*初始化列表*/
vListInitialiseItem(&ListItem1); /*初始化列表项1*/
vListInitialiseItem(&ListItem2); /*初始化列表项2*/
vListInitialiseItem(&ListItem3); /*初始化列表项3*/
ListItem1.xItemValue = 40;
ListItem2.xItemValue = 60;
ListItem3.xItemValue = 50;
/* 第二步:打印列表和其他列表项的地址 */
printf("/**************第二步:打印列表和列表项的地址**************/\r\n");
printf("项目\t\t\t地址\r\n");
printf("TestList\t\t0x%p\t\r\n", &TestList);
printf("TestList->pxIndex\t0x%p\t\r\n", TestList.pxIndex);
printf("TestList->xListEnd\t0x%p\t\r\n", (&TestList.xListEnd));
printf("ListItem1\t\t0x%p\t\r\n", &ListItem1);
printf("ListItem2\t\t0x%p\t\r\n", &ListItem2);
printf("ListItem3\t\t0x%p\t\r\n", &ListItem3);
printf("/**************************结束***************************/\r\n");
/* 第三步:列表项1插入列表 */
printf("/*****************第三步:列表项1插入列表******************/\r\n");
vListInsert((List_t* )&TestList, /* 列表 */
(ListItem_t*)&ListItem1); /* 列表项 */
printf("项目\t\t\t\t地址\r\n");
printf("TestList->xListEnd->pxNext\t0x%p\r\n", (TestList.xListEnd.pxNext));
printf("ListItem1->pxNext\t\t0x%p\r\n", (ListItem1.pxNext));
printf("TestList->xListEnd->pxPrevious\t0x%p\r\n", (TestList.xListEnd.pxPrevious));
printf("ListItem1->pxPrevious\t\t0x%p\r\n", (ListItem1.pxPrevious));
printf("/**************************结束***************************/\r\n");
/* 第四步:列表项2插入列表 */
printf("/*****************第四步:列表项2插入列表******************/\r\n");
vListInsert((List_t* )&TestList, /* 列表 */
(ListItem_t*)&ListItem2); /* 列表项 */
printf("项目\t\t\t\t地址\r\n");
printf("TestList->xListEnd->pxNext\t0x%p\r\n", (TestList.xListEnd.pxNext));
printf("ListItem1->pxNext\t\t0x%p\r\n", (ListItem1.pxNext));
printf("ListItem2->pxNext\t\t0x%p\r\n", (ListItem2.pxNext));
printf("TestList->xListEnd->pxPrevious\t0x%p\r\n", (TestList.xListEnd.pxPrevious));
printf("ListItem1->pxPrevious\t\t0x%p\r\n", (ListItem1.pxPrevious));
printf("ListItem2->pxPrevious\t\t0x%p\r\n", (ListItem2.pxPrevious));
printf("/**************************结束***************************/\r\n");
/* 第五步:列表项3插入列表 */
printf("/*****************第五步:列表项3插入列表******************/\r\n");
vListInsert((List_t* )&TestList, /* 列表 */
(ListItem_t*)&ListItem3); /* 列表项 */
printf("项目\t\t\t\t地址\r\n");
printf("TestList->xListEnd->pxNext\t0x%p\r\n", (TestList.xListEnd.pxNext));
printf("ListItem1->pxNext\t\t0x%p\r\n", (ListItem1.pxNext));
printf("ListItem2->pxNext\t\t0x%p\r\n", (ListItem2.pxNext));
printf("ListItem3->pxNext\t\t0x%p\r\n", (ListItem3.pxNext));
printf("TestList->xListEnd->pxPrevious\t0x%p\r\n", (TestList.xListEnd.pxPrevious));
printf("ListItem1->pxPrevious\t\t0x%p\r\n", (ListItem1.pxPrevious));
printf("ListItem2->pxPrevious\t\t0x%p\r\n", (ListItem2.pxPrevious));
printf("ListItem3->pxPrevious\t\t0x%p\r\n", (ListItem3.pxPrevious));
printf("/**************************结束***************************/\r\n");
/* 第六步:移除列表项2 */
printf("/*******************第六步:移除列表项2********************/\r\n");
uxListRemove((ListItem_t* )&ListItem2); /* 移除列表项 */
printf("项目\t\t\t\t地址\r\n");
printf("TestList->xListEnd->pxNext\t0x%p\r\n", (TestList.xListEnd.pxNext));
printf("ListItem1->pxNext\t\t0x%p\r\n", (ListItem1.pxNext));
printf("ListItem3->pxNext\t\t0x%p\r\n", (ListItem3.pxNext));
printf("TestList->xListEnd->pxPrevious\t0x%p\r\n", (TestList.xListEnd.pxPrevious));
printf("ListItem1->pxPrevious\t\t0x%p\r\n", (ListItem1.pxPrevious));
printf("ListItem3->pxPrevious\t\t0x%p\r\n", (ListItem3.pxPrevious));
printf("/**************************结束***************************/\r\n");
/* 第七步:列表末尾添加列表项2 */
printf("/****************第七步:列表末尾添加列表项2****************/\r\n");
TestList.pxIndex = &ListItem1;
vListInsertEnd((List_t* )&TestList, /* 列表 */
(ListItem_t* )&ListItem2); /* 列表项 */
printf("项目\t\t\t\t地址\r\n");
printf("TestList->pxIndex\t\t0x%p\r\n", TestList.pxIndex);
printf("TestList->xListEnd->pxNext\t0x%p\r\n", (TestList.xListEnd.pxNext));
printf("ListItem1->pxNext\t\t0x%p\r\n", (ListItem1.pxNext));
printf("ListItem2->pxNext\t\t0x%p\r\n", (ListItem2.pxNext));
printf("ListItem3->pxNext\t\t0x%p\r\n", (ListItem3.pxNext));
printf("TestList->xListEnd->pxPrevious\t0x%p\r\n", (TestList.xListEnd.pxPrevious));
printf("ListItem1->pxPrevious\t\t0x%p\r\n", (ListItem1.pxPrevious));
printf("ListItem2->pxPrevious\t\t0x%p\r\n", (ListItem2.pxPrevious));
printf("ListItem3->pxPrevious\t\t0x%p\r\n", (ListItem3.pxPrevious));
printf("/************************实验结束***************************/\r\n");
while(1)
{
printf("11111\r\n");
vTaskDelay(1000);
}
}