智能仪表综合训练设计说明书
题 目:基于DS1302的数字电子钟设计
学生姓名:曾晔
学 号:0867112305
专 业:测控技术与仪器
班 级:2008-3
指导教师:肖俊生
摘要
现代社会的快节奏生活要求人们对时间的掌握越来越精确,随着计算机在社会领域的渗透和大规模集成电路的发展,单片机的应用正在逐步地深入,电子钟也逐渐取代传统钟表被广泛应用于生活和工作中。电子时钟主要是利用电子技术将时钟电子化、数字化,拥有时间精确、体积小、界面友好、可扩展性能强等特点。
本设计以STCC52RC芯片作为核心,MAX7219LED显示和DS1302时钟芯片主要组成来实现电子钟的基本功能,用DS1302芯片来取得相应的时钟信号数据经由单片机STCC52RC处理输送给MAX7219芯片转化为对应的LED显示,除了显示模块外本设计还设计了一个时间调整程序使得电子钟可以更加人性化的自由调整时间,本设计还分析了相应软件的设计要点,包括软件设计流程和硬件设计过程。
关键词 电子钟;STCC52RC单片机;DS1302;MAX7219
目录
前 言 3
第二章 总体方案设计 4
2.1 设计概要 4
2.2 DS1302的设计思想 4
2.3 MAX7219的设计思想 4
2.3 键盘扫描程序的设计思想 4
第三章 硬件设计 5
3.1 设计大概 5
3.2 键盘电路设计 5
3.3晶振电路 5
3.5 MAX7219 LED显示 8
3.5.1 概述 8
3.5.2 时序图 9
3.5.3 串行地址格式 9
第四章 软件设计 11
3.1 系统结构图及总流程图 11
3.2 主程序模块 11
3.2.1 初始化模块 11
3.2.2 DS1302读写模块 12
3.2.3 显示模块 14
3.2.5 主程序流程图 14
3.3 中断调整模块 15
3.3.1 时间中断模块 15
参考文献 17
附录一 硬件仿真原理图 19
附录二 C语言程序 20
前 言
电子钟已成为人们日常生活中的必需品,广泛应用于家庭、车站、办公室等场所。研究数字钟及扩大其应用有着非常现实的意义。
数字电子钟设计与制作可以采用单片机来完成。用单片机来设计制作完成,由于其功能的实现主要通过软件编程来完成,降低了硬件电路的复杂性,成本也有所降低同时,若采用单片机计时,一方面需要采用计数器,占用硬件资源,另一方面需要设置中断、查询等,同样耗费单片机的资源,而且,某些测控系统可能不允许。但是,如果在系统中采用时钟芯片,则能很好地解决这个问题。现在流行的串行时钟电路很多,如DS1302、DS1307等。这些电路的接口简单、价格低廉、使用方便,被广泛地采用。美国Dallas公司生产的串行实时时钟芯片 DS1302是一种具有涓细电流充电能力的实时时钟芯片,采用普通32.768KHZ晶振,具有实时时钟和 31 字节的静态RAM。主要特点是采用串行数据传输,可方便地与单片机接口,可为掉电保护电源提供可编程的充电功能,并且可以关闭充电功能。
本设计要求利用51单片机和DS1302设计制作一个LED电子钟,用8个LED显示时间
第二章 总体方案设计
2.1 设计概要
本次设计主要是通过单片机从DS1302芯片里读取时钟信号然后发给MAX7219显示,透过按键的改变来修改寄存器内的数据然后写入DS1302芯片之后再次读取来实现电子钟的实时调整,本设计主要是关于DS1302数据的读取和写入、单片机和MAX7219之间信号传输的转换、按键的响应和MAX7219LED显示的问题。
2.2 DS1302的设计思想
本设计的DS1302的设计主要体现在DS1302的数据读取与写入过程中,单片机先对DS1302发送控制字设置时间的格式并指向相应时间寄存器为发送数据准备,写入数据亦然。读取和写入数据时是一位一位进行的这需要一个循环程序进行相应操作,其中DS1302储存的数据类型是BCD码送到单片机内时是需要进行BCD码转换的。
2.3 MAX7219的设计思想
在电子表中max7219是一个比较关键的部分没有这个部分是无法显示的,在运行之前需要对其数据读取方式进行设置由于BCD码已经经过前一步程序的处理所以选择为全译码方式,这次的显示做成动态显示比较合适。
2.3 键盘扫描程序的设计思想
键盘扫描程序主要是针对时间的修改而做,其中也涉及了显示的情况在修改时间的时候需要显示是哪一位正在被修改,使得键盘扫描程序成为一个重要的部分,必须有调节模式键和修改键这些部件。
第三章 硬件设计
3.1 设计大概
该设计以STCC52RC单片机为中心,分别设计了键盘电路、晶振电路、LED显示电路和DS1302时钟电路。
3.2 键盘电路设计
该设计总共设计了三个的按键即功能键、增加键,减小键,分别与单片机的P1^4 ,P1^5, P1^6连接,并且做了一个清零键,这些键用来进行时间和日期的设置,采用中断方式输入键操作信息。按键输入的信号会通过相应的端口进行传输,最后由LED显示出来,如下图3.1显示。
图3.1 键盘电路图
3.3晶振电路
设计过程中对键盘按键进行处理的过程中需要用到延时故需要一个产生时间的装置。
本设计采用内部时钟方式,利用芯片内部的震荡电路,在X1、X2引脚上外接定时元件,内部的震荡电路变会产生自激震荡。本设计采用最常用的内部时钟方式,即用外接晶体和电容组成的并联谐振回路。震荡晶体选择可在1.2MHZ到12MHZ之间选择。电容值无严格要求,但电容取值对震荡频率输出的稳定性、大小、震荡电路起震速度有少许影响,C1、C2可在20pF到100pF之间取值,但在60pF到70pF时震荡器会有较高的频率稳定性。所以在本设计中,震荡晶体选择11.0592MHZ,电容选择30pF,如下图3.2晶振电路所示。
图3.2晶振电路图
3.4 DS1302时钟电路
图3.3 DS1302电路图
DS1302的电路和单片机SCLK、RST等端口相接而且需要自接一个时钟震荡电路来产生信号。电路图如上图3.3所示。
3.4.1 DS1302控制字节及寄存器
DS1302的一次数据传送是从发送控制字节开始的。控制字节的最高有效位(位7)必须是逻辑1,如果该位为0,则无法把数据写入到DS1302中;位6表示要读写的数据类型,为0表示存取日历时钟数据,为1表示存取 RAM数据;位5至位1指示要操作单元的地址;最低有效位(位 0)表示命令类型,为0表示要进行写操作,为 1 表示要进行读操作。控制字节总是从最低位开始输出。其控制字节格式如图2-4所示。
图3.4 控制字节格式
对DS1302的操作就是对其内部寄存器的操作,DS1302内部共有12个寄存器,其中有7个寄存器与日历、时钟有关,存放的数据位为BCD码形式。
表3-1 DS1302的日历时钟寄存器及控制字
3.4.2 数据的传送
向 DS1302 写入数据时,数据在控制字节输入后的下一个 SCLK周期的上升沿被写入,多余的 SCLK将被忽略。数据写入时从低位(位0)开始;同样,从DS1302 读取数据时,数据在紧跟控制字节后的下一个 SCLK的下降沿读出,读出数据时也是从低位(0位)到高位(7 位),只要RST保持高电平,额外的 SCLK将导致数据字节的持续读出,这个特性用于实现该芯片的突发读模式。
对DS1302 的每一次读写需 16个时钟脉冲,前 8 个脉冲输入操作地址和读写命令,后8个脉冲写入或读出数据。数据传送时序如图3.5。
图3.5 数据读写时序图
3.5 MAX7219 LED显示
3.5.1 概述
MAX7219是一种集成化的串行输入/输出共阴极显示驱动器,它连接微处理器
与8位数字的7段数字LED显示,也可以连接条线图显示器或者个的LED。其上包括一个片上的B型BCD编码器、多路扫描回路,段字驱动器,而且还有一个8*8的静态RAM用来存储每一个数据。只有一个外部寄存器用来设置各个LED的段电流。
MAX7219同样允许用户对每一个数据选择编码或者不编码。整个设备包含一个150μA的低功耗关闭模式,模拟和数字亮度控制,一个扫描寄存器允许用户显示1-8位数据,还有一个让所有LED发光的检测模式。电路图如下图3.6所示。
图3.6 LED显示电路图
3.5.2 时序图
图3.7 时序图
Max7219采用串行寻址方式,在传送的串行数据中包含内部RAM的地址,加在DIN脚上的串行数据,必须在LOAD信号为高电平的前提下,以每个字节为一个数据包,在CLK信号上升沿移位16位的移位寄存器,然后再LOAD信号的上升沿锁存进数字或控制寄存器中,LOAD信号必须在第16个CLK信号上升沿的同时,或在下一个CLk信号上升沿之前升高,否则,数据会丢失。
3.5.3 串行地址格式
对MAX7219 来说,串行数据在DIN输入16 位数据包,无论LOAD 端处于何种状态,在时钟的上升沿数据均移入到内部16 位移位寄存器。对MAX7221 来说,无论数据输入或输出cs 必须为低电平。然后数据在LOAD/ cs 的上升沿被载入数据寄存器或控制寄存器。LOAD/ cs 端在第16 个时钟的上升沿同时或之后,下个时钟上升沿之前变为高电平,否则数据将会丢失。在DIN 端的数据传输到移位寄存器在16.5 个时钟周期之后出现在DOUT 端。在时钟的下降沿数据将被输出。数据位标记为D0-D15(如表 1 表示)。D8-D11 为寄存器地址位。D0-D7 为数据位。D12-D15 为无效位。在传输过程中,首先接收到的是D15 位,是非常重要的一位(MSB)。
表3.2:串行数据格式
D15 | D14 | D13 | D12 | D11 | D10 | D9 | D8 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
× | × | × | × | 地 址 | MSB 数据 LSB |
第四章 软件设计
3.1 系统结构图及总流程图
根据软件功能要求,将系统软件划分为若干个相对的部分,设计出合理的总体结构:时钟显示是一个循环过程,系统以单片机STCC52RC为主控制器,不断读取实时时钟芯片DS1302提供的时间送LED显示,时间采用24小时模式;当需要调整时间时,按下相应按键进入中断处理。整个系统的电源由电源线提供。
由于汇编语言产生的目标程序简短,占用存储空间小,执行快,能充分发挥计算机的硬件功能,因此根据系统总体结构确定总流程图后,用汇编语言编写程序实现各模块功能。总流程图如图3-1所示。
图3-1 系统总流程图
3.2 主程序模块
主程序模块包括初始化模块、DS1302读写模块、7219显示模块。
3.2.1 初始化模块
初始化模块包括了存储资源的分配、赋值、中断的状态设置。当使用机器编程时,必须进行初始化。初始化模块流程图如3-2所示。
图3-2 初始化模块流程图
在此模块,须定义好单片机与DS1302的串行通信接口以及调整时间按键端口,如下:
P0 数码管段码输入
P2 数码管位数选择
P1.1 7219片选
P1.0 7219 串行数据
P1.2 7219 串行时钟
P3.4 DS时钟控制总线SLCK
P3.3 DS数据传送总线I/O
P3.5 DS复位总线RST
P1.4 位选择键,按下选择要调整的位置
P1.5 UP,按此键调整时参数加
P1.6 DW,按此键调整时参数减
P1.7 按此键退出中断,取消调整
3.2.2 DS1302读写模块
DS1302 内有2 类寄存器,一类用于存放时钟/日历数据,另一类是静态 RAM。与外界数据的交换可分为单字节传送和多字节传送2 种方式。图3-4为DS实时时间读写流程图。
多字节模式可用于时钟/日历或有31个十进制地址(地址/命令位1~5 设为1)的 RAM 寄存器。时钟/日历寄存器的9~31及 RAM 的 31 寄存地址中无数据存储能力。连续模式的读或写从 0 地址的 0 位开始。当在连续模式向时钟寄存器写数据时,前8 个寄存器必须按传送数据顺序写。然而,此方式写入 RAM 时,不需要把传送数据的31B都写入。写入的每一个字节将传送到 RAM 不管是否所有的31B 都写入。
当时间能连续运行时,在时钟脉冲读的开始,当前时间被传送到另外一组寄存器,时间信息从这些从寄存器读出。这免去了在读取期间为刷新主寄存器而重读寄存器的需求。
图3-3 实时时间读写流程图
要注意的是,控制寄存器的第 7 位是写保护位。在对时钟或 RAM 读操作之前,第7 位必须是0。当为1 时,写保护位阻止对任何其他寄存器的写操作。初始的上电状态未被设置,因此,写保护位应该在试图写入器件之前清零。
3.2.3 显示模块
数码管的接口有静态接口和动态接口两种方式。
选用动态显示方式,将所有位的相应段选线并在一起,用一个接口完成字形码的输出(字形选择),位选线则分时轮流选通,即另一个接口完成各数码管的循环轮流点亮(数位选择),利用人眼视觉的暂留现象获得稳定的视觉效果。显示程序流程图如图3-4所示。
图3-4 显示流程图
设定8位数码管的显示格式为“XX-XX-XX”(时-分-秒),第六位和第三位的横杠固定正常显示。
3.2.5 主程序流程图
图3-7 主程序流程图
结合以上各模块流程图,设计主程序流程图如图3-7所示。
3.3 中断调整模块
本设计要处理的按键较多,主要是考虑到调整时间更人性化,方便人们的操作,因此设置了位选择键、加减键、结束键如果都以查询方式来检测,则程序会变得繁琐,而且出现误判断的机会较大,因此为了减少检测的麻烦,同时也为了区别时间和闹钟两个不同的调整任务,设计采用了外部中断方式来处理。该模块流程图如图3-8所示。
3.3.1 时间中断模块
当外部中断口P3.2收到下降沿信号,即时间调整键time按下时,程序进入时间调整中断,默认从“时”开始进行修改。
时间调整模块的重点在按键处理部分,本设计采用了查询方式检测是否有键按下,并消抖延时来确认按下的是哪一个键。如果按下的是位选择键、加键或减键,进入相应程序处理,子程序结束后需继续检测下一次是否有键按下;如果按下的是确认键或取消键,则结束中断。
位选择键处理:判断按键次数,当等于4时返回1
加键处理:要调整的部分加1。由于采用24小时模式,若修改“时”,则先检测是否为23,是则重新赋值为0,否则直接加1;若修改“分”或“秒”,先检测是否为59,是则重新赋值为0,否则直接加1。
减键处理:要调整的部分减1。由于采用24小时模式,若修改“时”,则先检测是否为0,是则重新赋值为23,否则直接减1;若修改“分”或“秒”,先检测是否为0,是则重新赋值为59,否则直接减1。
取消键处理:表示修改结束。
图3-8 中断调整流程图
参考文献
[1] 向继文,廖立新. 基于ATS51的电子钟系统设计[J].机电产品开发与创新, 2007.
[2] 罗政球. 时钟芯片DS1302可靠起振方法[J].制作天地, 2009.
[3] 张勇. 制作基于DS1302 的电子时钟时的难点分析[J]. 保定师范专科学校学报, 2004.
[4] 赵亮. 实时时钟芯片DS1302的应用[J].电子制作,2005.
[5] 能昌会. 时钟芯片DS1302在单片机系统中的应用[J].电子制作, 2007.
[6] 朱路,朱清慧. 连续补充充电实时时钟芯片DS1302及其应用[J].现代电子技术,2006.
[7] 刘盛雄,周奇,韦云. 基于单片机的数字式电子钟的设计与制作[J].重庆工学院学报,2006.
[8] 杨占军. 基于DS1302的数码管时钟电路设计[J].电子世界,2005.
[9] 庄建清,徐玮. 51单片机综合学习系统_DS1302时钟应用篇[J]. 电子制作, 2008.
[10] 黄明强. DS1302在单片机系统中的应用[N].保定师范专科学校学报,2004.
[11] 孙枫. 串行实时时钟芯片DS1302与单片机接口技术及应用[J].鞍钢技术,2001.
[12] 黄艺娜. 基于MAX7219的时钟显示设计 [J]. 漳州职业技术学院学报,2010年 02期.
[13] 唐晓蓉,周俊武,肖玉明. 利用MAX7219驱动LED显示器[J]电子技术应用, 1998.
[14] 刘汉民. LED显示驱动器MAX7219的单片机接口技术及编程[J]仪表技术与传感器, 2002 .
[15] 黄晓兵,王立琦. 串行LED显示驱动器MAX7219[J]电测与仪表, 2000.
[16] 贾新宇; 焦阳; 郭辉. MAX7219 LED显示芯片的应用 [J]. 电脑知识与技术,2010年 11期 .
[17] 徐玮. C51单片机高效入门[J].机械工业出版社,2010.
[18] 张晓乡. c51单片机实用教程[J].电子工业出版社,2010.
[19] 唐前辉; 丁明亮 . Proteus ISIS和Keil在单片机教学中的应用[J]. 重庆电力高等专科学校学报,2006年 04期 .
[20] 张怀广 . 《Protel99 SE》快速入门的几个技巧 [J]. 濮阳职业技术学院学报,2010年 第02期
附录一 硬件仿真原理图
附录二 C语言程序
#include #include sbit LOAD=P1^1; sbit DIN=P1^0; sbit CLK=P1^2; sbit SCK=P3^4; sbit SDA=P3^3; sbit RST=P3^5; sbit KEY1=P1^4; sbit KEY2=P1^5; sbit KEY3=P1^6; sbit KEY4=P1^7; #define DECODE_MODE 0x09 #define INTENSITY 0x0A #define SCAN_LIMIT 0x0B #define SHUT_DOWN 0x0C #define DISPLAY_TEST 0x0F #define RST_CLR RST=0/*电平置低*/ #define RST_SET RST=1/*电平置高*/ #define IO_CLR SDA=0/*电平置低*/ #define IO_SET SDA=1/*电平置高*/ #define IO_R SDA/*电平读取*/ #define SCK_CLR SCK=0/*时钟信号*/ #define SCK_SET SCK=1/*电平置高*/ #define ds1302_sec_add 0x80 #define ds1302_min_add 0x82 #define ds1302_hr_add 0x84 #define ds1302_control_add 0x8e #define ds1302_charger_add 0x90 #define ds1302_clkburst_add 0xbe #define time 10000 //函数声明 void Write7219(unsigned char address,unsigned char dat); void Initial(void); void Write_Ds1302_byte(unsigned char temp); void Write_Ds1302(unsigned char address,unsigned char dat ); unsigned char Read_Ds1302 ( unsigned char address ); void ds1302_write_time(void); void ds1302_read_time(void); void keyscan(void); void Read_RTC(void);//read RTC void Set_RTC(void); //set RTC void InitTIMER0(void);//inital timer0 bit ReadRTC_Flag; unsigned char time_buf1[4]={20,16,30}; unsigned int time_buf[4] ; unsigned char l_tmpdisplay[8]; unsigned char keydat,temp; //地址、数据发送子程序 void Write7219(unsigned char address,unsigned char dat) { unsigned char i; LOAD=0; //发送地址 for (i=0;i<8;i++) { CLK=0; DIN=(bit)(address&0x80); address<<=1; CLK=1; } for (i=0;i<8;i++) { CLK=0; DIN=(bit)(dat&0x80); dat<<=1; CLK=1; } LOAD=1; } /void Initial(void) { Write7219(SHUT_DOWN,0x01); //开启正常工作模式(0xX1) Write7219(DISPLAY_TEST,0x00); //选择工作模式(0xX0) Write7219(DECODE_MODE,0xff); //选用全译码模式 Write7219(SCAN_LIMIT,0x07); //8只LED全用 } void delay(unsigned int cnt) { while(--cnt); } void main(void) { InitTIMER0(); Initial(); ds1302_write_time(); while(1) { if(ReadRTC_Flag) { ReadRTC_Flag=0; ds1302_read_time(); l_tmpdisplay[0]=time_buf1[1]/10; l_tmpdisplay[1]=time_buf1[1]%10; l_tmpdisplay[2]=10; l_tmpdisplay[3]=time_buf1[2]/10; l_tmpdisplay[4]=time_buf1[2]%10; l_tmpdisplay[5]=10; l_tmpdisplay[6]=time_buf1[3]/10; l_tmpdisplay[7]=time_buf1[3]%10; } keyscan(); } } void InitTIMER0(void) { TMOD|=0x01;//定时器设置 16位 TH0=0xef;//初始化值 TL0=0xf0; ET0=1; TR0=1; EA=1; } /*向DS1302写入一字节数据*/ void ds1302_write_byte(unsigned char addr, unsigned char d) { unsigned char i; RST_SET; addr = addr & 0xFE; for (i = 0; i < 8; i ++) { if (addr & 0x01) { IO_SET; } else { IO_CLR; } SCK_SET; SCK_CLR; addr = addr >> 1; } for (i = 0; i < 8; i ++) { if (d & 0x01) { IO_SET; } else { IO_CLR; } SCK_SET; SCK_CLR; d = d >> 1; } RST_CLR; } unsigned char ds1302_read_byte(unsigned char addr) { unsigned char i; unsigned char temp; RST_SET; addr = addr | 0x01; for (i = 0; i < 8; i ++) { if (addr & 0x01) { IO_SET; } else { IO_CLR; } SCK_SET; SCK_CLR; addr = addr >> 1; } for (i = 0; i < 8; i ++) { temp = temp >> 1; if (IO_R) { temp |= 0x80; } else { temp &= 0x7F; } SCK_SET; SCK_CLR; } RST_CLR; return temp; } void ds1302_write_time(void) { unsigned char i,tmp; for(i=0;i<4;i++){ //BCD处理 tmp=time_buf1[i]/10; time_buf[i]=time_buf1[i]%10; time_buf[i]=time_buf[i]+tmp*16; } ds1302_write_byte(ds1302_control_add,0x00); ds1302_write_byte(ds1302_sec_add,0x80); ds1302_write_byte(ds1302_charger_add,0xa9); ds1302_write_byte(ds1302_hr_add,time_buf[1]); ds1302_write_byte(ds1302_min_add,time_buf[2]); ds1302_write_byte(ds1302_sec_add,time_buf[3]); ds1302_write_byte(ds1302_control_add,0x80); } void ds1302_read_time(void) { unsigned char i,tmp; time_buf[1]=ds1302_read_byte(ds1302_hr_add); //时 time_buf[2]=ds1302_read_byte(ds1302_min_add); //分 time_buf[3]=(ds1302_read_byte(ds1302_sec_add))&0x7F;//秒 for(i=0;i<4;i++){ tmp=time_buf[i]/16; time_buf1[i]=time_buf[i]%16; time_buf1[i]=time_buf1[i]+tmp*10; } } void tim(void) interrupt 1 using 1 { static unsigned char i,num; unsigned char j; TH0=0xf5; TL0=0xe0; for(j=1;j<9;j++) { Write7219(j,l_tmpdisplay[j-1]); } i++; if(i==8) { i=0; num++; if(10==num) { ReadRTC_Flag=1; num=0; } } } void keyscan(void) { if(!KEY1) { delay(time); if(!KEY1) { while(!KEY1) ; keydat++; if(keydat==4) keydat=1; } } if( keydat==1) { P0=0XFE; if(!KEY2) { delay(time); if(!KEY2) { while(!KEY2) ; time_buf1[1]++;if(time_buf1[1]==24)time_buf1[1]=0; ds1302_write_time(); } } if(!KEY3) { delay(time); if(!KEY3) { while(!KEY3) ; time_buf1[1]--;if(time_buf1[1]==255)time_buf1[1]=23; ds1302_write_time(); } } } if( keydat==2) { P0=0Xfd; if(!KEY2) { delay(time); if(!KEY2) { while(!KEY2) ; time_buf1[2]++;if(time_buf1[2]==60)time_buf1[2]=0;//分加1 ds1302_write_time(); } } if(!KEY3) { delay(time); if(!KEY3) { while(!KEY3) ; time_buf1[2]--;if(time_buf1[2]==255)time_buf1[2]=59; ds1302_write_time(); } } } if( keydat==3) { P0=0XFB; if(!KEY2) { delay(time); if(!KEY2) { while(!KEY2) ; time_buf1[3]++;if(time_buf1[3]==60)time_buf1[3]=0; ds1302_write_time(); } } if(!KEY3) { delay(time); if(!KEY3) { while(!KEY3) ; time_buf1[3]--;if(time_buf1[3]==255)time_buf1[3]=59; ds1302_write_time(); } } } if(KEY4==0) { delay(time); if(!KEY4) { keydat=0; P0=0XFF; } } }