定时器 + 动态数码管实现秒表功能

 

// 定时器 + 动态数码管显示秒表功能

#include <reg52.h>

#define u16 unsigned int
#define u8 unsigned char

// 74LS138译码器的管脚(用于控制动态数码管的显示,本例只使用右边的四个数码管)
sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;

// 数码管显示0-9 
u8 code smgduan[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};

// 将4位数码管的数字保存到一个数组中
u8 disp[4];    
u16 num=0;	// 数码管要显示的数字

// 延迟函数
void delay(u16 j)
{
    while(j--);
}

// 数据处理,提取各位数字
void datapros()
{
    disp[0]=smgduan[num/1000];			// 千位
    disp[1]=smgduan[num%1000/100];		// 百位
    disp[2]=smgduan[num%1000%100/10];	// 十位
    disp[3]=smgduan[num%1000%100%10];	// 个位  
}

// 数码管显示函数
void DigDisplay()
{
    u8 t;
    for(t=0;t<4;t++)
    {
        switch(t)    // 位选,选择点亮的数码管,
        {
            case(0):
                LSA=0;LSB=0;LSC=0; break;	// 显示第0位
            case(1):
                LSA=1;LSB=0;LSC=0; break;	// 显示第1位
            case(2):
                LSA=0;LSB=1;LSC=0; break;	// 显示第2位
            case(3):
                LSA=1;LSB=1;LSC=0; break;	// 显示第3位   
        }
        P0=disp[3-t];	// 发送数据
        delay(100); 	// 间隔一段时间扫描 
        P0=0x00;		// 消隐
    }      
}

// 定时器T0初始化函数
void Timer0Init()
{
	/*
	(1)工作方式:TMOD是8位的,高四位用于T1(GATE、C/T非、M1、M0),
	低四位用于T0(GATE、C/T非、M1、M0),它们的使用请参考单片机资料。
	这里设置GATE=0,C/T非=0,M1M0=01(工作方式1,16位定时器),所以低四位是:0001,
	高四位是:0000,所以是0x01
	*/
	TMOD=0x01;
	
	/*
	(2)计算初值:假设定时器定时1ms,即1000us,则需要1001个计数才会溢出,发生中断请求,
	因为定时器0是由TH0和TL0两个寄存器组成,每个寄存器是8位,总共是16位,总数是2^16=65536,
	从0开始计数,所以是0-65535,所以,初值=65535-1000+1=64536,转成十六进制数是:FC18,
	故高四位TH0=0xFC,低四位TL0=0x18
	*/
	TH0=0xFC;
	TL0=0x18;
	
	/*
	(3)中断允许位:如果定时器在数据溢出后需要向单片机CPU发出中断请求,
	还需要开启CPU中断总允许位,即EA=1,同时,需要开启定时器T0的中断允许位ET0,即ET0=1
	*/
	EA=1;
	ET0=1;
	
	/*
	(4)启动定时器工作:由电路图可知,需要将TR0置1,才能让定时器工作
	*/
	TR0=1;
}

// 主函数
void main()
{
	// 定时器初始化
	Timer0Init();
	while(1)
	{
		DigDisplay();	// 数码管显示函数
	}
}

// 定时器T0的中断函数
void Timer0() interrupt 1
{
	// 计数变量:用static关键字修饰,表示全局变量
	static u16 i;
	
	/*
	因为定时器选择工作方式1(M1M0=01,表示工作方式1,16位的定时器,没有自动重装功能),
	工作方式2(M1M0=10)由自动重装功能,是8位的定时器,总共有4中工作方式,查资料可知,
	需要把初始值重新写入TH0和TL0中
	*/
	TH0=0xFC;
	TL0=0x18;
	
	/*
	每次中断i都加1表示计数,每次中断时长是1ms,如果想让LED灯每隔1s切换一次状态,
	就需要让i=1000
	*/
	i++;
	if(i==1000)			// 计时达到1s
	{
		i=0;			// 让i复位
		num ++;			// 每隔1秒就自增
		datapros();  	// 数据处理函数
	}
}

 

posted @ 2018-03-19 22:33  半生戎马,共话桑麻、  阅读(1571)  评论(0)    收藏  举报
levels of contents