历史上的今天
返回首页

历史上的今天

今天是:2024年10月29日(星期二)

正在发生

2021年10月29日 | 51单片机学习笔记之中断

2021-10-29 来源:eefocus

(一)寄存器

要想学习中断那么首先就要了解寄存器,在这里我们学习一下什么是寄存器,寄存器怎么用。


1.什么是寄存器

寄存器是特殊的RAM,特殊功能寄存器是控制单片机硬件的开关(例如IE)或者是指示单片机状态的信号(例如PSW),通过特殊寄存器你就可以方便的控制整个MCU,并且知道当前的MCU的工作状态。


2.寄存器怎么用

AT89S51单片机中的特殊功能寄存器(SFR)的单元地址映射在片内RAM区的80H~FFH区域中,它共有26个,离散地分布在该区域中。用到哪个寄存器就相应配置哪个寄存器即可。寄存器太多就不一一写出来了,用到再去找就好。


(二)中断

单片机的中断是由单片机片内的中断系统来实现的。当中断请求源(简称中断源)发出中断请求时,如果中断请求被允许的话,单片机暂时中止当前正在执行的主程序,转到中断服务程序处理中断服务请求,处理完中断服务请求后,再回到原来被中止的程序之处(断点),继续执行被中断的主程序。


1.中断允许寄存器IE

在这里插入图片描述

EX0

外部中断0允许位。EX0=1,允许外部中断0中断;EX0=0,禁止外部中断0中断。当EX0=1( SETB EX0 )时,同时单片机P3.2引脚上出现中断信号时,单片机中断主程序的执行而“飞”往中断服务子程序,执行完后通过中断返回指令RET 动返回主程序。当EX0=0( CLR EX0)时,即使单片机P3.2引脚上出现中断信程序也不会从主程序“飞” 出去执行,因为此时单片机的CPU相当于被“堵上了耳朵”,根本接收不到P3.2引脚上的中断信号,但是这并不表示这个信号不存在。如果单片机的CPU有空查一下TCON中的IE0位,若为1就说明有中断信号出现过。


ET0

T0溢出中断允许位。ET0=1,允许T0中断;ET0=0,禁止T0中断。


EX1

外部中断1允许位。EX1=1,允许外部中断1中断;EX1=0,禁止外部中断1中断。当EX1=1( SETB EX1)时,并且外部P3.3引脚上出现中断信号时,单片机CPU会中断主程序而去执行相应的中断服务子程序;当EX1=0( CLR EX1)时使外部P3.3引脚上即使出现中断信号,单片机的CPU也不能中断主程序转而去行中断服务子程序。

因此,可以这样认为,EX0和EX1是决定CPU能否感觉到外部引脚P3.2P3.3上的中断信号的控制位。


ET1

T1溢出中断允许位。ET1=1,允许T1中断;ET1=0,禁止T1中断。


ES

串行中断允许位。ES=1,允许串行口中断;ES=0,禁止串行口中断。


EA

中断总允许位。EA=1,CPU开放中断;EA=0,CPU禁止所有的中断请求。总允许EA好比一个总开关。EA就相当于每家水管的总闸,如果总闸不开,各个龙头即使开了也不会有水;反过来,如果总闸开了而各个分闸没开也不会有水,所当我们想让P3.2和P3.3引脚上的信号能够中断主程序则必须将EA位设置为0(CLR EA)。


使用方法

(1)整体赋值:IE=0x81;(开启全局中断,打开外部中断0 )。

(2)单独赋值:EA=1;EX0=1;(开启全局中断,打开外部中断0 )。


2.中断优先级寄存器IP

在这里插入图片描述

PS——串行口中断优先级控制位

PS=1,串行口中断定义为高优先级中断。

PS=0,串行口中断定义为低优先级中断。


PT1——定时器/计数器1中断优先级控制位

PT1=1,定时器/计数器1中断定义为高优先级中断。

PT1=0,定时器/计数器1中断定义为低优先级中断。


PX1——外部中断1中断优先级控制位

PX1=1,外部中断1定义为高优先级中断。

PX1=0,外部中断1定义为低优先级中断。


PT0——定时器/计数器0中断优先级控制位

PT0=1,定时器/计数器0中断定义为高优先级中断。

PT0=0,定时器/计数器0中断定义为低优先级中断。


PX0——外部中断0中断优先级控制位

PX0=1,外部中断0定义为高优先级中断。

PX0=0,外部中断0定义为低优先级中断。


中断优先级(高到低)

外部中断0

T0溢出中断

外部中断1

T1溢出中断

串行口中断

T2溢出中断(52)


