基于AT89C52做秒表0~99秒

1、应网友要求做了个秒表。

2、定期器采用10毫秒,数码管后2位显示的是毫秒,故100毫秒进1秒,100毫秒*定时器10毫秒故就是1秒。

3、使用3个独立按键,按键2表示启动秒表,按键3表示暂停秒表,按键4表示清除秒表且暂停秒表。

4、已在我的清翔51开发板上实现,表现良好(只是按键的时候数码管会灭,这个我就不解了,需要用定时器做按键判断。)

main.c

#include "Time.h"
#include "key.h"
#include <reg52.h>
#include "dt.h"

void main(void)
{
	unsigned char dt_state=1;//数码管标志位
	Timer0_16bit(10);//配置初始化定时器0为10毫秒
	convert_data(9999,4);//初始化数码管
	while(1)
	{
		if(dt_state)//主程序驱动数码管标志位
		{
			dt_display(4);//使用主程序驱动数码管
		}
		switch(key2345())
		{
			case 2:TR0=1;dt_state=0;break;//启动秒表,且使用定时器驱动数码管
			case 3:TR0=0;dt_state=1;break;//暂停秒表,且使用主程序驱动数码管
			case 4:TR0=0;TIME=0;convert_data(TIME,4);dt_state=1;break;//清除时间,且暂停计时器,且使用主程序驱动数码管
			break;
		}
	}
}

delay.h

//这是一个延迟函数为毫秒级//
#ifndef __DELAY_H__
#define __DELAY_H__
void delay_ms(unsigned char ms);//最大输入255,ms=1,最小1ms时间
#endif // !__DELAY_H__

 delay.c

//软件延迟ms级别
void delay_ms(unsigned char ms)	//设置毫秒级别延迟函数,z最大输入65535
{
	unsigned char x;
	for (; ms > 0; ms--)
		for (x = 114; x > 0; x--);
}

key.h

#ifndef __KEY_H__
#define __KEY_H__

#include <reg52.h>
#include "delay.h"

//独立按键 
sbit key_S2 = P3^0;
sbit key_S3 = P3^1;
sbit key_S4 = P3^2;
sbit key_S5 = P3^3;

#define key_all P3

//按键占用P3口
unsigned char key2345(void); //函数返回值为2、3、4、5分别对应按键2、按键3、按键4、按键5,本函数只循环一次

#endif // !__KEY_H__

key.c

//独立按键 S2		S3	 S4		S5
//分别对应 P30	P31	 P32	P33
#include"key.h"

//独立按键使用switch语句
unsigned char key2345(void) //函数返回值为2、3、4、5分别对应按键2、按键3、按键4、按键5,本函数只循环一次
{
	key_all |= 0x0f;
	if ((key_all&0x0f) != 0x0f)	//&运算符没有!=高,故需要加()括号
	{
		delay_ms(10);
		if ((key_all & 0x0f) != 0x0f)
		{
			switch (key_all & 0x0f)
			{
			case 0x0e:while ((key_all & 0x0f) != 0x0f);return 2;	//while在这里进行松手检测
			case 0x0d:while ((key_all & 0x0f) != 0x0f);return 3;	//while在这里进行松手检测
			case 0x0b:while ((key_all & 0x0f) != 0x0f);return 4;	//while在这里进行松手检测
			case 0x07:while ((key_all & 0x0f) != 0x0f);return 5;	//while在这里进行松手检测
			}
		}
	}
	return 0;//没有按键按下时返回0
}

Time.h

#ifndef __TIME_H__
#define __TIME_H__

#include <REG52.h>

extern unsigned int TIME;
//定时器0初始化,并设定ms毫秒且工作方式1,16位模式
void Timer0_16bit(unsigned char time0_16_bit_ms);

#endif // !__TIME_H__

Time.c

#include "Time.h"
#include "dt.h"

static unsigned char H0 = 0, L0 = 0;
unsigned int TIME=0;
//定时器0初始化,设定ms毫秒且工作方式1,16位模式
void Timer0_16bit(unsigned char time0_16_bit_ms)
{
    TMOD |= 0x01;
    TH0 =(65536 - (unsigned int)(time0_16_bit_ms * 921.6)) / 256;//需将计算的小数转换整形
    TL0 =(65536 - (unsigned int)(time0_16_bit_ms * 921.6)) % 256;//需将计算的小数转换整形
    H0 = TH0;
    L0 = TL0;
    EA = 1;//开启总中断
    ET0 = 1;//允许定时器0溢出进入中断
    TR0 = 0;//先关闭定时器
}
void Timer0Interrupt(void) interrupt 1
{
   TH0 = H0;
   TL0 = L0;
	 dt_display(4);//每隔10毫秒刷新一下4个数码管
	 convert_data(TIME,4);//每隔10毫秒转换一下时间
	 if(TIME++==9999)//数码管最大显示99.99秒
	 {
	  	TIME=0;
	 }
}

