利用 8051 单片机设计秒表,包括 3 个按键、3 位数码管。按键分别用于启动、暂停、
显示学号,显示温度,时间用数码管显示。开始后显示学号后 3 位。按启动键下后,显示 0.00 以 0.01
秒的频率从 0.00 递增,期间按暂停键时暂停,再次按暂停继续递增,当递增到 9.99 以后循
环。按显示学号键,显示学号。
1、电路仿真:

2、程序设计:
(1)项目结构:

(2)主函数:
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
#include<display.c>
#include<key.c>
#include<DS18B20.C>
unsigned int cp;
void display(void);
void key(void);
/*Timer0中断服务函数*/
void timer0_isr(void) interrupt 1
{
TH0=(65535-2000)/256; //重装初值
TL0=(65535-2000)%256; //重装初值
cp++; //2000代表2ms,1000ms=1s
if(mode == 2)cp=0;//按下暂停按键后,mode为2
else{
if(cp>=5) //0.01s到了
{
cp=0;
xiaoshu++;
}
if(xiaoshu>=50) //1s到了
{
xiaoshu=0;
sec++; //秒+1
flash=~flash;
get_ds18b20();
if((a & 0x80) == 0x80)
{
t_x = 0xff - a;
b = (0x0f - b)*0.625;
}
else {t_x = a;b = b*0.625;}
}
if(sec>=10) sec=0; //10S到了
}
P0=0xff;
display(); //调用display函数
}
/*******timer0初始化函数********/
void timer0_init(void)
{
TMOD=0x01; //T0工作方式1
TH0=(65535-2000)/256; //对机器脉冲计数2000个积满溢出引发中断
TL0=(65535-2000)%256;
EA=1; //开总中断
ET0=1; //开T0中断
TR0=1; //启动定时器
}
/******主函数********/
void main()
{
timer0_init(); //调用timer0_init 中断函数
while(1)
{
key(); //调用按键函数
}
}
(3)显示函数:
采用的是动态显示方式(段选、位选),运用switch case 结构来实现数码管的显示,与按键结合,不同的mode值显示不同的数字。
#include <reg52.h>
unsigned char i,j,xuehao = 113,xiaoshu = 0,sec = 0,flash,mode;
unsigned char t_x,a,b;
unsigned char code seven_seg[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
void display(void)
{
if(mode == 0)//mode初始化默认为零,显示学号
{
switch(i)
{
case 0:P0 = seven_seg[xuehao%10];P1 = 0x04;break;//个位
case 1:P0 = seven_seg[xuehao/10%10];P1 = 0x02;break;//十位
case 2:P0 = seven_seg[xuehao/100];P1 = 0x01;break;//百
}
i++;
if(i>=3)i = 0;
}
if(mode == 1)
{
switch(j)
{
case 0:P0 = seven_seg[xiaoshu%10];P1 = 0x04;break;
case 1:P0 = seven_seg[xiaoshu/10];P1 = 0x02;break;
case 2:P0 = seven_seg[sec]&(0x7F | flash);P1 = 0x01;break;
}
j++;
if(j>=3)j = 0;
}
if(mode == 2)
{
switch(j)
{
case 0:P0 = seven_seg[xiaoshu%10];P1 = 0x04;break;
case 1:P0 = seven_seg[xiaoshu/10];P1 = 0x02;break;
case 2:P0 = seven_seg[sec]&(0x7F | flash);P1 = 0x01;break;
}
j++;
if(j>=3)j = 0;
}
if(mode == 3)
{
switch(j)
{
case 0:P0 = seven_seg[b];P1 = 0x08;break;
case 1:P0 = seven_seg[t_x % 10]& 0x7f;P1 = 0x04;break;
case 2:P0 = seven_seg[t_x / 10];P1 = 0x02;break;
case 3:P1 = 0x01;if((a & 0x80) == 0x80)P0 = 0xbf;
else P0 = 0xff;break;
}
j++;
if(j>=4)j = 0;
}
}
(4)按键:
采用按键按下有效的方式,都标志位mode的值进行修改。
#include <reg52.h>
sbit key1 = P2^3; //启动
sbit key2 = P2^4;//暂停
sbit key3 = P2^5;//显示学号
sbit key4 = P2^6;//显示WENDU
unsigned char mode;
void delay(unsigned int x)//delay函数实现短暂的延时(不精确,通过程序的执行次数累积出延时的时间)
{
while(x--);
}
void key(void)//采用按键按下有效的方式
{
if(key1 == 0) //启动键(如果按键按下)
{
delay(400); //消抖
if(key1 == 0)//消抖后,如果确定按键真的按下了
{
mode=1;
}
while(key1 == 0);//再按,不起作用,一直执行while
}
if(key2 == 0) //暂停键
{
delay(400); //消抖
if(key2 == 0)
{
mode = 2;
}
while(key2 == 0);//再按,不起作用
}
if(key3 == 0) //显示学号
{
delay(400); //消抖
if(key3 == 0)
{
mode = 0;
}
while(key3 == 0);//再按,不起作用
}
if(key4 == 0) //显示温度
{
delay(400); //消抖
if(key4 == 0)
{
mode = 3;
}
while(key3 == 0);//再按,不起作用
}
}
(5)ds18b20驱动程序:
uchar a,b;
sbit DQ = P3^7;
void ds18b20_init(void)
{
uchar x = 255;
DQ = 1;
DQ = 0;
delay(80);
DQ = 1;
delay(5);
while(DQ && x--);
delay(20);
DQ = 1;
}
uchar read_onechar(void)
{
uchar i,j;
for(i = 0;i < 8;i++)
{
DQ = 0;
delay(1);
DQ = 1;
j = j>>1;
if(DQ == 1)j = j | 0x80;
delay(5);
DQ = 1;
}
DQ = 1;
return(j);
}
void write_onechar(uchar x)
{
uchar i;
for(i = 0;i < 8;i++)
{
DQ = 0;
DQ = (bit)(x & 0x01);
x = x >> 1;
delay(10);
DQ = 1;
}
DQ = 1;
}
void get_ds18b20(void)
{
uchar i;
ds18b20_init();
write_onechar(0xcc);
write_onechar(0x44);
ds18b20_init();
write_onechar(0xcc);
write_onechar(0xbe);
a = read_onechar();
b = a & 0x0f;
i = read_onechar();
a = (i << 4) | (a >> 4);
}
来源:https://www.cnblogs.com/zhai1997/p/12128009.html