3.TCON寄存器

在这里插入图片描述

TF1:片内定时器/计数器T1的溢出中断请求标志位。

当启动T1计数后,定时器/计数器T1从初值开始加1计数,当计数溢出时,由硬件自动为TF1置“1”,向CPU申请中断。CPU响应TF1中断时,TF1标志位由硬件自动清零,TF1也可由软件清零。


TF0:片内定时器/计数器T0的溢出中断请求标志位。

功能与TF1相同。


IE1:外部中断请求1的中断请求标志位。

IE1=0,无中断请求。

IE1=1,外部中断1有中断请求。当CPU响应该中断,转向中断服务程序时,由硬件清“0”IE1。


IE0: 外部中断请求0的中断请求标志位。

IE0=0,无中断请求。

IE0=1,外部中断0有中断请求。当CPU响应该中断,转向中断服务程序时,由硬件清“0”IE0。


IT1:选择外部中断请求1为负跳变触发方式还是电平触发方式。

IT1=0,为电平触发方式,外部中断请求输入信号为低电平有效,并把IE置“1”。转向中断服务程序时,则由硬件自动把IE1清零。

IT1=1,为负跳变触发方式,外部中断请求输入信号电平为从高到低的负跳变有效,,并把IE置“1”。转向中断服务程序时,则由硬件自动把IE1清零。


IT0:选择外部中断请求0为负跳变触发还是电平触发方式。

与IT1相似。


4.SCON寄存器

在这里插入图片描述

TI:串行口发送中断请求标志位。

当CPU将1字节的数据写入串行口的发送缓冲器SBUF时,就启动一帧串行数据的发送,每发送完一帧串行数据后,硬件把TI中断请求标志位自动置“1”。CPU响应串行口发送中断时,并不能清除TI标志位,TI标志位必须在中断服务程序中用指令对其清零。


RI:串行口接收中断请求标志位。

在串行口接收完一个串行数据帧,硬件自动使RI中断请求标志位置“1”。CPU在响应串行口接收中断时,RI标志位并不清零,必须在中断服务程序中用指令对RI清零。


(三)外部中断

51单片机的外部中断int0对应的引脚为p3.2,外部中断int1对应的引脚为p3.3。


1.外部中断0,按下开关K3,数码管0变1

寄存器配置:

    EA=1;//总中断允许

EX0=1;//允许外部中断0

IT0=0;//选择外部中断0为电平触发方式


完整代码:

#include

#define uchar unsigned char

sbit key = P3^2;


void delay(unsigned int i)//延时函数

{

unsigned int j;

for(;i>0;i--)

for(j=0;j<333;j++){}

}


void main()//主函数

{

EA=1;//总中断允许

EX0=1;//允许外部中断0

IT0=0;//选择外部中断0为电平触发方式

while(1)//循环

{P0=0x3f;}//P0.0口的Led亮

}

void key_scan() interrupt 0 //外部中断0的中断服务函数

{

if(key==0)//判断是否有按键按下

{

delay(10);//延时去抖

if(key==0)

{

P2=0xfe;

P0=0x06;

while(!key);//等待按键松开

P2=0xff;

P0=0x3f;

}


}

}


2.外部中断1,按下开关K4,数码管0变1

寄存器配置:

    EA=1;//总中断允许

EX1=1;//允许外部中断0

IT1=0;//选择外部中断0为电平触发方式


完整代码:

#include

#define uchar unsigned char

sbit key = P3^3;


void delay(unsigned int i)//延时函数

{

unsigned int j;

for(;i>0;i--)

for(j=0;j<333;j++){}

}


void main()//主函数

{

EA=1;//总中断允许

EX1=1;//允许外部中断0

IT1=0;//选择外部中断0为电平触发方式

while(1)//循环

{P0=0x3f;}//P0.0口的Led亮

}

void key_scan() interrupt 1 //外部中断1的中断服务函数

{

if(key==0)//判断是否有按键按下

{

delay(10);//延时去抖

if(key==0)

{

P2=0xfe;

P0=0x06;

while(!key);//等待按键松开

P2=0xff;

P0=0x3f;

}


}

}


3.外部中断扩展

寄存器配置:

    IT0 = 1;//跳沿触发

    IT1 = 1;//跳沿触发

    PX1 = 1;//中断1高于中断0

    IE = 0x85;/*由低到高:EX1(第3位)=1,EX0 (第0位)= 1,EA (第八位)= 1 IE = 10000101*/


完整代码:

#include

#include

#define uchar unsigned char

#define uint unsigned int

uint i;

void delay(uint xms);

void Int();

void Interrupt0(); 

