中断里调用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