先解释中断优先级,后面讲代码的实现。
差异: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 else22 {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位数进行左移。
完!