/**
****************************************************************************************
*file : main.c
*author : xr
*date : 2014年4月15日10:08:26- 2014年4月15日12:40:51
*version: V1.2.3
*brief : Stopwatch数码管显示-实用秒表 单片机STC89C52RC MCU 晶振 11.0592MHZ
****************************************************************************************
*/
#include
//74HC138
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
//矩阵按键
sbit KEY_IN_1 = P2^4;//列
sbit KEY_IN_2 = P2^5;
sbit KEY_IN_3 = P2^6;
sbit KEY_IN_4 = P2^7;
//数码管编码
unsigned char code LedTable[] = {
0xC0, //"0"
0xF9, //"1"
0xA4, //"2"
0xB0, //"3"
0x99, //"4"
0x92, //"5"
0x82, //"6"
0xF8, //"7"
0x80, //"8"
0x90, //"9"
0x88, //"A"
0x83, //"B"
0xC6, //"C"
0xA1, //"D"
0x86, //"E"
0x8E //"F"
};
//数码管显示缓冲区
unsigned char LedBuff[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
bit flag10ms = 0;//10ms标志位
bit stopwatchRunning = 0;//秒表启动和停止标志
unsigned char thr0, tlr0;//T0重载值的高低字节
unsigned char decimal = 0;//小数位
unsigned int integer = 0;//整数位
static unsigned char volatile KeySta[4] = {1, 1, 1, 1}; //保存按键的当前值(static 保存在静态存储区,加上volatile关键字使KeySta[i]的值每次都从静态存储区读取,避免读取错误!)
/****************function definition**********************/
void Initial();
void ConfigTimer0(unsigned long xms);
void StopwatchDisplay();
void KeyAction();
/*主程序main()*/
void main(void)
{
Initial();
ConfigTimer0(1);//定时1ms
while (1)
{
KeyAction(); //检测按键动作
if (flag10ms) //10ms检测秒表的运行状态,当stopwatchRunning标志=1时进行计时++,否则就停止计时
{
flag10ms = 0;
if (stopwatchRunning) //10ms刷新秒表计数
{
decimal++;
if (decimal >= 100)
{
decimal = 0;
integer++;
if (integer >= 10000)
{
integer = 0;
}
}
StopwatchDisplay();//分解decimal和integer,存入LedBuff数码管缓冲区
}
}
}
}
/*程序初始化*/
void Initial()
{
ADDR3 = 1;
ENLED = 0;//选择数码管
P2 = 0xFE;//选择第四行按键检测(原理图上是第四列)
P0 = 0xFF;//默认关闭段选
LedBuff[0] = LedTable[decimal % 10]; //初始显示0.00
LedBuff[1] = LedTable[decimal / 10 % 10];
LedBuff[2] = LedTable[integer % 10];
LedBuff[2] &= 0x7F;//点亮小数点
}
/*配置定时器T0*/
void ConfigTimer0(unsigned long xms)
{
unsigned long tmp;//32bit 注意:此处必须用unsigned long 数据,因为11059200已经超出了16位unsigned int
tmp = 11059200/12;//单片机的机器周期频率
tmp = (tmp * xms) / 1000;//定时xms所需的频率
tmp = 65536-tmp;//定时xms的初始装载值
tmp += 18;//补偿值
thr0 = (unsigned char)(tmp >> 8);
tlr0 = (unsigned char)tmp;
TMOD &= 0xF0;//清零T0控制位
TMOD |= 0x01;//配置T0工作在方式1,16位可设定定时器
TH0 = thr0;
TL0 = tlr0;
TR0 = 1;
ET0 = 1;
EA = 1;
}
/*数码管刷新*/
void LedCharRefresh()
{
static unsigned char j = 0;
P0 = 0xFF;//消隐
P1 = (P1 & 0xF8) | j;//先清零P1口低三位,再|j
P0 = LedBuff[j++];
if (j > 5)
j = 0;
}
/*分解decimal和integer,存入LedBuff数码管缓冲区*/
void StopwatchDisplay()
{
signed char i = 0;
unsigned char buf[6];
buf[0] = decimal % 10;
buf[1] = decimal / 10 % 10;
buf[2] = integer % 10;
buf[3] = integer / 10 % 10;
buf[4] = integer / 100 % 10;
buf[5] = integer / 1000 % 10;
for (i = 5; i >= 3; i--) //去掉无效位
{
if (buf[i] == 0)
buf[i] = 0xFF;
else
break;
}
//处理有效位
for (; i >=0; i--)
{
buf[i] = LedTable[buf[i]]; //转为实际的数字
}
//拷贝
for (i = 0; i <= 5; i++)
{
LedBuff[i] = buf[i];//拷贝到显示缓冲区
}
LedBuff[2] &= 0x7F;//点亮小数点
}
/*秒表启动和停止*/
void StopwatchAction()
{
if (stopwatchRunning) //当前状态为运行
{
stopwatchRunning = 0; //停止运行
}
else
{
stopwatchRunning = 1; //启动
}
}
/*秒表复位*/
void StopwatchReset()
{
stopwatchRunning = 0;//停止秒表计时
decimal = 0;
integer = 0;//清零
StopwatchDisplay();//显示
}
/*按键动作*/
void KeyAction()
{
static unsigned char keybackup[4] = {1, 1, 1, 1};//按键的备份值(前一次按键值) 必须是静态的
unsigned char i = 0;
for (i = 0; i < 4; i++)
{
if (keybackup[i] != KeySta[i]) //按键的上一次的状态和当前状态不相同,即按键有动作
{
if (keybackup[i] != 0) //如果上一次按键的值是1,则此时按键是按下动作
{
switch (i)
{
case 1: StopwatchReset(); break; //ESC键秒表复位
case 2: StopwatchAction(); break;//Enter键控制秒表的启动和停止
default: break;
}
}
keybackup[i] = KeySta[i];//备份当前按键值
}
}
}
/*按键扫描函数*/
void KeyScan()
{
static unsigned char KeyBuf[4] = {0xFF, 0xFF, 0xFF, 0xFF}; //按键扫描缓冲区
unsigned char i = 0;
//检测一行按键的状态并存入按键检测缓冲区中
KeyBuf[0] = (KeyBuf[0] << 1) | KEY_IN_1;
KeyBuf[1] = (KeyBuf[1] << 1) | KEY_IN_2;
KeyBuf[2] = (KeyBuf[2] << 1) | KEY_IN_3;
KeyBuf[3] = (KeyBuf[3] << 1) | KEY_IN_4;
//更新消抖后按键的值(1ms检测一次,8ms检测)
for (i = 0; i < 4; i++)
{
if ((KeyBuf[i] & 0xFF) == 0x00)
KeySta[i] = 0;//8次检测按键状态都是0,即按键稳定按下
else if ((KeyBuf[i] & 0xFF) == 0xFF)
KeySta[i] = 1;//8次检测按键的状态都是1,即按键稳定弹起
}
}
/*定时器Timer0中断服务*/
void Timer0_ISP() interrupt 1
{
static unsigned char counter = 0;//计数器
TH0 = thr0;
TL0 = tlr0;//重新装载定时器初值
counter++;
LedCharRefresh();//数码管刷新
KeyScan(); //按键扫描
if (counter >= 10)
{
counter = 0;
flag10ms = 1;
}
}