void Interrupt1(); 


void main()

{

    Int();

    P2 = 0xfe;

while(1)

{

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

    {

        P2 = _crol_(P2, 1);//先左移

        delay(600);

    }


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

    {

        P2 = _cror_(P2, 1);//再右移

        delay(600);


    }


}



}


void Int()

{

    IT0 = 1;//跳沿触发

    IT1 = 1;//跳沿触发

    PX1 = 1;//中断1高于中断0

    IE = 0x85;/*由低到高:EX1(第3位)=1,EX0 (第0位)= 1,EA (第八位)= 1 IE = 10000101*/

}


void delay(uint xms)//AT89C5211.0592MHz

{

    uint x, y;

    for (x = xms;x > 0;x--)

        for (y = 110;y > 0;y--);

}


void Interrupt1() interrupt 0

{

    while (1)

    {

        P2 = 0x0f;

        delay(600);

        P2 = 0xf0;

        delay(600);

    }

}

void Interrupt2() interrupt 2/*外部中断1的标号是2!*/

{

    while (1)

    {

        P2 = 0xcc;//(11001100)

        delay(600);

        P2 = 0x33;

        delay(600);

    }



}


(四)定时器中断

1.定时器0

寄存器配置:

  TMOD = 0x01;

  TH0 = (65536 - 45872) / 256; // 设置定时器0为工作方式1(M1M0为01)

  TL0 = (65536 - 45872) % 256; // 装初值11.0592M晶振定时50ms数位45872

  EA = 1; // 开总中断

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

  TR0 = 1; // 启动定时器0


完整代码:

#include

#include

#define uchar unsigned char

#define uint unsigned int

sbit led1 = P2^0;

uchar num = 0;


void main()

{

  TMOD = 0x01;

  TH0 = (65536 - 45872) / 256; // 设置定时器0为工作方式1(M1M0为01)

  TL0 = (65536 - 45872) % 256; // 装初值11.0592M晶振定时50ms数位45872

  EA = 1; // 开总中断

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

  TR0 = 1; // 启动定时器0

  while(1)

  {

    ;

  }

}


void T0_time() interrupt 1

{

  TH0 = (65536 - 45872) / 256;

  TL0 = (65536 - 45872) % 256;

  num++;

  if (num == 20)

  {

    num = 0;

    led1 = ~led1;

  }

}


2.定时器1

寄存器配置:

  TMOD = 0x01;

  TH0 = (65536 - 45872) / 256; // 设置定时器1为工作方式1(M1M0为01)

  TL0 = (65536 - 45872) % 256; // 装初值11.0592M晶振定时50ms数位45872

  EA = 1; // 开总中断

  ET1 = 1; // 开定时器1中断

  TR1 = 1; // 启动定时器1


完整代码:

#include

#include

#define uchar unsigned char

#define uint unsigned int

sbit led1 = P2^0;

uchar num = 0;


void main()

{

  TMOD = 0x01;

  TH0 = (65536 - 45872) / 256; // 设置定时器1为工作方式1(M1M0为01)

  TL0 = (65536 - 45872) % 256; // 装初值11.0592M晶振定时50ms数位45872

  EA = 1; // 开总中断

  ET1 = 1; // 开定时器1中断

  TR1 = 1; // 启动定时器1

  while(1)

  {

    ;

  }

}


void T1_time() interrupt 3

{

  TH0 = (65536 - 45872) / 256;

  TL0 = (65536 - 45872) % 256;

  num++;

  if (num == 20)

  {

    num = 0;

    led1 = ~led1;

  }

}


3.定时器计数控制数码管0到60

寄存器配置:

    TMOD=0x11;//写在一起

//定时器0

//TMOD=0x01;

TH0=(65536-45872)/256;

TL0=(65536-45872)%256;

EA=1;

ET0=1;

TR0=1;

//定时器1

//TMOD=0x10;

TH1=(65536-45872)/256;

TL1=(65536-45872)%256;

EA=1;

ET1=1;

TR1=1;


完整代码:

#include

#define uint unsigned int

#define uchar unsigned char

uchar code table[]={

                    0x3f,0x06,0x5b,0x4f,

                    0x66,0x6d,0x7d,0x07,

                    0x7f,0x6f,0x77,0x7c,

                    0x39,0x5e,0x79,0x71

                   };//共阴极数码管编码

uchar num0,num1;

uint ge ,shi;

sbit LSA=P2^2;//74HC138译码器端口

sbit LSB=P2^3;

sbit LSC=P2^4;

void  display_time(uint ,uint);

void delay_ms(uint);


void main()

