proteus+keil5仿真学习笔记(第三章 4位数码管计数器)

本文详细介绍了4位数码管计数器的编程实现,涉及多位数码管显示、定时器原理、定时1秒功能和四位数码管计数器的设计。通过定时器配合外部中断,实现分钟和秒的动态更新。
摘要由CSDN通过智能技术生成

第三章 4位数码管计数器

4位数码管计数器与1位数码管计数器相比,增加了片选电路,以确定选择哪个数码管进行工作。单片机定时器的应用也与中断处理相似,需要设置一些规定的寄存器,以此来规定单片机的工作状态。

一、多位数码管显示程序

定义一个数组Dat[ ]={0,0,0,0}存放4位数,初值都为0。用变量S作为计数,tmp作为片选值。

数字分离:百位数分离用Dat[0] = S/100,例如S=235则S/100=2,Dat[]是整数,小数部分自动删除。十位数分离用Dat[1]=S%100/10公式解决,S%100取除100的余数,再把这个余数除10,就得到十位数了。例如,还是以上数字S=235,S%100/10=3。最后是个位数的分离,用Dat[2]=S%10,取S除以10的余数。

这里Dat[0]存放百位数,Dat[1]存放十位数,Dat[2]存放个位数。在输出时要按从高到低的顺序输出,不能搞错,否则数字就反了。在输出时,先选定片选值,即决定在哪个数码管输出,送到P2口,因为我们将片选线接在P2口。第1个片选值是1,根据数码管的标识在最左边位输出,然后通过P0口输出码段值,这时,就会在第1位显示数据了。接着,把片选值向左移动一位,为下一位输出做准备,停留片刻后进行下一位输出。这样,共循环3次,将3位数都输出显示在数码管上了。因为,我们的眼睛有视觉残留,所以感觉3位数字一起显示出来。但由于在输出完毕后还要停留较长时间才会进入下一个数的显示,输出会有闪烁的感觉。

#include <reg51.h>//单片机头文件
unsigned char code Tab[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};//共阳数码管码段表
unsigned char Dat[]={0,0,0,0};//存放4位数据数组
unsigned char tmp,i,j;//定义临时变量、循环变量
unsigned int S=0;//定义计数变量
void Delay(int n)//延时子程序
{
	int i;
	for(i=0;i<n;i++);
}
void main()//主程序
{
	while(1)//无限循环
	{
		S++;//计数值加1
		if(S>500)//如果计数值大于500则清零
			S=0;
		Dat[0]=S/100;//取计数值的百位数
		Dat[1]=S%100/10;//取计数值的十位数
		Dat[2]=S%10;//取计数值的个位数
		
		tmp=0x01;//片选初值
		for (i=0;i<3;i++)//循环3次
		{
			P2=tmp;//将片选值送P2口
			 P0=Tab[Dat[i]];//将某一位码段值送P0口
			tmp=tmp<<1;//片选值移至下一位
			Delay(500);//调用延时子程序
		}
		for(i=0;i<150;i++)//延时一段时间
		for(j=0;j<100;j++)
		Delay(60000);//调用延时子程序
	}
}

二、定时器原理

单片机定时/计数器的工作原理及工作方式,可以参考https://blog.csdn.net/kafmws/article/details/88046805这篇博文,在此不赘述。

计算定时器的初值,计算公式和一般方法如下:

1)T(初值)=2^N-定时时间/机器周期时间

2)N与工作方式有关

方式0           N=13

方式1           N=16

方式2、3     N=8

3)1机器周期时间=12/fosc=12/12MHz=1μs

例:晶振12MHz,求方式1,T0定时0.2ms初值

2^16-200/1=65536-200=FF38H则,高位TH0=FFH,低位TL0=38H

再举个例子,用T0,方式1,计时0.05s,设计一个发光二极管闪烁(0.05s开关一次)程序。计算初值。(-50000的补码为2^16-50000)

高位TH0=-50000/256

低位TL0=-50000%256

