单片机中断系统

单片机中断系统

中断的概念:

CPU在处理某一事件A时,发生了另一事件B请求CPU迅速去处理(中断发生);CPU暂时中断当前的工作,转去处理事件B(中断响应和中断服务);待CPU将事件B处理完毕后,再回到原来事件A被中断的地方继续处理事件A(中断返回),这一过程称为中断 。

随着计算机技术的应用,人们发现中断技术不仅解决了快速主机与慢速I/O设备的数据传送问题,而且还具有如下优点:

分时操作。 CPU可以分时为多个I/O设备服务,提高了计算机的利用率;

实时响应。 CPU能够及时处理应用系统的随机事件,系统的实时性大大增强;

可靠性高。 CPU具有处理设备故障及掉电等突发性事件能力,从而使系统可靠性提高。

1、(P3.2)可由IT0(TCON.0)选择其为低电平有效还是下降沿有效。当CPU检测到P3.2引脚上出现有效的中断信号时,中断标志IE0(TCON.1)置1,向CPU申请中断。

2、(P3.3)可由IT1(TCON.2)选择其为低电平有效还是下降沿有效。当CPU检测到P3.3引脚上出现有效的中断信号时,中断标志IE1(TCON.3)置1,向CPU申请中断。

3、TF0(TCON.5),片内定时/计数器T0溢出中断请求标志。当定时/计数器T0发生溢出时,置位TF0,并向CPU申请中断。

4、TF1(TCON.7),片内定时/计数器T1溢出中断请求标志。当定时/计数器T1发生溢出时,置位TF1,并向CPU申请中断。

5、RI(SCON.0)或TI(SCON.1),串行口中断请求标志。当串行口接收完一帧串行数据时置位RI或当串行口发送完一帧串行数据时置位TI,向CPU申请中断。

中断允许控制

EX0(IE.0),外部中断0允许位;

ET0(IE.1),定时/计数器T0中断允许位;

EX1(IE.2),外部中断0允许位;

ET1(IE.3),定时/计数器T1中断允许位;

ES(IE.4),串行口中断允许位;

EA (IE.7), CPU中断允许(总允许)位。

中断请求标志

IT0(TCON.0),外部中断0触发方式控制位。

          当IT0=0时,为电平触发方式。

          当IT0=1时,为边沿触发方式(下降沿有效)。

IE0(TCON.1),外部中断0中断请求标志位。

IT1(TCON.2),外部中断1触发方式控制位。

IE1(TCON.3),外部中断1中断请求标志位。

TF0(TCON.5),定时/计数器T0溢出中断请求标志位。

TF1(TCON.7),定时/计数器T1溢出中断请求标志位。

中断优先级

中断源

定时/计数器

51单片机定时/计数器的工作由两个特殊功能寄存器控制。TMOD用于设置其工作方式;TCON用于控制其启动和中断申请。

工作方式寄存器TMOD

  工作方式寄存器TMOD用于设置定时/计数器的工作方式,低四位用于T0,高四位用于T1。其格式如下:

GATE是门控位, GATE=0时,用于控制定时器的启动是否受外部中断源信号的影响。只要用软件使TCON中的TR0或TR1为1,就可以启动定时/计数器工作;GATA=1时,要用软件使TR0或TR1为1,同时外部中断引脚INT0/1也为高电平时,才能启动定时/计数器工作。即此时定时器的启动条件,加上了INT0/1引脚为高电平这一条件。

     C/T :定时/计数模式选择位。C/T =0为定时模式;C/T =1为计数模式。

     M1M0:工作方式设置位。定时/计数器有四种工作方式。

控制其启动和中断申请TCON

TCON的低4位用于控制外部中断,已在前面介绍。TCON的高4位用于控

制定时/计数器的启动和中断申请。其格式如下:

TF1(TCON.7):T1溢出中断请求标志位。T1计数溢出时由硬件自动置TF1为1。CPU响应中断后TF1由硬件自动清0。T1工作时,CPU可随时查询TF1的状态。所以,TF1可用作查询测试的标志。TF1也可以用软件置1或清0,同硬件置1或清0的效果一样。

TR1(TCON.6):T1运行控制位。TR1置1时,T1开始工作;TR1置0时,T1停止工作。TR1由软件置1或清0。所以,用软件可控制定时/计数器的启动与停止。

