The time delay function is often used in the process of MCU programming, the most commonly used is microsecond delay delay_us () and millisecond level Delay_ms ().
1. General Delay method
This is relatively simple, let the single-chip microcomputer do some unimportant work to pass the time, often with the loop to achieve, but to do more accurate or to the next effort. The following code is searched on the Internet, the test delay is more accurate.
Coarse delay function, microseconds
void Delay_us (U16 time)
{
U16 I=0;
while (time--)
{
i=10; Define Yourself
while (i--);
}
}
Millisecond-delay
void Delay_ms (U16 time)
{
U16 I=0;
while (time--)
{
i=12000; Define Yourself
while (i--);
}
}
2.SysTick Timer delay
CM3 Core processor, the internal contains a SysTick timer, SysTick is a 24-bit countdown timer, when counted to 0 o'clock, will automatically reload the timing initial value from the reload register. As long as the enable bits in the Systick control and status register are not removed, it will never cease. SysTick in STM32 's reference manual is simple and detailed, please refer to the CORTEX-M3 authoritative guide.
There are two ways to achieve this:
A. Mode of interruption
As below, define the delay time Time_delay,systick_config () defines the break time period, decrements the Time_delay in the interrupt, thus realizes the delay.
volatile unsigned long time_delay; Delay time, note defined as global variable
Delay N_ms
void Delay_ms (volatile unsigned long NMS)
{
System clock interrupt for Systick crossover--1ms
if (Systick_config (systemfrequency/1000))
{
while (1);
}
time_delay=nms;//Read Timing Time
while (Time_delay);
systick->ctrl=0x00; Turn off counters
Systick->val =0x00; Empty counter
}
Delay NUS
void Delay_us (volatile unsigned long NUS)
{
System clock interrupt for Systick crossover--1us
if (Systick_config (systemfrequency/1000000))
{
while (1);
}
time_delay=nus;//Read Timing Time
while (Time_delay);
systick->ctrl=0x00; Turn off counters
Systick->val =0x00; Empty counter
}
Decrements the Time_delay in the interrupt. Implementation delay
void Systick_handler (void)
{
if (Time_delay)
time_delay--;
}
B. Non-disruptive mode
The main imitation of the atom of the "STM32 Incomplete handbook". The clock of the SYSTICK is fixed at 1/8 of the HCLK clock, where we choose the internal clock source 72M, so the SYSTICK clock is 9M, that is, the SYSTICK timer decreases at 9M frequency. The SysTick consists of 4 registers, including CTRL, LOAD, VAL, calib, etc.
Systick->ctrl
Bit segment |
Name |
Type |
Reset Value |
Describe |
16 |
Countflag |
R |
0 |
If the Systick is 0 after the last reading of the register, the bit is 1, and if the bit is automatically zeroed |
2 |
Clksource |
RW |
0 |
0: External clock source 1: Internal clock |
1 |
Tickint |
RW |
0 |
0: Reduced to 0 no action; 1: Reduced to 0 generates Systick exception request |
0 |
ENABLE |
RW |
0 |
Systick timer Enable bit |
Systick-> LOAD
Bit segment |
Name |
Type |
Reset Value |
Describe |
23:0 |
RELOAD |
RW |
0 |
Reduced to 0 o'clock reload value |
Systick-> VAL
Bit segment |
Name |
Type |
Reset Value |
Describe |
23:0 |
Current |
RW |
0 |
Returns the current inverted count value on read, writes the zero, and clears the COUNTFLAG flag in the Systick control and status register |
Systick-> Calib is not commonly used, we can not use it here, it is not introduced.
The procedure is as follows, the equivalent of query method.
//Imitation atomic delay, do not enter systic interrupt
void Delay_us (u32 nus)
{
u32 temp;
systick->load = 9*nus;
systick->val=0x00;//Empty counter
systick->ctrl=0x01;//enable, minus Zero is no action, take external clock source
do
{
temp=systick->ctrl;//reads the current inverted count value
}while (temp&0x01) && (! ( temp& (1<<16)));//wait time arrives
SysTick->CTRL=0x00;//Close counter
systick->val =0x00; Empty counter
}
void Delay_ms (U16 nms)
{
u32 temp;
systick->load = 9000*nms;
systick->val=0x00;//Empty counter
systick->ctrl=0x01;//enable, minus Zero is no action, take external clock source
do
{
temp=systick->ctrl;//reads the current inverted count value
}while ((temp&0x01) && (!) ( temp& (1<<16)));//wait time arrives
SysTick->CTRL=0x00;//Close counter
systick->val =0x00; Empty counter
}
Three ways have pros and cons, the first way is easy to understand, but not very precise. The second way to use the library function, writing simple, because of the existence of interrupts, not conducive to other interrupts call this delay function. The third way to directly operate the register, it looks more cumbersome, in fact, it is not difficult, at the same time overcome the shortcomings of the above two ways, personal feeling more useful.