一、编程风格
1. 数据类型
/* portmacro.h */
/* Type definitions. */
#define portCHAR char
#define portFLOAT float
#define portDOUBLE double
#define portLONG long
#define portSHORT short
#define portSTACK_TYPE uint32_t
#define portBASE_TYPE long
typedef portSTACK_TYPE StackType_t;
typedef long BaseType_t;
typedef unsigned long UBaseType_t;
#if( configUSE_16_BIT_TICKS == 1 )
typedef uint16_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffff
#else
typedef uint32_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
2. 变量名
匈牙利命名法:变量名=属性+类型+对象描述。如pcxx表示char型指针变量。
3. 函数名
函数名=返回值类型+函数所在文件名+描述。如:
xQueueReceive()表示,函数返回值为portBASE_TYPE类型,再queue.c这个文件中定义。
4. 宏名
宏名=定义文件+描述。如:
二、FreeRTOS中的链表实现
1.链表节点
- 数据结构
/* list.h */
struct xLIST_ITEM
{
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;
- 初始化
/*
* Definition of the only type of object that a list can contain.
*/
void vListInitialiseItem( ListItem_t * const pxItem )
{
/* Make sure the list item is not recorded as being on a list. */
pxItem->pvContainer = NULL;
}
2.链表根节点
- 数据结构
/*
* Definition of the type of queue used by the scheduler.
*/
typedef struct xLIST
{
UBaseType_t uxNumberOfItems; /* 链表节点计数器 */
ListItem_t * pxIndex; /* 链表节点索引指针 */
MiniListItem_t xListEnd; /* 链表的最后一个节点即第一个 */
} List_t;
/* 精简节点 */
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;
- 初始化
void vListInitialise( List_t * const pxList )
{
/* 将链表的索引指针指向最后一个节点 */
pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd );
/* 将链表最后一个节点的辅助排序的值设置为最大,确保该节点就是链表的最后节点 */
pxList->xListEnd.xItemValue = portMAX_DELAY;
/* 将最后一个节点的pxNext和pxPrevious指针均指向节点自身,表示链表为空 */
pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd );
pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );
/* 初始化链表节点计数器的值为0,表示链表空 */
pxList->uxNumberOfItems = ( UBaseType_t ) 0U;
}
3.节点与链表交互操作
- 将节点插入链表尾部
void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )
{
ListItem_t * const pxIndex = pxList->pxIndex;
pxNewListItem->pxNext = pxIndex;
pxNewListItem->pxPrevious = pxIndex->pxPrevious;
pxIndex->pxPrevious->pxNext = pxNewListItem;
pxIndex->pxPrevious = pxNewListItem;
/* 记住该节点所在的链表 */
pxNewListItem->pvContainer = ( void * ) pxList;
/* 链表节点计数器++ */
( pxList->uxNumberOfItems )++;
}
- 将节点按照升序排列插入链表
void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )
{
ListItem_t *pxIterator;
/* 获取节点的排序辅助值 */
const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;
/* 寻找节点要求插入的位置 */
if( xValueOfInsertion == portMAX_DELAY )
{
pxIterator = pxList->xListEnd.pxPrevious;
}
else
{
for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd );
pxIterator->pxNext->xItemValue <= xValueOfInsertion;
pxIterator = pxIterator->pxNext )
{
/* There is nothing to do here, just iterating to the wanted
insertion position. */
}
}
/* 根据升序排列,将节点插入 */
pxNewListItem->pxNext = pxIterator->pxNext;
pxNewListItem->pxNext->pxPrevious = pxNewListItem;
pxNewListItem->pxPrevious = pxIterator;
pxIterator->pxNext = pxNewListItem;
/* 记住节点所在链表 */
pxNewListItem->pvContainer = ( void * ) pxList;
/* 链表计数器++ */
( pxList->uxNumberOfItems )++;
}
- 将节点从链表删除
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;
/*调整链表的节点索引指针 */
if( pxList->pxIndex == pxItemToRemove )
{
pxList->pxIndex = pxItemToRemove->pxPrevious;
}
/* 初始化该节点所在的链表为空,表示节点还没有插入任何链表 */
pxItemToRemove->pvContainer = NULL;
/* 链表节点计数器-- */
( pxList->uxNumberOfItems )--;
/* 返回链表中剩余节点的个数 */
return pxList->uxNumberOfItems;
}
4.节点宏小函数
1 /* 初始化节点的拥有者 */
2 #define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner )\
3 ( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) )
4
5 /* 获取节点拥有者 */
6 #define listGET_LIST_ITEM_OWNER( pxListItem )\
7 ( ( pxListItem )->pvOwner )
8
9 /* 初始化节点排序辅助值 */
10 #define listSET_LIST_ITEM_VALUE( pxListItem, xValue )\
11 ( ( pxListItem )->xItemValue = ( xValue ) )
12
13 /* 获取节点排序辅助值 */
14 #define listGET_LIST_ITEM_VALUE( pxListItem )\
15 ( ( pxListItem )->xItemValue )
16
17 /* 获取链表根节点的节点计数器的值 */
18 #define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList )\
19 ( ( ( pxList )->xListEnd ).pxNext->xItemValue )
20
21 /* 获取链表的入口节点 */
22 #define listGET_HEAD_ENTRY( pxList )\
23 ( ( ( pxList )->xListEnd ).pxNext )
24
25 /* 获取节点的下一个节点 */
26 #define listGET_NEXT( pxListItem )\
27 ( ( pxListItem )->pxNext )
28
29 /* 获取链表的最后一个节点 */
30 #define listGET_END_MARKER( pxList )\
31 ( ( ListItem_t const * ) ( &( ( pxList )->xListEnd ) ) )
33 /* 判断链表是否为空 */
34 #define listLIST_IS_EMPTY( pxList )\
35 ( ( BaseType_t ) ( ( pxList )->uxNumberOfItems == ( UBaseType_t )
0 ) )
36
37 /* 获取链表的节点数 */
38 #define listCURRENT_LIST_LENGTH( pxList )\
39 ( ( pxList )->uxNumberOfItems )
40
41 /* 获取链表第一个节点的 OWNER,即 TCB */
42 #define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )
43 {
44 List_t * const pxConstList = ( pxList );
45 /* 节点索引指向链表第一个节点 */ \
46 ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;
47 /* 这个操作有啥用? */ \
48 if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) ) \
49 {
50 ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;
51 }
52 /* 获取节点的 OWNER,即 TCB */ \
53 ( pxTCB ) = ( pxConstList )->pxIndex->pvOwner;
54 }
三、任务
1. 任务控制块
typedef struct tskTaskControlBlock
{
volatile StackType_t *pxTopOfStack; /* 栈顶 */
ListItem_t xStateListItem; /* 任务节点 */
StackType_t *pxStack; /* 任务栈起始地址 */
char pcTaskName[ configMAX_TASK_NAME_LEN ]; /* 任务名称,字符串形式 */
} tskTCB;
typedef tskTCB TCB_t;
4.任务创建流程
- 第一层-xTaskCreateStatic()
TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode, /* 任务函数名 */
const char * const pcName, /* 任务名称 */
const uint32_t ulStackDepth, /* 任务栈(4个子节单位) */
void * const pvParameters, /* 任务形参 */
UBaseType_t uxPriority, /* 任务优先级 */
StackType_t * const puxStackBuffer, /* 任务栈起始地址 */
StaticTask_t * const pxTaskBuffer ) /* 静态任务控制块指针 */
{
TCB_t *pxNewTCB;
TaskHandle_t xReturn;
if( ( pxTaskBuffer != NULL ) && ( puxStackBuffer != NULL ) )
{
pxNewTCB = ( TCB_t * ) pxTaskBuffer;
pxNewTCB->pxStack = ( StackType_t * ) puxStackBuffer;
/* 创建新任务 */
prvInitialiseNewTask( pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, &xReturn, pxNewTCB, NULL );
prvAddNewTaskToReadyList( pxNewTCB );
}
else
{
xReturn = NULL;
}
return xReturn;
}
- 第二层prvInitialiseNewTask&prvAddNewTaskToReadyList
static void prvInitialiseNewTask(TaskFunction_t pxTaskCode,
const char * const pcName,
const uint32_t ulStackDepth,
void * const pvParameters,
TaskHandle_t * const pxCreatedTask,
TCB_t *pxNewTCB )
{
StackType_t *pxTopOfStack;
UBaseType_t x;
/* 获取栈顶地址 */
pxTopOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 );
/* 向下做 8 字节对齐 */
pxTopOfStack = ( StackType_t * ) \
( ( ( uint32_t ) pxTopOfStack ) & ( ~( ( uint32_t ) 0x0007 ) ) );
/* 将任务的名字存储在 TCB 中 */
for ( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ )
{
pxNewTCB->pcTaskName[ x ] = pcName[ x ];
if ( pcName[ x ] == 0x00 )
{
break;
}
}
/* 任务名字的长度不能超过 configMAX_TASK_NAME_LEN */
pxNewTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = '\0';
/* 初始化 TCB 中的 xStateListItem 节点 */
vListInitialiseItem( &( pxNewTCB->xStateListItem ) );
/* 设置 xStateListItem 节点的拥有者 */
listSET_LIST_ITEM_OWNER( &( pxNewTCB->xStateListItem ), pxNewTCB );
/* 初始化任务栈 */
pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack,pxTaskCode,pvParameters );
/* 让任务句柄指向任务控制块 */ (14)
if ( ( void * ) pxCreatedTask != NULL )
{
*pxCreatedTask = ( TaskHandle_t ) pxNewTCB;
}
}