TF0(TCON.5):T0溢出中断请求标志位,其功能与TF1类同。

TR0(TCON.4):T0运行控制位,其功能与TR1类同。

TLx与THx之间的搭配关T0(TL0-0x8A,TH0-0x8C), T1(TL1-0x8B,TH1-0x8D)

1)、TLx与THx之间32进制。即当TLx计到32个脉冲时,TLx归0同时THx进1。这也称为方式0。

2)、TLx与THx之间256进制。即当TLx计到256个脉冲时,TLx归0同时THx进1。这也称为方式1。在方式1时,最多计65536个脉冲产生溢出。在主频为11.0592M时,每计一个脉冲为1.085us,所以溢出一次的时间为1.085usx65536=71.1ms。

3)、THx用于存放TLx溢出后,TLx下次计数的起点。这也称为方式2。

4)、THx与TLx分别独立对自己的输入脉冲计数。这也称为方式3。

5、定时器初始化

1)、确定定时器的计数模式。

2)、确定TLx与THx之间的搭配关系。

3)、确定计数起点值。即TLx与THx的初值。

STC单片机STC89C52RC定时器延时时间的计算

延时时间要根据晶振频率计算,不同板子可能有所不同。

时钟周期:
1/时钟源,在我现在这块板子上,晶振频率是11.0592M,也就是时钟周期是 1/11059200秒

机器周期:
一般51单片机是12个时钟周期,我的板子也就是 12/11059200秒

单次定时最长时间:
如果是16位的计数器,16位最大值是65535,共可计数65536次。基本的常数一定要记住,还要记住8位最大值是255,共可计数256次,还要记住8位上每位代表的数值。
12 * 65536/11059200 = 0.0711 s,也就是,71 ms内的定时可以单次定时就完成。如果定时时间超过71 ms,就要循环了。

一次定时需要几次机器周期:
计算公式:定时秒数/机器周期
比如我要定时1秒, 1/(12/11059200)= 921600次,16位计数器最大可计数65536次,921600次早就益出了。我们可以每次定时10 ms,循环100次就可以定时1秒了,1 s缩小100百倍就是10 ms, 也就是每次需要计数9216次。

确实计数器初始值:
定时10 ms时,如果计数器从0开始计数,我们就不知道什么时候到了9216次。所以应该计数了9216次,16位计数器最多计数95536次,然后就溢出,一溢出TCON的TF位就会置1,我们只要经常检测TF位就可以知道什么时候完成10ms的定时了。
计算公式:计数器初始值=最大计数次数 - 需要计数次数
如果定时10 ms,计数器的初始值就是 65536 - 9216

计算计数器的高位和低位:
16位的计数器,也就是两个8位组成,8位的最大计数次数是256。所以:
计数器高位 = 初始值/256
计数器低位 = 初始值%256

例如:

设置 外部中断0

#include "reg52.h"                      //此文件中定义了单片机的一些特殊功能寄存器

typedef unsigned int u16;    //对数据类型进行声明定义

typedef unsigned char u8;

sbit k3=P3^2;  //定义按键K3

sbit led=P2^0;     //定义P20口是led

void delay(u16 i)

{

    while(i--);

}

void Int0Init()

{

    //设置INT0

    IT0=1;//跳变沿出发方式(下降沿)

    EX0=1;//打开INT0的中断允许。

    EA=1;//打开总中断       

}

void main()

{  

    Int0Init();  //  设置外部中断0

    while(1);         

}

void Int0()    interrupt 0               //外部中断0的中断函数

{

    delay(1000);    //延时消抖

    if(k3==0)

    {

            led=~led;

    }

}

例如:

设置 定时器0

#include "reg52.h"                      //此文件中定义了单片机的一些特殊功能寄存器

typedef unsigned int u16;    //对数据类型进行声明定义

typedef unsigned char u8;

sbit led=P2^0;     //定义P20口是led

void Timer0Init()

{

    TMOD|=0X01;//选择为定时器0模式,工作方式1,仅用TR0打开启动。

    TH0=0XFC;       //给定时器赋初值,定时1ms

    TL0=0X18;      

    ET0=1;//打开定时器0中断允许

    EA=1;//打开总中断

    TR0=1;//打开定时器                     

}

void main()

{  

    Timer0Init();  //定时器0初始化

    while(1);         

}

void Timer0() interrupt 1

