从单片机基础到程序框架(全集 2019pdf版).pdf - 第607页

应该成双成 对的出现 (这样 关断响应更 及时, 并且 结构更紧 凑, 漏洞 更少) , 比如, 凡是总启动 Gu8RunSt art 发生改变的 时候,总运行 步骤 Gu8Ru nStep 都复位归零 一下。 (4)一 个硬 件的定 时器 中断 ,可 以衍生 出 N 个 软件 定时器 ,之 前跟 大家 介绍的 是 “递减 式” 的软 件定 时器 ,而且 实际 应用中 , “递 减式” 的软 件定时 器也 是用得 最多 。本 节因为 项…

100%1 / 836
第一百一十五节: 按键控制数码管的秒表。
【115.1 按键控制数码管的秒表。
上图 115.1.1 数码管
上图 115.1.2 独立按键
本节通过一个秒表的小项目,让大家学会以下 4 个知识点:
(1)上层的界面显示框架几乎都要用到更新变量,更新变量包括整屏更新和局部更新,本节只用到
屏更新。更新变量是用全局变量在函数之间传递信息。作用是,当有某个需要显示的数据发生改变的时候,
就要给更新变量置 1,让显示函数重新更新一次显示,确保最新的数据能及时显示出来,平时没有数据更
改变的时候不用频繁更新显示避免占用 CPU 过多的时间
(2)凡是需要显示数字的地方,都必须涉及如何把一个数据按“个十百千万...”的位逐个提取出来
算法。这个算法比较简单,主要“求余“求商”这两个运算语句就可以随心所欲的把数据位提取出来。
除此之外,还要学会如何用 if 语句判断数据的范围,来把高位尚未用到的某个数码管屏蔽,让该位数码
只显示一个“不显示”的数据(避免直接显示一 0)
(3)我常把单片机程序简化 4 个代表:按键(人机输入数码(人机界面)跑马灯(应用程序)
串口(通信)。本节的“应用程序”不是跑马灯,而是秒表。不管是跑马灯,还是秒表,都要用到一个总启
Gu8RunStart 一个运行步骤 Gu8RunStep。建议家,总启 Gu8RunStart 和总运行 Gu8RunStep
应该成双成对的出现(这样关断响应更及时,并且结构更紧凑,漏洞更少)比如,凡是总启动 Gu8RunStart
发生改变的时候,总运行步骤 Gu8RunStep 都复位归零一下。
(4)一个硬件的定时器中断,可以衍生 N 软件定时器,之前跟大家介绍的“递减式”的软件定
时器,而且实际应用中“递减式”的软件定时器也是用得最多。本节因为项目的需要,需要用到的是“累
加式”的软件定时器。不管是哪种软件定时器,大家都要注意定时器变量在定义时所用到的数据类型这个
数据类型决定了定时时间的长度,比如在 51 单片机中,unsigned int 范围 0 65535,最大一次性定
65.535 秒。 unsigned long 的范围是 0 4294967295,最大一次性定 4294967.295 秒。本节秒表的
时间超过 65.535 秒,因此需要用到 unsigned long 类型的定时器变量
本节秒表程序的功能:K1 键是复位按键,每按一次,秒表都停止并且重新归零。K2 键是启动和
停按键,当秒表处于复位后停止的状态时按一次则开始启动当秒表处于正在工作的状态时按一次则处于暂
停状态,当秒表处于暂停的状态时按一次则继续处于工作的状态本节 4 位数码管,显示的时间是带 2 位小
数点的,能显示的时间范围是:0.00 秒到 99.99 秒。代码如下:
#include "REG52.H"
#define KEY_FILTER_TIME 25
#define SCAN_TIME 1
void T0_time();
void SystemInitial(void) ;
void Delay(unsigned long u32DelayTime) ;
void PeripheralInitial(void) ;
void KeyScan(void);
void KeyTask(void);
void DisplayScan(void); //底层显示的驱动函数
void DisplayTask(void); //上层显示的任务函数
void RunTask(void); //秒表的应用程序
sbit KEY_INPUT1=P2^2;
sbit KEY_INPUT2=P2^1;
sbit P1_0=P1^0;
sbit P1_1=P1^1;
sbit P1_2=P1^2;
sbit P1_3=P1^3;
//数码管转换
code unsigned char Cu8DigTable[]=
{
0x3f, //0 序号 0
0x06, //1 序号 1
0x5b, //2 序号 2
0x4f, //3 序号 3
0x66, //4 序号 4
0x6d, //5 序号 5
0x7d, //6 序号 6
0x07, //7 序号 7
0x7f, //8 序号 8
0x6f, //9 序号 9
0x00, //不显 序号 10
};
//数码管底层驱动扫描的软件定时器
volatile unsigned char vGu8ScanTimerFlag=0;
volatile unsigned int vGu16ScanTimerCnt=0;
//秒表的软件定时器,注意,这里是 unsigned long 类型,范围是 0 4294967295 毫秒
volatile unsigned char vGu8StopWatchTimerFlag=0;
volatile unsigned long vGu32StopWatchTimerCnt=0;
//数码管上层 10ms 就定时刷新一次显示的软件定时器。用于及时更新显示秒表当前的实时数
volatile unsigned char vGu8UpdateTimerFlag=0;
volatile unsigned int vGu16UpdateTimerCnt=0;
unsigned char Gu8RunStart=0; //应用程序的总启动
unsigned char Gu8RunStep=0; //应用程序的总运行步骤。建议跟 vGu8RunStart 成双成对出
unsigned char Gu8RunStatus=0; //当前秒表的状态。0 代表停止,1 代表正在工作中,2 代表暂停
unsigned char Gu8WdUpdate=1; //开机默认整屏更新一次显示。此变量在显示框架中是非常重要的变
volatile unsigned char vGu8Display_Righ_4=10; //开机默认最高位数码管显示一个“不显示”数据
volatile unsigned char vGu8Display_Righ_3=0;
volatile unsigned char vGu8Display_Righ_2=0;
volatile unsigned char vGu8Display_Righ_1=0;
volatile unsigned char vGu8Display_Righ_Dot_4=0;
volatile unsigned char vGu8Display_Righ_Dot_3=1; //开机默认保留显示 2 个小数点
volatile unsigned char vGu8Display_Righ_Dot_2=0;
volatile unsigned char vGu8Display_Righ_Dot_1=0;
volatile unsigned char vGu8KeySec=0;
void main()