51单片机通过级联74HC595实现倒计时秒表Protues仿真设计

一、设计背景

        近年来随着科技的飞速发展,单片机的应用正在不断的走向深入。本文阐述了51单片机通过级联74HC595实现倒计时秒表设计,倒计时精度达0.05s,解决了传统的由于倒计时精度不够造成的误差和不公平性,是各种体育竞赛的必备设备之一。本设计采用51单片机为中心器件,利用其定时器/计数器定时和记数的原理,使用两片74HC595级联实现LED数码管的控制以及利用外部中断来设计倒计时器。将软、硬件有机地结合起来,使得系统能够实现八位LED显示,倒计时精度为0.05秒,能正确地进行倒计时,复位后倒计时重新回到初始状态。其中软件系统采用C语言编写程序,包括显示程序,定时中断服务,外部中断服务程序,延时程序等,并在KEIL5中调试运行,硬件系统利用Protues强大的功能来实现,简单易于观察,在仿真中就可以观察到实际的工作状态。

二、实现功能

        以51单片机为控制核心,设计一种可调倒计时秒表。整个系统包括51单片机芯片、晶振电路、时钟电路、功能按键以及74HC595数码管控制显示电路。该系统利用共阳数码管实时显示时、分、秒倒计时,通过独立按键键盘设计控制倒计时秒表的启停、定时时间的设计。可具体实现以下功能:

(1) 按下设置键后,在数字闪烁的过程中,采用启动外部中断,能对增、减按键产生响应,。

(2) 按下启动键后,启动定时器;按下暂停键后,停止定时器。

(3)·定时器定时50ms,20次定时可产生1秒钟计时。

(4) 倒计时结束后,停止定时器。

(5) 最大定时99时59分59秒。

三、仿真演示

 初始化定时时间0时0分0秒。

按下时间设置按键可以设置倒计时时间,通过连续按下时间设置按键可在时、分、秒设置来回切换,利用闪烁效果提示当前设置单位。

 设置好倒计时时间后,利用启动键和停止键实现倒计时秒表的启停。

四、源程序

#include <REGX52.H>
#include <intrins.h>


#define false 0
#define true 1
#define uchar unsigned char	 //0——255
#define uint unsigned int	 		//0——65535
#define ulong unsigned long	//0——4294967295
	

sbit SDA1 = P3^6;    //串行数据输入,对应595的14脚SER
sbit SCL1 = P3^7;     //移位寄存器时钟输入,对应595的11脚SCK
sbit SCL2 = P2^4;     //存储寄存器时钟输入,对应595的12脚RCK

sbit start_key = P3^0;	//启动按钮
sbit pause_key = P3^1;	//停止按钮
sbit set_key = P3^5;	//停止按钮

uchar state;	//状态:0-停止,1-启动,2-暂停
ulong ms = 0;	//存储毫秒值

uchar shi = 0;	// 小时数
uchar fen = 0; //分钟数
uchar miao = 0;	//秒数
uchar set_flag = 0;

uchar smg_c = 0;	//数码管闪烁时间计数
bit smg_f = 0;	//数码管闪烁标志

unsigned char code disp[17]=	{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
						0x7f,0x6f,0x77,0x7c,0x58,0x5e,0x79,0x71,0x40}; /***数码***/

                         //0  1   2   3   4   5   6   7   8   9
unsigned char code wei[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};


void displayTime(void);	 //刷新时间显示
void disPlay(uchar num, uchar loc);	 //数码管、led显示函数
void Exint_Init(void);
void Timer_Init(void);
void delay2ms(void);
void Delay1ms(unsigned int n);

void Delay1ms(unsigned int n)
{
	unsigned char i, j;	
	for (; n>0; n--)
		for(i=0;i<10;i++)
			for(j=0;j<33;j++);	
}

void delay2ms(void)
{
   unsigned char i,j;
   for(i=133;i>0;i--)
   for(j=6;j>0;j--);
}

void c595_in(unsigned char Data)
{
	unsigned char i;
	for(i = 0; i < 8; i++)   //循环8次,刚好移完8位
	{
		SCL1 = 0;        //先将移位寄存器控制引脚置为低    
		_nop_();
		if((Data & 0x80)== 0x80)
			SDA1 =1;
		else
			SDA1 =0;
			Data <<= 1;           //将数据的次高位移到最高位
			SCL1 = 1;         //再置为高,产生移位时钟上升沿,上升沿时数据寄存器的数据移位
			_nop_();
	}
}