{

    static u16 i;

    TH0=0XFC;       //给定时器赋初值,定时1ms

    TL0=0X18;

    i++;

    if(i==1000)

    {

            i=0;

            led=~led;

    }      

}

例如

交通灯

#include "reg52.h"                      //此文件中定义了单片机的一些特殊功能寄存器

typedef unsigned int u16;    //对数据类型进行声明定义

typedef unsigned char u8;

sbit LSA=P2^2;

sbit LSB=P2^3;

sbit LSC=P2^4;

//--定义使用的IO口--//

#define GPIO_DIG   P0

#define GPIO_TRAFFIC P1

sbit RED10   = P1^0;   //上人行道红灯

sbit GREEN10 = P1^1;   //上人行道绿灯

sbit RED11   = P1^2;

sbit YELLOW11= P1^3;

sbit GREEN11 = P1^4;

sbit RED00   = P3^0; //右人行道红灯

sbit GREEN00 = P3^1; //右人行道绿灯

sbit RED01   = P1^5;

sbit YELLOW01= P1^6;

sbit GREEN01 = P1^7;

u8 code smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,

                                    0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//显示0~F的值

u8 DisplayData[8];

u8 Second;

void delay(u16 i)

{

    while(i--);

}

void DigDisplay()

{

    u8 i;

    for(i=0;i<8;i++)

    {

            switch(i)  //位选,选择点亮的数码管,

            {

                    case(0):

                            LSA=0;LSB=0;LSC=0; break;//显示第0位

                    case(1):

                            LSA=1;LSB=0;LSC=0; break;//显示第1位

                    case(2):

                            LSA=0;LSB=1;LSC=0; break;//显示第2位

                    case(3):

                            LSA=1;LSB=1;LSC=0; break;//显示第3位

                    case(4):

                            LSA=0;LSB=0;LSC=1; break;//显示第4位

                    case(5):

                            LSA=1;LSB=0;LSC=1; break;//显示第5位

                    case(6):

                            LSA=0;LSB=1;LSC=1; break;//显示第6位

                    case(7):

                            LSA=1;LSB=1;LSC=1; break;//显示第7位     

            }

            GPIO_DIG=DisplayData[i];//发送段码

            delay(100); //间隔一段时间扫描 

            GPIO_DIG=0x00;//消隐

    }

}

void Timer0Init()

{

    TMOD|=0X01;//选择为定时器0模式,工作方式1,仅用TR0打开启动。

    TH0=0XFC;       //给定时器赋初值,定时1ms

    TL0=0X18;      

    ET0=1;//打开定时器0中断允许

    EA=1;//打开总中断

    TR0=1;//打开定时器                     

}

void main()