{

TMOD=0x11;//写在一起

//定时器0

//TMOD=0x01;

TH0=(65536-45872)/256;

TL0=(65536-45872)%256;

EA=1;

ET0=1;

TR0=1;

//定时器1

//TMOD=0x10;

TH1=(65536-45872)/256;

TL1=(65536-45872)%256;

EA=1;

ET1=1;

TR1=1;

while(1)

{

display_time(ge ,shi);//时间一直显示中

}

}


void T0_time()interrupt 1 //数码管处理 T0定时器

{

TH0=(65536-45872)/256;//每50ms产生一次中断

TL0=(65536-45872)%256;//所以每20次中断,个位+1

num0++;

if(num0==20)

{

num0=0;

ge++;

if(ge==10)

{

shi++; //时间进位

ge=0;

}

if(shi==6)

shi=0; //时间归零

}

}


void  display_time(uint ge ,uint shi)

{

LSA=0;LSB=1;LSC=1;

P0=table[ge];//送入个位数字

delay_ms(5);


LSA=1;LSB=1;LSC=1;

P0=table[shi];//送入十位数字

delay_ms(5);

}

void delay_ms(uint ms)

{

uint i,j;

for(i=ms;i>0;i--)

for(j=110;j>0;j--);

}


4.定时器做的时钟

寄存器配置:

    TMOD=0x01;

TH0=(65536-45872)/256;

TL0=(65536-45872)%256;

EA=1;

ET0=1;

TR0=1;


完整代码:

#include

#define uint unsigned int

#define uchar unsigned char

uchar code table[]={

                    0x3f,0x06,0x5b,0x4f,

                    0x66,0x6d,0x7d,0x07,

                    0x7f,0x6f,0x77,0x7c,

                    0x39,0x5e,0x79,0x71

                   };//共阴极数码管编码

uchar num;

uint hour_ge,hour_shi,minute_ge, minute_shi,second_ge,second_shi;

sbit LSA=P2^2;//74HC138译码器端口

sbit LSB=P2^3;

sbit LSC=P2^4;

void  display_time(uint,uint,uint,uint,uint,uint);

void delay_ms(uint);

void main()

{

TMOD=0x01;

TH0=(65536-45872)/256;

TL0=(65536-45872)%256;

EA=1;

ET0=1;

TR0=1;

while(1)

{

display_time(hour_shi,hour_ge,minute_shi,minute_ge,second_shi,second_ge);

//时间一直显示中

}

}


void T0_time()interrupt 1 //数码管处理 T0定时器

