蓝桥杯单片机开发及应用-基础模块08-定时器的应用

一、先前知识

  1. 定时器/计数器

定时器和计数器最基本的工作原理就是计数。作为定时器时,计数信号的来源选择周期性的内部时钟脉冲;用作计数器时,计数信号的来源选择非周期的外部输入信号。不管是定时器还是计数器,本质上都是计数器。

51单片机有两个定时器/计数器T0和T1,为16位加法器,由低八位TL和高八位TH两个寄存器构成,所有的工作模式中最大计数值为65535个计数脉冲。

该加1计数器的计数脉冲来源有2个:

①系统时钟震荡输出的12分频;

②T0或T1引脚输入的外部脉冲信号。

每接收到一个计数脉冲,计数器就会加1,当计数值累计至全为1时(8位255,13位8191,16位65535),再输入一个计数脉冲,计数器便会溢出回零,并且计数器的溢出是TCON寄存器的TF0或TF1位置1,同时向内核提出中断请求。如果定时器/计数器工作于定时模式,则表示间隔定时时间到;如果工作于计数模式,则表示计数值已满。

以定时器0工作模式1为例,定时10ms,把计算得到的初值写入TH0和TL0寄存器即可:

TH0 = 0xdb;或者TH0 = (65535-10000)/256;

TL0 = 0xef;或者TL0 = (65535-10000)%256;

这里我们一般使用后面的表示方法,因为比较直观而且不用我们再算成16进制。对于这里的“/256和%256”,其实就跟我们平时使用的10进制数一样,低位取余“%”,高位取商“/”。256就是2^16。

那么如果为工作模式0(13位定时器),则应该除以(取余)2^5=32,先满足高八位填满,再填剩下的。

  1. 定时器定时初值的计算

该计算公式是以定时器工作模式1为例(2^16),不同的工作模式定时最大值不同,工作模式是几位定时器,就是2的多少次方。根据所需要的不超过最大定时值的定时时间来计算要给的初值。

图一、定时器定时初值的计算

  1. 定时器中断用到的寄存器

每个中断源都对应着一个固定的入口地址,也就是中断向量,它们分别是:

0 0x0003: INT0

1 0x000B: TF0

2 0x0013: INT1

3 0x001B: TF1

4 0x0023: RI/TI

图二、IE寄存器

图三、IP寄存器

图四、TCON寄存器

图五、SCON寄存器

图六、TMOD寄存器

总开关,总中断EA,只有当总中断EA接上之后,同时相应的中断EX0、ET0等也接上,外部中断才能控制内核。

图七、中断寄存器的顺序

  1. 关于定时器中断服务函数程序的编写(与外部中断服务函数类似,框架一样,只是函数里面的内容不一样)

一般情况下,中断的处理函数有两个,其一为中断初始化函数,其二为中断服务函数。

初始化函数就是一个普通的函数,而中断服务函数有着特殊的格式:

①中断函数没有返回值,也不能对其输入参数;

②函数名后面要跟一个关键字“interrupt”,说明这是一个中断服务函数;

③在关键字“interrupt”后面要跟上中断号,说明这个中断服务函数是为哪个中断服务的

例如:

void 函数名() interrupt 中断号

以上关于定时器中断的介绍并不像书上以及老师们讲的那么专业,都只是本人学习过程中的理解总结而已。如果读者想要了解的更完整、更精细,可以查看相关方面的书和资料。也欢迎各位给我提出意见。

二、模块控制实现过程简述

要控制LED模块,就需要先往74HC138译码器中写入二进制数100(十进制数为4),输出就是Y4为低电平,经过一个或非门输出的Y4C就为高电平,再输入74HC573锁存器。然后控制LED灯的点亮。然后用定时器设置初值时间控制LED灯的闪烁。

三、所要实现的功能

用定时器T0的模式一,定时实现每1秒L1指示灯闪烁一下,即周期为2。每5秒L8指示灯闪烁一下,即周期为10。程序循环实现上述功能。

四、代码实现

①参数以及引脚定义

// LED灯引脚定义
sbit L1 = P0^0;
sbit L8 = P0^7;

// 参数定义
unsigned char count = 0;    // 定时器0计数

②138译码器通道选择函数

