If you have recently paid attention to some embedded job descriptions, you may often see that RTOS, Vxworks, QNX and other RTOS users are preferred. Just open a 20K embedded development job responsibilities: You will find that familiar with RTOS development, porting, and tailoring is really delicious! Today, we will introduce the real-time operating system UCOS-II. First, the embedded operating system overview The main advantage of the embedded operating system is to shield the difference between the underlying hardware, provide a unified interface to the upper application, and manage process scheduling and resource allocation (such as CPU time, memory). And you can make full use of hardware resources, such as when a single task (large loop structure, such as most 51 programs) encounters the delay function, the CPU is idle. In a multitasking system, when the delay or waiting for resources is encountered, the system automatically runs the next task. When the conditions are met, the previous task is returned, which makes full use of the CPU and improves efficiency. The biggest difference between the uC/OS operating system and the bare-metal program is that uC/OS has task scheduling, which can perform important tasks according to the importance (priority) of the task, so as to ensure that the most important data can be processed in time. (So ​​it is necessary for a system to use the OS's judgment to be able to divide tasks one by one, and the coupling between tasks is small) to think about the process that occurs when the bare metal program is interrupted. The stack can be freely switched between A and B. If the switch is fast enough, A and B seem to be executing at the same time. This is parallel, and A and B are tasks. If this switching operation is done in the timer function, it can be switched strictly according to time. In addition, there is a certain relationship between each task, there is a logical sequence, etc., you must introduce global structures, variables to mark some information, the global data will not be released, so all tasks can go through Read and write these data to realize the exchange of information in each block to achieve so-called synchronization and mutual exclusion. This is the principle of the operating system, and these different communication methods are subdivided into event management, memory management, and so on. Second, the operation of ucos overview The first is the main function, then OSInit(). This function initializes the global data structures, builds the desired linked list and other data structures, prepares for subsequent global variable communication, and creates 1-2 system tasks (idle The task must be, in order not to let the operating system return. The statistical task is optional), and the so-called creation task OSTaskCreate is to make a function's function address, its own stack connection, priority, task control block, etc., for task switching Good preparation. Set the relevant information of the timing switching to be similar to the timer, and perform the task switching judgment in the interrupt according to the beat (this beat is to provide the timing reference for the delay function, and the delay time of one task or the waiting resource is satisfied and enters the ready list. Check the priority to see if it can be executed. If it can be switched, the switch has not been turned on at this time, so after the task is created, start the multitasking function OSStart(). This function is to let the SP point to one of the stacks, then Jumping out of the stack jumps to a task function, and then the normal task runs. For the operating system, it is mainly how the task releases the CPU (delay, interrupt, wait for resources), how other tasks get the CPU (go into the ready list), how to find a task (priority and task control list). Third, the introduction of various parts of ucos The various services of μC/OS-II come in the form of tasks. In μC/OS-II, each task has a unique priority. It is based on a priority deprived core and is suitable for applications where real-time requirements are high. 3.1 μC/OS-II task The core part of μC/OS-II is its mission, which also responds to and handles different events through tasks. From the code point of view, the task of μC/OS-II is generally as follows (C language description, the same below): Void uCOSTask(void *p) { While(1) { Task specific function; } } The function to create a task is OSTaskCreate (void (*task) (void *pd), void *pdata, OS_STK *ptos, INT8U prio), OSTaskCreate () requires four parameters: task is a pointer to the task code, pdata is when A pointer to a parameter passed to the task at the start of the task, ptos is the top-of-stack pointer assigned to the stack of the task, and prio is the priority assigned to the task. The task of μC/OS-II is to look at memory. The task consists of three parts: the code part of the task, the task stack, and the task control block. The task control block saves the attributes of the task; the task stack saves the environment in which the task runs when the task is switched; the task code part is the C language code seen on the macro. There is usually only one processor in an embedded device, so only one task can occupy the processor at a specific moment. There are five states in the μC/OS-II task: sleep, ready, run, wait, and interrupt service. 3.2 Task Control Block The smallest unit involved in scheduling and management in μC/OS-II is the task. The task is managed in the form of a task control block. The task control block is a structure that contains the stack information of the task, the pointer of the task control block, the pointer of the previous task control block and the latter task control block (using the priority one by one to find out whether it is the task to be found, so The priority is unique), the priority of the task (find the task control block according to the priority, so that the task is found), the time the task needs to wait (when the task is delayed, the clock tick interrupt will come to wait time Subtract, when it is zero, put it in the ready list, check if you need to switch) and other information. The task control block contains all the information except the one pointing to the task code. And how is the code address of the task obtained when the task is running? In fact, the address of the task code is stored through the stack of tasks. 3.3 Task Stack When a task is created, it must indicate the stack of the task. The stack size of the task is defined by the user according to the actual situation. The μC/OS-II stack is actually a contiguous block of memory. When the task is created, the function OSTaskCreate() associates the code of the task with the stack defined by the user for the task. Since the stack can be divided into two types according to the growth direction, the stack initialization function called when the task is created is actually related to the microprocessor type. Therefore, these codes are also modified when they are migrated. 3.4 system tasks μC/OS-II provides two system tasks: idle tasks and statistical tasks. Among them, idle tasks are necessary. Because at some point it is possible that all user tasks are not in a ready state, so the microprocessor will crash the system because there is no task running. 3.5 critical section There is also a critical concept in μC/OS-II. The so-called critical section is a special code. The interrupted response is not allowed in this code to guarantee the atomicity of this code. The critical code segment is implemented by calling the switch to interrupt two macros. Management of 3.6 μC/OS-II tasks 3.6.1 Management of ready tasks μC/OS-II defines the data structure of a ready table, much like a normal array (that is, a one-dimensional array), but given a special meaning. Each bit in the ready list indicates whether a priority task is in the ready state. The subscript of each digit indicates the priority of the task. Ready tasks are highly efficient to manage through special data structures and meanings. The task ready list is represented by an OSRdyTbl array, and the array size (OS_RDY_TBL_SIZE) is determined by the lowest priority (OS_LOWEST_PRIO), which reduces unnecessary space waste and saves RAM resources. OSRdyTbl[] is an array of INT8U types, each of which takes up 8 bits. Each bit represents a priority status (1 is ready, 0 is not ready). Eight elements can represent 64 priority levels (8*8=64). To speed up the lookup of the continuation table, Labrosse classifies each OSRdyTbl element into each priority group, and 8 elements have 8 priority groups, which define an 8-bit variable OSRdyGrp of INT8U type, each of OSRdyGrp Corresponds to each priority group. As shown below: The third bit of the task priority is used to determine the first few bits of the task in osRdyTb1, and the next three bits are used to specify the first few elements. Assume that the task of priority 31 first joins the ready task table, at this time OSRdyGrp and OSRdyTbl: The third bit of OSRdyGrp is 1, indicating that the third priority group has a ready task. The 7th bit of OSRdyTbl is 1, indicating that the 31st priority task is ready. Use this to add or remove tasks from the ready list. When scheduling, it is to find this table, find the highest priority, and then find the task control block to perform the task. 3.6.2 Task creation, suspension, and other operations μC/OS-II provides two functions to create tasks. They are OSTaskCreate() and OSTaskCreateExt(). Tasks can also be suspended or restored after creation. This also uses the system functions provided by μC/OS-II. Suspend the task using the function OSTsakSuspend() to resume the suspended task using the function OSTaskResume(). μC/OS-II also provides functions for deleting tasks, modifying priorities, querying task information, and more. 3.6.3 Scheduling of tasks Scheduling of the μC/OS-II task is done by the scheduler. The so-called scheduler is actually a function OSShed(); this function obtains the highest priority ready task by searching the task ready list, and the task is switched by obtaining the control block of the task by the priority of the task. The scheduling of tasks is not done at any time, but is sometimes time-consuming. The μC/OS-II task will generate a task schedule when the following conditions occur: ◠A new task has been created and registered in the ready list ◠Some tasks have been deleted ◠A task that is waiting is awakened ◠When the interrupt is exited ◠A running task waits for an event and enters a wait state ◠Running tasks voluntarily give up microprocessor possession and wait for a while 3.6.4 Initialization and startup of tasks A large number of global variables and data structures are defined in μC/OS-II. These global variables and data structures need to be initialized before the μC/OS-II runs. In order to complete the initialization of μC/OS-II, the system provides the initialization function OSInit(). The startup of μC/OS-II is also implemented by the system-provided function OSStart(). OSStart() gets the highest priority ready task in the ready list after determining that the system is not running, and calls the function OSStartHighRdy() to start the system. 3.6.5 Interrupts and clocks In order to be able to respond to asynchronous events, real-time systems typically use interrupts. μC/OS-II also uses interrupts to respond to external events. The interrupt processing process of μC/OS-II is roughly as follows: When the system starts an interrupt, the system receives the interrupt and then finds the interrupt address of the interrupt service routine to execute the interrupt, and exits the interrupt after the execution is completed. The point to mention here is that when the interrupt is to be exited, the system will look for the ready list to have a higher priority than the task in the interrupted service state. If there is a dispatch once, the task that returns to the interrupt will continue to run. Some details about interrupts are discussed later in the migration section. The most important of all interrupt sources is the clock interrupt, which provides time service for the system to achieve task latency. 3.6.6 Communication between tasks For a complete embedded operating system, the communication mechanism between tasks is essential. μC/OS-II provides the corresponding data structure and mechanism to achieve synchronization and communication between tasks. There are several ways to communicate between tasks in ucos II: 1. Sharing global variables, this is the fastest and most efficient way to achieve this communication can be achieved in two ways: one is to use the macro OS_ENTER_CRITICAL () and OS_EXIT_CRITICAL () to close the interrupt and open the interrupt, the second is to use the function OSSchedLock () And OSSchedUnlock() locks and unlocks the task scheduling function in μC/OS-II. 2. Using semaphores 3. Use the mailbox 4. Using message queues Creating a task requires assigning a task control block to the task. This task control block stores important information about the task. Then, the event control block is like the task control block in the task. It stores important information about this event. We say that creating an event (signal, mailbox, message queue), the essential process is to initialize this event control block. Multiple tasks can wait for the same event to occur at the same time. In this case, when the event occurs, among the tasks waiting for the event, the task with the highest priority gets the event and enters the ready state, ready to execute. The event control block is a data structure defined as follows: Typedef struct { Void *OSEventPtr; /* Pointer to a message or message queue */ INT8U OSEventTbl[OS_EVENT_TBL_SIZE]; /* Waiting for task list */ INT16U OSEventCnt; /* counter (when the event is a semaphore) */ INT8U OSEventType; /* time type */ INT8U OSEventGrp; /* Wait for the group where the task is located */ } OS_EVENT; The .OSEventPtr pointer is only used if the defined event is a mailbox or message queue. When the defined event is a mailbox, it points to a message, and when the defined event is a message queue, it points to a data structure (since the queue is to pass multiple messages). .OSEventTbl[] and .OSEventGrp Much like OSRdyTbl[] and OSRdyGrp mentioned earlier, except that the first two contain tasks waiting for an event, while the latter two contain tasks in the system that are in a ready state. .OSEventCnt When an event is a semaphore, .OSEventCnt is a counter for the semaphore. (In initialization, if the semaphore is used to indicate the occurrence of one or more events, then the initial value of the semaphore should be set to 0. If the semaphore is used for access to the shared resource, then the initial value of the semaphore Should be set to 1) .OSEventType defines the specific type of event. It can be one of a semaphore (OS_EVENT_SEM), a mailbox (OS_EVENT_TYPE_MBOX), or a message queue (OS_EVENT_TYPE_Q). The user should call the corresponding system function according to the specific value of the domain to ensure the correctness of the operation. What is the semaphore? What is the use of semaphores? A semaphore can be used to indicate the occurrence of one or more events, and a second is used to access shared resources. Sometimes the mailbox can be used as a semaphore. In terms of the semaphore, the mailbox only passes a pointer variable. In fact, the process of creating a semaphore is almost the same, first apply for an empty event control block, and then initialize the event control block. Finally, a pointer to this event control block is returned. The difference is that the type of event control block is set to OS_EVENT_TYPE_MBOX, and the .OSEventPtr field is used to accommodate the message pointer. If the mailbox is like an upgraded version of the semaphore, then the message queue is an upgraded version of the mailbox. A mailbox can send a pointer variable from one task to another, and a message queue can send a lot of pointer variables from one task to another. And the data structure variables pointed to by each pointer can also be different. (The most fundamental part of the message queue is a circular buffer, where each unit contains a pointer.) And creating a mailbox, the process of creating a semaphore is very similar, first apply for a control block, then initialize the control block, and create a mailbox The semaphore is different. The process of creating a message queue is to apply for a queue control block. Finally, a brief summary of the knowledge reserve for understanding RTOS: 1. Find an MCU that someone else has ported the code to run uCOS. Then go to see other people's sample code, first understand how to use uC/OS. Try writing a control for three different led lights that flash at different frequencies. 2. Wait until uCOS has provided you with the API, and read the book about the operating system. Then go to the concept of stack, context, scheduler, lock, file system, network, interrupt, thread, mailbox (message queue) and so on. Try writing a multitasking HTTP server. Try to reconstruct existing code with uCOS. 3. Read an earlier version of the uCOS code to see how uCOS implements the operating system. At this time, I will go to the book on the principle of operating system. 4. Try to port uCOS to a new chip. Don't go to google unless you have to. Try to solve the problems you have encountered independently. 5. Change the original version of the uCOS code to see how the behavior of the operating system changes after the modification. 6. Check the history of the evolution of the uCOS version to see why everyone will modify this code like this? Why is this designed? The typical Electrical Wire harnesses that ETOP supplies include dozens of wires and sometimes hundreds of different components and terminations. Our engineering staff is well versed in the design and construction of wire harnesses and is available to assist in the development of the most efficient wiring harness to meet your demands. A basic Wire Harness may include as few as three discreet components, while the more classic harnesses include many more wires and other passive, and potentially active, components. Electrical Wiring Harness, terminal wiring, wire assembling,bullet terminals, lead wire assembly ETOP WIREHARNESS LIMITED , https://www.wireharness-assembling.com