打印
[学习资料]

中断的介绍和习题分析

[复制链接]
412|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2022-4-28 11:55 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
中断的介绍
什么是中断?官方定义:正常程序运行时发生了事先设定的事件,需要暂停原来运行的程序而转到处理目前,需要马上处理的事件。 对于大部分没有接触过计算机原理的人来说都是很陌生的。下面我们来举一个很简单的例子。
有一天,小强刷着手机走在路上,这时候小强的鞋带开了,这时候小强把手里的手机交给小强旁边的瑶瑶,瑶瑶替小强拿着,小强去系鞋带,系完鞋带,小强再从瑶瑶手里拿回手机。在这个过程中,小强停下刷手机,系鞋带,拿回手机这一个过程就叫做中断过程。
中断过程分为几个:首先有触发事件(在单片机中这个事件需要你提前定义,否则它不能判断是不是属于中断事件),也就是例子中鞋带开了。其次它需要一个可返回性,也就是系鞋带后再拿回手机这一个过程。这时候就需要我们的一个老朋友就是堆栈(记住是堆栈,而不是堆也不是单纯的栈),之前说过它是一个类似弹夹的东西,也就是先入后出,后入先出的结构。他就可以帮助我们暂时的存储我们中断的事情,也就是例子中的瑶瑶。发生中断后,PC(程序计数器)就会指向0004H也就是中断向量。执行中断事件发生后,你所需要执行的任务。执行完后,再从堆栈中取回刚才被中断的事情的地址值给PC,继续执行程序。具体的过程,如下图:

这里的GIE相当于中断事情发生的标识符,当你调试程序的时候你可以通过查询GIE观察中断是否发生。
GIE介绍:总的中断允许位(当GIE=0的时候,所有中断事件(称为中断源)都没法引起中断程序的发生,只有当GIE=1的时候,中断事件(称为中断源)才有可能引起中断程序。类比卵细胞膜反应和透明带反应,阻止其他中断事件继续进入中断程序)
具体的物理结构可以看下面的图

注意:可以看到图中字母结尾有E和F的,E就是使能端口(类似数电中三态门中的使能端口EN),F是标志位(Flag)当标志位为1时候,说明中断源发出中断的信号,这个1需要你手动复位为0,相当于每次中断程序执行的时候,GIE会自动复位,而这个标志位不会,需要你每次手动操作。
下面是几个重要的寄存器的使用图:
1.中断控制寄存器(interrupt control register缩写:INTCON)

2.第一外围寄存器
使能寄存器

标志位控制

3.第二外围寄存器
使能

标志位


注意:如果你要使用RB0即外部中断(RB0/INT)的中断边沿选择,需要用到一个之前学过的寄存器与中断直接相关的位为INTEDG。0为下降沿

复习一下,第一位那个表示B口弱上拉允许位,1为禁止。注意这里如果要设置弱上拉,请用OPTION_REG去设置,而不能直接用RBPU去设置。
注意:中断不允许嵌套执行,也就是递归使用!!!

作业:

在RB0上接开关,PORTD端口接8盏灯,利用RB0/INT中断的方式实现开关打开时,PORTD奇数端口接的灯亮;开关闭合时,PORTD偶数端口接的灯亮。利用中断完成这个作业!!!请自己先尝试一下,再看看,这道题目前存在两种主要的解法。加油!!!
电路图如下:


/*

* File:   demo04.c

* Author: Xueziqiang

*

* Created on 2022年3月19日, 下午11:01

*/

// PIC16F887 Configuration Bit Settings


// 'C' source line config statements


// CONFIG1

#pragma config FOSC = XT        // Oscillator Selection bits (XT oscillator: Crystal/resonator on RA6/OSC2/CLKOUT and RA7/OSC1/CLKIN)

#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled and can be enabled by SWDTEN bit of the WDTCON register)

#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)

#pragma config MCLRE = OFF      // RE3/MCLR pin function select bit (RE3/MCLR pin function is digital input, MCLR internally tied to VDD)

#pragma config CP = OFF         // Code Protection bit (Program memory code protection is disabled)

#pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)

#pragma config BOREN = OFF      // Brown Out Reset Selection bits (BOR disabled)

