FreeRTOS

490 阅读5分钟

一、编程风格

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