基于51单片机的比赛倒计时器仿真

仿真图:

在这里插入图片描述

芯片/模块的特点:

AT89C52简介:
AT89C52是一款经典的8位单片机,是意法半导体(STMicroelectronics)公司生产的一系列单片机之一。它基于8051内核,并具有许多与其兼容的特性。

AT89C52的主要特点如下:

内部存储器:AT89C52具有8KB的闪存(Flash)存储器,可用于存储用户程序和数据。这些存储器的内容可以通过编程器进行编程和擦除。

RAM存储器:AT89C52配备了256字节的随机存取存储器(RAM),用于暂存数据和程序的变量。

外部扩展性:AT89C52支持多种外部扩展设备的连接,包括外部存储器(如RAM、EEPROM)和外设(如ADC、LCD、UART等),通过外部硬件连接,可以扩展单片机的功能和应用。

通用I/O引脚:AT89C52拥有32个可编程的通用输入/输出引脚,可用于连接外部设备和与其他芯片进行通信。

定时器/计数器:AT89C52内置了3个16位定时器/计数器和一个可编程的串行定时器/计数器。这些计时器/计数器可用于实现定时功能、生成脉冲信号、测量时间间隔等。0

串行通信:AT89C52支持串行通信接口,包括UART(串行异步通信)和SPI(串行外设接口),便于与其他设备进行数据通信和交互。

低功耗模式:AT89C52具有多种低功耗模式,如空闲模式和电源下模式,在不需要执行任务的时候可以将CPU进入低功耗状态以节省能量。

宽电源电压范围:AT89C52的工作电压范围通常为4.0V至5.5V,可以满足大多数应用需求。

主程序:

#include <reg52.h>			//调用单片机头文件
#define uchar unsigned char //无符号字符型 宏定义	变量范围0~255
#define uint unsigned int	//无符号整型 宏定义	变量范围0~65535
#include <intrins.h>

//数码管段选定义      0     1    2    3    4    5	6	 7	  8	   9
uchar code smg_du[] = {0x28, 0xEE, 0x32, 0xA2, 0xE4, 0xA1, 0x21, 0xEA, 0x20, 0xA0,
					   0x60, 0x25, 0x39, 0x26, 0x31, 0x71, 0xff}; //断码

//管脚声明
sbit SMG_S1 = P3^4; //数码管位选定义
sbit SMG_S2 = P3^5;
sbit SMG_S3 = P3^6;
sbit SMG_S4 = P3^7;
sbit BUZZER = P3^2;
sbit KEY_SET = P2^0;
sbit KEY_ADD = P2^1;
sbit KEY_SUB = P2^2;
sbit KEY_START = P2^3;


uchar dis_smg[8] = {0x90, 0xf5, 0x1c, 0x34, 0x71, 0x32, 0x12, 0xf4}; //显示内容
uchar dis_smg_buf[8] = 0; //显示内容
bit flag_500ms = 1;
uchar a_a;
uchar g_setLocation; //设置参数用

uchar minute = 0; // 倒计时数
uchar second = 0; // 倒计时数
uchar mSec = 0; // 倒计时数
uchar numValue;				// 用做中间的变量
bit startFlag;				// 倒计时器开始计时使能标志位
uchar setMinute = 30;		// 设置倒计时数的启始值
uchar setSecond = 0;		// 设置倒计时数的启始值

/***********************1ms延时函数*****************************/
void DelayMs(uint q)
{
	uint i, j;
	for (i = 0; i < q; i++)
		for (j = 0; j < 120; j++)
			;
}

/***********************数码位选函数*****************************/
void smg_we_switch(uchar i) //选择i位单独显示
{
	switch (i)
	{
	case 0:
		SMG_S1 = 0;
		SMG_S2 = 1;
		SMG_S3 = 1;
		SMG_S4 = 1;
		break;
	case 1:
		SMG_S1 = 1;
		SMG_S2 = 0;
		SMG_S3 = 1;
		SMG_S4 = 1;
		break;
	case 2:
		SMG_S1 = 1;
		SMG_S2 = 1;
		SMG_S3 = 0;
		SMG_S4 = 1;
		break;
	case 3:
		SMG_S1 = 1;
		SMG_S2 = 1;
		SMG_S3 = 1;
		SMG_S4 = 0;
		break;
	}
}

/*************定时器0初始化程序***************/
void Timer_Init()
{
	EA = 1;		 //开总中断
	TMOD = 0X01; //定时器0、工作方式1
	ET0 = 1;	 //开定时器0中断
	TR0 = 1;	 //允许定时器0定时
}

/***********************数码显示函数*****************************/

void Display()
{
	uchar i;
	for (i = 0; i < 4; i++)
	{
		P1 = 0xff;		  //消隐
		smg_we_switch(i); //位选
		P1 = dis_smg[i];  //段选
		DelayMs(1);
	}
}

/********************独立按键程序*****************/
uchar key_can; //按键值

void key() //独立按键程序
{
	static uchar key_new;
	key_can = 20;			 //按键值还原
	if ((P2 & 0x0F) != 0x0F) //按键按下
	{
		DelayMs(1); //按键消抖动
		if (((P2 & 0x0F) != 0x0F) && (key_new == 1))
		{ //确认是按键按下
			key_new = 0;
			switch (P2 & 0x0F)
			{
			case 0x0E:
				key_can = 1;
				break; //得到k2键值
			case 0x0D:
				key_can = 2;
				break; //得到k3键值
			case 0x0B:
				key_can = 3;
				break; //得到k4键值
			case 0x07:
				key_can = 4;
				break; //得到k5键值
			}
		}
	}
	else
		key_new = 1;
}

