单片机定时器_单片机定时器实验报告 - CSDN
  • 51单片机中断系统(定时器、计数器)

    万次阅读 多人点赞 2017-11-21 00:17:12
    一、中断 中断是指计算机运行过程中,出现某些意外情况需主机干预时,机器能自动停止正在运行的程序并转入处理新情况...二、51单片机中断级别 中断号 优先级 中断源 中断入口地址 0 1(最高) INT0

    *部分内容来源于网络


    一、中断

    中断是指计算机运行过程中,出现某些意外情况需主机干预时,机器能自动停止正在运行的程序并转入处理新情况的程序,处理完毕后又返回原被暂停的程序继续运行。


    (*以上解释来自于百度百科-中断)

     

    二、51单片机中断级别

    中断号

    优先级

    中断源

    中断入口地址

    0

    1(最高)

    INT0

    外部中断0

    0003H

    1

    2

    T0

    定时器/计数器0中断

    000BH

    2

    3

    INT1

    外部中断1

    0013H

    3

    4

    T1

    定时器/计数器1中断

    0018H

    4

    5(最低)

    TX/RX

    串行口中断

    0023H

     

     

    三、中断结构图


    四、中断寄存器

    1、 中断允许控制寄存器IE

    位地址

    AFH

    AEH

    ADH

    ACH

    ABH

    AAH

    A9H

    A8H

    位序号

    7

    6

    5

    4

    3

    2

    1

    0

    位名称

    EA

    -

    -

    ES

    ET1

    EX1

    ET0

    EX0

    EX0/EX1:外部中断允许控制位

            EX0=1 外部中断0开关闭合     //开外部0中断

            EX0=0 外部中断0开关断开

    ET0/ET1:定时中断允许控制位

            ET0=1 定时器中断0开关闭合   //开内部中断0

            ET0=0 定时器中断0开关断开

    ES:串口中断允许控制位    

            ES=1 串口中断开关闭合         //开串口中断

            ES=0 串口中断开关断开

     

    2、 定时器控制寄存器TCON

    位地址

    8FH

    8EH

    8DH

    8CH

    8BH

    8AH

    89H

    88H

    位序号

    7

    6

    5

    4

    3

    2

    1

    0

    位名称

    TF1

    TR1

    TF0

    TR0

    IE1

    IT1

    IE0

    IT0

           外部中断:

               IE0/IE1:外部中断请求标志位

                       当INT0(INT1)引脚出现有效的请求信号,此位由单片机自动置1,

                       CPU开始响应,处理中断,而当入中断程序后由单片机自动置0.

               IT0/IT1:外部中断触发方式控制位          //选择有效信号

                       IT0/IT1=1:脉冲触发方式,下降沿有效。

                       IT0/IT1=0:电平触发方式,低电平有效。

           内部中断:

               TF0/TF1:内部定时器/计数器溢出中断标志位

                        当定时器、计数器计数溢出的时候,此位由单片机自动置1,

                        cup开始响应,处理中断,而当进入中断程序后由单片机自动置0.

                        //内部中断实际上就是利用内部的计数器,

                          只不过提供计数的脉冲来自单片机自身。

               TR0(TR1):定时器/计数器启动位                    //启动定时器

                       TR0/TR1=1;启动定时器/计数器0

                       TR0/TR1=0;关闭定时器/计数器0

     

    3、 串口控制寄存器SCON

    位地址

    9FH

    9EH

    9DH

    9CH

    9BH

    9AH

    99H

    98H

    位序号

    7

    6

    5

    4

    3

    2

    1

    0

    位名称

    SM0

    SM1

    SM2

    REN

    TB8

    RB8

    TI

    RI

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

               当单片机串口发送完一帧数据后,此位由单片机自动置1,

               而当进入中断服务程序后是不会自动清0的,

               必须由用户在中断服务中用软件清0.

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

               当单片机串口接收完一帧数据后,此位由单片机自动置1,

               而当进入中断服务程序后是不会自动清0的,

               必须由用户在中断服务软件中用软件清0.

    4、 中断优先控制寄存器IP

    位序号

     7 

     6 

     5 

    4

    3

    2

    1

    0

    位名称

    -

    -

    -

    PS

    PT1

    PX1

    PT0

    PX0

           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中断定义为低优先级中断。

     

    5、 定时器工作方式控制寄存器TMOD

    位序号

    7

    6

    5

    4

    3

    2

    1

    0

    定时器

    定时器/计数器1(ET1)

    定时器/计数器0(ET0)

    位名称

    GATE

    C/T

    M1

    MO

    GATE

    C/T

    M1

    M0

            GATE——门控制。   

                 GATE=1时,由外部中断引脚INT0、INT1来启动定时器T0、T1。   

                       当INT0引脚为高电平时TR0置位,启动定时器T0;   

                       当INT1引脚为高电平时TR1置位,启动定时器T1。   

                 GATE=0时,仅由TR0,TR1置位分别启动定时器T0、T1。

            C/T——功能选择位   

                 C/T=0时为定时功能,

                 C/T=1时为计数功能。    

            M0、M1——方式选择功能

    M1

    M0

    工作方式

    功  能

    0

    0

    工作方式0

    13位计数器

    0

    1

    工作方式1

    16位计数器

    1

    0

    工作方式2

    自动再装入8位计数器

    1

    1

    工作方式3

    定时器0:分成两个8位计数器

    定时器1:停止计数

     

    6、 定时器初值赋予寄存器(TH0/TH1,TL0/TL1)

     

    五、定时器、计数器

    1、 工作方式




    2、 定时器初值计算

    1.计数器初值的计算

       设计数器的最大计数值为M(根据不同工作方式,M可以是2^13、2^16或2^8),则计算初值X的公式如下:

                        X=M-要求的计数值

    2.定时器初值的计算

       在定时器模式下,计数器由单片机主脉冲fosc经12分频后计数。因此,定时器定时初值计算公式:

                        X=M-(要求的定时值)/(12/fosc)

       式中,M为定时器模值(根据不同工作方式,M可以是213、216或28)

     

    关于如何确定定时器T0的初值问题。定时器一但启动,它便在原来的数值上开始加1计数,若在程序开始时,我们没有设置TH0和TL0,它们的默认值都是0,假设时钟频率为12MHz,12个时钟周期为一个机器周期,那么此时机器周期为1us,记满TH0和TL0就需要216 -1个数,再来一个脉冲计数器溢出,随即向CPU申请中断。因此溢出一次共需65536us,约等于65.6ms,如果我们要定时50ms的话,那么就需要先给TH0和TL0装一个初值,在这个初值的基础上记50000个数后,定时器溢出,此时刚好就是50ms中断一次,当需要定时1s时,我们写程序时当产生20次50ms的定时器中断后便认为是1s,这样便可精确控制定时时间啦。要计50000个数时,TH0和TL0中应该装入的总数是65536-50000=15536.,把15536对256求模:15536/256=60装入TH0中,把15536对256求余:15536/256=176装入TL0中。

    以上就是定时器初值的计算法,总结后得出如下结论:当用定时器的方式1时,设机器周期为TCY,定时器产生一次中断的时间为t,那么需要计数的个数为N=t/TCY ,装入THX和TLX中的数分别为:

    THX=(65536-N)/256    ,     TLX=(65536-N)%256 

     

    设置为计数器模式时,外部计数脉冲由T0或T1引脚输入到计数器。在每个机器周期S5P2期间采样T0,T1引脚电平,当某周期采样到一高电平输入,而下一周期又采样到一低电平时,则计时器加1,更新的计数值在下一个机器周期的S3P1期间装入计数器。由于检测一个从1到0的下降沿需要两个机器周期,因此要求被采样的电平至少维持一个机器周期。当晶振频率位12MHz时,最高计数频率不超过1/2MHz,即技术脉冲的周期要大于2us。



    补充,

    定时计数器2: MCS-52单片机新增的定时计数器。

    特点:

          --16位定时计数器

          --具有捕捉、自动重装、波特率发生器3种工作模式

          --可作为编程时钟发生器

    寄存器:

          T2CON-定时器2控制寄存器

          T2MOD定时器2方式寄存器

          TH2,TL2定时计数寄存器

          RCAP2H,RCAP2L-捕获/重装寄存器

    引脚:

          T2(P1.0):定时器2外部时钟输入/时钟输出

          T2EXP(P1.1):定时器2重装/捕获/方向控制


    IE, IP, IPH中有定时器2的中断允许,终端优先控制位。


    T2CON 寄存器

    地址:0C8H 复位值:00000000B

    7

    6

    5

    4

    3

    2

    1

    0

    TF2

    EXF2

    RCLK

    TCLK

    EXEN2

    TR2

    C/T2

    CP/RL2

     

    符号

    功能

    T2CON.7

    TF2

    定时器2溢出标志位。

    RCLK或TCLK=1时不置位。

    T2CON.6

    EXF2

    定时器2外部标志。

    当EXEN2=1时,T2EX的负跳变产生捕获或重装时,EXF2=1.

    T2CON.5

    RCLK

    接受时钟标志

    T2CON.4

    TCLK

    发送时钟标志

    T2CON.3

    EXEN2

    定时器2外部使能标志。

    T2CON.2

    TR2

    定时器2启动/停止控制位。0停止,1启动。

    T2CON.1

    C/T2

    定时器计数器选择:0定时,1计数。

    T2CON.0

    CP/RL2

    捕获重装标志,1捕获,0重装。

    定时器2可以产生2个中断请求信号,分别是TF2和EXF2,这2中断请求信号通过逻辑“或”的关系共享一个终端请求通道。

    定时器2溢出时,TF2置1,向CPU申请中断。若在定时器2工作在重装模式时候,使RCAP2H,RCAP2L的值自动装入TH2,TL2。

    当EXEN2=1时,T2EX引脚的负跳变使EX2F置1,这个信号除了向CPU申请中断外,根据定时器2的工作方式,还有2个作用:一是将TH2,TL2的值装入RCAP2H,RCAP2L,称为捕获;二是将RCAP2H,RCAP2L的值装入TH2,TL2,称为重装。

    TF2,EXF2必须由软件清除。

    RCLK:当该位置1时,定时器2做串口接受波特率发生器,即接受时钟。否则使用定时器1做波特率发生器。

    TCLK:当该位置1时,定时2做串口波特率发生器,即发送时钟。否则使用定时器1做波特率发生器。

    TR2:置1时允许T2计数,置0时禁止T2计数

    C/T2:置1时定时器2对T2引脚输入的脉冲计数。置0时定时器2对内部震荡信号的12分频或6分频计数。

    CP/RL2:捕获/重装标志,置1时捕获,置0时重装。当定时器2做波特率发生器时,强制自动重装,不管该位状态。

    捕获模式:



    CKCON的X2位控制内部振荡信号是12分频还是6分频。

    T2CON的C/T2位控制T2对内部脉冲计数还是对外部脉冲计数。

    T2CON的TR2位启动或停止计数

    T2CON的CP/RL位置1,使T2工作在捕获模式

    T2CON的EXEN2置1,连接T2EX引脚到捕获控制端。

    在T2EX引脚的负跳变时刻,使TH2的值捕获到RCAP2H,TL2的值捕获到RCAP2L,同时使T2CON的EXF2置1,向CPU申请中断。

    当T2溢出时,T2CON的TF2置1向CPU申请中断。

    捕获方式可以用来测量外部脉冲的周期。

     

    自动重装模式

    自动重装模式下定时器的初值由硬件自动恢复。这个特性降低了软件开销。

    T2的工作在自动重装模式时计数方向可变,即定时器2即可工作在增量式计数方式,也可工作在减量式计数方式。计数方式的选择由T2MOD寄存器的DCEN位控制使能,由T2EX引脚控制计数方向。

    定时器2也可以在T2(P1.0)引脚输出可编程时钟。

    通过配置T2MOD寄存器选择以上功能。

     

    T2MOD寄存器

    地址0C9H   复位值:XXXXXX00B

    7

    6

    5

    4

    3

    2

    1

    0

    -

    -

    -

    -

    -

    -

    T2OE

    DCEN

     

    符号

    功能

    T2CON.1

    T2OE

    定时器2输出使能

    T2CON.0

    DCEN

    向下计数使能位,置1使能。

    其他不用的位在编程时不要置1.

     

    自动重装载模式


     

    自动重装模式(DCEN=0)说明

    CKCON的X2位控制内部振荡信号是12分频还是6分频。

    T2CON的C/T2位控制T2对内部脉冲计数还是对外部脉冲计数。

    T2CON的TR2位启动或停止计数

    T2CON的CP/RL位置0,使T2工作在自动重装模式

    T2CON的EXEN2置1,连接T2EX引脚到重装控制端。

    在T2EX引脚的负跳变时刻,使RCAP2H 的值重装到TH2 , RCAP2L 的值重装到TL2 ,同时使T2CON的EXF2置1,向CPU申请中断。

    当T2溢出时,T2CON的TF2置1,使RCAP2H 的值重装到TH2 , RCAP2L 的值重装到TL2 ,同时向CPU申请中断。

    在DCEN=0时,定时器2增量式计数。

     

    自动重装模式(DCEN=1)

    自动重装模式(DCEN=1)说明

    CKCON的X2位控制内部振荡信号是12分频还是6分频。

    T2CON的C/T2位控制T2对内部脉冲计数还是对外部脉冲计数。

    T2CON的TR2位启动或停止计数

    T2CON的CP/RL位置0,使T2工作在自动重装模式

    T2CON的EXEN2置1,连接T2EX引脚到重装控制端。

    在定时器2溢出时,自动装入初值。

    当T2EX=0时,定时器2减量方式计数,FFH自动装入TH2和TL2。

    当T2EX=1时,定时器2增量方式计数,RCAP2H自动装入TH2,RCAP2L自动装入TL2。

     

     

    波特率发生器模式

    当T2CON的RCLK=1,或TCLK=1,或RCLK=TCLK=1时,定时器2做波特率发生器。

    这时定时器2强制自动重装。

    T2CON的C/T2=0时,定时器2对内部振荡脉冲的2分频计数。

    T2CON的TR2位启动或停止T2计数

    定时器2溢出时不向CPU申请中断,溢出信号16分频后做串口的发送或接收时钟。由RCLK,TCLK的状态决定。

    当T2CON的EXEB2=1时,T2EX引脚可做为外部中断源,该引脚的负跳变使EXF2=1向CPU申请中断

     

     

    可编程时钟输出

    通过对定时器2的设置,可在T2(P10)引脚上输出频率可编程的时钟脉冲。

    T2CON的设置

    RCLK=TCLK=0

    C/T2=0

    CP/RL=0

    TMOD2的T2OE=1

    RCAPH2,RCAPL2的值控制输出时钟频率。

    输出时钟频率=

    振荡器频率/4*[65536-(RCAP2H,RCAP2H)]



    展开全文
  • 单片机学习(三)定时器

    千次阅读 2018-07-29 19:03:50
    一、定时器介绍  定时/计数器T0和T1分别是由两个8位的专用寄存器组成,即定时/计数器T0由TH0和TL0组成,T1由TH1和TL1组成。此外,其内部还有2个8位的特殊功能寄存器TMOD和TCON,TMOD负责控制和确定T0和T1的功能和...

    一、定时器介绍

           定时/计数器T0和T1分别是由两个8位的专用寄存器组成,即定时/计数器T0由TH0和TL0组成,T1由TH1和TL1组成。此外,其内部还有2个8位的特殊功能寄存器TMOD和TCON,TMOD负责控制和确定T0和T1的功能和工作模式,TCON用来控制T0和T1启动或停止计数,同时包含定时/计数器的状态。 [1] 

    TF1:定时器1溢出标志。定时/计数器溢出时由硬件置位。中断处理时由硬件清除。或用软件清除。

    TF0:定时器0溢出标志。定时/计数器溢出时由硬件置位。中断处理时由硬件清除,或用软件清除。

    二、单片机的内部框图与定时器工作原理分析


    从上面的图中红线可以看出由TMOD选择由那个定时器工作,工作于什么方式;
    从上面的图中蓝线可以看出由TCON决定定时器是否启动;
    从上面的图中黄线可以看出外部技术输入由TH和TL进行累计;
    从上面的图中紫线可以看出当TH和TL计数溢出时会向TCON进行申请报告;
    从上面的图中绿线可以看出所有的定时中断都由TCON向CPU进行中断申请;
    从上面的图中黑线可以看出外部中断直接向CPU进行中断申请;

    三、寄存器介绍

    TCON:
    TF0和TF1:定时器/计数器溢出标志位。

                        当定时器/计数器0(或定时器/计数器1)溢出时,由硬件自动使TF0(或TF1)置1,并向CPU申请中断。

                        CPU响应中断后,自动对TF1清零。TF1也可以用软件清零。 

    TR0和TR1:定时器/计数起运行控制位。  
                         TR0(或TR1)=0,停止定时器/计数器0(或定时器/计数器1)工作。
                         TR0(或TR1)=1,启动定时器/计数器0(或定时器/计数器1)工作。

     

    TMOD:
    GATE:门控位。  
                 GATE=0,只要用软件使TR0(或TR1)置1就能启动定时器/计数器0(或定时器/计数器1);
                 GATE=1,只有在(或)引脚为高电平的情况下,且由软件使TR0(或TR1)置1时,才能启动定时器/计数器0(或定时器/计数器1)工作。不管GATE处于什么状态,只要TR0(或TR1)=0定时器/计数器便停止工作。
    C/T: 定时器/计数器工作方式选择位。
               C/T =0,为定时工作方式;
               C/T=1,为计数工作方式。  
    M0、M1:工作方式选择位,确定4种工作方式。


    IE:
    EA = 1, CPU开放总中断;     
    ET0 = 1,允许T0中断;
    TR TL:定时器寄存器
    注意:由于reg52.h的库定义了大部分的寄存器所以可以直接给TCON TMOD IE赋值操作或者是单独寄存器操作。


    四、中断程序执行方法和定时计数公式
    中断程序执行方法有直接中断和查询两种方法,查询即查询TF位是否置位为1
    定时初值计算公式为:
    定时时间=(计数最大值 – 计数初值)×机器周期 
    机器周期T = 12/晶振频率


    或者是用取模的方式
    TH0=(计数最大值 – 定时时间)/256;
    TL0=(计数最大值 – 定时时间)%256;




    首先解析为什么要设定初值?
    当设定定时器为16为计数器时,则计数最大值为2^16 = 65536;
    TH和TL分别为8位,即TL每逢256进一位,所以除掉256就能看出TH进了多少位,取模则是余下多少位
    举个例子,2位计数器最大计数为4,要将初值6分到两个2位计数器,由于低位逢四进1所以剩下2

    即TL = 2然后高位是1即TH=1,按照上面的方法:2^4 = 16,2^2 = 4; TH = (16-(16-6))/4=1(整型不算小数);

    TL = (16-(16-6))%4=2;可见结果是一样的。

    一般的我们选取初值 TH0 = 0x3c,TLO = 0xb0,这时寄存器跑满时的时间为50ms,可以使这个过程进行20次,间隔也就是1s。

    五、程序设计

    //通过定时器中断实现数码管显示从0~59,间隔为1s

    #include <reg51.h>
    sbit LED1 = P1^0;
    #define DataPort P1     //宏定义,如果换接口,需要修改这里
    sbit Seg_Latch = P2^2;   //段锁存
    sbit Bit_Latch = P2^3;   //位锁存
    unsigned char code Seg_Code[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};  //段码从0~9
    unsigned char code Bit_Code[] = {0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};  //位码,控制8个LED灯
    void delayls(void);
    void Display(unsigned char m,unsigned char num,unsigned int n);
    static unsigned int n = 0;
    int main(void)
    {
            unsigned char i;
            TMOD = 0x01;
            TH0 = 0x3c;
            TL0 = 0xb0;
            EA = 1;        //开中断
            ET0 = 1;
            //因为只有一个中断,所以IP不用设置
            TR0 = 1;   //开启定时器0,等待中断到来
            while(1)
            {
                    Display(1,2,n);
            }
    }

    void T0_ISR(void) interrupt 1
    {
            unsigned char i;
            
            EA = 0;   //屏蔽其他中断
            TH0 = 0x3c;   //重新赋值,保证每次都是 50ms
            TL0 = 0xb0;
            i++;
            if(i == 20)
            {
                    i = 0;
               
                    if(n < 60)
                    {
                        n++;
                    }
                    else
                    {
                        n = 0;
                    }
            }
            
            EA = 1;
    }

     

    void Display(unsigned char m,unsigned char num,unsigned int n)   //m表示从第几个数码管开始控制,num表示到第几个数码管,n表示要显示的数字
    {
            unsigned char i,j,a[5],l;

            a[0] = n / 10;
            a[1] = n % 10;

            for(j = m-1;j < num;j++)
            {
                    DataPort = 0;   //初始化
                    Seg_Latch = 1;  
                    Seg_Latch = 0;  
                                
                    DataPort = Bit_Code[j];  //送位码
                    Bit_Latch = 1;    //位开门
                    Bit_Latch = 0;    //关门
                    
                    DataPort = Seg_Code[a[j]];  //送段码
                    Seg_Latch = 1;  //段开门
                    Seg_Latch = 0;   //关门     

            }         

    }

    展开全文
  • 定时器 目的 每过一秒静态数码管加一 代码 #include"reg51.h" #include"intrins.h" #define seg P0 //宏定义 typedef unsigned int u16; typedef unsigned char u8; u16 code smg[10]={0x3f,0x06,0x5b,0x4f,0x...

    定时器

    目的 每过一秒静态数码管加一

    代码

    #include"reg51.h"
    #include"intrins.h"
    #define seg P0                           //宏定义
    typedef unsigned int u16;
    typedef unsigned char u8;
    u16 code smg[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};   /共阴极数码管编码 CC为共阴   CA为共阳
    u16 num=0;     
    u16 i=0;
    void delay(u16 i)          							//延时函数  (约10微秒)
    {
    	while(i--);
    }
    
    void tim0_init()                        //定时器初始化函数
    {
    	EA=1;                                //中断总允许位
    	TMOD=0X01;                           //TMOD高四位是T1 低四位是T0   前两位是选择方式,第三位是选择计数器(1)或者定时器(0)  第四位门控位
    	TH0=0xd8;                            //高八位
    	TL0=0xf0;														 //第八位 (最后备注讲解怎么求初值)
    	ET0=1;                               //定时器计数器中断允许位
    	TR0=1;                               //开启定时
    }
    
    void main()                            
    {
    	tim0_init();  
    	while(1)
    	{
    		seg=~smg[num];               //因为用的共阳极   但是编码是共阴极 所以需要取反
    		delay(10);                          //消影 
    	}
    }
    
    void tim0()  interrupt 1                //中断服务函数 
    {
      TH0=0xd8;                             //对高低位重新初始化
    	TL0=0xf0;
    	i++; 
    	if(i==100)                             //根据初值 进入一次中断是10ms 所以100次是1秒
    	{
    	   num++;
    		i=0;
    	}
    	
    	if(num==10)                             //十进制中静态数码管最多显示数字9
    	{
    		num=0;
    	}
    }
    

    protues仿真图

    在这里插入图片描述
    在这里插入图片描述

    元器件

    AT89C51 (AT89C52)
    res (电阻)
    power (电源)
    seg CA(共阳极数码管)

    备注

    关于高低八位的初值计算
    因为是方式一 所以最大值为65536 累积加到65536才触发中断
    如果选择12W晶振 即累计加100次为1ms

    如果使用定时计数器 T1
    需要在初始化函数中将 ET0改为ET1
    TR0改为TR1
    TOMD 最后两位为方式选择
    00 方式0
    01 方式1
    10 方式2
    11 方式3

    展开全文
  • 51单片机定时器的原理与使用

    万次阅读 多人点赞 2017-06-18 21:04:40
    文章分析了定时器原理与定时器中断,通过实验详细阐述了定时器的使用,尤其是深入分析了各个细节问题。

    定时器是单片机的重要功能模块之一,在检测、控制领域有广泛应用。定时器常用作定时时钟,以实现定时检测,定时响应、定时控制,并且可以产生ms宽的脉冲信号,驱动步进电机。定时和计数的最终功能都是通过计数实现,若计数的事件源是周期固定的脉冲则可实现定时功能,否则只能实现计数功能。因此可以将定时和计数功能全由一个部件实现。通过下图可以简单分析定时器的结构与工作原理。

    一、定时器

    1、51单片机计数器的脉冲输入脚。主要的脉冲输入脚有Px,y, 也指对应T0的P3.4和对应T1的P3.5,主要用来检测片外来的脉冲。而引脚18和19则对应着晶振的输入脉冲,脉冲的频率和周期为

    F = f/12 = 11.0592M/12 = 0.9216MHZ      T = 1/F = 1.085us 

    2、定时器有两种工作模式,分别为计数模式和定时模式。对Px,y的输入脉冲进行计数为计数模式。定时模式,则是对MCU的主时钟经过12分频后计数。因为主时钟是相对稳定的,所以可以通过计数值推算出计数所经过的时间。

    3、51计数器的计数值存放于特殊功能寄存器中。T0(TL0-0x8A, TH0-0x8C), T1(TL1-0x8B, TH1-0x8D)

    4、TLx与THx之间的搭配关系

    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的初值。

    4)、是否开始计数。TRx

    (1)和(2)可以由工作方式寄存器TMOD来设定,TMOD用于设置定时/计数器的工作方式,低四位用于T0,高四位用于T1。其格式如下:


    GATE:门控位,用于设置计数器计数与否,是否受P3.2或P3.3电压状态的影响。GATE=0时,表示计数器计数与否与两端口电压状态无关;GATA=1时,计数器是否计数要参考引脚的状态,即P3.2为高时T0才计数,P3.3为高时T1才计数。
    C/T:定时/计数模式选择位。      =0为定时模式;    =1为计数模式。
    M1M0:工作方式设置位。定时/计数器有四种工作方式,由M1M0进行设置。


    6、计数器的溢出

    计数器溢出后,THx与TLx都归0。并将特殊功能区中对应的溢出标志位TFx写为1。

    好了,理论就讲述到这。现在我们通过一些实验来看看怎么使用定时器。

    实验一、P1口连接的8个LED灯以1秒钟的频率闪烁。

    首先上代码:

    #include "reg51.h"
    char c;
    
    void Timer0_Init() //初始化定时器
    {
       TMOD = 0x01;		//
       TH0 = 0;
       TL0 = 0;	  //定时器的计数起点为0
       TR0 = 1;	//启动定时器0
    }
    
    void main()
    {
    	Timer0_Init();
    	while(1)
    	{
    		if(TF0 == 1) //检测定时器0是否溢出,每到65535次
    		{
    			TF0=0;
    			c++;
    			if(c==14)	 //71ms乘以14为1s
    			{
    				c=0;
    				P1=~P1;
    			}
    		}
    	}
    }
    上述代码的思路是每计算14个溢出,则翻转P1口状态。产生一个溢出的时间是71.1ms,14个则约为1s。


    实验二、让一个LED灯每1秒钟闪烁。

    #include "reg51.h"
    sbit LD1 = P1^0;
    
    void Timer0_Init() //初始化定时器
    {
       TMOD = 0x01;		//
       TH0 = 0;
       TL0 = 0;	  //定时器的计数起点为0
       TR0 = 1;	//启动定时器0
    }
    
    void Timer0_Overflow()	//处理定时器0的溢出事件
    {
    	static char c;
    	if(TF0 == 1) //检测定时器0是否溢出,每到65535次
    		{
    			TF0=0;
    			c++;
    			if(c==14)	 //71ms乘以14为1s
    			{
    				c=0;
    				LD1=!LD1;
    			}
    		}	
    }
    
    void main()
    {
    	Timer0_Init();	  //初始化定时器0
    	while(1)
    	{
    		Timer0_Overflow();
    	}
    }
    相比于上个例子,这里有两个区别,首先是将timer0的溢出事件作为子函数单独出来,其次是注意翻转一个led灯时候用的是“!”。

    例子三、让连接到P1口的LED1和LED8灯每1秒钟闪烁。

    #include "reg51.h"
    
    void Timer0_Init() //初始化定时器
    
    {
       TMOD |= 0x01;		//定时器0方式1,计数与否不受P3.2的影响
       TH0 = 0;
       TL0 = 0;	  //定时器的计数起点为0
       TR0 = 1;	//启动定时器0
    }
    
    void Timer0_Overflow()	//´处理定时器0的溢出事件
    {
    	static char c;
    	if(TF0 == 1) //检测定时器0是否溢出,每到65535次
    		{
    			TF0=0;
    			c++;
    			if(c==14)	 //71ms乘以14为1s
    			{
    				c=0;
    				P1 ^= (1<<0);//LD1=!LD1;
    			}
    		}	
    }
    
    void Timer1_Init()
    {
    	TMOD|=0x10; //定时器1方式1,计数与否不受P3.3的影响
    	TH1=0;
    	TL1=0; //定时器1的计数起点为0
    	TR1=1; //启动定时器1
    }
    
    void Timer1_Overflow()	//处理定时器1的溢出事件
    {
    	static char c;
    	if(TF1==1) //软件查询,主循环每跑完一圈才会到这里。
    	{
    		TF1=0;
    		c++;
    		if(c==14)
    		{
    			c=0;
    			P1 ^= (1<<7);//LD8=!LD8;
    		}
    	}	
    }
    
    void main()
    {
    	Timer0_Init();	  //初始化定时器0
    	Timer1_Init(); 	   //初始化定时器1
    	while(1)
    	{
    		Timer0_Overflow();
    		Timer1_Overflow();
    	}
    }
    相较于例二,例子三有几个点值得注意:

    1、TMOD初始化为什么采用TMOD |= 0x01或0x10的形式?

          首先如果在定时器初始化函数中采用TMOD = 0x01和TMOD = 0x10,那么将造成LD1闪烁比LD8闪烁快8倍。分析一下,从main函数开始执行,先是初始化timer0,这时候定时器1设置为工作方式1。接着程序执行到Timer1_Init(),这时候TMOD=00010000,即选定了timer1在工作方式1,但同时timer0重新配置为工作方式0, 也就是32进制,所以产生快8倍现象。

         那为什么用|这个符号就可以做到互不影响呢?|是或运算符,即有1出1,全0出0。什么意思呢?举个例子,a是11110000,b是10101010,那么a|b就是11111010。通过引入这个符号,可以实现tmod对两个定时器的独立操作。


    2、为什么使用P1 ^= (1<<0)可以实现LD1的控制呢?

          首先解释下^这个符号。^称为异或运算符,相同出0,不同出1。举个例子,a是11110000,b是10101010,那么a^b就是01011010。

          然后再来分析 x ^= (1<<i), 假设x为10101010,当i为1时, (1<<i)为00000010,那么x^ (1<<i)=10101010^00000010=10101000。当i为2时,(1<<i)为00000100,那么x^ (1<<i)=10101010^00000100=10101110,以此类推。我们发现,x ^= (1<<i)是在将x的第i位翻转而同时不影响其他位。

         因此P1 ^= (1<<0)实际是在翻转P0口第一位的值,因此也就是在闪烁LD1灯。


    上面三个例子实际都是采用了软件查询法。即main函数会每次进入到溢出事件函数里去判断TF0或1是否等于1,这样就浪费了大量CPU时间。同时,实时性差,假如在执行Timer0_Overflow()的时候timer1也溢出了,这时候timer1的溢出事件就没有及时处理。因此下面我们要引入中断系统。


    二、中断系统

    中断系统是一套硬件电路,它可以在每个机器周期对所有的外设的标志位作查询。相比于前面的软件查询(if(xx==1)),中断系统也可以叫做硬件查询。51的中断系统可查询以下6个标志位。

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

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

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

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

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

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

    当中断系统查询到外设的标志位变为1时,中断系统可暂停当前的主循环,并且将程序跳转到用户预先指定的函数中执行。要启动中断系统,必须先进行中断初始化,其流程如下:

    a、是否要查询外设标志(EA=0或EA=1,EA 也叫 CPU中断允许(总允许)位)

    b、查询到标志1,是否要跳程序

    c、跳转的目标函数,即中断服务子函数

    所以在使用定时器中断时,我们只需要首先初始化中断系统,开启总中断(相当于总开关),开启定时器对应的控制位(相当于支路开关),再初始化定时器即可。中断系统作为单片机的外设,只有在某个中断产生时才会打断主循环,并由相应的中断号引入到相应的中断服务子函数。下图是6个中断标志位的信息。



    实验四、使用中断系统实现LD1灯每1秒钟闪烁。

    #include "reg51.h"
    
    void Timer0_Init()
    {
    	TMOD|=0x01;
    	TH0=56320/256;	 //计数起点为56320 ==10ms溢出一次
    	TL0=56320%256;
    	TR0=1;
    }
    
    void Timer1_Init()
    {
    	
    }
    
    void ISR_Init()	   //初始化中断系统
    {
    	EA=1; //启动中断系统
    	EX0=0; //-->IE0
    	ET0=1; //-->TF0 控制位置1,表明当TF0置1时,中断系统将介入 
    	EX1=0; //-->IE1
    	ET1=0; //-->TF1
    	ES=0; //-->RI,TI
    
    }
    
    //以下中断服务子程序,我们希望中断系统来调用,而不是我们在main函数里面调用,因此使用interrupt. */
    
    void IE0_isr() interrupt 0
    {
    
    }
    
    /*void TF0_isr()	interrupt 1	 //71.1ms 进入一次,但如果要求10MS进来一次呢?
    {
    	static char c;
    	c++;
    	if(c==14)
    	{
    		P1^=(1<<0);
    		c=0;
    	}
    }
    */
    void TF0_isr()	interrupt 1	 //10ms 进入一次
    {
    	static char c;
    	TH0=56320/256;	 //重装初值
    	TL0=56320%256;
    	c++;
    	if(c==100)
    	{
    		P1^=(1<<0);
    		c=0;
    	}
    }
    
    void IE1_isr()	interrupt 2
    {
    
    }
    
    void TF1_isr() interrupt 3
    {
    	
    }
    
    void RI_TI_isr() interrupt 4
    {
    
    }
    
    void main()
    {
    	 Timer0_Init();
    	 Timer1_Init();
    	 ISR_Init();
    
    	 while(1)
    	 {
    	 	 //...
    		 //发现溢出后,中断系统根据中断号寻找中断子服务函数,并强行暂停主循环并进入子函数
    		 //...
    	 }
    }
    显然使用中断系统查询得到的1s更为精确。因为中断系统独立于main函数运行。另外本程序还预装了timer0的初值,这样的话就可以实现比71ms更小的时间片,比如要求10ms就进入中断。关于初值的设定,请参考下图。


    实验五、用定时器实现数码管显示1234。

    //数码管的定时扫描,每5ms显示一个数码管,也就是说相同的数码管,每20ms会被重新装入同样的数值,根据人眼的延迟效应,人眼观测到的数码管上的数值是静态的。
     #include "reg51.h"
     unsigned int count;
     extern void load_smg();
     void Timer0_Init()
     {
     	TMOD|=0X01;
    	TH0=60928/256;
    	TL0=60928%256;//每5ms进入一次中断
    	TR0=1;
     }
    
    void isr_Init()
     {
     	EA=1;
    	ET0=1; //TF0 如果这个标志为1,进入中断子函数
     }
    
     void TF0_isr() interrupt 1
     {
     	TH0=60928/256;
    	TL0=60928%256;//重装初值
    	load_smg();
     }
    
     void main()
     {
     	Timer0_Init();
     	isr_Init();
    	while(1)
    	{
    	
    	}
    
     }
    
     #include "reg51.h" 
      //char seg[10]={0xC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90};
     code char seg[10]={0xC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90};
     char smgbuf[4]={1,2,3,4}; //从RAM的smgbuf这个地址开始连续存放4个数,并且每个数占一个单元。
     extern unsigned int count;	//外部申明,表示并不在这里申明
    
    void fill_smgbuf() //向LED缓冲区填充数据
    {
    	smgbuf[0]=count/1000;  //千位
    	smgbuf[1]=(count%1000)/100;  //百位
    	smgbuf[2]=((count%1000)%100)/10;   //十位
    	smgbuf[3]=((count%1000)%100)%10;   //个位
    }
    
    void load_smg()   //将数码管显示缓冲区的数据,显示到数码管上
     {
     	static char i;
    	fill_smgbuf();
    	i++;
    	if(i>=4)
    	{
    		i=0;
    	}
    	P0=0xFF;   //消除上一个循环的影子
    	P2 = ~(1<<i);
    	P0 = seg[smgbuf[i]];	
     }

    实验六、实现按钮控制数码管上的数值加1或减1,并且当按住按钮不放时,能实现快速的增减。


    这里的关键点在于如何实现快速增减,具体请详细分析代码。代码链接点击打开链接

    展开全文
  • 单片机中断原理及定时器详解

    万次阅读 多人点赞 2018-04-22 17:20:21
    一、中断系统1.1.中断的概念什么是中断:CPU在处理某一事件A时,发生的另外某一事件B请求CPU去处理(产生了中断),随后CPU暂时中断当前正在执行的任务,去对事件B进行处理,CPU处理完事件B后再返回之前中断的位置...
  • 单片机定时器概念和认识

    千次阅读 2016-09-20 17:00:43
    一、MCS-51单片机定时器/计数器概念 单片机中的定时器和计数器其实是同一个物理的电子元件,只不过计数器记录的是单片机外部发生的事情(接受的是外部脉冲),而定时器则是由单片机自身提供的一个非常稳定的计数器,...
  • 51单片机定时器/计数器应用实例(方式0、1、2、3)

    万次阅读 多人点赞 2019-05-26 22:19:13
    对于刚接触单片机的同学来说可能会对定时器/计数器的应用很蒙圈,特别是初值的计算和各种定时方式的选择。下面希望能给你带来一个清晰的思路。 定时器:一般用于软件计时,给定时器设置一个时间,时间到了系统停止...
  • 单片机定时器总结

    2020-07-11 18:03:01
    单片机定时器的使用可以说非常简单,只要掌握原理,有一点的C语言基础就行了。要点有以下几个: 1. 一定要知道英文缩写的原形,这样寄存器的名字就不用记了。 理解是最好的记忆方法。好的教材一定会给出所有英文...
  • 51单片机定时器中断

    万次阅读 2019-06-08 23:58:02
    51单片机有2个16位定时器/计数器:定时器0(T0为P3.4) 和定时器1(T1为P3.5) 这里所说的16位是指定时/计数器内部分别有16位的计数寄 存器。当工作在定时模式时,每经过一个机器周期内部的16位计数 寄存器的值就会...
  • 51单片机定时器工作方式1、2原理详解

    万次阅读 多人点赞 2020-05-30 20:02:24
    1.本篇博文旨在帮助那些像我一样刚入门51单片机,如果你对定时器有一定了解,但是其中的的工作方式不能理解,那么这篇文章很适合你,如果你是大神的话…直接绕行吧…… 2.我在学习的过程中由于知识上的不足很多的...
  • STC89C52单片机定时器2详细整理

    万次阅读 多人点赞 2020-03-10 15:44:13
    51单片机是我自学的第一款单片机,那时正好是过春节,想起那个寒假,外面下着大雪,有时...定时器2是新增资源,也是51单片机定时器里面功能最强大的一个定时器。所以掌握好定时器2还是非常有必要的。以下是在我完全搞明
  • 51单片机定时器计算工具,方便计算,自动生成C语言代码
  • 1、单片机定时器中断后计数器是否还会计数 解决:单片机定时器中断后计数器还是会计数的,如果重新赋值,会按照设置的时间进行计时。如果没有,则从0开始。 2、单片机在执行定时器中断时,是否在没执行当前中断...
  • 51单片机定时器实验

    2020-07-21 15:33:46
    51单片机定时器实验,代码简洁全面,均有标注,通俗易懂。
  • 单片机定时器实验仿真图及汇编程序,c语言程序。大学单片机技术实验课定时器答案
  • STC单片机定时器(1T_12T)初值计算器

    热门讨论 2020-07-30 23:32:50
    STC单片机定时器(1T_12T)初值计算器,支持1T定时器算法
  • 单片机定时器溢出后会继续计数,从“65536-设置“的初值开始,只有当TRn=0时才停止计数 单片机 定时器/计数器, 可以用来 作 定时器 或者 外部计数器 作 定时器 一般以中断 形式完成,当 定时器溢出后 产生中断,...
  • 51单片机定时器初值的计算

    千次阅读 2018-04-12 16:46:46
    51单片机定时器初值的计算: 二、50MS定时器初值的计算: 1.晶振12M 12MHz除12为1MHz,也就是说一秒=1000000次机器周期。50ms=50000次 机器周期。 65536-50000=15536(3cb0) TH0=0x3c,TL0=0xb0 2.晶振...
  • 51单片机定时器初值计算

    万次阅读 多人点赞 2017-08-08 09:56:58
    **菜鸟关于51类单片机定时器初值计算问题的计算**首先先来介绍单片机的几个周期: 1、时钟周期,也称为振荡周期:定义为时钟脉冲的倒数,在单片机中也就等于晶振的倒数。 51单片机中把一个时钟周期定义为一个...
  • 单片机 定时器/计数器

    千次阅读 2019-01-10 14:32:48
    单片机 定时器/计数器 一、简述  MCS—51系列单片机内部有两个16位定时器/计数器,即定时器T0和定时器T1。它们都具有定时和计数功能,可用于定时或延时控制,对外部事件进行检测、计数等。  定时器/计数器是一...
1 2 3 4 5 ... 20
收藏数 19,353
精华内容 7,741
关键字:

单片机定时器