This paper is participating in thePerformance optimization combat record”Topic essay activity

When writing code, especially for embedded code, the best way to optimize is to set the compiler’s optimization level. Or consider the scope of the variable when defining it, and then choose the appropriate data type according to the scope of the data. But this kind of optimization method operation is more fuzzy, there is no intuitive feeling. In order to make the code optimization have an intuitive feeling, today with the map file to optimize the code.

Let’s start with a simple example.

This is a very simple test code, is in the main program inside the LED light flashing, at the same time to the x variable 0.1 each time. Does this code need to be optimized? Don’t worry, first open the map file generated in the project to have a look.

The map file is in the List folder of the debug project directory. Use Notepad to open the file.

In the middle of the file, there is a part of the space occupied by each target file.

You can see that the float. O object file takes up a lot of space compared to other files. So where did this float.o file come from? If you see float, you can probably guess that this is a floating-point related file. Floating point arithmetic is used in only one place in the program.

Does this line of code take up that much space? So try replacing floating-point with an integer.

Expand x by 10 times, then increase by 1 each time, and re-open the map file after compiling the code.

You’ll notice that the float.o file in front of long.o has disappeared. You can see that the float.o file is the result of that single line of floating-point arithmetic in the code. Through the observation of map file, we can draw a conclusion that floating point operation takes up a lot of space in the microcontroller, so try to convert floating point operation into plastic operation. Otherwise, if the floating point operation of the calculation is relatively large, the space of the MCU will soon be occupied.

Then print out the value of the variable through the serial port.

View the printed value through the serial port assistant

The values printed by the serial port are also normal. Next, go to the map file.

In the map file you can see that there are several more files before and after the long.o file. And it takes up a lot of space.

So why is there a very large float.o file? This is because the printf function supports floating-point printing, and because there are floating-point numbers in the function, a float.o file is generated. Xprintffull_nomb. o is also generated when the printf function is called.

It can be seen that printf functions take up quite a lot of space, so avoid using printf functions in programs as much as possible. So what happens when you want to print data? You can print characters through the default output function of the serial port of the microcontroller, but there is a new problem, the serial port output is character format, and now to print integers, how to convert integers to character format? You can use custom functions to convert a number to a string and then print a string through the serial port.

Start by writing a function that converts integers to strings.

void int2str(int n, char *str)
{
    char buf[10] = "";
    int i = 0;
    int len = 0;
    int temp = n < 0 ? -n: n;  // Temp is the absolute value of n

    if (str == NULL)
    {
        return;
    }
    while(temp)
    {
        buf[i++] = (temp % 10) + '0';  // Store each bit of temp into buF
        temp = temp / 10;
    }

    len = n < 0 ? ++i: i;  // If n is negative, one more bit is needed to store the negative sign
    str[i] = 0;            // The terminator is 0
    while(1)
    {
        i--;
        if (buf[len-i- 1] = =0)
        {
            break;
        }
        str[i] = buf[len-i- 1];  // Copy the characters in the buf array to the string
    }
    if (i == 0 )
    {
        str[i] = The '-';          // If it is negative, add a negative sign}}Copy the code

Next, write the serial port related functions.

// Send a single character
void SendChar( unsigned char dat )
{
    while( ( UART1_SR & 0x80) = =0x00 );       // Send data register is empty
    UART1_DR = dat;
}
// Send a string
void SendString( unsigned char* s )
{
    while( 0 != *s )
    {
        SendChar( *s );
        s++;
    }
}
Copy the code

Let’s change the main function code.

void main( void )
{
    int  x = 10;
    char str[100] = {0};
        
    __asm( "sim" );                             // Disable interrupts
    SysClkInit();
    delay_init( 16 );
    LED_GPIO_Init();
    Uart1_IO_Init();
    Uart1_Init( 9600 );
    __asm( "rim" );                             // Enable interrupts

    while( 1 )
    {
        LED = ~LED;

        x += 1;    
        int2str(x,str);
        SendString(str);
        SendString("\r\n");
        delay_ms( 1000); }}Copy the code

The variable x is converted to a string through int2str, the string is printed out through SendString, and the carriage return newline character is printed after a call to SendString. The printing effect is as follows:

Now look at the size of the map file.

As you can see from the map file, the custom function can save a lot of space for printing than using the printf function directly. In this way, by observing the size of the target file in the map file, in the process of optimizing the program, we can intuitively see the specific gap between the optimized code and the code before optimization. This way in the process of debugging code will be confident, not like a headless chicken running around.