在差不多熟练运用完STM32F103单片机的基本功能之后,比如GPIO口配置、IIC、SPI、PWM波等,想继续深入系统进行学习,当然学习阶段最终的目标是ARM+Linux,为了学习这些轻量级的操作系统,将开发板从F103换成了F429,因为后续想结合GUI一起学习。
去年了解过一些FreeRTOS的API,并走过一些基本的例程,但不入虎穴,焉得虎子,内核不了解有什么意思,所以这段时间的学习从内核入手,可能在学习的过程当中会复习一些《操作系统与编译原理》中的知识,希望自己尽快完成这方面的学习。
在新建工程之后开始了概念学习:
裸机系统:分为轮询系统和前后台系统。轮询系统:只适合哪些按顺序执行的功能代码,实时性差;前后台系统:在轮询系统中加入中断,中断被称之为前台,main函数的无限循环被称之为后台;
多任务系统:就是任务也拥有了优先级,相对前后台系统,能够提升实时性,用言语描述,太麻烦,直接用代码来表现好了:
int flag1 = 0;
int flag2 = 0;
int flag3 = 0;
void DoSomething1(void)
void DoSomething2(void)
void DoSomething3(void)
int main(void)
{
HardWareInit(); //硬件相关初始化;
RTOSInit(); //OS初始化;
RTOSStart(); //OS开始启动,多任务调度;
}
void ISR1(void)
{
flag1 = 1; //置位标志位;
}
void ISR2(void)
{
flag2 = 2; //置位标志位;
}
void ISR3(void)
{
flag3 = 1; //置位标志位;
}
void DoSomething1(void)
{
for (;;) {
if (flag1) {} // 任务实体 ;
}
}
void DoSomething2(void)
{
for (;;) {
if (flag2) {} // 任务实体 ;
}
}
void DoSomething3(void)
{
for (;;) {
if (flag3) {} // 任务实体 ;
}
}
用了嵌入式操作系统的好处是:不用精心设计程序执行流,坏处是需要额外的FLASH和RAM;
当然本着学习的心态,暂时搁置优缺点,就是它再不好,现在也得学;
List & List item:
FreeRTOS中与链表相关的操作均在list.h和list.c这两个文件中实现,列表项结构体展开为:
struct xLIST_ITEM
{
portTickType xItemValue; //列表项的值 通常用来进行列表项排序
volatile struct xLIST_ITEM * pxNext; //指向下一个列表项
volatile struct xLIST_ITEM * pxPrevious; //指向前一个列表项
void * pvOwner; //指向拥有该列表项的内核对象,通常是即任务控制块
void * pvContainer; //指向该节点所在的列表
}
其中的含义如图所示:
这里其实我一直有个疑问:pvOwner和pvContainer有什么区别:
这里的pvOwner指该链表属于哪个任务,而pvContainer指向该列表项属于哪个列表;
列表结构体展开为:
typedef struct xLIST
{
volatile unsigned UBaseType_t uxNumberOfItems; // 列表中链表项的数目
ListItem_t * pxIndex; // 列表项索引指针,用于步寻列表项
MiniListItem_t xListEnd; // 列表中最后一个列表项
}
列表的作用是用来跟踪任务的。
初始化:vListInitialise () 和 vListInitialiseItem()
void vListInitialise( List_t * const pxList )
{
pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd ); //pxIndex 指向xListEnd
pxList->xListEnd.xItemValue = portMAX_DELAY; //xListEnd 的列表项值初始化为portMAX_DELAY
pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd ); //初始化xListEnd 的pxPrevious 变量,指向xListEnd 自身;
pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd ); //同上;
pxList->uxNumberOfItems = ( UBaseType_t ) 0U; //初始化列表项个数为0
}
void vListInitialiseItem( ListItem_t * const pxItem )
{
pxItem->pvContainer = NULL; //初始化pvContainer 为NULL
}
列表项成员的初始化会在任务创建函数中进行初始化。
列表项的插入:
对列表项值进行升序插入:vListInsert ()
void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )
{
ListItem_t *pxIterator;
const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;
listTEST_LIST_INTEGRITY( pxList );
listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );
if( xValueOfInsertion == portMAX_DELAY ) //如果插入链表项值为允许最大值,则插入列表结尾
{
pxIterator = pxList->xListEnd.pxPrevious;
}
else
{
for( pxIterator = ( xListItem * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext )
{
//找到插入位置
}
}
// 插入链表项
pxNewListItem->pxNext = pxIterator->pxNext;
pxNewListItem->pxNext->pxPrevious = pxNewListItem;
pxNewListItem->pxPrevious = pxIterator;
pxIterator->pxNext = pxNewListItem;
pxNewListItem->pvContainer = ( void * ) pxList;
( pxList->uxNumberOfItems )++; //更新链表项值
列表项末尾插入函数:vListInsertEnd ()
void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )
{
ListItem_t * const pxIndex = pxList->pxIndex;
pxNewListItem->pxNext = pxIndex;
pxNewListItem->pxPrevious = pxIndex->pxPrevious;
mtCOVERAGE_TEST_DELAY();
pxIndex->pxPrevious->pxNext = pxNewListItem;
pxIndex->pxPrevious = pxNewListItem;
pxNewListItem->pvContainer = ( void * ) pxList;
( pxList->uxNumberOfItems )++;
}
列表项删除:uxListRemove ()
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )
{
List_t * const pxList = ( List_t * ) pxItemToRemove->pvContainer; //读取该列表项对应列表
pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext; //和上面一行一起,将要删除的、与下面一行完成列表项的删除,其实就是将要前后两个“连接”在一起
mtCOVERAGE_TEST_DELAY();
if( pxList->pxIndex == pxItemToRemove )
{
pxList->pxIndex = pxItemToRemove->pxPrevious;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
pxItemToRemove->pvContainer = NULL; // 被删除列表项的成员变量 pvContainer清
( pxList->uxNumberOfItems )--; //列表项个数减一
return pxList->uxNumberOfItems; //返回新列表当前列表项数目
}
列表项遍历:listGET_OWNER_OF_NEXT_ENTRY ()
#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )
{
List_t * const pxConstList = ( pxList );
( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;
if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) )
{
( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;
}
( pxTCB ) = ( pxConstList )->pxIndex->pvOwner;
}
本质是定义在list.h中的宏,每调用一次这个函数,pxIndex变量就会指向下一个列表项,并且返回这个列表项的pxOwner变量。