Use macro definition
In C, macros are the only way to generate embedded code. For embedded systems, macros are a good method to replace functions to meet performance requirements.
Write a "standard" macro min, which inputs two parameters and returns a smaller one:
Incorrect practice:
# Define min (a, B) (a <= B? A: B) |
Correct practice:
# Define min (A, B) (a) <= (B )? (A): (B )) |
For macros, we need to know three points:
(1) macro definition of "image" functions;
(2) macro definition is not a function, so it must include all "Parameters ";
(3) macro definitions may produce side effects.
The following code:
Least = min (* P ++, B ); |
Will be replaced:
(* P ++) <= (B )? (* P ++) (B )) |
Unexpected events.
Therefore, do not input "Parameters" with side effects to the macro definition ".
Use register variables
When a variable is frequently read/written, the memory needs to be accessed repeatedly, which takes a lot of access time. Therefore, the C language provides a variable, register variable. These variables are stored in the CPU registers. When used, they do not need to access the memory, but are directly read and written from the registers to improve efficiency. The register variable description is register. Variable control variables with a large number of loops and variables used repeatedly in the loop body can be defined as register variables, and cyclic count is the best candidate for applying register variables.
(1) only local automatic variables and parameters can be defined as register variables. Because register variables are dynamically stored, the amount of data that requires static storage cannot be defined as register variables, including: Inter-module global variables, intra-module global variables, and local static variables;
(2) register is a "recommended" keyword, meaning that the program recommends that the variable be placed in the register, but the variable may not become a register variable because the condition is not met, it is stored in the memory, but the compiler does not report an error (there is another "suggested" keyword in C ++: inline ).
The following is an example of using register variables:
/* Calculate 1 + 2 + 3 + .... + N value */ Word addition (byte n) { Register I, S = 0; For (I = 1; I <= N; I ++) { S = S + I; } Return S; } |
This program loops n times, I and S are frequently used, so it can be defined as a register variable.
Embedded Assembly
The time-demanding part of the program can be rewritten using Embedded Assembly to significantly increase the speed. However, developing and testing assembly code is a hard task, which takes a longer time. Therefore, you must carefully choose the part to be compiled.
In the program, there is a 80-20 principle, that is, 20% of the program consumes 80% of the running time, so we need to improve the efficiency, the most important is to consider improving that 20% of the Code.
Embedded C programs mainly use online Assembly, that is, directly inserting _ ASM {} Embedded Assembly statements in C Programs:
/* Add the values of two input parameters and store the results in another global variable */ Int result; Void add (long a, long * B) { _ ASM { MoV ax, MoV BX, B Add ax, [BX] MoV result, ax } } |
Utilize hardware features
First of all, you must understand the access speed of the CPU to various types of memory, basically as follows:
CPU internal RAM> external synchronization Ram> external asynchronous Ram> flash/ROM
The program code has been burned in flash or ROM. We can allow the CPU to directly read and execute the code from it, but this is usually not a good solution, we 'd better copy the target code in flash or ROM into RAM after the system is started, and then execute the code to speed up instruction obtaining;
For uart and other devices, there is a certain internal capacity of the receiving buffer. We should try to interrupt the CPU after the buffer is full. For example, when the computer terminal transmits data to the target machine through the RS-232, it is not suitable to set UART to receive only one byte to raise the interrupt to the CPU, thus unnecessary waste of interrupt processing time;
If a device can be read in DMA mode, it will adopt DMA reading. The DMA reading method is more efficient in reading the storage information contained in the target. The basic unit of data transmission is block, the transmitted data is directly sent from the device to the memory (or vice versa ). Compared with the interrupt driver, the DMA mode reduces CPU intervention on peripherals and further improves parallel operations between the CPU and peripherals.
Bitwise operation
The bitwise operation in C language can reduce the division and modulo operation. The bit of data in a computer program is the smallest unit of data that can be operated. In theory, you can use the bit operation to complete all operations. Therefore, flexible bit operations can effectively improve the program running efficiency. Example:
/* Method 1 */ Int I, J; I = 879/16; J = 562% 32; /* Method 2 */ Int I, J; I = 879> 4; J = 562-(562> 5 <5 ); |
For mathematical operations that take the exponent level of 2 as "*", "/", or "%", conversion to shift operations "<>" can generally improve the algorithm efficiency. Because the period of multiplication and division operations is usually larger than that of shift operations.
In addition to improving the computing efficiency, the C language bit operation is another typical application in embedded system programming, in addition, it is widely used in scenarios such as bitwise AND (&), or (|), non (~) Operation, which is closely related to the programming features of embedded systems. We usually need to set the bit of the hardware register. For example, we set the low 6 bits of the interrupt Shield Control Register of the am186er 80186 processor to 0 (on interrupt 2 ), the most common practice is:
# Define int_i2_mask 0x0040 Wtemp = inword (int_mask ); Outword (int_mask, wtemp &~ Int_i2_mask ); |
The method to set this bit to 1 is:
# Define int_i2_mask 0x0040 Wtemp = inword (int_mask ); Outword (int_mask, wtemp | int_i2_mask ); |
To determine whether the bit is 1 is:
# Define int_i2_mask 0x0040 Wtemp = inword (int_mask ); If (wtemp & int_i2_mask) { ... /* This bit is 1 */ } |
The above methods are very common in embedded system programming, and we need to master them firmly.
Summary
In terms of performance optimization, always pay attention to the 80-20 preparation. Do not optimize the program to sell less than that of 80%, which is laborious.
Macro definition is a good way to implement similar function functions in C language without function call and return overhead. However, macro is not a function in essence, so it is necessary to prevent unexpected results after macro development, be cautious in defining and using macros. Unfortunately, the standard C does not include the inline function in C ++ so far. The inline function has the advantages of no call overhead and security.
Using register variables, embedded assembly, and bitwise operations is also an effective way to improve program efficiency.
In addition to programming skills, in order to improve the operating efficiency of the system, we usually need to take advantage of the features of various hardware devices to minimize their operation overhead, for example, reducing the number of interruptions and using DMA transmission.