单片微机原理P2:80C51外部中断与定时器系统

发布者:EnchantedDream最新更新时间:2024-08-21 来源: cnblogs关键字:单片微机  80C51  外部中断 手机看文章 扫描二维码
随时随地手机看文章

0. 外部中断

  书上的废话当然是很多的了,对于中断我想大家应该早就有一个很直观的认识,就是“设置断点,执行外部外码,然后返回断点”这样的三个过程。中断给系统提供了一个良好的响应模式。当然了,响应中断的时候记得保护现场,这是写汇编的良好习惯。

  80C51一共是5个中断源,这五个中断源分别是外部中断0,1定时器中断0,1,串口中断。

 

1. 我们现在先来看外部中断:

一般开外部中断分为4个步骤(不用查询的方式的话):

1. 设置触发方式(IT0/IT1)

2. 开启外部中断(EX0/EX1)

3. 设定优先级(IP寄存器)

4. 开启总中断(EA)

查询方式只是多了一步看IE的值而已

  代码(汇编代码)

SETB IT1

SETB EX1

SETB PX1 ;设定外部中断1为高级中断

SETB EA

  (C51代码)

IT1 = 1;

EX1 = 1;

PX1 = 1;

EA = 1;

   (如果不用AJMP $那种方式等待中断,通过查询IE0/IE1的状态,我们应该这样写)


LOOP:

        JB IE0, EVENT_OCCUR:

        LJMP LOOP

        EVENT_OCCUR:

        ;这里相当于可以是中断处理程序

        CLR IE0     ;记得清掉IE0的状态

        LJMP LOOP


2. 外部中断相关寄存器位:

  

IE0/IE1和IT0/IT1在TCON寄存器(88H),而EX0/EX1,EA在IE寄存器(A8H)

  IT0/IT1是设定外部中断0,1的触发方式的。比如当IT0为0时,是低电平触发,当INT0引脚(P3.2)为低电平时,IE置1,撤销的办法只有将外部输入的低电平变为高电平。当是下降沿触发时(INT0 = 1),则由硬件自动清0。

  IE0/IE1是中断请求位,当有中断请求的时候,这个位就会被置1,可以通过查询的方式来确定是否有中断的响应(闲的蛋疼的时候可以尝试下,就是简单的论询方式而已,JB判断一下即可)。

  注意如果设定IT0/IT1为低电平触发的时候一定要注意中断在引脚维持的时间,设置不好将引发玄学。如果引脚低电平维持时间太短,那么中断可能不会被响应,如果太长,有可能让中断处理程序执行完了都还没变回高,使得中断被一直响应。(低电平触发软件/硬件修改IE0/IE1是无效的)

  (PS:当然这种情况可以引入锁存器来解决,只要锁住INT0的信号为低电平就可以了,比如书上采用了D触发器,把外部中断接入D触发器的时钟断,D触发器的输入口接地,Q端接INT0,然后随便拿一个P口置D触发器异步置位端,这样一旦有中断响应,D触发器的输出为0,然后中断处理程序给对应的异步置位端1的信号,这样就可以保证在整个中断处理程序之内INT0的引脚都是1(撤销IE),中断处理程序结束后再把异步置位端为0,以便接受其他中断)。

  但是如果IT0/IT1为下降沿触发的时候就不会这样,如果处理器在两个机器周期扫描到INT0引脚的电平先后为高电平和低电平,那么就会设置中断标志位为1,直到中断被响应之前都不会被撤销,一旦中断响应后,硬件将自动将IE0/IE1置0。

  

  

  外部中断优先级的优先位设置也是在IP位中的(Interrupt Priority),在普通的80C51中,只能设定两个中断优先级(当然前面我们已经说了新型的可以达到4个了),中断优先级的自然顺序是规定好了的,是按照外部中断0,定时器中断0,外部中断1,定时器中断1,串口中断的顺序来定的。(在C51里面这些interrupt分别是0-4)在80C51中,中断是可以嵌套的,也就是遵循高级中断可以打断低级中断,同级中断不可以重入这样的规则,在80C51中,中断嵌套最大层数为两层。)

 

  3. 关于中断响应时间:

  处理器收到中断请求后,下一个机器周期是否转去执行中断服务子程序,还受到以下影响:

  ① 若当前机器周期不是处理器正在执行的指令的最后一个机器周期,则需要等到指令执行完成。

  ② 若正在执行RETI指令或者是其他读写与中断有关的寄存器IE、IP的指令,则需要在执行完该指令后,再执行一条指令,然后再转入中断服务子程序。

  ③ 中断返回后至少执行一条指令后才能响应新的中断。

  中断申请到执行第一条中断服务程序的最短时间是3个机器周期(优先权扫描1机器周期,LCALL指令2个机器周期)。若遇到不是执行指令的最后一个机器周期和正在执行RET、RETI或任何访问IE或IP寄存器指令时,则需要最长的等待时间不超过8个机器周期(3个最短周期,和5个最长等待周期。)

 

