STM32中使用systick時鐘進行延時的中斷與非中斷兩種方法
阿新 • • 發佈:2018-12-27
一、第一種方法是進入核心中斷的方式
//以下程式是根據官方程式修改的 #include "systick.h" /* Private variables ---------------------------------------------------------*/ u32 TimingDelay; void Delay_ms(__IO uint32_t nTime) { if (SysTick_Config(SystemCoreClock / 1000)) { /* Capture error */ while (1); } TimingDelay = nTime; while(TimingDelay != 0); SysTick->CTRL = 0x00; //失能SysTick SysTick->VAL = 0x00; //當前值清零 } void Delay_us(__IO uint32_t nTime) { if (SysTick_Config(SystemCoreClock / 1000000)) { /* Capture error */ while (1); } TimingDelay = nTime; while(TimingDelay != 0); SysTick->CTRL = 0x00; SysTick->VAL = 0x00; }
void SysTick_Handler(void)
{
if (TimingDelay != 0x00)
{
TimingDelay--;
}
}
中斷函式位置在
注意:使用這種延時方式在普通情況下是可以的,但是一旦在其他中斷中呼叫此延時函式,便會使程式卡死,比如在按鍵外部中斷中進行按鍵消抖延時。
void EXTI0_IRQHandler(void)
{
Delay_ms(10);
if(K0 == 1)
{
LED1 = ~LED1;
}
EXTI_ClearITPendingBit(EXTI_Line0);
}
觸發中斷進入延時函式後會死在 while(TimingDelay != 0);
此核心中斷優先順序的設定在,比如將優先順序設定為0後可以搶佔使用,但是需注意呼叫延時函式的中斷的優先順序要小於systick所改的優先順序,經實驗是可行的。
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); //中斷優先順序設定 /* set Priority for Cortex-M0 System Interrupts */ //NVIC_SetPriority (SysTick_IRQn, 0); //將中斷優先順序改為0 SysTick->VAL = 0; /* Load the SysTick Counter Value */ SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ return (0); /* Function successful */ }
二、第二種方法是無需進入核心中斷的方式
這種方式利用設定Systick時鐘的重灌載值,然後重灌載值倒數完畢後會將SysTick->CTRL的位15置1,對該位進行判斷便可知道延時完畢否。這種延時方式無需進入 void SysTick_Handler(void) 中斷,在中斷中使用也不怕優先順序問題了,就不需要改核心檔案了。這種方式雖然看起來有點繁瑣,但是也不難理解。
#include "delay.h"
static u8 fac_us=0; //us延時倍乘數
static u16 fac_ms=0; //ms延時倍乘數
//初始化延遲函式
//SYSTICK的時鐘固定為AHB時鐘的1/8
//SYSCLK:系統時鐘頻率
void SysTick_Init(u8 SYSCLK)
{
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
fac_us=SYSCLK/8;
fac_ms=(u16)fac_us*1000;
}
//延時nus
//nus為要延時的us數.
void delay_us(u32 nus)
{
u32 temp;
SysTick->LOAD=nus*fac_us; //時間載入
SysTick->VAL=0x00; //清空計數器
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //開始倒數
do
{
temp=SysTick->CTRL;
}while((temp&0x01)&&!(temp&(1<<16))); //等待時間到達
SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //關閉計數器
SysTick->VAL =0X00; //清空計數器
}
//延時nms
//注意nms的範圍
//SysTick->LOAD為24位暫存器,所以,最大延時為:
//nms<=0xffffff*8*1000/SYSCLK
//SYSCLK單位為Hz,nms單位為ms
//對72M條件下,nms<=1864
void delay_ms(u16 nms)
{
u32 temp;
SysTick->LOAD=(u32)nms*fac_ms; //時間載入(SysTick->LOAD為24bit)
SysTick->VAL =0x00; //清空計數器
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //開始倒數
do
{
temp=SysTick->CTRL;
}while((temp&0x01)&&!(temp&(1<<16))); //等待時間到達
SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //關閉計數器
SysTick->VAL =0X00; //清空計數器
}
總結:兩種方法最好都能掌握,因為比如一些比賽中,核心檔案是上鎖修改不了的。另外中斷中其實最好不要使用延時的,但是有時候似乎迫不得已,儘量少用而且不能延時太長吧。