// 通道选择
void HC138_Init( unsigned char channel )
{
    switch( channel )
    {
        case 0:
            P2 = ( P2 & 0x1f ) | 0x00;    // 0
        break;
        case 4:
            P2 = ( P2 & 0x1f ) | 0x80;    // Y4C
        break;
        case 5:
            P2 = ( P2 & 0x1f ) | 0xa0;    // Y5C
        break;
        case 6:
            P2 = ( P2 & 0x1f ) | 0xc0;    // Y6C
        break;
        case 7:
            P2 = ( P2 & 0x1f ) | 0xe0;    // Y7C
        break;
    }
}

③初始化系统-关闭目前不需要的蜂鸣器和继电器

// 系统初始化
void System_Init(void)
{
    // 关闭LED灯
    HC138_Init( 4 );
    P0 = 0xff;
    
    // 关闭蜂鸣器和继电器
    HC138_Init( 5 );
    P0 = 0xaf;          // 1010 1111
    
    HC138_Init( 0 );    // 关闭通道选择
    P0 = 0xff;          // 初始化P0的值
}

④定时器0初始化函数

// 定时器0初始化函数
void Timer0_Init(void)
{
    TMOD = 0x01;    // 使用定时器0工作模式1
    ET0 = 1;
    TR0 = 1;
    EA = 1;
    
    // 计数初值
    TH0 = ( 65535 - 50000 ) / 256;
    TL0 = ( 65535 - 50000 ) % 256;
    
}

⑤定时器0服务函数

// 定时器0服务函数
void Timer0() interrupt 1
{
    // 由于是不能自动重装载的,所以要再次赋初值
    TH0 = ( 65535 - 50000 ) / 256;
    TL0 = ( 65535 - 50000 ) % 256;
    
    HC138_Init( 4 );
    count++;
    if( count % 20 == 0 )    // 一秒翻转一次电平
    {
        L1 = ~L1;
    }
    if( count == 100 )       // 五秒翻转一次电平
    {
        L8 = ~L8;
        count = 0;
    }
}

⑥整个函数展示


#include <STC15F2K60S2.H>


// LED灯引脚定义
sbit L1 = P0^0;
sbit L8 = P0^7;

// 参数定义
unsigned char count = 0;    // 定时器0计数


// 通道选择
void HC138_Init( unsigned char channel )
{
    switch( channel )
    {
        case 0:
            P2 = ( P2 & 0x1f ) | 0x00;    // 0
        break;
        case 4:
            P2 = ( P2 & 0x1f ) | 0x80;    // Y4C
        break;
        case 5:
            P2 = ( P2 & 0x1f ) | 0xa0;    // Y5C
        break;
        case 6:
            P2 = ( P2 & 0x1f ) | 0xc0;    // Y6C
        break;
        case 7:
            P2 = ( P2 & 0x1f ) | 0xe0;    // Y7C
        break;
    }
}


// 系统初始化
void System_Init(void)
{
    // 关闭LED灯
    HC138_Init( 4 );
    P0 = 0xff;
    
    // 关闭蜂鸣器和继电器
    HC138_Init( 5 );
    P0 = 0xaf;          // 1010 1111
    
    HC138_Init( 0 );    // 关闭通道选择
    P0 = 0xff;          // 初始化P0的值
}


// 定时器0初始化函数
void Timer0_Init(void)
{
    TMOD = 0x01;    // 使用定时器0工作模式1
    ET0 = 1;
    TR0 = 1;
    EA = 1;
    
    // 计数初值
    TH0 = ( 65535 - 50000 ) / 256;
    TL0 = ( 65535 - 50000 ) % 256;
    
}


// 定时器0服务函数
void Timer0() interrupt 1
{
    // 由于是不能自动重装载的,所以要再次赋初值
    TH0 = ( 65535 - 50000 ) / 256;
    TL0 = ( 65535 - 50000 ) % 256;
    
    HC138_Init( 4 );
    count++;
    if( count % 20 == 0 )    // 一秒翻转一次电平
    {
        L1 = ~L1;
    }
    if( count == 100 )       // 五秒翻转一次电平
    {
        L8 = ~L8;
        count = 0;
    }
}




int main(void)
{
    System_Init();    // 系统初始化
    Timer0_Init();    // 定时器0初始化
    while(1);
}

五、运行图片

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

汽小迪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值