中斷裡呼叫HAL_Delay()進入死迴圈的原因
阿新 • • 發佈:2019-01-05
CUBE生成的程式中, SysTick是中斷型延時(利用中斷來查詢時間到了沒)。
/* Use systick as time base source and configure 1ms tick (default clock after Reset is MSI) */
資料補充:
網上還有一種寫 法是時間摘取法,是一直讀取SysTick產生延時函式~(原子的例程就是用這種方法)
/* Use systick as time base source and configure 1ms tick (default clock after Reset is MSI) */
HAL_InitTick(TICK_INT_PRIORITY);
#define TICK_INT_PRIORITY ((uint32_t)0x000F) /*!< tick interrupt priority */SysTick是核心中斷,優先級別預設最低。
(可以用核心函式來修改~ 當然,這就要看核心M3的書了,而不是看STM32的參考手冊那麼簡單。暫時就不深入研究,日後更新。)
總結起來就是,就是傳說中優先級別預設最低,雖然SysTick一直在跑,但是沒進入到中斷來讀取它的值~
(不知是哪裡讓我潛意識地認為SysTick級別比外設都高,導致這問題)
如果中斷裡呼叫HAL_Delay就會停在那裡,因為根本不會進入那個級別更低的中斷。資料補充:
網上還有一種寫 法是時間摘取法,是一直讀取SysTick產生延時函式~(原子的例程就是用這種方法)
其次,有人提到,中斷裡面不應該使用延時,中斷所佔的時間越短越好~有道理~
附上原子的時間摘取法的程式,很有學習價值~
////////////////////////////////////////////////////////////////////////////////// //本程式只供學習使用,未經作者許可,不得用於其它任何用途 //Mini STM32開發板 //使用SysTick的普通計數模式對延遲進行管理 //包括delay_us,delay_ms //正點原子@ALIENTEK //技術論壇:www.openedv.com //修改日期:2010/5/27 //版本:V1.2 //版權所有,盜版必究。 //Copyright(C) 正點原子 2009-2019 //All rights reserved //******************************************************************************** //V1.2修改說明 //修正了中斷中調用出現死迴圈的錯誤 //防止延時不準確,採用do while結構! ////////////////////////////////////////////////////////////////////////////////// static u8 fac_us=0;//us延時倍乘數 static u16 fac_ms=0;//ms延時倍乘數 //初始化延遲函式 //SYSTICK的時鐘固定為HCLK時鐘的1/8 //SYSCLK:系統時鐘 void delay_init(u8 SYSCLK) { SysTick->CTRL&=0xfffffffb;//bit2清空,選擇外部時鐘 HCLK/8 fac_us=SYSCLK/8; fac_ms=(u16)fac_us*1000; } //延時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=0x01 ; //開始倒數 do { temp=SysTick->CTRL; } while(temp&0x01&&!(temp&(1<<16)));//等待時間到達 SysTick->CTRL=0x00; //關閉計數器 SysTick->VAL =0X00; //清空計數器 } //延時nus //nus為要延時的us數. void delay_us(u32 nus) { u32 temp; SysTick->LOAD=nus*fac_us; //時間載入 SysTick->VAL=0x00; //清空計數器 SysTick->CTRL=0x01 ; //開始倒數 do { temp=SysTick->CTRL; } while(temp&0x01&&!(temp&(1<<16)));//等待時間到達 SysTick->CTRL=0x00; //關閉計數器 SysTick->VAL =0X00; //清空計數器 }