文章目录
🔴🟡🟢其他文章链接,独家吐血整理
【吐血总结】FreeRTOS难点、Systick中断-滴答定时器、PendSV中断-任务切换、SVC中断-系统底层、时间片调度-时钟节拍【已完结】
(第1-8讲)STM32F4单片机,FreeRTOS基础知识总结【视频笔记、代码讲解】【正点原子】【原创】
(第9-10讲)STM32F4单片机,FreeRTOS任务创建和删除(动态方法)【视频笔记、代码讲解】【正点原子】【原创】
(第12讲)STM32F4单片机,FreeRTOS任务创建和删除(静态方法)【视频笔记、代码讲解】【正点原子】【原创】
(第13-14讲)STM32F4单片机,FreeRTOS任务挂起和恢复【视频笔记、代码讲解】【正点原子】【原创】
(第16-17讲)STM32F4单片机,FreeRTOS中断管理简介【视频笔记、代码讲解】【正点原子】【原创】
(第18-19讲)32单片机,FreeRTOS临界段代码保护、任务调度器的挂起和恢复【视频笔记、代码讲解】【原创】
(第20-22讲)STM32F4单片机,FreeRTOS列表和列表项API函数讲解【视频笔记、代码讲解、正点原子】【原创】
(第34-36讲)FreeRTOS消息队列知识汇总【B站UP、硬件家园、普中科技、正点原子】【视频笔记】【原创】
(第40-44讲)STM32F4单片机,FreeRTOS信号量【二值、计数、翻转、互斥】【代码讲解】【正点原子】【原创】
1、❤systick中断、pendsv中断、svc异常、时间片调度
看下文链接
【吐血总结】FreeRTOS难点、Systick中断-滴答定时器、PendSV中断-任务切换、SVC中断-系统底层、时间片调度-时钟节拍【已完结】
看上文链接
2、视频笔记
1、2024温故知新(纯文字)
根据前面的知识可知,列表是存放任务的,列表有三种就绪、阻塞、挂起,没有运行态列表,列表的优先级为0-31,一个列表中可以存放多个任务,而任务是有优先级的,比如2优先级的任务存放在列表中,列表中的列表项就是任务,多个列表项之间通过链表连接(双向循环链表)
rtos中任务的创建和删除是无时无刻存在的,因此链表这种数据结构很好地实现任务的管理并且实时
待补充,这块太难了。。。
1、列表、列表项、末尾列表项=mini列表项=迷你列表项都是结构体。
2、列表包含列表项,也包含mini列表项
1、先上后下,即上一个指针,下一个指针
2、升序排列,末尾列表项的数值最大,所以在最底,永远是它首先指向别人(别的列表项)
3、previous指针指向最后一个插入的,next指针指向第一个插入的,双向循环链表,两个环,手拉手
4、没有列表插入的时候,列表的数值=0,index指针指向末尾列表项,末尾列表项的两个指针指向自己
1、列表数值变为了2
这个图片很能解释了,最初10->40->0xFFFFFFFF,现在30要插入进来,首先呢进入for循环,30小于0xFFFFFFFF成立,P指针指向了下一个next也就是列表项1,于是30不小于10就跳出for循环,于是找到了位置,这就是个插入算法吧
3、实验现象
4、代码讲解
list.h
struct xLIST;
struct xLIST_ITEM//列表项结构体
{
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
configLIST_VOLATILE TickType_t xItemValue; /*< The value being listed. In most cases this is used to sort the list in ascending order. */
//列表项数值,根据这个值升序进行排序
struct xLIST_ITEM * configLIST_VOLATILE pxNext; /*< Pointer to the next ListItem_t in the list. */
//指向下一个列表项
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; /*< Pointer to the previous ListItem_t in the list. */
//指向上一个列表项
void * pvOwner; /*< Pointer to the object (normally a TCB) that contains the list item. There is therefore a two way link between the object containing the list item and the list item itself. */
//任意类型指针,用于指向某个列表结构体
struct xLIST * configLIST_VOLATILE pxContainer; /*< Pointer to the list in which this list item is placed (if any). */
//指向列表的结构体指针变量
listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
};
typedef struct xLIST_ITEM ListItem_t; /* For some reason lint wants this as two separate definitions. */
struct xMINI_LIST_ITEM//mini列表项结构体
{
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
configLIST_VOLATILE TickType_t xItemValue;
//列表项数值
struct xLIST_ITEM * configLIST_VOLATILE pxNext;
//指向下一个列表项
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;
//指向上一个列表项
};
typedef struct xMINI_LIST_ITEM MiniListItem_t;
/*
* Definition of the type of queue used by the scheduler.
*/
typedef struct xLIST//列表结构体
{
listFIRST_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
volatile UBaseType_t uxNumberOfItems;
//ulong变量=列表中的列表项数量(不包括mini列表项),用于列表项插入删除
ListItem_t * configLIST_VOLATILE pxIndex; /*< Used to walk through the list. Points to the last item returned by a call to listGET_OWNER_OF_NEXT_ENTRY (). */
//指向某个列表项=pxIndex=结构体指针变量
MiniListItem_t xListEnd; /*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */
//mini列表项=末尾列表项=结构体变量
listSECOND_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
} List_t;
list.c
void vListInitialise( List_t * const pxList )
{
/* The list structure contains a list item which is used to mark the
* end of the list. To initialise the list the list end is inserted
* as the only list entry. */
pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. */
//指向末尾列表,xListEnd是mini列表项结构体变量,pxIndex是列表项结构体变量
/* The list end value is the highest possible value in the list to
* ensure it remains at the end of the list. */
pxList->xListEnd.xItemValue = portMAX_DELAY;
//末尾列表数值=最大=( TickType_t ) 0xffffffffUL
/* The list end next and previous pointers point to itself so we know
* when the list is empty. */
pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. */
//pxList->xListEnd.pxNext是指向结构体中的成员结构体中的结构体指针变量pxNext
pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. */
//也是结构体中的结构体成员中的结构体指针变量pxPrevious
pxList->uxNumberOfItems = ( UBaseType_t ) 0U;
//列表项数量默认为0
/* Write known values into the list if
* configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );
listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList );
}
/*-----------------------------------------------------------*/
末尾列表项=mini列表项地址给了index
初值=最大
末尾列表项地址,给了自己的两个手
列表项数量=0
void vListInitialiseItem( ListItem_t * const pxItem )
{
/* Make sure the list item is not recorded as being on a list. */
pxItem->pxContainer = NULL;
//列表项中的结构体指针变量为NULL
/* Write known values into the list item if
* configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
}
/*-----------------------------------------------------------*/
列表项(不是mini)的容器结构体指针给了null
void vListInsert( List_t * const pxList,
ListItem_t * const pxNewListItem )
{
ListItem_t * pxIterator;
const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;
//指向的列表项结构体中的列表项数量 赋给 插入值
//获取待插入的列表项值
/* Only effective when configASSERT() is also defined, these tests may catch
* the list data structures being overwritten in memory. They will not catch
* data errors caused by incorrect configuration or use of FreeRTOS. */
listTEST_LIST_INTEGRITY( pxList );
listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );
/* Insert the new list item into the list, sorted in xItemValue order.
*
* If the list already contains a list item with the same item value then the
* new list item should be placed after it. This ensures that TCBs which are
* stored in ready lists (all of which have the same xItemValue value) get a
* share of the CPU. However, if the xItemValue is the same as the back marker
* the iteration loop below will not end. Therefore the value is checked
* first, and the algorithm slightly modified if necessary. */
if( xValueOfInsertion == portMAX_DELAY )//如果插入的列表项的值等于最大值(极极小概率)
{
pxIterator = pxList->xListEnd.pxPrevious;//将末尾列表项的pxprevious的内容=列表项自身的地址给了刚定义的结构体指针
}
//列表项和mini列表项虽然不同(结构体变量名不同,成员也不同),但是它们中的两只手都是结构体指针,是【相同】struct类型
//即相当于插入的列表项指向了末尾列表项,实现了末尾列表项永远处于最底端
else
{
/* *** NOTE ***********************************************************
* If you find your application is crashing here then likely causes are
* listed below. In addition see https://www.FreeRTOS.org/FAQHelp.html for
* more tips, and ensure configASSERT() is defined!
* https://www.FreeRTOS.org/a00110.html#configASSERT
*
* 1) Stack overflow -
* see https://www.FreeRTOS.org/Stacks-and-stack-overflow-checking.html
* 2) Incorrect interrupt priority assignment, especially on Cortex-M
* parts where numerically high priority values denote low actual
* interrupt priorities, which can seem counter intuitive. See
* https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html and the definition
* of configMAX_SYSCALL_INTERRUPT_PRIORITY on
* https://www.FreeRTOS.org/a00110.html
* 3) Calling an API function from within a critical section or when
* the scheduler is suspended, or calling an API function that does
* not end in "FromISR" from an interrupt.
* 4) Using a queue or semaphore before it has been initialised or
* before the scheduler has been started (are interrupts firing
* before vTaskStartScheduler() has been called?).
* 5) If the FreeRTOS port supports interrupt nesting then ensure that
* the priority of the tick interrupt is at or below
* configMAX_SYSCALL_INTERRUPT_PRIORITY.
**********************************************************************/
for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM. This is checked and valid. *//*lint !e440 The iterator moves to a different value, not xValueOfInsertion. */
{
/* There is nothing to do here, just iterating to the wanted
* insertion position. */
}
//列表的末尾列表项地址给刚定义的结构体指针pxi ; 数值<最大值 ; 即刚刚赋给pxi指针的末尾列表项的next再次给了pxi
//即此时刚刚定义的结构体指针pxi指向的结构体中的next指向了末尾列表项
//没懂没懂,待补充
}
pxNewListItem->pxNext = pxIterator->pxNext;
pxNewListItem->pxNext->pxPrevious = pxNewListItem;
pxNewListItem->pxPrevious = pxIterator;
pxIterator->pxNext = pxNewListItem;
/* Remember which list the item is in. This allows fast removal of the
* item later. */
pxNewListItem->pxContainer = pxList;
( pxList->uxNumberOfItems )++;
}
讲解在代码中注释了
if( xValueOfInsertion == portMAX_DELAY )//如果插入的列表项的值等于最大值(极极小概率)
{
pxIterator = pxList->xListEnd.pxPrevious;//将末尾列表项自己的地址给了刚定义的结构体指针
}
//列表项和mini列表项虽然不同(结构体变量名不同,成员也不同),但是它们中的两只手都是结构体指针,是【相同】struct类型
详情请见上面的视频笔记