C51单片机学习(二):定时器与中断系统详解

参考

  • 51单片机入门教程
  • 1. 定时器

    1.1 定时器定义

  • 51 单片机的定时器属于单片机的内部资源,其电路的连接和运转均在单片机内部完成
  • C51 单片机学习(一):基础外设 讲的都是单片机的 IO 口控制的外设
  • 1.2 定时器作用

  • 用于计时系统,可实现软件计时,或者使程序每隔一固定时间完成一项操作
  • 替代长时间的 Delay,提高 CPU 的运行效率和处理速度
  • Delay() 时 CPU 干不了其它事,就会白白占用 CPU 的时间
  • 1.3 STC89C52 定时器资源

  • 定时器个数:3个(T0、T1、T2),T0 和 T1 与传统的 51 单片机兼容,T2 是此型号单片机增加的资源

    注意:定时器的资源和单片机的型号是关联在一起的,不同的型号可能会有不同的定时器个数和操作方式,但一般来说,T0 和 T1 的操作方式是所有 51 单片机所共有的(T:Timer,计数器

  • 1.4 定时器框图

  • 定时器在单片机内部就像一个小闹钟一样,根据时钟的输出信号,每隔 “一秒”,计数单元的数值就增加一,当计数单元数值增加到 “设定的闹钟提醒时间” 时,计数单元就会向中断系统发出中断申请,产生 “响铃提醒”,使程序跳转到中断服务函数中执行
  • 中断系统也是 51 单片机的内部资源,中断系统是为了使 CPU 具有外界紧急事件的实时处理能力而设置
  • 1.5 定时器工作模式

  • STC89C52 的 T0 和 T1 均有四种工作模式
  • 模式 0:13 位定时器/计数器
  • 模式 1:16 位定时器/计数器(常用)
  • 模式 2:8 位自动重装模式
  • 模式 3:两个 8 位计数器
  • 1.6 定时器时钟

  • SYSclk 系统时钟(下图左上部分):即晶振周期,本开发板上的晶振为 12MHz
  • MCU in 12T mode 进行 1MHZ 的一个分频,每隔 1us 进行一次计数,当它为最大值时就会产生一次中断
  • T0 pin:单片机外部的一个接口,时钟可以由系统时钟提供也可以由外部引脚提供
  • 中间是一个选择开关,C = Count(计数) ,T = Timer(计时器) ,C = 1、T = 0,如果这一位给 1 就链接到 T0 pin ,给 0 就是连接到 SYSclk
  • 计数/定时系统(下图左下部分):TL0(低字节)和 TH0(高字节),0 代表定时器 0,这是一个十六位的计数器,这两个字节计数范围 0~65535
  • 计数系统的左边的时钟给了它提供了一个脉冲(方波),每来一个脉冲它的定时器的值就会加 1,一直这样循环往复的话,当加到 65535 时,那么再下一个脉冲的时候它就会产生一个溢出,溢出时这个计数器就会到 0 的位置
  • 溢出标志位:TF0,负责向中断系统申请中断请求
  • TR0 控制定时器的启动是否暂停,当 TR0 = 1 时开始计数
  • 2. 中断系统

    2.1 概述

    2.2 中断程序流程

    2.3 STC89C52 中断资源

  • 中断源个数:8 个(外部中断 0、定时器 0 中断、外部中断 1、定时器 1 中断、串口中断、定时器 2 中断、外部中断 2、外部中断 3)
  • 中断优先级个数:4 个
  • 中断号
  • 注意:中断的资源和单片机的型号是关联在一起的,不同的型号可能会有不同的中断资源,例如中断源个数不同、中断优先级个数不同等等

    3. 定时器和中断系统

    3.1 连接框图

  • 中断源:INT0(外部中断 0)、INT1(外部中断 1)、T0(定时器 0)、T1(定时器 1)、RXD 和 TXD(同属串口中断)
  • 3.2 相关寄存器

  • 寄存器是连接软硬件的媒介,在单片机中寄存器就是一段特殊的 RAM 存储器

  • 一方面,寄存器可以存储和读取数据
  • 另一方面,每一个寄存器背后都连接了一根导线,控制着电路的连接方式
  • 单片机中两种寄存器:ROM 和 RAM
  • 可位寻址/不可位寻址

  • 可位寻址可以单独的对一位寄存器进行赋值:如 P2 = 1; P2_1 = 1; 都可
  • 不可位寻址就是它的寄存器只能进行整体的进行赋值
  • 3.3 寄存器配置

  • TMOD 配置

  • 1.5 小节提到模式 1 最常用,则 M1 = 0,M0 = 1
  • 选用 SYSclk 系统时钟,则 C/T(取反) = 0
  • GATE(门控端),GATE = 0
  • TCON 配置

  • TF0 中断溢出标志位,程序中可直接先给 TF0 = 0,因为一旦 TF0 = 1 就会产生中断
  • TR0 = 1 表示开始计数
  • IE0 和 IT0 用来控制外部中断引脚,但 GATE 门控端 = 0,所以不用配置这两个
  • TH0 = 64536/256; // 取出高 8 位
  • TL0 = 64536%256; // 取出低 8 位
  • 3.4 中断配置

  • 参照 3.1 小节连接框图配置如下参数
  • ET0 = 1
  • EA = 1
  • PT0 = 0
  • 3.3 代码示例

    1、按键控制 LED 流水灯模式
  • Delay.h
  • #ifndef __DELAY_H__
    #define __DELAY_H__
    
    void Delay(unsigned int xms);
    
    #endif
    
  • Delay.c
  • void Delay(unsigned int xms) {
        unsigned char i, j;
        while (xms--) {
            i = 2;
            j = 239;
            do {
                while (--j);
            } while (--i);
        }
    }
    
  • Key.h
  • #ifndef __KEY_H__
    #define __KEY_H__
    
    unsigned char Key();
    
    #endif
    
  • Key.c
  • #include <REGX52.H>
    #include "Delay.h"
    
    /**
      * @brief  获取独立按键键码
      * @param  无
      * @retval 按下按键的键码,范围:0~4,无按键按下时返回值为0
      */
    unsigned char Key() {
        unsigned char KeyNumber=0;
        
        if (P3_1 == 0) {Delay(20); while (P3_1 == 0); Delay(20); KeyNumber = 1;}
        if (P3_0 == 0) {Delay(20); while (P3_0 == 0); Delay(20); KeyNumber = 2;}
        if (P3_2 == 0) {Delay(20); while (P3_2 == 0); Delay(20); KeyNumber = 3;}
        if (P3_3 == 0) {Delay(20); while (P3_3 == 0); Delay(20); KeyNumber = 4;}
        
        return KeyNumber;
    }
    
  • Timer0.h
  • #ifndef __TIMER0_H__
    #define __TIMER0_H__
    
    void Timer0Init(void);
    
    #endif
    
  • Timer0.c
  • #include <REGX52.H>
    
    /**
      * @brief  定时器 0 初始化,1 毫秒 @12.000MHz
      * @param  无
      * @retval 无
      */
    void Timer0Init(void) {
        TMOD &= 0xF0;      // 把 TMOD 低 4 位清零,高四位保持不变
        TMOD |= 0x01;      // 把 TMOD 最低位置零,高四位保持不变
        TL0 = 0x18;        // 设置定时初值,低 8 位
        TH0 = 0xFC;        // 设置定时初值,高 8 位
        TF0 = 0;           // 清除 TF0 标志
        TR0 = 1;           // 定时器 0 开始计时
        ET0 = 1;
        EA = 1;
        PT0 = 0;
    }
    
    /*定时器中断函数模板
    void Timer0_Routine() interrupt 1 {
        static unsigned int T0Count;
        TL0 = 0x18;  // 设置定时初值
        TH0 = 0xFC;  // 设置定时初值
        T0Count++;
        if (T0Count >= 1000) {
            T0Count = 0;	
        }
    }
    */
    
  • main.c
  • #include <REGX52.H>
    #include "Timer0.h"
    #include "Key.h"
    #include <INTRINS.H>
    
    unsigned char KeyNum, LEDMode;
    
    void main() {
        P2 = 0xFE;
        Timer0Init();
        while (1) {
            KeyNum = Key();          // 获取独立按键键码
            if (KeyNum) {            // 如果按键按下
                if (KeyNum == 1) {   // 如果 K1 按键按下
                    LEDMode++;       // 模式切换
                    if (LEDMode >= 2)
                        LEDMode = 0;
                }
            }
        }
    }
    
    void Timer0_Routine() interrupt 1 {
        static unsigned int T0Count;
        TL0 = 0x18;    // 设置定时初值
        TH0 = 0xFC;    // 设置定时初值
        T0Count++;     // T0Count 计次,对中断频率进行分频
        if (T0Count >= 500) {    // 分频 500 次,500ms
            T0Count = 0;
            if (LEDMode == 0)      // 模式判断
                P2 = _crol_(P2, 1);   // LED 输出
            if (LEDMode == 1)
                P2 = _cror_(P2, 1);
        }
    }
    
    2、 定时器时钟
  • main.c
  • #include <REGX52.H>
    #include "Delay.h"
    #include "LCD1602.h"
    #include "Timer0.h"
    
    unsigned char Sec=55,Min=59,Hour=23;
    
    void main() {
        LCD_Init();
        Timer0Init();
        
        LCD_ShowString(1, 1, "Clock:");  // 上电显示静态字符串
        LCD_ShowString(2, 1, "  :  :");
        
        while (1) {
            LCD_ShowNum(2, 1, Hour, 2);	//显示时分秒
            LCD_ShowNum(2, 4, Min, 2);
            LCD_ShowNum(2, 7, Sec, 2);
        }
    }
    
    void Timer0_Routine() interrupt 1 {
        static unsigned int T0Count;
        TL0 = 0x18;    // 设置定时初值
        TH0 = 0xFC;    // 设置定时初值
        T0Count++;
        if (T0Count >= 1000) {  // 定时器分频,1s
            T0Count = 0;
            Sec++;          // 1 秒到,Sec 自增
            if (Sec >= 60) {
                Sec = 0;      // 60 秒到,Sec 清 0,Min 自增
                Min++;
                if (Min >= 60) {
                    Min = 0;    // 60 分钟到,Min 清 0,Hour 自增
                    Hour++;
                    if (Hour >= 24) {
                        Hour = 0;  // 24 小时到,Hour 清 0
                    }
                }
            }
        }
    }
    
    物联沃分享整理
    物联沃-IOTWORD物联网 » C51单片机学习(二):定时器与中断系统详解

    发表评论