1. 定时器/计数器中断


  定时器和计数器中断也是掌握怎么开的步骤就可以了,中断处理程序打的写法除了地址不一样其他没什么不一样。

 

  开定时器和计数器要有6个步骤:

1. 设定TMOD(确定计数还是计时,确定什么方式)

2. 设定定时or计数时间

3. 打开ET0/ET1

4. 打开TR0/TR1

5. 设定优先级(IP寄存器)

6. 开启总中断(EA)

 

  定时器/计数器中断在但单片机上的中断的引脚是P3.4(T0),P3.5(T1),当选定内部时钟时,对应的机器周期脉冲为f0sc/12(即对应晶振的12分频)。

  当定时器/计数器作为计数器时,其最大频率是晶振的24分频(Fosc / 24)。(因为采集一个下降沿需要两个机器周期)。

  当定时器/计数器作为定时器时,其最大频率是晶振的12分频(Fosc / 12)。周期T = 12*(1/f)

 

  1. 定时器/计数器相关寄存器:

  

  

  

  

  

  TH0/TL0,TH1/TL1这四个寄存器都是不能位寻址的,代表的是定时器/计数器0,定时器/计数器1的当前值,当我们开启定时器/计数器时前要设定他们的初值。

  TCON这个寄存器是上面提过的,现在我们来看属于定时器/计数器的那一部分,TR1/TR0是开启定时器/计数器的标志位,TF1/TF0是标识计数器/定时器满的标志位(当TH0/TL0的内容达到2^x - 1的时候(x代表的x位的计数器/定时器)),这个时候TF1/TF0就置1(和外部中断一样,我们也可以用查询这个位的状态方式来代替中断处理程序的方式)。

  IE位的ET1和ET0是允许定时/计数器标志位,不要和TR0/TR1搞混了。

  TMOD是一个不能位寻址的寄存器,只能整体操作。TMOD分为两个部分,其中高四位是对应设置T1,低四位对应设置的是T0。

  GATE位是计数器门控制位:当GATE = 0时,只要启动TR0/TR1定时器就开始工作。当GATE = 1时,还需要一个外加条件即INT1/INT0为0时才会启动计数。

  C/T位:当C/T = 0,为定时器,当C/T = 1,为计数器。

 

  M1M0位:设定定时器/计数器打的工作方式(一共四种)

 

  设定了工作方式后需要做的就是根据工作方式来设定T0/T1的初值了,只要记住这个公式就可以了:

  其中X的值取决于这是多少位的计数器or定时器,比如如果设定工作方式0,那么x应该为13

  说下几个比较值得注意的坑:

 

1. 对于方式0,设定其初值的时候一定要记得其13位数的安排是TH0/TH1 8位,TL0/TL1 5位(而不是反过来)。

比如,80C51的工作时钟为6MHZ,定时时间为800us,使用定时器0工作方式0,如何设定初值

  所以TH0的值是0F3H,TL0的值是10H(而不是TH0 = 1EH,TL0 = 70H)

 

  2. 除了方式2可以自动重装外(如果采用了定时器2的工作方式,对应定时器/计数器TH和TL一定要设定一样),其他方式当中断响应以后一定要给对应定时器/计数器TH和TL设定新的值,不然不会响应下一次中断。

 

3. 方式3是一个比较特殊的定时方式,要注意只有T0才能设定为方式3,T1设定为方式3的时候会停止计数。

   

  我们可以看到如果设定为方式3的时候相当于把TH0和TL0拆成两个单独的8位计数器,其中TL0占用TR0和TF0,TH0占用TR1和TR0,TL0作为一个单独的8位计数器/定时器和其他定时器/计数器没有区别(只是是8位而已)。但是TH0不一样,由于它没有C/T位和GATE位控制,所以它只能作为一个定时器。

  在T0工作在方式3的时候,T1可以工作在方式0,1,2(由于TR1和TF1被TH0占用,所以想要停止T1工作只能把它的工作方式设定为工作方式3,同时也不能查询TF1的状态来看触发次数,只能直接查看TH1和TL1来看)。一般当我们设置T0为方式3时,T1会设置为方式2(自动填装),以方便串口的发送。

 

  那怎么打开T?比如我现在要打开定时器/计数器0,以工作方式1工作,定时为10ms(计算可知T0初值为0EC78H)

