在stm32調試過程中加入一個延時,有兩種方式:一種是純計數方式,另一種是使用系統計數器的方式。
現使用系統計數器産生中斷的方式實作,查閱STM32的程式設計手冊可知,STM32有一個24bit的系統計時器,并有STK_CTRL、STK_LOAD、STK_VAL、STK_CALIB寄存器供讀寫配置。
而CORTEX_M3有提供了一些函數可以供我們調用來控制這幾個寄存器。
在編寫延時函數時需要的庫函數:
/**
\brief System Tick Configuration
\details Initializes the System Timer and its interrupt, and starts the System Tick Timer.
Counter is in free running mode to generate periodic interrupts.
\param [in] ticks Number of ticks between two interrupts.
\return 0 Function succeeded.
\return 1 Function failed.
\note When the variable <b>__Vendor_SysTickConfig</b> is set to 1, then the
function <b>SysTick_Config</b> is not included. In this case, the file <b><i>device</i>.h</b>
must contain a vendor-specific implementation of this function.
*/
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
{
return (1UL); /* Reload value impossible */
}
SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */
NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
SysTick->VAL = 0UL; /* 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 (0UL); /* Function successful */
}
它将延時計數寫入LOAD寄存器,設定時鐘源為AHB并啟動計數器。
如果我們使用的系統時鐘為72MHz,那麼如果ticks的值設定為72,000,000,則完成一個計數周期為1s,那麼如果ticks值為72,000則計數周期為1ms,ticks值為72則計數周期為1us。
在計數器運作的過程中,每次計數都會産生一個系統中斷,如果我們在中斷中進行計數,就可以得到一個“準确”的延時了。
源碼如下:
volatile unsigned long time_delay; // 延時時間,注意定義為全局變量,并且要在中斷中做自減
/*********************************************************************************************
函 數 名: delay_ms
實作功能: 延時一定的毫秒數
輸入參數: volatile unsigned long nms: 延時的毫秒數
輸出參數: 無;
返 回 值: 0 發送成功,
其他 發送失敗;
說 明: 無;
*********************************************************************************************/
void delay_ms(volatile unsigned long nms)
{
//設定計數器 若失敗則傳回1
if (SysTick_Config(SYS_FREQ/1000))
{
while (1)
{
printf("delay_ms init error\n");
}
}
time_delay=nms;//讀取定時時間
while(time_delay);
SysTick->CTRL=0x00; //關閉計數器
SysTick->VAL =0X00; //清空計數器
}
/*********************************************************************************************
函 數 名: delay_us
實作功能: 延時一定的微秒數
輸入參數: volatile unsigned long nus: 延時的微秒數
輸出參數: 無;
返 回 值: 0 發送成功,
其他 發送失敗;
說 明: 無;
*********************************************************************************************/
void delay_us(volatile unsigned long nus)
{
//設定計數器 若失敗則傳回1
if (SysTick_Config(SYS_FREQ/1000000))
{
while (1)
{
printf("delay_us init error\n");
}
}
time_delay=nus;//讀取定時時間
while(time_delay);
SysTick->CTRL=0x00; //關閉計數器
SysTick->VAL =0X00; //清空計數器
}
extern __IO unsigned long time_delay; // 延時時間,注意定義為全局變量,并且要在中斷中做自減
void SysTick_Handler(void)
{
if(time_delay > 0)
{
time_delay--;
}
}
需要注意的是,SysTick_Config()函數的使用需要調用core_cm3.h,而單獨包含 core_cm3.h則會産生error:#20:identifier"IRQn_Type"isundefined 錯誤,這是因為資料類型RQn_Type是在stm32f10x.h中聲明的,而core_cm3.h并沒有進行包含,是以我們應用程式需要在包含core_cm3.h之前包含stm32f10x.h才可以。