基于51单片机(普中开发板)的四位数码管秒表设计

说明

今天学校布置的课后作业,利用51单片机做一个秒表,本来是做了个8位数码管的秒表,但后来想了下秒表计时一般都不会用到以小时为单位,就把小时的部分以及毫秒的部分去掉了,就留下了分钟跟秒。

每个开发板的电路连接不一定是一样的,我所使用这块开发板是普中科技的,连接数码管的位选是接了一个138译码器的,如果是购买的普中科技的开发板可以直接复制程序就能使用,如果开发板的数码管的位选是接了锁存器的,那么就要相应地更改。

如果不理解138芯片使用方法的,我也要把138芯片的真值表附在下面了,顺便说下它的用法:
74HC138译码器可接受3位二进制加权地址输入(A0, A1和A2),并当使能时,提供8个互斥的低有效输出(Y0至Y7)。74HC138特有3个使能输入端:两个低有效(E1和E2)和一个高有效(E3)。除非E1和E2置低且E3置高,否则74HC138将保持所有输出为高。74HC138正常工作的话,一次只能输出一个低电平,其他全为高电平

要求:

  1. 按下按钮S1,秒表开始计时;
  2. 按下按钮S2,秒表暂停计时(停留在计时的数);
  3. 按下按钮S3,秒表清零;
  4. 计时精确到0.5s

电路图

**单片机****8个数码管****4个独立按键****138芯片**138芯片真值表

程序

程序已经过测试,可以正常使用,注释非常多,比较容易理解。

/****************************************************************************************
								秒表实验
实验现象:按下按钮S1开始计时,最大为59.59。按下按钮S2定时器暂停,按下按钮S3清零

*****************************************************************************************/
#include <reg52.h>
#define uint unsigned int						  //对数据类型进行声明定义
#define uchar unsigned char

sbit LS138_A = P2^2;							  //138芯片A2引脚
sbit LS138_B = P2^3;							  //138芯片A1引脚
sbit LS138_C = P2^4;							  //138芯片A0引脚

uchar DT_s = 0;								  //秒计时
uchar DT_min = 0;									  //分计时

uchar code duan[] = {0x3F,0x06,0x5B,0x4F,		  //共阴数码管无小数点 显示0~9
					 0x66,0x6D,0x7D,0x07,
					 0x7F,0x6F	
					};

uchar code duanpoint[] = {0xbf,0x86,0xdb,0xcf,	   //共阴数码管有小数点 显示0~9
						  0xe6,0xed,0xfd,0x87,
						  0xff,0xef,0xf7,0xfc,
						  0xb9,0xde,0xf9,0xf1
						 };

/************************************************
函数名				:delay1ms
函数功能            :t=1,大约延时1ms
************************************************/
void delay1ms(uint t)
{
	uint i,j;
	for(i=0;i<t;i++)
	{
		for(j=0;j<120;j++);	
	}
}

/************************************************
函数名				:Timer0Init
函数功能			:定时/计数器0中断初始化
*************************************************/
void Timer0Init()
{
	TMOD = 0x01; 		//选择T0定时/计数器,工作在方式1,16位计数器		
	TH0 = 0xFC;			//计数初始值,计数从64536开始,计1000个数,完成一次计数,时间为1ms
	TL0 = 0x18;		
	ET0 = 1;			//定时/计数器0中断允许位
	EA = 1;				//总中断
}

/************************************************
函数名				:S3
函数功能			:按下按钮S3时,秒表归零
*************************************************/
void S3()
{
	DT_s = 0;			//秒归零
	DT_min = 0;			//分归零
	TR0 = 0;			//运行控制位清0,关闭定时器
}

/**********************************************************
函数名				:ScanKey
函数功能			:按键扫描函数,循环扫描哪个键被按下
**********************************************************/
void ScanKey()
{
	uchar Key;		   //临时变量
	Key = P3&0x07;	   //只需要三个按键,分别接的P3^1,P3^2,P3^3,故把P3高五位被屏蔽
	if(Key!=0x07)	   //判断哪个键被按下
	{
		delay1ms(10);	 //消抖10ms
		Key = P3&0x07;	 //再次赋值,避免此时按键状态改变
		if(Key!=0x07)	 //确认按键被按下
		{
			switch(Key)
			{
				case 0x05:				  //S1(P3^2)被按下
							TR0 = 1;	  //定时器0运行控制位为1,启动定时器0
							break;
				case 0x06:				  //S2(P3^1)被按下
							TR0 = 0;	  //定时器0运行控制位为0,关闭定时器0
							break;
				case 0x03:				  //S3(P3^3)被按下
							S3();
							break;
			}
		}
		while(Key!=0x07)		//松手检测
		{
			Key = P3&0x07;
		}
	}
}

