SCLK:
串行时钟,输入,控制数据的输入与输出;
I/O:
三线接口时的双向数据线;
CE:
输入信号,在读、写数据期间,必须为高。
该引脚有两
个功能:
第一,CE开始控制字访问移位寄存器的控制逻辑;其次,CE提供结束单字节或多字节数据传输的方法。
2.硬件设计
3.基本原理
DS1302是一款实时时钟芯片,就是一种控制时钟的芯片。
一旦初始化后,它就会像我们常用的手表一样计数时间。
DS1302内部有多个寄存器,存放在这些我们需要获取的时间数据。
所以对要1302的操作,最终就是如何访问DS1302的寄存器,如何向DS1302写入数据和读出数据。
如图是DS1302单字节写操作的时序图,第一个字节是“访问寄存器的地址”,第二字节是“要写入的数据”。
在写操作的时候,都是“上升沿有效”,即不管是“地址字节”还是“数据字节”,都是在SCLK的上升沿被采集的。
(数据都是从最低位开始发送至最高位结束)
如图是DS1302芯片读操作的时序图。
大家可能发现,读操作基本上和写操作的时序图差不多,区别的地方就是在第二个字节时“读的数据”的动作。
第二字节读数据开始时,SCLK信号都是“下降沿有效”。
(第一节数据是从LSB开始输出,第二节数据是从LSB开始读入)
细心的朋友可能发现,不管是读操作还是写操作,CE信号都是处于高电平状态的,所以在对DS1302进行读写操作前都要拉高CE信号开始,操作结束后拉低CE信号结束。
读和写操作,都是先发送一个字节的“访问寄存器的地址”。
这些寄存器地址格式如上图所示:
Bit7固定。
注:
为“1”
Bit6表示是访问寄存器本身,还是访问RAM空间。
注:
为“1”表示访问RAM,为“0”表示访问寄存器本身
Bit5-1表示是寄存器或者RAM空间的地址。
注:
表示具体的寄存器或者RAM地址;跟bit6相关
Bit0表示是访问寄存器本身是写操作,还是读操作。
注:
为“1”表示读操作;为“0”表示写操作
上图为DS1302各个寄存器的地址组成,比如,
秒寄存器:
高四位(bit7除外),表示“秒的十位”;低四位表示“秒的个位”。
其他的寄存器的地址组成也是如此。
但是,“秒寄存器”“时寄存器”“控制寄存器”(最后两行)比较特别。
秒寄存器的最高位(BIT7),如果写入“逻辑0”DS1302芯片就开始启动,反之就关闭;时寄存器的最高位(BIT7,表示了“逻辑1是12小时进制”“逻辑0是24小时进制”,推荐24小时进制的表示方式;控制寄存器的最高位(BIT7),如果写入“逻辑0”表示关闭写保护;写入“逻辑1”表示打开写保护。
所以,每当要变更寄存器的内容之前,就要关闭写保护。
因为秒寄存器的最高位控制着DS1302芯片是否工作,所以配置寄存器时秒寄存器的配置都是留在最后才配置的。
4.实验任务和现象
任务:
运用DS1302实现对时间的计时,用数码管显示分、秒。
现象:
数码管左边两位显示从DS1302中读出的分钟数据,右边两位显示读出的秒数据。
注:
因为数码管模块我们直接copy了动态数码管显示的程序,所以数码管的小数点一直处于常亮状态。
5.设计思路
本次的实验,我们采用建立多个module,最后在顶层文件调用实现任务要求。
首先先介绍一下工程的层次组成
在ds1302_module.v。
此模块包含两个基本模块,cmd_control_module.v和function_module.v。
function_module:
此模块中包含两个基本函数,即“写字节函数”和“读字节函数”。
下图为该模块的元件模型:
Start_Sig[1:
0]是该模块的起始信号。
Words_Addr和Write_Data,即“写字节操作”中的“第一字节”和“第二字节”数据。
Read_Data和Access_Done_Sig分别是返回的“读出数据”和“完成信号”。
DS1302_CE、DS1302_CLK,DS1302_IO:
分别连接到DS1302的对应管脚。
这里重点强调一下DS1302_IO:
输入输出口,但是同一时刻只能是输出或者输入。
如图是IO口的硬件设计:
要使IO输出,必须拉高isOut,Data_Out的数据就会输出。
要使IO为输入,需要拉低isOut,三态门会输出高阻态将“输出”截止,从IO口输入的数据就会Data_In输入。
DS1302_CLK:
参考数据手册,我们选取频率为500KHz的时钟。
在function_module中其他的变量:
i:
指示着执行步骤;
rData用来暂存数据;
rSCLK用来驱动DS1302_CLK;
rRST用来驱动DS1302_CE;
rSIO用来驱动DS1302_IO的输出,isOut用来控制IO口的方向;
isDone是完成标志,同时用来反馈完成信息。
在这个模块中完成了DS1302_CLK的配置、写操作和读操作。
写操作:
步骤0的时候,对rData,rSCLK,rRST,isOut等寄存器进行初始化,这一步一定要做。
步骤1-16之中,将“第一个字节数据”,即“访问寄存器地址字节”发送出去。
在时钟下降沿设置数据,时间上升沿锁存数据。
步骤17将rData设置为“第二个字节数据”,即“写入的数据”。
发送数据和发送地址的时序一样。
不再重复。
步骤34,对rRST拉低,以示“写字节操作”已经结束。
步骤35-36反馈完成信号。
读操作:
步骤0:
对rData,rSCLK,rRST,isOut等寄存器进行初始化。
步骤1-16之中,将“第一个字节数据”,即“访问寄存器地址字节”发送出去。
这时的数据锁存发生在时间的上升沿。
步骤17设置IO为输入,即将isOut设置为“0”。
步骤18-33之间是“读取一个字节数据”,该动作时时间的下降沿,对SIO信后读取数据。
注:
DS1302芯片,数据的传输都是从LSB开始到MSB结束。
步骤35:
rRST的拉低,以示“读字节数据”操作已经结束。
然后恢复IO口为输出,即拉高isOut寄存器,然后产生一个完成信号。
从DS1302芯片读取的数据会暂存在rData这个寄存器,然后该寄存器会驱动Read_Data信号线。
cmd_control_module:
此模块中包含两个基本函数,即“写字节函数”和“读字节函数”。
下图为该模块的元件模型:
Words_Addr和Write_Data的(rAddr和rData)暂存寄存器。
换句话说,rAddr寄存器是用来驱动
Words_Addr信号,rData寄存器是用来驱动Write_Data信号。
在8位Start_Sig的位宽之中,Start_Sig[7..3]是写操作,反之Start_Sig[2..0]是读操作。
在DS1302芯片的时序中“写操作”的第一个字节需要“访问寄存器的地址”,第二个字节是“写数据”。
在执行rAddr和rData寄存器值的赋值。
如在8'b1000_0000的时候,是“关闭写保护”的操作,就是要往“控制寄存器”写入“数据8'h00”。
即对rAddr和rData赋值{2'b10,5'd7,1'b0}和8'h00。
再举一个例子,当Start_Sig等价于8'b0100_0000的时候,即表示对“时寄存器”,“写入数据”。
这时候对rAddr赋予早已经预定好的值,即{2'b10,5'd2,1'b0}。
至于rData被赋予的值,是从上层发来的Time_Write_Data。
当Start_Sig[2..0]是表示“读操作”,在DS1302芯片的时序中,读操作只需要写入“第一字节数据”,第二字节数据是从DS1302读来的。
举例:
如当Start_Sig等价于8b0000_0001是表示从“秒寄存器读出数据”,所以关于这个操作rAddr被赋予{2'b10,5'd0,1'b1}。
该模块的具体操作中:
i寄存器表示执行步骤,
rRead寄存器是读出数据的暂存寄存器,
isStart寄存器是用于驱动Access_Start_Sig,即是对function_module控制的寄存器。
假设一个情况,当Start_Sig等价于8'b0000_0001的时候,这表示“从秒寄存器读取数据”。
在同一个瞬间rAddr会被赋予相关的值,然后读操作条件就会成立,就会完成一次的“读字节数据”的操作。
当完成一次性的“读字节数据”,读取到的数据就会被暂存在rRead寄存器,最后反馈一个完成信号。
以示上一层模块“一次性的读数据操作”已经完成。
Start_Sig[7:
0]:
状态表
ds1302_module:
只是对以上两个模块的例化,不多做解释。
seg_module:
该模块我们是直接copy以前的seg程序,只是做了简单修改,请参考以前的程序和方案。
最后看看,顶层模块
DS1302.v:
该模块例化了ds1302_module.v和seg_module.v。
根据执行步骤i的值有:
0:
关闭写保护,亦即发送命令8'b1000_0000;
1:
变更时寄存器,亦即发送命令8'b0100_0000;
2:
变更分寄存器,亦即发送命令8'b0010_0000;
3:
变更秒寄存器,亦即发送命令8'b0001_0000;
4:
读取秒寄存器的值,即发送命令8'b0000_0001。
将读取的数据高四位和低四位分别送给右边两个数码管的驱动信号线。
5:
读取分寄存器的值,即发送命令8'b0000_0010。
将读取的数据高四位和低四位分别送给左边两个数码管的驱动信号线。
然后跳回步骤4,
最后程序一直在步骤4和5之间循环,不停的读取秒和分。