1、应网友要求做了个秒表。
2、定期器采用10毫秒,数码管后2位显示的是毫秒,故100毫秒进1秒,100毫秒*定时器10毫秒故就是1秒。
3、使用3个独立按键,按键2表示启动秒表,按键3表示暂停秒表,按键4表示清除秒表且暂停秒表。
4、已在我的清翔51开发板上实现,表现良好(只是按键的时候数码管会灭,这个我就不解了,需要用定时器做按键判断。)
main.c
#include "Time.h"
#include "key.h"
#include <reg52.h>
#include "dt.h"
void main(void)
{
unsigned char dt_state=1;//数码管标志位
Timer0_16bit(10);//配置初始化定时器0为10毫秒
convert_data(9999,4);//初始化数码管
while(1)
{
if(dt_state)//主程序驱动数码管标志位
{
dt_display(4);//使用主程序驱动数码管
}
switch(key2345())
{
case 2:TR0=1;dt_state=0;break;//启动秒表,且使用定时器驱动数码管
case 3:TR0=0;dt_state=1;break;//暂停秒表,且使用主程序驱动数码管
case 4:TR0=0;TIME=0;convert_data(TIME,4);dt_state=1;break;//清除时间,且暂停计时器,且使用主程序驱动数码管
break;
}
}
}
delay.h
//这是一个延迟函数为毫秒级//
#ifndef __DELAY_H__
#define __DELAY_H__
void delay_ms(unsigned char ms);//最大输入255,ms=1,最小1ms时间
#endif // !__DELAY_H__
delay.c
//软件延迟ms级别
void delay_ms(unsigned char ms) //设置毫秒级别延迟函数,z最大输入65535
{
unsigned char x;
for (; ms > 0; ms--)
for (x = 114; x > 0; x--);
}
key.h
#ifndef __KEY_H__
#define __KEY_H__
#include <reg52.h>
#include "delay.h"
//独立按键
sbit key_S2 = P3^0;
sbit key_S3 = P3^1;
sbit key_S4 = P3^2;
sbit key_S5 = P3^3;
#define key_all P3
//按键占用P3口
unsigned char key2345(void); //函数返回值为2、3、4、5分别对应按键2、按键3、按键4、按键5,本函数只循环一次
#endif // !__KEY_H__
key.c
//独立按键 S2 S3 S4 S5
//分别对应 P30 P31 P32 P33
#include"key.h"
//独立按键使用switch语句
unsigned char key2345(void) //函数返回值为2、3、4、5分别对应按键2、按键3、按键4、按键5,本函数只循环一次
{
key_all |= 0x0f;
if ((key_all&0x0f) != 0x0f) //&运算符没有!=高,故需要加()括号
{
delay_ms(10);
if ((key_all & 0x0f) != 0x0f)
{
switch (key_all & 0x0f)
{
case 0x0e:while ((key_all & 0x0f) != 0x0f);return 2; //while在这里进行松手检测
case 0x0d:while ((key_all & 0x0f) != 0x0f);return 3; //while在这里进行松手检测
case 0x0b:while ((key_all & 0x0f) != 0x0f);return 4; //while在这里进行松手检测
case 0x07:while ((key_all & 0x0f) != 0x0f);return 5; //while在这里进行松手检测
}
}
}
return 0;//没有按键按下时返回0
}
Time.h
#ifndef __TIME_H__
#define __TIME_H__
#include <REG52.h>
extern unsigned int TIME;
//定时器0初始化,并设定ms毫秒且工作方式1,16位模式
void Timer0_16bit(unsigned char time0_16_bit_ms);
#endif // !__TIME_H__
Time.c
#include "Time.h"
#include "dt.h"
static unsigned char H0 = 0, L0 = 0;
unsigned int TIME=0;
//定时器0初始化,设定ms毫秒且工作方式1,16位模式
void Timer0_16bit(unsigned char time0_16_bit_ms)
{
TMOD |= 0x01;
TH0 =(65536 - (unsigned int)(time0_16_bit_ms * 921.6)) / 256;//需将计算的小数转换整形
TL0 =(65536 - (unsigned int)(time0_16_bit_ms * 921.6)) % 256;//需将计算的小数转换整形
H0 = TH0;
L0 = TL0;
EA = 1;//开启总中断
ET0 = 1;//允许定时器0溢出进入中断
TR0 = 0;//先关闭定时器
}
void Timer0Interrupt(void) interrupt 1
{
TH0 = H0;
TL0 = L0;
dt_display(4);//每隔10毫秒刷新一下4个数码管
convert_data(TIME,4);//每隔10毫秒转换一下时间
if(TIME++==9999)//数码管最大显示99.99秒
{
TIME=0;
}
}
dt.h
#ifndef __DT_H__
#define __DT_H__
#include <reg52.h>
#include "delay.h"
sbit wei = P2^7; //锁存器位选
sbit duan = P2^6; //锁存器段选
#define dt_dt P0
//0<=dt_data<=9999,y=4表示4个数码管亮
void convert_data(unsigned int dt_data,unsigned char y);
//y个数码管显示
void dt_display(unsigned char y);
#endif
dt.c
//数码管dt 使用共阴极数码管即位选是阴极时数码管才选中
//使用P0-8个GPIO口
//P2.7位选脚(控制哪个数码管亮)、P2.6段选脚(送数码管值) 控制2个74锁存器
#include "dt.h"
static unsigned char datax[8];//定义局部变量//用来存放小数及正整数,然后发给数码管进行显示低位到高位存放
static code unsigned char dt_duan[26] = //数码管段选真值表 dt_duan[i] + 0x80 数码管显示数据并且此数据的右下角有小数点
{
0x3F, //"0"
0x06, //"1"
0x5B, //"2"
0x4F, //"3"
0x66, //"4"
0x6D, //"5"
0x7D, //"6"
0x07, //"7"
0x7F, //"8"
0x6F, //"9"
0x80, //"."
0x40, //"-"
0x77, //"A"
0x7C, //"B"
0x39, //"C"
0x5E, //"D"
0x79, //"E"
0x71, //"F"
0x76, //"H"
0x38, //"L"
0x37, //"n"
0x3E, //"u"
0x73, //"P"
0x5C, //"o"
0x00, //熄灭
0x00 //自定义
};
static code unsigned char dt_wei[9]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe,0xff};//1位-8位(0x7f表示最右边哪个数码管)0xff数码管就不亮了
static void clear_reset_dt(void)//清除数码管,关闭数码管,初始化数码管
{
dt_dt= dt_wei[8];//清除位码,关闭所有数码管
wei=1;
wei=0;
dt_dt= dt_duan[25];//清除段码,关闭所有数码管显示
duan=1;
duan=0;
dt_dt=0xff;//恢复单片机IO口默认高电平状态
}
void dt_display(unsigned char y)//y表示的是要几个数码管显示取值0~8
{
unsigned char a;
for (a = 0; a < y; a++)//a亮——a值——a值灭;a+1亮——a+1值——a+1值灭;开始循环(亮,真值,假值)
{
dt_dt = dt_wei[a];//灯亮
wei = 1; //打开位选
wei = 0; //锁存位选
dt_dt = datax[a];//数字
duan = 1; //打开段选
duan = 0; //锁存段选
delay_ms(1);//亮的时间,防闪烁
dt_dt = dt_duan[25];//数字熄灭,假值
duan = 1; //打开段选
duan = 0; //锁存段选
}
clear_reset_dt();//清除数码管显示,初始化数码管
}
//将要显示的正整数临时存储在数组里面,然后循环显示数组里的元素即可
//x传递的数据10进制(x不是8位则高位不会亮)
void convert_data(unsigned int dt_data,unsigned char y)//y表示的是要几个数码管显示取值0~8
{
unsigned char i; //数组标号也是段选真值
unsigned char a; //流水号,用来表示数码管1~8个
for (a = 0;a < y;a++) //将x没位的值存放到数组里面
{
i = dt_data % 10;//获取最后一位数字
dt_data = dt_data / 10;//每次舍去最低位
if(a==2)
datax[a] = dt_duan[i]+0x80;//0x80是小数点
else
datax[a] = dt_duan[i];
}
clear_reset_dt();//清除数码管显示
}