STC89C52单片机启动--综合案例秒表

代码功能:


1.自动开始计数,一共5个数码管来显示时间。一位数码管显示0-9,对应分度值是0.1s;两位数码管显示00-59,对应分度值1s;两位数码管显示00-59,对应分度值1min;上电后自动开始计时模式。

2.按下开关K1,计时暂停;按下开关K2,计时清0,从头开始计时;按下开关K3,显示520.1314,再次按下开关回到计时模式,显示520.1314期间计时仍在进行。

代码如下

delay.h  delay.c  main.c  SMG.h  SMG.c部分

//main.c
#include<regx52.h>
#include"function.h"
#include"delay.h"
#include"SMG.h"
void main(){Init_T0();while(1){//一直检测是否有按键按下,从而执行下面三个函数pause();clear();love();//这个flag变量其实没有必要写,但这里我想借这个别的文件中的变量来说明一个知识点
//因为当不显示520.1314的时候flag==1是肯定的,就会自动腾出来数码管来执行clock函数显示时间if(flag==1){clock();}}
}//delay.h
#ifndef __delay_H__
#define __delay_H__
void delay(unsigned int t);
#endif//delay.c
#include"delay.h"
void delay(unsigned int t){while(t--);
}//SMG.h
#ifndef __SMG_H__
#define __SMG_H__
//传入显示哪个数码管,显示哪个数字,显示不显示小数点三个参数
void SMG_show(unsigned char pos,unsigned char num,unsigned char dot);
#endif//SMG.c
#include<regx52.h>
#include"delay.h"
#include"SMG.h"
sbit A1=P2^2;
sbit B1=P2^3;
sbit C1=P2^4;
//这里是共阴数码管,定义了两个数组,分别是不显示点和显示点的
//第二的SMGdot[]数组第11个数据表示单独仅一个小数点
//用来显示520.1314中让一个数码管仅仅显示一个.
//最需要注意的是pos和C1,C2,C3对应顺序
unsigned char SMGndot[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
unsigned char SMGdot[11]={0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef,0x80};
void SMG_show(unsigned char pos,unsigned char num,unsigned char dot){switch(pos){case 1:C1=0;B1=0;A1=0;break;case 2:C1=0;B1=0;A1=1;break;case 3:C1=0;B1=1;A1=0;break;case 4:C1=0;B1=1;A1=1;break;case 5:C1=1;B1=0;A1=0;break;case 6:C1=1;B1=0;A1=1;break;case 7:C1=1;B1=1;A1=0;break;case 8:C1=1;B1=1;A1=1;break;}if(dot==1){P0=SMGdot[num];}else{P0=SMGndot[num];}}

function.h function.c部分

//function.h
#ifndef __function_H__
#define __function_H__
extern unsigned int s;
extern unsigned int min;
extern unsigned int ms10;//0.5s
extern unsigned char flag;//控制显示静态520还是动态时钟
void Init_T0();
void pause();
void clear();
void love();
void clock();
#endif//function.c
#include<regx52.h>
#include"delay.h"
#include"function.h"
#include"SMG.h"
unsigned int s=0;
unsigned int min=0;
unsigned int ms10=0;
unsigned char flag=1;
void clock(){SMG_show(1,ms10/2,0);delay(50);SMG_show(2,s%10,1);delay(50);SMG_show(3,s/10,0);delay(50);SMG_show(4,min%10,1);delay(50);SMG_show(5,min/10,0);delay(50);
}
void Init_T0(){TMOD=0x01;TH0=(65536-50000)/256;TL0=(65536-50000)%256;ET0=1;EA=1;TR0=1;
}
void service_T0()interrupt 1{TH0=(65536-50000)/256;TL0=(65536-50000)%256;ms10++;if(ms10==20){s++;ms10=0;}if(s==60){min++;s=0;}
}
void pause(){if(P3_1==0){delay(20);if(P3_1==0){while(P3_1==0);TR0=~TR0;//注意让定时器暂停我们改变的是TR0}}
}
void clear(){if(P3_0==0){delay(20);if(P3_0==0){while(P3_0==0);ms10=0;s=0;min=0;}}
}
void love(){
//这小段代码是检测按键有没有按下,从而改变变量flag的值if(P3_2==0){delay(100);if(P3_2==0){while(P3_2==0);if(flag==0){flag=1;}if(flag==1){flag=0;}//1.这段代码是在flag==0时一直让数码管显示数字,
因为这里多位数码管的显示都是利用不断循环刷新,视觉暂留效果,
所以我们要写到while(flag==0){}里面,目的是:没有再次按下按键K3的时候一直运行这段代码,
一直刷新才能一直显示8位数字。同时在这个函数中也要加上一段按键检测的代码,
来检测有没有按键再次按下,不然就永远困在这个while循环了。
//2.所以我们说刚刚在main.c中的if(flag==1)执行时钟代码时没有用的其实,完全可以不加if(flag==0){while(flag==0){if(P3_2==0){delay(100);if(P3_2==0){while(P3_2==0);flag=1;}}	SMG_show(8,5,0);delay(50);SMG_show(7,2,0);delay(50);SMG_show(6,0,0);delay(50);SMG_show(5,10,1);delay(50);SMG_show(4,1,0);delay(50);SMG_show(3,3,0);delay(50);SMG_show(2,1,0);delay(50);SMG_show(1,4,0);delay(50);}}}}
}

收获

1.定时器0暂停为什么是对TR0操作?

从图中我们可以看出来想让定时器计数暂停就要让控制信号K来断开,所以最好的方式就是通过TRx来控制定时器的启动和停止,这样同时也能保留当前加1计数器中的数字不变。如果是改变了我们IE寄存器的使能端,只能是让定时器中断过去不了,但前面计数仍在继续。

2.全局变量如何跨文件使用

在上面代码中我们在function.c文件中使用了flag全局变量,但是我们还想在main.c中使用这个全局变量,我们应该如何写代码?

其实这和让函数在被别的文件中使用差不多,都是在.h中声明,在.c中实现,在别的文件中用到的时候包含.h头文件就可以了,但是为什么变量的声明前面要额外加extern呢?

在 C 语言中,使用 extern 关键字来声明变量时,是为了告诉编译器该变量是在其他文件中定义的,需要在当前文件中进行引用。而对于函数的声明,通常不需要使用 extern 关键字是因为函数的声明本身就隐含了 extern 的含义。

3.并不是所有在.c文件中使用的全局变量和函数都要在.h文件添加声明

我们只用将那些,我们想让外面可以看到全局变量和函数在.h文件中声明。对于比如SMGndot[10]数组,又比如中断服务函数(中断服务函数都是自动调用的,一般就不会写到.h中,供应别的函数使用),这些变量和函数没必要或者我们不想提供给别的文件使用就可以不用在.h文件中添加声明。对于flag这个全局变量我们在main.c中要用到,就需要在.h文件添加声明了

4.巩固了学过的知识

在这个代码中使用到了独立按键,需要用到独立按键的去抖动处理。

使用到了数码管,需要我们通过74HC138译码器来实现对8个数码管的循环提供信号,利用视觉再留达到同时显示的效果,同时回顾了这里使用的是switch,代码上要注意的是C1对应译码器的高位,还要注意其他对应问题,这里我们还是用了两个数组来保存字段码。

使用到了定时器的知识,需要我们来进行一开始定时器的各个变量的初始化,定时器的启动和暂停,要编写中断服务函数。

5.加强了模块化编程

这里我们将暂停,清除,显示8位静态码,显示时间变化,定时器初始化,中断服务函数,这些功能函数写到了一个文件中。(再想说一下,并不是所有的这些数组,或者函数必须要在.h文件中添加说明)

将数码管具体显示实现也单独写到了一个文件中

这样写更清晰明了。

6.残留的缺点

就是这个在使用clear,pause函数的时候,在按下按键之后就不能保持原来正在计数的状态,因为函数会卡在while(P3_1==0)这些地方,在我们松开按键之后才能变为暂停的数字,中间会有一点没有显示的时候,当然快速按下按键然后松开就几乎可以达到连贯的感觉。

在我刚刚写完上面的那段话的时候我忽然就想到了解决方法,代码如下,就是卡在while(P3_1==0)的时候让它来执行clock();同样在clear函数中和love函数中也可做此优化。

while(P3_0==0){clock();};//clear

while(P3_2==0){clock();};//love

这样在按下后但没松开时可以保持原状态

void pause(){if(P3_1==0){delay(20);if(P3_1==0){while(P3_1==0){clock();};TR0=~TR0;}}
}

参考文章:关于C语言全局变量的定义和用法_c语言全局变量的定义与调用-CSDN博客

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

学习刷题-12

3.22 hw机试【双指针】 Leetcode674 最长连续递增序列 给定一个未经排序的整数数组&#xff0c;找到最长且 连续递增的子序列&#xff0c;并返回该序列的长度。 双指针 一个慢指针一个快指针 慢指针记录递增子序列起点&#xff0c;快指针去寻找还在当前递增子序列的最后一…

忘记密码找回流程请求拦截器-前端

目录 设置找回密码请求拦截器 1.相关参数 2.约定 代码实现 1. 实现思路 2. 实现代码 校园统一身份认证系统&#xff1a; 基于网络安全&#xff0c;找回密码、重新设置密码的流程和正常登录流程中密钥等请求头不一致。 设置找回密码请求拦截器 1.相关参数 clientId 应…

【Android开发】【创建Activity,Activity之间的切换/消息传递】【java】

一、第一个Activity 1.1 创建一个空Activity 1.2 创建一个布局 知识点 在XML中引用一个id&#xff1a;id/id_name 在XML中定义一个id&#xff1a;id/id_name 右键错误&#xff0c;点击Show Quick-Fixes&#xff0c;再点击弹出的Suppress:Add........&#xff0c;错误会被自动修…

【C语言】动态内存分配

1、为什么要有动态内存分配 不管是C还是C中都会大量的使用&#xff0c;使用C/C实现数据结构的时候&#xff0c;也会使用动态内存管理。 我们已经掌握的内存开辟方式有&#xff1a; int val 20; //在栈空间上开辟四个字节 char arr[10] { 0 }; //在栈空间…

利用Base64加密算法将数据加密解密

1. Base64加密算法 Base64准确来说并不像是一种加密算法&#xff0c;而更像是一种编码标准。 我们知道现在最为流行的编码标准就是ASCLL&#xff0c;它用八个二进制位&#xff08;一个char的大小&#xff09;表示了127个字符&#xff0c;任何二进制序列都可以用这127个字符表…

【小沐学AI】智谱AI大模型的一点点学习(Python)

文章目录 1、简介1.1 大模型排行榜 2、智谱AI2.1 GLM2.1.1 模型简介2.1.2 开源代码2.1.2.1 GLM-130B 2.2 ChatGLM2.2.1 模型简介2.2.2 开源代码2.2.2.1 ChatGLM-6B2.2.2.2 ChatGLM3 2.3 CodeGeeX2.3.1 模型简介2.3.2 开源代码 2.4 CogView2.4.1 模型简介2.4.2 开源代码 2.5 Cog…

关于序列化和反序列化

什么是序列化&#xff0c;什么是反序列化 简单来说&#xff1a; 序列化&#xff1a;将数据结构或对象转换成二进制字节流的过程反序列化&#xff1a;将在序列化过程中所生成的二进制字节流转换成数据结构或者对象的过程 为什么要进行序列化 我们要将java对象进行网络传输&a…

Grok-1安装

安装 源代码 huggingface git clone https://github.com/xai-org/grok-1.git # 新建虚拟环境 conda create --prefixD:\CondaEnvs\grok1 python3.11conda activate D:\CondaEnvs\grok1 pip install huggingface_hub[hf_transfer] pip install -U "huggingface_hub[cli]&…

#Linux(Source Insight安装及工程建立)

&#xff08;一&#xff09;发行版&#xff1a;Ubuntu16.04.7 &#xff08;二&#xff09;记录&#xff1a; &#xff08;1&#xff09;安装教程&#xff1a; Source insight 工具安装及使用方法-CSDN博客https://blog.csdn.net/YAOHAIPI/article/details/125191451&#xff…

浅谈前端路由原理hash和history

1、认识前端路由 本质 前端路由的本质&#xff0c;是监听 url 地址或 hash 值的改变&#xff0c;来切换渲染对应的页面组件 前端路由分为两种模式 hash 模式 history 模式 两种模式的对比 2、hash 模式 &#xff08;1&#xff09;hash 定义 hash 模式是一种把前端路由的路…

SpringCloud之网关组件Gateway学习

SpringCloud之网关组件Gateway学习 GateWay简介 Spring Cloud Gateway是Spring Cloud的⼀个全新项目&#xff0c;目标是取代Netflix Zuul&#xff0c;它基于Spring5.0SpringBoot2.0WebFlux&#xff08;基于高性能的Reactor模式响应式通信框架Netty&#xff0c;异步⾮阻塞模型…

Wireshark TS | DNS 案例分析之外的思考

前言 承接之前一篇《Packet Challenge 之 DNS 案例分析》&#xff0c;在数据包跟踪文件 dnsing.pcapng 中&#xff0c;关于第 4 题&#xff08;What is the largest DNS response time seen in this trace file? &#xff09;的分析过程中曾经碰到一个小问题&#xff0c;主要…