先解釋中斷優先級,后面講代碼的實現。
差異:M0的中斷優先級相比於M4,沒有用到分組,且只用到了2個bit位(即0~3)來設置,數值越小,優先級越高;同等優先級,根據終端號的大小來決定誰先執行。
根據下面這張編程手冊里的圖來說明:
從上往下看,共32個IRQ中斷,每個中斷優先級占8個位,一個寄存器存4個中斷的優先級,所以M0的IRQ中斷最多只有32個;表27中高亮部分,說的是只用高兩位來表示優先級的值,低六位填0,沒有用到。
還有一個要提到的是word-accessible,就是寄存器只能按字操作。
M0的中斷優先級就講完了,還是很簡單的,那我們講一下代碼的實現:
1 void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct) 2 { 3 uint32_t tmppriority = 0x00; 4 5 /* Check the parameters */ 6 assert_param(IS_FUNCTIONAL_STATE(NVIC_InitStruct->NVIC_IRQChannelCmd)); 7 assert_param(IS_NVIC_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelPriority)); 8 9 if (NVIC_InitStruct->NVIC_IRQChannelCmd != DISABLE) 10 { 11 /* Compute the Corresponding IRQ Priority --------------------------------*/ 12 tmppriority = NVIC->IP[NVIC_InitStruct->NVIC_IRQChannel >> 0x02]; 13 tmppriority &= (uint32_t)(~(((uint32_t)0xFF) << ((NVIC_InitStruct->NVIC_IRQChannel & 0x03) * 8))); 14 tmppriority |= (uint32_t)((((uint32_t)NVIC_InitStruct->NVIC_IRQChannelPriority << 6) & 0xFF) << ((NVIC_InitStruct->NVIC_IRQChannel & 0x03) * 8)); 15 16 NVIC->IP[NVIC_InitStruct->NVIC_IRQChannel >> 0x02] = tmppriority; 17 18 /* Enable the Selected IRQ Channels --------------------------------------*/ 19 NVIC->ISER[0] = (uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F); 20 } 21 else 22 { 23 /* Disable the Selected IRQ Channels -------------------------------------*/ 24 NVIC->ICER[0] = (uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F); 25 } 26 }
這段代碼是官方庫的代碼,我說下思路:
1、要設置優先級,要先找到該中斷的優先級寄存器在哪個寄存器里,將中斷號除以4,得到對應寄存器,讀該寄存器的值給變量tmppriority ,代碼如下:
tmppriority = NVIC->IP[NVIC_InitStruct->NVIC_IRQChannel >> 0x02];
2、再判斷該終端號的優先級值在對應寄存器的哪個位置,並清零該8位,共四個位置為:0~7、8~15、16~23、24~31,代碼如下,NVIC_InitStruct->NVIC_IRQChannel & 0x03表示對4求余的結果;
tmppriority &= (uint32_t)(~(((uint32_t)0xFF) << ((NVIC_InitStruct->NVIC_IRQChannel & 0x03) * 8)));
3、接着給該8位寫入要設置的優先級的值,由於優先級只占了8位的高兩位,所以NVIC_InitStruct->NVIC_IRQChannelPriority << 6寫高兩位,再左移到在該寄存器中對應的位置,和讀到寄存器的值tmppriority 與運算,就完成了對該寄存器的對應位寫優先級值得操作,記住,這是一個32位的數;
tmppriority |= (uint32_t)((((uint32_t)NVIC_InitStruct->NVIC_IRQChannelPriority << 6) & 0xFF) << ((NVIC_InitStruct->NVIC_IRQChannel & 0x03) * 8));
4、把這個32位的數寫入該寄存器中;
NVIC->IP[NVIC_InitStruct->NVIC_IRQChannel >> 0x02] = tmppriority;
廢話:((NVIC_InitStruct->NVIC_IRQChannel & 0x03) * 8))這個語句是用來獲得在寄存器中的偏移值得,用這個偏移值就能把8位數進行左移。
完!