/*************delay.h*************************/
#ifndef __DELAY_H
#define __DELAY_H
#include
//////////////////////////////////////////////////////////////////////////////////
//ALIENTEK STM32 development board
//Use SysTick's normal counting mode to manage delays
//Including delay_us, delay_ms
//Atom on point @ALIENTEK
//Technical forum: www.openedv.com
//Modification date: 2012/9/2
//Version: V1.5
//All rights reserved. Piracy will be prosecuted.
//Copyright(C) Guangzhou Xingyi Electronic Technology Co., Ltd. 2009-2019
//All rights reserved
//********************************************************************************
//V1.2 modification instructions
//Fixed the error of calling an infinite loop during an interrupt
//To prevent inaccurate delay, use do while structure!
//V1.3 modification instructions
//Added support for UCOSII delay.
//If you use ucosII, delay_init will automatically set the value of SYSTICK to correspond to TICKS_PER_SEC of ucos.
//delay_ms and delay_us have also been modified for ucos.
//delay_us can be used under ucos, and it is very accurate, and more importantly, it does not occupy additional timers.
//delay_ms can be used as OSTimeDly under ucos. When ucos is not started, it is implemented using delay_us to accurately delay
//Can be used to initialize peripherals. After starting ucos, delay_ms selects OSTimeDly implementation or delay_us implementation according to the length of the delay.
//V1.4 modification instructions 20110929
//Fixed the bug that the interrupt in delay_ms cannot respond when ucos is used but not started.
//V1.5 modification instructions 20120902
//Add ucos lock to delay_us to prevent inaccurate delay caused by ucos interrupting the execution of delay_us.
//////////////////////////////////////////////////////////////////////////////////
void delay_init(u8 SYSCLK);
void delay_ms(u16 nms);
void delay_us(u32 nus);
#endif
/*************delay.c******************/
#include "delay.h"
#include "sys.h"
//////////////////////////////////////////////////////////////////////////////////
//If you use ucos, just include the following header file.
#if SYSTEM_SUPPORT_UCOS
#include "includes.h" //ucos 使用
#endif
//////////////////////////////////////////////////////////////////////////////////
//This program is for learning purposes only and may not be used for any other purpose without the author's permission.
//ALIENTEK STM32 development board
//Use SysTick's normal counting mode to manage delays
//Including delay_us, delay_ms
//Atom on point @ALIENTEK
//Technical forum: www.openedv.com
//Modification date: 2012/9/2
//Version: V1.5
//All rights reserved. Piracy will be prosecuted.
//Copyright(C) Guangzhou Xingyi Electronic Technology Co., Ltd. 2009-2019
//All rights reserved
//********************************************************************************
//V1.2 modification instructions
//Fixed the error of calling an infinite loop during an interrupt
//To prevent inaccurate delay, use do while structure!
//V1.3 modification instructions
//Added support for UCOSII delay.
//If you use ucosII, delay_init will automatically set the value of SYSTICK to correspond to TICKS_PER_SEC of ucos.
//delay_ms and delay_us have also been modified for ucos.
//delay_us can be used under ucos, and it is very accurate, and more importantly, it does not occupy additional timers.
//delay_ms can be used as OSTimeDly under ucos. When ucos is not started, it is implemented using delay_us to accurately delay
//Can be used to initialize peripherals. After starting ucos, delay_ms selects OSTimeDly implementation or delay_us implementation according to the length of the delay.
//V1.4 modification instructions 20110929
//Fixed the bug that the interrupt in delay_ms cannot respond when ucos is used but not started.
//V1.5 modification instructions 20120902
//Add ucos lock to delay_us to prevent inaccurate delay caused by ucos interrupting the execution of delay_us.
//////////////////////////////////////////////////////////////////////////////////
static u8 fac_us=0; //us delay multiplier
static u16 fac_ms=0; //ms delay multiplier, under ucos, represents the number of ms per beat
#ifdef OS_CRITICAL_METHOD //If OS_CRITICAL_METHOD is defined, it means ucosII is used.
//systick interrupt service function, used when using ucos
void SysTick_Handler(void)
{
OSIntEnter(); //Enter interrupt
OSTimeTick(); //Call the ucos clock service program
OSIntExit(); //Trigger task switching soft interrupt
}
#endif
// Initialize delay function
//When using ucos, this function will initialize the clock beat of ucos
//SYSTICK clock is fixed to 1/8 of HCLK clock
//SYSCLK: system clock
void delay_init(u8 SYSCLK)
{
#ifdef OS_CRITICAL_METHOD //If OS_CRITICAL_METHOD is defined, it means ucosII is used.
u32 reload;
#endif
SysTick->CTRL&=~(1<<2); //SYSTICK uses external clock source
fac_us=SYSCLK/8; //Whether or not to use ucos, fac_us needs to be used
#ifdef OS_CRITICAL_METHOD //If OS_CRITICAL_METHOD is defined, it means ucosII is used.
reload=SYSCLK/8; //The number of counts per second is in K
reload*=1000000/OS_TICKS_PER_SEC; //Set overflow time according to OS_TICKS_PER_SEC
//reload is a 24-bit register, with a maximum value of 16777216. At 72M, it takes about 1.86 seconds
fac_ms=1000/OS_TICKS_PER_SEC; // represents the minimum unit that ucos can delay
SysTick->CTRL|=1<<1; //Enable SYSTICK interrupt
SysTick->LOAD=reload; //Interrupt every 1/OS_TICKS_PER_SEC seconds
SysTick->CTRL|=1<<0; //Turn on SYSTICK
#else
fac_ms=(u16)fac_us*1000; //Under non-ucos, represents the number of systick clocks required for each ms
#endif
}
#ifdef OS_CRITICAL_METHOD //If OS_CRITICAL_METHOD is defined, it means ucosII is used.
//Delay nus
//nus is the number of us to be delayed.
void delay_us(u32 nus)
{
u32 ticks;
u32 told,tnow,tcnt=0;
u32 reload=SysTick->LOAD; //LOAD value
ticks=nus*fac_us; //The number of beats required
tcnt=0;
OSSchedLock(); //Prevent ucos scheduling to prevent interruption of us delay
told=SysTick->VAL; //Counter value when entering
while(1)
{
tnow=SysTick->VAL;
if(tnow!=told)
{
if(tnow else tcnt+=reload-tnow+told; told=tnow; if(tcnt>=ticks)break;//If the time exceeds/equals the delay time, exit. } }; OSSchedUnlock(); // Enable ucos scheduling } //Delay nms //nms: the number of ms to delay void delay_ms(u16 nms) { if(OSRunning==TRUE) //If os is already running { if(nms>=fac_ms)//The delay time is greater than the minimum time period of ucos { OSTimeDly(nms/fac_ms); //ucos delay } nms%=fac_ms; //ucos can no longer provide such a small delay, so use the normal delay method } delay_us((u32)(nms*1000));//Normal delay } #else//When not using ucos //Delay nus //nus is the number of us to be delayed. void delay_us(u32 nus) { u32 temp; SysTick->LOAD=nus*fac_us; //Time loading SysTick->VAL=0x00; //Clear the counter SysTick->CTRL=0x01; //Start countdown do { temp=SysTick->CTRL; } while((temp&0x01)&&!(temp&(1<<16)));//Wait for time to arrive SysTick->CTRL=0x00; //Turn off the counter SysTick->VAL =0X00; //Clear the counter } //Delay nms //Note the range of nms //SysTick->LOAD is a 24-bit register, so the maximum delay is: //nms<=0xffffff*8*1000/SYSCLK //SYSCLK is in Hz, nms is in ms //Under 72M conditions, nms<=1864 void delay_ms(u16 nms) { u32 temp; SysTick->LOAD=(u32)nms*fac_ms; //Time loading (SysTick->LOAD is 24bit) SysTick->VAL =0x00; //Clear the counter SysTick->CTRL=0x01; //Start countdown do { temp=SysTick->CTRL; } while((temp&0x01)&&!(temp&(1<<16)));//Wait for time to arrive SysTick->CTRL=0x00; //Turn off the counter SysTick->VAL =0X00; //Clear the counter } #endif /*********************Main program test.c**************/ #include "sys.h" #include "usart.h" #include "delay.h" #include "led.h" #include "includes.h" //ALIENTEK Battleship STM32 Development Board Experiment 53 //UCOSII Experiment 1-Task Scheduling //Technical support: www.openedv.com //Guangzhou Xingyi Electronic Technology Co., Ltd. //////////////////////////UCOSII task settings//////////////////////////////////// //START task //Set task priority #define START_TASK_PRIO 10 //Set the priority of the start task to the lowest //Set the task stack size #define START_STK_SIZE 64 //Task stack OS_STK START_TASK_STK[START_STK_SIZE]; //Task function void start_task(void *pdata); //LED0 task //Set task priority #define LED0_TASK_PRIO 7 //Set the task stack size #define LED0_STK_SIZE 64 //Task stack OS_STK LED0_TASK_STK[LED0_STK_SIZE]; //Task function void led0_task(void *pdata); //LED1 task //Set task priority #define LED1_TASK_PRIO 6 //Set the task stack size #define LED1_STK_SIZE 64 //Task stack OS_STK LED1_TASK_STK[LED1_STK_SIZE]; //Task function void led1_task(void *pdata); int main(void) { Stm32_Clock_Init(9); //System clock settings delay_init(72); //delay initialization LED_Heat(); LED_Init(); //Initialize the hardware interface connected to the LED OSInit(); OSTaskCreate(start_task,(void *)0,(OS_STK *)&START_TASK_STK[START_STK_SIZE-1],START_TASK_PRIO );//Create a start task OSStart(); } //Start the task void start_task(void *pdata) { OS_CPU_SR cpu_sr=0; pdata = pdata; OS_ENTER_CRITICAL(); //Enter the critical section (cannot be interrupted) OSTaskCreate(led0_task,(void *)0,(OS_STK*)&LED0_TASK_STK[LED0_STK_SIZE-1],LED0_TASK_PRIO); OSTaskCreate(led1_task,(void *)0,(OS_STK*)&LED1_TASK_STK[LED1_STK_SIZE-1],LED1_TASK_PRIO); OSTaskSuspend(START_TASK_PRIO); //Suspend the start task. OS_EXIT_CRITICAL(); //Exit the critical section (can be interrupted) } //LED0 task void led0_task(void *pdata) { while(1) { LED0=0; delay_ms(50); LED0=1; delay_ms(50); }; } //LED1 task void led1_task(void *pdata) { while(1) { LED1=0; delay_ms(300); LED1=1; delay_ms(300); }; } /*********Related explanations*************/ Chapter 5 Introduction to the SYSTEM Folder In the previous chapter, we introduced how to create an STM32 project under MDK3.80A. In this newly created project, we We used the code in a SYSTEM folder, which is provided by ALIENTEK. The underlying core driver functions of the STM32F103 series can be used on various models of the STM32F103 series, making it easy for everyone to quickly build their own projects. The SYSTEM folder contains three folders, namely delay, sys, and usart. They contain delay.c, sys.c, usart.c and their header files respectively. With these three c files, you can quickly build the most basic framework for any STM32. It is very convenient to use. In this chapter, we will introduce these codes to you. Through the study of this chapter, you will understand the origin of these codes and I hope you can flexibly use the functions provided in the SYSTEM folder to quickly build projects and apply them to your own projects. This chapter includes the following three summaries: 5.1, delay folder code introduction; 5.2, sys folder code introduction; 5.3, usart folder code introduction; 5.1 Delay folder code introduction The delay folder contains two files, delay.c and delay.h, which are used to implement the delay function of the system. They contain three functions (we will not talk about the SysTick_Handler function here, which will be introduced when we talk about ucos): void delay_init(u8 SYSCLK); void delay_ms(u16 nms); void delay_us(u32 nus); The following are the three functions. Before that, let's first understand the programming concept: the CM3 core processor, It contains a SysTick timer, which is a 24-bit countdown timer. When it reaches 0, it will automatically reload the initial value of the timer from the RELOAD register. As long as the enable bit in the SysTick control and status register is not cleared, it will never stop. SysTick is introduced very simply in the "STM32 Reference Manual" (here refers to the V10.0 version, the same below). For a detailed introduction, please refer to page 133 of the "Cortex-M3 Authoritative Guide". We use the internal SysTick of STM32 to achieve delay, which does not occupy interrupts or system timers. Here we will introduce the latest version of the delay function provided by ALIENTEK, which supports It is used under ucos, and it can share the systick timer with ucos. First, let's briefly introduce the clock of ucos: ucos needs a system clock beat (similar to "heartbeat") to run, and this beat is fixed (set by OS_TICKS_PER_SEC), such as 5ms (set: OS_TICKS_PER_SEC=200). Under STM32, systick is generally used to provide this beat, that is, systick should be set to interrupt once every 5ms to provide clock beats for ucos, and this clock generally cannot be interrupted (otherwise it will be inaccurate). Because systick can no longer be changed at will under ucos, if we still want to use systick to make delay_us or delay_ms, we must think of a way. Here we use the clock extraction method. Take delay_us as an example, such as delay_us (50), when just entering delay_us, we first calculate the number of systick counts required to wait for this delay, which is 50*9 here (assuming that the system clock is 72Mhz, then every increase of systick is 1/9us), and then we keep counting the change of systick count until this value changes by 50*9. Once the change is detected to reach or exceed this value, it means that the delay time of 50us has expired. Let's start introducing these functions. ALIENTEK Battleship STM32 Development Board www.openedv.com 79 5.1.1 delay_init function This function is used to initialize two important parameters: fac_us and fac_ms; at the same time, select the SysTick clock source as the external clock. If ucos is used, the SysTick interrupt time will be configured according to the configuration of OS_TICKS_PER_SEC, and the SysTick interrupt will be enabled. The specific code is as follows: // Initialize delay function //When using ucos, this function will initialize the clock beat of ucos //SYSTICK clock is fixed to 1/8 of HCLK clock //SYSCLK: system clock void delay_init(u8 SYSCLK) { #ifdef OS_CRITICAL_METHOD //If OS_CRITICAL_METHOD is defined, ucosII is used. u32 reload; #endif SysTick->CTRL&=~(1<<2); //SYSTICK uses external clock source fac_us=SYSCLK/8; //Whether or not to use ucos, fac_us needs to be used #ifdef OS_CRITICAL_METHOD //If OS_CRITICAL_METHOD is defined, ucosII is used. reload=SYSCLK/8; //Number of counts per second (unit: K) reload*=1000000/OS_TICKS_PER_SEC; //Set overflow time according to OS_TICKS_PER_SEC //reload is a 24-bit register, with a maximum value of 16777216. Under 72M, it takes about 1.86 seconds fac_ms=1000/OS_TICKS_PER_SEC; // represents the minimum unit that ucos can delay SysTick->CTRL|=1<<1; // Enable SYSTICK interrupt SysTick->LOAD=reload; //Interrupt every 1/OS_TICKS_PER_SEC seconds SysTick->CTRL|=1<<0; //Turn on SYSTICK #else fac_ms=(u16)fac_us*1000; //Under non-ucos, represents the number of systick clocks required for each ms #endif } It can be seen that the delay_init function uses conditional compilation to select different initialization processes. When ucos is not used, it is the same as the method described in the "Incomplete Manual". If ucos is used, some different configurations will be performed. The conditional compilation here is determined by the macro OS_CRITICAL_METHOD, because as long as ucos is used, the macro OS_CRITICAL_METHOD will be defined. SysTick-> CALIB is not commonly used, and we don't need it here, so we won't introduce it.
SysTick is a structure defined by MDK (in stm32f10x_map.h), which contains 4 registers such as CTRL, LOAD, VAL, and CALIB.
The definition of each bit of SysTick->CTRL is shown in Figure 5.1.1.1:
SysTick-> CTRL & = 0xfffffffb; This sentence selects the external clock for the SysTick clock. It should be noted here that the SysTick clock is derived from the 8-frequency division of HCLK. Assuming that our external crystal oscillator is 8M, and then multiplied to 72M, then the SysTick clock is 9Mhz, that is, every time the SysTick counter VAL decreases by 1, it means that 1/9us has passed.
When ucos is not used: fac_us is the base of the us delay, that is, the delay of 1us, the value that SysTick-> LOAD should set. fac_ms is the base of the ms delay, that is, the delay of 1ms, the value that SysTick-> LOAD should set. fac_us is an 8-bit integer data, and fac_ms is a 16-bit integer data. Systick's clock comes from the system clock divided by 8. Because of this, if the system clock is not a multiple of 8 (not divisible by 8), the delay function will be inaccurate. This is why we recommend that the external clock be 8M. You should pay special attention to this.
When using ucos, fac_us is still the base of the us delay, but this value will not be written to the SysTick->LOAD
register to achieve the delay, but is achieved through clock extraction (which will be introduced later). And fac_ms represents the minimum delay time that can be achieved by the delay function of ucos (such as OS_TICKS_PER_SEC=200, then fac_ms is 5ms).
5.1.2 delay_us function
This function is used to delay the specified us, and its parameter nus is the number of microseconds to be delayed. This function has two versions, one using ucos and the other not. We will introduce them separately here. First, when ucos is not used, the implementation function is as follows:
//Delay nus
//nus is the number of us to be delayed.
void delay_us(u32 nus)
{
ALIENTEK Battleship STM32 Development Board www.openedv.com
81
u32 temp;
SysTick->LOAD=nus*fac_us; //Time load
SysTick->VAL=0x00; //Clear counter
SysTick->CTRL=0x01 ; //Start countdown
do
{
temp=SysTick->CTRL;
}
while((temp&0x01)&&!(temp&(1<<16)));//Wait for time to arrive
SysTick->CTRL=0x00; //Turn off counter
SysTick->VAL =0X00; //Clear counter
}
With the above description of SysTick The description of the registers, this code is not difficult to understand. In fact, it is to convert the number of us to be delayed into the number of SysTick clocks, and then write it into the LOAD register. Then clear the content of the current register VAL, and then turn on the countdown
function. When the countdown ends, nus is delayed. Finally, turn off SysTick and clear the value of VAL. Implement a delay of nus, but here you must pay attention to the value of nus, which cannot be too large. It must ensure that nus<=(2^24)/fac_us, otherwise the delay time will be inaccurate. Here is a special note: temp&0x01, this sentence is used to determine whether the systick timer is still in the on state, which can prevent the dead loop caused by the accidental closure of systick.
Let's take a look at the implementation function of delay_us when using ucos:
//Delay nus
//nus is the number of us to be delayed.
void delay_us(u32 nus)
{
u32 ticks;
u32 told,tnow,tcnt=0;
u32 reload=SysTick->LOAD; //LOAD value
ticks=nus*fac_us; //Required number of beats
tcnt=0;
OSSchedLock(); //Prevent ucos scheduling to prevent interruption of us delay
told=SysTick->VAL; //Counter value when entering
while(1)
{
tnow=SysTick->VAL;
if(tnow!=told)
{
if(tnow
told=tnow;
if(tcnt>=ticks)break;//Time exceeds/equals the time to be delayed, then exit.
}
};
OSSchedUnlock(); //Open ucos scheduling
}
ALIENTEK Battleship STM32 Development Board www.openedv.com
82Here
is the clock extraction method we mentioned earlier. Ticks is the number of SysTick counts (that is, the delay time) that the delayed nus needs to wait for. Told is used to record the most recent SysTick->VAL value, and tnow is the current SysTick->VAL value. Through their comparison and accumulation, the SysTick count count is counted and the statistical value is stored in tcnt. Then, by comparing tcnt and ticks, it is determined whether the delay has arrived, so as to achieve the delay of nus without modifying SysTick, so that one SysTick can be shared with ucos.
The above OSSchedLock and OSSchedUnlock are two functions provided by ucos, which are used to schedule locking and unlocking. Here, in order to prevent ucos from interrupting the delay during delay_us, which may cause inaccurate delay, we use these two functions to achieve no interruption, thereby ensuring the delay accuracy! At the same time, the delay_us at this time can achieve a maximum delay of 2^32us, which is about 4294 seconds.
5.1.3 delay_ms function
This function is used to delay the specified ms, and its parameter nms is the number of microseconds to be delayed. This function also has two versions, one using ucos and the other not. Here we introduce them separately. First, when not using ucos, the implementation function is as follows:
//Delay nms
//Note the range of nms
//SysTick->LOAD is a 24-bit register, so the maximum delay is:
//nms<=0xffffff*8*1000/SYSCLK
//SYSCLK unit is Hz, nms unit is ms
//For 72M conditions, nms<=1864
void delay_ms(u16 nms)
{
u32 temp;
SysTick->LOAD=(u32)nms*fac_ms;//Time loading (SysTick->LOAD is 24bit)
SysTick->VAL =0x00; //Clear counter
SysTick->CTRL=0x01; //Start countdown
do
{
temp=SysTick->CTRL;
}
while((temp&0x01)&&!(temp&(1<<16)));//Wait for time to arrive
SysTick->CTRL=0x00; //Turn off counter
SysTick->VAL =0X00; //Clear counter
}
This part of the code is roughly the same as the delay_us (non-ucos version) in Section 5.1.2, but it should be noted that because LOAD is only a 24-bit register, the delay in ms cannot be too long. Otherwise, it exceeds the range of LOAD, and the high bits will be discarded, resulting in inaccurate delay. The maximum delay in ms can be calculated by the formula: nms<=0xffffff*8*1000/SYSCLK. The unit of SYSCLK is Hz, and the unit of nms is ms. If the clock is 72M, the maximum value of nms is 1864ms. If it exceeds this value, it is recommended to implement it by calling delay_ms multiple times, otherwise the delay will be inaccurate.
Let’s take a look at the implementation of delay_ms when using ucos:
//delay nms
//nms: the number of ms to delay
void delay_ms(u16 nms)
ALIENTEK Battleship STM32 Development Board www.openedv.com
83
{
if(OSRunning==TRUE)//If the os is already running
{
if(nms>=fac_ms)//The delay time is greater than the minimum time period of ucos
{
OSTimeDly(nms/fac_ms);//ucos delay
}
nms%=fac_ms;//ucos can no longer provide such a small delay, use the normal delay
}
delay_us((u32)(nms*1000)); //Normal delay
}
In this function, OSRunning is a sign that ucos is running, OSTimeDly is a function provided by ucos based on ucos The delay function of the clock beat, its parameter represents the number of clock beats of the delay (assuming OS_TICKS_PER_SEC=200,
then OSTimeDly(1) means a delay of 5ms).
When ucos is not running yet, our delay_ms is directly implemented by delay_us. Delay_us under ucos can achieve a very long delay without overflow! So feel free to use delay_us to implement delay_ms. However, since the task scheduling is locked during delay_us, it is still recommended not to use delay_us to delay for a long time, otherwise it will affect the performance of the entire system.
When ucos is running, our delay_ms function will first determine whether the delay duration is greater than or equal to 1 ucos clock beat (fac_ms). When it is greater than this value, we will implement it by calling the delay function of ucos (the task can be scheduled at this time). When it is less than 1 clock beat, directly call the delay_us function to implement it (the task cannot be scheduled at this time).
Previous article:STM32 system learning-SysTick (system timer)
Next article:In STM32, systick specific delay time calculation
- Popular Resources
- Popular amplifiers
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
- Huawei's Strategic Department Director Gai Gang: The cumulative installed base of open source Euler operating system exceeds 10 million sets
- Download from the Internet--ARM Getting Started Notes
- Learn ARM development(22)
- Learn ARM development(21)
- Learn ARM development(20)
- Learn ARM development(19)
- Learn ARM development(14)
- Learn ARM development(15)
- Analysis of the application of several common contact parts in high-voltage connectors of new energy vehicles
- Wiring harness durability test and contact voltage drop test method
- Help: I wrote a program using DS18B20 but I don’t know why it only displays 85 degrees Celsius. Please help me figure out what to do.
- How to flip and restore the PCB in Altium Designer 19 in 3D
- [STM32WB55 Review] 6# Use of STM32WB development board UART
- [New Year's Taste Competition] + New Year's Eve dinner + New Year's 7 days of fun, I wish you all a prosperous New Year, smooth sailing and a good start.
- Sell TI POS Kit Chip
- It is said that the new technologies and solutions that electronic engineers are looking for are all here!
- Online Upgrade Method of DSP Application Based on Serial Communication
- RISC-V MCU IDE MRS (MounRiver Studio) development: Set not to automatically compile before debugging
- Predictions for the development trend of the Internet of Things in 2021
- 【AT-START-F425 Review】 4. External interrupts and code analysis