单片机实现秒表倒数计数器

单片机实现秒表计数器

最近博主在学习单片机的课程,这快到期末考试了,老师让做个简单的课设,我看了看老师给的课题,感觉这个比较容易实现,今天下午花了两个小时左右的时间,把仿真程序电路图画好了,现在分享大家,希望大家批评改正。
实验器材:**单片机、按钮、电阻、PNP型三极管、有源蜂鸣器、共阴极数码管

实现的功能

  1. 通过按键实现倒计时

  2. 逐秒倒计时

  3. 使用4为一体数码管显示时间

  4. 时间到发出警报声,或者在数码管闪烁显示0000

仿真电路图:推荐使用网络标号连接电路图,这样作图较为专业,适合以后的大点的作图方式。网络标号相同的即为相连接的,图貌似不是很清晰,如果看不清,评论区留言,我发给你proteus仿真文件。
在这里插入图片描述

程序代码:148行程序,不是太长

//尽本人最大的努力,将程序中的每条语句较为详细的讲解
#include <reg51.h>
#include <stdio.h>
#define uint unsigned int
#define uchar unsigned char
uchar count=0,minute=0,second=3,flag=0,stop=0;
uchar table[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//共阴极
uchar disbuf[4]={0};//位选定义一个四位的数组,循环扫描显示相应的内容
sbit buzzer=P1^0;//定义单片机的相应引脚
sbit P1_1=P1^1;
sbit P1_2=P1^2;

void delay_ms(uint x) //延时消抖函数
{uint t; 
 while(x--) for(t = 0; t < 120; t++);
}

void display()//模块化书写函数,进行相应的调用,实现模块化编程
{
	uchar i,j;
	uchar sel;
	disbuf[0]=second%10; //disbuf[]每一个元素赋值,对秒赋值
	disbuf[1]=second/10;
	disbuf[2]=minute%10;//对分钟赋值
	disbuf[3]=minute/10;
	P2=0XFF;     //P2口接数码管的位选端,选择哪个数码管工作  共阴极数码管,位选0时有效  先置FF,使为选段为高电平,数码管不工作
	sel=0x01;//定义一个扫描的位选端
	for(i=0;i<4;i++)
		{
			j=disbuf[i];  //扫描依次显示四个数码管  上面的赋值已经将disbuf数值更改,也就是1~9
			P0=table[j]; //将字形码发送到P0端口,显示位的数据
			P2=(sel^0xff); // ^异或相异为1,保证每次都有一个数码管点亮
			delay_ms(1); // 延时后,防止程序运行太快,跑飞
			P2=0XFF;
			sel=sel<<1;  //  左移运算  0x01左移,1将依次在四位上循环
		}
}

void modify_time()//更改计时器时间的函数,修改初始定时时间
{
	if(flag==0)//修改秒
		{
			second++;
			if(second==60)//秒的最大为60,然后会发生进位
				{
					second=0;
					disbuf[0]=0;
					disbuf[1]=0;
				}
		}
	else//修改分钟
		{
			minute++;
			if(minute==60)//分钟最大为60,到60以后会发生进位
				{
					minute=0;
					disbuf[2]=0;
					disbuf[3]=0;
				}
		}

}
void main(void)//主函数
 { 
  TMOD=0x01;//定时器T0,工作方式1,为16位定时器
  TH0=(65536-50000)/256;//高8位赋值
  TL0=(65536-50000)%256;//低8位赋值
  TR0=0;//默认情况下,定时器不工作,在外部的触发情况下,定时器,工作,开始减1运算
  ET0=1;//打开定时器T0的中断
  IT0=1;//设置外部中断0的触发方式
  EX0=1;//打开外部中断的中断
  IT1=1;//设置外部中断0触发方式
  EX1=1;//打开外部中断1中断
  EA=1;//总中断
  while(1)
	{
		if(stop==1)//当计时倒计时完成以后,屏幕闪烁显示
			{
				while(1)
					{
						P2=~P2;
						delay_ms(150);
					}
			}
		else
			display();//调用显示函数,依次减一
		if(!P1_1)//判断更改时间按键是否按键  进行相应的消抖
       {
		   while(!P1_1)  
           delay_ms(10);  
           if(P1_1)
           modify_time();//调用调日期时间的函数
		}	
	}
 }

void inter1() interrupt 1//定时器T0的中断
{
	count++;
	TH0=(65536-50000)/256;
    TL0=(65536-50000)%256;
	if(count==20)//50ms   20次即为1s
		{	
			count=0;
			second--;
			if(second==0)//该处的程序结构应该仔细看下
				{
					if(minute!=0)//防止minute最后为0的时候,还执行minute--,使程序出错。
						{
							minute--;
							second=60;
							second--;
							if(second==0)
								{	
									if(minute==0)
										{
											second=0;
											minute=0;
											TR0=0;
											count=0;
											buzzer=0;
											stop=1;

										}
								}
						}
					else
						{
							second=0;
							minute=0;
							TR0=0;
							count=0;
							buzzer=0;
							stop=1;
						}
				}
		}
}
	
void inter0() interrupt 0//外部中断0
{
	flag=~flag;//flag参数的作用,是修改定时时间的时,确定是分钟位还是小时位。
	
}

void inter2() interrupt 2//外部中断1
{
	TR0=~TR0;//按键3,奇数次按下,定时器开始工作,偶数次关闭。
}

所用器材的介绍
PNP型三极管:判断的依据,可根据,箭头方向来判断,箭头向外NPN,箭头向内PNP
蜂鸣器:选择无源蜂鸣器 并且将电压设置为2V,如果不这样设置,可能蜂鸣器不发声。

发布了11 篇原创文章 · 获赞 72 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_41948771/article/details/103552517