/****************按键处理数码管显示函数***************/
void key_with()
{
	if (key_can == 1)
	{
		g_setLocation++;
		if (g_setLocation >= 3) //确定设置
		{
			g_setLocation = 0;
			minute = setMinute;
			second = setSecond;
		}
	}

	if (g_setLocation == 0) //倒计时器按键操作开始 暂停
	{
		if (key_can == 4) //开始键
		{
			startFlag = ~startFlag;
			BUZZER = 0; //打开蜂鸣器
			DelayMs(30);
			BUZZER = 1; //关闭蜂鸣器
		}
	}

	if (g_setLocation == 1) //设置倒计时器开始数
	{
		if (key_can == 2)
		{
			setSecond++; // 设置数加
			if (setSecond >= 60)
				setSecond = 0;						  //最大加到99
			dis_smg[0] = smg_du[setSecond % 10];	  //取个数显示
			dis_smg[1] = smg_du[setSecond / 10 % 10]; //取十位显示
		}
		if (key_can == 3)
		{
			if (setSecond == 0)
				setSecond = 60;
			setSecond--;							  // 设置数减
			dis_smg[0] = smg_du[setSecond % 10];	  //取个数显示
			dis_smg[1] = smg_du[setSecond / 10 % 10]; //取十位显示
		}
	}

	if (g_setLocation == 2) //设置倒计时器开始数
	{
		if (key_can == 2)
		{
			setMinute++; // 设置数加
			if (setMinute > 99)
				setMinute = 0;						  //最大加到99
			dis_smg[2] = smg_du[setMinute % 10];	  //取个数显示
			dis_smg[3] = smg_du[setMinute / 10 % 10]; //取十位显示
		}
		if (key_can == 3)
		{
			if (setMinute == 0)
				setMinute = 100;
			setMinute--;							  // 设置数减
			dis_smg[2] = smg_du[setMinute % 10];	  //取个数显示
			dis_smg[3] = smg_du[setMinute / 10 % 10]; //取十位显示
		}
	}
}

/******************主程序**********************/
void main()
{
	BUZZER = 0; //开机蜂鸣器叫一声
	DelayMs(100);
	P0 = P1 = P2 = P3 = 0xff; //初始化IO口
	Timer_Init();
	second = setSecond; //开机显示设置数
	minute = setMinute; //开机显示设置数
	while (1)
	{
		key();
		if (key_can < 10)
		{
			key_with(); //按键执行函数
		}

		if (g_setLocation == 0) //扫描显示倒计时数
		{
			dis_smg[0] = smg_du[second % 10];
			dis_smg[1] = smg_du[second / 10 % 10];
			dis_smg[2] = smg_du[minute % 10] & 0xdf;
			dis_smg[3] = smg_du[minute / 10 % 10];
			if (flag_500ms == 1)
			{
				flag_500ms = 0;
				if ((second <= 5) && (minute == 0)) //计时到小于等于5s 蜂鸣器报警
					BUZZER = ~BUZZER;
			}

			if ((minute == 0) && (second == 0))
			{
				BUZZER = 1;			//关闭蜂鸣器
				second = setSecond; //让显示最大数
				minute = setMinute; //让显示最大数
				startFlag = 0;
				mSec = 1;
			}
		}

		if (g_setLocation == 1) //在设置的时候十位数闪烁
		{
			if (flag_500ms == 1)
			{
				dis_smg[0] = smg_du[setSecond % 10];		//取个位显示
				dis_smg[1] = smg_du[setSecond / 10 % 10];	//取十位显示
				dis_smg[2] = smg_du[setMinute % 10] & 0xdf; //取个数显示
				dis_smg[3] = smg_du[setMinute / 10 % 10];	//取十位显示
			}
			else
			{
				dis_smg[0] = 0xff;							//取个位显示
				dis_smg[1] = 0xff;							//取十位显示
				dis_smg[2] = smg_du[setMinute % 10] & 0xdf; //取个数显示
				dis_smg[3] = smg_du[setMinute / 10 % 10];	//取十位显示
			}
		}

		if (g_setLocation == 2) //在设置的时候十位数闪烁
		{
			if (flag_500ms == 1)
			{
				dis_smg[0] = smg_du[setSecond % 10];		//取个位显示
				dis_smg[1] = smg_du[setSecond / 10 % 10];	//取十位显示
				dis_smg[2] = smg_du[setMinute % 10] & 0xdf; //取个数显示
				dis_smg[3] = smg_du[setMinute / 10 % 10];	//取十位显示
			}
			else
			{
				dis_smg[0] = smg_du[setSecond % 10];	  //取个位显示
				dis_smg[1] = smg_du[setSecond / 10 % 10]; //取十位显示
				dis_smg[2] = 0xff;						  //取个数显示
				dis_smg[3] = 0xff;						  //取十位显示
			}
		}

		Display(); //数码管显示函数

	}
}

/*************定时器0中断服务程序***************/
void time0_int() interrupt 1
{
	static uint cnt = 0;
	TH0 = (65536 - 9216) / 256;
	TL0 = (65536 - 9216) % 256; // 10ms
	cnt++;
	if (cnt >= 50) //每次10ms 定时到50次也就是500ms
	{
		cnt = 0;
		flag_500ms = ~flag_500ms; //标志置位
	}
	if (startFlag == 1) //显示标志
	{
		numValue = 0;
		if (mSec == 0) //显示秒位
		{
			mSec = 100;
			if (second == 0)
			{
				second = 60;	 //重置s单位
				if (minute != 0) //如果分不为0
					minute--;
			}
		}
		mSec--;
	}
}

设计文件:

链接:https://pan.baidu.com/s/1eKMjcgs3EX09a7ZgCS4LHw?pwd=8b66

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值