void c595_out(void)
{
   	SCL2 = 0;   //先将存储寄存器引脚置为低
    _nop_();
    SCL2 = 1;    //再置为高,产生移位时钟上升沿,上升沿时移位寄存器的数据进入数据存储寄存器,更新显示数据。
}

void Timer_Init(void)
{
	TMOD=0x11; //0110 0001	//方式一
	
	TH0= (65536-50000)/256;
	TL0= (65536-50000)%256;		// 50ms
    TH1= (65536-50000)/256;
	TL1= (65536-50000)%256;		// 50ms
	
	TR0=1;		//开启T0
	TR1=1;		//开启T1
	//ET0=1;		//T0中断允许
    //ET1=1;		//T1中断允许
	EA=1;	//总中断开启
}

void T0_INT0(void)  interrupt 1
{ 
	ms++;
	if(ms == 20)  //1s时间到
	{
		ms = 0;
		if(miao > 0){miao--;}
		if(miao == 0)    //秒数计时为0
		{
			if(fen == 0)   //没有分钟数
			{
              if(shi == 0){TR0 = 0;}	 //判断是否还有时数,若没有,倒计时结束,停止计时	
			  else{ shi--;fen = 60;}
			}
			if(fen > 0) //有分钟数
			{
				fen--;
				miao = 59;
			}
		}
	}
}

void T0_INT1(void)  interrupt 3
{ 
	smg_c++;
	if(smg_c == 10)
	{
		smg_c = 0;
		smg_f = ~smg_f;
	}
}

/*********外部中断0、1初始化***********/
void Exint_Init()
{
	IT0 = 1;
	IT1 = 1;    //下降沿触发
	EX0 = 1;
	EX1 = 1;
	PX0 = 1;    // 中断优先级设置
	PX1 = 0;
}

/*********外部中断0服务函数***********/
void Exint0_Service() interrupt 0
{
    if(set_flag == 3) 
    {
		miao++;
		if(miao == 60){miao = 59;}
	}
	if(set_flag == 2) 
    {
	    fen++;if(fen == 60){fen = 59;}       //按键加
	}
	 if(set_flag == 1) 
     {
		shi++;
		if(shi == 100) {shi = 99;}
	 }
}

/*********外部中断1服务函数***********/
void Exint1_Service() interrupt 2
{
   if(set_flag == 3) 
   {
	  if(miao > 0){miao--;}
   }
   if(set_flag == 2) 
   {
	  if(fen > 0){fen--;}         //按键减
   }
	 if(set_flag == 1) 
   {
      if(shi > 0){shi--;}
   }
}

void displayTime(void)	 //刷新时间显示
{
	if(((smg_f == 0) && (set_flag == 1))|| (set_flag == 0) || (set_flag == 2) || (set_flag == 3))
	{
		c595_in(wei[0]);  //先传位码
		c595_in(disp[shi/10]);  //再传段码
		c595_out();
		delay2ms();
		c595_in(wei[1]);  //先传位码
		c595_in(disp[shi%10]);  //再传段码		
		c595_out();
		delay2ms();
	}	
	
	c595_in(wei[2]);  //先传位码
	c595_in(disp[16]);  //再传段码		
	c595_out();
	delay2ms();
	
  if(((smg_f == 0) && (set_flag == 2))|| (set_flag == 0) || (set_flag == 1) || (set_flag == 3))
	{
		c595_in(wei[3]);  //先传位码
		c595_in(disp[fen/10]);  //再传段码
		c595_out();
		delay2ms();
		c595_in(wei[4]);  //先传位码
		c595_in(disp[fen%10]);  //再传段码
		c595_out();
		delay2ms();
	}
	
	c595_in(wei[5]);  //先传位码
	c595_in(disp[16]);  //再传段码		
	c595_out();
	delay2ms();
	
  if(((smg_f == 6) && (set_flag == 3))|| (set_flag == 0) || (set_flag == 1) || (set_flag == 2))
	{
		c595_in(wei[6]);  //先传位码
		c595_in(disp[miao/10]);  //再传段码
		c595_out();
		delay2ms();
		c595_in(wei[7]);  //先传位码
		c595_in(disp[miao%10]);  //再传段码
		c595_out();
		delay2ms();
	}
}

