目录
实验内容
基于protues8.13、51单片机,使用定时器制作一个秒表,四位显示(00.00)
功能要求:
1、最低显示0.01秒
2、两个显示模式(分-秒,秒-毫秒),用按键随时切换(K2)。
3、一个按键控制开始、暂停、清零(K1)。
protues原理图
与上一个实验一样,数码管连接在P0和P3上,在P1.0\P1.1上连接两个按键(K1为开始、暂停、清零,K2为切换模式)。
Keil代码
不加入按键功能
让它实现简单的秒表功能(即上电就开始计时,不会停止),为了查看分-秒模式显示是否正常,我建立了一个t_flag标志位,开始时t_s<60s,t_flag=0,显示秒-毫秒模式,当t_s>60s,则切换为分-秒模式。
#include<reg51.h>
#define uchar unsigned char
#define uint unsigned int
/***********参数定义**********************************/
uchar t_f = 0;//f
uchar t_s = 0;//s
uchar t_001s = 0;//ms
uint t_flag = 0;
//uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66, //共阴型段码表0~9
// 0x6d,0x7d,0x07,0x7f,0x6f};//让我恶心的共阴数码管段码
//共阳数码管,最后两个段码是-和.
unsigned char code SMG_duanma[18]= //共阳段码0~F - .
{
0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,
0X80,0X90,0X88,0X80,0XC6,0XC0,0X86,0X8E,
0XBF,0X7F
};
/*************函数声名*****************************************/
void delay();
void InitTimer0();//定时器初始化
void Timer0();//定时器中断
void ShowSMG_Bit_No(unsigned char value, unsigned int pos);//无点段选位选
void ShowSMG_Bit(unsigned char value, unsigned int pos);//有点段选位选
void Display_SMG();//数码管显示函数
/****************主函数******************************************************/
void main()
{
InitTimer0();
while(1)
{
Display_SMG();
}
}
void delay() //延时函数
{
uint i;
for(i=0;i<1000;i++);
}
/******************************定时器********************************************/
//====定时器初始化=============================//
void InitTimer0()
{
TMOD = 0X01;
TH0 = (65535 - 10000) /256;//要求最低显示0.01s,即定时器10ms
TL0 = (65535 - 10000) %256;
ET0 = 1;
EA = 1;
TR0 = 1;
}
//====定时器中断=============================//
void Timer0() interrupt 1
{
TH0 = (65535 - 10000) /256;
TL0 = (65535 - 10000) %256;
t_001s++;
if(t_001s == 100)//10ms++100次=1s
{
t_s++;
t_001s = 0;
if(t_s == 60)
{
t_f++;
t_flag=1;
t_s = 0;
}
}
}
/******************************数码管********************************************/
//====数码管位选段选=============================//
void ShowSMG_Bit_No(unsigned char value, unsigned int pos)//无点
{
//共阴数码管,位选接P3为低,段选接P0为高
//数码管位选
P3 = ~(0X01 << pos);//通过移位选位
//数码管段选
P0 = ~(SMG_duanma[value]);
}
void ShowSMG_Bit(unsigned char value, unsigned int pos)//有点
{
//共阴数码管,位选接P3为低,段选接P0为高
//数码管位选
P3 = ~(0X01 << pos);//通过移位选位
//数码管段选
P0 = ~(SMG_duanma[value]&0X7f);
}
//====数码管显示=============================//
void Display_SMG()
{
switch(t_flag)
{
case 0 ://时间在60s以内,模式1,秒-毫秒显示
//ms
ShowSMG_Bit_No(t_001s%10,3);//00.01
delay();
ShowSMG_Bit_No(t_001s/10,2);//00.10
delay();
//S
ShowSMG_Bit(t_s%10,1);//01.00
delay();
ShowSMG_Bit_No(t_s/10,0);//10.00
delay();
break;
case 1 ://当时间超过60s,数码管不够显示,则转为模式2,分-秒显示
//s
ShowSMG_Bit_No(t_s%10,3);//00.01
delay();
ShowSMG_Bit_No(t_s/10,2);//00.10
delay();
//f
ShowSMG_Bit(t_f%10,1);//01.00
delay();
ShowSMG_Bit_No(t_f/10,0);//10.00
delay();
break;
}
}
*注:通过这么多次的实验,我发现共阴数码管的段码是真不好用,不如直接用共阳数码管的段码,然后对其进行取反即可。
分享一个我在使用共阴数码管段码时遇到的个小问题,属于是我自己没注意:
因为平时做的内容不需要用上小数点,所以并没住。以前我用的都是共阳(段码给低电平点亮)的,在加上小数点时,我不喜欢重新写一个带有点的数组,所以会在P0 = SMG_duanma[value];的后面直接与上一个0X7F,即P0 = ~(SMG_duanma[value]&0X7f);。0X7F=0111 1111,假如数字段码是0,0XC0=1100 0000。将他们与上,结果为0100 0000=0X40;这是成功显示(0.)的。
刚开始我想共阴一样,只点亮小数点是0X80,所以我在P0 = table[value]上直接与上0x80,但是发现数码管都不亮了,后面才发现0X80=1000 0000,同样数字段码假如0是0X3F=0011 1111,他们两个与上就变成了,与0=0故最后段码变成0000 0000=0X00,共阴数码管给0是不亮的。
加入按键功能
*注:不将数码管显示调用在while(k1==0)循环中,在按下按键后数码管会闪烁一下(K2同理)。
#include<reg51.h>
#define uchar unsigned char
#define uint unsigned int
#define SB sbit
uchar t_f = 0;//f
uchar t_s = 0;//s
uchar t_001s = 0;//ms
uint K1_flag = 0;
uint K2_flag = 0;
uint mod;
SB K1=P1^0;
SB K2=P1^1;
unsigned char code SMG_duanma[18]= //共阳段码0~F - .
{
0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,
0X80,0X90,0X88,0X80,0XC6,0XC0,0X86,0X8E,
0XBF,0X7F
};
void delay();
void Delay_key();
void InitTimer0();
void Timer0();
void ShowSMG_Bit_No(unsigned char value, unsigned int pos);//无点
void ShowSMG_Bit(unsigned char value, unsigned int pos);//有点
void Display_SMG();
void key_scan();
void main()
{
InitTimer0();
while(1)
{
Display_SMG();
key_scan();
}
}
/******************************延时函数*******************************************************/
void delay() //数码管延时函数
{
uint i;
for(i=0;i<1000;i++);
}
void Delay_key()//按键延时
{
uint t=200;
while(t--);
}
/******************************定时器********************************************/
//====定时器初始化=============================//
void InitTimer0()
{
TMOD = 0X01;
TH0 = (65535 - 10000) /256;//要求最低显示0.01s,即定时器10ms
TL0 = (65535 - 10000) %256;
ET0 = 1;
EA = 1;
TR0 = 0;
}
//====定时器中断=============================//
void Timer0() interrupt 1
{
TH0 = (65535 - 10000) /256;
TL0 = (65535 - 10000) %256;
t_001s++;
if(t_001s == 100)//10ms++100次=1s
{
t_s++;
t_001s = 0;
if(t_s == 60)
{
t_f++;
t_s = 0;
}
}
}
/******************************数码管********************************************/
//====数码管位选段选=============================//
void ShowSMG_Bit_No(unsigned char value, unsigned int pos)//无点
{
//共阴数码管,位选接P3为低,段选接P0为高
//数码管位选
P3 = ~(0X01 << pos);//通过移位选位
//数码管段选
P0 = ~(SMG_duanma[value]);
}
void ShowSMG_Bit(unsigned char value, unsigned int pos)//有点
{
//共阴数码管,位选接P3为低,段选接P0为高
//数码管位选
P3 = ~(0X01 << pos);//通过移位选位
//数码管段选
P0 = ~(SMG_duanma[value]&0X7f);
}
//====数码管显示=============================//
void Display_SMG()
{
switch(mod)
{
case 0 ://时间在60s以内,模式1,秒-毫秒显示
//ms
ShowSMG_Bit_No(t_001s%10,3);//00.01
delay();
ShowSMG_Bit_No(t_001s/10,2);//00.10
delay();
//S
ShowSMG_Bit(t_s%10,1);//01.00
delay();
ShowSMG_Bit_No(t_s/10,0);//10.00
delay();
break;
case 1 ://当时间超过60s,数码管不够显示,则转为模式2,分-秒显示
//s
ShowSMG_Bit_No(t_s%10,3);//00.01
delay();
ShowSMG_Bit_No(t_s/10,2);//00.10
delay();
//f
ShowSMG_Bit(t_f%10,1);//01.00
delay();
ShowSMG_Bit_No(t_f/10,0);//10.00
delay();
break;
}
}
/******************************KEY********************************************/
void key_scan()
{
if(K1== 0)
{
Delay_key();
if(K1==0)
{
K1_flag++;
switch(K1_flag)
{
case 1:TR0=~TR0;break;
case 2:TR0=~TR0;break;
case 3:t_f = 0;//f
t_s = 0;//s
t_001s = 0;//ms
K1_flag=0;break;
}
while(K1==0){Display_SMG();}
}
}
if(K2==0)
{
Delay_key();
if(K2==0&&K2_flag==0)
{
K2_flag=1;
mod=K2_flag;
}
else if(K2==0&&K2_flag==1)
{
K2_flag=0;
mod=K2_flag;
}
while(K2==0){Display_SMG();}
}
}