FreeRTOS学习笔记(4)

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);
    }
}

 
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值