void main(void)
{
  Timer_Init();
	Exint_Init();
	while(1)
	{
		displayTime();	 //刷新时间显示
			
		//检测启动按钮
		if(start_key == 0)	 //按下了启动、停止按钮
		{
			Delay1ms(10);	//延时消抖
			if(start_key == 0)
			{
			    ET0 = 1;		//T0中断允许打开,开始计时
				set_flag = 0;
				TR0 = 1;
			    while(start_key == 0) displayTime();	//防止按键重复检测
			}
		}
		
		//检测停止按钮
		if(pause_key == 0)	//已启动计时,并且暂停按钮按下
		{
			Delay1ms(10);	//延时消抖
			if(pause_key == 0)
			{
				ET0 = 0;	
			    while(pause_key == 0) displayTime();	//防止按键重复检测
			}
		}
		
		if(set_key == 0)	//已启动计时,并且暂停按钮按下
		{
			Delay1ms(10);	//延时消抖
			if(set_key == 0)
			{
				ET1=1;	
				set_flag++;
				if(set_flag == 4)
				{
					set_flag = 1;
				}
			    while(set_key == 0) displayTime();	//防止按键重复检测
			}
		}
	}
}

仿真源文件与keil工程百度网盘链接:https://pan.baidu.com/s/1L-FwKgHhRAUiHs6nwD4cBA 
提取码:fqjd 
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/357022.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据结构.栈

一、栈的定义 二、初始化 #include<iostream> using namespace std; const int N 10; typedef struct {int data[N];int top; }SqStack; void InitSqStack(SqStack &S)//初始化 {S.top -1; } 三、进栈 void Push(SqStack& S, int x)//入栈 {S.data[S.top] x; …

深入了解Matplotlib中的子图创建方法

深入了解Matplotlib中的子图创建方法 一 add_axes( **kwargs):1.1 函数介绍1.2 示例一 创建第一张子图1.2 示例二 polar参数的运用1.3 示例三 创建多张子图 二 add_subplot(*args, **kwargs):2.1 函数介绍2.2 示例一 三 两种方法的区别3.1 参数形式3.2 布局灵活性3.3 适用场景3…

机器学习:多项式回归(Python)

多元线性回归闭式解&#xff1a; closed_form_sol.py import numpy as np import matplotlib.pyplot as pltclass LRClosedFormSol:def __init__(self, fit_interceptTrue, normalizeTrue):""":param fit_intercept: 是否训练bias:param normalize: 是否标准化…

verdaccio搭建npm私服

一、安装verdaccio 注&#xff1a;加上–unsafe-perm的原因是防止报grywarn权限的错 npm install -g verdaccio --unsafe-perm 二、启动verdaccio verdaccio 三、配置文件 找到config.yml一般情况下都在用户下的这个文件夹下面 注&#xff1a;首次启动后才会生成 C:\Users\h…

/etc/profile错误,命令失效

source /etc/profile后所有命令失效 执行 export PATH/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin 修改后 执行:wq! 执行:w !sudo tee %

怎么控制Element的数据树形表格展开所有行;递归操作,打造万能数据表格折叠。

HTML <el-button type"success" size"small" click"expandStatusFun"> <span v-show"expandStatusfalse"><i class"el-icon-folder-opened"></i>展开全部</span><span v-show"expan…

鸿蒙原生应用开发已全面启动,你还在等什么?

2019年&#xff0c;鸿蒙系统首次公开亮相&#xff0c;你们说&#xff0c;等等看&#xff0c;还不成熟&#xff1b; 2021年&#xff0c;鸿蒙系统首次在手机端升级&#xff0c;你们说&#xff0c;等等看&#xff0c;还不完善&#xff1b; 2024年&#xff0c;鸿飞计划发布&#…

STM32以太网接口在TCP/IP通信中的应用案例

在STM32的以太网通信中&#xff0c;TCP/IP协议广泛应用于各种领域&#xff0c;如远程监控、物联网、工业控制等。下面以一个STM32基于TCP/IP协议的以太网通信的应用案例为例进行介绍。 ✅作者简介&#xff1a;热爱科研的嵌入式开发者&#xff0c;修心和技术同步精进 ❤欢迎关注…

C#颜色拾取器