MOV TMOD, #00000001B

MOV TH0, #0ECH

MOV TL0, #78H

SETB ET0

SETB TR0

SETB EA


(C51)


TMOD = 0x01;

TH0 = 0xEC;

TL0 = 0x78;

ET0 = 1;

TR0 = 1;

EA = 1;


2. 一些例子

  1. 编程实现INT1为高级中断,下降沿触发,T0设为低优先级中断,串行口设定为高优先级中断,其他中断禁止

  (汇编)


    ORG 0000H

    LJMP MAIN

    ORG 0100H

MAIN:

    MOV IP, #014H    ; PS:PT1:PX1:PT0:PX0 = 10100(INT1高级中断,串口高级中断)

    SETB IT1            ;外部中断下降沿触发

    SETB EX1            ;允许外部中断1

    SETB ET1            ;允许定时器中断1

    SETB ES            ;打开串口中断

    SETB EA

END                ;写汇编程序千万不要忘记写END


(C51)


int main()

{

  IP = 0x14;

  IT1 = 1;

  EX1 = 1;

  ET1 = 1;

  ES = 1;

  EA = 1;


  return 0; 

}


2. 80C51单片机晶振频率为6MHZ,要求定时为10ms,定时器0工作在方式0,1,2时,定时器初值应该设置为多少?要求用16进制表示:

解:

  方式0:2^13 - (6*10^6 * 10 *10^-3 )/12 = 3192 -> TH0(063H) TL0(018H)(注意TH0放高8位,TL0放低5位)。

  方式1:2^16 - (6*10^6 * 10 *10^-3 )/12 = 60536 -> TH0(0ECH) TL0(078H)

  方式2:2^8 - (6*10^6 * 10 *10^-3 )/12 < 0 (溢出不能设置)

 

3. 用定时器/计数器T0产生时钟,使连接P1口的8盏灯循环点亮(1s一次),用中断方式编写

(这一题定时为1s太长了,需要我们拓展,我们可以定时个10ms然后定100次就可以了,用循环队列的思想即可完成任务)


    ORG 0000H

    LJMP MAIN

    ORG 000BH

    LJMP EVENT_OCCUR

    ORG 0100H

MAIN:

    MOV R0, #00H    ;设定队列初值0


    MOV P1, #01H

    MOV TMOD, #00000001B

    MOV TH0, #0ECH

    MOV TL0, #78H

    SETB ET0

    SETB TR0

    SETB EA

    AJMP $

EVENT_OCCUR:

    CLR EA

    PUSH ACC     ;保护现场,虽然在这一题没必要

    INC R0

    CJNE R0, #100, NEXT_EVENT

    RL A

    MOV P1, A

    MOV R0, #00H


    NEXT_EVENT:

        MOV TH0, #0ECH    ;一定要记得重设初值

        MOV TL0, #78H


    POP ACC        ;恢复现场

    RETI

END


  4. 测手速:统计两秒内按下按钮的次数,显示在数码管上,并且2S后让数码管清0

  (汇编代码)


_CODE_SEGMENT:

    ORG 0000H

    LJMP START

    ORG 000BH

    LJMP BUTTON_HASED_PUSHED

    ORG 001BH

    LJMP EVENTLOOP_OCCUR

    ORG 0100H

START:

    ;crystal oscillator frequency is 12MHZ

    

    ;Register 0 is uesd to log the number pushing actions 

    MOV R0,#00H

    

    ;register 1 is uesd to log the microsecond event times

    MOV R1,#00H

    

    MOV TH0,#0FFH

    MOV TL0,#0FFH

    

    MOV TH1,#0D8H

    MOV TL1,#0F0H

    

    MOV TMOD,#00010101B

    

    ;we must make time interrupt 1 is the advance interrupt

    MOV IP,#02H


    SETB ET0

    SETB TR0

    

    SETB ET1

    SETB TR1

    

    SETB EA

    LCALL DISPLAY_DIGITAL_NUM

    

    AJMP $

BUTTON_HASED_PUSHED:

    INC R0

    UPDATE_DIGITL_NUM:

    LCALL DISPLAY_DIGITAL_NUM

    

    MOV TH0,#0FFH

    MOV TL0,#0FFH

    

    RETI

EVENTLOOP_OCCUR:

    PUSH ACC

    

    INC R1

    CJNE R1,#200,NEXT_EVENT

    

    MOV R0,#00H

    LCALL DISPLAY_DIGITAL_NUM

    MOV R1,#00H

    

    NEXT_EVENT:

    MOV TH1,#0D8H

    MOV TL1,#0F0H

    

    POP ACC

    RETI

