|
ARM的中断管理体系和51系列微控制器的中断管理体系不太一样。熟悉51体系结构的用户需要特别注意这一点。ARM的中断不会自动嵌套,实现ARM微控制器的中断嵌套比较烦琐,我们不提倡中断嵌套。但不排除需要嵌套的应用,因而在启动代码中,有对中断嵌套的处理。模板中的文件IRQ.S用于处理中断嵌套,是以下中断处理方法的依据。用户要根据自己的应用更改此文件,只需要在文件末尾添加中断处理程序的句柄即可。<br /> 中断嵌套的原则:低优先级的中断嵌套高优先级的中断。<br /> 可嵌套中断服务程序编写方法:<br /> 1、保存当前中断使能寄存器VICIntEnable的值;<br /> 2、禁止当前中断和低优先级中断;<br /> 3、清除中断逻辑,使VIC能够响应更高优先级的中断;<br /> 4、中断处理服务程序;<br /> 5、恢复保存的中断使能寄存器的值。<br /> 声明需要嵌套的中断服务程序时,不能使用'__irq'关键字,而需要通过句柄的方式进行。<br /> 请注意IRQ.S中宏$IRQ_Label HANDLER $IRQ_Exception_Function的用法。<br /><br />例子如下:<br /><br />/********************************************************************************************<br />* 文 件 名:VIC_Nesting.c<br />* 功 能:本实验演示中断嵌套现象。程序开启了两个中断:定时器0和外部中断0。定时器0使LED8~LED1<br />* 闪烁,而外部中断0取反蜂鸣器控制口。分配定时器0中断优先级高于外部中断0的优先级。设置<br />* KEY1连接外部中断0。按住KEY1键后全速运行程序,看LED8~LED1能否闪烁,若闪烁,则说明中<br />* 断嵌套成功。需要在文件IRQ.S末尾添加句柄:<br />* Timer0_Handler HANDLER IRQ_Timer0<br />* Eint0_Handler HANDLER IRQ_Eint0<br />* 说 明:用跳线帽短接KEY1,BEEP,74HC595_2相关跳线。<br />*<br />*在产生IRQ中断,进入服务程序之前,IRQ中断将自动禁止,而Fiq中断依然使能,故在IRQ中断下依然要响应Fiq中断。<br />*<br />*********************************************************************************************/<br />#include 'config.h'<br />#define BEEPCON ((uint32)0x01<<7) // P0.7引脚控制蜂鸣器,低电平蜂鸣<br />#define BEEP_ON() IO0CLR=BEEPCON // P0.7引脚输出低电平,蜂鸣器蜂鸣<br />#define BEEP_OFF() IO0SET=BEEPCON // P0.7引脚输出高电平,蜂鸣器不蜂鸣<br />#define SPI_CS ((uint32)0x01<<20) // P1.20引脚模拟SPI的片选信号<br />#define SPI_DATA ((uint32)0x01<<22) // P0.22引脚模拟SPI的数据信号<br />#define SPI_CLK ((uint32)0x01<<25) // P1.25引脚模拟SPI的时钟信号<br />#define H_SPI_CS() IO1SET=SPI_CS // SPI的片选信号置高 <br />#define L_SPI_CS() IO1CLR=SPI_CS // SPI的片选信号置低<br />#define H_SPI_DATA() IO0SET=SPI_DATA // SPI的数据信号置高<br />#define L_SPI_DATA() IO0CLR=SPI_DATA // SPI的数据信号置低<br />#define H_SPI_CLK() IO1SET=SPI_CLK // SPI的时钟信号置高<br />#define L_SPI_CLK() IO1CLR=SPI_CLK // SPI的时钟信号置低<br />void Timer0_Handler(void);<br />void Eint0_Handler(void);<br />uint8 data;<br />/********************************************************************************************<br />* 函数名称:SendDataTo74HC595()<br />* 功 能:向74HC595发送一字节数据<br />* 入口参数:data 要发送的数据<br />* 出口参数:无<br />* 注 意:发送数据时,高位先发送<br />*********************************************************************************************/<br />void SendDataTo74HC595(uint8 data)<br />{<br /> uint8 i;<br /> <br /> L_SPI_CS(); // SPI_CS=0<br /> for(i=0;i<8;i++) // 发送8位数据(1个字节)<br /> {<br /> L_SPI_CLK(); // SPI_CLK=0<br /> /* 设置SPI_DATA输出值 */<br /> if((data & 0x80)!=0)<br /> H_SPI_DATA(); // SPI_DATA=1<br /> else<br /> L_SPI_DATA(); // SPI_DATA=0<br /> data<<=1; // 将要发送的1字节数据左移一位<br /> H_SPI_CLK(); // SPI_CLK=1<br /> }<br /> H_SPI_CS(); // SPI_CS=1 <br />}<br />/********************************************************************************************<br />* 函数名称:IRQ_Timer0()<br />* 功 能:Timer0中断服务函数,LED8~LED1闪烁<br />* 入口参数:无<br />* 出口参数:无<br />*********************************************************************************************/<br />void IRQ_Timer0(void)<br />{<br /> uint32 bak;<br /> <br /> bak='VICIntEnable'; // 备份当前VICIntEnable的值<br /> VICIntEnClr=(1<<4)|(1<<14); // 禁止当前优先级中断及低优先级中断<br /> VICVectAddr='0x00'; // 清除中断逻辑,以便VIC可以响应更高优先级IRQ中断<br /> <br /> /* LED8~LED1闪烁 */<br /> if(data==0x00) <br />data='0xff';<br /> else<br />data='0x00';<br /> SendDataTo74HC595(data);<br /> T0IR=0x01; // 清除Timer0中断标志<br /> <br /> VICIntEnable='bak';<br />}<br />/********************************************************************************************<br />* 函数名称:IRQ_Eint0()<br />* 功 能:外部中断0中断服务函数,取反蜂鸣器控制口,允许中断嵌套<br />* 入口参数:无<br />* 出口参数:无<br />*********************************************************************************************/<br />void IRQ_Eint0(void)<br />{<br /> uint32 bak;<br /> <br /> bak='VICIntEnable'; // 备份当前VICIntEnable的值<br /> VICIntEnClr='1'<<14; // 禁止当前中断<br /> VICVectAddr='0x00'; // 清除中断逻辑,以便VIC可以响应更高优先级IRQ中断<br /> <br /> IRQEnable(); // 使能IRQ中断 <br /> <br /> /* 取反蜂鸣器控制口 */<br /> if((IO0PIN & BEEPCON)==0)<br />BEEP_OFF();<br /> else<br />BEEP_ON();<br /><br /> /* 等待外部中断信号恢复为高电平,清除EINT0中断标志*/<br /> while((EXTINT & 0x01)!=0)<br /> {<br /> EXTINT='0x01';<br /> }<br /> <br /> VICIntEnable='bak';<br />}<br /><br />/********************************************************************************************<br />* 函数名称:main()<br />* 功 能:初始化定时器0,设置定时器0中断和外部中断0<br />*********************************************************************************************/<br />int main(void)<br />{<br /> PINSEL0&=~((uint32)0x03<<14); // 将P0.7引脚选择为GPIO功能<br /> IO0DIR|=BEEPCON; // 设置P0.7为输出<br /> BEEP_OFF(); // 蜂鸣器禁止蜂鸣<br /> <br /> PINSEL1&=~((uint32)0x03<<0); // 将P0.16引脚选择为EINT0功能<br /> PINSEL1|=0x00000001;<br /> <br /> PINSEL1&=~((uint32)0x03<<12); // 设置P0.22引脚为GPIO<br /> PINSEL2&=~((uint32)0x01<<3); // 设置P1.20和P1.25引脚为GPIO<br /> IO0DIR|=SPI_DATA; // 设置P0.22,P1.20,P1.25引脚为输出<br /> IO1DIR|=(SPI_CS | SPI_CLK); <br /> <br /> /* Timer0初始化*/<br /> T0TC=0; // 定时器设置为0 <br /> T0PR=0; // 时钟不分频<br /> T0MCR=0x03; // 设置T0MR0匹配后复位T0TC,并产生中断标志<br /> T0MR0=Fpclk/10; // 0,1秒定时<br /> T0TCR=0x01; // 启动定时器<br /> <br /> IRQEnable(); // 使能IRQ中断<br /> <br /> data='0x00';<br /> <br /> /* 初始化Timer0、Eint0中断(使用向量IRQ)*/<br /> VICIntSelect='0x00000000'; // 设置所有中断分配为IRQ中断<br /> VICVectCntl0=0x20 | 4; // 分配Timer0中断到向量中断0<br /> VICVectAddr0=(uint32)Timer0_Handler; // 设置中断服务程序地址<br /> VICVectCntl1=0x20 | 14; // 分配EINT0中断到向量中断1<br /> VICVectAddr1=(uint32)Eint0_Handler; // 设置中断服务程序地址<br /> T0IR=0x01; // 清除Timer0中断标志<br /> EXTINT='0x01'; // 清除EINT0中断标志<br /> <br /> VICIntEnable=(1<<4)|(1<<14); // 使能Timer0、EINT0中断<br /> <br /> while(1); // 等待中断 <br /> return 0; <br />} <br /><br /> |
|