定时器及其应用

定时器及其应用

为什么要使用定时器

在前面的案例中,我们都是使用一个Delay函数实现延时,而Delay函数却会造成很多的不方便,因为在Delay的延时过程中,我们无法同时进行其他的事情,就比如我们使用洗衣机洗个衣服,如果我们啥也不干,就只在洗衣机前干等着就相当于单片机中使用Delay函数,但是我们知道,现实生活中我们还有很多别的事可以做,所以我们就可以定个闹钟,先干别的事情,等闹钟响了我们再来取衣服,而单片机中的定时器就是这个闹钟,有了闹钟的加入,我们的单片机的效率就可以大大提升。

怎么使用定时器

我们在学习单片机的时候,一定要记住两句话,单片机通过配置寄存器来控制内部线路的连接寄存器是连接软硬件的媒介,我们使用定时器也不例外,首先我们需要知道,定时器有哪些寄存器,通过查看手册可以知道分别有控制寄存器TCON和工作模式寄存器TMOD,所以我们只需要对这两个寄存器分别配置即可使用定时器。

在我们等待洗衣机洗衣服的时候,我们在做别的事情,但是当闹钟响时我们需要先放下手中的事情,去洗衣机收衣服,收完衣服后我们要继续做没有完成的事情,这个过程在单片机中就由中断系统来实现,因此我们需要对中断系统由一定的了解并配置中断系统的寄存器。

所以我们只需要分别配置定时器的工作模式、控制方式、中断系统三个部分,即可实现定时器工作

(我们目前只对定时器0进行配置)

定时器控制

其中寄存器TCON为可位寻址(可以单独对其某一位赋值),各位如下:

SFR nameAddressbitB7B6B5B4B3B2B1B0
TCON88HnameTF1TR1TF0TR0IE1IT1IE0IT0

TCON我们只对定时器0的相关位进行赋值 定时器范围为0~65535,每隔1us计数加一,总共定时65535us即65.535ms不足一秒 1s:1ms执行1000次,给定定时器初值64535,理溢出差值就为1000,实现计时1ms,所以我们还需要对定时器的初值进行设置,赋值为:

TF0=0;
TR0=1;
TH0=64535/256;      //高位赋值
TL0=64535%256;      //低位赋值

中断系统

中断系统结构如图:

6da3139706170775b634930eea1efa30a27f87950d124918.png

我们在使用定时器0即Timer0时,我们想要其进入中断程序,就需要对其各个寄存器(红线圈出来的位置)进行配置,具体参数配置为:

ET0=1;                      //配置中断
EA=1;                       //配置中断
PT0=0;                      //配置中断

定时器工作模式选择

寄存器TMOD为不可位寻址(只能整体赋值),各位如下:

GATEC/TM1M0GATEC/TM1M0
定时器1定时器1定时器1定时器1定时器0定时器0定时器0定时器0

TMOD的低四位为定时器0的位

M1和M0决定定时器工作在哪种模式,定时器有四种模式,分别为

模式0:13位定时器/计数器

模式1:16位定时器/计数器(常用)

模式2:8位自动重装模式

模式3:两个8位计数器

C/T选择定时器或计数器,门控端控制工作 我们想要让定时器工作在模式一,那么就给TMOD最后两位,分别给M1和M0 0和1 选择定时器模式,则给倒数第三位C/T位0 门控端给0

赋值如下:

TMOD=0x01;              //0000 0001

但是这样会对定时器1的值造成影响,而在我们不能对其进行位赋值的情况下,我们可以使用按位与和按位或来只对寄存器的低四位进行赋值,实现如下:

TMOD&=0xF0;             //将TMOD的低四位全置为0,高四位不变
TMOD|= 0x01;            //将TMOD的最低位置为1,其余位不变

综上所述,对定时器0的初始化进行模块化,封装为一个函数,得到:

void Timwer0_Init()
{
    TMOD&=0xF0;             //将TMOD的低四位全置为0,高四位不变
    TMOD|= 0x01;            //将TMOD的最低位置为1,其余位不变
    TF0=0;
    TR0=1;                  //让定时器开始工作
    TH0=64535/256;          //高位赋值
    TL0=64535%256;          //低位赋值
    ET0=1;                  //配置中断
    EA=1;                   //配置中断
    PT0=0;                  //配置中断
}

当我们使用这个“闹钟”的时候,我们要设置好,”闹钟“响后到底要干什么,所以,我们需要写一个中断子程序,来执行中断后到底要进行什么工作,中断子程序的模板为:

void Timer0_Routine()   interrupt 1//中断子程序
{
    static unsigned int T0_Count;//static使T0_Count在函数结束后的值仍然保持不变
    TH0=64535/256;
    TL0=64535%256;              //定时器需要重新赋初值
    if(T0_Count++ >= 1000)      //定时器的时长为1ms,执行一千次得到1s
    {                           //每隔1s执行一次if的函数体内的内容
        T0_Count=0;
        P2_0=~P2_0;             //此处为改变LED0的状态
    }
}
//以上是一个使LED0进行闪烁的子程序,设置的间隔为1s

定时器的应用示例

使用定时器实现控制流水灯

#include <REGX52.H>
#include "Timer0.h"
#include "Key.h"
#include <INTRINS.H>
unsigned char KeyNum,LEDMODE;//KeyNum记录按键编号 LEDMODE记录流水灯模式
void main()
{
    P2=0xFE;
    Timer0_Init();              //定时器初始化
    while(1)
    {
        KeyNum=Key();           //监测按键按下
        if(KeyNum)
        {
            if(KeyNum==1)       //按了一下按键1
            {
                LEDMODE++;      //LEDMODE加一
                if(LEDMODE>=2)  LEDMODE=0;//LEDMODE只会取值0和1
            }
        }
    }
}
​
void Timer0_Routine()           interrupt 1//中断子程序
{
    static unsigned int T0_Count;//static使T0_Count在函数结束后的值仍然保持不变
    TH0=64535/256;
    TL0=64535%256;              //定时器需要重新赋初值
    if(T0_Count++ >= 500)
    {
        T0_Count=0;
        if(LEDMODE==0)      //LEDMOED为0时流水灯左流
        {
            P2=_crol_(P2,1);//函数crol包含在头文件<INTRINS.H>中实现循环右移
        }
        if(LEDMODE==1)      //LEDMODE为1时流水灯右流
        {
            P2=_cror_(P2,1);//cror循环右移
        }
            
    }
}

程序运行分析:主函数中第一步将LED0点亮,之后调用第一个函数定时器初始化函数Timer0_Init此时相当于已经设置好了闹钟,中断程序1在闹钟每隔500个闹钟周期(0.5s)就会执行一次if内的语段(判断LEDMODE并实现一次流水)。主函数始终运行在while循环中,不断收集判断按键情况,每按下一次按键LEDMODE就会改变,从而改变流水灯的流水方向

使用定时器实现时钟显示

#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "Timer0.h"
​
unsigned char Sec=55,Min=59,Hour=23;
void main()
{
    LCD_Init();
    Timer0_Init();
    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 T0_Count;
    TH0=64535/256;
    TL0=64535%256;
    if(T0_Count++ >= 1000)
    {
        T0_Count=0;
        Sec++;
        if(Sec>=60)
        {
            Sec=0;
            Min++;
            if(Min>=60)
            {
                Min=0;
                Hour++;
                if(Hour>=24)
                    Hour=0;
            }
        }
    }
}

程序运行方式类似流水灯

  • 24
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值