{

TH0=(65536-45872)/256;//每50ms产生一次中断

TL0=(65536-45872)%256;//所以每20次中断,个位+1

num++;

if(num==20)

{

num=0;

second_ge++;//秒+1

}

if(second_ge==10)

{

second_ge=0;

second_shi++;

if(second_shi==6)

{

second_shi=0;

minute_ge++;

if(minute_ge==10)

{

minute_ge=0;

minute_shi++;

if(minute_shi==6)

{

minute_shi=0;

hour_ge++;

if(hour_ge==10)

{

hour_ge=0;

hour_shi++;

if(hour_shi==2&&hour_ge==4)

{

hour_shi=0;

hour_ge=0;

推荐阅读

史海拾趣

辉芒微(FMD)公司的发展小趣事

近年来,辉芒微积极筹备上市工作,旨在通过资本市场进一步拓展融资渠道和品牌影响力。尽管在上市过程中经历了两次撤回申请资料的波折,但公司始终保持着对资本市场的热情和信心。通过不断优化内部管理、提升产品竞争力和加强市场拓展,辉芒微最终赢得了市场的广泛认可。其产品被广泛应用于智能家居、生活电器、智能穿戴等领域,并与小米、飞科、中兴等众多知名品牌建立了长期稳定的合作关系。

GWP Group公司的发展小趣事

辉芒微(FMD)成立于2005年6月,作为一家新兴的芯片设计企业,其成立之初便专注于EEPROM(电可擦除可编程只读存储芯片)的研发与生产。在成立的同一年,辉芒微便成功实现了EEPROM芯片的量产销售,这一里程碑式的成就为公司后续的快速发展奠定了坚实的基础。随着技术的不断积累和市场的持续拓展,辉芒微在集成电路设计领域逐渐崭露头角。

台湾义隆电子(ELAN)公司的发展小趣事

义隆电子在多个技术领域保持领先地位,如数字模拟混合技术、高阶设计流程等。这些技术优势使得公司能够迅速掌握市场脉动,开发出具有实用性的新产品。同时,义隆电子还注重将先进技术应用于实际产品中,如高性能的触摸屏控制器、触摸板模块等,这些产品广泛应用于智能手机、平板电脑等消费电子产品中,赢得了市场的广泛认可。

Advanced Power Solutions公司的发展小趣事

随着全球环保意识的提高,Advanced Power Solutions公司开始关注电源管理技术的环保性能。公司投入大量资源研发绿色、低碳的电源管理产品,并成功推出了一系列符合环保标准的新产品。这些产品不仅受到了消费者的欢迎,也赢得了政府和环保组织的认可。公司的环保理念和创新精神为其赢得了良好的社会声誉。

CYAN公司的发展小趣事

随着5G技术的兴起,CYAN敏锐地捕捉到了市场的变化。公司投入大量研发资源,成功开发出一款基于5G技术的高性能网络路由器。这款路由器不仅具有超高的数据传输速度和稳定性,还具备智能管理和安全保护功能,满足了市场对高性能网络设备的需求。

FREESCALE (NXP)公司的发展小趣事

1996年,瑞典的工程师Jan Nilsson在电子行业中创立了CYAN公司,专注于高性能网络设备的研发。在初创阶段,CYAN就凭借其独特的技术理念和创新的产品设计,赢得了市场的初步认可。公司推出了一款具有高效能和高可靠性的网络交换机,解决了当时网络传输中的瓶颈问题,从而在市场中崭露头角。

问答坊 | AI 解惑

急救!关于protel 99se的仿真

当我在对一个电路进行仿真时总是出现这些错误,但我又不知道什么意思,请各位高手指点一下。 非常感谢! C3 Error: Pin order data (PINS=1:[]) not in READ ONLY field 4. Pins sorted by pin-name. C3 Error ...…

查看全部问答>

IPCWorks Asia 2008十月引领绿色制造潮流

从无铅、RoHS到无卤素,再到PoHS,业界对环保材料的“门槛”越设越高,未来的绿色之路将走向何处?今年10月15-16日高交会电子展期间,品牌研讨会\"IPCWorks Asia\"将再次在深圳举办,本届会议的主题是\"无铅/无卤素制造\",届时众多业内无卤技术专 ...…

查看全部问答>

rt12864

我想rt12864所有的型号内部都是一样的吗?…

查看全部问答>

要写一个嵌入式实时操作系统,不知如何下手

最近组了一个3人团队,要写一个嵌入式实时操作系统,看了两星期的相关资料了,但是还是没有头绪,请各位大虾给点指点…

查看全部问答>

SqlCE PULL正常 SubmitSql也是正常的. 但是在 PUSH时出错. 请会的指点一下.

程序如下:             string _strRemoteConnect = \"provider=sqloledb;data source=192.168.1.99;Initial Catalog=zls;User ID=sa;\";             SqlCeRe ...…

查看全部问答>

问一个AVR的延时函数_delay_ms()的问题

_delay_ms()这个延时到底有多准啊? 如果用计数器TNCT0计数,TNCT0的初始值为55,跳到255后溢出中断, 选择8分频的时钟源,F_CPU= 16M,10ms的时间TNCT0的溢出次数应该是100次 即TNCT0跳了100*(255-55)= 20000次。 问:     _ ...…

查看全部问答>

运放做跟随器用

本帖最后由 dontium 于 2015-1-23 12:53 编辑    还是来说说跟随器吧,我是采用AD转换,把模拟信号采取回来,后用了个跟随器。但是跟随回来的电压不稳定,在数码管上有斗动。运放是LM358 …

查看全部问答>

要求输出电流高的的开关电路,求高手详解一下电路,谢谢

要求输出电流高的的开关电路,集电极输入vcc为6.5v,按键基极输入5.22v。求高手详解一下电路,q1为ss8050,q2为2SC2500,我觉得这个电路构不成开关电路,我的理由是6.5>5.22是反偏,集电极反偏,发射极正便,求高手解决小弟的问题。更加纳闷的是 ...…

查看全部问答>

心电图(ECG)信号链的模拟基础(三)

本帖最后由 dontium 于 2015-1-23 12:43 编辑 ECG 机的基本功能包括 ECG 波形显示(通过 LCD 显示屏或印刷纸媒质显示)、心跳律动指示以及通过按钮控制的简单用户界面。越来越多的 ECG 产品要求具备更多的功能,例如通过便携式媒体存储电子病历、 ...…

查看全部问答>

nRF24L01无线数据传输电路

芯片适用,nRF24L01无线数据传输电路,nRF24L01引脚说明及封装图。 资源连接: https://download.eeworld.com.cn/detail/lbk747/948…

查看全部问答>