今天看os_core.c文件中的各种初始化函数。
OS_EventWaitListInit(OS_EVENT *pevent)初始化事件控制块的等待列表:
/*$PAGE*/
/*2018/2/8
*********************************************************************************************************
* INITIALIZE EVENT CONTROL BLOCK'S WAIT LIST
* 初始化事件控制块的等待列表
* Description: This function is called by other uC/OS-II services to initialize the event wait list.
*描述:该功能被其他uc/os-ii服务调用,用来初始化事件的等待列表。
* Arguments : pevent is a pointer to the event control block allocated to the event.
*参数: --pevent是一个指向事件控制块的指针
* Returns : none
*返回值:无
* Note : This function is INTERNAL to uC/OS-II and your application should not call it.
注释:该功能是内部函数,你的应用程序不能调用
*********************************************************************************************************
*/
#if (OS_EVENT_EN) /*允许生成事件*/
void OS_EventWaitListInit(OS_EVENT *pevent) /*调用初始化事件等待列表函数*/
{
INT8U i;
pevent->OSEventGrp = 0u; /*将事件组初始化为0*/
for (i = 0u; i < OS_EVENT_TBL_SIZE; i++)
{
pevent->OSEventTbl[i] = 0u; /*将事件表全部初始化为0*/
}
}
#endif
OS_InitEventList(void)初始化事件控制块的空闲列表:
/*$PAGE*/
/*2018/2/8
*********************************************************************************************************
* INITIALIZATION
* INITIALIZE THE FREE LIST OF EVENT CONTROL BLOCKS
* 初始化事件控制块的空闲列表
* Description: This function is called by OSInit() to initialize the free list of event control blocks.
*描述:该功能被初始化函数 OSInit()调用,用来初始化事件控制块的空闲列表
* Arguments : none
*参数:无
* Returns : none
返回值:无
*********************************************************************************************************
*/
static void OS_InitEventList(void)
{
#if (OS_EVENT_EN) && (OS_MAX_EVENTS > 0u)
#if (OS_MAX_EVENTS > 1u) /*最大事件数不止1个,用循环处理*/
INT16U ix;
INT16U ix_next;
OS_EVENT *pevent1; /*第一个指向事件控制块的指针*/
OS_EVENT *pevent2; /*第二个指向事件控制块的指针*/
OS_MemClr((INT8U *)&OSEventTbl[0], sizeof(OSEventTbl)); /* Clear the event table 将事件表从内存中清理掉*/
for (ix = 0u; ix < (OS_MAX_EVENTS - 1u); ix++) /* Init. list of free EVENT control blocks初始化事件控制块的空闲列表*/
{
ix_next = ix + 1u;
pevent1 = &OSEventTbl[ix]; /*pevent1指向ix个ECB*/
pevent2 = &OSEventTbl[ix_next]; /*pevent2指向下一个ECB*/
pevent1->OSEventType = OS_EVENT_TYPE_UNUSED; /*将事件的类型设置为无使用类型*/
pevent1->OSEventPtr = pevent2; /*将OSEvenPtr指向下一个元素(ECB)*/
#if OS_EVENT_NAME_EN > 0u /*如果事件控制块被命名,设置为未命名*/
pevent1->OSEventName = (INT8U *)(void *)"?"; /*未命名就用“?”表示*/
#endif
}
pevent1 = &OSEventTbl[ix]; /*对数组的最后一个进行处理*/
pevent1->OSEventType = OS_EVENT_TYPE_UNUSED;
pevent1->OSEventPtr = (OS_EVENT *)0; /*最后的OSEventPtr指针指向0,作为结束*/
#if OS_EVENT_NAME_EN > 0u /*如果最后一个事件也有名称,设置为未命名*/
pevent1->OSEventName = (INT8U *)(void *)"?";
#endif
OSEventFreeList = &OSEventTbl[0]; /*最后事件空闲列表的指针指向事件表的首地址*/
#else
OSEventFreeList = &OSEventTbl[0]; /*如果只有一个事件控制块,就不需要循环了,直接进行处理*/
OSEventFreeList->OSEventType = OS_EVENT_TYPE_UNUSED;
OSEventFreeList->OSEventPtr = (OS_EVENT *)0;
#if OS_EVENT_NAME_EN > 0u
OSEventFreeList->OSEventName = (INT8U *)"?";
#endif
#endif
#endif
}
其中:在循环体内使用两个指针,如下所示:
ix_next = ix + 1u;
pevent1 = &OSEventTbl[ix]; /*pevent1指向ix个ECB*/
pevent2 = &OSEventTbl[ix_next]; /*pevent2指向下一个ECB*/
pevent1->OSEventType = OS_EVENT_TYPE_UNUSED; /*将事件的类型设置为无使用类型*/
pevent1->OSEventPtr = pevent2; /*将OSEvenPtr指向下一个元素(ECB)*/
个人认为是想通过EventPtr指针将所有的事件控制块链接起来。
这个函数,最主要的是设置时间的类型 (初始化为UNUSED)。
此外,
OS_MemClr((INT8U *)&OSEventTbl[0], sizeof(OSEventTbl)); /* Clear the event table 将事件表从内存中清理掉*/
for (ix = 0u; ix < (OS_MAX_EVENTS - 1u); ix++) /* Init. list of free EVENT control blocks初始化事件控制块的空闲列表*/
{
ix_next = ix + 1u;
pevent1 = &OSEventTbl[ix]; /*pevent1指向ix个ECB*/
pevent2 = &OSEventTbl[ix_next]; /*pevent2指向下一个ECB*/
pevent1->OSEventType = OS_EVENT_TYPE_UNUSED; /*将事件的类型设置为无使用类型*/
pevent1->OSEventPtr = pevent2; /*将OSEvenPtr指向下一个元素(ECB)*/
#if OS_EVENT_NAME_EN > 0u /*如果事件控制块被命名,设置为未命名*/
pevent1->OSEventName = (INT8U *)(void *)"?"; /*未命名就用“?”表示*/
#endif
}
刚开始对这几行语句有些疑问:内存已经把OSEventTb1清理掉了,怎么后面for循环中还能用?
后来认为是内存清理的是具体的数据,但是地址还保留着。下面是对地址进行的相关操作。主要是设置了事件的类型,改了名字,并且重新建立了表的链接。
OS_InitMisc(void)初始化各种变量:
/*$PAGE*/
/*2018/2/8
*********************************************************************************************************
* INITIALIZATION
* INITIALIZE MISCELLANEOUS VARIABLES
* 初始化各种变量
* Description: This function is called by OSInit() to initialize miscellaneous variables.
*描述:该功能被OSInit()调用,用来初始化各种变量
* Arguments : none
*参数:无
* Returns : none
返回值:无
*********************************************************************************************************
*/
static void OS_InitMisc(void)
{
#if OS_TIME_GET_SET_EN > 0u /*如果可以生成OS_TIME_GET_SET()函数*/
OSTime = 0uL; /* Clear the 32-bit system clock将时钟设为0。清除32位系统时钟*/
#endif
OSIntNesting = 0u; /* Clear the interrupt nesting counter将中断嵌套数初始化为0*/
OSLockNesting = 0u; /* Clear the scheduling lock counter将调度锁数目初始化为0*/
OSTaskCtr = 0u; /* Clear the number of tasks将任务的数目初始化为0*/
OSRunning = OS_FALSE; /* Indicate that multitasking not started将OSRunning设置为false,说明多任务没有开始*/
OSCtxSwCtr = 0u; /* Clear the context switch counter将上下文切换次数初始化为0*/
OSIdleCtr = 0uL; /* Clear the 32-bit idle counter将空闲节拍计数值初始化为0*/
#if OS_TASK_STAT_EN > 0u /*如果有任务统计*/
OSIdleCtrRun = 0uL; /*将已运转的空闲数初始化为0*/
OSIdleCtrMax = 0uL; /*将空闲节拍最大值初始化为0*/
OSStatRdy = OS_FALSE; /* Statistic task is not ready将统计任务的状态设置为为准备好(false)*/
#endif
#ifdef OS_SAFETY_CRITICAL_IEC61508
OSSafetyCriticalStartFlag = OS_FALSE; /* Still allow creation of objects */
#endif
}
OS_InitRdyList(void)初始化就绪列表:
/*$PAGE*/
/*2018/2/8
*********************************************************************************************************
* INITIALIZATION
* INITIALIZE THE READY LIST
* 初始化就绪列表
* Description: This function is called by OSInit() to initialize the Ready List.
*描述:该功能被OSInit()调用,用来初始化就绪列表
* Arguments : none
*参数:无
* Returns : none
返回值:无
*********************************************************************************************************
*/
static void OS_InitRdyList(void) /*初始化就绪列表*/
{
INT8U i;
OSRdyGrp = 0u; /*将就绪列表组清除为0*/
for (i = 0u; i < OS_RDY_TBL_SIZE; i++)
{
OSRdyTbl[i] = 0u; /*将就绪表初始化为0*/
}
OSPrioCur = 0u; /*将当前任务的优先级设置为0*/
OSPrioHighRdy = 0u; /*最高优先级任务的优先级设置为0*/
OSTCBHighRdy = (OS_TCB *)0; /*就绪列表中,指向最高优先级TCB的指针设置为0*/
OSTCBCur = (OS_TCB *)0; /*指向当前任务控制块的指针设置为0*/
}
这个函数中,个人认为很需要搞清楚各个变量代表的含义究竟是什么。不然后面会出现混乱和误用。
OS_InitTCBList(void)初始化任务控制块的空闲列表:
/*$PAGE*/
/*2018/2/8
*********************************************************************************************************
* INITIALIZATION
* INITIALIZE THE FREE LIST OF TASK CONTROL BLOCKS
* 初始化任务控制块的空闲列表
* Description: This function is called by OSInit() to initialize the free list of OS_TCBs.
*描述:该功能被OSInit()调用,用来初始化OS_TCB的空闲列表
* Arguments : none
*参数:无
* Returns : none
返回值:无
*********************************************************************************************************
*/
static void OS_InitTCBList(void) /*初始化任务控制块的空闲列表*/
{
INT8U ix;
INT8U ix_next;
OS_TCB *ptcb1; /*第一个指向TCB的指针*/
OS_TCB *ptcb2; /*第二个指向TCB的指针*/
OS_MemClr((INT8U *)&OSTCBTbl[0], sizeof(OSTCBTbl)); /* Clear all the TCBs 将所有的TCB从内存中清除掉*/
OS_MemClr((INT8U *)&OSTCBPrioTbl[0], sizeof(OSTCBPrioTbl)); /* Clear the priority table将优先级表从内存中清除掉*/
for (ix = 0u; ix < (OS_MAX_TASKS + OS_N_SYS_TASKS - 1u); ix++)/*初始化TCB的空闲列表*/
{
ix_next = ix + 1u;
ptcb1 = &OSTCBTbl[ix]; /*ptcb1指向TCB表的第ix个*/
ptcb2 = &OSTCBTbl[ix_next]; /*ptcb2指向下一个*/
ptcb1->OSTCBNext = ptcb2; /*通过TCBNext指针将该表的每一项建立连接*/
#if OS_TASK_NAME_EN > 0u /*如果有名字,设置为未命名*/
ptcb1->OSTCBTaskName = (INT8U *)(void *)"?";
#endif
}
ptcb1 = &OSTCBTbl[ix]; /*处理最后一个T*/
ptcb1->OSTCBNext = (OS_TCB *)0;
#if OS_TASK_NAME_EN > 0u
ptcb1->OSTCBTaskName = (INT8U *)(void *)"?";
#endif
OSTCBList = (OS_TCB *)0; /*将任务控制块列表进行初始化*/
OSTCBFreeList = &OSTCBTbl[0]; /*将TCB空闲列表的指针指向TCB表的首地址*/
}
初始化空闲列表和初始化就绪列表很相似。不赘述。
以上是CORE.C文件中有关初始化的内容。总结为下图:
OS_MemClr(INT8U *pdest,INT16U size)清理内存:
/*$PAGE*/
/*2018/2/8
*********************************************************************************************************
* CLEAR A SECTION OF MEMORY
* 清理内存某些部分
* Description: This function is called by other uC/OS-II services to clear a contiguous block of RAM.
*描写:该功能被其他服务调用,用来清除RAM中一段连续块。
* Arguments : pdest is the start of the RAM to clear (i.e. write 0x00 to)
*参数: --pdest是RAM中要清除的块的开始地址
* size is the number of bytes to clear.
* --size是要清除的大小。
* Returns : none
*返回值:无
* Notes : 1) This function is INTERNAL to uC/OS-II and your application should not call it.
* 2) Note that we can only clear up to 64K bytes of RAM. This is not an issue because none
* of the uses of this function gets close to this limit.
* 3) The clear is done one byte at a time since this will work on any processor irrespective
* of the alignment of the destination.
注释: 1)该功能为内部函数,你的应用程序不能调用。
2)需要注意我们只能清理RAM中的64KB。其他部分不能清理。不过这也不是什么问题,因为一般不会邻近这个限制区。
3)清理的时候一次只能清理一个字节。因为这样的话不用考虑目标的排列方式,与处理器无关,移植性更高。
*********************************************************************************************************
*/
void OS_MemClr(INT8U *pdest, /*清理内存*/
INT16U size)
{
while (size > 0u) {
*pdest++ = (INT8U)0; /*指针置为0*/
size--; /*大小最后也置为0*/
}
}
关于内存的管理,这里总结介绍一下:https://wenku.baidu.com/view/51e6f4f7a417866fb94a8e4b.html
OS_MemClr()函数:
- 用于对指定内存中的数据进行清零操作。
- 最大只允许清除内存中64KB的字节的数据。用户不必担心数据量不满足要求的问题,因为这个功能的应用没有一个能接近这个限制。
- 该功能一个时间点只能清除一个字节的数据,这是为了在任何程序上移植该程序时都能对准内存位置。当然,如果确定了处理器类型,可以修改该函数,提高代码的效率。
第三个图也可以和上文TCB的空闲列表函数很好的联系起来。都是类似的。
其他相关的内存管理没有介绍。因为还没有涉及到相关函数。涉及到再说。
OS_MemCopy(INT8U *pdest,INT8U *psrc,INT16U size)内存复制函数:
/*$PAGE*/
/*2018/2/8
*********************************************************************************************************
* COPY A BLOCK OF MEMORY
* 复制内存块
* Description: This function is called by other uC/OS-II services to copy a block of memory from one
* location to another.
*描述:该功能被其他服务调用,用来将内存块从某个位置复制到另一个位置。
* Arguments : pdest is a pointer to the 'destination' memory block
*参数: --pdest指向目的内存块的指针
* psrc is a pointer to the 'source' memory block
* --psrc指向源内存块的指针
* size is the number of bytes to copy.
* --size:要复制的内容的大小
* Returns : none
*返回值:无
* Notes : 1) This function is INTERNAL to uC/OS-II and your application should not call it. There is
* no provision to handle overlapping memory copy. However, that's not a problem since this
* is not a situation that will happen.
* 2) Note that we can only copy up to 64K bytes of RAM
* 3) The copy is done one byte at a time since this will work on any processor irrespective
* of the alignment of the source and destination.
注释: 1)该功能为内部函数,你的应用程序不能调用。没有提供处理重复内存复制的方法。不过没什么问题,因为这种情况不会发生。
2)我们只能复制RAM的64KB。
3)我们一个时间点只能复制一个字节。
*********************************************************************************************************
*/
void OS_MemCopy(INT8U *pdest,
INT8U *psrc,
INT16U size)
{
while (size > 0u) {
*pdest++ = *psrc++; /*从源内存块复制到目标内存块*/
size--;
}
}