中断不要看成一次异常,中断就是发生了一个信号然后我得去停止本来的程序然后去处理这个信号。我们可以利用中断去进行一些操作。 例如: 我的快递到了,然后我正在上班,快递打电话给我叫我去拿,我不上班去拿快递这个过程就是中断处理。拿快递是一件快乐的事。 而不是想成我CPU宕机了,或者我那个二极管爆炸了,那个硬件坏了然后再去进行中断处理。 ————————————————————————————— 扩展一下: 异常处理有三种方式:轮询,中断,DMA
轮询: cpu一直问你这个信号什么时候来,来了我就得处理 我们可以设置一个外设引脚,把相应控制器的寄存器设置成轮询模式然后,CPU就会一直去询问 像:我的快递正在派送,它告诉了我在派送,但是我不知道它什么时候到,而且它跟我说它手机没电了不能通知我,我(cpu)正在上班(正常运行程序),我又不知道它什么时候来,所以的过几秒(根据CPU运算速度)我就出去看一下快递小哥有没有到(轮询)
中断: cpu就正常的处理程序,但是中断信号一来我就得去停下我的正常程序去处理这个中断信号; 像:别人给我买了一个快递,我不知道她给我买了快递,我就正常的上班,而且我是某上市公司的高管,我很牛逼而且很忙。我就是CPU。 然后我有一个专门帮我 ———接快递电话的女秘书(中断控制器),好,快递电话一来,那个女秘书就去拿快递,并给快递分类,然后中断我的正常程序,告诉我这是谁谁谁的快递,你现在就得处理一下。
DMA: DMA就是信号不经过CPU处理,它直接就放到对应的SOC内部,这个信号应该出现的位置。就比如,我买了一个桌子,我直接跟快递说,你到了不用告诉我,你直接从我家(SOC)后门(一个通道把?)进去,帮我把桌子(信号)放到客厅(SOC内部,可能是内存可能是其他地方,看你的异常怎么处理的) ————————————————————————————— 好,中断的概念我们知道了,那我们怎么去产生一个中断呢? 我们这里讲的是外部硬件产生中断(软中断之前已经讲过了SWI)
我们很多硬件都可以产生中断,比如说由UART控制一个引脚,uart控制器你可以设置里面的寄存器设置成中断模式,(设置一些寄存器),当这个引脚变成我们特定的一个信号,就可以去产生一个中断(比如接受到特定的信号,或者引脚变成了什么电平)
我们通过一个按键实验来具体操作一下中断的产生和处理: 一、(外设层次,让外部的硬件控制器能产生一个中断并发送给中断控制器) (设置对应引脚的中断模式) 1、 设置key-2找到对应引脚为gpx1_1; 设置GPX1_I状态寄存器设置为中断状态 GPX1.GPX1CON = GPX1.GPX1CON & (~(0XF << 4 ) | (OXF << 4); 2、 设置对应引脚的中断寄存器
由于我们设置的引脚为GPX1_1所以所有的EXT_INT41…的寄存器都是相关寄存器(EXTURN INTREEUPT 外部中断) 1)中断状态寄存器(中断的触发方式) 可以设置为(低电平、高电平、下降沿、上升沿、双边沿)触发,这里我们设置下降沿触发。 EXT_INT41_CON = EXT_INT41 _CON & (~0XF << 4) | (0X2 << 4) 2)EXT_INT41_FLTCION 这个寄存器是设置信号滤波的,可以按键防抖,这里我们不用。 3)EXT_INT41_MASK 中断开关寄存器,可以打开或关闭对应位的中断 EXT_INT41_MASK = EXT_INT41_MASK | (0X1<<1); 4)EXT_INT_PIND 中断挂起寄存器:当中断产生后,CPU在处理其他同等级或高等级的中断时,可以将我们的这个中断挂起,等待其他中断执行完,再处理我们这个中断。 二、设置中断控制器内的相关寄存器 1)中断控制器
现在我们引脚的中断就设置好了,但是我们处理中断我们还没有写 三、处理中断 中断处理程序怎么写随便你,这是你的程序,来了一个IRQ中断你按照你自己想要的的方式去处理就好了哪怕是去让CPU去放一个屁。 SO,我们学处理中断重要的不是学去写中断处理程序,而是要知道CPU怎么去处理中断的。 梳理一遍:我设置按一个按键视为发生了一个中断(把按键设为中断模式),中断产生了,中断控制器就会去接收这个中断信号,并且我们可以设置中断控制器对这个信号的处理方式。(中断开不开,挂起不挂起。。。)然后中断控制器会把处理过的中断信号发给指定CPU。CPU是如何处理终端的呢? 之前讲过异常处理,cpu接收收到中断信号会自动进行: 二、 1)将CPSR的的内容拷贝 到对应异常模式下的SPSR_mod中 /CPSR是当前状态寄存器 保存着当前处理器遇到异常前的状态 保存在SPSR中,方便跳转之后回到正常的的工作状态(mod 为对应的异常模式eg :SPSR_fiq)/ 2,修改CPSR的值1)、 修改中断禁止为禁止相应中断(不再响应同等优先级或低优先级的中断请求)设置位为图中I 位或F位 2)、修改模式位进入对应的模式状态(修改位数为M0~M4) 3)、修改状态位为arm状态(无论之前为什么状态ARM或thumb 执行异常必须进入ARM状态) 3、 保存返回地址到对应模式下的LR_mode(异常出现时LR自动保存当前程序的下一段的地址)//LR 就是R14 4、 设置PC的值让它跳到相应的异常向量表中。(异常向量表) //异常向量表(32Baty//每个异常4字节) 2、异常返回 异常返回不像异常处理一样处理器自己完成,异常返回需要自己手动完成 首先异常处理程序的自己写 CPSR=SPSR; PC=LR; //这是我们之前讲的CPU处理异常的过程。 那么我们的irq中断处理程序也是这样处理的,所以我们要做的是 1、在异常向量表中在IRQ的位置写一个跳转指令,跳到处理程序: 写处理程序: //最后一句^的意思就是把SPSR的值给CPSR,恢复 我们来看一下我们写的处理程序 首先我们看一下led_con的下一句: EXT_INT41_PEND = (1<<1); 这句的作用是什么呢,先看一下手册。 中断挂起位,这个不用我们写,中断处理的时候是默认是挂起的,但是我们这里为什么要去写呢? 因为我把一个中断挂起了,但是我CPU处理完另一个中断,那我应该就要去处理挂起的第一个中断对不对,那我们怎么知道我处理完中断了呢?就是我们要自己去把中断挂起位置0 (置0是往里面写1),如果不这样,那我就不能处理其他中断 比如,我按一次按键,LDE开一次,那我再按一次它就会没反应,因为他默认我CPU还在处理程序,你排队,不要打扰CPU。
那这句是什么意识呢? 先看手册 它是一个只读的寄存器,这样看也看不出它是干嘛的 但是我们现在想一个问题, 我按一个按键触发IRQ中断去让Led亮灭, 那我IRQ中断的处理程序就是让LED亮灭,但是我们知道IRQ中断有160个寄存器可以去触发irq中断,那我如果这样写的话 160个irqh中断就都触发led,这样肯定不行,我UART.GPIO.WTD…等等不同的控制器触发的IRQ中断处理肯定要不一样,甚至我同一个GPIO控制器下我按下不同的KEY的处理方式也要不一样; 那么我们就要用到中断标识 ,这里我们用的触发方式都有一跟固定的中断ID ,比如我按KEY2标识就一定是57 ,我们设置中断控制器的时候也要写这个 这样我们读到一个ID 我们就知道它是谁产生的,并利用SWITCH CASE 去写相应程序。
|