从单片机基础到程序框架(全集 2019pdf版).pdf - 第370页
#include " REG52.H" #define BLIN K_TIME 500 //时间是 500ms sbit P0_0= P0^0; volatile u nsigned c har vGu8Time Flag=0; //互斥 量变量标志 volatile u nsigned i nt vGu16TimeCn t=0; //计时 器变量 unsigned c har Gu8St ep=0; //switc…

vGu8TimeFlag=1; //互斥量 vGu8TimeFlag 的“解锁”。同时也起到“启动计时器”的开关作用
while(1) //主循环
{
if(0==vGu16TimeCnt) //时间变量为 0 则表示时间到了
{
...在这里执行具体的功能代码
}
}
}
void T0_time() interrupt 1 //每 1ms 中断一次的定时中断函数
{
if(1==vGu8TimeFlag&&vGu16TimeCnt>0) //判断 vGu8TimeFlag 是否等于 1,就是互斥量的判断。
{
vGu16TimeCnt--; //“自减一”的操作
}
}
分析:上述代码中,vGu8TimeFlag 是一箭双雕,既起到互斥量的作用,也起到了计数器 vGu16TimeCnt
开始计时的启动开关作用。
【86.3 练习例程。】
现在根据上述程序框架,编写一个 LED 灯闪烁的程序。
图 86.3.1 灌入式驱动 8 个 LED

#include "REG52.H"
#define BLINK_TIME 500 //时间是 500ms
sbit P0_0=P0^0;
volatile unsigned char vGu8TimeFlag=0; //互斥量变量标志
volatile unsigned int vGu16TimeCnt=0; //计时器变量
unsigned char Gu8Step=0; //switch 的切换步骤
void main()
{
TMOD=0x01; //设置定时器 0 为工作方式 1
TH0=0xfc; //产生 1ms 中断的 TH0 初始值
TL0=0x66; //产生 1ms 中断的 TL0 初始值
EA=1; //开总中断
ET0=1; //允许定时 0 的中断
TR0=1; //启动定时 0 的中断
while(1) //主循环
{
switch(Gu8Step)
{
case 0:
if(0==vGu16TimeCnt) //时间到
{
P0_0=0; //LED 灯亮
vGu8TimeFlag=0; //互斥量“加锁”
vGu16TimeCnt=BLINK_TIME; //计时器的写操作。设定计时的长度
vGu8TimeFlag=1; //互斥量“解锁”,同时蕴含了计时器“启动”的动作
Gu8Step=1; //切换到 case 1 这个步骤
}
break;
case 1:
if(0==vGu16TimeCnt) //时间到
{
P0_0=1; //LED 灯灭。
vGu8TimeFlag=0; //互斥量“加锁”
vGu16TimeCnt=BLINK_TIME; //计时器的写操作。设定计时的长度
vGu8TimeFlag=1; //互斥量“解锁”,同时蕴含了计时器“启动”的动作

Gu8Step=0; //切换到 case 0 这个步骤,依次循环
}
break;
}
}
}
void T0_time() interrupt 1 //定时器 0 的中断函数,每 1ms 单片机自动执行一次此函数
{
if(1==vGu8TimeFlag&&vGu16TimeCnt>0) //判断 vGu8TimeFlag 是否等于 1,就是互斥量的判断
{
vGu16TimeCnt--; //“自减一”的操作
}
TH0=0xfc; //重装初值,不能忘
TL0=0x66; //重装初值,不能忘
}
【86.4 解决闪烁出现不规则“非对称感”现象的方法。】
上述例子,实验现象应该是 LED 闪烁很有规则的每 1s 闪烁一次,但是也有一部分初学者可能会遇到闪
烁出现不规则“非对称感”的现象,这个问题的解决办法如下:在 keil2 的 project 下拉菜单下,选择 Options
for Target 选项,弹出的窗口中,切换到 Target 选项,在 Memory Model 选项中选择 small:variables in Data。
图 86.4.1 设置窗口