浅见"/>
ARM学习《七》——关于STM32中断设置之浅见
关于中断的设置,在STM32的PDF文档中是找不到关于NVIC相关寄存器的说明的,我不知道为什么,是让大家摸不着门道吗?还是故装高深?我非常的不理解。我最后是在《Cortex-M3权威指南》这本书上找到NVIC相关寄存器的,这本书很好,建议大家买来仔细阅读。
在STM32的PDF文档中关于中断的设置只给出了一个中断异常向量表,让人摸不着头脑,其实NVIC相关寄存器才是管理STM32所有中断开关和中断优先级的司令部,NVIC 共支持1 至240 个外部中断输入(通常外部中断写作IRQs)。具体的数值由芯片厂商在设计芯片时决定。此外,NVIC 还支持一个“永垂不朽”的不可屏蔽中断(NMI)输入。NMI 的实际功能亦由芯片制造商决定。
先说为什么NVIC 共支持1 至240 个外部中断。Cortex‐M3 在内核水平上搭载了一个异常响应系统,这个系统规定为0到256个中断异常,支持为数众多的系统异常和外部中断。其中,编号为1-15 的对应系统异常,大于等于16 的则全是外部中断。除了个别异常
的优先级被定死外,其它异常的优先级都是可编程的。异常的优先级在这里我们先不说,对于所有的Cortex‐M3 内核处理器(包括STM32)256个异常中的0~15号异常都是一样的,内核规定好的,这就是Cortex‐M3的特点。0~15号异常如下:
从16 开始的外部中断类型,是制造商做成芯片后,支持的中断源数,自然各种芯片的中断源数目常常不到240 个,并且优先级的位数也由芯片厂商最终决定。如表:
这240个中断的使能与除能分别使用各自的寄存器来控制——这与传统的,使用单一比特的两个状态来表达使能与除能是不同的。CM3 中可以有240 对使能位/除能位,每个中断拥有一对。这240 个对子分布在8 对32 位寄存器中(最后一对没有用完)。欲使能一个中断,你需要写1 到对应SETENA 的位中;欲除能一个中断,你需要写1 到对应的CLRENA 位中;如果往它们中写0,不会有任何效果。通过这种方式,使能/除能中断时只需把“当事位”写成1,其它的位可以全部为零。再也不用像以前那样,害怕有些位被写入0 而破坏其对应的中断设置(写0 没有效果),从而实现每个中断都可以自顾地设置,而互不侵犯——只需单一的写指令,不再需要读‐改‐写。
如上所述,SETENA 位和CLRENA 位可以有240 对,对应的32 位寄存器可以有8 对,因此使用数字后缀来区分这些寄存器,如SETENA0, SETENA1…SETENA7,如表8.1 所示。但是在特定的芯片中,只有该芯片实现的中断,其对应的位才有意义。因此,如果你使用的芯片支持32 个中断,则只有SETENA0/CLRENA0 才需要使用。SETENA/CLRENA 可以按字/半字/字节的方式来访问。又因为前16 个异常已经分配给系统异常,故而中断0 的异常号是16。
现在我们再回到STM32的中断中来,STM32支持43个外部中断,既IRQ0~IRQ42(窗口看门狗中断~USB 从挂起唤醒中断),我们拿串口中断来说,如果要使能串口中断,就要找到串口终端号,查看STM32控制寄存器资料手册中的中断向量表得知串口1(UART1)的终端号为37,那么我们见寄存器SETENA1中的位5置一就可使能UART1中断。就这么简单
下面我们将上篇中的串口调试程序以串口中断的形式实现如下:
//头文件中增加SETENA1寄存器
/
#define SETENA1 (*((volatile unsigned long *)0xE000E104))
/
void stm32_UsartSetup ()
{
RCC_APB2ENR|=0x00004000; // enable clock for USART1
RCC_APB2ENR|=0x00000001; //复用功能IO时钟使能
RCC_APB2ENR|=0x00000004; //端口A时钟使能
GPIO_PORTA_CRH&=~(0x00000FF0); // Clear PA9, PA10
GPIO_PORTA_CRH|=0x000000B0; // USART1 Tx (PA9) alternate output push-pull
GPIO_PORTA_CRH|=0x00000400; // USART1 Rx (PA10) input floating
USART1_BRR=0x00000823; 波特率9600/20M
USART1_CR1&=0xFFFFEFFF; // set Data bits
USART1_CR2&=0xFFFFCFFF; // set Stop bits
USART1_CR1&=0xFFFFFBFF; // // set Parity
USART1_CR1|=(0x00000004|0x00000008); // RX, TX enable
USART1_CR1|=0x00002000; // USART enable
USART1_CR1|=0X00000020; //允许接收中断
SETENA1=0x00000020; //使能UART1中断
}
void USART1_IRQHandler(void) //串口中断处理程序
{
unsigned long flag=0;
while(USART1_SR&0x00000020)
{
USART1_CR1&=0xffffffdf;
flag=USART1_DR&0xff;
USART1_DR=flag&0xff;
while((USART1_SR)&0x80==0); //等待发送完毕
while((USART1_SR)&0x40==0);
flag=USART1_SR;
}
USART1_CR1|=0x00000020;
}
int main()
{
SystemInit0(); //时钟初始化
stm32_UsartSetup (); //串口初始化
while(1)
{
}
}
就这么简单!当然,库函数考虑的很全面,有好多地方是值得我们学习的,但先学会,弄懂了它的基本功能功能再提高也不迟……
更多请见.html
发布评论