学蓝桥Chapter8:计时/定数器及相关的寄存器

定时器是什么

定时器:对时钟信号或外部输入信号进行计数,当计数完成,定时器向CPU发出中断处理请求,从而实现定时功能。
从本质来讲定时器就是计数器,可以理解为特殊的计数器

51单片机定时/计数器

51单片机有两个定时/计数器T0和T1,均为16位加法计数器,由低八位TLx和高八位THx两个寄存器组成,最大计数值为65535个计数脉冲

  • 计算公式
    • 定时器时钟频率=内部时钟振荡器振荡频率÷分频数
    • 定时器1个脉冲的周期=1/定时器周期
    • 定时脉冲数=定时数÷定时器1个脉冲的周期

计数脉冲来源

  1. 系统时钟振荡器(可以理解为MCU内部时钟振荡器,其输出信号就是内部时钟信号)输出信号的12分频:
    ---- : 如果你的系统时钟为12mhz,那么你的定时器时钟则为12mhz/12=1mhz,对应的定时器1个脉冲的周期就是1/1mhz=1μs。
  2. T0或T1引脚输入的外部脉冲信号

51单片机定时器T0的大体运作图

在这里插入图片描述

相关寄存器

IE寄存器
在这里插入图片描述

IP寄存器
在这里插入图片描述

TMOD寄存器
不能进行位寻址,只能进行字节操作,也就是只能直接将数值写给TMOD从而控制其运作,也就是只能进行类似TMOD=0xFF这样的操作
在这里插入图片描述
自动重装模式:当定时/计数值超过最大值时,会回到0值,相当于重置定时/计数值。因此当设定自动重装功能的时候,需要在程序中设定重装后回具体初值的功能,不然定时器运行效果可能出错。
非自动重装模式:如果处于非自动重装模式,则需要对THx和TLx重新赋值

TCON寄存器
在这里插入图片描述

定时/计数器程序设计思路

打开总中断——EA=1
配置工作模式——TMOD寄存器赋值
计算定时/计数初值——THx和TLx寄存器赋值
定时/计数器使能中断——ET0/1=1
启动定时器——TR0/1=1

例题

51单片机中,若我要定时50ms,TH0(高八位)和TL0(低八位)该怎么设置:
TH0=(65535-50000)/256
TL0=(65535-50000)%256(低八位取余数)
在这里插入图片描述

程序实现

利用定时/计数器溢出中断0实现P0^0口的LED灯1秒闪烁1次.

#include <reg52.h>

sbit L1=P0^0;
sbit L8=P0^7;

void hc(){ //选择锁存器
	P2=(P2&0x1f)|0x80;
}

void initTimer0(){ //定时器T0初始化函数
	EA=1;
	ET0=1;
	T0=0X01;//选择低四位定义定时/计数器0,并且选择TR0/TR1(具体选择要用TR0=1或者TR1=1)作为启动位
	TR0=1;//最终选择TR0作为启动位,即选择定时器T0;若选择TR1作为具体启动位,则TR1=1,即选择定时器T1,那么将会执行的是interrupt 3的函数内容
	TH0=(65535-50000)/256;
	TL0=(65535-50000)%256;
}

unsigned int count=0; //倍数,如每500ms执行一次,则需要50ms*10,这里的10就是count充当的角色
void servicetime0() interrupt 1{ //选择定时器/计数器 T0 溢出中断;定时器中断函数:在中断过程中你需要执行的动作
	//非自动重装模式,需要对THx和TLx重新赋值
	TH0=(65535-50000)/256; //高8位定时器存入50ms的部分值
	TL0=(65535-50000)%256; //低8位定时器存入50ms的部分值
	//实际上因为51单片机是8位的单片机 它的寄存器一般都是8位,而它的定时器是16位,所以只能分为两个寄存器来存储,因而要同时定义高八位和低八位从而组成1个16位值。如果遇到了16位的单片机,则无需定义高8位和低8位直接就能存入16位的值。
	count++; //倍数自增
	if(count==10){  //当倍数达到10,即50ms的10倍时(此时为500ms)执行动作
		L1 =~ L1; //P0^0口LED灯动作
		count = 0; //重置倍数,跳出条件动作。
	}
}