DISPLAY_DIGITAL_NUM:

    CLR EA 

    PUSH ACC

    

    MOV A, R0

    MOV DPTR, #DIGITAL_NUM

    MOVC A, @A + DPTR

    MOV P2, A

    

    POP ACC

    SETB EA 

    RET

_DATA_SEGMENT:

DIGITAL_NUM:

    DB 0C0H, 0F9H, 0A4H,0B0H,99H,92H,82H,0F8H,00H,90H 

    DB 88H, 83H, 0C6H, 0A1H, 86H, 8EH

END



(C51代码)


#include

#define FinalOuccr 200


unsigned char const digitalNumsSet[] 

                    = {0xC0, 0xF9, 0xA4, 0xB0,

                       0x99, 0x92, 0x82, 0xF8,

                       0x00, 0x90, 0x88, 0x83, 

                       0xC6, 0xA1, 0x86, 0x8E};

                       

enum StarterTime{ TH0_Start = 0xFF,

                  TL0_Start = 0xFF,

                  TH1_Start = 0xD8,

                  TL1_Start = 0xF0};

                  

//-----------------------------------------------------

void updateDigitalNumber(unsigned char const digitalNum);


static int eventOccurTimes = 0, BtnPushedTimes = 0;


void ButtonPushed()interrupt 1 using 0//中断1(定时器0中断),使用寄存器组0

{

    BtnPushedTimes++;

    updateDigitalNumber(digitalNumsSet[BtnPushedTimes]);

    

    TH0 = TH0_Start;

    TL0 = TL0_Start;

}


void EventOccur()interrupt 3 using 1//中断3(定时器1中断),使用寄存器组1

{

    eventOccurTimes++;

    if(eventOccurTimes == FinalOuccr)

    {

        BtnPushedTimes = 0;

        updateDigitalNumber(digitalNumsSet[BtnPushedTimes]);

        eventOccurTimes = 0;

    }

    TH1 = TH1_Start;

    TL1 = TL1_Start;

}


int main()

