作业
用51单片机完成一个数字钟的计时及校时功能。
1、设置8个数码管的显示缓冲区为DISPBUFF[8],并初始化为02,02,-,04,08,-,03,06.
2、定时器0每隔5ms刷新一次数码管显示缓冲区,并显示时间(中断来做)
3、定时器1负责精确定时,计时1s,每隔50ms中断一次,中断20次即为1s
4、用图中两个按键实现时分和小时的校时功能,MODE按键实现小时校准、分校准及正常显示的3个模式切换,ADD按键实现对应时间加一,按键采用外部中断方式实现功能。在校准小时及分钟的时候,对应两位数码管的小数点必须亮,正常模式时所有小数点全灭.
5、秒脉冲由51单片机的定时器来提供。
按要求上交实验报告(校准小时、分钟及正常模式的对应Proteus仿真截图及开发板下载图一定要)。
思路
-
定义一个数码管显示模块,起名为dis_seg7()
-
定时器0每隔5ms刷新一次数码管显示缓冲区,并显示时间(中断来做)
-
定时器1负责精确定时,计时1s,每隔50ms中断一次,中断20次即为1s
-
外部中断0实现模式切换
- 正常显示,stat = 0;
- 校分,stat = 1;
- 校时,stat = 2;
- 注意:校时,校分时要停止定时器T1
-
外部中断1实现hour/min自增
- 先检测一下stat
- stat =1,min_increase
- stat = 2, hour_increase
代码
#include<reg52.h>
//共阳极数码管
unsigned char code segCodeTable[12] = {0xc0,0xf9,0xa4,0xb0,
0x99,0x92,0x82,0xf8,
0x80,0x90,0xbf,0x7f}; //0-9,-,.,
//带小数点的共阳极数码管段码表
unsigned char code segCodeTable1[10] = {0x40,0x79,0x24,0x30,
0x19,0x12,0x02,0x78,
0x00,0x10};//0-9
//位码表
unsigned char code posCodeTable[8] = {
0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};
//数码管显示缓冲区
unsigned char LEDBuffer[8] = {0x82,0xb0,0xbf,0x80,0x99,0xbf,0xa4,0xa4,};
void display_seg7();
void TIMER0_INIT();
void TIMER1_INIT();
void EXT_INTR0_INIT();
void EXT_INTR1_INIT();
unsigned char sec = 36,min = 48,hour = 22;
//定义一个变量,记录状态
unsigned char stat = 0;
void main()
{
//定时器0初始化配置
TIMER0_INIT();
//定时器1初始化配置
TIMER1_INIT();
//外部中断0初始化
EXT_INTR0_INIT();
//外部中断1初始化
EXT_INTR1_INIT();
EA = 1;//开启总中断
while(1);
}
//定时器1初始化配置
void TIMER1_INIT()
{
TMOD = (TMOD & 0x0f) | 0x10;
PT1 = 1;
ET1 = 1;
TH1 = 0x3c;
TL1 = 0xb0;
TR1 = 1;
}
//定时器1负责精确定时,计时1s,每隔50ms中断一次,中断20次即为1s
void TIMER1_INTR() interrupt 3
{
static unsigned char cnt = 0;
TH1 = 0x3c;
TL1 = 0xb0;
cnt++;
if(cnt >= 20)
{
cnt = 0;
sec++;
if(sec == 60)
{
sec = 0;
min++;
if(min == 60)
{
min = 0;
hour++;
if(hour == 24)
{
hour = 0;
}
}
}
}
}
//定时器0初始化配置
void TIMER0_INIT()
{
//定时器0初始化配置
TMOD = (TMOD & 0xf0) | 0x01;
ET0 = 1;//使能定时器0中断
PT0 = 0;//设置中断优先级
TL0 = 0x78; //设置定时初值
TH0 = 0xEC; //设置定时初值
TR0 = 1;
}
//定时器0每隔5ms刷新一次数码管显示缓冲区
void TIMER0_INTR() interrupt 1
{
TL0 = 0x78; //设置定时初值
TH0 = 0xEC; //设置定时初值
if(stat == 0) //正常显示
{
LEDBuffer[0] = segCodeTable[sec%10]; //更新数码管显示缓冲区
LEDBuffer[1] = segCodeTable[sec/10];
LEDBuffer[3] = segCodeTable[min%10];
LEDBuffer[4] = segCodeTable[min/10];
LEDBuffer[6] = segCodeTable[hour%10];
LEDBuffer[7] = segCodeTable[hour/10];
}
else if(stat == 1) //校分
{
LEDBuffer[0] = segCodeTable[sec%10]; //更新数码管显示缓冲区
LEDBuffer[1] = segCodeTable[sec/10];
LEDBuffer[3] = segCodeTable1[min%10];
LEDBuffer[4] = segCodeTable1[min/10];
LEDBuffer[6] = segCodeTable[hour%10];
LEDBuffer[7] = segCodeTable[hour/10];
}
else if(stat == 2) //校时
{
LEDBuffer[0] = segCodeTable[sec%10]; //更新数码管显示缓冲区
LEDBuffer[1] = segCodeTable[sec/10];
LEDBuffer[3] = segCodeTable[min%10];
LEDBuffer[4] = segCodeTable[min/10];
LEDBuffer[6] = segCodeTable1[hour%10];
LEDBuffer[7] = segCodeTable1[hour/10];
}
display_seg7();
}
//数码管显示模块
void display_seg7()
{
unsigned char j = 0,i = 0;
for(i = 0;i<8;i++)
{
P2 = LEDBuffer[i]; //段码
P1 = posCodeTable[i]; //位码
for(j = 0;j<200;j++); //延时
P2 = 0xff; //清除余晖
}
}
//外部中断0初始化
void EXT_INTR0_INIT()
{
EX0 = 1;
PX0 = 1; //设置中断优先级
IT0 = 1; //脉冲下降沿中断
}
//外部中断0
void intr0() interrupt 0
{
stat++;
if(stat == 3) //正常显示
{
stat = 0;
TR1 = 1;//定时器T1开启
}
if(stat == 1)//校分
{
TR1 = 0;//定时器T1停止
}
if(stat == 2)//校时
{
TR1 = 0;//定时器T1停止
}
}
//外部中断1初始化
void EXT_INTR1_INIT()
{
EX1 = 1;
PX1 = 1; //设置中断优先级
IT1 = 1; //脉冲下降沿中断
}
//外部中断1
void intr1() interrupt 2
{
if(stat == 1) //校分
{
min++;
if(min == 60)
{
min = 0;
hour++;
if(hour == 24)
{
hour = 0;
}
}
}
if(stat == 2) //校时
{
hour++;
if(hour == 24)
{
hour = 0;
}
}
}
运行结果
0.初始化
1.正常显示
2.校分
- 先按下按键mode切换模式
- 再按下按键add,实现分加一
3.校时
- 先按下按键mode切换模式
- 再按下按键add,实现时加一