基于AVR单片机的电子闹钟设计.docx
《基于AVR单片机的电子闹钟设计.docx》由会员分享,可在线阅读,更多相关《基于AVR单片机的电子闹钟设计.docx(38页珍藏版)》请在冰豆网上搜索。
基于AVR单片机的电子闹钟设计
基于AVR单片机的
数字电子闹钟设计
此处按务老师要求填写即可
摘要
本文主要讲述基于AVR单片机的数字电子闹钟,能够显示年月日时分秒,具备闰年平年补偿及闹铃功能。
时钟信号源采用单片机内部定时器中断实现,该系统原理简单,成本低廉,操作简单。
控制核心为Atmel公司的AVR高性能单片机,程序基于C语言开发,可读性强。
显示核心为字符液晶LCD1602,显示效果稳定。
输入模块为6个独立式按键,可操作性强,便于使用。
关键词:
AVR单片机、LCD1602、数字电子闹钟
Abstract
ThispapermainlydescribedthedigitalelectronicbasedonAVRmicrocontrollerabletodisplaywhenthealarmclock,dateofFebruaryalone,havealeapyearprovidescompensationandalarmfunction.Theclocksignalsourceadoptssinglechipinternaltimerinterruptachieve,thissystemtheoryissimple,lowcost,simpleoperation.AtmelcompanycontrolcorefortheAVRhigh-performancesinglechipmicrocomputerbasedonClanguage,programdevelopment,readable.ShowLCD1602coretocharactersLCDdisplayeffect,stable.Inputmoduleforsixindependenttypekey,themaneuverabilityisstrong,easytouse.
Keywords:
AVRmicrocontroller,LCD1602,digitalelectronicalarmclock
一系统构造
根据系统设计要求,本设计由电源模、用户设置键盘、报警模块、显示模块组成,形成实时时钟系统。
总体的框图如下:
方案论证
一.1单片机的的选择:
方案一:
使用功能较为简单的89C51单片机作为控制器,其优点是价格便宜。
但是功能相对较为简单,烧录比较复杂,不便于程序调试。
方案二:
使用功能齐全的ATMEGA16单片机作为控制器,内部资源多,价格相对51稍贵,程序烧录容易,便于系统调试。
根据我们设计的实际要求,我需要一个性能较高,稳定性好的单片机,我们选择了ATMEGA16单片机实现设计。
一.2电源模块
方案一:
使用具有反馈保护的集成开关电源芯片LM2575,其能够提供1A的稳定5V电源输出,发热量少;但是外围电路比较复杂,价格较高。
常用于电源能耗相对较高,发热量少的系统中。
方案二:
使用三端集成稳压芯片LM7805,其输出电流为1A,但是经过测试知道,芯片输出电压在500mA发热量较小,超过500mA发热量较大,不能运用于功耗较大的电路中。
但是其外围电路简单,价格便宜,比较适合小功率电路使用。
经分析,由于系统中使用的是低功耗的8位单片机,能耗较高的是液晶显示器。
但是总电流不超过500mA。
综上我选择使用三端集成稳压芯片LM7805。
一.3时钟信号源;
方案一:
采用单片机内部定时器实现时钟,不需要外接芯片,成本较低,但是时间精度不高,时间掉电会丢失,只适合一般场合使用;
方案二:
使用时钟芯片DS1302作为时钟源,该芯片断电后需要通过外接电池或者电容供电,因此电路相对比较复杂,成本也较高。
结合我们使用的实际情况,我们一般要求时钟精度不是很高,只用于一般使用,故选择成本较低的方案一实现。
一.4显示器
方案一:
使用数码管扫描,显示效果一般,只能显示数字,显示效果单一,不易于使用。
方案二:
使用LCD1602液晶显示,可以显示一些字符,显示效果较好,易于使用。
综上,我们考虑到用户的使用方便,选择用LCD1602作为显示终端。
一.5报警
方案一:
通过使用语音芯片实现语音播报来实现报时和闹钟功能。
但是接口比较麻烦,同时需要录音和实现地址检索。
方案二:
通过三极管控制蜂鸣器发出BEEP声报警,电路简单,价格便宜。
比较适合我们这个设计的使用。
二硬件电路:
二.1电源电路设计
使用LM7805制作的5V系统稳压电源可以满足系统电源的使用,电路构造简单。
在电源输入端有两个滤波电容,处理输入电源的纹波,输出端根据负载使用470uF的电容可以满足输出电流的纹波滤除。
其中D3为电源信号指示灯。
D1为稳压芯片保护,防止突然断电,导致稳压芯片的损坏,D2在电路中实现了反向保护功能,防止输入电源方向接反导致了电源模块损坏。
二.2按键输入模块
使用六个按键设计,分别为闹钟/时钟切换键,设置键,修改切换键,加,减,确认。
人性化设计,将调节按键分开,使用加、减键分离,更加便于调试。
二.3控制器最小系统:
系统使用ATmega16L作为系统主控芯片,主要接受到按键设置信号。
对报警蜂鸣器和显示器做出相应控制。
单片机不断的扫描按键信息,通过LCD显示时钟和实现设置、闹钟的功能。
二.4显示模块:
使用1602液晶的4线控制方法,减少端口使用,提高硬件资源的充分利用。
偏置电压使用RP1对电源分压输入,可以对液晶对比度进行调节。
4线控制需要对一个字节的数据分两次写入液晶,所以在程序设计中每个字节需要使用2次传输完成。
二.5报警电路设置:
使用PNP三极管驱动蜂鸣器报警。
当单片机输出为低电平时,三级管导通,蜂鸣器发声报警。
这样设计的原因在于,AVR单片机在上电时的电平输出为高电平,这样可以防止在单片机上电时发出蜂鸣声。
三程序设计框图:
三.1主流程图:
三.2按键设置程序:
四液晶屏驱动:
四.1模块说明:
1602引脚说明
主要技术参数:
四.2通信时序图
读时序
写时序
4线式数据传送共分两次实现一个字节数据的传输。
时序参数
四.3字符显示坐标
五AVR定时器CTC模式介绍
CTC(比较匹配时清零定时器)模式
本设计的时间采用AVR单片机内部定时器0的CTC模式实现。
六系统调试
经过分阶段的调试,成功完成系统的调试。
六.1可以显示时间
六.2调节时间
六.3系统整体运行正常。
a.开机正常显示初始化时间2011年5月14号星期一,00:
00:
00闹铃关。
b.通过按键可以设置时间和闹钟。
c.闹钟响起时按下除功能键、设置键外其他键,闹钟停止。
d.显示信息正常。
七附录
七.1电路总图
七.2全部程序
#include
#definebeePORTB.0
#include
#include
ints,year;
intsec,min,hour,date,month,xuanze,flog,flog1,week;
intsec0,min0,hour0,bee_0,bee_turn;
unsignedcharkey,moshi;
unsignedcharkey_scan();
unsignedconstdate_run[12]={31,28,31,30,31,30,31,31,30,31,30,31};//闰年月份
unsignedconstdate_pin[12]={31,29,31,30,31,30,31,31,30,31,30,31};//平年月份
unsignedcharleapyear(intyear1);
unsignedcharbee_clock();
interrupt[TIM0_COMP]voidtimer0_comp_isr(void)
{
unsignedchartemp,temp1,tt;
s++;
if(s==1000)
{
s=0;
sec++;
tt=bee_clock();
if(bee_turn)
{
if(tt==1)
{
bee=0;
bee_0=1;
}
}
if(bee_0>0)
{
bee_0++;
if(bee_0==20)
{
bee=1;
bee_0=0;
}
}
if(sec==60)
{
sec=0;
min++;
if(min==60)
{
min=0;
hour++;
if(hour==24)
{
hour=0;
temp=leapyear(year);
if(temp==0)
{
temp1=date_pin[month+1];
}
if(temp==1)
{
temp1=date_run[month+1];
}
date++;
week++;
if(week==8)
{
week=1;
}
if(date==temp1)
{
date=0;
month++;
if(month==13)
{
month=0;
year++;
if(year==2099)
{
year=1899;
}
}
}
}
}
}
}
}
unsignedcharleapyear(intyear1)//判断某年是否闰年闰年返回1,平年返回0
{
if((year1%400==0)||(year1%100!
=0)&&(year1%4==0))
return1;
else
return0;
}
voidguangbaioshanshuo()//光标闪烁函数
{
switch(xuanze)
{
case0:
lcd_gotoxy(14,1);_lcd_write_data(0x0d);break;
case1:
lcd_gotoxy(9,1);_lcd_write_data(0x0d);break;
case2:
lcd_gotoxy(6,1);_lcd_write_data(0x0d);break;
case3:
lcd_gotoxy(3,1);_lcd_write_data(0x0d);break;
case4:
lcd_gotoxy(14,0);_lcd_write_data(0x0d);break;
case5:
lcd_gotoxy(10,0);_lcd_write_data(0x0d);break;
case6:
lcd_gotoxy(7,0);_lcd_write_data(0x0d);break;
case7:
lcd_gotoxy(4,0);_lcd_write_data(0x0d);break;
}
}
voiddisplay_0()
{
chari;
unsignedchardis[2];
lcd_gotoxy(4,0);
lcd_putsf("Alarm");
//显示时
dis[0]=hour0/10;
dis[1]=hour0%10;
lcd_gotoxy(2,1);
for(i=0;i<2;i++)
{
lcd_putchar(dis[i]+'0');
}
lcd_putchar(':
');
//显示分
dis[0]=min0/10;
dis[1]=min0%10;
lcd_gotoxy(5,1);
for(i=0;i<2;i++)
{
lcd_putchar(dis[i]+'0');
}
lcd_putchar(':
');
//显示秒
dis[0]=sec0/10;
dis[1]=sec0%10;
lcd_gotoxy(8,1);
for(i=0;i<2;i++)
{
lcd_putchar(dis[i]+'0');
}
lcd_gotoxy(12,1);
switch(bee_turn)
{
case0:
lcd_putsf("off");break;
case1:
lcd_putsf("on");break;
}
}
voiddisplay()
{
chari;
unsignedchardis[4];
//显示年
dis[0]=year/1000;
dis[1]=year%1000/100;
dis[2]=year%1000%100/10;
dis[3]=year%1000%100%10;
lcd_gotoxy(1,0);
for(i=0;i<4;i++)
{
lcd_putchar(dis[i]+'0');
}
lcd_putchar('-');
//显示月份
dis[0]=month/10;
dis[1]=month%10;
lcd_gotoxy(6,0);
for(i=0;i<2;i++)
{
lcd_putchar(dis[i]+'0');
}
lcd_putchar('-');
//显示日期
dis[0]=date/10;
dis[1]=date%10;
lcd_gotoxy(9,0);
for(i=0;i<2;i++)
{
lcd_putchar(dis[i]+'0');
}
lcd_gotoxy(12,0);
switch(week)
{
case1:
lcd_putsf("Mon");break;
case2:
lcd_putsf("Tues");break;
case3:
lcd_putsf("Wed");break;
case4:
lcd_putsf("Thur");break;
case5:
lcd_putsf("Fri");break;
case6:
lcd_putsf("Sat");break;
case7:
lcd_putsf("Sun");break;
}
//显示时
dis[0]=hour/10;
dis[1]=hour%10;
lcd_gotoxy(2,1);
for(i=0;i<2;i++)
{
lcd_putchar(dis[i]+'0');
}
lcd_putchar(':
');
//显示分
dis[0]=min/10;
dis[1]=min%10;
lcd_gotoxy(5,1);
for(i=0;i<2;i++)
{
lcd_putchar(dis[i]+'0');
}
lcd_putchar(':
');
//显示秒
dis[0]=sec/10;
dis[1]=sec%10;
lcd_gotoxy(8,1);
for(i=0;i<2;i++)
{
lcd_putchar(dis[i]+'0');
}
lcd_gotoxy(12,1);
switch(bee_turn)
{
case0:
lcd_putsf("off");break;
case1:
lcd_putsf("on");break;
}
}
voidadjust(unsignedchari,unsignedcharj)//切换修改i为选择位j为加或减判断
{
inttemp1;//临时变量用于计算日期的上限
switch(i)
{
case1:
//调秒
{
if(j==0)
{
sec++;
if(sec>=60)
{
sec=0;
}
else
{
}
}
else
{
sec--;
if(sec<=0)
{
sec=59;
}
}
break;
}
case2:
{
if(j==0)
{
min++;
if(min>=60)
{
min=0;
}
else
{
}
}
else
{
min--;
if(min<0)
{
min=59;
}
}
break;
}
case3:
{
if(j==0)
{
hour++;
if(hour>=24)
{
hour=0;
}
else
{
}
}
else
{
hour--;
if(hour<0)
{
hour=23;
}
}
break;
}
case4:
{
if(j==0)
{
week++;
if(week>7)
{
week=1;
}
else
{
}
}
else
{
week--;
if(week<1)
{
week=7;
}
}
break;
}
case5:
{
if(j==0)
{
date++;
temp1=leapyear(year);
if(temp1==0)
{
if(date>date_pin[month+1])
{
date=0;
}
else
{
}
}
else
{
if(date>date_run[month+1])
{
date=0;
}
else
{
}
}
}
else
{
date--;
if(date<=0)
{
temp1=leapyear(year);
if(temp1==0)
{
date=date_pin[month+1];
}
else
{
date=date_run[month+1];
}
}
}
break;
}
case6:
{
if(j==0)
{
month++;
if(month>=12)
{
month=1;
}
else
{
}
}
else
{
month--;
if(month<1)
{
month=12;
}
}
break;
}
case7:
{
if(j==0)
{
year++;
if(year>=2099)
{
year=1899;
}
else
{
}
}
else
{
year--;
if(year<1899)
{
year=2099;
}
}
break;
}
}
lcd_clear();
display();
}
voidadjust_0(unsignedchari,unsignedcharj)//切换修改i为选择位j为加或减判断
{
switch(i)
{
case0:
{
if(bee_turn)
{
bee_turn=0;
}
else
{
bee_turn=1;
}
break;
}
case1:
//调秒
{
if(j==0)
{
sec0++;
if(sec0>=60)
{
sec0=0;
}
else
{
}
}
else
{
sec0--;
if(sec0<=0)
{
sec0=59;
}
}
break;
}
case2:
{
if(j==0)
{
min0++;
if(min0>=60)
{
min0=0;
}
else
{
}
}
else
{
min0--;
if(min0<0)
{
min0=59;
}
}
break;
}
case3:
{
if(j==0)
{
hour0++;
if(hour0>=24)
{
hour0=0;
}
else
{
}
}
else
{
hour0--;
if(hour0<0)
{
hour0=23;
}
}
break;
}
}
lcd_clear();
display_0();
}
voidclock()
{
display();
key=key_scan();
switch(key)
{
case1:
//时钟闹铃
{
moshi=1;
flog=0;
break;
}
case2:
//设置
{
flog1=1;
xuanze=1;
guangbaioshanshuo();
TIMSK=0x00;
while(flog1)
{
key=key_scan();
switch(key)
{
case3:
//切换
{
xuanze++;
if(xuanze==8)
{
xuanze=1;
}
guangbaioshanshuo();
break;
}
case4:
//加
{
adjust(xuanze,0);
guangbaioshanshuo();
break;
}
case5:
//减
{
adjust(xuanze,1);
guangbaioshanshuo();
break;
}
case6:
//确认
{
flog1=0;
TIMSK=0x02;
_lcd_write_data(0x0c);
break;
}
}
}
break;
}
case3:
case4:
case5:
case6:
{
if(bee_0!
=0)
{
bee=1;
bee_0=0;
}
break;
}
}
}
voidalarm_clock()
{
display_0();
key=key_scan();
switch(key)
{
case1:
//时钟闹铃
{
moshi=0;
flog=0;
break;
}
case2:
//设置
{
flog1=1;
xuanze=0;
guangbaios