{

    TH0 = TH0_Start;

    TL0 = TL0_Start;

    

    TH1 = TH1_Start;

    TL1 = TL1_Start;

    

    TMOD = 0x15;

    TCON = 0x50;

    IP = 0X02;

    ET0 = 1;

    ET1 = 1;

    EA = 1;

[1] [2]
关键字:单片微机  80C51  外部中断 引用地址:单片微机原理P2:80C51外部中断与定时器系统

上一篇:单片微机原理P4:80C51串口与串行总线拓展
下一篇:单片微机原理P1:80C51指令系统和编程方法

推荐阅读最新更新时间:2026-03-24 11:41

基于单片工业控制微机的无线式键盘接口设计
  1. 引言   对于工业控制微机系统来说输入设备键盘几乎是必不可少的。在按键数目较少时,一般直接利用按键控制接口线的高低电平来表示,因此需要相应的接口支持,由于单片工业控制微机系统接口线数目有限,为了减少占用接口线常常采用一键定义多功能,但这又增加了软件的复杂性;在按键数目较多时,则大多采用动态扫描的方式构成键盘矩阵,这种键盘虽然结构原理简单,驱动程序易于设计,但是在具体实现时往往需要花很多的时间去设计印刷电路板、考虑面板布局,而且在硬件资源比较紧张时,还要考虑扩充I/ O 口,从而使得电路变得越来越复杂。   2. 系统简介   本文介绍一种无线式键盘接口,该接口可以最大限度地减少对单片机系统的硬件资源要求,仅占
[嵌入式]
《嵌入式-STM32开发指南》第二部分 基础篇 - 第2章 Systick系统定时器(HAL)
2.1 STM32Cube新建工程 关于如何使用使用STM32Cube新建工程在前文已经讲解过了,这里直说配置GPIO部分内容。本文要实现流水灯,其实输出为初始化设置为高电平还是低电平都可以,因为流水灯需要不断反转 第1章 GPIO(HAL库) 1.GPIO配置 我们将PB0、PG6、PG7配置输出模式(高电平、低电平均可)、输出速率、上/下拉等,默认即可。 图1GPIO初始化 2.时钟源配置 图2时钟源 3.时钟配置 图3时钟配置 4.sys配置(滴答定时器配置) 图4滴答定时器 以上配置和GPIO流水灯是一样的,本文只具体讲解Systick的内容。 2.2 Systick系统定时器具体代码分析 Systic
[单片机]
80C51 数码管动态显示0~7
所使用的开发板 普中科技HC6800-ES V2.0 PC:win7 64位 编译软件: keil uversion2 烧写工具: 普中科技开发的PZ-ISP V1.82 烧写方式:热烧写 #include reg52.h typedef unsigned char u8; typedef unsigned int u16; //P2引脚的2 3 4 片选数码管 sbit LSA=P2^2; sbit LSB=P2^3; sbit LSC=P2^4; //变量保存在flash里面 共阴数码管表 u8 code smgduan ={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
[单片机]
80C51学习 蜂鸣器
/* 蜂鸣器分为有源和无源 其中有源是指有振荡源 ULN2003 达林顿管 输入输出反向放大 */ #include reg52.h typedef unsigned int u16; //蜂鸣器通过ULN2003与80C51的P1^5引脚连接 sbit beep=P1^5; void delay(u16 i) { while(i--); } void main() { while(1) { //取反 形成高低电平变换 beep=~beep; //通过延时 形成一定的变化频率 delay(1000); } }
[单片机]
80C51系列单片机硬件基础
一、总体介绍; 单片机是一个大规模的集成电路芯片。现在一般介绍单片机时,一般以MCS-51单片机为基础介绍。学习单片机,以硬件和软件方面学习。硬件方面:外部引脚、内部编程结构、存储器结构、时钟电路、复位电路以及最小系统构成。 二、引脚介绍:   1、主电源引脚(2条):接电源和接地   2、外接晶体引脚(2条);   3、输入输出引脚(32条)     P0——通用口;双向通道;外部一般接上拉电阻 P1——准双向出口,内带上拉电阻 P2/3——准双向出口   4、控制引脚(4条):RST——复位信号输入端 ALE——地址锁存允许信号 EA——片内外程序存储器选择控制端 三、单片机思维导图 四、单片机硬件
[单片机]
<font color='red'>80C51</font>系列<font color='red'>单片</font>机硬件基础
80C51串行口
串行通信是指 使用一条数据线,将数据一位一位地依次传输,每一位数据占据一个固定的时间长度 单工、半双工、全双工 单工数据传输只支持数据在一个方向上传输 半双工数据传输允许数据在两个方向上传输,但是,在某一时刻,只允许数据在一个方向上传输,它实际上是一种切换方向的单工通信 全双工数据通信允许数据同时在两个方向上传输,因此,全双工通信是两个单工通信方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力 奇/偶校验(ECC) 传输的一组二进制代码的数位中“1”的个数是奇数或偶数 传输距离与传输速率 当传输线使用每0.3m有50PF电容的非平衡屏蔽双绞线时,传输距离随传输速率的增加而减小。当比特率超过1000 bps 时,最大传输距
[单片机]
<font color='red'>80C51</font>串行口
80C51单片机对压力测量控制系统的设计
1 引言 目前我国发展煤炭生产机械化发展迅速。综采设备的应用,是提高效率、改善安全状况的措施。 影响开机率的一个主要因素是支架对工作面的顶板控制的好坏,因此,对综采工作面进行矿压监测与控制是很有必要的。要做到这一点,首先需要对井下工作面的液压支架的实际工作状况进行监测,通过对检测数据处理、分析,评定其效果,并采取相应措施,以提高开机率、提高产量。本文以监测综采液压支架的压力为研究内容,开发了一套基于单片机的压力测量控制系统。 2 压力测量控制系统功能设计 压力测量控制系统用于监测支架压力, 每台测量控制系统配有四只传感器, 可分别通过高压油管连接支架的立柱、平衡千斤顶, 前探梁千斤顶的油压腔。压力测量控制系统接收到通讯测量
[单片机]
<font color='red'>80C51</font><font color='red'>单片</font>机对压力测量控制<font color='red'>系统</font>的设计
基于80C51单片机和CH375芯片实现打印机驱动系统的设计
引言 本课题来源于北京普析通用公司的一个项目。由于公司现有单机版光谱仪器产品(如1810、T6等)采用的是并行口打印技术,而随着USB打印机技术的逐渐普及,并行口打印机越来越不好买到,而且有些用户的打印机只是USB接口而非并行口,因此现有仪器产品对打印机的支持变得不能适应用户需要。为了实现能将公司的并行口仪器直接和USB打印机相连进行打印,决定设计开发一款LPT-USB打印机的驱动器,负责并口仪器和USB打印机的连接。 本文利用单片机和USB总线接口芯片实现LPT-USB打印机的驱动器设计。利用该设计将能够实现并行打印口数据可以在USB打印机上的直接打印工作,克服了有些并口仪器必须连接并口打印机才能打印的弊端,极大地方便了用户
[单片机]
基于<font color='red'>80C51</font><font color='red'>单片</font>机和CH375芯片实现打印机驱动<font color='red'>系统</font>的设计
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved