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

void Syste mInitial( void) { P0=0x00; P1_0=1; P1_1=1; P1_2=1; P1_3=1; TMOD=0x01; TH0=0xfd; //此参 数可根据具体 的时间来修改 ,尽量 确保每定时中 断一次接近 1 ms TL0=0x40; //此参 数可根据具体 的时间来修改 ,尽量 确保每定时中 断一次接近 1 ms EA=1; ET0=1; TR0=1; //上电初始化 一些关键的数 据 …

100%1 / 836
P3_4=0;
}
void BeepClose(void)
{
P3_4=1;
}
void T0_time() interrupt 1
{
VoiceScan(); //蜂鸣器的驱动函数
KeyScan(); //按键底层的驱动扫描函数
DisplayScan(); //数码管底层的驱动扫描函数
if(1==vGu8ScanTimerFlag&&vGu16ScanTimerCnt>0)
{
vGu16ScanTimerCnt--; //递减式的软件定时器
}
if(1==vGu8BlinkTimerFlag&&vGu16BlinkTimerCnt>0) //数码管闪烁跳动的定时器
{
vGu16BlinkTimerCnt--; //递减式的软件定时器
}
//在正常工作的窗口下,每 500ms 就定时更新一次显示的软件定时
if(1==vGu8UpdateTimerFlag&&vGu16UpdateTimerCnt>0)
{
vGu16UpdateTimerCnt--; //递减式的软件定时器
}
//时钟实际走的时间的软件定时器,注意,这里是递增式的软件定时
if(1==vGu8ClockTimerFlag)
{
vGu32ClockTimerCnt++; //递增式的软件定时
if(vGu32ClockTimerCnt>=86400000) //86400000 毫秒代表 24
{
vGu32ClockTimerCnt=0;
}
}
TH0=0xfd; //此参数可根据具体的时间来修改,尽量确保每定时中断一次接近 1ms
TL0=0x40; //此参数可根据具体的时间来修改,尽量确保每定时中断一次接近 1ms
}
void SystemInitial(void)
{
P0=0x00;
P1_0=1;
P1_1=1;
P1_2=1;
P1_3=1;
TMOD=0x01;
TH0=0xfd; //此参数可根据具体的时间来修改,尽量确保每定时中断一次接近 1ms
TL0=0x40; //此参数可根据具体的时间来修改,尽量确保每定时中断一次接近 1ms
EA=1;
ET0=1;
TR0=1;
//上电初始化一些关键的数
Gu8Wd=1; //窗口 1。开机默认处于正常工作的窗口
Gu8WdUpdate=1; //整屏更新变量
vGu8ClockTimerFlag=0;
vGu32ClockTimerCnt=43200000; //43200000 毫秒开机默认 12:00 点。12 时就 43200000 毫秒
vGu8ClockTimerFlag=1; //启动时钟的定时器
//时钟正常工作的时候,每 500ms 更新显示一次
vGu16UpdateTimerCnt=500;
vGu8UpdateTimerFlag=1; //启动小数点闪烁的定时器
}
void Delay(unsigned long u32DelayTime)
{
for(;u32DelayTime>0;u32DelayTime--);
}
void PeripheralInitial(void)
{
}
第一百二十三节: 一种能省去一个 lock 自锁变量的按键驱动程序。
【123.1 一种能省去一个 lock 自锁变量的按键驱动程序。
一位群友给我提到了一个按键的改进建议,能巧妙的省去一个 lock 自锁变量。这个建议引起了我对“变
量的分工要专一,一个变量尽量只用在一类事物上,尽量不取巧兼容”的思考。
第一种:带 lock 自锁变量,也是我一直在用的代码。
if(0!=KEY_INPUT1)//IO 是高电平,说明按键没有被按下,这时要及时清零一些标志
{
Su8KeyLock1=0; //按键解锁
Su16KeyCnt1=0; //按键去抖动延时计数器清零,此行非常巧妙,是全场的亮点。
}
else if(0==Su8KeyLock1)//有按键按下且是第一次被按下。这行如果有疑问请看 92 节的专题分析
{
Su16KeyCnt1++; //累加定时中断次数
if(Su16KeyCnt1>=KEY_FILTER_TIME) //滤波的“稳定时间”KEY_FILTER_TIME,长度 25ms。
{
Su8KeyLock1=1; //按键的自锁,避免一直触发
vGu8KeySec=1; //触发 1 号键
}
}
第二种:省略掉一个 lock 自锁变量,群友提出的改进建议
if(0!=KEY_INPUT1)
{
Su16KeyCnt1=0;
}
else if(Su16KeyCnt1<KEY_FILTER_TIME) //巧妙的利用了 Su16KeyCnt1 等于滤波时间时,只执行一次
{
Su16KeyCnt1++;
if(KEY_FILTER_TIME==Su16KeyCnt1) //巧妙的利用 Su16KeyCnt1 等于滤波时间时,只执行一次
{
vGu8KeySec=1;
}
}
分析:
不得不佩服群友的智慧第二种改进后看起来非常巧妙,犹如蜻蜓点水般轻盈洒脱。但是,为此代码狂
欢片刻后,我又有了新的思考和看法。“计时器 Su16KeyCnt1”自锁变量 Su8KeyLock1”是两个不同的事
物,是两个不同的范畴就应该用两个不同的变量进行区分如果逞一时之巧把两种不同范畴的事物巧妙
合并成一个变量,势必会导致程序的“易读性”后续维护的可扩展性”大打折扣。“自锁变量 Su8KeyLock1”
真的是可有可无吗?假设,如果“计时 Su16KeyCnt1”的消抖时 KEY_FILTER_TIME 求等 0,那么
二种改进后的代码立刻暴露出了问题,行不通。而第一种代码,因为有“自锁变量 Su8KeyLock1”的存在,
即使消抖时间 KEY_FILTER_TIME 等于 0,也不影响代码功能的完整性,因为第一种代码的理念是“自锁与计