{  

    Second = 1;

    Timer0Init();

    while(1)

    {

            if(Second == 70)

            {

                    Second = 1;

            }

            //--宝田路通行,30秒--//

            if(Second < 31)

            {

                    DisplayData[0] = 0x00;

                    DisplayData[1] = 0x00;

                    DisplayData[2] = smgduan[(30 - Second) % 100 / 10];

                    DisplayData[3] = smgduan[(30 - Second) %10];

                    DisplayData[4] = 0x00;

                    DisplayData[5] = 0x00;

                    DisplayData[6] = DisplayData[2];

                    DisplayData[7] = DisplayData[3];

                    DigDisplay();

                    //--宝田路通行--//

                    GPIO_TRAFFIC = 0xFF;  //将所有的灯熄灭

                    RED00 = 1;

                    GREEN00 = 1;

                    GREEN11 = 0;    //宝田路绿灯亮                      

                    GREEN10 = 0;    //宝田路人行道绿灯亮

                    RED01 = 0;      //前进路红灯亮

                    RED00 = 0;      //前进路人行道红灯亮

            }

            //--黄灯等待切换状态,5秒--//

            else if(Second < 36)

            {

                    DisplayData[0] = 0x00;

                    DisplayData[1] = 0x00;

                    DisplayData[2] = smgduan[(35 - Second) % 100 / 10];

                    DisplayData[3] = smgduan[(35 - Second) %10];

                    DisplayData[4] = 0x00;

                    DisplayData[5] = 0x00;

                    DisplayData[6] = DisplayData[2];

                    DisplayData[7] = DisplayData[3];

                    DigDisplay();

                    //--黄灯阶段--//

                    GPIO_TRAFFIC = 0xFF;  //将所有的灯熄灭

                    RED00 = 1;

                    GREEN00 = 1;

                    YELLOW11 = 0;    //宝田路黄灯亮                    

                    RED10      = 0;     //宝田路人行道红灯亮

                    YELLOW01 = 0;    //前进路红灯亮

                    RED00 = 0;       //前进路人行道红灯亮

            }

            //--前进路通行--//

            else if(Second < 66)

            {

                    DisplayData[0] = 0x00;

                    DisplayData[1] = 0x00;

                    DisplayData[2] = smgduan[(65 - Second) % 100 / 10];

                    DisplayData[3] = smgduan[(65 - Second) %10];

                    DisplayData[4] = 0x00;

                    DisplayData[5] = 0x00;

                    DisplayData[6] = DisplayData[2];

                    DisplayData[7] = DisplayData[3];

                    DigDisplay();

                    //--黄灯阶段--//

                    GPIO_TRAFFIC = 0xFF;  //将所有的灯熄灭

                    RED00 = 1;

                    GREEN00 = 1;

                    RED11 = 0;       //宝田路红灯亮                     

                    RED10 = 0;       //宝田路人行道红灯亮

                    GREEN01 = 0;     //前进路绿灯亮

                    GREEN00 = 0;     //前进路人行道绿灯亮

            }

            //--黄灯等待切换状态,5秒--//

            else

            {

                    DisplayData[0] = 0x00;

                    DisplayData[1] = 0x00;

                    DisplayData[2] = smgduan[(70 - Second) % 100 / 10];

                    DisplayData[3] = smgduan[(70 - Second) %10];

                    DisplayData[4] = 0x00;

                    DisplayData[5] = 0x00;

                    DisplayData[6] = DisplayData[2];

                    DisplayData[7] = DisplayData[3];

                    DigDisplay();

                    //--黄灯阶段--//

                    GPIO_TRAFFIC = 0xFF;  //将所有的灯熄灭

                    RED00 = 1;

                    GREEN00 = 1;

                    YELLOW11 = 0;    //宝田路黄灯亮                    

                    RED10      = 0;     //宝田路人行道红灯亮

                    YELLOW01 = 0;    //前进路红灯亮

                    RED00 = 0;       //前进路人行道红灯亮

            }

    }                                      

}

void Timer0() interrupt 1

{

    static u16 i;

    TH0=0XFC;       //给定时器赋初值,定时1ms

    TL0=0X18;

    i++;

    if(i==1000)

    {

            i=0;

            Second ++;      

    }      

}

例如

脉冲发生器

#include "reg52.h"                      //此文件中定义了单片机的一些特殊功能寄存器

typedef unsigned int u16;    //对数据类型进行声明定义

typedef unsigned char u8;

//--定义使用的IO--//

#define GPIO_DIG P0

sbit LSA=P2^2;

sbit LSB=P2^3;

sbit LSC=P2^4;

u8 code smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,

                                    0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//显示0~F的值

u8 DisplayData[8];

//--定义全局变量--//

unsigned long   Freq;        //用来存放要显示的频率值

unsigned long      TimeCount;   //用于计算1S钟的

void delay(u16 i)

{

    while(i--);

}

void DigDisplay()

{

    u8 i;

    for(i=0;i<8;i++)

    {

            switch(i)  //位选,选择点亮的数码管,

            {

                    case(0):

                            LSA=0;LSB=0;LSC=0; break;//显示第0位

                    case(1):

                            LSA=1;LSB=0;LSC=0; break;//显示第1位

                    case(2):

                            LSA=0;LSB=1;LSC=0; break;//显示第2位

                    case(3):

                            LSA=1;LSB=1;LSC=0; break;//显示第3位

                    case(4):

                            LSA=0;LSB=0;LSC=1; break;//显示第4位

                    case(5):

                            LSA=1;LSB=0;LSC=1; break;//显示第5位

                    case(6):

                            LSA=0;LSB=1;LSC=1; break;//显示第6位

                    case(7):

                            LSA=1;LSB=1;LSC=1; break;//显示第7位     

            }

            GPIO_DIG=DisplayData[i];//发送段码

            delay(10); //间隔一段时间扫描   

            GPIO_DIG=0x00;//消隐

    }

}

void Timer_Config()

