精华内容
下载资源
问答
  • stm32f103基于正点原子待机唤起实验写的停机唤起实验。 按键KEY0(PB0)按下,触发中断,进入停机模式;按键KEY1(PB1)按下,触发外部中断,从停机模式唤醒;
  • S3C6410外部中断 中断在嵌入式里面是很常见的一个功能了。通过这个功能,可以让CPU减轻很多负担,不用不断的查询设备的状态。提高了CPU的效率。 中断的过程如下:   中断源检测中断信号产生,然后将中断信号发送给...

    转自:http://comm.chinaaet.com/adi/blogdetail.aspx?id=40071&currentpage=2#a


    S3C6410外部中断

    中断在嵌入式里面是很常见的一个功能了。通过这个功能,可以让CPU减轻很多负担,不用不断的查询设备的状态。提高了CPU的效率。

    中断的过程如下:

        clip_image002

    中断源检测中断信号产生,然后将中断信号发送给中断控制器,中断控制器判断该中断是否被屏蔽,从而决定该中断信号是否要发送给CPU。中断信号发送给CPU后,CPU对中断进行处理,也就是调用中断函数。

    上述过程,基本上是嵌入式的通过中断处理过程,只是不同的嵌入式在这三部分配置有区别而已。

        S3C6410共有64个中断源。

    clip_image004

     上图是S3C6410的中断控制器,这里就关心红色框部分。这两个是中断控制器,分别管理各自的32个中断。 

    clip_image006

    clip_image008

    这里,就截取了一部分的图。总共有64个中断,每个中断有自己的标号,以及自己的所属组,也是属于哪个中断控制器控制。标号是指在对应的中断控制器寄存器的哪一位或者是哪一个寄存器对应自己。如INT_EINT0,这个是外部中断0,属于VIC0,标号是0。说明VIC0的寄存器的第0位或者是第0个寄存器对应外部中断0这个中断。


     本章,是关心外部中断的部分。S3C6410共有127个外部中断,其I0引脚及分组如下:

    clip_image010

      S3C6410将外部中断分成了10组。每一组有相应的管脚。对于外部中断组0,可以使用GPN0-GPN15这16个管脚。

    除了分组,还对组分配了中断号:

    clip_image012

    属于外部中断组027个中断占用了VIC里的4个中断号,分别是外部中断0-3,外部中断4-11,外部中断12-19,外部中断20-27。外部中断组1-9只占用了1个中断号。

    为了节约中断,不可能为每个外部管脚都分配一个中断号,所以就会把某几个外部中断给合并成一个中断号。例如,对于外部中断0-3,就合并成了一个中断号,INT_EINT0。当这4个中断有任意一个产生中断时,INT_EINT0会挂起,CPU就会知道产生了外部中断0-3中断,然后去执行中断处理,在中断服务程序中,为了知道具体是哪一个中断,还需要去查询寄存器以知道是哪一个中断产生。


    S3C6410中断处理有向量模式和非向量方式。因为要与之前的ARM系列兼容,所以保存了非向量方式。非向量方式,就是当中断产生时,都跳转到中断异常去,然后这个中断异常中,编写程序,判断是哪一个中断产生,然后去执行对应的中断处理程序。但是在非向量模式中,提前设定每个中断对应的入口地址,这样当中断产生的时候,就不用跳转到中断异常去了,直接跳转到对应的中断程序去了。这样中断处理的效率就提高了。

    在我的设计中,使用的就是中断向量方式。推荐用中断向量方式。



    clip_image014

      上图是中断非向量方式。



    clip_image016

      上图是中断向量方式。

      明显看出,中断向量方式的效率要高。


    中断程序编写流程,大致就只有3步:

    1、  初始化中断源,也就是设置中断源是什么,以及中断的触发方式(高电平,低电平,上边沿,下降沿,双边沿)

    2、  初始化中断控制器,也就是使能对应的中断,让中断信号能够传递到CPU。在这里还需要设置中断优先级,中断滤波等与中断的相关设置

    3、  编写中断处理函数。也就是中断到了,该干什么。干完后,还要把中断挂起给清除掉,以免进入第二次中断     下面就进行外部中断程序的编写了。这里要控制一些寄存器。OK6410的开发板有6个按键,接到了GPN0-5的六个外部中断脚上。

    第一步,中断源设置

     1、设置外部管脚为中断。

    clip_image018

      将对应管脚的值设置为10,就是外部中断了。这里,没有说明是哪个组,就是默认的第0组。

    clip_image020

      上面,就说明GPH0是外部中断第6组的外部中断0。


    所以代码就有了

    clip_image022

    clip_image024

    首先定义寄存器的地址,然后将这个寄存器的后12位设置为AAA。表示这几个管脚作为外部中断。


    2、设置触发方式

    clip_image026

    设置外部中断中,有以上一堆寄存器。说明下这些寄存器有什么用

    EINTxCONy: 外部中断组x的第y个控制器。这个就是设置中断的触发方式。有5种触发方式。

    clip_image028

    EINTxFLTCON: 外部中断组x的第y个滤波功能控制器。S3C6410对于外部中断有滤波功能,这个就是用来设置滤波功能。有延迟滤波,有数字滤波。滤波,可以用来滤掉毛刺信号。在以前51做按键外部中断,按键是有抖动的,就需要一个去抖动的一个东西。但是有了这个滤波的话,直接设定滤波的时间,就可以滤掉这一段时间的毛刺了。就不用再加去抖动的程序了。

    clip_image030

    EINTxMASK:外部中断组x的屏蔽寄存器。用来使能中断的。当要使用某个中断的时候,就需要让这个中断使能,就需要在这个寄存器中的对应位写入0,来打开中断。默认为中断都是屏蔽的。

    clip_image032

    EINTxPEND:外部中断组x的中断挂起寄存器。这个寄存器就是用来保存中断的状态的。当对应的中断产生时,对应的位为1。当中断处理完毕后,需要往对应对写入1进行清除。

    clip_image034

     

    在这里,就只需要设置触发方式即可了。将外部管脚的触发方式都设置为下降沿触发。因为在开发板上,按键按下的时候是低电平,没有按下的时候是高电平。

    首先是定义寄存器地址

    clip_image036

    配置IO代码就如下了,对EINT0CON0配置即可。

    clip_image037


    第二步:中断控制器配置

    1、  去掉外部中断屏蔽

    就是配置EINT0MASK寄存器。让对应的位为0.

    clip_image039

    2、  设置滤波

    就是配置EINT0FLTCON寄存器。打开滤波,设置为数字滤波,滤波宽度为6‘h3F。

    clip_image041

    3、  使能中断号。

    外部中断0-3属于INT_EINT0中断号,外部中断4-11属于INT_EINT1中断号,这里用到了外部中断0-5。所以用到了这两个中断号。就要是能这两个中断号。

    clip_image043

    这个VICxENABLE寄存器用来使能中断号。每一位就对应各个中断号的标号。我们这要打开INT_EINT0和INT_EINT1.这两个的标号是

    clip_image045

     所以要将VIC0ENABLE的最后两位设置为1.

         clip_image047


    因为S3C6410是采用向量中断,所以就需要配置中断的入口地址。这个入口地址就是靠VICxVECTADDRy寄存器来配置的。

    clip_image049

    对于VIC0和VIC1有各自的寄存器。每个寄存器保存的是对应中断的入口地址。例如,VIC0VECRADDR0就是VIC0下的第0个中断号的入口地址。

    我们这用到VIC0下的第0个中断号和第一个中断号。

    clip_image051

    isr_INT_EINT0,isr_INT_EINT1是中断函数的名字。将函数地址地址转换为unsigned long型。在传递给寄存器。这样,就有了中断号的入口地址。当外部中断0-3产生的时候,0号中断号就有效,然后就跳转到isr_INT_EINT0函数去执行了。


    最后两步,就是使能向量中断和打开总中断。在之前的qboot设计中,是将中断全部关掉的。

    clip_image053

    使用嵌入汇编,这里代码就不分析了。去看看CP15的c1寄存器和CPSR寄存器就知道这段代码有什么用了。


             第三步:编写中断处理函数

             这个就是写中断产生的时候,要做什么。这里就将灯翻转就行了。当有外部中断,就将灯状态翻转一次。

             clip_image055

                  clip_image057

    总共两个中断函数。在中断函数前和中断函数末尾都有使用嵌入汇编。这段代码是固定的。目的是为了保存环境,将r0-r12,lr寄存器的值给压入栈中,然后执行完后,在将这些值返回给r0-r12,pc寄存器。这样r0-r12寄存器的内容就恢复了,同时pc得到返回地址,就返回到中断前的程序地址去了。

    这里有sub lr,lr,#4。将lr的值减去4。这个原因就要从ARM的流水线说起了。ARM采用流水线,取址,译码,执行。所以pc的值永远是当前执行指令的地址+8.

    clip_image059

    中断跳转的时候,会将pc的值给lr,pc的值为当前执行程序地址+8,lr的值就是pc的值。而返回的地址应该是执行阶段的下一条地址,也就是当前执行程序地址+4,所以直接返回lr的值就不对了,应该返回lr-4的值。

    中断处理完后,需要将中断挂起位给清零。这里,很简单的将所有中断位都给清零。然后再将中断执行地址给清0。

    clip_image061

    这个寄存器,当执行中断函数的时候,值是中断函数的入口地址。往这个寄存器写入任意的值,就清除这个中断了。所以最后需要将这个寄存器给清0。


    这样,就完成了S3C6410的外部中断程序设计了。总结下来就几步:

    1、  设置外部管脚为中断

    2、  设置中断触发方式

    3、  取消中断屏蔽,使外部中断不屏蔽

    4、  设置中断滤波

    5、  设置中断号的中断选择,是irq还是fiq,默认为是irq。

    6、  使能中断号

    7、  设置中断号的入口地址

    8、  开启向量中断方式并打开全局中断

    9、  编写中断处理函数,中断函数前和后要使用嵌入汇编,保存环境和恢复环境。中断处理后,要清除中断挂起位和中断执行地址


    这样下来,就能实现外部中断了吗?当然,是不可以的。因为还差了一步。中断处理函数的代码是用c代码写的,c代码需要什么?需要栈啊。不然怎么时间环境保护和恢复环境了。之前不是设置过栈吗?怎么这样还需要设置了?
    那是因为之前设置的栈是SVC模式下的栈,而不是irq模式下的栈。不同模式,有自己的备份寄存器,其中,栈SP是每个模式都有自己的。所以需要设置下irq模式下的栈。代码也是比较简单的。在之前的设置栈的汇编代码中,将模式切换为irq模式,再设置sp。

    init_stack:
            msr cpsr_c, #0xd2
            ldr sp, =0x53000000 //初始化r13_irq
            msr cpsr_c, #0xd3
    	ldr sp, =0x54000000  //初始化R13_svc
    	mov pc, lr


    STM32外部中断

    STM32直接就是采用的中断向量模式。而且中断的入口地址是相对固定的。所以就不像S3C6410那样,需要配置中断的入口地址。

             在手册中,就定义了各个中断函数的入口地址。

    clip_image063

             所以在启动代码中,才有如下的程序,去定义中断函数的入口地址。

    clip_image065

           在后面还将各个中断函数导出

    clip_image067

    导出的中断函数用[weak]修饰,说明这个函数是弱函数,外部程序是可以改写这个函数的。在启动代码中,就将各个中断函数的名字给固定了,所以当我们要编写中断函数的时候,函数名可是不能乱取的,要取这里定义的函数,不然就跳转不到中断函数去了。


    STM32的中断上电默认就是关闭的。所以要使用中断的话,就得要配置中断。过程和S3C6410的一样。

    1、  配置中断源

    2、  中断控制器配置

    3、  编写中断处理函数


    STM32将中断分成了中断和事件两种。其框图:

    clip_image069

         中断和事件有什么区别了?中断,是一定要到CPU中去处理的。但是事件就不用,事件可以通知一些外设进行一些操作。例如使用DMA发送串口数据,当串口发送完一个数据后,就产生一个事件通知DMA,表示数据发送完毕,DMA接收到这个事件后,发送一个新的数据给串口进行发送。整个过程不需要CPU参与。效率就提高了。

         从图中,也可以看出,配置外部中断,需要配置5个寄存器。


         STM32将外部中断分成了16组线,对应每一组IO的一根线。

    clip_image071

    所以当要用外部管脚的中断,要开放来自对应线的请求。


    另外,STM32对外部中断也采用的分组管理,也就是不是每一组外部线都有对应的中断。

    STM32对外部共有6个中断号。

    中断号

    说明

    EXTI0

    EXTI线0中断

    EXTI1

    EXTI线1中断

    EXTI2

    EXTI线2中断

    EXTI3

    EXTI线3中断

    EXTI4

    EXTI线4中断

    EXTI9_5

    EXTI线[9:5]中断

    EXTI15_10

    EXTI线[15:10]中断

          每个中断号对应自己的中断函数。

    clip_image073

    clip_image075

    clip_image077

        当外部中部9-5有一个产生时,就会跳转到EXTI9_5_IRQHandler这个中断处理函数中去,当然还需要判断到底是哪一个中断产生,通过查中断挂起寄存器就知道了。

       以下,假设将外部管脚PA0-5设置为外部中断,触发方式都为下降沿。

       第一步、中断源配置

       1、IO管脚配置

    首先是配置PA0-5这6个管脚为上拉输入,并且开启GPIOA的时钟。这里在这里配置就不说了,可以参考之前的点亮led。这个和S3C6410不一样,没有外部中断这一项,但是外部中断其实是属于输入的一种,所以就配置为输入就好了。上拉下拉就看IO的外部是怎么接的。

    开启时钟要多一个AFIO时钟,当IO作为其他功能使用,要开启辅助功能时钟。这个在APB2外设时钟使能寄存器(RCC_APB2ENR)中设置。

    clip_image079


         2、设置中断的触发方式

    配置中断触发方式,配置为下降沿。

     clip_image081

         所以最低6位也都设置为1。有下降沿寄存器,当然就有上升沿寄存器,但是这里不用上升沿,所以就不用配置了。


    第二步:中断控制器配置

          1、打开中断线请求

    clip_image083

    PA0-5对应中断线的0-5。这个寄存器的低6位就都要写入1。因为这里就只用到中断,事件屏蔽寄存器就不用管了。

    2、配置中断线选择哪一个IO组。

    clip_image084

    在中断线是将每个组的IO管脚通过选择器到外部中断线上。所以就需要配置具体是哪一组的管脚链接到外部中断线上了。


    clip_image086

     外部中断0-3选择的都是PA管脚,这个寄存器的低16位值为0x0000。同理,外部中断4,外部中断5也是一样的配置。


    第三步,编写中断处理函数

     STM32不向S3C6410那样,在进入前要保存下环境,退出要保存环境。这些都不用做了。直接写中断处理即可。中断处理完毕后,要将中断挂起位给清零掉,避免再次进入中断。

                  clip_image088

          这个寄存器就保存了各个中断线的请求,当处理完毕后,要将对应的位给清零。


          这样,就将STM32的外部中断给搞定了,但是真的搞定了吗?

    clip_image089

    中断的框图中,中断最终是到NVIC中断控制器的,并没有到CPU。这说明什么,还需要配置NVIC中断控制器了。


    NVIC中断控制器已经属于cortex-M3内核的部分了。从官方库文件的core_cm3.h文件中有NVIC的结构体。

    clip_image091

     以下是摘录STM32不完全手册-寄存器版本中的内容。

    ISER[8] : ISER全称是:Interrupt Set-Enable Registers,这是一个中断使能寄存器组。CM3内核支持256个中断,所以这里用8个32位寄存器来控制,每个位控制一个中断。但是STM32的可屏蔽中断最多只有68个(互联型),所以有用的就是三个(ISER[0~2]]),总共可以表示96个中断。而STM32只用了其中的前68位。ISER[0]的bit0~31分别对应中断0~31;              ISER[1]的bit0~32对应中断32~63;ISER[2]的bit0~3对应中断64~67;这样总共68个中断就分别对应上了。你要使能某个中断,必须设置相应的ISER位为1,使该中断被使能。

    ICER[8]:全称是:Interrupt Clear-Enable Registers,是一个中断除能寄存器组。该寄存器组与ISER的作用恰好相反,是用来清除某个中断的使能的。向对应位写1,就清除了该中断。

    ISPR[8]:全称是:Interrupt Set-Pending Registers,是一个中断挂起控制寄存器组。每个位对应的中断和ISER是一样的。通过置1,可以将正在进行的中断挂起,而执行同级或更高级别的中断。写0是无效的。

    ICPR[8]:全称是:Interrupt Clear-Pending Registers,是一个中断解挂控制寄存器组。其作用与ISPR相反,对应位也和ISER是一样的。通过设置1,可以将挂起的中断接挂。写0无效。

    IABR[8]:全称是:Interrupt Active Bit Registers,是一个中断激活标志位寄存器组。对应位所代表的中断和ISER一样,如果为1,则表示该位所对应的中断正在被执行。这是一个只读寄存器,通过它可以知道当前在执行的中断是哪一个。在中断执行完了由硬件自动清零。

    IP[240]:全称是:Interrupt Priority Registers,是一个中断优先级控制的寄存器组。这个寄存器组相当重要!STM32的中断分组与这个寄存器组密切相关。IP寄存器组由240个8bit的寄存器组成,每个可屏蔽中断占用8bit,这样总共可以表示240个可屏蔽中断。而STM32只用到了其中的68个。IP[67]~IP[0]分别对应中断67~0。而每个可屏蔽中断占用的8bit并没有全部使用,而是只用了高4位。这4位,又分为抢占优先级和子优先级。抢占优先级在前,子优先级在后。而这两个优先级各占几个位又要根据SCB->AIRCR中的中断分组设置来决定。


    STM32对中断分成了5组,组0-组4。该分组设置是由SCB->AIRCH的bit10~8寄存器来定义的。

    clip_image093


    在使用中断前。必须要设置一个中断分组。而且一个系统,只能有一个中断分组。抢占优先级值越小,其中断的优先级越高,抢占优先级相同的话,响应优先级值越低的,优先级越高。

            

    假设中断分组设置为2。那么就要往SCB->AIRCH的[10:4]写入101,也就是将2的取反的最后三位写入。但是写入这个寄存器,需要填入钥匙才能写进去。钥匙就是0x05FA。写入的值最高16位为0x05FA,才能将[10:8]的值写入。

    书中也提供了参考代码

    clip_image095

    下面就是要设置各个中断的开启以及设置优先级了。这个也提供了参考代码:

    clip_image097

    其实就是设置NVIC下的ISER和IP寄存器。对中断使能及设置优先级。这里要填入中断的编号。怎么样得知中断的编号是多少了,从STM32的手册就可以得到。

    clip_image099

     最前面一列就是中断号。EXTI线0中断编号就是6。

          

    假设,设置外部中断0-5的抢占优先级都是0,相应优先级从0-5。中断组为1。所以有1位抢占优先级,3位响应优先级。

     那么代码就是

    clip_image101

    这部分的配置相对比较麻烦,因为这个是属于内核的一部分。不过呢,我们开发的时候,都是使用库开发的,库将这些都已经封装好了,只需要调用库函数即可了。

    在库文件的misc.h文件中,就提供了函数。

    clip_image103

    这里,就用到前两个

    第一个设置中断分组,第二个对中断进行设置。具体,大家可以去看看代码就知道了。其实也不难。


    这样下来,才将STM32的外部中断给设置好了。


    总结

    对比下来,STM32的中断配置比S3C6410要复杂一些,因为要配置内核的NVIC。不过其他都是差不多一样的。

    最后来一个图比较

    clip_image105



    展开全文
  • 重要声明: 以下代码有粘贴 截取他人劳动成果的成分 如有...它能使CPU在运行过程中对外部事件发出的中断请求及时地进行处理,处理完成后又立即返回断点,继续进行CPU原来的工作。引起中断的原因或者说发出中断请求的

    重要声明: 以下代码有粘贴 截取他人劳动成果的成分 如有雷同 不胜荣幸 如您不能容忍 请不要独自忍受@weChat:iisssssssssii 联系小民 主动删除       

    中断含义: 

    {

    中断是CPU处理外部突发事件的一个重要技术。它能使CPU在运行过程中对外部事件发出的中断请求及时地进行处理,处理完成后又立即返回断点,继续进行CPU原来的工作。引起中断的原因或者说发出中断请求的来源叫做中断源。

           根据中断源的不同,可以把中断分为硬件中断和软件中断两大类,而硬件中断又可以分为外部中断内部中断两类

    硬件中断:

          外部中断:一般是指由计算机外设发出的中断请求如:键盘中断、打印机中断、定时器中断等。外部中断是可以屏蔽的中断,也是说,利用中断控制器可以屏蔽这些外部设备 的中断请求。

           内部中断:是指因硬件出错(如突然掉电、奇偶校验错等)或运算出错(除数为零、运算溢出、单步中断等)所引起的中断。内部中断是不可屏蔽的中断。 软件中断其实并不是真正的中断,它们只是可被调用执行的一般程

    软件中断:

    其实并不是真正的中断,它们只是可被调用执行的一般程例如:ROM BIOS中的各种外部设备管理中断服务程序(键盘管理中断、显示器管理中断、打印机管理 中断等,)以及DOS的系统功能调用(INT 21H)等都是软件中断

    }

    硬中断、软中断是怎么来的? :Linux 将中断 分为两个部分 

       上半部--》硬中断:完成紧急但很快完成的事 

       下半部:分为软中断、tasklet(当然它也是一种软中断)、工作队列(当然它也是一种软中断) 作用:处理不紧急但比较耗时间的事 

    重要是事:中断下半部的最早执行时间是中断上半部执行完之后 但是中断还没有完全返回之前 比如软中断

    完整过程:

    第一步:参考 http://blog.csdn.net/zqixiao_09/article/details/50927416 略

    第二步:参考 https://www.cnblogs.com/wmx-learn/p/5360269.html#undefined

    第三步:参考 http://blog.csdn.net/zhangskd/article/details/21992933

    第四步: 需要说明的是:

    /*----------------------------------------------**** 巩固 *****------------------------------------------------------*/

    1. 问:对于软中断,I/O操作是否是由内核中的I/O设备驱动程序完成?

    答:对于I/O请求,内核会将这项工作分派给合适的内核驱动程序,这个程序会对I/O进行队列化,以可以稍后处理(通常是磁盘I/O),或如果可能可以立即执行它。通常,当对硬中断进行回应的时候,这个队列会被驱动所处理。当一个I/O请求完成的时候,下一个在队列中的I/O请求就会发送到这个设备上。

    2. 问:软中断所经过的操作流程是比硬中断的少吗?换句话说,对于软中断就是:进程 ->内核中的设备驱动程序;对于硬中断:硬件->CPU->内核中的设备驱动程序?

    答:是的,软中断比硬中断少了一个硬件发送信号的步骤。产生软中断的进程一定是当前正在运行的进程,因此它们不会中断CPU。但是它们会中断调用代码的流程。

    如果硬件需要CPU去做一些事情,那么这个硬件会使CPU中断当前正在运行的代码。而后CPU会将当前正在运行进程的当前状态放到堆栈(stack)中,以至于之后可以返回继续运行。这种中断可以停止一个正在运行的进程;可以停止正处理另一个中断的内核代码;或者可以停止空闲进程。;

    一般硬中断 基本为中断的上半部分,软中断、tasklet、队列是中断的下半部分,将上半部分没有实现完的处理继续执行。

    中断下半部的处理

    对于一个中断,如何划分出上下两部分呢?哪些处理放在上半步,哪些放在下半部?

    这里有一些经验可供借鉴:

    如果一个任务对时间十分敏感,将其放在上半部。

    如果一个任务和硬件有关,将其放在上半部。

    如果一个任务要保证不被其他中断打断,将其放在上半部。

    其他所有任务,考虑放在下半部。

    实现下半部中断的三种机制

    目前使用下面三种方法:

    1.软中断

    2.tasklet

    3.工作队列

    软中断

    软中断是一组静态定义的下半部接口,有 32 个,可以在所有处理器上同时执行,类型相同也可以;在编译时静态注册。

    asmlinkage void do_softirq(void)
    {
        __u32 pending;
        unsigned long flags;
     
        /* 判断是否在中断处理中,如果正在中断处理,就直接返回 */
        if (in_interrupt())
            return;
     
        /* 保存当前寄存器的值 */
        local_irq_save(flags);
     
        /* 取得当前已注册软中断的位图 */
        pending = local_softirq_pending();
     
        /* 循环处理所有已注册的软中断 */
        if (pending)
            __do_softirq();
     
        /* 恢复寄存器的值到中断处理前 */
        local_irq_restore(flags);
    }

    代码之中第一次就判断是否在中断处理中,如果在立刻退出函数。这说明了什么?说明了如果有其他软中断触发,执行到此处由于先前的软中断已经在处理,则其他软中断会返回。所以,软中断不能被另外一个软中断抢占!唯一可以抢占软中断的是中断处理程序,所以软中断允许响应中断。虽然不能在本处理器上抢占,但是其他的软中断甚至同类型可以再其他处理器上同时执行。由于这点,所以对临界区需要加锁保护。

    软中断留给对时间要求最严格的下半部使用。目前只有网络,内核定时器和 tasklet 建立在软中断上。

    Tasklet

    注意,这第二种机制是基于软中断实现的,灵活性强,动态创建的下半部实现机制。两个不同类型的 tasklet 可以在不同处理器上运行,但相同的不可以,可以通过代码动态注册。

    在 SMP 上,调用 tasklet 是会检测 TASKLET_STATE_SCHED 标志,如果同类型在运行,就退出函数。

    tasklet 由于是基于软中断实现的,所以也允许响应中断。但不能睡眠(我认为不能睡眠原因是它们内部有 spin lock)。

    工作队列

    将下半部功能交由内核线程执行,有着线程上下文环境,可以睡眠。

    提供接口把需要推后执行的任务排列到队列里,提供默认的工作者线程处理排到队列里的下半部工作。

    工作队列实际上是一个链表,工作线程作为死循环,链表空时休眠,不空是执行每一个工作。

    各种机制的比较

    下半部 上下文 顺序执行保障
    软中断 中断 随意,同类型都可以在不同处理器同时执行
    tasklet 中断 同类型不能同时执行
    工作队列 进程 不保障,可能被调度和抢占

    选择:

    - 工作队列:适用于任务推后到进程上下文完成,可以休眠

    - tasklet:任务接口简单,支持中断响应,但有同种类型不能同时执行的限制

    - 软中断:提供的执行顺序保障最少,支持中断响应,由于同类型软中断在其他处理器可同时执行,所以要采取措施保护共享数据。


    linux的驱动程序分两个部分实现:top-half和bottom-half。
    top-half在运行时,不能被其他任何中断再次中断,也不能被其他进程中断,它通过对CPU内的中断屏蔽置位实现,而bottom-half则只对top-half开中断。
    这样,系统就可以根据中断服务程序的访问特点,安排那些访问临界区的服务程序为top-half,其他中断服务程序为bottom-half。

    每次离开中断处理程序,系统会执行schedule(),发生进程调度。




    
    
    
    
    展开全文
  • ESP8266--外部中断

    千次阅读 2018-10-07 12:50:26
    外部中断只针对于输入设备,当设备输入时的IO口电平发送变化时,调用相对应的IO的外部中断函数或者寄存器就会进入到IO口的外部中断控制。 当配置完成时,加入需要对外部IO口变化之后进行操作时,通常的单片机需要...

    GPIO外部中断

    外部中断只针对于输入设备,当设备输入时的IO口电平发送变化时,调用相对应的IO的外部中断函数或者寄存器就会进入到IO口的外部中断控制。
    当配置完成时,加入需要对外部IO口变化之后进行操作时,通常的单片机需要外部中断服务函数控制,但是我们的ESP8266单片机不需要外部中断服务函数,它需要的是一个回调函数,而且它的回调函数是需要声明的。

    GPIO外部中断相关API函数

    ETS_GPIO_INTR_ATTACH()函数

    函数原型:ETS_GPIO_INTR_ATTACH(func, arg)
    #define ETS_GPIO_INTR_ATTACH(func, arg)  ets_isr_attach(ETS_GPIO_INUM, (func), (void *)(arg))
    void ets_isr_attach(int i, ets_isr_t func, void *arg);
    
    函数功能:注册GPIO中断处理函数`在这里插入代码片`
    函数形参:
              func:中断服务函数名称
              arg:
    返回值:无
    例子:ETS_GPIO_INTR_ATTACH(KeyExtiInterruptFunction, NULL);
    

    ETS_GPIO_INTR_DISABLE()函数

    函数原型:ETS_GPIO_INTR_DISABLE()
    函数功能:关闭GPIO中断功能
    函数形参:无
    返回值:  无
    

    ETS_GPIO_INTR_ENABLE()函数

    函数原型:ETS_GPIO_INTR_ENABLE()
    函数功能:打开GPIO中断功能
    函数形参:无
    返回值:  无
    

    gpio_pin_intr_state_set()函数

    函数原型:void gpio_pin_intr_state_set(uint32 i, GPIO_INT_TYPE intr_state)
    函数功能:设置GPIO中断出发状态
    函数形参:
              uint32 i:GPIO引脚的ID
    可填参数:GPIO_ID_PIN(x)  //x表示要设置的引脚号
              GPIO_INT_TYPE intr_state:中断触发方式;
              GPIO_PIN_INTR_DISABLE = 0   //不触发中断
              GPIO_PIN_INTR_POSEDGE = 1  //上升沿触发中断
              GPIO_PIN_INTR_NEGEDGE = 2  //下降沿触发中断
              GPIO_PIN_INTR_ANYEDGE = 3  //双边沿触发中断
              GPIO_PIN_INTR_LOLEVEL = 4   //低电平触发中断
              GPIO_PIN_INTR_HILEVEL = 5,   //高电平触发中断
    以上形参定义在一枚举类型里面
    返回值:无
    例子:gpio_pin_intr_state_set(GPIO_ID_PIN(0), GPIO_PIN_INTR_NEGEDGE);//设置GPIO0为下降沿触发进入中断
    

    GPIO_REG_READ()函数

    函数原型:GPIO_REG_READ(reg)
    	以上函数为宏定义:
    		#define GPIO_REG_READ(reg)  READ_PERI_REG(PERIPHS_GPIO_BASEADDR + reg)
    		#define PERIPHS_GPIO_BASEADDR               0x60000300
    		#define READ_PERI_REG(addr) (*((volatile uint32_t *)ETS_UNCACHED_ADDR(addr)))
    		#define ETS_UNCACHED_ADDR(addr) (addr)
    函数功能:获取GPIO中断状态
    函数形参:
    	reg:乐鑫官方文档提供的地址形参为GPIO_STATUS_ADDRESS
    		#define GPIO_STATUS_ADDRESS          	0x1c
        返回值:所有GPIO口的中断状态
    官方举例:
    	uint32 gpio_status;
    	gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS);
    注:官方标明该文件必须添加在GPIO中断处理函数内
    

    GPIO_REG_WRITE()函数

    函数原型:GPIO_REG_WRITE(reg, val) 
    	以上函数为宏定义:
    		#define GPIO_REG_WRITE(reg, val) WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + reg, val)
    		#define PERIPHS_GPIO_BASEADDR               0x60000300
    		#define WRITE_PERI_REG(addr, val) (*((volatile uint32_t *)ETS_UNCACHED_ADDR(addr))) = (uint32_t)(val)
    		#define ETS_UNCACHED_ADDR(addr) (addr)
    函数功能:清除GPIO中断状态->退出中断
    函数形参:
    	reg:乐鑫官方文档提供的地址形参为GPIO_STATUS_ADDRESS
    	val:GPIO_REG_READ()函数的返回值
    返回值:无
    官方举例:GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status);
    

    GPIO中断寄存器

    中断状态寄存器GPIO_STATUS

    在这里插入图片描述

    清中断寄存器GPIO_STATUS_W1TC

    在这里插入图片描述

    参考代码

    //user_mian.c源代码
    void ICACHE_FLASH_ATTR user_init(void)
    {
    	system_soft_wdt_feed();//喂软件看门狗,防止程序跑偏
    	uart_init(9600, 9600);//设置串口波特率
    	LedInitConfig();//LED灯初始化函数
    	KeyInitConfig();//按键初始化函数
    	KeyExtiInitConfig();//配置按键外部中断
    	os_printf("=============================================\r\n");
    	os_printf("\t SDK version:\t%s", system_get_sdk_version());
    	os_printf("\r\n嵌入式陈工个人编辑资料\r\n未经本人同意请勿私自传播\r\n");
    	os_printf("\r\n按键外部中断测试代码\r\n");
    	os_printf("\r\n带看门狗\r\n");
    	os_printf("=============================================\r\n");
    }
    
    //key.c源代码
    /*
    * key.c
    *
    *  Created on: 2018年8月10日
    *      Author: 小良哥
    */
    
    #include "driver/key.h"
    #include "driver/led.h"
    #include "ets_sys.h"			// 回调函数
    
    void KeyInitConfig(void)
    {
    	//1.设置按键所对应的GPIO0口为IO口模式 -- 详见文档3.3.1.1章节
    	PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0);	// GPIO0设为IO口
    	//2.由于GPIO0通过R3进行电源上拉,所以GPIO0默认为高电平状态,在这里要将内部拉高取消
    	PIN_PULLUP_DIS(PERIPHS_IO_MUX_GPIO0_U);
    	//3.设定GPIO0引脚为输入模式
    	GPIO_DIS_OUTPUT(GPIO_ID_PIN(0));
    }
    
    void KeyExtiInitConfig(void)
    {
    	//1.关闭GPIO中断
    	ETS_GPIO_INTR_DISABLE();
    	//2.注册中断回调函数
    	ETS_GPIO_INTR_ATTACH((ets_isr_t)KeyExtiInterruptFunction, NULL);
    	//3.设置外部中断IO口以及触发方式
    	gpio_pin_intr_state_set(GPIO_ID_PIN(0), GPIO_PIN_INTR_NEGEDGE);	// GPIO_0下降沿中断
    	//4.打开GPIO中断
    	ETS_GPIO_INTR_ENABLE();
    }
    
    //按键外部中断服务函数--需要函数声明
    void KeyExtiInterruptFunction(void)
    {
    	static i = 1;
    	uint32 gpio_status;
    	uint32 GpioFlag;
    	//1.读取GPIO中断状态
    	gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS);
    	//2.清除中断状态位
    	GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status);
    	//3.判断按键的中断状态
    	GpioFlag = gpio_status & (0x01 << 0);
    	os_printf("\r\n进入中断\r\n");
    	if (GpioFlag == 1)
    	{
    		LED(i);
    		i = !i;
    		os_printf("\r\n按下按键\r\n");
    	}
    }
    
    //key.h源代码
    /*
    * key.h
    *
    *  Created on: 2018年8月10日
    *      Author: 小良哥
    */
    
    #ifndef APP_INCLUDE_DRIVER_KEY_H_
    #define APP_INCLUDE_DRIVER_KEY_H_
    
    #include "ets_sys.h"
    #include "osapi.h"
    #include "user_interface.h"
    #include "driver/uart.h"
    #include "gpio.h"
    #include "eagle_soc.h"
    #include "driver/delay.h"
    
    void KeyInitConfig(void);
    void KeyExtiInitConfig(void);
    void KeyExtiInterruptFunction(void);
    #define KEY (!!(GPIO_INPUT_GET(GPIO_ID_PIN(0))))
    
    #endif /* APP_INCLUDE_DRIVER_KEY_H_ */
    

    源代码参考:https://github.com/ChenJiliang00/ESP8266

    展开全文
  • F2812 外部中断及其中断问题

    千次阅读 2013-03-07 14:18:35
    F2812的外部中断,只有三个外接引脚,分别是XINT1、2、13,每个中断都可以选择上升沿触发或者是下降沿触发,同时还可以选择使能/禁止状态。书上是这样描述这三个中断的:F2812支持3个隐藏的外部中断(XINT1,2,13),...

     

      F2812的外部中断,只有三个外接引脚,分别是XINT1、2、13,每个中断都可以选择上升沿触发或者是下降沿触发,同时还可以选择使能/禁止状态。书上是这样描述这三个中断的:F2812支持3个隐藏的外部中断(XINT1,2,13),XINT13还和一个没有隐藏的外部中断(XNMI)连接在一起,他们一起组成的信号称为XNMI-XINT13。疑问:为什么称这三个外部中断为隐藏的中断呢?这三个中断对应的三个引脚是XINT1->149,XINT2->151,XINT13->150。

        

        为了防止CPU的误操作,许多寄存器都通过EALLOW来保护,中断向量列表寄存器就是其中之一,中断向量列表(PIE Vector Table)。中断向量列表寄存器包括哪一些东西详见《TMS320F2812原理及其C语言程序开发》一书。当然有讲F2812的书或者是其他应用文档手册里都应该能找到。

      

        PIE是什么,翻译成中文确切的是什么我也不知道,当作外设中断扩展模块来理解吧,反正是和中断有关的一个名词来理解吧。书上的东西讲的比较全面,但是实际用起来和理解起来都感觉非常不方便,我就凭着自己的理解和书上的内容,写一下最相关的外部中断部分吧。再在实践中来修正和加深理解。

     

        PIE一共有96个独立的中断,分成12组,每一组8个,从PIE的向量列表中可以查阅到每一个存放中断服务程序的地址。中断服务程序(ISR)。可以看到这些中断的地址和作用在中断向量列表中已经一一对应了,包括EV事件,SCI,SPI,ECAN等,还有众多的保留端口,由于我还没有用过,就不讨论这些端口的作用了。只关注要用的部分,我准备做一个上升沿触发的中断,所接受的信号来自前端器件。

     

        我选择了外部中断1(XINT1),其对应的PIE列表中的位置为第1组的第4位,向量ID号为35,地址为0x0000 0D46,占用空间为32bit,CPU优先级为5,PIE分组优先级为4.

     

        中断分为外设级中断,PIE级中断和CPU级中断,刚看的时候感觉云里雾里的,多看了两遍之后才有一点点明白。有一个中断来了,是什么样的中断,外设中断还是外部中断?好,先到了外设级中断,在PIE中竖起了标志(PIEIFRx.y),将该中断位使能(PIEIERx.y),硬件置位(PIEACKx),然后就将中断请求发送到了CPU,进行CPU级的中断处理了。在CPU中也是线树立标志(IFRx),使能(IERx),还要树立一个全局中断屏蔽位(INTM),以防止其他的中断产生,这些链路都建立起来之后,好的可以相应中断了。从我的理解上是这样的,实际上呢?还会不会有什么出入,待定,等做了试验之后再来补充吧。

    展开全文
  • 外部中断的使用

    千次阅读 2015-08-17 14:25:04
    STM32学习笔记:外部中断的使用  中断对于开发嵌入式系统来讲的地位绝对是毋庸置疑的,在C51单片机时代,一共只有5个中断,其中2个外部中断,2个定时/计数器中断和一个串口中断,但是在STM32中,中断数量大大增加...
  • 如果是下降沿触发,当从高至低电平转变时,触发产生;低电平保持多久都只产生一次。所以,边沿触发适合与以负脉冲形式输入的外部...所以,电平触发方式适合于外部中断以低电平输入而且中断服务能清除外部中断源的情况
  • STM32外部中断使用方法
  • 6.0 外部中断控制LED灯

    千次阅读 2014-07-02 22:07:04
    实例4---外部中断控制LED灯-----程序目的:学会如何配置外部中断 硬件与实例3一致,仅KEY1有外部中断能力,单片机的P1与P2口具有第二功能就是外部中断,并且一个端口的所有IO共用一个中断向量,说白了就是一个中断...
  • S3C6410中断以及外部中断

    千次阅读 2011-12-12 15:27:57
    6410的中断系统: 嵌入式软件里的中断处理...而且在物理上CPU分离的芯片产生的中断,称为外部中断外部中断可以联接不同的中断脚上,因此需要对中断IO进行较复杂的配置。    轮询模式是否一无是处?轮询的优
  • STM32开发 -- 外部中断详解

    千次阅读 2019-02-18 10:44:27
    未完待续!! 在讲三轴加速度计的时候,提到外部中断。接下来就看看中断为什么这么配置。
  • STM32上的外部中断

    千次阅读 2018-05-31 13:37:47
    今天记录一下关于外部中断的知识点以及在32上外部中断的相关寄存器以及配置的流程。一、原理介绍 首先,什么是中断 中断就是将正在做的事情停下来,先去完成另外一件事情,完成后继续回来做这件事。 比如:在吃饭...
  • stm32hal库之外部中断巨坑,如果使用按键外部中断会导致频繁触发中断,从而不能退出中断,导致卡死 void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin) { /* EXTI line interrupt detected */ if(__HAL_GPIO_EXTI_...
  • uCOS_II系统实操_外部中断

    千次阅读 2016-12-28 18:11:01
    uCOS_II 的外部中断配置
  • stm8l051 halt之后外部中断唤醒问题

    万次阅读 2016-01-26 08:34:09
    最近用到stm8l051 halt,在halt之后开启了外部中断,有时灵,有时不灵,发现下降沿触发,但是按键(低有效)放开了才会从HALT退出,最后发现在进去外部中断的时候一直在外部中断里面不退出,在外部中断程序里面把...
  • stm32f103ZET6外部中断控制led灯

    千次阅读 2020-08-05 19:27:20
    stm32f103zet6外部中断控制led灯 目录stm32f103zet6外部中断控制led灯stm32f103zet6外部中断控制led灯led端口定义按键端口定义按键中断的配置中断的配置个人笔记延时函数 stm32f103zet6外部中断控制led灯 led端口...
  • 前面我们学习了ATmega8的I/O口作为通用数字输入/输出口来用时对LED数码管控制和扫描按键的应用;... PD2端口是外部中断源0,PD3端口是外部中断源1。ATmega8的外部中断就是由这两个引脚触发的。 *要注意的是:...
  • TQ2440裸机中断(外部中断)

    千次阅读 2013-05-31 14:51:23
    1.所谓中断,是指CPU在正常运行程序时,由于内部/外部事件或由程序预先安排的事件,引起CPU中断正在运行的程序,而转到为内部/外部事件或为预先安排的事件服务的中断程序中去,服务完毕,再返回去执行刚才被中断的...
  • 51单片机之外部中断应用实例(电平触发、边沿触发)

    万次阅读 多人点赞 2019-05-15 15:10:32
    硬件:STC89C52RC 开发工具:Keil uVision4 前言:8051是一款很经典的、历史悠久的单片机,作为一款入门级的...下面详细讲述外部中断功能的使用。 外部中断:单片机提供的系统紧急事件的输入控制。事件触发的方式...
  • 然后利用32的外部中断和定时器来测量32输出的波形 硬件:STM32F103C8T6核心板、示波器、串口调试助手 所用到的的引脚为PA8和PA0。 测量方案 在第一次外部中断(上升沿触发)到之时,开启定时器,同时计数器清零。然后...
  • 如果是下降沿触发,当从高至低电平转变时,触发产生;低电平保持多久都只产生一次。所以,边沿触发适合与以负脉冲形式输入的外部...所以,电平触发方式适合于外部中断以低电平输入而且中断服务能清除外部中断源的情况
  • 版权声明:本文为CSDN博主「menghuanshen」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 ...————————————————...最近在调试按键作为外部中断exti进行触发动作,发现每次...
  • 关于51单片机外部中断的触发方式

    万次阅读 2016-01-25 11:47:55
    51单片机有两个外部中断申请输入端:INT0 和 INT1。51单片机的外部中断,分为低电平触发和下降沿触发。在单片机内部,分别由控制位 IT0 和 IT1 来控制。复位时,IT0/1 都为 0,即默认为低电平触发。一般来说,外设第...
  • 外部中断可以分为电平触发和边缘触发两种,那么这两种中断有什么区别,我们今天讲解下 1什么是中断 CPU在处理某一事件A时,发生了另一事件B请求CPU迅速去处理(中断发生); CPU暂时中断当前的工作,转去处理...
  • 外部中断流程: io口初始化(包括时钟); 调用HAL_NVIC_SetPriority函数设置优先级,调用HAL_NVIC_EnableIRQ函数使能各中断线; 编写EXTI0_IRQHandler函数,在函数中调用HAL_GPIO_EXTI_IRQHandler; 在函数HAL_...
  • 今天我们会详细的带你学习STM32CubeMX配置外部中断,并且讲解HAL库的GPIO的各种函数,带你学习不一样的STM32 如果还没有配置过工程,请参看上一篇博客《STM32CubeMX教程二--基本使用(新建工程点亮LED灯)》 那么话...
  • stm32 外部中断 按键的误触发

    千次阅读 2019-04-20 22:40:14
    最近在调试按键作为外部中断exti进行触发动作,发现每次按键按下和按键抬起都会多次进入中断函数,造成程序不稳定,经过反复调试和查阅资料,最后终于已经把这个问题解决,现在总结一下: 1、EXTI重复配置两次导致...
  • 51单片机有两个外部中断,分别为INT0(P32)与INT1(P33),INT0对应中断编号为interrupt 0,INT1对应中断编号为interrupt 2; 外部中断配置过程主要如下:1.打开总中断EA,置1开启;2.打开外部中断EX0,置1开启;3.配置...
  • 20190428-stm32外部中断(按键)

    千次阅读 2019-04-28 21:45:11
    void EXTI0_IRQHandler (void) //中断服务函数 进行中断时的执行程序 比如灯亮 { static char n=1; // static静态变量 只初始化一次 且n=1,按第一下就亮 delay_us(100); //按键防抖 if(!(GPIOA->IDR & 1<...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 47,840
精华内容 19,136
关键字:

怎么退出外部中断