(1)关闭蜂鸣器、继电器等无关外设;
(2)设备初始化时钟为23时59分50秒,闹钟提醒时间0时0分0秒。
(1)时间显示格式
(2)温度显示格式
(1)按键S7定义为“时钟设置按键”,通过该按键可切换选择待调整的时、分、秒,当前选择的显示单元以1秒为间隔亮灭,时、分、秒的调整需注意数据的边界属性。
(2)按键S6定义为“闹钟设置”按键,通过该按键可进入闹钟时间设置功能,数码管显示当前设置的闹钟时间。
(3)按键S5定义为“加”按键,在“时钟设置”或“闹钟设置”状态下,每次按下当前选择的单元(时、分或秒)增加1个单位。
(4)按键S4定义为“减”按键,在“时钟设置”或“闹钟设置”状态下,每次按下当前选择的单元(时、分或秒)减少1个单位。
(5)按键功能说明:
按键S4、S5的“加”、“减”功能只在“时钟设置”或“闹钟设置”状态下有效;
在“时钟显示”状态下,按下S4按键,显示温度数据,松下按键,返回“时钟显示”界面。
(1)指示灯L1以0.2秒为间隔闪烁,持续5秒钟;
(2)闹钟提示状态,按下任意按键,关闭闪烁提示功能。
在所有的分析开始之前,先来说说本设计所用的底层芯片,分别是DS1302和DS18B20,看看两者的用法。
(1)自己懒得总结,找了篇好文章。。。 ==》DS1302总结
(2)关于DS1302是否为SPI接口还是IIC接口 ==》接口方式
(3)初始化时间
关于DS18B20,又找了几篇总结文章。。。
==》DS18B20基本操作
==》DS18B20进阶操作
==》DS18B20详细原理
(1)关于通过S7按键可切换选择待调整的时、分、秒,当前选择的显示单元以1秒为间隔亮灭,时、分、秒的调整需注意数据的边界属性
运用标志位,就可以让按键具有设置时分秒的功能。
由于当初始化时间设置完成后,时间就会1秒1秒地走,以秒为依据,将秒除以2,如果能整除,就显示时、分或秒;如果不能整除,就让数码管熄灭。这样看起来,当前选择的单元以1秒为间隔亮灭。
(2)关于通过S6按键设置闹钟
与设置时钟类似,这里要特别注意一下标志位的设置。
(3)关于S5按键“加”,S4按键“减”
首先要注意这个问题,就是在时间设置上,准备两个数组,一个数组用来初始化时间,一个数组用来设置时间。
以加为例,要注意时间设置的边界值,另外,当时间设置好后,注意初始化。
(4)在“时钟显示”状态下,按下S4按键,显示温度数据,松下按键,返回“时钟显示”界面。
这句话该怎么理解呢,这里涉及到一个长按键的思想。
从代码可知,长按键的思想就是先设置一个阈值,也就是 timestr[ ] 里面设置的1000,然后再设置一个因按键而改变的变量,也就是这里的 keydowntime[ ], 当按键按下后,keydowntime[ ] 一次增加200,如果 keydowntime[ ] 里面的数值没有超过设置的阈值1000,那么就执行按键的动作;如果 keydowntime[ ] 里面的数值超过设置的阈值1000,那么从超过阈值那刻开始,按键的动作照样执行,阈值也开始增加,但是阈值增加速度远远小于设置的变量的增加速度,这样,因按键产生的动作也会一直执行。
(5)细节问题
DS1302输出数据为十六进制,要转化为十进制。
用上文来记叙当时刚进实验室考核所做的实物-电子钟,以及19年参加蓝桥杯所准备的题目-电子钟。
下面附加上蓝桥杯整个源代码:
#include "system.h"
#include "seg.h"
#include "key.h"
#include "ds18b20.h"
#include "ds1302.h"
extern u8 yi,er,san,si,wu,liu,qi,ba,time[7],set=0;
extern bit clock_set=0;
extern bit clock_show=1; //时钟显示标志位
extern bit alarm_show=0; //闹钟显示标志位
extern u8 alarm_set=0; //闹钟设置时分秒标志位
u8 alarm[7]; //闹钟设置
bit led1=0; //提示闹钟的时间到了
bit led_shanshuo=0; //led闪烁
bit led_flag=0; //限制指示灯持续5秒后的其他动作
bit wendu_flag=0; //温度读取标志位
bit wendu_show=0; //温度显示标志位
u8 temperature;
void Timer0Init(void) //2毫秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x9A; //设置定时初值
TH0 = 0xA9; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
EA=1;
ET0=1;
}
void main()
{
All_Init();
Timer0Init();
Ds1302_Init();
while(1)
{
ledshow();
keydriver();
readtime();
if(wendu_flag==1)
{
wendu_flag=0;
temperature=temperature_change();
}
if(time[2]==alarm[2] && time[1]==alarm[1] && time[0]==alarm[0])
{
if(led_flag==0) //该标志位的作用是放置闹钟过了5秒之后还有其他的动作
{
led1=1;
}
}
if(clock_show==1 && wendu_show==0)
{
if(clock_set==0)
{
yi=time[2]/10;er=time[2]%10;san=10;
si=time[1]/10;wu=time[1]%10;liu=10;
qi=time[0]/10;ba=time[0]%10;
}
else if(clock_set==1)
{
if(set==0)
{
if(time[0]%2 == 0)
{
yi=time[2]/10;er=time[2]%10;san=10;
si=time[1]/10;wu=time[1]%10;liu=10;
qi=time[0]/10;ba=time[0]%10;
}
else if(time[0]%2 != 0)
{
yi=11;er=11;san=10;
si=time[1]/10;wu=time[1]%10;liu=10;
qi=time[0]/10;ba=time[0]%10;
}
}
else if(set==1)
{
if(time[0]%2 == 0)
{
yi=time[2]/10;er=time[2]%10;san=10;
si=time[1]/10;wu=time[1]%10;liu=10;
qi=time[0]/10;ba=time[0]%10;
}
else if(time[0]%2 != 0)
{
yi=time[2]/10;er=time[2]%10;san=10;
si=11;wu=11;liu=10;
qi=time[0]/10;ba=time[0]%10;
}
}
else if(set==2)
{
if(time[0]%2 == 0)
{
yi=time[2]/10;er=time[2]%10;san=10;
si=time[1]/10;wu=time[1]%10;liu=10;
qi=time[0]/10;ba=time[0]%10;
}
else if(time[0]%2 != 0)
{
yi=time[2]/10;er=time[2]%10;san=10;
si=time[1]/10;wu=time[1]%10;liu=10;
qi=11;ba=11;
}
}
}
}
else if(alarm_show==1 && wendu_show==0)
{
if(alarm_set==1)
{
if(time[0]%2 == 0)
{
yi=alarm[2]/10;er=alarm[2]%10;san=10;
si=alarm[1]/10;wu=alarm[1]%10;liu=10;
qi=alarm[0]/10;ba=alarm[0]%10;
}
else if(time[0]%2 != 0)
{
yi=11;er=11;san=10;
si=alarm[1]/10;wu=alarm[1]%10;liu=10;
qi=alarm[0]/10;ba=alarm[0]%10;
}
}
else if(alarm_set==2)
{
if(time[0]%2 == 0)
{
yi=alarm[2]/10;er=alarm[2]%10;san=10;
si=alarm[1]/10;wu=alarm[1]%10;liu=10;
qi=alarm[0]/10;ba=alarm[0]%10;
}
else if(time[0]%2 != 0)
{
yi=alarm[2]/10;er=alarm[2]%10;san=10;
si=11;wu=11;liu=10;
qi=alarm[0]/10;ba=alarm[0]%10;
}
}
else if(alarm_set==3)
{
if(time[0]%2 == 0)
{
yi=alarm[2]/10;er=alarm[2]%10;san=10;
si=alarm[1]/10;wu=alarm[1]%10;liu=10;
qi=alarm[0]/10;ba=alarm[0]%10;
}
else if(time[0]%2 != 0)
{
yi=alarm[2]/10;er=alarm[2]%10;san=10;
si=alarm[1]/10;wu=alarm[1]%10;liu=10;
qi=11;ba=11;
}
}
}
else if(wendu_show==1)
{
yi=11;er=11;san=11;si=11;wu=11;
liu=temperature/10;qi=temperature%10;ba=12;
}
}
}
void Timer0() interrupt 1
{
static u16 led1_count=0,lednum_count=0;
static wendu_count=0;
wendu_count++;
if(wendu_count==100)
{
wendu_count=0;
wendu_flag=1;
}
else if(led1==1)
{
led1_count++;
lednum_count++;
if(led1_count==100)
{
led1_count=0;
if(led_shanshuo==0)
{
led_shanshuo=1;
P2=(P2&0x1f)|0x80;
P0=0xfe;
P2&=0x1f;
}
else if(led_shanshuo==1)
{
led_shanshuo=0;
P2=(P2&0x1f)|0x80;
P0=0xff;
P2&=0x1f;
}
if(lednum_count==2500)
{
lednum_count=0;
led_flag=1;
led1=0;
P2=(P2&0x1f)|0x80;
P0=0xff;
P2&=0x1f;
}
}
}
ledscan();
keyscan();
}
#include"system.h"
void All_Init()
{
P2=(P2&0x1f)|0xa0; //关闭继电器、蜂鸣器
P0=0x00;
P2=(P2&0x1f)|0xe0; //关闭数码管
P0=0xff;
P2=(P2&0x1f)|0x80; //关闭LED灯
P0=0xff;
P2&=0x1f;
}
#include "seg.h"
u8 yi,er,san,si,wu,liu,qi,ba;
u8 code ledchar[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0xff,0xc6}; //0-9,-,灭,C
u8 ledbuff[]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
void ledscan()
{
static u8 index=0;
P2=(P2&0x1f)|0xe0;
P0=0xff;
P2=(P2&0x1f)|0xc0;
P0=0x01<
#include "key.h"
#include "ds1302.h"
extern u8 yi,er,san,si,wu,liu,qi,ba;
extern bit clock_set; //时钟设置标志位
extern bit clock_show; //时钟显示标志位
extern bit alarm_show; //闹钟显示标志位
extern bit led1; //提示闹钟的时间到了
extern bit led_flag; //限制指示灯持续5秒后的其他动作
extern bit wendu_show;
extern u8 set; //时钟设置时分秒标志位
extern u8 alarm_set; //闹钟设置时分秒标志位
extern u8 time[7],time_init[7]; //时钟设置的初始值以及设置值
extern u8 alarm[7]; //闹钟设置
u8 keysta[4]={1,1,1,1};
u8 keycodemap[4]={1,2,3,4};
u8 keydowntime[]={0,0,0,0};
void keydriver()
{
u8 i;
static u8 backup[]={1,1,1,1};
static u8 timestr[]={1000,1000,1000,1000};
for(i=0;i<4;i++)
{
if(keysta[i]!=backup[i])
{
if(backup[i] != 0)
{
keyaction(keycodemap[i]);
}
backup[i]=keysta[i];
}
else if(keydowntime[i]>timestr[i])
{
if(i==3)
{
keyaction(keycodemap[i]);
timestr[i] += 4;
}
}
}
}
void keyscan()
{
u8 i;
static u8 keybuff[]={0xff,0xff,0xff,0xff};
keybuff[0]=(keybuff[0]<<1)|S7;
keybuff[1]=(keybuff[1]<<1)|S6;
keybuff[2]=(keybuff[2]<<1)|S5;
keybuff[3]=(keybuff[3]<<1)|S4;
for(i=0;i<4;i++)
{
if(keybuff[i]==0xff)
{
keysta[i]=1;
keydowntime[i]=0;
if(i==3)
{
wendu_show=0;
}
}
else if(keybuff[i]==0x00)
{
keysta[i]=0;
keydowntime[i] += 200;
}
else
{}
}
}
void keyaction(u8 keycode)
{
if(keycode==1)
{
if(led1==1) //闹钟时间到了
{
led1=0;
led_flag=1;
P2=(P2&0x1f)|0x80;
P0=0xff;
P2&=0x1f;
}
else if(clock_show==1)
{
if(clock_set==0) //如果在非时钟设置界面,切换到时钟设置界面
{
clock_set=1;
}
else if(clock_set==1)
{
if(set==0) //当前在设置小时,按一下设置分钟
{
set=1;
}
else if(set==1) //当前在设置分钟,按一下设置秒
{
set=2;
}
else if(set==2) //当前设置秒,按一下设置完成,且标志位指向设置小时
{
set=0;
clock_set=0;
}
}
}
}
if(keycode==2)
{
if(led1==1) //闹钟时间到了
{
led1=0;
led_flag=1;
P2=(P2&0x1f)|0x80;
P0=0xff;
P2&=0x1f;
}
else if(clock_set==0) //如果在非时钟设置界面
{
clock_show=0; //时钟不显示
alarm_show=1; //闹钟显示
if(alarm_set==0)
{
alarm_set=1;
}
else if(alarm_set==1)
{
alarm_set=2;
}
else if(alarm_set==2)
{
alarm_set=3;
}
else if(alarm_set==3)
{
alarm_set=0;
clock_show=1;
alarm_show=0;
}
}
}
if(keycode==3)
{
if(led1==1) //闹钟时间到了
{
led1=0;
led_flag=1;
P2=(P2&0x1f)|0x80;
P0=0xff;
P2&=0x1f;
}
else if(clock_show==1) //在时钟显示界面
{
if(clock_set == 1)
{
if(set == 0)
{
time[2]++;
if(time[2] == 24)
{
time[2]=23;
}
time_init[2]=time[2];
time_init[2]=time[2];
time_init[2]=time[2];
Ds1302_Init();
}
else if(set == 1)
{
time[1]++;
if(time[1] == 60)
{
time[1]=59;
}
time_init[1]=time[1];
time_init[1]=time[1];
time_init[1]=time[1];
Ds1302_Init();
}
else if(set == 2)
{
time[0]++;
if(time[0] == 60)
{
time[2] = 59;
}
time_init[0]=time[0];
time_init[0]=time[0];
time_init[0]=time[0];
Ds1302_Init();
}
}
}
else if(alarm_show==1) //在闹钟显示界面
{
if(alarm_set==1)
{
alarm[2]++;
if(alarm[2]==24)
{
alarm[2]=23;
}
}
else if(alarm_set==2)
{
alarm[1]++;
if(alarm[1]==60)
{
alarm[1]=59;
}
}
else if(alarm_set==3)
{
alarm[0]++;
if(alarm[0]==60)
{
alarm[2]=59;
}
}
}
}
if(keycode == 4)
{
if(led1==1) //闹钟时间到了
{
led1=0;
led_flag=1;
P2=(P2&0x1f)|0x80;
P0=0xff;
P2&=0x1f;
}
if(clock_set==0 && alarm_set==0)
{
wendu_show=1;
}
else if(clock_show==1)
{
if(clock_set == 1)
{
if(set == 0)
{
if(time[2] > 0)
{
time[2]--;
}
time_init[2]=time[2];
time_init[2]=time[2];
time_init[2]=time[2];
Ds1302_Init();
}
else if(set == 1)
{
if(time[1] > 0)
{
time[1]--;
}
time_init[1]=time[1];
time_init[1]=time[1];
time_init[1]=time[1];
Ds1302_Init();
}
else if(set == 2)
{
if(time[0] > 0)
{
time[0]--;
}
time_init[0]=time[0];
time_init[0]=time[0];
time_init[0]=time[0];
Ds1302_Init();
}
}
}
else if(alarm_show==1)
{
if(alarm_set == 1)
{
if(alarm[2] > 0)
{
alarm[2]--;
}
}
else if(alarm_set == 2)
{
if(alarm[1] > 0)
{
alarm[1]--;
}
}
else if(alarm_set == 3)
{
if(alarm[0] > 0)
{
alarm[0]--;
}
}
}
}
}
#include "ds1302.h"
u8 time_init[]={50,59,23,20,3,2,18}; //秒,分钟,小时,日,月,星期,年
u8 time[7];
void Ds1302_Writebyte(u8 dat)
{
u8 i;
for(i=0;i<8;i++)
{
SCLK=0;
SDA=dat&0x01;
SCLK=1;
dat>>=1;
}
}
void Ds1302_Write(u8 add,u8 dat)
{
CE=0;
SCLK=0;
CE=1;
Ds1302_Writebyte(add);
dat=((dat/10)<<4)|(dat%10); //把十进制数转化为二进制,将其写入
Ds1302_Writebyte(dat);
}
u8 Ds1302_Read(u8 add)
{
u8 i,dat,dat1,dat2;
CE=0;
SCLK=0;
CE=1;
Ds1302_Writebyte(add);
for(i=0;i<8;i++)
{
SCLK=0;
dat>>=1; //dat从高位开始读起
if(SDA)
{
dat|=0x80;
}
SCLK=1;
}
SDA=0;
dat1=dat/16;
dat2=dat%16;
dat=dat1*10+dat2;
return dat;
}
void Ds1302_Init()
{
u8 i,add=0x80;
Ds1302_Write(0x8e,0x00); //关闭写保护
for(i=0;i<7;i++)
{
Ds1302_Write(add,time_init[i]);
add+=2;
}
Ds1302_Write(0x8e,0x80);
}
void readtime()
{
u8 i,add=0x81;
Ds1302_Write(0x8e,0x00);
for(i=0;i<7;i++)
{
time[i]=Ds1302_Read(add);
add+=2;
}
Ds1302_Write(0x8e,0x00);
}
#include "ds18b20.h"
void Delay100us() //@11.0592MHz
{
unsigned char i, j;
_nop_();
_nop_();
i = 2;
j = 15;
do
{
while (--j);
} while (--i);
}
void Delay500us() //@11.0592MHz
{
unsigned char i, j;
_nop_();
_nop_();
i = 6;
j = 93;
do
{
while (--j);
} while (--i);
}
void Ds18b20_Init()
{
DQ=0;
Delay500us();
DQ=1;
Delay500us();
}
void Ds18b20_Write(u8 dat)
{
u8 i;
for(i=0;i<8;i++)
{
DQ=0;
DQ=dat&0x01;
Delay100us();
dat>>=1;
DQ=1;
}
}
u8 Ds18b20_Read()
{
u8 i,dat;
for(i=0;i<8;i++)
{
DQ=0;
dat>>=1;
DQ=1;
if(DQ==1)
{
dat=dat|0x80;
}
Delay100us();
}
return dat;
}
u8 temperature_change()
{
u8 high,lower,temp;
Ds18b20_Init();
Ds18b20_Write(0xcc); //允许总线控制器不用提供64位ROM编码就使用储存器操作命令,
//在单点总线情况下可以节约时间。
Ds18b20_Write(0x44); //启动一次温度转换而无需其他数据
Ds18b20_Init();
Ds18b20_Write(0xcc);
Ds18b20_Write(0xbe); //读取暂存器的内容
lower=Ds18b20_Read();
high=Ds18b20_read();
temp=(high<<4)|(lower>>4);
return temp;
}
#ifndef __SYSTEM_H
#define __SYSTEM_H
#include
#include
typedef unsigned int u16;
typedef unsigned char u8;
void All_Init();
#endif
#ifndef __SEG_H
#define __SEG_H
#include "system.h"
void ledscan();
void ledshow();
#endif
#ifndef __KEY_H
#define __KEY_H
#include "system.h"
sbit S7=P3^0;
sbit S6=P3^1;
sbit S5=P3^2;
sbit S4=P3^3;
void keydriver();
void keyscan();
void keyaction(u8 keycode);
#endif
#ifndef __DS1302_H
#define __DS1302_H
#include "system.h"
sbit SCLK=P1^7;
sbit SDA=P2^3;
sbit CE=P1^3;
void Ds1302_Writebyte(u8 dat);
void Ds1302_Write(u8 add,u8 dat);
u8 Ds1302_Read(u8 add);
void Ds1302_Init();
void readtime();
#endif
#ifndef __DS18B20_H
#define __DS18B20_H
#include "system.h"
sbit DQ=P1^4;
void Delay100us();
void Delay500us();
void Ds18b20_Init();
void Ds18b20_Write(u8 dat);
u8 Ds18b20_read();
u8 temperature_change();
#endif