一、原理图
采用2个4位共阳数码管,由 74HC537控制段码,74HC595控制位码
二、代码
#include <reg52.h>
#include <intrins.h>
typedef unsigned int u16; //对系统默认数据类型进行重定义
typedef unsigned char u8;
sbit SRCLK = P2 ^ 3;
sbit LATCH = P2 ^ 2; //位锁存
sbit SER = P2 ^ 1;
#define DataPort P0 //定义数据端口 程序中遇到DataPort 则用P0 替换
sbit LATCH1 = P2 ^ 0; // 段锁存
//定义独立按键控制脚
sbit KEY1 = P3 ^ 1;
sbit KEY2 = P3 ^ 0;
sbit KEY3 = P3 ^ 2;
sbit KEY4 = P3 ^ 3;
//使用宏定义独立按键按下的键值
#define KEY1_PRESS 1
#define KEY2_PRESS 2
#define KEY3_PRESS 3
#define KEY4_PRESS 4
#define KEY_UNPRESS 0
u8 gmsec = 0; // ms级定义
u8 gsec = 0; //秒定义
u8 gmin = 0; //分定义
u8 ghour = 0; //时定义
unsigned char code MIN_DuanMa[] = {0xbf, 0x86, 0xdb, 0xcf, 0xE6, 0xED, 0xFd, 0x87, 0xFF, 0XEF};
unsigned char code dofly_DuanMa[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e};
// 显示段码值0---F
unsigned char code dofly_WeiMa[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
//分别对应相应的数码管点亮,即位码
void delay_10us(u16 ten_us)
{
while (ten_us--);
}
void delay_ms(u16 ms)
{
u16 i, j;
for (i = ms; i > 0; i--)
for (j = 110; j > 0; j--);
}
void Out595(void)
{
LATCH = 0;
_nop_();
LATCH = 1;
}
void SendByte(unsigned char dat) //位码发送
{
unsigned char i;
for (i = 0; i < 8; i++)
{
SRCLK = 0;
SER = dat & 0x80;
dat <<= 1;
SRCLK = 1;
}
}
void smg_display(u8 dat[], u8 pos)
{
u8 i = 0;
u8 pos_temp = pos - 1;
for (i = pos_temp; i < 8; i++)
{
switch (i) //位选
{
case 0:
SendByte(dofly_WeiMa[i]);
Out595();
break;
case 1:
SendByte(dofly_WeiMa[i]);
Out595();
break;
case 2:
SendByte(dofly_WeiMa[i]);
Out595();
break;
case 3:
SendByte(dofly_WeiMa[i]);
Out595();
break;
case 4:
SendByte(dofly_WeiMa[i]);
Out595();
break;
case 5:
SendByte(dofly_WeiMa[i]);
Out595();
break;
case 6:
SendByte(dofly_WeiMa[i]);
Out595();
break;
case 7:
SendByte(dofly_WeiMa[i]);
Out595();
break;
}
DataPort = dofly_DuanMa[dat[i]]; //取显示数据,段码
delay_10us(100); //延时一段时间,等待显示稳定
DataPort = 0XFF; //消音
}
}
u8 key_scan(u8 mode)
{
static u8 key = 1;
if (mode)
key = 1; //连续扫描按键
if (key == 1 && (KEY1 == 0 || KEY2 == 0 || KEY3 == 0 || KEY4 == 0)) //任意按键按下
{
delay_10us(1000); //消抖
key = 0;
if (KEY1 == 0)
return KEY1_PRESS;
else if (KEY2 == 0)
return KEY2_PRESS;
else if (KEY3 == 0)
return KEY3_PRESS;
else if (KEY4 == 0)
return KEY4_PRESS;
}
else if (KEY1 == 1 && KEY2 == 1 && KEY3 == 1 && KEY4 == 1) //无按键按下
{
key = 1;
}
return KEY_UNPRESS;
}
void time0_init(void)
{
TMOD |= 0X01; //选择为定时器0模式,工作方式1
TH0 = 0XDC; //给定时器赋初值,定时10ms
TL0 = 0X00;
ET0 = 1; //打开定时器0中断允许
EA = 1; //打开总中断
TR0 = 0; //关闭定时器
}
void time0_start(void)
{
TR0 = 1; //打开定时器
}
void time0_stop(void)
{
TR0 = 0; //关闭定时器
TH0 = 0X00;
TL0 = 0X00;
}
u8 key = 0;
u8 time_buf[8];
u8 time_flag = 0;
void task()
{
key = key_scan(0);
if (key == KEY1_PRESS) //开始和停止计时
{
time_flag = !time_flag;
}
else if (key == KEY2_PRESS) //清除计时
{
time0_stop();
time_flag = 0;
gmin = 0;
gsec = 0;
gmsec = 0;
ghour = 0;
}
else if (key == KEY3_PRESS)
gmin++;
else if (key == KEY4_PRESS)
ghour++;
if (time_flag)
time0_start(); //开始计时
else
time0_stop(); //停止计时
time_buf[1] = ghour / 10;
time_buf[0] = ghour % 10; //时
time_buf[3] = gmin / 10;
time_buf[2] = gmin % 10; //分
time_buf[5] = gsec / 10;
time_buf[4] = gsec % 10; //秒
time_buf[7] = gmsec / 10;
time_buf[6] = gmsec % 10; //毫秒
smg_display(time_buf, 1); //显示
}
void main()
{
time0_init();
while (1)
{
task();
}
}
void time0() interrupt 1 //定时器0中断函数
{
TH0 = 0XDC; //给定时器赋初值,定时10ms
TL0 = 0X00;
gmsec++; // 10ms加1次
if (gmsec == 100) //定时1秒
{
gmsec = 0;
gsec++; //对秒计数
if (gsec == 60) //到达60秒,即1分钟
{
gsec = 0;
gmin++; //对分计数
if (gmin == 60)
{
gmin = 0;
ghour++; //对时计数
if (ghour == 60)
ghour = 0;
}
}
}
}