How to realize modular programming on single chip microcomputer
Let's unveil the mystery of modularity and get a glimpse of its true colors. C language source files *. C mentioned the source file of C language, which is familiar to everyone. Because almost all the program codes we usually write are in this XX. C file. This file is also used by the compiler to compile and generate the corresponding target file. As the basis of modular programming, the source code of all the functions we want to realize is in this file. Ideal modularity should be regarded as a black box. In other words, we only care about the functions provided by the module, without considering the implementation details inside the module. For example, when we buy a mobile phone, we only need to know the functions provided by the mobile phone, and we don't need to know how it sends short messages and responds to the input of our keys. These processes are just a black box for our users. In large-scale program development, a program consists of many modules, and it is very likely that the writing tasks of these modules are assigned to different people. When you write this module, you probably need to use the excuse of using the module written by others. At this time, what we care about is what kind of interface its module implements, how to call it, and how to organize it inside. For me, there is no need to care too much. It is exactly what we need to pay attention to that we pursue the singleness of the interface and shield unnecessary details from the outside as much as possible. C language header file *. H talking about modular programming will inevitably involve multi-file compilation, that is, engineering compilation. In such a system, there are often multiple C files, and each C file has different functions. In our C file, because we need to provide external interfaces, we must provide some functions or variables for other external files to call. Suppose we have a liquid crystal display. C file, which provides the most basic LCD driver function LCD Putchar (CharCNEW value); //To output a character at the current position, you need to call this function in another file. What should I do? This is the function of the header file. It can be called an interface description file. Its file should not contain any substantive functional code. We can understand this header file as a specification, which is an interface function or an interface variable provided by our module. At the same time, the file also contains some important macro definitions and some structural information. Without this information, it is likely that interface functions or interface variables will not be used normally. But the general principle is that the information that should not be known to the outside world should not appear in the header file, but the information necessary for the outside world to call the interface function or interface variable in the module must appear in the header file, otherwise the outside world will not be able to call the interface function we provided correctly. Therefore, in order for an external function or file to call the interface function we provide, we must include the interface description file we provide-that is, the header file. At the same time, our own module also needs to include this module header file (because it contains the macro definition or structure required in the module source file), just like all the files we usually use are in triplicate, the module itself needs to include this header file. Let's define this header file. Generally speaking, the name of the header file should be consistent with the name of the source file, so that we can clearly know which header file is the description of which source file. So we got the header file LCD. H. C, which reads as follows. # IFN def _ LCD _ H _ # define _ LCD _ H _ extern LcdPutChar(char cNewValue); #endif This is similar to defining a function in the source file. The difference is that the extern modifier is added in front of it, indicating that it is an external function and can be called by other external modules. # ifndef _ LCD _ h _ # define _ LCD _ h _ # endif These conditional compilation and macro definitions are to prevent repeated inclusion. If there are two different source files that need to call the LcdPutChar(char cNewValue) function, they both contain header files through # include "LCD.h". When compiling the first source file, since _LCD_H_ has not been defined, the conditions of #ifndef _LCD_H_ holds, so _LCD_H_ are defined, and the following statements are included. When compiling the second file, _LCD_H_ has been defined, because the first file contains time. Therefore #ifndef _LCD_H_ does not hold, and does not include the entire header file content. Assuming that there is no such conditional compilation statement, then both files contain Extern LCD Putchar (CharCNEW value); It will cause the error of repeated inclusion. Typedef, I have to say this, many friends seem to be accustomed to using the following statements to define the data type # define uint unsigned int # define uchar unsigned char in the program and then directly use uint g _ ntime counter = 0; when defining variables; There is no denying that it is really convenient and easy to transplant. But considering the following situation, do you still think so? #define PINT unsigned INT * // Define unsigned int pointer types pint g _ nptimecounter, g _ nptimestate So did you define two pointer variables of unsigned int type, or a pointer variable and an integer variable? And what is your original intention? Do you want to define two pointer variables of unsigned int type? If so, it is estimated that it will soon be crazy and wrong. Fortunately, C language has taken this into account for us. Typedef was born for this purpose. In order to give a variable an alias, we can use the following statement typedef unsigned int16; //Give the unsigned integer an alias uint 16typedef unsigned int * puint16; //Give the pointer to the unsigned integer variable an alias puint 16, which can be defined when we define the variable: uint16g _ ntime counter = 0; //Define an unsigned integer variable puint16g _ nptimecounter; //Pointer defines an unsigned plastic variable. When we program with C language of 5 1 single chip microcomputer, the range of plastic variable is 16 bits, while the plastic variable under 32-base microprocessor is 32 bits. If you want to transplant some codes written by an 8-bit microcontroller to a 32-bit processor, it is very likely that you need to modify the type definitions of variables in the source file. This is an arduous task. In order to consider the portability of the program, we should form a good habit of defining variables with aliases from the beginning. For example, under the platform of 8-bit single chip microcomputer, there are the following variables defined: uint16g _ ntime counter = 0; If the platform of 32 single-chip microcomputer is transplanted, the expected range is still 16 bits. You can directly modify the definition of uint 16, that is, typedef unsigned short integer int unt16; That's all, you don't need to look around for modified source files. All commonly used data types are defined in this way, forming a header file, which is convenient for us to call directly in future programming. The file name of MacroAndConst.h is as follows: # ifndef _ macro _ and _ const _ h _ # define _ macro _ and _ const _ h _ typedef unsigned int16; Typedef unsigned integer unit; Typedef unsigned integer unit; Typedef unsigned intuint16; Typedef unsigned int word; Typedef unsigned int word; typedef int int 16; typedef int int 16; Typedef unsigned long integer uint32typedef unsigned long integer UINT32typedef unsigned long DWORDtypedef unsigned long dword typedef long int 32 typedef signed character INT8typedef signed character int8typedef unsigned character byte; Typedef unsigned character bytes; Typedef unsigned character uchartypedef unsigned character UINT8typedef unsigned character uint8typedef unsigned char BOOL#endif At this point, we seem to have a little idea about the division of labor between source files and header files and modular programming. Then let's strike while the iron is hot and reorganize the LED flicker function we wrote in the last chapter into modules for compilation. In the last chapter, we mainly completed the function that the LED driven by P0 port flashes at the frequency of 1Hz. In which a timer and an LED driver module are used. So we can simply divide the whole project into three modules, timer module and LED module. The file relationship corresponding to the main function is as follows: main.c Timer.c-? Timer.hLed.c -? The Led.h is here, and the third chapter is here.