之前的章节都是针对某个或某些知识点进行的专项讲解,重点在功能和代码解释。
回到最初开始学μC/OS-III系统时,当时就定下了一个目标,不仅要读懂,还要读透,改造成更适合中国宝宝体质的使用方式。在学完野火的教程后,经过几经思考,最后决定自己锦上添花,再续上几章。
这几章想达成目的如下:
- 能够快速的上手
- 能够控制系统的功能
- 明白移植的过程
- 能够根据需要的功能来裁剪源码
从第六十一章开始的章节都是熟读源码后,根据笔者的整理方法,按照某种逻辑从系统源码中抽出来的专项解释。
笔者整理方法如下
- 各文件夹功能介绍(每个文件夹放什么文件,哪些是移植的,哪些不需要改,哪些需要修改)
- 各文件功能概览(每个文件都明白有哪些东西,是系统的哪一部分)
- 各文件函数概览(每个文件的有什么函数,函数的作用是什么,形参是什么)
- 移植的本质与移植的顺序(哪些文件需要了解,哪些文件是移植的时候需要更换的)
- 添加与裁剪源码(添功能与删功能怎么上手)
- 常用的结构体列表
- 常用宏介绍(如何用宏来控制整个系统,启用或关闭某个功能)
- main函数常用的结构顺序
- 创建任务的流程
- 任务在几种队列的变化
每个整理方法会用一章或多章的篇幅来解释。
点击此处进入μC/OS-iii章节总目录
2024.05.09:UCOSIII第六十三节:常用的结构体(os.h文件)第二部分
- 六十八、UCOSIII:常用的结构体(os.h文件)第二部分
- OS_MEM
- OS_MSG
- OS_MSG_POOL
- OS_MSG_Q
- OS_MUTEX
- OS_INT_Q
- OS_Q
六十八、UCOSIII:常用的结构体(os.h文件)第二部分
OS_MEM
typedef struct os_mem OS_MEM;
/*
------------------------------------------------------------------------------------------------------------------------
* MEMORY PARTITIONS
------------------------------------------------------------------------------------------------------------------------
*/
struct os_mem { /* MEMORY CONTROL BLOCK */
OS_OBJ_TYPE Type; /* Should be set to OS_OBJ_TYPE_MEM */
void *AddrPtr; /* Pointer to beginning of memory partition */
CPU_CHAR *NamePtr;
void *FreeListPtr; /* Pointer to list of free memory blocks */
OS_MEM_SIZE BlkSize; /* Size (in bytes) of each block of memory */
OS_MEM_QTY NbrMax; /* Total number of blocks in this partition */
OS_MEM_QTY NbrFree; /* Number of memory blocks remaining in this partition */
#if OS_CFG_DBG_EN > 0u
OS_MEM *DbgPrevPtr;
OS_MEM *DbgNextPtr;
#endif
};
这个结构体定义描述了一个内存分区(Memory Partition)。下面是结构体中各个字段的详细解释:
Type
: 对象类型,应设置为OS_OBJ_TYPE_MEM
,表示这是一个内存分区对象。AddrPtr
: 指向内存分区起始地址的指针,指向内存分区中第一个可用内存块的地址。NamePtr
: 指向内存分区名称的指针,通常是一个以NUL终止的ASCII字符串。FreeListPtr
: 指向空闲内存块链表的指针,用于存储内存分区中未分配的内存块。BlkSize
: 内存块大小,表示每个内存块的字节数。NbrMax
: 内存分区中总共可用的内存块数量。NbrFree
: 内存分区中当前可用的空闲内存块数量。DbgPrevPtr
和DbgNextPtr
: 调试目的的前一个和后一个内存分区指针,用于链表连接。
内存分区是一种动态内存分配的管理机制,它将一块大的连续内存空间分割成多个固定大小的内存块,并维护一个空闲内存块链表。应用程序可以通过内存分区来分配和释放内存块,以满足动态内存需求。这个结构体包含了内存分区的属性,例如名称、起始地址、内存块大小和数量等,以及用于调试的指针。
OS_MSG
typedef struct os_msg OS_MSG;
/*
------------------------------------------------------------------------------------------------------------------------
* MESSAGES
------------------------------------------------------------------------------------------------------------------------
*/
struct os_msg { /* MESSAGE CONTROL BLOCK */
OS_MSG *NextPtr; /* Pointer to next message */
void *MsgPtr; /* Actual message */
OS_MSG_SIZE MsgSize; /* Size of the message (in # bytes) */
CPU_TS MsgTS; /* Time stamp of when message was sent */
};
这个结构体定义描述了一个消息(Message)的控制块。下面是结构体中各个字段的详细解释:
NextPtr
: 指向下一个消息控制块的指针,用于链接消息队列中的消息。MsgPtr
: 指向实际消息数据的指针,存储了消息的内容。MsgSize
: 消息的大小,表示消息数据的字节数量。MsgTS
: 消息的时间戳,记录了消息被发送的时间。
这个结构体用于管理消息队列中的消息。消息队列是一种常用的通信机制,允许任务之间传递数据。每个消息控制块代表了一个消息,包含了消息的内容、大小和发送时间等信息。通常,消息控制块会被链接成一个链表,形成一个消息队列,任务可以通过发送和接收消息来进行通信。
OS_MSG_POOL
typedef struct os_msg_pool OS_MSG_POOL;
struct os_msg_pool { /* OS_MSG POOL */
OS_MSG *NextPtr; /* Pointer to next message */
OS_MSG_QTY NbrFree; /* Number of messages available from this pool */
OS_MSG_QTY NbrUsed; /* Current number of messages used */
OS_MSG_QTY NbrUsedMax; /* Peak number of messages used */
};
这个结构体定义描述了一个消息池(Message Pool)。下面是结构体中各个字段的详细解释:
NextPtr
: 指向下一个消息池的指针,用于链接消息池链表中的不同消息池。NbrFree
: 池中当前可用的消息数量,表示尚未被使用的消息数量。NbrUsed
: 池中当前已使用的消息数量,表示已经被分配给任务的消息数量。NbrUsedMax
: 池中曾经同时被使用的最大消息数量,表示消息池在任何时间点上达到的最大负载。
消息池是一种预先分配的消息存储区域,用于分配和管理消息控制块。它通常由固定数量的消息控制块组成,以满足任务之间的通信需求。消息池的主要目的是提高消息管理的效率和实时性,避免了在消息发送和接收时的动态内存分配和释放操作。通过维护消息池的状态信息,可以有效地跟踪消息的使用情况,帮助系统监视消息的分配和释放情况,从而实现对系统资源的合理管理。
OS_MSG_Q
typedef struct os_msg_q OS_MSG_Q;
struct os_msg_q { /* OS_MSG_Q */
OS_MSG *InPtr; /* Pointer to next OS_MSG to be inserted in the queue */
OS_MSG *OutPtr; /* Pointer to next OS_MSG to be extracted from the queue */
OS_MSG_QTY NbrEntriesSize; /* Maximum allowable number of entries in the queue */
OS_MSG_QTY NbrEntries; /* Current number of entries in the queue */
OS_MSG_QTY NbrEntriesMax; /* Peak number of entries in the queue */
};
这个结构体定义描述了一个消息队列(Message Queue)。下面是结构体中各个字段的详细解释:
InPtr
: 指向队列中下一个将要插入的消息的指针,表示队列的尾部。OutPtr
: 指向队列中下一个将要提取的消息的指针,表示队列的头部。NbrEntriesSize
: 队列中允许的最大消息数量,即队列的容量。NbrEntries
: 队列当前的消息数量,表示当前队列中包含的消息数量。NbrEntriesMax
: 队列曾经同时存在的最大消息数量,表示队列在任何时间点上达到的最大负载。
消息队列是一种用于在任务之间进行异步通信的机制,允许任务以先进先出(FIFO)的方式发送和接收消息。通过维护队列的入口指针和出口指针,可以有效地管理消息的插入和提取操作。消息队列通常用于实现任务之间的解耦合,提高系统的可维护性和可扩展性,同时可以避免任务之间直接的数据共享,从而减少了竞态条件和死锁的发生。
OS_MUTEX
typedef struct os_mutex OS_MUTEX;
/*
------------------------------------------------------------------------------------------------------------------------
* MUTUAL EXCLUSION SEMAPHORES
*
* Note(s) : See PEND OBJ Note #1'.
------------------------------------------------------------------------------------------------------------------------
*/
struct os_mutex { /* Mutual Exclusion Semaphore */
/* ------------------ GENERIC MEMBERS ------------------ */
OS_OBJ_TYPE Type; /* Should be set to OS_OBJ_TYPE_MUTEX */
CPU_CHAR *NamePtr; /* Pointer to Mutex Name (NUL terminated ASCII) */
OS_PEND_LIST PendList; /* List of tasks waiting on mutex */
#if OS_CFG_DBG_EN > 0u
OS_MUTEX *DbgPrevPtr;
OS_MUTEX *DbgNextPtr;
CPU_CHAR *DbgNamePtr;
#endif
/* ------------------ SPECIFIC MEMBERS ------------------ */
OS_TCB *OwnerTCBPtr;
OS_PRIO OwnerOriginalPrio;
OS_NESTING_CTR OwnerNestingCtr; /* Mutex is available when the counter is 0 */
CPU_TS TS;
};
这个结构体定义描述了一个互斥信号量(Mutual Exclusion Semaphore),通常称为互斥锁(Mutex)。下面是结构体中各个字段的详细解释:
Type
: 对象类型,应设置为OS_OBJ_TYPE_MUTEX
,表示这是一个互斥信号量对象。NamePtr
: 指向互斥信号量名称的指针,通常是一个以NUL终止的ASCII字符串。PendList
: 等待互斥信号量的任务列表,用于存储等待该互斥信号量的任务的信息。DbgPrevPtr
、DbgNextPtr
和DbgNamePtr
: 调试目的的前一个和后一个互斥信号量指针以及互斥信号量名称的指针。OwnerTCBPtr
: 指向当前拥有该互斥信号量的任务控制块(TCB)的指针。OwnerOriginalPrio
: 拥有者任务原始优先级,记录拥有该互斥信号量的任务的原始优先级。OwnerNestingCtr
: 拥有者任务的嵌套计数器,用于跟踪任务对互斥锁的嵌套请求。TS
: 互斥信号量的时间戳,记录了最近一次操作的时间。
如果我们创建一个互斥量,那么互斥量创建成功的示意图具体见图
互斥信号量是一种同步原语,用于在多任务环境中保护共享资源免受并发访问的影响。它确保一次只有一个任务能够访问共享资源,其他任务必须等待拥有互斥信号量的任务释放资源后才能访问。通过维护互斥信号量的拥有者信息和等待列表,可以实现对共享资源的有效保护和同步访问。
OS_INT_Q
typedef struct os_int_q OS_INT_Q;
/*
------------------------------------------------------------------------------------------------------------------------
* ISR POST DATA
------------------------------------------------------------------------------------------------------------------------
*/
#if OS_CFG_ISR_POST_DEFERRED_EN > 0u
struct os_int_q {
OS_OBJ_TYPE Type; /* Type of object placed in the circular list */
OS_INT_Q *NextPtr; /* Pointer to next OS_INT_Q in circular list */
void *ObjPtr; /* Pointer to object placed in the queue */
void *MsgPtr; /* Pointer to message if posting to a message queue */
OS_MSG_SIZE MsgSize; /* Message Size if posting to a message queue */
OS_FLAGS Flags; /* Value of flags if posting to an event flag group */
OS_OPT Opt; /* Post Options */
CPU_TS TS; /* Timestamp */
};
#endif
这个结构体定义描述了用于延迟中断服务程序(ISR)投递的数据(ISR Post Data)。下面是结构体中各个字段的详细解释:
Type
: 放置在循环列表中的对象的类型,应设置为相应的对象类型。NextPtr
: 指向循环列表中下一个os_int_q
结构体的指针,用于链接循环列表的节点。ObjPtr
: 指向要投递的对象的指针,可以是一个消息队列、事件标志组或其他支持的对象。MsgPtr
: 如果投递到消息队列,则指向要投递的消息的指针。MsgSize
: 如果投递到消息队列,则表示要投递的消息的大小。Flags
: 如果投递到事件标志组,则表示要设置的事件标志的值。Opt
: 投递选项,例如指定是否等待、是否强制投递等。TS
: 时间戳,记录了投递操作的时间。
这个结构体通常用于在中断服务程序中延迟执行某些操作。当在中断服务程序中需要执行的操作不能立即完成时,可以将相关数据填充到这个结构体中,并将其添加到延迟投递队列中。然后,当中断服务程序完成并退出时,操作系统可以在适当的时间点(通常在任务上下文中)检查延迟投递队列,并执行相应的操作。这种延迟投递的机制可以避免在中断上下文中执行耗时的操作,从而提高系统的响应性和可靠性。
OS_Q
typedef struct os_q OS_Q;
/*
------------------------------------------------------------------------------------------------------------------------
* MESSAGE QUEUES
*
* Note(s) : See PEND OBJ Note #1'.
------------------------------------------------------------------------------------------------------------------------
*/
struct os_q { /* Message Queue */
/* ------------------ GENERIC MEMBERS ------------------ */
OS_OBJ_TYPE Type; /* Should be set to OS_OBJ_TYPE_Q */
CPU_CHAR *NamePtr; /* Pointer to Message Queue Name (NUL terminated ASCII) */
OS_PEND_LIST PendList; /* List of tasks waiting on message queue */
#if OS_CFG_DBG_EN > 0u
OS_Q *DbgPrevPtr;
OS_Q *DbgNextPtr;
CPU_CHAR *DbgNamePtr;
#endif
/* ------------------ SPECIFIC MEMBERS ------------------ */
OS_MSG_Q MsgQ; /* List of messages */
};
这个结构体定义描述了一个消息队列(Message Queue)。下面是结构体中各个字段的详细解释:
Type
: 对象类型,应设置为OS_OBJ_TYPE_Q
,表示这是一个消息队列对象。NamePtr
: 指向消息队列名称的指针,通常是一个以NUL终止的ASCII字符串。PendList
: 等待消息队列的任务列表,用于存储等待从消息队列中获取消息的任务的信息。DbgPrevPtr
、DbgNextPtr
和DbgNamePtr
: 调试目的的前一个和后一个消息队列指针以及消息队列名称的指针。MsgQ
: 消息队列中的消息列表,包含了实际的消息数据。
消息队列创建完成的示意图具体见图
消息队列是一种在多任务系统中用于任务间通信的机制。它允许任务以先进先出(FIFO)的顺序发送和接收消息。任务可以通过向消息队列发送消息来通知其他任务,也可以通过从消息队列接收消息来获取其他任务发送的数据。消息队列通常用于解耦合任务之间的依赖关系,允许任务异步地进行通信,提高系统的灵活性和可维护性。