However, when we first get started, how can we make these small lights run happily according to our ideas? Most children's approach is to add a delay program in a while loop, let the small lights stay in each state for a period of time, and then enter the next state. In this way, the small lights will switch between different states and flash according to the program we designed.
This involves the issue of writing a delay program, and the general approach is to subtract a large number in a for loop until it reaches 0, then the delay is completed. The value of that number is estimated based on the clock frequency and the instruction running cycle. I still remember reading a post a long time ago that introduced several methods of precise delay for 51 microcontrollers. One method is to set the clock frequency in keil, and then calculate the delay time through software simulation to achieve more precise timing.
However, these methods are generally not convenient enough, and the delay is not accurate enough. A more advanced method is to start a timer and count in the timer interrupt to achieve the purpose of accurate delay.
In the application of STM32, you can consider using the SysTick system tick timer to implement it. However, there is little introduction to it in the STM32 development manual, almost to the point of non-existence. Because it is part of the Cortex core, CM3 has specially opened an exception type for it, and it has a place in the interrupt vector table (exception number 15), so that it can be easily ported to chips with CM3 cores from different manufacturers, and for software with real-time operating systems, it is generally used as the time base of the entire system, which is very important for the operating system. For a detailed introduction to SysTick, please refer to Chapter 8 on page 133 and Chapter 13 on page 179 of the "Cortex-M3 Authoritative Guide".
SysTick has a total of four registers:
1,
Corresponds to SysTick->CTRL in the software;
2,
Corresponds to SysTick-> LOAD in the software;
3.
Corresponds to SysTick->VAL in the software;
4.
Corresponding to SysTick-> CALIB () in the software, it has not been used and is not often used, so it will not be introduced for now.
The offsets of these registers are shown in the following figure:
The definition of the register structure is in CMSISCM3CoreSupport core_cm3.h, as follows
/** @addtogroup CMSIS_CM3_SysTick CMSIS CM3 SysTick memory mapped structure for SysTick @{ */ typedef struct { __IO uint32_t CTRL; /*!< Offset: 0x00 SysTick Control and Status Register */ __IO uint32_t LOAD; /*!< Offset: 0x04 SysTick Reload Value Register */ __IO uint32_t VAL; /*!< Offset: 0x08 SysTick Current Value Register */ __I uint32_t CALIB; /*!< Offset: 0x0C SysTick Calibration Register */ } SysTick_Type;
SysTick is a 24-bit timer, which means it can count up to 224 clock pulses at a time. This pulse count value is saved in the SysTick->VAL current count value register. It can only count down. Each time a clock pulse is received, the value of SysTick->VAL is reduced by 1 until it reaches 0. Then the hardware automatically reloads the value in the reload register SysTick->LOAD to SysTick->VAL and recounts. When the SysTick->VAL value counts to 0, an exception is triggered and the void SysTick_Handler(void) function is called. The timer interrupt event can be processed in this interrupt service function, which is generally a count-down operation for the set value. As long as the 0th enable bit in the SysTick control and status register SysTick->CTRL is not cleared, it will never stop.
The SysTick interrupt priority issue needs to be emphasized here.
It is a system exception, a kernel-level interrupt, and the priority can be set. The specific settings are also in core_cm3.h
/** * @brief Initialize and start the SysTick counter and its interrupt. * * @param ticks number of ticks between two interrupts * @return 1 = failed, 0 = successful * * Initialize the system tick timer and its interrupt and start the * system tick timer / counter in free running mode to generate * periodical interrupts. */ static __INLINE uint32_t SysTick_Config(uint32_t ticks) { if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */ SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; /* set reload register */ NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); SysTick->VAL = 0; SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk; return (0); /* Function successful */ }
The following sentence is the function for setting the priority. This function sets both the kernel interrupt priority and the external interrupt priority. It is quite powerful, but it is not convenient to calculate the preemption and slave priorities manually. When jumping into this function, we can calculate that Systick has the lowest default priority (the effect is equivalent to SCB->SHP[11] = 0xF0;)
NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
At this time, if other external interrupt priorities are set higher than it, it can be deprived and turned to external interrupt.
The following experiments can be performed to verify:
First set an event interrupt and set the priority higher.
void Exti_Config(void) { EXTI_InitTypeDef EXTI_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; EXTI_InitStructure.EXTI_Line = EXTI_Line1; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Event; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(& EXTI_InitStructure); NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); }
Note: In my experiment, the interrupt grouping was initially initialized as follows:
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
Set as the second group.
exist
void SysTick_Handler(void) { EXTI_GenerateSWInterrupt(EXTI_SWIER_SWIER1); LED_1 = ON; Delay(); }
The system tick interrupt triggers an external interrupt event and lights up LED1.
The external interrupt processing function is as follows
void EXTI1_IRQHandler(void) { if (EXTI_GetITStatus(EXTI_Line1) != RESET) { EXTI_ClearITPendingBit(EXTI_Line1); LED_0 = ON; Delay(); } }
This delay function is a blocking delay as follows:
void Delay(void) { u32 i; for(i=0 ; i < 0xFFFFF; i++){} }
The delay is added to see which light turns on first.
When the external interrupt priority is higher, it can preempt the Systick interrupt and execute first. The experimental result of the above code is that LED0 lights up first, and then returns to LED1 to light up.
When the external interrupt is set to the same priority as the systick, the systick priority will be relatively high. For example, change the above priority to
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
Then LED1 will light up first, and EXTI1_IRQHandler will execute only after the SysTick_Handle function is executed.
Personally, I think that if you want to achieve accurate systick delay, it is best to set the systick priority higher, for example
NVIC_SetPriority (SysTick_IRQn, 0);
That is, by setting SCB->SHP[11] = 0x00; the systick priority can be higher than any external interrupt, and the delay will be more accurate.
In addition, for the selection of SysTick clock source, it should be noted that its clock source can be selected as internal clock (FCLK, free running clock on CM3, corresponding to AHB in STM32), or external clock (STCLK signal on CM3 processor, corresponding to AHB/8 in STM32)
Please refer to the following figure
It is set in the SysTick->CTRL second bit CLKSOURCE clock source selection.
For the writing of systick delay function, please refer to Wildfire's "Zero Dead Angle Play STM32-Beginner's Edition".
At this point we can simply implement a first-class water lamp program
while(1) { LED_0 =OFF; LED_1 = ON; Delay_ms(500); LED_0 =OFF; LED_1 = ON; Delay_ms(500); }
However, is this really a good idea? Blocking delay is used here, and a large part of the CPU efficiency is consumed in idling, which is a waste of resources.
Assuming that the system clock frequency is 72MHZ or tens or hundreds of MHZ, when it only takes tens or tens of nanoseconds or even shorter to complete a cycle, and there is a blocking delay of tens to hundreds of milliseconds in this cycle, it is like a bumpy muddy road suddenly appearing across the highway. You can imagine that the entire road will slow down, and even catastrophic consequences may occur. Personally, I think that during the system initialization process, the timing of each chip has time requirements, and blocking delay can be used. It only needs to be run when the system starts. After the system is running, it is best not to do this stupidly.
At this time, the main method is to count in the timer, query the variable in the external loop, and execute a certain action when a certain value is reached to achieve the delay effect. Before the time is up, the system can keep running in circles and do other things.
gticks counts once every millisecond in the timer interrupt
while(1) { if(500 == gticks) { LED_0 =OFF; LED_1 = ON; } if(1000 == gticks) { LED_0 =OFF; LED_1 = ON; gticks = 0 } Do_others(); }
The above requires processing gticks during event processing, which increases the coupling of the code and is more prone to errors. If gticks are cleared in one event processing and need to be queried in the next event, this may cause processing timing disorder and mutual interference.
Is it possible to only provide query function in event processing, and leave the scheduling work to the scheduler itself?
In the next section, an expert will appear and introduce to you an ingenious design of non-blocking delay that I learned in a project.
Previous article:STM32 study notes 1 clock and timer
Next article:SysTick system clock tick experiment (introduction to stm32 interrupts)
- Popular Resources
- Popular amplifiers
- Learn ARM development(16)
- Learn ARM development(17)
- Learn ARM development(18)
- Embedded system debugging simulation tool
- A small question that has been bothering me recently has finally been solved~~
- Learn ARM development (1)
- Learn ARM development (2)
- Learn ARM development (4)
- Learn ARM development (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- CGD and Qorvo to jointly revolutionize motor control solutions
- CGD and Qorvo to jointly revolutionize motor control solutions
- Keysight Technologies FieldFox handheld analyzer with VDI spread spectrum module to achieve millimeter wave analysis function
- Infineon's PASCO2V15 XENSIV PAS CO2 5V Sensor Now Available at Mouser for Accurate CO2 Level Measurement
- Advanced gameplay, Harting takes your PCB board connection to a new level!
- Advanced gameplay, Harting takes your PCB board connection to a new level!
- A new chapter in Great Wall Motors R&D: solid-state battery technology leads the future
- Naxin Micro provides full-scenario GaN driver IC solutions
- Interpreting Huawei’s new solid-state battery patent, will it challenge CATL in 2030?
- Are pure electric/plug-in hybrid vehicles going crazy? A Chinese company has launched the world's first -40℃ dischargeable hybrid battery that is not afraid of cold
- Where are PCB professionals heading?
- Ubuntu development environment installation (I) system installation
- Implementation strategies for Industrial IoT networks
- The long-lasting coronavirus
- XXXXX Teardown
- Working principle and application of module power supply
- RF/Wireless Popular Data Download Collection
- How to implement wireless video transmission
- [Me and Atria 3] at32-littlevgl uses gui-guider designer to make a mini-hmi display
- Come if you dare! Enter the top-secret black technology laboratory of Tektronix!