基于单片机的电子时钟和显示屏的设计 精品.docx
《基于单片机的电子时钟和显示屏的设计 精品.docx》由会员分享,可在线阅读,更多相关《基于单片机的电子时钟和显示屏的设计 精品.docx(41页珍藏版)》请在冰豆网上搜索。
基于单片机的电子时钟和显示屏的设计精品
1方案设计
1.1单片机电子时钟的背景
随着电子技术和计算机技术的迅速发展,单片机已经在工业过程控制、智能仪表、计算机集成控制、人工智能、通信设备的智能化以及家电的智能化等方面得到广泛的应用。
以单片机和微控制器为核心仍然是当今实现智能化技术的主流。
随着单片机技术广泛地应用与人们生活的各个方面,一些人们经常使用的产品大多数是基于单片机研发的,如电子时钟。
钟表从原来的沙漏计时和机械打点塔钟等演变到如今的电池驱动钟、交流钟、指针式石英电子钟表和数字式石英电子钟表,并且钟表的准确度越来越高了。
随着人们的时间观念逐渐地增强,时钟在我们人类的世界里扮演着一个非常重要的角色,几乎出现在我们生活的各个角落里,并且人们几乎离不开它了。
如今的时钟的功能更加全面,与机械时钟相比具有更高的正确性和直观性,且无机械装置,具有更长的寿命,因此广泛地应用于人类正常生活中,得到人们的关注和研发。
1.2电子时钟的意义
电子时钟采用数字电路实现对时、分、秒和数字显示的计时装置,广泛使用于个人家庭、车站、机场等公共场所,成为人们日常生活中不可缺少的必需品,给人们的生活、学习、工作、娱乐带来了极大的方便。
由于数字集成电路的发展和石英晶体振荡器的广泛应用,使得电子时钟的精度、稳定性大幅度提高。
现在的钟表的功能越来越强,具有定时自动报警、按时自动打铃、时间程序自动控制、定时广播、自动启闭路灯、定时开关烘箱、通断动力设备、甚至各种定时电气的自动启用等,因此,研究数字时钟及其扩展,有着重大意义。
1.3电子时钟的工作原理及其具体实现
电子时钟的工作原理是采用单片机最小系统,用DS1302时钟芯片和12864LCD液晶显示屏芯片以及DS18B20温度传感器分别进行寄存相关信息、显示年月日时分秒和采取温度,用四个键分别实现选择调整对象为、增加调节对象的数值、减少调节对象的数值和调整确定,采用24小时制、定时器0中断和外部中断0,从而实现可调式中文电子日历、温度及整点报时功能。
采用定时器0中断,定时50ms,其中断服务程序的功能是将时间和日期显示到LCD上。
每1s时间,刷新液晶显示屏上的秒钟数值;每60s时间,刷新显示屏的分钟数值;每60min时间,刷新显示屏的小时数值;每24h时间,刷新显示屏的日期;星期是通过年月日进行调整;温度是通过温度传感器芯片DS18B20进行调整;时钟每次到整点时,通过蜂鸣器进行整点报时。
采用外部中断0实现时钟的调整,将四个键通过“与门”连接单片机P3^2端口,从而通过键产生外部中断信号。
当要调整日期时间的时候,首先要按K1键来选择调整对象,否则按其他键不会进行时间调整,然后可以按K2和K3键对日期时间进行加减调整,最后按K4键可以将改动的日期时间重新显示到LCD上。
并且每次按下键后,都会通过蜂鸣器发出按键声音。
1.4设计任务
(1)可调式中文电子日历的硬件和软件设计;
(2)画出程序流程图;
(3)编写代码;
(4)程序分析与调试;
2电路方案设计
2.1模块一电路图
该模块主要通过DS1302时钟芯片实现计算秒、分、时、星期、日、月、年的信息,且具有闰年补偿的功能,其在proteus中的电路图如图2.1.1所示。
图2.1.1记录年月日秒分时星期的电路图
2.2模块二电路图
该模块主要通过12864LCD实现中文电子日历功能,其在proteus中的电路图如图2.2.1所示
图2.2.1显示时间电路图
2.3模块三电路图
该模块主要通过DS18B20温度传感芯片、四个键以及蜂鸣器实现温度采集,时间调节和闹钟等功能。
图2.3.1时间调整电路图
2.4总电路图
如图2.4.1所示。
图2.4.1总体硬件电路图
3程序设计
3.1主程序流程图
图3.1.1主函数流程图
3.2模块一DS1302流程图
图3.2.1获取当前时间的流程图
图3.2.2年月日时分秒++/--流程图
图3.2.3定时器0的中断服务程序
图3.2.4外部中断0服务程序
3.3模块二12864LCD流程图
图3.3.1LCD初始化流程图
图3.3.2通用显示函数流程图
3.4模块三DS18B20流程图
图3.41读取温度值
3.5源程序
#include
#include
#include
#defineucharunsignedchar
#defineuintunsignedint
sbitSDA=P1^0;/*DS1302数据线*/
sbitCLK=P1^1;/*DS1302时钟线*/
sbitRST=P1^2;/*DS1302复位线*/
sbitK1=P3^4;/*选择键*/
sbitK2=P3^5;/*加键*/
sbitK3=P3^6;/*减键*/
sbitK4=P3^7;/*确定键*/
sbitSPK=P2^6;
/*************子函数定义***************/
/*************显示年函数***************/
externvoidLCD_Initialize();/*液晶初始化函数*/
/*******读取温度值******/
externvoidRead_Temperature();
externvoidDisplay_Temperature();/*显示时间函数*/
externvoidDisplay_A_Char_8X16(ucharP,ucharL,ucha
*M)reentrant;/*显示年月日,星期,时分秒的固定汉字函数*/
externvoidDisplay_A_WORD(ucharP,ucharL,uchar*M)reentrant;
voidBeep();/*启动蜂鸣器函数*/
/*在调整日期时间时,用该位决定是否反白显示*/
externbitReverse_Display;
externucharDisplay_Digit[]={0,0,0,0};/*待显示的各温度数位*/
externbitDS18B20_IS_OK=1;/*传感器正常标志*/
/*********全局变量和数组定义*********/
uchartCount=0;
/*一年中每个月的天数,2月的天数由年份决定*/
ucharMonthsDays[]={0,31,0,31,30,31,30,31,31,30,31,30,31};
/*所读取的日期时间*/
ucharDateTime[7];
/*当前调整的时间对象:
秒,分,时,日,月,星期,年(0,1,2,3,4,5,6)变量*/
/*其中星期由年月日调整自动完成*/
charAdjust_Index=-1;
ucharH_Offset=10,V_Page_Offset=0;/*水平与垂直偏移变量*/
/*年月日,星期,时分秒汉字点阵16乘16*/
ucharcodeDATE_TIME_WORDS[]=
{
0x40,0x20,0x10,0x0C,0xE3,0x22,0x22,0x22,0xFE,0x22,0x22,0x22,0x22,0x02,0x00,0x00,0x04,0x04,0x04,0x04,0x07,0x04,0x04,0x04,0xFF,0x04,0x04,0x04,0x04,0x04,0x04,
0x00,/*年*/
0x00,0x00,0x00,0x00,0x00,0xFF,0x11,0x11,0x11,0x11,0x11,0xFF,0x00,0x00,0x00,
0x00,0x00,0x40,0x20,0x10,0x0C,0x03,0x01,0x01,0x01,0x21,0x41,0x3F,0x00,0x00,0x00,
0x00,/*月*/
0x00,0x00,0x00,0xFE,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0xFE,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x3F,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x3F,0x00,0x00,0x00,
0x00,/*日*/
0x00,0x00,0x00,0xBE,0x2A,0x2A,0x2A,0xEA,0x2A,0x2A,0x2A,0x2A,0x3E,0x00,
0x00,0x00,0x00,0x48,0x46,0x41,0x49,0x49,0x49,0x7F,0x49,0x49,0x49,0x49,0x49,0x41,0x40,
0x00,/*星*/
0x00,0x04,0xFF,0x54,0x54,0x54,0xFF,0x04,0x00,0xFE,0x22,0x22,0x22,0xFE,0x00,0x00,0x42,0x22,0x1B,0x02,0x02,0x0A,0x33,0x62,0x18,0x07,0x02,0x22,0x42,0x3F,0x00,0x00,/*期*/
0x00,0xFC,0x44,0x44,0x44,0xFC,0x10,0x90,0x10,0x10,0x10,0xFF,0x10,0x10,0x10,0x00,0x00,0x07,0x04,0x04,0x04,0x07,0x00,0x00,0x03,0x40,0x80,0x7F,0x00,0x00,0x00,
0x00,/*时*/
0x80,0x40,0x20,0x98,0x87,0x82,0x80,0x80,0x83,0x84,0x98,0x30,0x60,0xC0,0x40,
0x00,0x00,0x80,0x40,0x20,0x10,0x0F,0x00,0x00,0x20,0x40,0x3F,0x00,0x00,0x00,0x00,0x00,/*分*/
0x12,0x12,0xD2,0xFE,0x91,0x11,0xC0,0x38,0x10,0x00,0xFF,0x00,0x08,0x10,0x60,0x00,0x04,0x03,0x00,0xFF,0x00,0x83,0x80,0x40,0x40,0x20,0x23,0x10,0x08,0x04,0x03,
0x00,/*秒*/
0x10,0x21,0x86,0x70,0x00,0x7E,0x4A,0x4A,0x4A,0x4A,0x4A,0x7E,0x00,0x00,
0x00,0x00,0x02,0xFE,0x01,0x40,0x7F,0x41,0x41,0x7F,0x41,0x41,0x7F,0x41,0x41,0x7F,0x40,
0x00,/*温*/
0x00,0x00,0xFC,0x04,0x24,0x24,0xFC,0xA5,0xA6,0xA4,0xFC,0x24,0x24,0x24,
0x04,0x00,0x80,0x60,0x1F,0x80,0x80,0x42,0x46,0x2A,0x12,0x12,0x2A,0x26,0x42,0xC0,0x40,0x00,/*度*/};
/*星期几的汉字点阵16乘16*/
ucharcodeWEEKDAY_WORDS[]={
0x00,0x00,0x00,0xFE,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0xFE,0x00,0x00,0x00,
0x00,
0x00,0x00,0x00,0x3F,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x3F,0x00,0x00,0x00,
0x00,/*日*/
0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xC0,0x80,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,/*一*/
0x00,0x00,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x06,0x04,0x00,0x00,
0x00,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x18,0x10,
0x00,/*二*/
0x00,0x04,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x04,0x00,
0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
0x00,/*三*/
0x00,0xFE,0x02,0x02,0x02,0xFE,0x02,0x02,0xFE,0x02,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,0x7F,0x28,0x24,0x23,0x20,0x20,0x20,0x21,0x22,0x22,0x22,0x22,0x7F,0x00,
0x00,/*四*/
0x00,0x02,0x82,0x82,0x82,0x82,0xFE,0x82,0x82,0x82,0xC2,0x82,0x02,0x00,0x00,
0x00,0x20,0x20,0x20,0x20,0x20,0x3F,0x20,0x20,0x20,0x20,0x3F,0x20,0x20,0x30,0x20,
0x00,/*五*/
0x10,0x10,0x10,0x10,0x10,0x91,0x12,0x1E,0x94,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x40,0x20,0x10,0x0C,0x03,0x01,0x00,0x00,0x01,0x02,0x0C,0x78,0x30,0x00,0x00,/*六*/
};
/*半角数字点阵8乘16*/
ucharcodeDIGITS[]=
{
0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,
0x00,/*0*/0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,
0x00,/*1*/0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,
0x00,/*2*/0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x11,0x0E,
0x00,/*3*/0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,0x24,
0x00,/*4*/0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,
0x00,/*5*/0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,
0x00,/*6*/0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,
0x00,/*7*/0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,
0x00,/*8*/0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x00,0x31,0x22,0x22,0x11,0x0F,
0x00,/*9*/
};
/*生日快乐歌的音符频率表,不同的频率由不同的延时值来决定*/
ucharcodeSONG_TONE[]=
{
212,212,190,212,159,169,212,212,190,212,142,159,212,212,106,126,159,169,190,119,119,126,159,142,159,0
};
/*生日快乐歌节拍表,节拍表决定了每个音符的演奏长短*/
ucharcodeSONG_LONG[]=
{
9,3,12,12,12,24,9,3,12,12,12,24,
9,3,12,12,12,12,12,9,3,12,12,12,24,0
};
voidDelayMS(uintx)/*调用延时子函数*/
{
uchari;
while(x--)for(i=0;i<120;i++);
}
voidPlayMusic()/*音乐播放函数*/
{
uinti=0,j,k;
while(SONG_LONG[i]!
=0||SONG_TONE[i]!
=0)
{
/*播放各个音符,SONG_LONG为拍
*/for(j=0;j{
SPK=~SPK;
/*SONG_TONE延时表决定了每个音符的频率*/
for(k=0;k}
DelayMS(100);
/*下一个音符的索引*/
i++;
}
}
voidAlarm(uchart)/*温度报警函数*/
{
uchari,j;
for(i=0;i<200;i++)
{
SPK=~SPK;
/*由参数t形成不同的频率*/
for(j=0;j}
}
/*向DS1302写入一字节*/
voidWrite_A_Byte_TO_DS1302(ucharx)
{
uchari;
for(i=0;i<8;i++)
{
SDA=x&1;CLK=1;CLK=0;x>>=1;
}
}
/*从DS1302读取一字节*/
ucharGet_A_Byte_FROM_DS1302()
{
uchari,b,t;
for(i=0;i<8;i++)
{
b>>=1;t=SDA;b|=t<<7;CLK=1;CLK=0;
}
/*BCD码转换*/
return(b/16*10+b%16);
}
/*从DS1302指定位置读数据*/
ucharRead_Data(ucharaddr)
}
uchardat;
RST=0;CLK=0;RST=1;
Write_A_Byte_TO_DS1302(addr);
dat=Get_A_Byte_FROM_DS1302();
CLK=1;RST=0;
returndat;
}
/*向DS1302某地址写入数据*/
voidWrite_DS1302(ucharaddr,uchardat)
{
CLK=0;RST=1;
Write_A_Byte_TO_DS1302(addr);
Write_A_Byte_TO_DS1302(dat);
CLK=1;RST=0;
}
/*设置时间*/
voidSET_DS1302()
{
uchari;
Write_DS1302(0x8E,0x00);/*秒分时日月年依次写入*/
for(i=0;i<7;i++)
{
/*秒,分,时,日,月,星期,年的起始地址分别为0x80,0x82,0x84,0x86,0x88,0x8A,0x8C*/Write_DS1302(0x80+2*i,(DateTime[i]/10<<4)|(DateTime[i]%10));
}
Write_DS1302(0x8E,0x80);
}/*读取当前时间*/
voidGetTime()
{
uchari;
for(i=0;i<7;i++)
{
DateTime[i]=Read_Data(0x81+2*i);
}
}
ucharisLeapYear(uinty)/*判断是否为闰年*/
{
return(y%4==0&&y%100!
=0)||(y%400==0);
}
/*********刷新星期******/
voidRefreshWeekDay()
{
uinti,d,w=5;/*已知1999.12.31是周五*/
for(i=2000;i<2000+DateTime[6];i++)
{
d=isLeapYear(i)?
366:
365;
w=(w+d)%7;
}
d=0;
for(i=1;id+=DateTime[3];
/*保存星期,0~6表示星期日,星期一,二,三,四,五,六,为了与DS1302的星期格式匹配,返回值需要加1*/
DateTime[5]=(w+d)%7+1;
}/*蜂鸣器函数*/
voidBeep(uchart)
{
uchari;
for(i=0;i<100;i++)
{
SPK=~SPK;DelayMS(t);
}
SPK=0;
}
voidDateTime_Adjust(charx)/*年月日时分++或--*/
{
switch(Adjust_Index)
{
case6:
/*年00-99*/
if(x==1&&DateTime[6]<99)DateTime[6]++;
if(x==-1&&DateTime[6]>0)DateTime[6]--;/*获取2月天数*/
MonthsDays[2]=isLeapYear(2000+DateTime[6])?
29:
28;
/*如果年份变化后当前月份的天数大于上限则设为上限*/
if(DateTime[3]>MonthsDays[DateTime[4]])
DateTime[3]=MonthsDays[DateTime[4]];
RefreshWeekDay();/*刷新星期*/
break;
case4:
/*月01至12*/
if(x==1&&DateTime[4]<12)
DateTime[4]++;
if(x==-1&&DateTime[4]>1)
DateTime[4]--;/*获取2月天数*/
MonthsDays[2]=isLeapYear(2000+DateTime[6])?
29:
28;
/*如果年份变化后当前月份的天数大于上限则设为上限*/
if(DateTime[3]>MonthsDays[DateTime[4]])DateTime[3]=MonthsDays[DateTime[4]];
RefreshWeekDay();/*刷新星期*/
break;
case3:
/*日00至28/29/30/31;调节之前首先根据年份得出该年中2月的天数*