#pragma config IESO = OFF       // Internal External Switchover bit (Internal/External Switchover mode is disabled)

#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is disabled)

#pragma config LVP = OFF        // Low Voltage Programming Enable bit (RB3 pin has digital I/O, HV on MCLR must be used for programming)


// CONFIG2

#pragma config BOR4V = BOR40V   // Brown-out Reset Selection bit (Brown-out Reset set to 4.0V)

#pragma config WRT = OFF        // Flash Program Memory Self Write Enable bits (Write protection off)


// #pragma config statements should precede project file includes.

// Use project enums instead of #define for ON and OFF.

//在RB0上接开关,PORTD端口接8盏灯,利用RB0/INT中断的方式实现开关打开时,PORTD奇数端口接的灯亮;开关闭合时,PORTD偶数端口接的灯亮。

#include <xc.h>

void DELAY(unsigned int n);

void __interrupt()ISR(void);

void main(void) {  

    //端口初始化,在使用端口前需要对端口进行初始化设定

    TRISD=0B00000000; // 端口D全部定义为输出口 0为输出

    PORTD=0; // 初始状态下,灯全部熄灭

    TRISB=0b00000001; // 端口B定义  RB0为输入口,其他随意,没有使用到

    ANSEL=0;  //定义低八位对应为数字量输入  详细可查询IO口的**

    ANSELH=0;  //定义高八位对应为数字量输入  详细可查询IO口的**

    OPTION_REG=0b10000000;    //禁止弱上拉,并设置为下降沿中断

    //这里我使用到的是RB0/INT外部事件触发的中断,这里需要将这个口(第五位)的使能端打开 如果你使用其他的使能口,那就打开其他的使能口。//第二种方法用到是RB口电平变化,这时候就打开第四位的使能

    INTCON=0b10010000; //注意第八位为全局中断使能,需要打开(为1)

    /*/下面是对灯进行初始化,有人问为什么?原因在于,刚开始,你不知道开关的状态是什么,所以后面灯亮就很可能是随机的,不符合题目的要求。

     * 这时候就要对灯也进行按照开关的状态进行初始化。

     * 最前面对灯的初始化(PORTD=0;)是一个普遍的初始化,即没有建立灯与输入口的逻辑关系

     */

    if(RB0==1){  

        PORTD=0b01010101;//开关打开,此时奇数灯亮 记住端口RD0对应是最右边的那一位。不要搞反了!!!

        INTEDG=0;//将端口触发状态设置为下降沿,因为此时开关是断开的,RB0处在高电平,当中断事件(开关闭合,RB0等于低电平)这时候是下降沿过程,所以触发的方式就应该设置为下降沿

    }

    else{

        PORTD=0b10101010;//偶数

        INTEDG=1;//将端口触发状态设置为上升沿,因为此时开关是闭合的,RB0处在低电平,当中断事件(开关闭合,RB0等于高电平)这时候是上升沿过程,所以触发的方式就应该设置为上升沿

    }

    while(1); //让程序等待,等待外部中断事件的发生

    return;

   

}

void DELAY(unsigned int n)

{   unsigned int j;

    char k;

for (j=0;j<n;j++){   

    for (k=1;k>0;k--) NOP();//延时语句,NOP()意思是啥也不做 但是也需要占据一个指令周期

    }

   

}

void __interrupt()ISR(void){

    if(INTF==1){ //外部事件中断标志位为1,意味着这时候发生了外部中断

        DELAY(100); //延迟,对于按钮开关起到防止抖动的作用。这里其实可以省略

        INTF=0;  //!!!一定要注意,一定要把标志位复位

        if(RB0==0){

             PORTD=0b10101010;  

             INTEDG=1;//将端口触发状态设置为上升沿,因为此时开关是闭合的,RB0处在低电平,当中断事件(开关闭合,RB0等于高电平)这时候是上升沿过程,所以触发的方式就应该设置为上升沿

        }

        else{

            PORTD=0b01010101;

            INTEDG=0;//将端口触发状态设置为下降沿,因为此时开关是断开的,RB0处在高电平,当中断事件(开关闭合,RB0等于低电平)这时候是下降沿过程,所以触发的方式就应该设置为下降沿

        }

    }  

    }



使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2186

主题

16505

帖子

17

粉丝