1&#xff0c;目的&#xff1a; 获取屏幕上任意位置像素的色值。 2&#xff0c;知识点: 热键的注册与注销。 /// <summary>/// 热键注册/// </summary>/// <param name"hWnd">要定义热键的窗口的句柄 </param>/// <param name"id…

如何使用Python Flask搭建一个web页面并实现远程访问

文章目录 前言1. 安装部署Flask并制作SayHello问答界面2. 安装Cpolar内网穿透3. 配置Flask的问答界面公网访问地址4. 公网远程访问Flask的问答界面 前言 Flask是一个Python编写的Web微框架&#xff0c;让我们可以使用Python语言快速实现一个网站或Web服务&#xff0c;本期教程…

C++多线程1(复习向笔记)

创建线程以及相关函数 当用thread类创建线程对象绑定函数后&#xff0c;该线程在主线程执行时就已经自动开始执行了,join起到阻塞主线程的作用 #include <iostream> #include <thread> #include <string> using namespace std; //测试函数 void printStrin…

Java强训day10(选择题编程题)

选择题 public class Test01 {public static void main(String[] args) {try{int i 100 / 0;System.out.print(i);}catch(Exception e){System.out.print(1);throw new RuntimeException();}finally{System.out.print(2);}System.out.print(3);} }编程题 题目1 import jav…

day 59 503.下一个更大元素II 42. 接雨水

vector的扩充要熟悉 vector<int> numsT(nums.begin(),nums.end()); nums.insert(nums.end(),numsT.begin(),numsT.end()); class Solution { public:vector<int> nextGreaterElements(vector<int>& nums) {stack<int> st;vector<int> nums…

C++入门(一)— 使用VScode开发简介

文章目录 C 介绍C 擅长领域C 程序是如何开发编译器、链接器和库编译预处理编译阶段汇编阶段链接阶段 安装集成开发环境 &#xff08;IDE&#xff09;配置编译器&#xff1a;构建配置配置编译器&#xff1a;编译器扩展配置编译器&#xff1a;警告和错误级别配置编译器&#xff1…

自动驾驶代客泊车AVP决策规划详细设计

背景 随着产品的不断迭代&#xff0c;外部停车场的铺开&#xff0c;PAVP车辆需要应对的场景将越来越复杂&#xff0c;因此整体算法泛化能力的提升显得尤为关键。为了打磨巡航规划的能力&#xff0c;算法架构应当设计的更为灵活&#xff0c;可以针对使用场景迁入更为先进有效的算…

Springboot 快速集成 ES

1、Springboot 官网给出的版本选择标准 2、选择版本依赖 我的 elasticsearch 服务版本为 7.17.13&#xff0c;所以 springboot 版本我选用 2.7.10 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies<…

电脑上如何压缩图片?这个方法简单又方便

电脑上如何压缩图片&#xff1f;我们在需要压缩图片大小的时候&#xff0c;最经常使用的就是下载安装一些图片处理软件&#xff0c;这样的方法不仅耽误时间&#xff0c;有些软件的操作步骤还特别繁琐&#xff0c;对新手小白非常不友好&#xff0c;所以小编今天就给大家介绍一个…

巴厘行记(四)——乌布漫游

欢迎览阅《巴厘行记》系列文章 巴厘行记巴厘行记&#xff08;一&#xff09;——海神庙 巴厘行记&#xff08;二&#xff09;——乌布之夜 巴厘行记&#xff08;三&#xff09;——Auntie和Mudi 巴厘行记&#xff08;四&#xff09;——乌布漫游 巴厘行记&#xff08;五&a…

Spring MVC 基本知识

知识回顾 Tomcat 是 Servlet 容器&#xff0c;会解析 Java Web 应用下的 WEB-INF/web.xml 文件&#xff0c;得到相关的 Servlet 组件。 原理解析 Spring MVC 实际是定义了一个 DispatcherSevlet 来统一管理当前 Web 应用下的 Path 路径。在 DispatchSevlet 中持有了一个 Spr…

Mybatis-plus原生pages分页未生效的解决方案

文章目录 前言原因1、Mybatis Plus版本的问题2、Mapper.xml文件中SQL语句格式问题3、Mybatis Plus默认分页拦截器问题4、分页参数传参问题5、分页配置的问题 解决方案1、升级对应的Mybatis-plus版本分页插件配置问题3、自定义分页拦截器4、正确的参数5、不同版本的配置文件3.4.…