#include <reg51.h>//单片机头文件
sbit led=P0^0;//定义发光二极管引脚
void main()//主程序
{
EA=1;//允许所有中断
ET0=1;//允许T0中断
TMOD=0x01;//T0方式1计时0.05S
TH0=-50000/256;//定时器T0的高八位
TL0=-50000%256;//定时器T0的低八位
TR0=1;//启动T0定时器
for(;;);//无限循环
}
void intserv1 (void) interrupt 1 using 1//定时器0中断服务子程序,中断号1
{
TH0=-50000/256;//重新定义初值
TL0=-50000%256;
LED=!LED;//电平取反
}

编译程序,在单片机上加载程序,可看到发光二极管0.05s的闪烁。由于间隔时间很短,发光二极管闪烁的很快。如何能使得间隔时间长一点呢?这就需要把定时器初值设的大一点,但是,最大也不能超过2^16,即65536,也就65536μs=0.065536s。如果要设置成1s闪烁一次该怎么办呢?显然,定时器初值设置成1s是不可能的,只有另外设置变量来延长定时时间。

我们修改一下中断处理程序如下:

void intserv1 (void) interrupt 1 using 1
{
TH0=-50000/256;//重新定义初值
TLO=-500005256;
t++;//变量t加1
if(t>=20)//如果变量t=20;
{
t=0;//变量t清零
LED=!LED;//电平取反
}
}

在程序头部加上一个全局变量t,定义为unsigned char t;,作为中断子程序的中间变量。每次定时器时间到,处理中断时,给变量t加1,若t=20,就是0.05s×20=1s。即每次0.05s时间到中断时并不执行发光二极管电平取反,直到20次时,就是1s时,才执行一次。这样就实现了定时1s的功能。

三、程序设计与仿真

在前面我们实现了多位数码管显示程序,并学习了1s定时器功能的实现,两者结合,设计一个四位数码管计数器。前2位表示分钟,后2位表示秒。从0分0秒开始计时,逢60进1,每秒变化一次。

proteus 电路

程序

#include <reg51.h>//单片机头文件
unsigned char code Tab[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};//共阳数码管码段表
unsigned char Dat[]={0,0,0,0};//存放4位数字数组

int i ,t;//定义变量,作为循环,定时计数
unsigned char tmp;//定义片选变量
unsigned char second=0,min=0;//定义秒、分变量
void Delay()//延时子程序,作为数码管显示延迟
{
	unsigned char i;
	for(i=0;i<250;i++);
}

void main()
{
	IT0=1;EX0=1;//开外部中断0和外部中断0允许
	IT1=1;EX1=1;//开外部中断1和外部中断1允许
	EA=1;//允许所有中断
	ET0=1;//允许T0中断
	TMOD=0x01;//T0方式1计时0.05S
	TH0=-50000/256;//定时器T0的高八位
	TL0=-50000%256;//定时器T0的低八位
	TR0=1;//启动定时器0
	while(1)//无限循环
	{
		tmp=0x01;//片选初值
		for(i=0;i<4;i++)//循环4次
		{
			P2=tmp;//片选初值
			P0=Tab[Dat[i]];//输出某一位数字的码段值
			tmp=tmp<<1;//片选值左移一位
			Delay();//调用延时
		}
	}
}

void intserv1 (void) interrupt 1 using 1//定时器0中断服务子程序
{
	TH0=-50000/256;//定时器高八位赋值
	TL0=-50000%256;//定时器低八位赋值
	t++;//变量t加1
	if(t==20)//20次到,即1秒到
	{
		t=0;//变量t清零
		second++;//秒加1
		if(second>=60)//60秒到
		{
			second=0;//秒变量清零
			min++;//分加1
			if(min>=60)//60分到
				min=0;//分变量清零
		}
		Dat[0]=min/10;//计算分高位
		Dat[1]=min%10;//计算分低位
		Dat[2]=second/10;//计算秒高位
		Dat[3]=second%10;//计算秒低位
	}
}

void intersvr0 (void) interrupt 0 using 1//外部中断0子程序
{
	min++;//分加1
	if(min>=60)//如果分到60
		min=0;//分清零
}

void intersvr1 (void) interrupt 2 using 1//外部中断1子程序
{
	second++;//秒加1
	if(second>=60)//如果秒到60
		second=0;//秒清零
}

总结

定时1S的功能将会在很多程序功能中被使用,需要大家好好学习消化这一知识点。

  • 61
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值