电子时钟设计报告Word文档格式.docx
《电子时钟设计报告Word文档格式.docx》由会员分享,可在线阅读,更多相关《电子时钟设计报告Word文档格式.docx(24页珍藏版)》请在冰豆网上搜索。
方案2——基于DS1302的电子万年历设计
在以单片机为核心构成的装置中,经常需要一个实时的时钟和日历,以便对一些实时发生事件记录时给予时标,实时时钟芯片便可起到这一作用。
过去多用并行接口的时钟芯片,如MC146818,DS12887等。
它们已能完全满足单片机系统对实时时钟的要求,但是这些芯片与单片机接口复杂、占用地址,数据总线接线多、芯片体积大占用空间多、近年来串行接口的各种芯片在单片机系统中应用愈来愈多,串行接口的实时时钟芯片也出现了不少,DS1302是一个综合性能较好且价格便宜的串行接口实时时钟芯片。
利用单片机进行控制,采用DS1302作为实时时钟芯片,其三线接口SCLK、I/O、/RST与单片机进行同步通信,外加掉电存储电路、显示电路、键盘电路,即构成一个基本的电子万年历系统,若还要添加其他功能,在这基础上外扩电路即可。
由于在系统设计时,需要考虑以下几点因素:
功耗低、精确度高、软件编程较简单,芯片的体积小、芯片成本低等,而DS1302芯片有上面所述的诸多优点,所以本设计采用方案2。
2、系统设计与理论分析
2.1系统核心部分——ATmega16单片机
高性能、低功耗的8位AVR微处理器
先进的RISC结构
131条指令
大多数指令执行时间为单个时钟周期
32个8位通用工作寄存器
全静态工作
工作于16MHz时性能高达16MIPS
只需两个时钟周期的硬件乘法器
非易失性程序和数据存储器
16K字节的系统内可编程Flash,擦写寿命:
10,000次
具有独立锁定位的可选Boot代码区,通过片上Boot程序实现系统内编程,真正的同时读写操作
512字节的EEPROM,擦写寿命:
100,000次
1K字节的片内SRAM
可以对锁定位进行编程以实现用户程序的加密
JTAG接口(与IEEE1149.1标准兼容)
符合JTAG标准的边界扫描功能
支持扩展的片内调试功能
通过JTAG接口实现对Flash、EEPROM、熔丝位和锁定位的编程
ATMEGA16的管
2.2DS1302时钟电路
低功耗时钟芯片DS1302可以对年、月、日、时、分、秒进行计时,且具有闰年补偿等多种功能。
DS1302用于数据记录,特别是对某些具有特殊意义的数据点的记录上,能实现数据与出现该数据的时间同时记录。
这种记录对长时间的连续测控系统结果的分析以及对异常数据出现的原因的查找有重要意义。
采用DS1302作为记录测控系统中的数据记录,其软硬件设计简单,时间记录准确,既避免了连续记录的大工作量,又避免了定时记录的盲目性,给连续长时间的测量、控制系统的正常运行及检查都来了很大的方便,可广泛应用于长时间连续的测控系统中。
在测量控制系统中,特别是长时间无人职守的测控系统中,经常需要记录某些具有特殊意义的数据及其出现的时间。
记录及分析这些特殊意义的数据,对测控系统的性能分析及正常运行具有重要的意义。
传统的数据记录方式是隔时采样或定时采样,没有具体的时间记录,因此只能记录数据而无法准确记录其出现的时间;
若采用单片机计时,一方面需要采用计数器,占用硬件资源,另一方面需要设置中断、查询等,同样耗费单片机的资源,而且某些测控系统可能不允许。
而在系统中采用DS1302则能很好地解决这个问题
图3-4DS1302内部结构图
2.3液晶显示电路LCD1602
1602液晶也叫1602字符型液晶它是一种专门用来显示字母、数字、符号等的点阵型液晶模块它有若干个5X7或者5X11等点阵字符位组成,每个点阵字符位都可以显示一个字符。
每位之间有一个点距的间隔每行之间也有间隔起到了字符间距和行间距的作用,正因为如此所以他不能显示图形
(用自定义CGRAM,显示效果也不好)
n1602LCD是指显示的内容为16X2,即可以显示两行,每行16个字符液晶模块(显示字符和数字)。
n目前市面上字符液晶绝大多数是基于HD44780液晶芯片的,控制原理是完全相同的,因此基于HD44780写的控制程序可以很方便地应用于市面上大部分的字符型液晶。
1602采用标准的16脚接口,其中:
第1脚:
VSS为电源地
第2脚:
VDD接5V电源正极
第3脚:
V0为液晶显示器对比度调整端,接正电源时对比度最弱,接地电源时对比度最高(对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度)。
第4脚:
RS为寄存器选择,高电平1时选择数据寄存器、低电平0时选择指令寄存器。
第5脚:
RW为读写信号线,高电平
(1)时进行读操作,低电平(0)时进行写操作。
第6脚:
E(或EN)端为使能(enable)端。
第7~14脚:
D0~D7为8位双向数据端。
第15~16脚:
空脚或背灯电源。
15脚背光正极,16脚背光负极。
LCD1602模块电路
3、软件设计
3.1时间程序的设计
因为使用了时钟芯片DS1302,时间程序只需从DS1302各寄存器中读出年、周、月、日、[小]时、分、秒等数据,再处理即可。
在首次对DS1302进行操作之前,必须对它进行初始化,然后从DS1302中读出数据,再经过处理后,送给显示缓冲单元。
时间程序流程图
4、系统测试
4.1测试结果
设计完成后,给系统上电,液晶显示屏显示结果如图所示。
4.2误差分析
DS1302存在时钟精度不高,易受环境影响,出现时钟混乱等缺点。
DS1302可以用于数据记录,特别是对某些具有特殊意义的数据点的记录,能实现数据与出现该数据的时间同时记录。
这种记录对长时间的连续测控系统结果的分析及对异常数据出现的原因的查找具有重要意义。
传统的数据记录方式是隔时采样或定时采样,没有具体的时间记录,因此,只能记录数据而无法准确记录其出现的时间;
若采用单片机计时,一方面需要采用计数器,占用硬件资源,另一方面需要设置中断、查询等,同样耗费单片机的资源,而且,某些测控系统可能不允许。
5、结论
本设计硬件电路较简单,所用器件较少,电路中使用了ATMEGA16单片机、DS1302时钟芯片、LCD1602液晶显示器等主要芯片,实现了基本的显示时间与日期功能。
在对芯片的管脚功能和用法有充分的了解后,根据设计要求设计硬件电路,包括单片机控制电路、时钟电路、存储电路、键盘扫描电路、显示电路。
然后通过软件编程,实现了对年、月、日、时、分、秒、星期、闰年和阴历的自动调整,用按键进行控制,用液晶模块进行显示。
实时日历电子钟可以正常显示时间,基本完成了预期要实现的目标。
但是由于时间和技术有限,所做的作品暂时还不支持时间日期的调节,我们将会在以后通过更加努力的学习以完善作品!
(12),pp.20–36
7、附主要程序清单
********************************************
1602驱动程序
#defineLCDa_CTRLPORTD//1602控制端口定义
#defineLCDa_CTRL_DDRDDRD//控制端口方向寄存器定义
#defineLCDa_RSPD4//定义三个控制引脚
#defineLCDa_RWPD5
#defineLCDa_EPD6
#defineLCDa_L10x80//第一行的地址:
0x80+addr,addr为列数
#defineLCDa_L20xC0//第二行的地址:
0x80+0x40+addr
#defineLCDa_CGRAM_ADDR0x40//CGRAM的开始地址
#defineLCDa_CGMAX64//CGRAM存储的最大字节数
#defineLCDa_SET_RSLCDa_CTRL|=BIT(LCDa_RS)//三个控制管脚的控制操作
#defineLCDa_SET_RWLCDa_CTRL|=BIT(LCDa_RW)
#defineLCDa_SET_ELCDa_CTRL|=BIT(LCDa_E)
#defineLCDa_CLR_RSLCDa_CTRL&
=~BIT(LCDa_RS)
#defineLCDa_CLR_RWLCDa_CTRL&
=~BIT(LCDa_RW)
#defineLCDa_CLR_ELCDa_CTRL&
=~BIT(LCDa_E)
#defineLCDa_DOPORTB//输出数据总线端口定义
#defineLCDa_DIPINB//输入数据总线端口定义
#defineLCDa_DATA_DDRDDRB//数据总线方向寄存器定义
#defineLCDa_FUNCTION0x38//液晶模式为8位,2行,5*8字符
#defineiDat1//数据标志
#defineiCmd0//指令标志
#defineLCDa_CLS0x01//清屏
#defineLCDa_HOME0x02//地址返回原点,不改变DDRAM内容
#defineLCDa_ENTRY0x06//设定输入模式,光标加,屏幕不移动
#defineLCDa_C2L0x10//光标左移
#defineLCDa_C2R0x14//光标右移
#defineLCDa_D2L0x18//屏幕左移
#defineLCDa_D2R0x1C//屏幕又移
#defineLCDa_ON0x0C//打开显示
#defineLCDa_OFF0x08//关闭显示
#defineLCDa_CURON0x0E//显示光标
#defineLCDa_CURFLA0x0F//打开光标闪烁
/*******************************************
函数名称:
LCD1602_portini
功能:
初始化1602液晶用到的IO口
参数:
无
返回值:
/********************************************/
voidLCD1602_portini(void)
{
LCDa_CTRL_DDR|=BIT(LCDa_RS)|BIT(LCDa_RW)|BIT(LCDa_E);
//配置控制管脚为输出
LCDa_DATA_DDR|=0xFF;
//配置数据管脚为输出
}
LCD1602_readbyte
从1602液晶读出一个字节数据或者指令
DatCmd--为iDat时是数据,为iCmd时是指令
dByte--读回的数据或者指令
ucharLCD1602_readbyte(ucharDatCmd)
uchardByte;
if(DatCmd==iCmd)//指令操作
LCDa_CLR_RS;
else
LCDa_SET_RS;
LCDa_SET_RW;
//读操作
LCDa_SET_E;
LCDa_DATA_DDR=0x00;
//数据总线定义为输入
dByte=LCDa_DI;
//读数据或者指令
Delayms
(1);
//时序调整
LCDa_CLR_E;
LCDa_DATA_DDR|=0xff;
//数据总线还原为输出
returndByte;
LCD1602_sendbyte
向1602液晶写入一个字节数据或者指令
dByte--为写入1602的数据或者指令
voidLCD1602_sendbyte(ucharDatCmd,uchardByte)
LCDa_CLR_RW;
//写操作
LCDa_DO=dByte;
//写入数据
LCD1602_sendstr
向1602液晶写入一个字符串
ptString--字符串指针
voidLCD1602_sendstr(uchar*ptString)
while((*ptString)!
='
\0'
)//字符串未结束
{
LCD1602_sendbyte(iDat,*ptString++);
}
LCD1602_clear
1602液晶清屏
voidLCD1602_clear(void)
LCD1602_sendbyte(iCmd,LCDa_CLS);
Delayms
(2);
//清屏指令写入后,2ms的延时是很必要的!
!
LCD1602_readBF
busy--为1时忙,为0时可以接收指令
ucharLCD1602_readBF(void)
{
ucharbusy;
busy=LCD1602_readbyte(iCmd);
//读回BF标志和地址
if(busy&
0x80)//忙
busy=1;
else//不忙,可以写入
busy=0;
returnbusy;
LCD1602_gotoXY
移动到指定位置
Row--指定的行
Col--指定的列
voidLCD1602_gotoXY(ucharRow,ucharCol)
{
switch(Row)//选择行
case2:
LCD1602_sendbyte(iCmd,LCDa_L2+Col);
break;
//写入第2行的指定列
default:
LCD1602_sendbyte(iCmd,LCDa_L1+Col);
//写入第1行的指定列
LCD1602_initial
1602液晶初始化
voidLCD1602_initial(void)
Delayms(100);
//等待内部复位
LCD1602_portini();
//端口初始化
LCD1602_sendbyte(iCmd,LCDa_FUNCTION);
//功能、模式设定
while(LCD1602_readBF());
LCD1602_sendbyte(iCmd,LCDa_ON);
//打开显示
LCD1602_clear();
//清屏
LCD1602_sendbyte(iCmd,LCDa_ENTRY);
//输入模式设定
***************************************************
主程序
#include<
iom16v.h>
//包含型号头文件
macros.h>
//包含"
位"
操作头文件
#defineucharunsignedchar
#defineuintunsignedint
#defineTRUE1
#defineFALSE0
#include"
YJ1602.C"
//包含1602液晶函数文件
/******************RTC常量******************/
#defineRTC_CLKPB7
#defineRTC_DATAPB5
#defineRTC_CSPC7
//命令
#defineRD0x01
#defineWR0x00
#defineC_SEC0x80//秒
#defineC_MIN0x82//分
#defineC_HR0x84//时
#defineC_DAY0x86//日
#defineC_MTH0x88//月
#defineC_WK0x8A//星期DATE
#defineC_YR0x8C//年
#defineC_WP0x8E//控制(写保护)
#defineC_CHARGE0x90//涓流充电
#defineC_BURST0xBE//时钟多字节
//配置
#defineCLK_HALT0x80//停止时钟控制位SECONDbit7
#defineCLK_START0x00//启动时钟
#defineM12_240x80//12/24小时值选择位HOURbit7
#definePROTECT0x80//写保护控制位CONTROLbit7
#defineUPROTECT0x00//写保护控制位CONTROLbit7
//涓流充电控制常量
#defineTC_D1R20xA5//high1Diode+2KResistors
#defineTC_D2R80xAB//low2Diodes+8KResistors
#defineTC_DISABLED0x00//Disabled(TCS<
>
1010orDS=00orRS=00)
//RAM命令
#defineC_RAMBASE0xC0//RAM0~RAM30<
<
1地址需左移一位
voidDelayus(uintUS)
uinti;
US=US*5/4;
//5/4是在8MHz晶振下,通过软件仿真反复实验得到的数值
for(i=0;
i<
US;
i++);
voidDelayms(uintMS)
uinti,j;
MS;
i++)
for(j=0;
j<
1141;
j++);
//1141是在8MHz晶振下,通过软件仿真反复实验得到的数值
DS1302_init
初始化DS1302的数据接口
voidDS1302_portinit(void)
DDRB|=BIT(RTC_CLK)|BIT(RTC_DATA)|BIT(RTC_CS);
//将时钟端(RTC_CLK)数据端(RTC_DATA)片选端(RTC_CS)设置为输出
/******************