dt.h

#ifndef __DT_H__
#define	__DT_H__

#include <reg52.h>
#include "delay.h"

sbit wei = P2^7;		//锁存器位选
sbit duan = P2^6;		//锁存器段选
#define dt_dt  P0

//0<=dt_data<=9999,y=4表示4个数码管亮
void convert_data(unsigned int dt_data,unsigned char y);

//y个数码管显示
void dt_display(unsigned char y);

#endif

dt.c

//数码管dt  使用共阴极数码管即位选是阴极时数码管才选中
//使用P0-8个GPIO口
//P2.7位选脚(控制哪个数码管亮)、P2.6段选脚(送数码管值) 控制2个74锁存器

#include "dt.h"

static unsigned char datax[8];//定义局部变量//用来存放小数及正整数,然后发给数码管进行显示低位到高位存放
static code unsigned char dt_duan[26] =   //数码管段选真值表   dt_duan[i] + 0x80  数码管显示数据并且此数据的右下角有小数点
{
	0x3F,  //"0"
	0x06,  //"1"
	0x5B,  //"2"
	0x4F,  //"3"
	0x66,  //"4"
	0x6D,  //"5"
	0x7D,  //"6"
	0x07,  //"7"
	0x7F,  //"8"
	0x6F,  //"9"
	0x80,  //"."
	0x40,  //"-"
	0x77,  //"A"
	0x7C,  //"B"
	0x39,  //"C"
	0x5E,  //"D"
	0x79,  //"E"
	0x71,  //"F"
	0x76,  //"H"
	0x38,  //"L"
	0x37,  //"n"
	0x3E,  //"u"
	0x73,  //"P"
	0x5C,  //"o"
	0x00,  //熄灭
	0x00  //自定义
};

static code unsigned char dt_wei[9]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe,0xff};//1位-8位(0x7f表示最右边哪个数码管)0xff数码管就不亮了

static void clear_reset_dt(void)//清除数码管,关闭数码管,初始化数码管
{
	dt_dt= dt_wei[8];//清除位码,关闭所有数码管
	wei=1;
	wei=0;
	dt_dt= dt_duan[25];//清除段码,关闭所有数码管显示
	duan=1;
	duan=0;
	dt_dt=0xff;//恢复单片机IO口默认高电平状态
}

void dt_display(unsigned char y)//y表示的是要几个数码管显示取值0~8
{
	unsigned char a;
	for (a = 0; a < y; a++)//a亮——a值——a值灭;a+1亮——a+1值——a+1值灭;开始循环(亮,真值,假值)
	{
		dt_dt = dt_wei[a];//灯亮
		wei = 1;            //打开位选
		wei = 0;            //锁存位选
			
		dt_dt = datax[a];//数字
		duan = 1;           //打开段选
		duan = 0;           //锁存段选
			
		delay_ms(1);//亮的时间,防闪烁
		
		dt_dt = dt_duan[25];//数字熄灭,假值
		duan = 1;           //打开段选
		duan = 0;           //锁存段选
	}
	clear_reset_dt();//清除数码管显示,初始化数码管
}

//将要显示的正整数临时存储在数组里面,然后循环显示数组里的元素即可
//x传递的数据10进制(x不是8位则高位不会亮)
void convert_data(unsigned int dt_data,unsigned char y)//y表示的是要几个数码管显示取值0~8
{
	unsigned char i;		//数组标号也是段选真值
	unsigned char a;		//流水号,用来表示数码管1~8个
	for (a = 0;a < y;a++)		//将x没位的值存放到数组里面
	{
		i = dt_data % 10;//获取最后一位数字
		dt_data = dt_data / 10;//每次舍去最低位
		if(a==2)
			datax[a] = dt_duan[i]+0x80;//0x80是小数点
		else
		  datax[a] = dt_duan[i];
	}
	clear_reset_dt();//清除数码管显示
}

  • 4
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

金丝草

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

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

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

打赏作者

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

抵扣说明:

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

余额充值