今天和大家聊聊什么是NVIC,NVIC全名也叫做嵌套向量控制器,看名字也就知道了它和中斷密不可分。它是ARM公司設計的內核管理設備,因此各個廠商在使用的時候往往都各不相同,但是原理都差不多,我們今天討論的就是ST公司是在怎么使用的,這里大家最好看看M3/M4權威指南第7章,239頁。這里我就不說中斷的基本概念了,直接進入主題。為什么要使用中斷?CPU的運行有中斷和查詢,但是查詢的時候CPU一直工作,這樣一直占用CPU,而中斷來的時候,CPU檢查到了中斷標志,就會立刻知道要有事情去處理。那么它就會去處理緊急的事情。這里就涉及到了優先級的3種情況。
1)搶占優先級:看名字就知道它特別霸道,會從CPU手中去搶占資源,也就是高搶占優先級會干擾低搶占優先級,也就是中斷嵌套。
2)響應優先級:高響應優先級有優先處理(同時到來),但是如果高響應優先級后來的話,那么對不起,你也要排隊,等這個事情處理完,響應優先級沒有中斷嵌套。
3)自然優先級:有沒有響應優先級,我們在數據手冊看到的中斷(除了內核設備)都是自然優先級,我們可以通多NVIC來設置優先級級別。
二:中斷的來源:1:外設比如定時器,串口等;2:中斷請求;3:系統滴答定時器;4:系統異常;5:軟件中斷。總共要有255個中斷來源,15個是系統異常,240個是外部中斷。
三:ARM公司設計NVIC:
some of the registers are saved onto the stack automatically 這段話表明了在處理中斷的時候,外了恢復中斷程序,ARM 公司把一些寄存器保存到堆棧中,在返回的時候自動恢復,
when an exception is accepted, and are also automatically restored in an exception
return sequence. This mechanism allows the exception handlers to be written as
normal C functions without any additional software overhead.
Set up the priority level of the required interrupt (this step is optional)
• Enable the interrupt generation control in the peripheral that triggers the interrupt
• Enable the interrupt in the NVIC
這段話告訴我們:當要使用中斷的時候,第一步:使用外部中斷的使能(就好比開時鐘一樣);第二步:設置中斷的優先級級別;第3步:啟用NVIC的中斷。
四:優先級級別有優先級級別寄存器來控制,ARM公司一共有8位確定優先級級別;但是ST公司只使用了4位;我們看看ST公司是在怎么確定優先級級別的。
看下面4個函數就知道了在CM4.h文件的1485頁。
1)void NVIC_EnableIRQ(IRQn_Type IRQn) 函數功能:NVIC中斷使能,函數參數:IRQn_Type IRQn,中斷名:指明了是哪一個中斷
2)void NVIC_SetPriority (IRQn_Type IRQn,uint32_t priority) 1568頁:函數功能:設定優先級級別,函數參數:IRQn_Type IRQn,中斷名:指明了是哪一個中斷
uint32_t priority:中斷優先級級別。
3)void NVIC_SetPriorityGrouping(uint32_tPriorityGroup)函數功能:設定優先級分組(一個工程內就只能用一次分組,如果多次分組,之前的分組就會無效)函數參數:uint32_tPriorityGroup優先級分組值 ===========(7-組編號)
4)uint32_t NVIC_EncodePriority (uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority)
{
uint32_t PriorityGroupTmp = (PriorityGroup & 0x07); /* only values 0..7 are used */ //表示ST公司只用了4位
uint32_t PreemptPriorityBits; //搶占優先級位數
uint32_t SubPriorityBits; //響應優先級位數
PreemptPriorityBits = ((7 - PriorityGroupTmp) > __NVIC_PRIO_BITS) ? __NVIC_PRIO_BITS : 7 - PriorityGroupTmp;
SubPriorityBits = ((PriorityGroupTmp + __NVIC_PRIO_BITS) < 7) ? 0 : PriorityGroupTmp - 7 + __NVIC_PRIO_BITS;
return (
((PreemptPriority & ((1 << (PreemptPriorityBits)) - 1)) << SubPriorityBits) |
((SubPriority & ((1 << (SubPriorityBits )) - 1)))
);
}
NVIC_PRIO_BITS:恒等于4
我們來分析這個函數:函數功能:得到優先級級別;函數參數:uint32_t PriorityGroup;優先級分組值;uint32_t PreemptPriority:搶占優先級
uint32_t SubPriority:響應優先級;
uint32_t PriorityGroupTmp = (PriorityGroup & 0x07); 上面我們說過PriorityGroup=7-組邊號,當組邊號是0,PriorityGroupTmp=7;帶進這一句話
PreemptPriorityBits = ((7 - PriorityGroupTmp) > __NVIC_PRIO_BITS) ? __NVIC_PRIO_BITS : 7 - PriorityGroupTmp;結果PreemptPriorityBits =0;表示搶占優先級位數是0,響應優先級位數是4;返回的值是0和15.然后依次分析1,2 ,3,4。組。得到優先級級別。
下面我們把這4個函數封裝成一個函數得到:
void My_NVIC_Init(IRQn_Type IRQn,u32 PG,u32 PP,u32 SP)
{
u32 priority;
NVIC_SetPriorityGrouping(PG); //設定優先級分組
priority=NVIC_EncodePriority (PG,PP,SP); //得到優先級級別
NVIC_SetPriority (IRQn, priority); //設定優先級級別
NVIC_EnableIRQ (IRQn); /NVIC中斷使能。
}
接下來我會通過外部中斷實驗來告訴你們如何使用這個NVIC函數。
|