{

    //--定时器T1做计数器,工作方式1(16位定时器),只由TRx打开计数器--//

    //--定时器T0做定时器,工作方式1(16位定时器),只由TRx打开定时器--//  

    TMOD=0x51;

    //--设置定时器晶振为12MHZ时定时50ms--//

    TH0=0x3C;

    TL0=0xB0;

    //--打开中断-//

    ET0=1;

    ET1=1;

    EA=1;

    //--打开定时器*/

    TR0=1;

    TR1=1;

}

void main()

{  

    Timer_Config();

   

    while(1)

    {

            if(TR1 == 0)         //当计数器停下的时候,表明计数完毕

            {

                    Freq = Freq + TL1;         //读取TL的值

                    Freq = Freq + (TH1 * 256); //读取TH的值

                    //--求频率的个十百千万十万位--//

                    DisplayData[0] = smgduan[Freq%1000000/100000];   

                    DisplayData[1] = smgduan[Freq%100000/10000];

                    DisplayData[2] = smgduan[Freq%10000/1000];   

                    DisplayData[3] = smgduan[Freq%1000/100];

                    DisplayData[4] = smgduan[Freq%100/10];   

                    DisplayData[5] = smgduan[Freq%10];

                   

                    //--显示完,重新计算下一次频率。--//     

                    Freq = 0;//将计算的频率清零

                    TH1 = 0; //将计数器的值清零

                    TL1 = 0;

                    TR0 = 1; //开启定时器

                    TR1 = 1; //开启计数器  

            }

            //--显示求得的数值--//

            DigDisplay();

    }                              

}

void Timer0() interrupt 1

{

    //--12MHZ设置定时50ms的初值--//

    TH0=0x3C;

    TL0=0xB0;

   

    TimeCount++;

    if(TimeCount==20)//计时到1S

    {

            TR0=0;

            TR1=0;

            TimeCount=0;        

    }              

}

void Timer1() interrupt 3

{  

    //--进入一次中断,表明计数到了65536--//

    Freq=Freq+65536;         

}

例如

串口通讯

#include "reg52.h"                      //此文件中定义了单片机的一些特殊功能寄存器

typedef unsigned int u16;    //对数据类型进行声明定义

typedef unsigned char u8;

void UsartInit()

{

    SCON=0X50;                   //设置为工作方式1

    TMOD=0X20;                  //设置计数器工作方式2

    PCON=0X80;                   //波特率加倍

    TH1=0XF3;                               //计数器初始值设置,注意波特率是4800的

    TL1=0XF3;

    ES=1;                                               //打开接收中断

    EA=1;                                               //打开总中断

    TR1=1;                                     //打开计数器

}

void main()

{  

    UsartInit();  //        串口初始化

    while(1);         

}

void Usart() interrupt 4

{

    u8 receiveData;

    receiveData=SBUF;//出去接收到的数据

    RI = 0;//清除接收中断标志位

    SBUF=receiveData;//将接收到的数据放入到发送寄存器

    while(!TI);                        //等待发送数据完成

    TI=0;                                                //清除发送完成标志位

}

例如   485通讯

#include "reg52.h"                      //此文件中定义了单片机的一些特殊功能寄存器

typedef unsigned int u16;    //对数据类型进行声明定义

typedef unsigned char u8;

sbit RS485DIR=P1^0;    //RS485DIR=0为接收状态  RS485DIR=1为发送状态

void delay(u16 i)

{

    while(i--);

}

void UsartInit()

{

    SCON=0X50;                   //设置为工作方式1

    TMOD=0X20;                  //设置计数器工作方式2

    PCON=0X80;                   //波特率加倍

    TH1=0XF3;                               //计数器初始值设置,注意波特率是4800的

    TL1=0XF3;

    ES=1;                                               //打开接收中断

    EA=1;                                               //打开总中断

    TR1=1;                                     //打开计数器

    RS485DIR=0;

}

void main()

{  

    UsartInit();  //        串口初始化

    while(1);         

}

void Usart() interrupt 4

{

    u8 receiveData;

    receiveData=SBUF;//出去接收到的数据

    RI = 0;//清除接收中断标志位

    delay(100);

    RS485DIR=1;

    SBUF=receiveData;//将接收到的数据放入到发送寄存器

    while(!TI);                        //等待发送数据完成

    TI=0;                                                //清除发送完成标志位

    RS485DIR=0;

}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值