摘要 本设计是以89c51单片机作为控制核心的闹铃系统。本文大致可以分三个章节,第一章讲用单片机制作电子闹钟带来的优势,还有电子闹钟在未来的电子产品中的趋势以及本次设计所要实现的课题目标。第二章讲一些设计思路和硬件组成。第三讲程序代码,最后结论,体会,附录图。
关键词 pc机,单片机,串行通讯,LCD1602显示。
电了闹钟是一种应用非常广泛的日常计时工具,数字显示的日历钟已经越来越流行,特别是适合在家庭居室、办公室、大厅、会议室、车站和广场等使用,壁挂式LED数码管显示的日历钟逐渐受到人们的欢迎。单片机电了闹钟是集电子技术、数字显示技术为一体的高产品,具有按时闹铃,显示清晰直观、走时准确等优点。首先介绍设计电子闹钟所涉及的主要硬件和特性,然后说明软件设计的思路,程序结构及流程,并在测试软件上进行调试和修改,以完成电子闹钟的基本要求,即可以随意设定起始时间,有秒显示功能,有2/24时制选择,可以设定闹钟,停电时由电池供电等功能。现代社会电了闹钟发挥着很大的作用,也是它存在和发展的一个重要方面,尤其是在代表集成电路技术的发展方面,通过不断提高电子闹钟的计时的精确度可以极大促进定时技术芯片的发展。同时电了闹钟与其他嵌入式电子产品一样是微处理器的应用,通过电子闹钟的设计可以很好的掌握电子设计技术
AT89C51简介
AT89C51是一个低功耗,高性能CMOS8位单片机,片内含4kBytes ISP(In-systemprogrammable)的可反复擦写1佣0次的Flash只读程序存储器,器件采用ATMEL公同的高密度、非易失性存储技术制造,兼容标准MCS-51指令系统及80C51引脚结构,芯片内集成了通用8位中央处理器和ISPFlash存储单元,功能强大的微型计算机的AT89C51可为许多嵌入式控制应用系统提供高性价比的解决方案。
引脚介绍
AT89C51具有如下特点:40个引脚,4kBytesFlash片内程序存储器,128bytes的随机存取数据存储器(RAM),32个外部双向输入/输出囗,5个中断优先级2层中断嵌套中断,2个16位可编程定时计数器,2个全双工串行通信口,看门狗(WDT)电路,片内时钟振荡器。
此外,AT89C51设计和配置了振荡频率可为OHz并可通过软件设置省电模式。空闲模式下,CPU暂停工作,血RAM定时计数器,串行凵,外中断系统可继续工作,掉电模式冻结振荡器血保存RAM的数据,停止芯片其它功能直至外中断激活或硬件复位。同时该芯片还具有PDIP、TQFP和PLCC等三种封装形式,以适应不同产品的需求。
主要功能特性:
·兼容MCS-51指令系统
·32个双向1/0囗
·2个16位可编程定时/计数器
·全双工CART串行中断口线
·2个外部中断源
·中断唤醒省电模式
·看门狗(WDT)电路
·灵活的ISP字节和分页编程
·4k可反复擦写01000次)ISPFlashROM
·4.5一5.5V工作电压时钟频率0-33MHz
·128x8bit内部RAM
·低功耗空闲和省电模式
·3级加密位
·软件设置空闲和省电功能
·双数据寄存器指针
设计一个电子闹钟
1) 能随意设定走时起始时间
2) 能指示秒节奏,即秒指示
3) 能通过pc机远程控制
4) 可设闹钟7组(可继续增加)
5) 可以设置重复/不重复(和手机闹钟设置一样)
6) 显示实时温度
7) 可选音乐5首(可继续增加)
1 时间设置
1)ds1302的调试
2)ds18b20的调试
3)ds1302与ds18b20的组合调试
4)/key1: 选择设置位置/
/******key2: 加 ******/
/******key3: 减 ******/
/******key4: 退出设置 ******/
2 闹钟设置
1) 建立一个数组储存闹钟alarm[7][5];
alarm[x][0] 分钟设置,
alarm[x][1] 小时设置,
alarm[x][2] 开关闹钟,
alarm[x][3] 重复/不重复,
alarm[x][4] 选择音乐
2) 建立一个数组储存闹钟重复/不重复repeat[7][7];
repeat[x][0] 星期一 1重复 0不重复
repeat[x][1] 星期二 1重复 0不重复
repeat[x][2] 星期三 1重复 0不重复
repeat[x][3] 星期四 1重复 0不重复
repeat[x][4] 星期五 1重复 0不重复
repeat[x][5] 星期六 1重复 0不重复
repeat[x][6] 星期日 1重复 0不重复
3) 建立一个数组储存闹钟暂停功能stop[7];
stop[x] 1不暂停 0暂停
总体硬件组成
基本功能
系统具有时间,日期,7路闹钟功能,并可以对时间日期,闹钟进行设定,闹钟有5首音乐可选择,显示格式为:
时间:“时”(第1、2位)、“分”(第3、4位)、“秒”(第5、6位),am/pm(第7位)
日期:“年”(第1、2,3,4位,如2007年)、“月”(第5、6位)、“日”(第7、8位),“周”(第9位)
扩展功能
该系统可以增加温度传感器,实现温度测量,以实时显示温度,用2位显示。
可增加湿度传感器,实现湿度测量,以实时显示湿度,用3位显示。
/****** 主界面显示 /
/2018年01月01日 P 星期五/
/12:01:01 温度:20C 闹钟开关/
/ 主界面按键功能 ******/
/******key1: 进入设置 ******/
/******key2: 加 ******/
/******key3: 减 ******/
/******key4: 打开闹钟 ******/
/****** 功能选择 ******/
/******1:timeSet ******/
/******2: alarmSet /
/ 按键功能 ******/
/******key1: 进入设置 ******/
/******key2: 加 ******/
/******key3: 减 ******/
/******key4: 退出设置 /
/ 时间设置 ******/
/key1: 选择设置位置/
/******key2: 加 ******/
/******key3: 减 ******/
/******key4: 退出设置 /
/ 闹钟设置 /
/ +:增加,-:删除 ******/
/******key1: 确定选择 ******/
/******key2: 选择设置位置加1 ******/
/******key3: 选择设置位置减1 ******/
/******key4: 退出设置 /
/ 闹钟x ******/
/******key1: 选择设置 (时间,开关,重复/不重复,选择音乐)******/
/******key2: 加1 ******/
/******key3: 减一 ******/
/******key4: 退出设置 /
/ 重复/不重复 ******/
/******key2: 重复 ******/
/******key3: 不重复 ******/
/****** 重复 ******/
/key1:选择设置位置/
/******key2: 开启重复 ******/
/******key3: 关闭重复 ******/
/******key4: 退出设置 /
/ 不重复 ******/
/key1:选择设置位置/
/******key2: 开启 ******/
/******key3: 关闭 ******/
/******key4: 退出设置 ******/
时钟电路
实验板的时钟振荡源电路如图2.4所示。其中JT为庄0592MHz的晶振,
改变两电容CB的值即可对此晶振频率进行调节。该电路提供单片机工作所需的
振荡频率,计算定时器初值即需此晶振频率,在通信时也需知道晶振频率,以
对波特率进行计算。
复位电路
如图2.5所示为实验板的复位电路,当RESET信号为低电平时,实验板为
工作状态,当RESET信号为高电平时,实验板为复位或下载程序状态。由于
AT89S52貝有ISP的功能,即可以通过并口线直接将程序下载到单片机内,因
此,AT89S52具有两种状态,下载程序状态和运行状态。该复位电路能实现上
电自动复位,也能手动复位,一般复位时RESET应保持20毫秒以上高电平,此
复位时间由接地电容控制。
键盘电路
key1:P1.4
key2:P1.5
key3:P1.6
key4:P1.7
LCD1602显示电路
数据分配
TIME[7]:秒分时日月周年
alarm[x][0] 分钟设置,
alarm[x][1] 小时设置,
alarm[x][2] 开关闹钟,
alarm[x][3] 重复/不重复,
alarm[x][4] 选择音乐
repeat[x][0] 星期一 1重复 0不重复
repeat[x][1] 星期二 1重复 0不重复
repeat[x][2] 星期三 1重复 0不重复
repeat[x][3] 星期四 1重复 0不重复
repeat[x][4] 星期五 1重复 0不重复
repeat[x][5] 星期六 1重复 0不重复
repeat[x][6] 星期日 1重复 0不重复
stop[x] 1不暂停 0暂停
时钟程序设计步骤
实现方式
该时钟程序的功能模块先后实现的顺序为.
主程序一时间模块一显示模块一键盘模块一时间设定及其显示模块一日期及其显示模块一日期设定及其显示模块—闹钟设定及其显示模块—闹钟重复设定及其显示模块
每完成一个模块就与前一个已完成的模块结合起来调试,直至实现相应功能,再编写下一模块程序.在与主程序衔接时,主程序和各子程序也需作相应的改动,以便与子程序更好的衔接,特别是显示子程序需作较大改动,以便对不同内容进行显示。
源程序
sys.h
#ifndef __SYS_H
#define __SYS_H
#include "reg51.h"
#include "intrins.h"
#ifndef uchar
#define uchar unsigned char
#endif
#ifndef uint
#define uint unsigned int
#endif
#ifndef ulong
#define ulong unsigned long
#endif
#endif
main.c
#include "sys.h"
#include "delay.h"
#include "lcd1602.h"
#include "temp.h"
#include "ds1302.h"
#include "keyProcess.h"
#include "otherProcess.h"
#include "musicCode.h"
#define RldTmr(fr) 65536 - (11059200 / 12) / (fr << 1)
#define FuDian(n) (n << 1) / 3 //附点n分音符的换算
sbit beep = P2^0;
uchar Temp_TH0,Temp_TL0;
uchar Temp_TH1,Temp_TL1;
uchar tmrFlg=0,enable = 1;
extern uint mflag; //音符计算
extern bit nflag;
extern bit aflag; //闹钟开关
extern uchar a;
extern uchar b;
void PlayMusic(uchar *Sound,uchar *lengthlen,uint speed); //固定标准为4分音符的速度:例如speed = 108 表示一分钟扫过108个4分音符
void sound_Init();
uint length(uchar *Sound); //判断音符个数
uint mflag; //音符循环个数
bit nflag=0; //1分钟关闭闹钟暂停标志
bit aflag=1; //总开关
uchar stop[5]; //暂停标志位
uchar a; //闹钟x
uchar b; //重复检测
void main()
{
uchar mode;
stop[0]=1; //暂停标志位
stop[1]=1;
stop[2]=1;
stop[3]=1;
stop[4]=1;
Clock=0; //初始闹钟个数
LCD1602_Init(); //1602初始化
DS1302_Init(); //1302初始化
sound_Init(); //定时器初始化
while(1)
{
/**********按键处理***********/
if(key_scan()==K1||key_scan()==K2||key_scan()==K3||key_scan()==K4)
{
switch (key_scan())
{
case K1: mode=MODE0;break; //MODE0进入菜单
case K2: mode=MODE1;break; //MODE0设置日期
case K3: mode=MODE2;break; //MODE0设置闹钟
case K4: mode=MODE3;aflag=!aflag;break; //MODE3退出
}
key_process(mode); //按键处理函数
}
/**********主屏幕显示**********/
LCD1602_DisplayTemp(DS18B20_ReadTemp()); //温度
DS1302_ReadTime(); //读时间
LCD1602_DisplayData(); //显示时间
if(AM_PM==0&&hour12_24==1) //显示上午
{
LCD1602_WriteCom(0x80+13);
LCD1602_WriteData('A');
}
if(AM_PM==1&&hour12_24==1) //显示下午
{
LCD1602_WriteCom(0x80+13);
LCD1602_WriteData('P');
} //24小时制
if(hour12_24==0)
{
LCD1602_WriteCom(0x80+13);
LCD1602_WriteData(' ');
}
LCD1602_WriteCom(0xc0+15); //显示闹钟开关
if(aflag)
LCD1602_WriteData('N');
else
LCD1602_WriteData('F');
/**********闹钟设置**********/
if(aflag==1)
{
for(a=0;a<=Clock;a++) //检测闹钟
{
if(alarm[a][2]==1) //判断闹钟是否开启
{
if(alarm[a][3]==1) //判断是否重复 alarm[a][3]==1为重复
{
for(b=0;b<7;b++) //判断周是否重复
{
if(TIME[5]==b+1&&repeat[a][b]==1) // repeat[a][0] 重复天数星期一到星期日
{
if((alarm[a][0]==TIME[1]&&alarm[a][1]==TIME[2])) //alarm[0][0]=分钟 alarm[0][1]=小时
{
nflag=1;
switch(alarm[a][4])
{
case 0: PlayMusic(musicNote5,noteDuration5,108); break;
case 1: PlayMusic(musicNote1,noteDuration1,108); break;
case 2: PlayMusic(musicNote2,noteDuration2,108); break;
case 3: PlayMusic(musicNote3,noteDuration3,108); break;
case 4: PlayMusic(musicNote4,noteDuration4,108); break;
}
}
else
stop[a]=1;
}
}
}
else
{
for(b=0;b<7;b++)
{
if(TIME[5]==b+1&&repeat[a][b]==1) // repeat[a][0] 重复天数星期一到星期日
{
if((alarm[a][0]==TIME[1]&&alarm[a][1]==TIME[2])) //alarm[0][0]=分钟 alarm[0][1]=小时
{
switch(alarm[a][4])
{
case 0: PlayMusic(musicNote5,noteDuration5,108); break;
case 1: PlayMusic(musicNote1,noteDuration1,108); break;
case 2: PlayMusic(musicNote2,noteDuration2,108); break;
case 3: PlayMusic(musicNote3,noteDuration3,108); break;
case 4: PlayMusic(musicNote4,noteDuration4,108); break;
}
}
else
stop[a]=1;
}
}
}
}
}
}
else
{
beep=1;TR0=0;
}
LCD1602_WriteCom(0xc0+15);
if(stop[a]==1)
{
LCD1602_WriteData('1');
}
else
LCD1602_WriteData('0');
delay_ms(10);
}
}
/********音乐代码*********/
void sound_Init()
{
Temp_TH1 = (65535-1000)/256; // 计算TL1应装入的初值 (1ms的初装值)
Temp_TL1 = (65535-1000)%256; // 计算TH1应装入的初值
beep=1;
EA=1;
TMOD|=0x11;
TH1=Temp_TH1;
TL1=Temp_TL1;
TH0=0xff;
TL0=0x00;
ET0=1;
ET1=0;
TR0=0;
TR1=0;
}
uint length(uchar *Sound)
{
uint SoundLength=0;
while(Sound[SoundLength] != 0) //计算歌曲长度
{
SoundLength+=1;
}
return SoundLength;
}
void PlayMusic(uchar *Sound,uchar *music,uint speed) {
uint i;
uchar idx;
uint Tone,Temp_T,durationCnt=0,soundCnt=0,NO_soundCnt=0,cnt=0;
TR0 = 1;
TR1 = 1;
Tone=length( Sound);
mflag=0;
if((alarm[a][0]==TIME[1]&&alarm[a][1]==TIME[2]))
nflag=1;
else
{
nflag=0;
if(alarm[a][3]==0)
repeat[a][b]=0;
}
while(mflag!=Tone&&nflag==1&&stop[a]==1)
{
if((alarm[a][0]==TIME[1]&&alarm[a][1]==TIME[2]))
nflag=1;
else
{
nflag=0;
stop[a]=1;
if(alarm[a][3]==0)
repeat[a][b]=0;
}
if(nflag==0)
{ TR0=0;
break;
}
if(key_scan()==K1||key_scan()==K2||key_scan()==K3||key_scan()==K4)
{
switch (key_scan())
{
case K1: break;
case K2: break;
case K3: break;
case K4: stop[a]=0;delay_ms(100);
if(alarm[a][3]==0)
repeat[a][b]=0;
break;
}
}
while (!tmrFlg) ;
tmrFlg = 0;
idx = Sound[mflag] - 1;
Temp_T= tmrRld[idx];
Temp_TH0 = Temp_T/256;
Temp_TL0 = Temp_T%256;
TH0 = Temp_TH0;
TL0 = Temp_TL0 + 12; //加12是对中断延时的补偿
durationCnt = (ulong)240 * (ulong)noteFreq[idx] / ((ulong)music[mflag] * (ulong)speed);
soundCnt=durationCnt-(durationCnt >> 2);//发声
NO_soundCnt = durationCnt >> 2; //当前音符时值的前3/4发声,后1/4静音
for(i=soundCnt;i>0;i--) //发规定长度的音
{
while(TF1==0);
TH1 = Temp_TH1;
TL1 = Temp_TL1;
TF1=0;
}
enable=0;
for(i=NO_soundCnt-20;i>0;i--) //音符间的间隔
{
while(TF1==0);
TH1 = Temp_TH1;
TL1 = Temp_TL1+50;
TF1=0;
}
if(key_scan()==K1||key_scan()==K2||key_scan()==K3||key_scan()==K4)
{
switch (key_scan())
{
case K1: break;
case K2: break;
case K3: break;
case K4: stop[a]=0;delay_ms(100);
if(alarm[a][3]==0)
repeat[a][b]=0;
break;
}
}
/*********闹钟响显示时间*********/
DS1302_ReadTime();
LCD1602_DisplayData();
if(AM_PM==0&&hour12_24==1)
{
LCD1602_WriteCom(0x80+13);
LCD1602_WriteData('A');
}
if(AM_PM==1&&hour12_24==1)
{
LCD1602_WriteCom(0x80+13);
LCD1602_WriteData('P');
}
if(hour12_24==0)
{
LCD1602_WriteCom(0x80+13);
LCD1602_WriteData(' ');
}
LCD1602_WriteCom(0xc0+15);
if(aflag)
LCD1602_WriteData('N');
else
LCD1602_WriteData('F');
/********判断响一分钟的时间********/
if((alarm[a][0]==TIME[1]&&alarm[a][1]==TIME[2]))
nflag=1;
else
{
nflag=0;
stop[a]=1;
if(alarm[a][3]==0)
repeat[a][b]=0;
}
enable=1;
mflag+=1;
}
beep=1;enable=0;TR0=0;
if(!(alarm[a][0]==TIME[1]&&alarm[a][1]==TIME[2]))
stop[a]=1;
}
void InterruptTmr0() interrupt 1
{
TH0=Temp_TH0;
TL0=Temp_TL0;
tmrFlg = 1;
if (enable)
beep=!beep;
else
beep=1;
}
delay.h
#ifndef __DELAY_H
#define __DELAY_H
#include "sys.h"
#define uchar unsigned char
#define uint unsigned int
void delay_ms(uint i);
void delay_us(uchar x);
#endif
delay.c
#include "delay.h"
void delay_ms(uint i)
{
uchar n;
while(i--)
for(n=0;n<80;n++)
;
}
void delay_us(uchar x) //x*10 us
{
uchar a,b;
for(b=x;b>0;b--)
for(a=1;a>0;a--);
}
Ds18b20.h
#ifndef __TEMP_H_
#define __TEMP_H_
#include "reg51.h"
#include "delay.h"
#include"intrins.h"
#ifndef uchar
#define uchar unsigned char
#endif
#ifndef uint
#define uint unsigned int
#endif
sbit WDIO=P3^7;
uchar DS18B20_Init();
void DS18B20_WriteByte(uchar dat);
uchar DS18B20_ReadByte();
void DS18B20_ChangeTemp();
void DS18B20_ReadTempCom();
int DS18B20_ReadTemp();
void LCD1602_DisplayTemp(int temp);
#endif
Ds18b20.c
#include "temp.h"
#include "lcd1602.h"
uchar DS18B20_Init()
{
uint i=0;
WDIO=0; //总线拉低
// i=70;
// while(i--);//延时642us
delay_us(32); //延时720us
WDIO=1; //总线拉高
i=0;
while(WDIO) //等待是否拉低,
{
i++;
if(i>5000)
return 0;
}
return 1;
}
void DS18B20_WriteByte(uchar dat)
{
uchar i;
for(i=0;i<8;i++)
{
WDIO=0;
_nop_();
// j++;
WDIO=dat&0x01;
// j=6;
// while(j--);
delay_us(4);
WDIO=1;
dat>>=1;
}
}
uchar DS18B20_ReadByte()
{
uchar byte,b;
uchar i;
for(i=0;i<8;i++)
{
WDIO=0;
// j++;
_nop_();
WDIO=1;
// j++;
// j++;
delay_us(1);
b=WDIO;
byte=(byte>>1)|(b<<7);
// j=4;
// while(j--);
delay_us(5);
}
return byte;
}
void DS18B20_ChangeTemp()
{
DS18B20_Init();
delay_ms(1);
DS18B20_WriteByte(0xcc);
DS18B20_WriteByte(0x44);
delay_ms(100);
}
void DS18B20_ReadTempCom()
{
DS18B20_Init();
delay_ms(1);
DS18B20_WriteByte(0xcc);
DS18B20_WriteByte(0xbe);
}
int DS18B20_ReadTemp()
{
int temp;
uchar tmh,tml;
DS18B20_ChangeTemp();
DS18B20_ReadTempCom();
tml=DS18B20_ReadByte();
tmh=DS18B20_ReadByte();
temp=tmh;
temp<<=8;
temp|=tml;
return temp;
}
void LCD1602_DisplayTemp(int temp)
{
float tp;
uchar i;
uchar Temp_datas[]={0,0,0,0,0};
if(temp<0)
{
LCD1602_WriteCom(0xc0+10);
LCD1602_WriteData('-');
temp=temp-1;
temp=~temp;
tp=temp;
temp=tp*0.0625*100+0.5;
}
else
{
LCD1602_WriteCom(0xc0+10);
LCD1602_WriteData(' ');
temp=temp-1;
tp=temp;
temp=tp*0.0625*100+0.5;
}
Temp_datas[0]=temp%10000/1000;
Temp_datas[1]=temp%1000/100;
Temp_datas[3]=temp%100/10;
Temp_datas[4]=temp%10;
for(i=0;i<2;i++)
{
LCD1602_WriteData('0'+Temp_datas[i]);
}
LCD1602_WriteData('C');
}
lcd1602.h
#ifndef __LCD1602_H
#define __LCD1602_H
#define LCD1602_4PINS
#include "delay.h"
#define LCD1602_DATAPINS P0
sbit LCD1602_E=P2^7;
sbit LCD1602_RW=P2^5;
sbit LCD1602_RS=P2^6;
void LCD1602_WriteCom(uchar com); //写入命令
void LCD1602_WriteData(uchar dat); //写入数据
void LCD1602_Init(); //LCD初始化子程序
void LCD1602_Cursor(uchar addr,uchar Data);
#endif
lcd1602.c
#include "lcd1602.h"
//#ifndef LCD1602_4PINS //当没有定义这个LCD1602_4PINS时
void LCD1602_WriteCom(uchar com) //写入命令
{
LCD1602_E=0;
LCD1602_RS=0;
LCD1602_RW=0;
LCD1602_DATAPINS=com;
delay_ms(1);
LCD1602_E=1;
delay_ms(1);
LCD1602_E=0;
}
//#else
//void LCD1602_WriteCom(uchar com) //写入命令
//{
// LCD1602_E=0;
// LCD1602_RS=0;
// LCD1602_RW=0;
// LCD1602_DATAPINS=com; //由于4位的接线是接到P0口的高四位,所以传送高四位不用改
// delay_ms(1);
// LCD1602_E=1;
// delay_ms(1);
// LCD1602_E=0;
// delay_ms(1);
// LCD1602_DATAPINS=com<<4;
// delay_ms(1);
// LCD1602_E=1;
// delay_ms(1);
// LCD1602_E=0;
//}
//#endif
//#ifndef LCD1602_4PINS
void LCD1602_WriteData(uchar dat) //写入数据
{
LCD1602_E=0;
LCD1602_RS=1;
LCD1602_RW=0;
LCD1602_DATAPINS=dat;
delay_ms(1);
LCD1602_E=1;
delay_ms(1);
LCD1602_E=0;
}
//#else
//void LCD1602_WriteData(uchar dat) //写入数据
//{
// LCD1602_E=0;
// LCD1602_RS=1;
// LCD1602_RW=0;
// LCD1602_DATAPINS=dat; //由于4位的接线是接到P0口的高四位,所以传送高四位不用改
// delay_ms(1);
// LCD1602_E=1;
// delay_ms(1);
// LCD1602_E=0;
// LCD1602_DATAPINS=dat<<4;
// delay_ms(1);
// LCD1602_E=1;
// delay_ms(1);
// LCD1602_E=0;
//}
//#endif
//#ifndef LCD1602_4PINS
void LCD1602_Init() //LCD初始化子程序
{
LCD1602_WriteCom(0x38); //开显示
LCD1602_WriteCom(0x0c); //开显示不显示光标
LCD1602_WriteCom(0x06); //写一个指针加1
LCD1602_WriteCom(0x01); //清屏
LCD1602_WriteCom(0x80); //设置数据指针起点
}
//#else
//void LCD1602_Init()
//{
// LCD1602_WriteCom(0x32);
// LCD1602_WriteCom(0x28); //开显示
// LCD1602_WriteCom(0x0c); //开显示不显示光标
// LCD1602_WriteCom(0x06); //写一个指针加1
// LCD1602_WriteCom(0x01); //清屏
// LCD1602_WriteCom(0x80); //设置数据指针起点
//}
//#endif
void LCD1602_Cursor(uchar CF,uchar addr)
{
LCD1602_WriteCom(CF);
LCD1602_WriteCom(addr);
}
Ds1302.h
#ifndef __DS1302_H_
#define __DS1302_H_
#include "reg51.h"
#include "intrins.h"
#ifndef uchar
#define uchar unsigned char
#endif
#ifndef uint
#define uint unsigned int
#endif
sbit DSIO=P3^4;
sbit DSCE=P3^5;
sbit SCLK=P3^6;
void DS1302_lock(); // 开启写保护
void DS1302_unlock(); //取消写保护
void DS1302Write(uchar addr,uchar dat);
uchar DS1302Read(uchar addr);
void DS1302_Init();
void DS1302_ReadTime();
extern uchar TIME[7]; //加入全局变量
void LCD1602_DisplayData();
#endif
Ds1302.c
#include "ds1302.h"
#include "lcd1602.h"
//DS1302写入和读取时分秒的地址命令
uchar code READ_RTC_ADDR[7]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d}; //秒分时日月周年 最低位读写位};
uchar code WRITE_RTC_ADDR[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};
//DS1302时钟初始化2013年1月1日星期二12点00分00秒。存储顺序是秒分时日月周年,存储格式是用BCD码
uchar TIME[7]={0,0x00,0x20,0x07,0x12,0x05,0x18};
//uchar code T[]={"T "};
//uchar code D[]={"D "};
void DS1302Write(uchar addr,uchar dat)
{
uchar i;
DSCE=0;
_nop_();
SCLK=0;
_nop_();
DSCE=1;
_nop_();
for(i=0;i<8;i++)
{
DSIO=addr&0x01;
addr>>=1;
SCLK=1;
_nop_();
SCLK=0;
_nop_();
}
for(i=0;i<8;i++)
{
DSIO=dat&0x01;
dat>>=1;
SCLK=1;
_nop_();
SCLK=0;
_nop_();
}
DSCE=0;
_nop_();
}
uchar DS1302Read(uchar addr)
{
uchar i,dat,dat1;
DSCE=0;
_nop_();
SCLK=0;
_nop_();
DSCE=1;
_nop_();
for(i=0;i<8;i++)
{
DSIO=addr&0x01;
addr>>=1;
SCLK=1;
_nop_();
SCLK=0;
_nop_();
}
_nop_();
for(i=0;i<8;i++)
{
dat1=DSIO;
dat=(dat>>1)|(dat1<<7);
SCLK=1;
_nop_();
SCLK=0;
_nop_();
}
// DSCE=0;
_nop_();
SCLK=1;
DSIO=0;
_nop_();
DSIO=1;
_nop_();
return dat;
}
void DS1302_lock() // 开启写保护
{
DS1302Write(0x8E,0x80);
}
void DS1302_unlock() //取消写保护
{
DS1302Write(0x8E,0X00);
}
void DS1302_Init()
{
uchar n;
DS1302_unlock(); //禁止写保护,就是关闭写保护功能
for(n=0;n<7;n++)//写入7个字节的时钟信号:分秒时日月周年
{
// DS1302Write(0x84,TIME[2]|0x80);
DS1302Write(WRITE_RTC_ADDR[n],TIME[n]);
}
DS1302_lock(); //打开写保护功能
}
void DS1302_ReadTime()
{
uchar n;
for(n=0;n<7;n++)//读取7个字节的时钟信号:分秒时日月周年
{
// TIME[2]=DS1302Read(0x85);
// TIME[2]<<=3;
// TIME[2]>>=3;//前三位置0
TIME[n]=DS1302Read(READ_RTC_ADDR[n]);
}
}
//void LCD1602_DisplayData()
//{
uchar i;
// LCD1602_WriteCom(0x80+0X40);
for(i=0;i<2;i++)
LCD1602_WriteData(T[i]);
// LCD1602_WriteData('T');
// LCD1602_WriteData(' ');
// if(hour12_24==0)
// {
// LCD1602_WriteData('0'+TIME[2]/16); //时
// LCD1602_WriteData('0'+(TIME[2]&0x0f));
// }
// LCD1602_WriteData(':');
// LCD1602_WriteData('0'+TIME[1]/16); //分
// LCD1602_WriteData('0'+(TIME[1]&0x0f));
// LCD1602_WriteData(':');
// LCD1602_WriteData('0'+TIME[0]/16); //秒
// LCD1602_WriteData('0'+(TIME[0]&0x0f));
//
// LCD1602_WriteCom(0x80);
for(i=0;i<2;i++)
LCD1602_WriteData(D[i]);
// LCD1602_WriteData('D');
// LCD1602_WriteData(' ');
// LCD1602_WriteData('2');
// LCD1602_WriteData('0');
// LCD1602_WriteData('0'+TIME[6]/16); //年
// LCD1602_WriteData('0'+(TIME[6]&0x0f));
// LCD1602_WriteData('-');
// LCD1602_WriteData('0'+TIME[4]/16); //月
// LCD1602_WriteData('0'+(TIME[4]&0x0f));
// LCD1602_WriteData('-');
// LCD1602_WriteData('0'+TIME[3]/16); //日
// LCD1602_WriteData('0'+(TIME[3]&0x0f));
// LCD1602_WriteCom(0x8f);
// LCD1602_WriteData('0'+(TIME[5]&0x07)); //星期
//}
key.h
#ifndef __KEY_H
#define __KEY_H
#include "sys.h"
#include "delay.h"
#define KEYPORT P1 // 四个按键接在了P1口的四个引脚#define NO_KEY 0xf0#define K1 0X01#define K2 0X02#define K3 0X03#define K4 0X04#define KEYSUB 0X02#define KEYADD 0X01#define KEYSET 0X04#define KEYNEXT 0X03 //K1,2,3,4,和这些是一样的,只是写.c文件时#define LONGCNT 150#define SHORTCNT 12
#define K1 1
#define K2 2
#define K3 3
#define K4 4
uchar key_scan();
#endif
key.c
#include"key.h"
sbit KeyPort0=P1^4;
sbit KeyPort1=P1^5;
sbit KeyPort2=P1^6;
sbit KeyPort3=P1^7;
//sbit KeyPort2=P1^2;
//sbit KeyPort0=P1^0;
//sbit KeyPort1=P1^1;
//sbit KeyPort3=P1^3;
/************************************************************************
函数名称:key_scan()
函数功能:4个独立按键检测
输入参数:无
返回值:KeyV 通过返回值的不同来确定哪个按键被按下
*************************************************************************/
uchar key_scan()
{
uchar KeyV;
KEYPORT=0xff; //从51IO口读数据,一般要先给锁存器写1,
//具体请参考51IO口内部结构
if(KeyPort0==0||KeyPort1==0||KeyPort2==0||KeyPort3==0) //判断是否有按键按下
//这里改成if((P3&0xf0)!=0xf0)总是错,原因可能是P3读数据不是从引脚读的
//而是从锁存器读的,一直是0xff
{
delay_ms(10); //防止抖动(拿板子实验时,发现这里延不延时并无影响)
if(KeyPort0==0) //判断哪个按键被按下//
{
KeyV=K1;
}
else if(KeyPort1==0)
{
KeyV= K2;
}
else if(KeyPort2==0)
{
KeyV=K3;
}
else if(KeyPort3==0)
{
KeyV=K4;
}
}
else
{
KeyV= 0;
} //判断哪个按键被按下//
// if(KeyV != 0) //有按键按下时,进行松手检测
// while(KeyPort0==0||KeyPort1==0||KeyPort2==0||KeyPort3==0);
//delay_ms(10); //延时消抖
return KeyV; //返回KeyV来标识哪一个按键被按下
}
keyProcess.h
#ifndef __KEYPROCESS_H
#define __KEYPROCESS_H
#include "sys.h"
#include "stdio.h"
#include "delay.h"
#include "key.h"
#include "ds1302.h"
#include "lcd1602.h"
extern uchar alarm[5][5];
extern uchar repeat[5][7];
extern int Clock;
#define MODE0 0
#define MODE1 1
#define MODE2 2
#define MODE3 3
#define TIMESET MODE0
#define DATESET MODE1
#define ALARMSET MODE2
#define SECCON MODE3
void key_process(uchar mode);
#endif
keyProcess.c
#include"keyProcess.h"
#include "lcd1602.h"
#include "temp.h"
#include "ds1302.h"
#include "otherProcess.h"
/****************************************************************************************************
函数名称:key_process(uchar mode)
函数功能:按键处理函数(调节日期,时间,闹钟)
输入参数:mode 用来选择模式,是修改日期,时间还是闹钟
返回值:无
****************************************************************************************************/
uchar alarm[5][5]={0}; //0-4个闹钟//alarm[0][0] 分钟设置,alarm[0][1] 小时设置,alarm[0][2] 重复/不重复,alarm[0][3] 选择音乐
uchar repeat[5][7]={0}; //重复
int Clock; //闹钟个数
uchar code timeSet[]={"1:timeSet"};
uchar code alarmSet[]={"2:alarmSet"};
void key_process(uchar mode)
{
bit flag=0; //退出标志位
int Wch=0; //时间设置标志
uchar AlarmWch=0; //闹钟设置标志
uchar n;
uchar t;
bit year=1; //闰年判断
int function=0; //功能选择
int ClockWch=0; //位置选择
int ClockNum=0; //闹钟x
switch(mode)
{
case MODE0: //打开菜单
LCD1602_WriteCom(0x01);
LCD1602_WriteCom(0x80);
for(t=0;t<9;t++)
LCD1602_WriteData(timeSet[t]);
LCD1602_WriteCom(0xC0);
for(t=0;t<10;t++)
LCD1602_WriteData(alarmSet[t]);
LCD1602_Cursor(0x0F,0x80);
while(1)
{
delay_ms(500);
if(key_scan()==K1||key_scan()==K2||key_scan()==K3||key_scan()==K4)//检测有没有按键按下,有按键按下才执行操作
{
switch(key_scan())
{
case K1:
/****************设置时间***************/
if(function==0)
{
/***********时间显示***********/
DS1302_ReadTime();
LCD1602_DisplayData();
if(AM_PM==0&&hour12_24==1)
{
LCD1602_WriteCom(0x80+13);
LCD1602_WriteData('A');
LCD1602_WriteCom(0xC0+13);
LCD1602_WriteData('1');
LCD1602_WriteData('2');
}
if(AM_PM==1&&hour12_24==1)
{
LCD1602_WriteCom(0x80+13);
LCD1602_WriteData('P');
LCD1602_WriteCom(0xC0+13);
LCD1602_WriteData('1');
LCD1602_WriteData('2');
}
if(hour12_24==0)
{
LCD1602_WriteCom(0xC0+13);
LCD1602_WriteData('2');
LCD1602_WriteData('4');
}
LCD1602_Cursor(0x0F,0xC0+9);
/**********按键处理修改时间**********/
while(1)
{
delay_ms(500);
if(key_scan()==K1||key_scan()==K2||key_scan()==K3||key_scan()==K4)//检测有没有按键按下,有按键按下才执行操作
{
switch(key_scan())
{
case K1: Wch++;if(Wch>7) Wch=0; //选择时间的哪一位被更改
/***********光标显示哪个被选中*********/
if(Wch<3)
LCD1602_Cursor(0x0F,0xC0+9-3*Wch);
if(Wch==3)
LCD1602_Cursor(0x0F,0x80+11);
if(Wch==4)
LCD1602_Cursor(0x0F,0x80+8);
if(Wch==5)
LCD1602_Cursor(0x0F,0x80+15);
if(Wch==6)
LCD1602_Cursor(0x0F,0x80+5);
if(Wch==7)
LCD1602_Cursor(0x0F,0xC0+14);
break;
case K2: //K2按下,数字加一
TIME[Wch]++;
/********时间修改上限*********/
if((TIME[Wch]&0x0f)>9) //换成BCD码。
{
TIME[Wch]=TIME[Wch]+6;
}
if((TIME[Wch]>=0x60)&&(Wch<2)) //分秒只能到59
{
TIME[Wch]=0;
}
if((TIME[Wch]>=0x24)&&(Wch==2)) //小时只能到23
{
TIME[Wch]=0;
}
if((TIME[Wch]>=0x32)&&(TIME[4]==1||TIME[4]==3||TIME[4]==5||TIME[4]==7||TIME[4]==8||TIME[4]==0x10||TIME[4]==0x12)&&(Wch==3)) //日只能到31
{
TIME[Wch]=1;
}
if((TIME[Wch]>=0x31)&&(TIME[4]==4||TIME[4]==6||TIME[4]==9||TIME[4]==0x11)&&(Wch==3)) //日只能到30
{
TIME[Wch]=1;
}
if(TIME[4]==2&&(((uint)(TIME[6]+2000)%4==0&&(uint)(TIME[6]+2000)%100!=0)||((uint)(TIME[6]+2000)%400==0))) //润年判断
year=1; //1为闰年
else
year=0; //0不是闰年
if((TIME[Wch]>=0x30)&&(TIME[4]==2)&&(Wch==3)&&year==1) //日只能到29
{
TIME[Wch]=1;
}
if((TIME[Wch]>=0x29)&&(TIME[4]==2)&&(Wch==3)&&year==0) //日只能到28
{
TIME[Wch]=1;
}
if((TIME[Wch]>=0x13)&&(Wch==4)) //月只能到12
{
TIME[Wch]=1;
}
if((TIME[Wch]>0x7)&&(Wch==5)) //周只能到7
{
TIME[Wch]=1;
}
if(Wch==7) //改变时间制
{
hour12_24=!hour12_24;
}
if(hour12_24==0) //0为24小时制
{
LCD1602_WriteCom(0x80+13);
LCD1602_WriteData(' ');
}
LCD1602_DisplayData(); //显示修改时间
if(AM_PM==0&&hour12_24==1) //判断12小时制上午
{
LCD1602_WriteCom(0x80+13);
LCD1602_WriteData('A');
LCD1602_WriteCom(0xC0+13);
LCD1602_WriteData('1');
LCD1602_WriteData('2');
}
if(AM_PM==1&&hour12_24==1) //判断12小时制下午
{
LCD1602_WriteCom(0x80+13);
LCD1602_WriteData('P');
LCD1602_WriteCom(0xC0+13);
LCD1602_WriteData('1');
LCD1602_WriteData('2');
}
if(hour12_24==0) //显示24小时制
{
LCD1602_WriteCom(0xC0+13);
LCD1602_WriteData('2');
LCD1602_WriteData('4');
}
/**********开光标显示修改位置*********/
if(Wch<3)
LCD1602_Cursor(0x0F,0xC0+9-3*Wch);
if(Wch==3)
LCD1602_Cursor(0x0F,0x80+11);
if(Wch==4)
LCD1602_Cursor(0x0F,0x80+8);
if(Wch==5)
LCD1602_Cursor(0x0F,0x80+15);
if(Wch==6)
LCD1602_Cursor(0x0F,0x80+5);
if(Wch==7)
LCD1602_Cursor(0x0F,0xC0+14);
DS1302_Init();
break;
break;
case K3: TIME[Wch]--; //K3按下,数字减一 //有毒,待改
if((TIME[Wch]==0x00-1)&&(Wch<2)) //分秒只能到59
{
TIME[Wch]=0x59;
}
if((TIME[Wch]==0x00-1)&&(Wch==2)) //小时只能到23
{
TIME[Wch]=0x23;
}
// if((TIME[Wch]==0x00-1)&&(Wch==2)&&hour12_24==1) //小时只能到12 待改
// {
// TIME[Wch]=0x12;
// }
if((TIME[Wch]==0x00)&&(TIME[4]==1||TIME[4]==3||TIME[4]==5||TIME[4]==7||TIME[4]==8||TIME[4]==0x10||TIME[4]==0x12)&&(Wch==3)) //日只能到31
{
TIME[Wch]=0x31;
}
if((TIME[Wch]==0x00)&&(TIME[4]==4||TIME[4]==6||TIME[4]==9||TIME[4]==0x11)&&(Wch==3)) //日只能到30
{
TIME[Wch]=0x30;
}
if(TIME[4]==2&&((((TIME[6]/16*10+TIME[6]&0x0f)+2000)%4==0&&((TIME[6]/16*10+TIME[6]&0x0f)+2000)%100!=0)))
{
year=1;
}
else if(TIME[4]==2&&(((TIME[6]/16*10+TIME[6]&0x0f)+2000)%400==0))
{
year=1;
}
else
year=0;
if((TIME[Wch]==0x00)&&(TIME[4]==2)&&(Wch==3)&&year==1) //日只能到29
{
TIME[Wch]=0x29;
}
if((TIME[Wch]==0x00)&&(TIME[4]==2)&&(Wch==3)&&year==0) //日只能到28
{
TIME[Wch]=0x28;
}
if((TIME[Wch]==0x00)&&(Wch==4)) //月只能到12
{
TIME[Wch]=0x12;
}
if((TIME[Wch]==0x00)&&(Wch==5)) //周只能到7
{
TIME[Wch]=0x07;
}
if((TIME[Wch]&0x0f)>9) //换成BCD码。
{
TIME[Wch]=TIME[Wch]-6;
}
// DS1302_ReadTime();
if(Wch==7)
{
hour12_24=!hour12_24;
}
if(hour12_24==0)
{
LCD1602_WriteCom(0x80+13);
LCD1602_WriteData(' ');
}
LCD1602_DisplayData();
if(AM_PM==0&&hour12_24==1)
{
LCD1602_WriteCom(0x80+13);
LCD1602_WriteData('A');
LCD1602_WriteCom(0xC0+13);
LCD1602_WriteData('1');
LCD1602_WriteData('2');
}
if(AM_PM==1&&hour12_24==1)
{
LCD1602_WriteCom(0x80+13);
LCD1602_WriteData('P');
LCD1602_WriteCom(0xC0+13);
LCD1602_WriteData('1');
LCD1602_WriteData('2');
}
if(hour12_24==0)
{
LCD1602_WriteCom(0xC0+13);
LCD1602_WriteData('2');
LCD1602_WriteData('4');
}
if(Wch<3)
LCD1602_Cursor(0x0F,0xC0+9-3*Wch);
if(Wch==3)
LCD1602_Cursor(0x0F,0x80+11);
if(Wch==4)
LCD1602_Cursor(0x0F,0x80+8);
if(Wch==5)
LCD1602_Cursor(0x0F,0x80+15);
if(Wch==6)
LCD1602_Cursor(0x0F,0x80+5);
if(Wch==7)
LCD1602_Cursor(0x0F,0xC0+14);
DS1302_Init();
break;
case K4: flag=1;break; //保存退出
}
}
/********退出后显示**********/
if(flag==1)
{
// DS1302_Init();
// LCD1602_DisplayTemp(DS18B20_ReadTemp());
// DS1302_ReadTime();
// LCD1602_DisplayData();
// delay_ms(1000);
LCD1602_WriteCom(0x01);
LCD1602_WriteCom(0x80);
for(t=0;t<9;t++)
LCD1602_WriteData(timeSet[t]);
LCD1602_WriteCom(0xC0);
for(t=0;t<10;t++)
LCD1602_WriteData(alarmSet[t]);
if(function==0)
LCD1602_Cursor(0x0F,0x80);
if(function==1)
LCD1602_Cursor(0x0F,0xC0);
flag=0;
Wch=0;
break;
}
}
}
/********************************闹钟设置*********************************/
if(function==1)
{
LCD1602_WriteCom(0x01);
LCD1602_WriteCom(0x80);
for(n=0;n<=Clock;n++)
{
if(n>4)
break;
LCD1602_WriteData('1'+n);
LCD1602_WriteData(':');
if(alarm[n][2]==0)
LCD1602_WriteData('F');
else
LCD1602_WriteData('N');
LCD1602_WriteData(' ');
if(n==2)
LCD1602_WriteCom(0xC0);
}
LCD1602_WriteCom(0xC0+13);
LCD1602_WriteData('+');
LCD1602_WriteCom(0xC0+14);
LCD1602_WriteData('-');
if(ClockWch==2)
LCD1602_Cursor(0x0F,0x80);
if(ClockWch==3)
LCD1602_Cursor(0x0F,0x80+4);
if(ClockWch==4)
LCD1602_Cursor(0x0F,0x80+8);
if(ClockWch==5)
LCD1602_Cursor(0x0F,0xC0);
if(ClockWch==6)
LCD1602_Cursor(0x0F,0xC0+4);
if(ClockWch==0)
LCD1602_Cursor(0x0F,0xC0+13);
if(ClockWch==1)
LCD1602_Cursor(0x0F,0xC0+14); //开显示光标
while(1)
{
delay_ms(500);
if(key_scan()==K1||key_scan()==K2||key_scan()==K3||key_scan()==K4)//检测有没有按键按下,有按键按下才执行操作
{
switch(key_scan())
{
case K1: //确定选择
if(ClockWch==0)
{
Clock++;
LCD1602_WriteCom(0x01);
if(Clock>4)
{
Clock=4;
}
}
if(ClockWch==1)
{
Clock--;
LCD1602_WriteCom(0x01);
if(Clock<0)
{
Clock=0;
}
}
if(ClockWch>1)
{
ClockNum=ClockWch-2;
while(1)
{
delay_ms(500);
if(key_scan()==K1||key_scan()==K2||key_scan()==K3||key_scan()==K4)//检测有没有按键按下,有按键按下才执行操作
{
switch(key_scan())
{
case K1: //进入闹钟x设置
LCD1602_WriteCom(0x01);
LCD1602_alarm(0x80,alarm[ClockNum][1],alarm[ClockNum][0]); //显示闹钟时分
LCD1602_Data(0x80+7,'S'); //开关说明
LCD1602_Data(0x80+8,'W');
LCD1602_Data(0x80+9,':');
if(alarm[ClockNum][2]==0) //开关闹钟
LCD1602_Data(0x80+10,'F');
else
LCD1602_Data(0x80+10,'N');
LCD1602_Data(0x80+12,'R'); //重复说明
LCD1602_Data(0x80+13,'P');
LCD1602_Data(0x80+14,':');
if(alarm[ClockNum][3]==0) //显示重复/不重复闹钟
LCD1602_Data(0x80+15,'0'); //0不重复
else
LCD1602_Data(0x80+15,'1'); //1重复
LCD1602_Data(0xC0+0,'M'); //音乐说明
LCD1602_Data(0xC0+1,'U');
LCD1602_Data(0xC0+2,'S');
LCD1602_Data(0xC0+3,'I');
LCD1602_Data(0xC0+4,'C');
LCD1602_Data(0xC0+5,':');
for(n=0;n<5;n++) //显示音乐
{
LCD1602_Data(0xC0+n*2+6,'0'+n);
}
LCD1602_Cursor(0x0F,0x80+4); //开显示光标
while(1)
{
delay_ms(500);
if(key_scan()==K1||key_scan()==K2||key_scan()==K3||key_scan()==K4)//检测有没有按键按下,有按键按下才执行操作
{
switch(key_scan())
{
case K1: AlarmWch++; // 选择设置 重复/不重复,时间,选择音乐
if(AlarmWch>4)
AlarmWch=0;
if(AlarmWch==3)
LCD1602_Cursor(0x0F,0x80+13);
break;
case K2: alarm[ClockNum][AlarmWch]++; // 闹钟时间加1
if((alarm[ClockNum][AlarmWch]&0x0f)>9&&AlarmWch<2) //换成BCD码。
{
alarm[ClockNum][AlarmWch]=alarm[Clock][AlarmWch]+6;
}
if((alarm[ClockNum][AlarmWch]>=0x60)&&AlarmWch==0) //分秒只能到59
{
alarm[ClockNum][AlarmWch]=0;
}
if((alarm[ClockNum][AlarmWch]>=0x24)&&(AlarmWch==1)) //小时只能到23
{
alarm[ClockNum][AlarmWch]=0;
}
if(AlarmWch==2&&alarm[ClockNum][AlarmWch]>1) //开关闹钟
alarm[ClockNum][AlarmWch]=0;
if(AlarmWch==3&&alarm[ClockNum][AlarmWch]>1) //重复/不重复
alarm[ClockNum][AlarmWch]=1;
if(AlarmWch==4&&alarm[ClockNum][AlarmWch]>4) //选择音乐
alarm[ClockNum][AlarmWch]=0;
if(AlarmWch==3) //选择重复
{
LCD1602_WriteCom(0x01);
LCD1602_WriteCom(0x80);
for(n=0;n<7;n++)
{
LCD1602_WriteData('n');
LCD1602_WriteData(':');
LCD1602_WriteData('0'+repeat[Clock][n]);
LCD1602_WriteData(' ');
if(n==3)
LCD1602_WriteCom(0xC0);
}
LCD1602_Data(0xC0+12,'n');
LCD1602_Data(0xC0+13,'=');
LCD1602_Data(0xC0+14,'1');
LCD1602_Cursor(0x0F,0x80);
while(1)
{
delay_ms(500);
if(key_scan()==K1||key_scan()==K2||key_scan()==K3||key_scan()==K4)//检测有没有按键按下,有按键按下才执行操作
{
switch(key_scan())
{
case K1: Wch++;if(Wch>6) Wch=0;break;
case K2: repeat[ClockNum][Wch]=1;break;
case K3: repeat[ClockNum][Wch]=0;break;
case K4: flag=1;Wch=0;break;
}
LCD1602_WriteCom(0x80);
for(n=0;n<7;n++)
{
LCD1602_WriteData('n');
LCD1602_WriteData(':');
LCD1602_WriteData('0'+repeat[ClockNum][n]);
LCD1602_WriteData(' ');
if(n==3)
LCD1602_WriteCom(0xC0);
}
LCD1602_Data(0xC0+12,'n');
LCD1602_Data(0xC0+13,'=');
LCD1602_Data(0xC0+14,'0'+Wch+1);
if(Wch==0)
LCD1602_Cursor(0x0F,0x80);
if(Wch==1)
LCD1602_Cursor(0x0F,0x80+4);
if(Wch==2)
LCD1602_Cursor(0x0F,0x80+8);
if(Wch==3)
LCD1602_Cursor(0x0F,0x80+12);
if(Wch==4)
LCD1602_Cursor(0x0F,0xC0);
if(Wch==5)
LCD1602_Cursor(0x0F,0xC0+4);
if(Wch==6)
LCD1602_Cursor(0x0F,0xC0+8);
}
if(flag==1)
{
flag=0;
LCD1602_WriteCom(0x01);
LCD1602_alarm(0x80,alarm[Clock][1],alarm[Clock][0]); //显示闹钟界面
//显示光标
LCD1602_Data(0x80+7,'S'); //开关说明
LCD1602_Data(0x80+8,'W');
LCD1602_Data(0x80+9,':');
if(alarm[ClockNum][2]==0) //显示开关闹钟
LCD1602_Data(0x80+10,'F'); //0关
else
LCD1602_Data(0x80+10,'N'); //1开
LCD1602_Data(0x80+12,'R'); //重复说明
LCD1602_Data(0x80+13,'P');
LCD1602_Data(0x80+14,':');
if(alarm[ClockNum][3]==0) //显示重复/不重复闹钟
LCD1602_Data(0x80+15,'0'); //0不重复
else
LCD1602_Data(0x80+15,'1'); //1重复
LCD1602_Data(0xC0+0,'M'); //音乐说明
LCD1602_Data(0xC0+1,'U');
LCD1602_Data(0xC0+2,'S');
LCD1602_Data(0xC0+3,'I');
LCD1602_Data(0xC0+4,'C');
LCD1602_Data(0xC0+5,':');
for(n=0;n<5;n++)
{
LCD1602_Data(0xC0+n*2+6,'0'+n);
}
if(AlarmWch==0) //开显示光标
LCD1602_Cursor(0x0F,0x80+4);
if(AlarmWch==1)
LCD1602_Cursor(0x0F,0x80+1);
if(AlarmWch==2)
LCD1602_Cursor(0x0F,0x80+10);
if(AlarmWch==3)
LCD1602_Cursor(0x0F,0x80+14);
if(AlarmWch==4)
{
LCD1602_Cursor(0x0F,0xC0+alarm[ClockNum][4]*2+6);
}
break;
}
}
}
break;
case K3: alarm[ClockNum][AlarmWch]--; // 闹钟时间减1
if((alarm[ClockNum][AlarmWch]==0x00-1)&&(AlarmWch==0)) //分秒只能到59
{
alarm[ClockNum][AlarmWch]=0x59;
}
if((alarm[ClockNum][AlarmWch]==0x00-1)&&(AlarmWch==1)) //小时只能到23
{
alarm[ClockNum][AlarmWch]=0x23;
}
if((alarm[ClockNum][AlarmWch]&0x0f)>9&&AlarmWch<2) //换成BCD码。
{
alarm[ClockNum][AlarmWch]=alarm[ClockNum][AlarmWch]-6;
}
if(AlarmWch==2&&alarm[ClockNum][AlarmWch]<0) //开关闹钟
alarm[ClockNum][AlarmWch]=1;
if(AlarmWch==3) //重复/不重复
alarm[ClockNum][AlarmWch]=0;
if(AlarmWch==4&&alarm[ClockNum][AlarmWch]<0) //选择音乐
alarm[ClockNum][AlarmWch]=4;
if(AlarmWch==3) //选择重复
{
LCD1602_WriteCom(0x01);
LCD1602_WriteCom(0x80);
for(n=0;n<7;n++)
{
LCD1602_WriteData('n');
LCD1602_WriteData(':');
LCD1602_WriteData('0'+repeat[Clock][n]);
LCD1602_WriteData(' ');
if(n==3)
LCD1602_WriteCom(0xC0);
}
LCD1602_Data(0xC0+12,'n');
LCD1602_Data(0xC0+13,'=');
LCD1602_Data(0xC0+14,'1');
LCD1602_Cursor(0x0F,0x80);
while(1)
{
delay_ms(500);
if(key_scan()==K1||key_scan()==K2||key_scan()==K3||key_scan()==K4)//检测有没有按键按下,有按键按下才执行操作
{
switch(key_scan())
{
case K1: Wch++;if(Wch>6) Wch=0;break;
case K2: repeat[ClockNum][Wch]=1;break;
case K3: repeat[ClockNum][Wch]=0;break;
case K4: flag=1;Wch=0;break;
}
LCD1602_WriteCom(0x80);
for(n=0;n<7;n++)
{
LCD1602_WriteData('n');
LCD1602_WriteData(':');
LCD1602_WriteData('0'+repeat[ClockNum][n]);
LCD1602_WriteData(' ');
if(n==3)
LCD1602_WriteCom(0xC0);
}
LCD1602_Data(0xC0+12,'n');
LCD1602_Data(0xC0+13,'=');
LCD1602_Data(0xC0+14,'0'+Wch+1);
if(Wch==0)
LCD1602_Cursor(0x0F,0x80);
if(Wch==1)
LCD1602_Cursor(0x0F,0x80+4);
if(Wch==2)
LCD1602_Cursor(0x0F,0x80+8);
if(Wch==3)
LCD1602_Cursor(0x0F,0x80+12);
if(Wch==4)
LCD1602_Cursor(0x0F,0xC0);
if(Wch==5)
LCD1602_Cursor(0x0F,0xC0+4);
if(Wch==6)
LCD1602_Cursor(0x0F,0xC0+8);
}
if(flag==1)
{
flag=0;
LCD1602_WriteCom(0x01);
LCD1602_alarm(0x80,alarm[Clock][1],alarm[Clock][0]); //显示闹钟界面
//显示光标
LCD1602_Data(0x80+7,'S'); //开关说明
LCD1602_Data(0x80+8,'W');
LCD1602_Data(0x80+9,':');
if(alarm[ClockNum][2]==0) //显示开关闹钟
LCD1602_Data(0x80+10,'F'); //0关
else
LCD1602_Data(0x80+10,'N'); //1开
LCD1602_Data(0x80+12,'R'); //重复说明
LCD1602_Data(0x80+13,'P');
LCD1602_Data(0x80+14,':');
if(alarm[ClockNum][3]==0) //显示重复/不重复闹钟
LCD1602_Data(0x80+15,'0'); //0不重复
else
LCD1602_Data(0x80+15,'1'); //1重复
LCD1602_Data(0xC0+0,'M'); //音乐说明
LCD1602_Data(0xC0+1,'U');
LCD1602_Data(0xC0+2,'S');
LCD1602_Data(0xC0+3,'I');
LCD1602_Data(0xC0+4,'C');
LCD1602_Data(0xC0+5,':');
for(n=0;n<5;n++)
{
LCD1602_Data(0xC0+n*2+6,'0'+n);
}
if(AlarmWch==0) //开显示光标
LCD1602_Cursor(0x0F,0x80+4);
if(AlarmWch==1)
LCD1602_Cursor(0x0F,0x80+1);
if(AlarmWch==2)
LCD1602_Cursor(0x0F,0x80+10);
if(AlarmWch==3)
LCD1602_Cursor(0x0F,0x80+15);
if(AlarmWch==4)
{
LCD1602_Cursor(0x0F,0xC0+alarm[ClockNum][4]*2+6);
}
break;
}
}
}
break;
case K4: flag=1;break; // 退出设置
}
LCD1602_alarm(0x80,alarm[ClockNum][1],alarm[ClockNum][0]); //显示闹钟界面
//显示光标
LCD1602_Data(0x80+7,'S'); //开关说明
LCD1602_Data(0x80+8,'W');
LCD1602_Data(0x80+9,':');
if(alarm[ClockNum][2]==0) //显示开关闹钟
LCD1602_Data(0x80+10,'F'); //0关
else
LCD1602_Data(0x80+10,'N'); //1开
LCD1602_Data(0x80+12,'R'); //重复说明
LCD1602_Data(0x80+13,'P');
LCD1602_Data(0x80+14,':');
if(alarm[ClockNum][3]==0) //显示重复/不重复闹钟
LCD1602_Data(0x80+15,'0'); //0不重复
else
LCD1602_Data(0x80+15,'1'); //1重复
LCD1602_Data(0xC0+0,'M'); //音乐说明
LCD1602_Data(0xC0+1,'U');
LCD1602_Data(0xC0+2,'S');
LCD1602_Data(0xC0+3,'I');
LCD1602_Data(0xC0+4,'C');
LCD1602_Data(0xC0+5,':');
for(n=0;n<5;n++)
{
LCD1602_Data(0xC0+n*2+6,'0'+n);
}
if(AlarmWch==0) //开显示光标
LCD1602_Cursor(0x0F,0x80+4);
if(AlarmWch==1)
LCD1602_Cursor(0x0F,0x80+1);
if(AlarmWch==2)
LCD1602_Cursor(0x0F,0x80+10);
if(AlarmWch==3)
LCD1602_Cursor(0x0F,0x80+15);
if(AlarmWch==4)
{
LCD1602_Cursor(0x0F,0xC0+alarm[ClockNum][4]*2+6);
}
}
if(flag==1) //退出显示闹钟选择界面
{
AlarmWch=0;
LCD1602_WriteCom(0x01);
LCD1602_WriteCom(0x80);
for(n=0;n<=Clock;n++)
{
if(n>4)
break;
LCD1602_WriteData('1'+n);
LCD1602_WriteData(':');
if(alarm[n][2]==0)
LCD1602_WriteData('F');
else
LCD1602_WriteData('N');
LCD1602_WriteData(' ');
if(n==2)
LCD1602_WriteCom(0xC0);
}
LCD1602_WriteCom(0xC0+13);
LCD1602_WriteData('+');
LCD1602_WriteCom(0xC0+14);
LCD1602_WriteData('-');
if(ClockWch==2)
LCD1602_Cursor(0x0F,0x80);
if(ClockWch==3)
LCD1602_Cursor(0x0F,0x80+4);
if(ClockWch==4)
LCD1602_Cursor(0x0F,0x80+8);
if(ClockWch==5)
LCD1602_Cursor(0x0F,0xC0);
if(ClockWch==6)
LCD1602_Cursor(0x0F,0xC0+4);
if(ClockWch==0)
LCD1602_Cursor(0x0F,0xC0+13);
if(ClockWch==1)
LCD1602_Cursor(0x0F,0xC0+14);
break;
}
}
break;
case K2: ClockWch++; break; //选择设置位置加1
case K3: ClockWch--; break; //选择设置位置减1
case K4: flag=1;break;
}
}
if(flag==1||ClockWch!=(ClockNum+2))
{
flag=0;
ClockNum=0;
LCD1602_WriteCom(0x01);
LCD1602_WriteCom(0x80);
for(n=0;n<=Clock;n++)
{
if(n>4)
break;
LCD1602_WriteData('1'+n);
LCD1602_WriteData(':');
if(alarm[n][2]==0)
LCD1602_WriteData('F');
else
LCD1602_WriteData('N');
LCD1602_WriteData(' ');
if(n==2)
LCD1602_WriteCom(0xC0);
}
LCD1602_WriteCom(0xC0+13);
LCD1602_WriteData('+');
LCD1602_WriteCom(0xC0+14);
LCD1602_WriteData('-');
if(ClockWch==2)
LCD1602_Cursor(0x0F,0x80);
if(ClockWch==3)
LCD1602_Cursor(0x0F,0x80+4);
if(ClockWch==4)
LCD1602_Cursor(0x0F,0x80+8);
if(ClockWch==5)
LCD1602_Cursor(0x0F,0xC0);
if(ClockWch==6)
LCD1602_Cursor(0x0F,0xC0+4);
if(ClockWch==0)
LCD1602_Cursor(0x0F,0xC0+13);
if(ClockWch==1)
LCD1602_Cursor(0x0F,0xC0+14);
break;
}
}
}
LCD1602_WriteCom(0x80);
for(n=0;n<=Clock;n++)
{
if(n>4)
break;
LCD1602_WriteData('1'+n);
LCD1602_WriteData(':');
if(alarm[n][2]==0)
LCD1602_WriteData('F');
else
LCD1602_WriteData('N');
LCD1602_WriteData(' ');
if(n==2)
LCD1602_WriteCom(0xC0);
}
LCD1602_WriteCom(0xC0+13);
LCD1602_WriteData('+');
LCD1602_WriteCom(0xC0+14);
LCD1602_WriteData('-');
if(ClockWch==2) //显示光标
LCD1602_Cursor(0x0F,0x80);
if(ClockWch==3)
LCD1602_Cursor(0x0F,0x80+4);
if(ClockWch==4)
LCD1602_Cursor(0x0F,0x80+8);
if(ClockWch==5)
LCD1602_Cursor(0x0F,0xC0);
if(ClockWch==6)
LCD1602_Cursor(0x0F,0xC0+4);
if(ClockWch==0)
LCD1602_Cursor(0x0F,0xC0+13);
if(ClockWch==1)
LCD1602_Cursor(0x0F,0xC0+14);
break;
case K2:
ClockWch++; //选择设置位置加1
if(ClockWch>Clock+2)
ClockWch=0;
break;
case K3: ClockWch--; //选择设置位置减1
if(ClockWch<0)
ClockWch=Clock+2;
break;
case K4: flag=1;break;
}
}
// LCD1602_WriteCom(0x01); //显示闹钟个数
LCD1602_WriteCom(0x80);
for(n=0;n<=Clock;n++)
{
if(n>4)
break;
LCD1602_WriteData('1'+n);
LCD1602_WriteData(':');
if(alarm[n][2]==0)
LCD1602_WriteData('F');
else
LCD1602_WriteData('N');
LCD1602_WriteData(' ');
if(n==2)
LCD1602_WriteCom(0xC0);
}
LCD1602_WriteCom(0xC0+13);
LCD1602_WriteData('+');
LCD1602_WriteCom(0xC0+14);
LCD1602_WriteData('-');
if(ClockWch==2) //显示光标
LCD1602_Cursor(0x0F,0x80);
if(ClockWch==3)
LCD1602_Cursor(0x0F,0x80+4);
if(ClockWch==4)
LCD1602_Cursor(0x0F,0x80+8);
if(ClockWch==5)
LCD1602_Cursor(0x0F,0xC0);
if(ClockWch==6)
LCD1602_Cursor(0x0F,0xC0+4);
if(ClockWch==0)
LCD1602_Cursor(0x0F,0xC0+13);
if(ClockWch==1)
LCD1602_Cursor(0x0F,0xC0+14);
if(flag==1) //退出显示主菜单
{
flag=0;
ClockWch=0; //位置选择置0
LCD1602_WriteCom(0x01);
LCD1602_WriteCom(0x80);
for(t=0;t<9;t++)
LCD1602_WriteData(timeSet[t]);
LCD1602_WriteCom(0xC0);
for(t=0;t<10;t++)
LCD1602_WriteData(alarmSet[t]);
if(function==0)
LCD1602_Cursor(0x0F,0x80);
if(function==1)
LCD1602_Cursor(0x0F,0xC0);
break;
}
}
}
break;
case K2: function++; //功能选择
if(function>1)
function=0;
if(function==0)
LCD1602_Cursor(0x0F,0x80);
if(function==1)
LCD1602_Cursor(0x0F,0xC0);
break;
case K3: function--; //功能选择
if(function<0)
function=1;
if(function==0)
LCD1602_Cursor(0x0F,0x80);
if(function==1)
LCD1602_Cursor(0x0F,0xC0);
break;
case K4: flag=1;break; //退出设置
}
}
if(flag==1) //退出开主显示界面
{
LCD1602_DisplayTemp(DS18B20_ReadTemp());
DS1302_ReadTime();
LCD1602_DisplayData();
if(AM_PM==0&&hour12_24==1)
{
LCD1602_WriteCom(0x80+13);
LCD1602_WriteData('A');
}
if(AM_PM==1&&hour12_24==1)
{
LCD1602_WriteCom(0x80+13);
LCD1602_WriteData('P');
}
// delay_ms(1000);
flag=0;
break;
}
}
LCD1602_WriteCom(0x0C); //取消光标
break;
case MODE1: hour12_24=!hour12_24;break; //更改时制
case MODE2: if(hour12_24==1)
{
AM_PM=!AM_PM;
if(AM_PM==1)
{
if(TIME[2]==0x08)
TIME[2]=0x20;
else if(TIME[2]==0x09)
TIME[2]=0x21;
else
TIME[2]+=0x12;
DS1302_Init();
}
if(AM_PM==0)
{
if(TIME[2]==0x20)
TIME[2]=0x08;
else if(TIME[2]==0x21)
TIME[2]=0x09;
else
TIME[2]-=0x12;
DS1302_Init();
}
}
break; //无
case MODE3: break; //开关闹钟
}
}
otherProcess.h
#ifndef __OTHERPROCESS_H
#define __OTHERPROCESS_H
#include "sys.h"
#include "lcd1602.h"
extern bit hour12_24;
extern bit AM_PM;
extern bit alarm_AM_PM;
void LCD1602_alarm(uchar addr,uchar hour,uchar min);
void LCD1602_Data(uchar addr,uchar dat);
void LCD1602_DisplayData();
#endif
otherProcess.c
#include "otherProcess.h"
#include "ds1302.h"
bit hour12_24=0;
bit AM_PM=0;
bit alarm_AM_PM;
void LCD1602_alarm(uchar addr,uchar hour,uchar min)
{
uchar i;
if(hour12_24==0)
{
LCD1602_WriteCom(addr);
LCD1602_WriteData('0'+hour/16); //时
LCD1602_WriteData('0'+(hour&0x0f));
}
if(hour12_24==1)
{
if(hour>0x12)
{
i=hour-0x12;
alarm_AM_PM=1;
if(hour==0x20)
i=0x08;
if(hour==0x21)
i=0x09;
}
else //早上
{
alarm_AM_PM=0;
i=hour;
if(hour==0x12)
alarm_AM_PM=1;
if(hour==0x00)
i=0x12;
}
LCD1602_WriteCom(addr);
LCD1602_WriteData('0'+i/16); //时
LCD1602_WriteData('0'+(i&0x0f));
if(alarm_AM_PM==0)
{
LCD1602_WriteCom(addr+5);
LCD1602_WriteData('A');
}
else
{
LCD1602_WriteCom(addr+5);
LCD1602_WriteData('P');
}
}
LCD1602_WriteCom(addr+2);
LCD1602_WriteData(':');
LCD1602_WriteData('0'+min/16); //分
LCD1602_WriteData('0'+(min&0x0f));
}
void LCD1602_Data(uchar addr,uchar dat) //写一个地址和数据
{
LCD1602_WriteCom(addr);
LCD1602_WriteData(dat);
}
void LCD1602_DisplayData()
{
uchar i;
LCD1602_WriteCom(0x80+0X40);
// for(i=0;i<2;i++)
// LCD1602_WriteData(T[i]);
LCD1602_WriteData('T');
LCD1602_WriteData(' ');
if(hour12_24==0)
{
LCD1602_WriteCom(0x80+0X40+2);
LCD1602_WriteData('0'+TIME[2]/16); //时
LCD1602_WriteData('0'+(TIME[2]&0x0f));
}
if(hour12_24==1)
{
if(TIME[2]>0x12) //下午
{
i=TIME[2]-0x12;
AM_PM=1;
if(TIME[2]==0x20)
i=0x08;
if(TIME[2]==0x21)
i=0x09;
}
else //早上
{
AM_PM=0;
i=TIME[2];
if(TIME[2]==0x12)
AM_PM=1;
if(TIME[2]==0x00)
i=0x12;
}
LCD1602_WriteCom(0x80+0X40+2);
LCD1602_WriteData('0'+i/16); //时
LCD1602_WriteData('0'+(i&0x0f));
}
LCD1602_WriteCom(0x80+0X40+4);
LCD1602_WriteData(':');
LCD1602_WriteData('0'+TIME[1]/16); //分
LCD1602_WriteData('0'+(TIME[1]&0x0f));
LCD1602_WriteData(':');
LCD1602_WriteData('0'+TIME[0]/16); //秒
LCD1602_WriteData('0'+(TIME[0]&0x0f));
LCD1602_WriteCom(0x80);
// for(i=0;i<2;i++)
// LCD1602_WriteData(D[i]);
LCD1602_WriteData('D');
LCD1602_WriteData(' ');
LCD1602_WriteData('2');
LCD1602_WriteData('0');
LCD1602_WriteData('0'+TIME[6]/16); //年
LCD1602_WriteData('0'+(TIME[6]&0x0f));
LCD1602_WriteData('-');
LCD1602_WriteData('0'+TIME[4]/16); //月
LCD1602_WriteData('0'+(TIME[4]&0x0f));
LCD1602_WriteData('-');
LCD1602_WriteData('0'+TIME[3]/16); //日
LCD1602_WriteData('0'+(TIME[3]&0x0f));
LCD1602_WriteCom(0x8f);
LCD1602_WriteData('0'+(TIME[5]&0x07)); //星期
}
转载自原文链接, 如需删除请联系管理员。
原文链接:电子闹钟设计,转载请注明来源!