For every single-chip enthusiast and engineering development designer, in the first lush years of the first contact with the microcontroller, there have been experiences of lighting the marquee. From seeing the rows of small lights, we were excited when we beat. As you get more experience, you will feel that this little light is a good thing, especially in an environment with limited debugging resources, sometimes it will help.
But for the vast majority of people, we will use the blocking delay implementation when we first make the lights blink, which looks like the following code:
Then, when we come into contact with the timer, we will find that it would be better to use a timed interrupt to handle it. For example, we can interrupt once for 500ms, let the light be on or off, and the rest of the time system can do a lot of things, the efficiency has improved a lot.
At this time, we will slowly realize that the first (blocking delay) method is inefficient, let the chip run hundreds of millimeters there, and do nothing. It is a great waste, especially at the high frequency of the chip. When there are many tasks, it is like digging a big hole on a flat and wide highway. It is easy to imagine an accident.
But the timer in a single-chip microcomputer is limited after all. If I need dozens or more timed interrupts, I will complete different processing actions every time, how to do it. In general, we will think of re-defining the staTIc variable in a timed interrupt function to continue timing, to the required time, to do different actions. This in turn will lead to a lot of different things in an interruption, will seize the main poll for more time, and sometimes even take the lead, and is not very logical thinking.
So is there a better way to achieve it? The answer is yes. Here's a look at a project I encountered in a project, a subtle design of non-blocking timing delay software (this design is mainly for bare-metal programs without operating system).
In the last article, there is an introduction to sysTIck. For example, if I want to set a 10ms interrupt, how can I achieve it?
It is also very simple, just call the SysTIck_Config function in the core_cm3.h file. When the system clock is 72MHZ, set it to SysTIck_Config(720000) as follows (it will be interrupted once after counting down 720,000). At this point, the SysTick_Handler interrupt function will enter once in 10ms;
How is the task timing software designed?
And look at its data structure first, this is where the exquisiteness is, here is a top-down introduction:
Its definition structure type is as follows:
Where Char_Field is a union, the design is as follows:
And its internal Timer_Bit is a structure that can be accessed bit by bit:
The purpose of this design of this consortium will be reflected in the code that follows.
The design of such a structure is completed.
Then we define a global variable, Timer_Struct gTimer;
And the macro in the header file is defined as follows:
In addition, in order to clear the latter program, define a status indication:
At this point, the preparations are complete. Now let's start to show our magic!
First, the 10ms timer interrupt handler function can be seen that bTemp10Msec will be set to 1 every 10ms, bTemp50Msec will be set every 50ms, bTemp100Msec will be set every 100ms, and bTemp1Sec will be set every 1s.
And what is the use of this?
At this point, we need to call a timing handler in the main polling while(1) as follows:
The beginning and end of this function are two sentences:
The clues of bSystemXXX (lower 4 bits) and bTempXXX (higher 4 bits) are neatly implemented, and the count value needs to be manually cleared after waiting for the timing to arrive. The zeroing work here uses the characteristics of the variables in the union sharing a starting storage space.
However, to ensure that the while (1) polling time is much less than 10ms, otherwise the timing delay will be inaccurate. In this way, in each poll, first bSystemXXX, then according to bTempXXX to determine whether the time arrives, and set the corresponding bSystemXXX, and all subsequent tasks can be delayed by bSystemXXX, when the last function exits , will also clear bTempXXX, ready for the next time after the arrival of the query judgment.
Having said that, let me give you an example of how to apply:
The above example four task processes,
In the main poll, you can do the following:
In this way, multiple tasks can be easily and clearly implemented, and different events can be handled in different time periods. (But note that there is no blocking delay in each task processing, and don't deal with too many things, so that the processing time is longer. It can be designed as a state machine to handle different tasks.)
Nantong Boxin Electronic Technology Co., Ltd. , https://www.ntbosen.com