void main(){
	hc();
	initTimer0(); //中断初始化函数执行后会自动执行初始化内指定的中断函数,我选中执行的是定时器/计数器溢出中断0(对应中断号为1),所以会执行interrupt 1的函数内容
	//经测试,当后面while()存在时,initTimer0在循环体内或体外都可以实现灯泡的500ms动作一次的功能,即1秒内动作两次(即闪烁1次)。
	while(1){ //循环执行中断函数,实现灯泡的500ms动作一次的功能,即1秒内动作两次(即闪烁1次)
	//initTimer0(); //中断初始化函数执行后会自动执行初始化内指定的中断函数,我选中执行的是定时器/计数器溢出中断0(对应中断号为1),所以会执行interrupt 1的函数内容	
	}
	
	
}

综合训练

使用板子的BTN独立按键模式(J5短接23脚),当按下S4暂停/启动秒表计时,当按下S5则清零。并且在8位共阳数码管上分别以两位的形式显示分时,毫秒,毫秒以0.05ms作为单位,当显示到20自动令秒进1

#include <reg52.h>

sbit s4=P3^3;
sbit s5=P3^2;
unsigned char code dx[]={0xc0,0xf9,0xa4,0xb0,0x99,0x12,0x82,0xf8,0x80,0x90,0xbf}; //共阳极数码管段码
unsigned char min=0;	//分钟变量定义
unsigned char sec=0;	//秒变量定义
unsigned char msec=0;  //毫秒变量定义

void hc573(unsigned char num){  //hc573锁存器初始化:选择指定的hc573锁存器
	switch(num)
	{
		case 4:
			P2=(P2&0x1f)|0x80;break;
		case 5:
			P2=(P2&0x1f)|0xa0;break;		
		case 6:
			P2=(P2&0x1f)|0xc0;break;
		case 7:
			P2=(P2&0x1f)|0xe0;break;		
	}
}

void displaysw(unsigned int value,unsigned int pos){  //数码管显示函数
	hc573(6);
	P0=0x01 << pos; //P0初始值设为0x01,根据pos值决定点亮第几位。若pos为3,则P0值左移3位,此时P0=00001000=0x08,因为0x08对应4位数码管从左往右的第4位,所以会亮从左往右的第4位数码管
	hc573(7);
	P0=value; //这里的value与dx[]形成了链接的关系
}

void delay(unsigned char dd){ //延时函数
	while(dd){
	dd--;
	}
}

void displaytime(){ //该函数只负责显示时间的方法。核心计算函数是initT0()和workT0()组合在一起的中断函数
	displaysw(dx[msec%10],7);//数码管显示毫秒的从右数第1位
	delay(50);
	displaysw(dx[msec/10],6);//数码管显示毫秒的从右数第2位
	delay(50);
	displaysw(dx[10],5); //数码管显示”-“
	
	displaysw(dx[sec%10],4);//数码管显示秒的从右数第1位
	delay(50);
	displaysw(dx[sec/10],3);//数码管显示秒的从右数第2位
	delay(50);
	displaysw(dx[10],2); //数码管显示”-“
	
	displaysw(dx[min%10],1);//数码管显示分钟的从右数第1位
	delay(50);
	displaysw(dx[min/10],0);//数码管显示分钟的从右数第2位
	delay(50);
}

void scankey(){  //去抖动操作,防止误触操作
	if(s4==0){ //S4被按下,秒表启动、暂停
		delay(10);
		if(s4==0){
		TR0 =~ TR0;
		}
		
	}
		if(s5==0){ //S5按下秒表清零
		delay(10);
		if(s5==0){
		min=0;
		sec=0;
		msec=0;
		}
		
	}
}

void initT0(){  //定时器0初始化函数
	EA=1;
	ET0=1;
	TMOD=0X01;
	TR0=1; //选用T0定时器
	TH0=(65535-50000)/256;
	TL0=(65535-50000)%256;
}
void workT0() interrupt 1{ //中断号1对应定时器T0,这是T0的动作函数
	TH0=(65535-50000)/256;
	TL0=(65535-50000)%256;
	
	msec++;  
	if(msec==20){
		sec++;
		msec=0;
		if(sec==60){
			min++;
			sec=0;
		}
		if(min==99){
			min=0;
		}
	}
}

void main(){
	initT0(); //启用中断函数
	while(1){
		displaytime();
		scankey();
	}
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值