/*******************************************************************
函数名				:DigDisplay
函数功能			:数码管动态扫描函数,循环扫描8个数码管显示
********************************************************************/
void DigDisplay(uchar s,uchar min)
{
	LS138_A = 0;			  //秒个位位选
	LS138_B = 0;
	LS138_C = 0;
	P0 = duan[s%10];		  //发送段码,显示秒个位
	delay1ms(5);			  //间隔一段时间扫描
	LS138_A = 1;			  //秒十位位选
	LS138_B = 0;
	LS138_C = 0;
	P0 = duan[s/10];		  //发送段码显示秒十位
	delay1ms(5);			  //间隔一段时间扫描

	LS138_A = 0;			  //分的个位位选
	LS138_B = 1;
	LS138_C = 0;
	P0 = duanpoint[min%10];		  //发送段码,显示分的个位
	delay1ms(5);			  //间隔一段时间扫描
	LS138_A = 1;			  //分的十位位选
	LS138_B = 1;			  //间隔一段时间扫描
	LS138_C = 0;
	P0 = duan[min/10];		  //发送段码,显示分的十位
	delay1ms(5);			  //间隔一段时间扫描
	P0 = 0x00;				  //消隐
}

/**********************************************************
函数名				:主函数
函数功能			:无
**********************************************************/
void main(void)
{
	P0 = 0x00;		  //读端口前写1
	P3 = 0xFF;		  //读端口前写1
	Timer0Init();	  //定时器中断初始化函数
	while(1)
	{
		DigDisplay(DT_s,DT_min);	   //数码管显示函数
		ScanKey();							   //按键扫描函数
	}
}

/**********************************************************
函数名				:Timer0
函数功能			:定时器计数
**********************************************************/
void Timer0() interrupt 1
{
	static uint count_s;	
	static uint count_min;		
	TH0 = 0xFC;				//计数值初始化,从64536开始计数,计满时为65536,溢出时即为 1ms
	TL0 = 0x18;
	count_s++;				 //秒计数
	count_min++;				 //分计数
	if(count_s==1000)			 //计数到1s时,秒计数器开始工作
	{
		count_s = 0;		 //秒计数清零
		DT_s++;			 //显示秒计数值自增
		if(DT_s>59)		 //秒数最大为59
		{
			DT_s = 0;
		}
	}
	if(count_min==60000)		  //计数到60000ms时,秒计数器开始工作
	{
		count_min = 0;		  //分计数清零
		DT_min++;				  //显示分计数值自增
		if(DT_min>59)			  //分数最大为59
		{
			DT_min = 0;
		}
	}
}
要实现51单片机数码管显示999秒表的功能,需要以下步骤: 1. 确定使用的数码管型号,并查阅其接口电路图,了解其引脚定义和使用方法。 2. 配置单片机的IO口,将数码管的控制引脚连接至单片机的IO口,设置IO口的输出模式。 3. 编写程序,实现秒表计时功能。可以使用定时器中断来计时,每隔一定时间触发中断,在中断服务函数中更新计时器的值。 4. 将计时器的值转换为数码管需要显示的格式,例如将计时器的秒数分解为百位、十位和个位,并将其存储到数组中。 5. 在主程序中循环调用数码管显示函数,将数组中存储的数码依次输出到数码管。 以下是示例代码: ```c #include <reg51.h> // 51单片机头文件 #define LED P1 // 将数码管控制引脚连接至P1口 unsigned char code SegCode[10] = { // 数码管段码表 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f }; unsigned int secCount = 0; // 秒表计时器 void timer0_isr() interrupt 1 // 定时器0中断服务函数 { TH0 = (65536 - 1000) / 256; // 重新设置定时器初值 TL0 = (65536 - 1000) % 256; secCount++; // 计时器加1 } void display(unsigned int num) // 数码管显示函数 { unsigned char i, j; unsigned int output[3]; output[0] = num / 100; // 分解百位 output[1] = (num / 10) % 10; // 分解十位 output[2] = num % 10; // 分解个位 for (i = 0; i < 3; i++) { LED = SegCode[output[i]]; // 输出段码 for (j = 0; j < 100; j++); // 稍作延时 LED = 0x00; // 关闭数码管 } } void main() { TMOD = 0x01; // 设置定时器0为模式1 TH0 = (65536 - 1000) / 256; // 设置定时器初值 TL0 = (65536 - 1000) % 256; ET0 = 1; // 使能定时器0中断 EA = 1; // 使能总中断 TR0 = 1; // 启动定时器0 while (1) { display(secCount); // 显示计时器的值 if (secCount >= 999) { secCount = 0; // 计时器清零 } } } ``` 上述代码中,使用了定时器0中断来实现计时,每隔1秒触发一次中断,在中断服务函数中将计时器加1。在主程序中循环调用数码管显示函数,将计时器的值输出到数码管上。
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值