中斷里調用HAL_Delay()進入死循環的原因
摘自:http://blog.csdn.net/alwxkxk/article/details/47204677
CUBE生成的程序中, 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產生延時函數~(原子的例程就是用這種方法)
其次,有人提到,中斷里面不應該使用延時,中斷所占的時間越短越好~有道理~
附上原子的時間摘取法的程序,很有學習價值~
1 ////////////////////////////////////////////////////////////////////////////////// 2 3 //本程序只供學習使用,未經作者許可,不得用於其它任何用途 4 5 //Mini STM32開發板 6 7 //使用SysTick的普通計數模式對延遲進行管理 8 9 //包括delay_us,delay_ms 10 11 //正點原子@ALIENTEK 12 13 //技術論壇:www.openedv.com 14 15 //修改日期:2010/5/27 16 17 //版本:V1.2 18 19 //版權所有,盜版必究。 20 21 //Copyright(C) 正點原子 2009-2019 22 23 //All rights reserved 24 25 //******************************************************************************** 26 27 //V1.2修改說明 28 29 //修正了中斷中調用出現死循環的錯誤 30 31 //防止延時不准確,采用do while結構! 32 33 ////////////////////////////////////////////////////////////////////////////////// 34 35 static u8 fac_us=0;//us延時倍乘數 36 37 static u16 fac_ms=0;//ms延時倍乘數 38 39 //初始化延遲函數 40 41 //SYSTICK的時鍾固定為HCLK時鍾的1/8 42 43 //SYSCLK:系統時鍾 44 45 void delay_init(u8 SYSCLK) 46 47 { 48 49 SysTick->CTRL&=0xfffffffb;//bit2清空,選擇外部時鍾 HCLK/8 50 51 fac_us=SYSCLK/8; 52 53 fac_ms=(u16)fac_us*1000; 54 55 } 56 57 //延時nms 58 59 //注意nms的范圍 60 61 //SysTick->LOAD為24位寄存器,所以,最大延時為: 62 63 //nms<=0xffffff*8*1000/SYSCLK 64 65 //SYSCLK單位為Hz,nms單位為ms 66 67 //對72M條件下,nms<=1864 68 69 void delay_ms(u16 nms) 70 71 { 72 73 u32 temp; 74 75 SysTick->LOAD=(u32)nms*fac_ms;//時間加載(SysTick->LOAD為24bit) 76 77 SysTick->VAL =0x00; //清空計數器 78 79 SysTick->CTRL=0x01 ; //開始倒數 80 81 do 82 83 { 84 85 temp=SysTick->CTRL; 86 87 } 88 89 while(temp&0x01&&!(temp&(1<<16)));//等待時間到達 90 91 SysTick->CTRL=0x00; //關閉計數器 92 93 SysTick->VAL =0X00; //清空計數器 94 95 } 96 97 //延時nus 98 99 //nus為要延時的us數. 100 101 void delay_us(u32 nus) 102 103 { 104 105 u32 temp; 106 107 SysTick->LOAD=nus*fac_us; //時間加載 108 109 SysTick->VAL=0x00; //清空計數器 110 111 SysTick->CTRL=0x01 ; //開始倒數 112 113 do 114 115 { 116 117 temp=SysTick->CTRL; 118 119 } 120 121 while(temp&0x01&&!(temp&(1<<16)));//等待時間到達 122 123 SysTick->CTRL=0x00; //關閉計數器 124 125 SysTick->VAL =0X00; //清空計數器 126 127 } 128 129
