本设计中,在按键处理方面,下了不少功夫,虽然只有三个按键,不同状态下,实现不同的功能.
为了节省用电,设计背景灯有按键铵下才亮,延时5秒后灭.长按K1进入设置状态,按K2移位,K3数字加.依次设置年月日,星期,时分秒,闹钟1,闹钟2.
在走时状态下,按K2显示闹钟1,按K3显示闹钟2,延时5秒后返回走时.在显示闹钟状态下,按K1,开关闹钟,显示"*"为开.走时状态下显示"%"为只有一个闹钟开,显示"@"为两个闹钟开.在闹钟响铃时,按任意键关闭声音.
制作出来的原理图如下:
Altium Designer画的原理图和PCB图如下:(51hei附件中可下载工程文件)
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
单片机源程序如下:
- #include "Lcd1602.h"
- #include "KEY.h"
- #include "DS18B20.h"
- #include "DS1302.h"
- uchar T0RH,T0RL;
- bit flag1s = 1; //1秒标志
- bit flag200ms = 1; //200毫秒标志
- bit beeonoff1=0,beeonoff2=0; //闹钟1,2开关标志
- bit beeon = 0; //峰鸣开关
- uchar keybee = 0; //按键闹钟1,2切换
- uchar hourbee1=0x08,minbee1=0x00,hourbee2=0x13,minbee2=0x30; //闹钟1,2存放值
- uchar flag = 0; //闹钟显示时间
- uchar pos = 0; //设置时间引索
- sint buftemp; //温度暂存
- struct sTime {
- uchar year;
- uchar mon;
- uchar day;
- uchar hour;
- uchar min;
- uchar sec;
- uchar week;
- };
- struct sTime buftime;
- void ConfigTimer0(uchar ms);
- void ShowTemp();
- void RefrTime();
- void main()
- {
- bit reg = 0;
- uchar bufsec = 0xaa;
-
- EA = 1;
- ConfigTimer0(2);
- LcdInit();
- DS1302Init();
- Start18B20();
- GainTime(&buftime);
- RefrTime();
- while(1)
- {
- KeyDriver();
- if (!pos)
- {
- if (flag200ms)
- {
- flag200ms = 0;
- GainTime(&buftime);
- if (bufsec != buftime.sec)
- {
- RefrTime();
- bufsec = buftime.sec;
- }
- if (((hourbee1==buftime.hour) && (minbee1==buftime.min) && beeonoff1) || (hourbee2==buftime.hour) && (minbee2==buftime.min) && beeonoff2)
- {
- beeon = 1;
- }
- else
- {
- beeon = 0;
- }
- }
- if (flag1s )
- {
- flag1s = 0;
- reg = Get18B20Temp(&buftemp);
- if (reg)
- {
- ShowTemp();
- }
- Start18B20();
- }
- }
- }
- }
- void ShowTemp() //温度显示
- {
- schar i = 0;
- uchar len=0;
- uchar tempint,tempdec; //温度整数部分,小数部分存放
- uchar buf[4],str[6];
- tempint = (buftemp>>4) & 0x7f; //取出整数部分
- tempdec = buftemp & 0x0f; //取出小数部分
- do {
- buf[i++] = tempint%10;
- tempint = tempint/10;
- }while (tempint > 0);
- if (i < 2)
- {
- str[len++] = ' ';
- }
- while (i-- > 0)
- {
- str[len++] = buf[i] + '0';
- }
- str[len++] = '.';
- str[len++] = (tempdec*10/16) +'0';
-
- str[len] = '\0';
- LcdShowStr(11,1,str);
- }
- void NumToStr(uchar x,uchar y, uchar *str) //数据转换字符
- {
- uchar buf[3];
- buf[0] = (*str>>4) + '0';
- buf[1] = (*str&0x0f) + '0';
- buf[2] = '\0';
- LcdShowStr(x,y,buf);
- }
- void RefrTime() //刷新时间
- {
- NumToStr(2,0,&buftime.year);
- NumToStr(5,0,&buftime.mon);
- NumToStr(8,0,&buftime.day);
- LcdShowStr(15,0,&buftime.week);
- if (((flag>0) && (keybee ==1)) || ((pos>=14) && (pos<=17))) //闹钟1显示
- {
- NumToStr(2,1,&hourbee1);
- NumToStr(5,1,&minbee1);
- LcdShowStr(8,1,"-1");
- }
- else if (((flag>0) && (keybee ==2)) || ((pos>=18) && (pos<=21))) //闹钟2显示
- {
- NumToStr(2,1,&hourbee2);
- NumToStr(5,1,&minbee2);
- LcdShowStr(8,1,"-2");
- }
- else
- {
- NumToStr(2,1,&buftime.hour);
- NumToStr(5,1,&buftime.min);
- NumToStr(8,1,&buftime.sec);
- if (beeonoff1 && beeonoff2) //如果两个闹钟开,则显示"@"
- LcdShowStr(0,1,"@");
- else if (!beeonoff1 && !beeonoff2) //如果两个闹钟关,则不显示,
- LcdShowStr(0,1," ");
- else
- LcdShowStr(0,1,"%"); //如果其中一个闹钟开,则显示"%"
- }
- }
- void BeeOnroOff() //闹钟开关时显示
- {
- if (keybee == 1) //闹钟1开关
- {
- beeonoff1 = ~beeonoff1;
- if (beeonoff1)
- {
- LcdShowStr(0,1,"*"); //显示"*",表示闹钟开
- }
- else
- {
- LcdShowStr(0,1," ");
- }
- }
- else if (keybee == 2) //闹钟2开关
- {
- beeonoff2 = ~beeonoff2;
- if (beeonoff1 || beeonoff2)
- {
- LcdShowStr(0,1,"*");
- }
- else
- {
- LcdShowStr(0,1," ");
- }
- }
- }
- void CurPosit() //光标位置,设置修改的位置
- {
- switch(pos)
- {
- case 1: LcdSetCort(2,0); break; //日期
- case 2: LcdSetCort(3,0); break;
- case 3: LcdSetCort(5,0); break;
- case 4: LcdSetCort(6,0); break;
- case 5: LcdSetCort(8,0); break;
- case 6: LcdSetCort(9,0); break;
- case 7: LcdSetCort(15,0); break; //星期
- case 8: LcdSetCort(2,1); break; //时间
- case 9: LcdSetCort(3,1); break;
- case 10: LcdSetCort(5,1); break;
- case 11: LcdSetCort(6,1); break;
- case 12: LcdSetCort(8,1); break;
- case 13: LcdSetCort(9,1); break;
- case 14: LcdSetCort(2,1); break; //闹钟1
- case 15: LcdSetCort(3,1); break;
- case 16: LcdSetCort(5,1); break;
- case 17: LcdSetCort(6,1); break;
- case 18: LcdSetCort(2,1); break; //闹钟2
- case 19: LcdSetCort(3,1); break;
- case 20: LcdSetCort(5,1); break;
- case 21: LcdSetCort(6,1); break;
- default: break;
- }
- }
- void RightShift() //向右移动
- {
- if (pos != 0)
- {
- if (pos < 21)
- pos++;
- else
- pos = 1;
- if ((pos==14) || (pos==18) || (pos==1))
- RefrTime();
- CurPosit();
- }
- }
- uchar IncBcdHigh(uchar dat, uchar n) //高位加
- {
- if ((dat&0xf0) < (n<<4))
- dat += 0x10;
- else
- dat &= 0x0f;
- return dat;
- }
- uchar IncBcdLow(uchar dat, uchar n) //低位加
- {
- if ((dat&0x0f) < n)
- dat += 0x01;
- else
- dat &= 0xf0;
- return dat;
- }
- uchar IncBcdWeek(uchar dat, uchar n) //星期加
- {
- if ((dat&0x0f) < n)
- dat += 0x01;
- else
- dat = 1;
- return dat;
- }
- void IncSetTime() //向上(加)
- {
- switch (pos)
- {
- case 1: buftime.year = IncBcdHigh(buftime.year,9); break;
- case 2: buftime.year = IncBcdLow(buftime.year,9); break;
- case 3: buftime.mon = IncBcdHigh(buftime.mon,1); break;
- case 4: buftime.mon = IncBcdLow(buftime.mon,9); break;
- case 5: buftime.day = IncBcdHigh(buftime.day,3); break;
- case 6: buftime.day = IncBcdLow(buftime.day,9); break;
- case 7: buftime.week = IncBcdWeek(buftime.week,7); break;
- case 8: buftime.hour = IncBcdHigh(buftime.hour,2); break;
- case 9: buftime.hour = IncBcdLow(buftime.hour,9); break;
- case 10: buftime.min = IncBcdHigh(buftime.min,5); break;
- case 11: buftime.min = IncBcdLow(buftime.min,9); break;
- case 12: buftime.sec = IncBcdHigh(buftime.sec,5); break;
- case 13: buftime.sec = IncBcdLow(buftime.sec,9); break;
- case 14: hourbee1 = IncBcdHigh(hourbee1,2); break;
- case 15: hourbee1 = IncBcdLow(hourbee1,9); break;
- case 16: minbee1 = IncBcdHigh(minbee1,5); break;
- case 17: minbee1 = IncBcdLow(minbee1,9); break;
- case 18: hourbee2 = IncBcdHigh(hourbee2,2); break;
- case 19: hourbee2 = IncBcdLow(hourbee2,9); break;
- case 20: minbee2 = IncBcdHigh(minbee2,5); break;
- case 21: minbee2 = IncBcdLow(minbee2,9); break;
- default: break;
- }
- RefrTime();
- CurPosit();
- }
- void EntertimeSet() //进入时间设置
- {
- pos = 21;
- RightShift();
- LcdCoorTwin(); //光标闪动
- }
- void KeyAction(uchar cod,bit set) //按键动作
- {
- switch(cod)
- {
- case 0: if (!set)
- {
- if (flag > 0) //闹钟延时显示状态下,则可以设置闹钟开关
- BeeOnroOff();
- pos = 0;
- SetTime(&buftime);
- LcdClsCur(); //光标闪动清除
- }
- else //进入设置
- {
- flag = 0; //延时显示时间清零
- EntertimeSet();
- }
- break;
- case 1: if (!set && (pos==0)) //非设置状态,显示闹钟1
- {
- keybee = 1;
- flag = 3; //延时6秒计算
- if (beeonoff1)
- {
- LcdShowStr(0,1,"*"); //显示闹钟标志
- }
- else
- {
- LcdShowStr(0,1," ");
- }
- RefrTime();
- }
- else if (pos!=0) //设置状态,数字移动
- {
- RightShift();
- }
- break;
- case 2: if (!set && (pos==0)) //非设置状态,显示闹钟2
- {
- keybee = 2;
- flag = 3; //延时6秒计算
- if (beeonoff2)
- {
- LcdShowStr(0,1,"*"); //显示闹钟标志
- }
- else
- {
- LcdShowStr(0,1," ");
- }
- RefrTime();
- }
- else if (pos!=0) //设置状态,数字加
- {
- IncSetTime();
- }
- break;
- }
- }
- void LedLigh(bit ledt) //背影灯开启
- {
- static bit ledflag = 0;
- static uint ledcou=0;
- if (ledt)
- {
- ledflag = 1;
- ledcou = 3000;
- LED = 0;
- }
- if (ledflag)
- {
- if (ledcou > 0)
- {
- ledcou--;
- }
- else
- {
- ledflag = 0;
- LED = 1;
- }
- }
- }
- void AlarmClock(bit on, bit beet) //闹钟发声 on 闹钟触发开关,beet为按键暂时关
- {
- static bit off = 0;
- static uchar alcou=0;
- if (on)
- {
- if (beet)
- off = 1;
- if (!off)
- {
- alcou++;
- if (alcou == 255)
- {
- alcou = 0;
- }
- if (alcou > 150)
- {
- BEE = ~BEE;
- }
- }
- else
- {
- BEE = 1;
- }
- }
- else
- {
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
所有资料51hei提供下载:
自制小型万年历.zip
(440.2 KB, 下载次数: 150)
|