The "planning" of module division means planning, which means how to reasonably divide a large software into a series of functionally independent parts to cooperate to complete the system requirements. As a structured programming language, C language is divided into modules based on functions (division according to functions becomes an error in object-oriented design, Newton's law meets> Theory of Relativity), modular programming of C language needs to be understood The following concepts:
(1) A module is a combination of a .c file and a .h file. The header file (.h) is the declaration of the module interface; (2) The external functions and data that a module provides for other modules to call must be in The file in .h is declared with the keyword extern; (3) The functions and global variables in the module should be declared with the keyword static at the beginning of the .c file; (4) Never define variables in the .h file! The difference between defining a variable and declaring a variable is that the definition will produce memory allocation operations, which is a concept in the assembly phase; while the declaration only tells the module containing the declaration to look for external functions and variables from other modules in the link phase. Such as:
The result of the above program is that the integer variable a is defined in modules 1, 2, and 3. A corresponds to different address units in different modules. Such a program has never been needed in this world. The correct approach is:
In this way, if modules 1, 2, and 3 operate a, they correspond to the same memory unit. An embedded system usually includes two types of modules: (1) hardware drive modules, one specific hardware corresponds to one module; (2) software function modules, the division of modules should meet the requirements of low coupling and high cohesion. Multi-task or single-task The so-called "single-task system" means that the system cannot support multi-task concurrent operations and executes a task macroscopically. On the other hand, a multitasking system can perform multiple tasks "simultaneously" in a macro-parallel (maybe serially). The concurrent execution of multitasking usually relies on a multitasking operating system (OS). The core of the multitasking OS is the system scheduler, which uses the task control block (TCB) to manage task scheduling functions. TCB includes information such as the current state of the task, priority, events or resources to be waited for, the starting address of the task program code, and the initial stack pointer. The scheduler uses this information when the task is activated. In addition, TCB is also used to store the "context" of the task. The context of the task is all the information to be saved when an executing task is stopped. Usually, the context is the current state of the computer, that is, the contents of each register. When a task switch occurs, the context of the currently running task is stored in the TCB, and the context of the task to be executed is taken out of its TCB and placed in each register. Typical examples of embedded multitasking OS are Vxworks, ucLinux, etc. Embedded OS is not out of reach of the altar, we can use less than 1,000 lines of code to achieve the simplest OS kernel for the 80186 processor. The choice between multi-tasking and single-tasking depends on whether the software system is huge. For example, most mobile phone programs are multi-tasking, but some PHS protocol stacks are single-tasking and have no operating system. Their main program calls the processing programs of each software module in turn to simulate a multi-tasking environment.
Typical architecture of single task program
(1) Start execution from the specified address when the CPU is reset; (2) Jump to the assembly code startup for execution; (3) Jump to the user's main program main for execution, complete in main: a. Initialize each hardware device;
b. Initialize each software module; c. Enter an endless loop (infinite loop), and call the processing function of each module. The user's main program and the processing functions of each module are all completed in C language. The user's main program finally enters an endless loop, and the preferred solution is:
Some programmers wrote:
This grammar does not exactly express the meaning of the code. We can't see anything from for (;;). Only when we understand that for (;;) means unconditional loop in C language can we understand its meaning. Here are a few "famous" endless loops:
1. Operating system is an endless loop; 2. WIN32 program is an endless loop; 3. Embedded system software is an endless loop; 4. The thread processing function of a multithreaded program is an endless loop. You may argue and say loudly: "Everything is not absolute, 2, 3, and 4 are not infinite loops." Yes, you are right, but you can't get flowers and applause. In fact, this is a point of no great significance, because the world never needs a WIN32 program that calls the OS to kill it after processing a few messages, and does not need an embedded system that just starts RUN and breaks itself. , You don’t need to start a thread that does a little bit and kills itself inexplicably. Sometimes, being too rigorous creates not convenience but trouble. Don’t you see, the five-layer TCP/IP protocol stack surpasses the rigorous ISO/OSI seven-layer protocol stack and becomes the de facto standard?
Interrupt service routine
Interruption is an important part of embedded system, but it does not include interruption in standard C. Many compiler developers have added support for interrupts to standard C, providing new keywords to indicate interrupt service routines (ISR), similar to __interrupt, #program interrupt, etc. When a function is defined as ISR, the compiler will automatically add the interrupt on-site stacking and popping code required by the interrupt service routine for the function. The interrupt service routine needs to meet the following requirements: (1) cannot return a value; (2) cannot pass parameters to the ISR; (3) the ISR should be as short as possible; (4) printf(char * lpFormatString,...) Access and performance issues cannot be used in ISR. In the development of a project, we designed a queue. In the interrupt service program, only the interrupt type was added to the queue. In the infinite loop of the main program, the interrupt queue was continuously scanned for interrupts. The first interrupt type is processed accordingly.
Determine whether there is an interruption in the main program loop:
The interrupt service program designed according to the above method is very small, and the actual work is performed by the main program.
Hardware driver module A hardware driver module usually includes the following functions: (1) Interrupt service routine ISR (2) Hardware initialization a. Modify registers and set hardware parameters (such as UART should set its baud rate, AD/DA device should set its Sampling rate, etc.); b. Write the entry address of the interrupt service routine into the interrupt vector table.
For example, for LCD, its driving module should provide functions such as drawing pixels, drawing lines, drawing matrix, and displaying character dot matrix; while for real clock, its driving module needs to provide functions such as acquisition time and setting time. The object-oriented of C has the concept of class in object-oriented language. A class is a collection of specific operations on specific data. The class contains two categories: data and operations. The struct in C language is just a collection of data. We can use function pointers to simulate struct as a "class" containing data and operations. The following C program simulates the simplest "class":
We can use C language to simulate three object-oriented features: encapsulation, inheritance, and polymorphism, but more often, we just need to encapsulate data and behavior to solve the problem of software structure chaos. The purpose of C simulation object-oriented thinking is not to simulate the behavior itself, but to solve the problem of the scattered structure of the overall program framework and the disconnection of data and functions when using C language programming in some cases. We will see such examples in subsequent chapters.
Finally, summarize the knowledge of embedded system programming software architecture introduced today, mainly including module division, multi-task or single-task selection, typical single-task program architecture, interrupt service routine, hardware driver module design, etc., from a macro perspective The main elements of an embedded system software.
Rayhot Technology Group Co.,Ltd , https://www.cnrayhot.com