一天一个设计实例-实时时钟芯片DS1302的接口电路、时序及程序设计(二)

实时时钟的缩写是RTC(RealTime Clock)。RTC 是集成电路,通常称为时钟芯片。控制时钟的芯片。一旦初始化后,它就会随着现实的时钟一直计数。
现在流行的串行时钟电路很多,如DS1302、 DS1307、PCF8485等。这些电路的接口简单、价格低廉、使用方便,被广泛地采用。本文介绍的实时时钟电路DS1302是DALLAS公司的一种具有涓细电流充电能力的电路,主要特点是采用串行数据传输,可为掉电保护电源提供可编程的充电功能,并且可以关闭充电功能。采用普通32.768kHz晶振。
DS1302的功能分析及时序分析
实时时钟芯片,一旦初始化后,它就会随着现实的时钟一直计数。要明白 DS1302 芯片最主要的关键,就是“传输时序”和“芯片本身的寄存器分配
图4‑6 DS1302 芯片写操作的时序图
上图是 DS1302 芯片写操作的时序图。第一个字节是“访问寄存器的地址”,第二字节是“写数据”。在写操作的时候,都是“上升沿有效”,然而还有一个条件,就是 CE(/RST)信号必须拉高。(数据都是从 LSB 开始发送,亦即是最低位开始至最高位结束)。
图4‑7 DS1302 芯片读操作的时序图
上图是 DS1302 芯片读操作的时序图。基本上和写操作的时序图大同小异,区别的地方就是在第二个字节时“读数据”的动作。第二字节读数据开始时, SCLK 信号都是“下降沿有效”。嗯,别忘了 CE(/RST)信号同样是必须拉高。(第一节数据是从 LSB 开始输出,第二节数据是从 LSB 开始读入)。
图4‑8 访问寄存器的地址
无论是读操作还是写操作,在时序图中,第一个字节都是“访问寄存器的地址”,然而这一字节数据有自己的格式。
BIT 7 固定。
BIT 6 表示是访问寄存器本身,还是访问 RAM 空间。
BIT 5…1 表示是寄存器|RAM 空间的地址。
BIT 0 表示是访问寄存器本身是写操作,还是读操作。
图4‑9 写操作的理想时序(主机视角)
图4‑9是写操作的理想时序图, SCLK 为串行时钟, CS 为拉高有效的片选(又名为RESET), DATA 是数据进出的 I/O。忘了说, DS1302 由于使用 SPI 传输的关系,所以下降沿设置数据,上升沿锁存数据。如图 23.1 所示,左边为访问字节,右边则是数据字节, CS 拉高为写操作有效。对此,主机先将访问字节写入,再将数据字节写入指定的位置。 闲置状态, SCLK 信号还有 CS 信号都是拉低发呆,而且读写数据都是由低至高。
图4‑10 写操作的理想时序(从机视角)
图4‑10则是从机视角的写操作时序,从机任何时候都是利用上升沿读取数据。
图4‑11 读操作的理想时序(主机视角)
图4‑11为读操作的理想时序。T0~T7,主机写入访问字节并且指定读出地址。T8~T15,从机读出数据字节,期间 DATA 为输入状态,从机根据下降沿设置(更新)数据,主机为上升沿读取。
图4‑12 读操作的理想时序(从机视角)
图4‑12为从机视角的读操作,从机在 T0~T7 利用上升沿读取数据,然后在 T8~T15 利用下降沿输出数据。
下面看下DS1302寄存器的内容,详见芯片Datasheet。
表4‑1 访问内容/寄存器内容
表4‑1为 DS1302 的访问内容,或者说为寄存器地址与寄存器内容,其中秒寄存器的[7]为 0 开始计时,为 1 则停止计时。调用过程大致如下:
初始化:
 发送 8EH 访问字节,关闭写保护;
 发送 84H 访问字节,初始化“时种”;
 发送 82H 访问字节,初始化“分钟”;
 发送 80H 访问字节,初始化“秒钟”,开始计时。
调用:
 发送 81H 访问字节,读取“秒钟”内容;
 发送 83H 访问字节,读取“分钟”内容;
 发送 85H 访问字节,读取“时种”内容;
 重复上述内容
Verilog HDL 语言有的是很强的位操作,“访问寄存器的地址”可以这样表示:
{ 2'b10 , 5'd Addr, 1'b RD/W }
我们知道 BIT 7 是固定的位,然而 BIT 6 表示“访问 RAM空间还是访问寄存器”。在寄存器地址中, BIT 6 都是清一色的为“逻辑 0”。
假设要写秒寄存器,那么笔者可以这样输入:
{ 2'b10, 5'd0, 1'b0 }
再假设我要读秒寄存器,那么笔者可以这样输入:
{ 2'b10, 5'd0, 1'b1 }
在表4‑1中,秒寄存器(第一个),前高四位(BIT7 除外),表示“秒的十位”,低四位表示“秒的个位”。其他的寄存器的字节配置也是如此。但是有 3 个寄存器比较特别,那就是“秒寄存器”,“时寄存器”,“控制寄存器”(最后两个)。秒寄存器的最高位(BIT7),如果写入“逻辑 0” DS1302 芯片就开始启动,反之就关闭。
时寄存器的最高位(BIT7),表示了“逻辑 1 是 12 小时进制”,“逻辑 0 是 24 小时进制”,一般认为,还是 24 小时进制比较方便工作。
控制寄存器的最高位(BIT7),如果写入“逻辑 0”表示关闭写保护,写入“逻辑 1”表示打开写保护。所以呀,每当要变更寄存器的内容之前,就要关闭写保护。
图4‑13 RAM 的全家福
上图是 RAM 的全家福。RAM 的空间有 2^5 - 2 = 0~30 , 亦即 31 words x 8 bits 的空间。由于是访问 RAM,所以“访问寄存器的地址”的 BIT6 必须是逻辑 1。RAM 地址的范围如下:
{ 2'b11 , 5'd0 , 1'b RD/W } ~ { 2'b11 , 5'd30 , 1'b RD/W }
接下来是驱动 DS1302 的简单操作概念:
如果笔者要关闭写保护,那么笔者需要的操作如下:
先写第一节地址 - { 2'b10, 5'd 7, 1'b0 }
后写第二节数据 - { 8'h00 }
如果笔者要在时寄存器写入 10 十进制( 如果以 24 小时进制 ),那么笔者需要如下的操作:
先写第一节地址 - { 2'b10, 5'd2, 1'b0 }
后写第二节数据 - { 4'h1, 4'h0 }
如果笔者要在分寄存器写入 20 十进制,那么笔者需要的操作如下:
先写第一节地址 - { 2'b10, 5'd1, 1'b0 }
后写第二节数据 - { 4'h2, 4'h0 }
如果笔者要在秒寄存器写入 33 十进制,那么笔者需要的操作如下:
先写第一节地址 - { 2'b10, 5'd0, 1'b0 }
后写第二节数据 - { 4'h3, 4'h3 }
(在这里我们知道,秒寄存器的最高位,控制着 DS1302 芯片的启动和关闭,所以秒寄存器的配置都是留在最后才操作)
如果我要在地址 20, RAM 空间写入 0xff 的数据,那么笔者需要如下的操作:
先写第一节地址 - { 2'b11, 5'd 20, 1'b0 }
后写第二节数据 - { 8'hff }
如果笔者要在时寄存器读出的“十位和个位” ( 如果以 24 小时进制 ),那么笔者需要如下的操作:
先写第一节地址 - { 2'b10, 5'd2, 1'b1 }
后读第二节数据 - { 4'h 读出时十位, 4'h 读出时个位 }
如果笔者要在秒寄存器读出“十位和个位”,那么笔者需要的操作如下:
先写第一节地址 - { 2'b10, 5'd1, 1'b1 }
后读第二节数据 - { 4'h 读出秒十位, 4'h 读出秒个位}
如果笔者要在地址 20, RAM 空间读出数据,那么笔者需要如下的操作:
先写第一节地址 - { 2'b11, 5'd 20, 1'b1}
后读第二节数据 - { 8'h 读出数据 }
理论上来说DS1302是SPI接口(其实比标准的SPI接口少了一根线),它包含RST线、SCLK线、IO线(双向传送数据用,标准的SPI则将其分成两根MISO与MOSI)3条接线。所以不能用传统的SPI总线协议的代码直接调用,需要重新根据时序编写代码。
在datasheet中,有关DS1302的时序,如下:
表4‑2 datasheet中有关DS1302的时序
简单整理一下:
表4‑3 DS1302 的时序参数①
从上面两个表中可以看出,DS1302 最高速率为 2Mhz 并且无下限, 50Mhz 的量化结果为 25。时钟信号拉高 TCH 或拉低 TCL至少需要保持 250ns,量化结果为 12.5。至于时钟信号上升时间 TR 或者下降时间 TF 最大时间为500ns,极端说是最小时间是 0ns。
图4‑14 时序参数①
如图4‑14所示,那是时钟信号还有相关的时序参数,左图为理想时序,右图为物理时序。TR+TH 造就前半时钟周期, TF+TL 造就后半时钟周期,然后 TR+TH+TF+TL 为一个时钟周期。
表4‑4 DS1302 的时序参数②
图4‑15 时序参数②
如表4‑4是 TCC 还有 TDC 的时序参数,虽然两者都有 Setup 字眼,实际上它们都是推挤作用的时序参数。如图4‑15的右图所示,那是物理时序图, TCC 向右推挤 SCLK信号, TDC 向右推挤 TDC 信号。换做左图的理想时序图, TCC 使 SCLK 被覆盖, TDC使 DATA 被覆盖。有些同学可能会被 TCC 的要求吓到,既然是 1us。原理上,它是时钟周期的两倍,不过那是推挤作用的时序参数,只要操作结束之前一直拉高 CS 即可无视。
表4‑5 DS1302 的时序参数③
图4‑16 时序参数③
表4‑5显示 TCDD 还有 TCDH 两只时序参数,如 23.7 的右图所示,那是物理时序。我们知道 DS1302 是下降沿设置(输出)数据,上升沿锁存数据,期间 TCDD 将数据向右推挤, TCDH 则就是典型的 THold,即锁存数据以后的确保时间。如图4‑16的左图所示,那是理想时序,由于这两只都是小家伙,一般都无法完全覆盖数据。
表4‑6 DS1302 的时序参数④
表4‑6有 3 个比较奇怪的时序参数, TCWH 为片选信号进入静态所需的时间,也认为是释放片选所需的最小时间。至于 TCDZ 与 TCCZ 都是与高阻态有关的时序参数,而高阻态也与 I/O 息息相关。感觉上,高阻态好比一只切断输出的大刀,而且这只大刀必须由人操纵,其中 TCDZ 就是 CE 切断输出状态所需的最小时间, TCCZ 就是 SCLK 切断输出状态所需的最小时间
图4‑17 DS1302 基础模块(ds1302_basemod.v)的建模图
图4‑17是 DS1302 基础模块的建模图,内容包含命令控制模块与功能函数模块,功能函数模块负责最基础的读写操作,命令控制模块则负责功能调度,准备访问字节等任务。换之,函数功能模块的右边是驱动硬件资源的顶层信号。
表4‑7 ds1302 (ds1302_basemod.v)模块间信号定义
模块间信号
管脚
传输方向
作用/说明
iCall
信号为命令控制模块发送给功能函数模块。
iCall为2位,其中 [1]为写操作, [0]为读操作。
oDone
oDone为功能函数模块发送给控制模块。
oDone为操作完成信号。
iAddr
命令控制模块发送给功能函数模块
读/写操作的地址
iData
命令控制模块发送给功能函数模块
写数据内容
oData
功能函数模块发送给命令控制模块
读数据内容
时序
见上述分析
表4‑8 ds1302 (ds1302_basemod.v)顶层模块信号定义
顶层模块
输入管脚
作用/说明
输出管脚
作用/说明
iCall
iCall位宽为 8,作用是调用时给的操作模式。
oDone
操作完成信号
iData
写数据内容
SCLK
传感器SCLK引脚
oData
读数据内容
SIO
传感器读取/写入数据
RST/CS
传感器RST引脚
时序
见上述时序分析
下面分析下ds1302_funcmod.v模块
图4‑18 DS1302 功能函数模块(ds1302_ funcmod.v)的建模图
相关的介绍详见代码说明。
代码4‑1 DS1302 功能函数模块
1.//****************************************************************************//
2.//# @Author: 碎碎思
3.//# @Date:   2019-05-19 21:06:32
4.//# @Last Modified by:   zlk
5.//# @WeChat Official Account: OpenFPGA
6.//# @Last Modified time: 2019-05-19 21:31:51
7.//# Description:
8.//# @Modification History: 2019-05-19 20:58:19
9.//# Date                By             Version             Change Description:
10.//# ========================================================================= #
11.//# 2019-05-19 20:58:19
12.//# ========================================================================= #
13.//# |                                                                       | #
14.//# |                                OpenFPGA                               | #
15.//****************************************************************************//
16.module ds1302_funcmod
17.(
18.    input CLOCK, RST_n,
19.     output RTC_NRST,RTC_SCLK,
20.     inout RTC_DATA,
21.     input [1:0]iCall,
22.     output oDone,
23.     input [7:0]iAddr,iData,
24.     output [7:0]oData
25.);
26.     parameter FCLK = 6'd25, FHALF = 6'd12; // 2Mhz,(1/2Mhz)/(1/50Mhz) FCLK 为一个周期
27.     parameter FF_Write = 6'd16, FF_Read = 6'd32;//FHALF 为半周期
28.
29.     reg [5:0]C1;
30.    reg [5:0]i,Go;
31.     reg [7:0]D1,T; //D1 为暂存读取结果 T 为伪函数的操作空间
32.     reg rRST, rSCLK, rSIO;
33.     reg isQ,isDone; //isQ 为 IO 的控制输出
34.
35.    always @ ( posedge CLOCK or negedge RST_n )
36.         if( !RST_n )
37.              begin
38.                    C1 <= 6'd0;
39.                    { i,Go } <= { 6'd0,6'd0 };
40.                     { D1,T } <= { 8'd0,8'd0 };
41.                     { rRST, rSCLK, rSIO } <= 3'b000;
42.                     { isQ, isDone } <= 2'b00;
43.                end
44./***********************************************************************
45.下面步骤是写一个字节的伪函数。步骤 0 拉高片选,准备访问字节,并且进入伪函数。
46.步骤 1 准备写入数据并且进入伪函数。
47.步骤 2 拉低片选,步骤 3~4 则是用来产生完成信号。
48.***********************************************************************/
49.           else if( iCall[1] )
50.                case( i )
51.
52.                      0:
53.                      begin { rRST,rSCLK } <= 2'b10; T <= iAddr; i <= FF_Write; Go <= i + 1'b1; end
54.
55.                      1:
56.                      begin T <= iData; i <= FF_Write; Go <= i + 1'b1; end
57.
58.                      2:
59.                      begin { rRST,rSCLK } <= 2'b00; i <= i + 1'b1; end
60.
61.                      3:
62.                      begin isDone <= 1'b1; i <= i + 1'b1; end
63.
64.                      4:
65.                      begin isDone <= 1'b0; i <= 6'd0; end
66.
67.                      /******************/
68.
69.                      16,17,18,19,20,21,22,23:
70.                      begin
71.                          isQ = 1'b1;
72.                          rSIO <= T[i-16];
73.
74.                            if( C1 == 0 ) rSCLK <= 1'b0;
75.                          else if( C1 == FHALF ) rSCLK <= 1'b1;
76.
77.                          if( C1 == FCLK -1) begin C1 <= 6'd0; i <= i + 1'b1; end
78.                            else C1 <= C1 + 1'b1;
79.                      end
80.
81.                      24:
82.                      i <= Go;
83.
84.                 endcase
85./***********************************************************************
86.以下内容是读操作,下面步骤是写一个字节的伪函数,
87.步骤 0 拉高使能,准备访问字节并且进入写函数。
88.步骤 1 进入读函数。
89.步骤 2 拉低使能之余,也将读取结果暂存至 D。
90.步骤 3~4 用来产生完成信号。
91.***********************************************************************/
92.        else if( iCall[0] )
93.                case( i )
94.
95.                     0 :
96.                      begin { rRST,rSCLK } <= 2'b10; T <= iAddr; i <= FF_Write; Go <= i + 1'b1; end
97.
98.                      1:
99.                     begin i <= FF_Read; Go <= i + 1'b1; end
100.
101.                      2:
102.                      begin { rRST,rSCLK } <= 2'b00; D1 <= T; i <= i + 1'b1; end
103.
104.                      3:
105.                      begin isDone <= 1'b1; i <= i + 1'b1; end
106.
107.                      4:
108.                      begin isDone <= 1'b0; i <= 6'd0; end
109.
110.                      /*********************/
111.
112.                      16,17,18,19,20,21,22,23:
113.                      begin
114.                          isQ = 1'b1;
115.                          rSIO <= T[i-16];
116.
117.                            if( C1 == 0 ) rSCLK <= 1'b0;
118.                          else if( C1 == FHALF ) rSCLK <= 1'b1;
119.
120.                          if( C1 == FCLK -1) begin C1 <= 6'd0; i <= i + 1'b1; end
121.                            else C1 <= C1 + 1'b1;
122.                      end
123.
124.                      24:
125.                      i <= Go;
126.
127.                      /*********************/
128.
129.                      32,33,34,35,36,37,38,39:
130.                      begin
131.                          isQ = 1'b0;
132.
133.                            if( C1 == 0 ) rSCLK <= 1'b0;
134.                          else if( C1 == FHALF ) begin rSCLK <= 1'b1; T[i-32] <= RTC_DATA; end
135.
136.                          if( C1 == FCLK -1) begin C1 <= 6'd0; i <= i + 1'b1; end
137.                            else C1 <= C1 + 1'b1;
138.                      end
139.
140.                      40:
141.                      i <= Go;
142.
143.                 endcase
144./***********************************************************************
145.以下内容为相关输出驱动声明,其中 rSIO 驱动 RTC_DATA, D 驱动 oData   。
146.***********************************************************************/
147.        assign { RTC_NRST,RTC_SCLK } = { rRST,rSCLK };
148.        assign RTC_DATA = isQ ? rSIO : 1'bz;
149.        assign oDone = isDone;
150.        assign oData = D1;
151.
152.endmodule
图4‑19 DS1302 控制函数模块(ds1302_ ctrlmod.v)的建模图
表4‑9 Call/Done 的位宽内容
内容
[7]
关闭写保护
[6]
写入时钟
[5]
写入分钟
[4]
写入秒钟
[3]
开启写保护
[2]
读取时钟
[1]
读取分钟
[0]
读取秒钟
代码4‑2 DS1302 控制函数模块
1.//****************************************************************************//
2.//# @Author: 碎碎思
3.//# @Date:   2019-05-19 20:55:44
4.//# @Last Modified by:   zlk
5.//# @WeChat Official Account: OpenFPGA
6.//# @Last Modified time: 2019-05-19 21:05:49
7.//# Description:
8.//# @Modification History: 2019-05-19 20:58:05
9.//# Date                By             Version             Change Description:
10.//# ========================================================================= #
11.//# 2019-05-19 20:58:05
12.//# ========================================================================= #
13.//# |                                                                       | #
14.//# |                                OpenFPGA                               | #
15.//****************************************************************************//
16.module ds1302_ctrlmod
17.(
18.    input CLOCK, RST_n,
19.     input [7:0]iCall,
20.     output oDone,
21.     input [7:0]iData,
22.     output [1:0]oCall,
23.     input iDone,
24.     output [7:0]oAddr, oData
25.);
26.     reg [7:0]D1,D2;
27.
28.     always @ ( posedge CLOCK or negedge RST_n )
29.         if( !RST_n )
30.              begin
31.                    D1 <= 8'd0;
32.                     D2 <= 8'd0;
33.                end
34.          else
35.              case( iCall[7:0] )
36.
37.                    8'b1000_0000 : // Write unprotect
38.                     begin D1 = 8'h8E; D2 = 8'b0000_0000; end
39.
40.                    8'b0100_0000 : // Write hour
41.                     begin D1 = 8'h84; D2 = iData; end
42.
43.                     8'b0010_0000 : // Write minit
44.                     begin D1 = 8'h82; D2 = iData; end
45.
46.                     8'b0001_0000 : // Write second
47.                     begin D1 = 8'h80; D2 = iData; end
48.
49.                     8'b0000_1000 : // Write protect
50.                     begin D1 = 8'h8E; D2 = 8'b1000_0000; end
51.
52.                     8'b0000_0100 : // Read hour
53.                     begin D1 = 8'h85; end
54.
55.                     8'b0000_0010 : // Read minit
56.                     begin D1 = 8'h83; end
57.
58.                     8'b0000_0001 : // Read second
59.                     begin D1 = 8'h81; end
60.
61.                endcase
62.
63.     reg [1:0]i;
64.     reg [1:0]isCall;
65.     reg isDone;
66.
67.     always @ ( posedge CLOCK or negedge RST_n )
68.         if( !RST_n )
69.              begin
70.                     i <= 2'd0;
71.                     isCall <= 2'b00;
72.                     isDone <= 1'b0;
73.                end
74.          else if( iCall[7:3] ) // Write action
75.              case( i )
76.
77.                    0 :
78.                     if( iDone ) begin isCall[1] <= 1'b0; i <= i + 1'b1; end
79.                     else begin isCall[1] <= 1'b1; end
80.
81.                     1 :
82.                     begin isDone <= 1'b1; i <= i + 1'b1; end
83.
84.                     2 :
85.                     begin isDone <= 1'b0; i <= 2'd0; end
86.
87.                endcase
88.          else if( iCall[2:0] ) // Read action
89.              case( i )
90.
91.                    0 :
92.                     if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1; end
93.                     else begin isCall[0] <= 1'b1; end
94.
95.                     1 :
96.                     begin isDone <= 1'b1; i <= i + 1'b1; end
97.
98.                     2 :
99.                     begin isDone <= 1'b0; i <= 2'd0; end
100.
101.                endcase
102.
103.      assign oDone = isDone;
104.      assign oCall = isCall;
105.      assign oAddr = D1;
106.      assign oData = D2;
107.
108.endmodule
按照错误!未找到引用源。将DS1302模块进行封装,代码如下
代码4‑3 ds1302_basemod模块
1.//****************************************************************************//
2.//# @Author: 碎碎思
3.//# @Date:   2019-05-19 20:56:01
4.//# @Last Modified by:   zlk
5.//# @WeChat Official Account: OpenFPGA
6.//# @Last Modified time: 2019-05-19 21:06:16
7.//# Description:
8.//# @Modification History: 2019-05-19 20:57:52
9.//# Date                By             Version             Change Description:
10.//# ========================================================================= #
11.//# 2019-05-19 20:57:52
12.//# ========================================================================= #
13.//# |                                                                       | #
14.//# |                                OpenFPGA                               | #
15.//****************************************************************************//
16.module ds1302_basemod
17.(
18.    input CLOCK, RST_n,
19.     output RTC_NRST, RTC_SCLK,
20.     inout RTC_DATA,
21.     input [7:0]iCall,
22.     output oDone,
23.     input [7:0]iData,
24.     output [7:0]oData
25.);
26.    wire [7:0]AddrU1;
27.     wire [7:0]DataU1;
28.     wire [1:0]CallU1;
29.
30.     ds1302_ctrlmod U1
31.     (
32.         .CLOCK( CLOCK ),
33.          .RST_n( RST_n ),
34.          .iCall( iCall ),  // < top
35.          .oDone( oDone ),    // > top
36.          .iData( iData ),    // > top
37.          .oCall( CallU1 ),  // > U2
38.          .iDone( DoneU2 ),    // < U2
39.          .oAddr( AddrU1 ),    // > U2
40.          .oData( DataU1 )     // > U2
41.     );
42.
43.     wire DoneU2;
44.
45.     ds1302_funcmod U2
46.     (
47.         .CLOCK( CLOCK ),
48.          .RST_n( RST_n ),
49.          .RTC_NRST( RTC_NRST ),   // > top
50.          .RTC_SCLK( RTC_SCLK ),         // > top
51.          .RTC_DATA( RTC_DATA ),         // <> top
52.          .iCall( CallU1 ),            // < U1
53.          .oDone( DoneU2 ),              // > U1
54.          .iAddr( AddrU1 ),              // > U1
55.          .iData( DataU1 ),              // > U1
56.          .oData( oData )                // > top
57.     );
58.
59.endmodule
完成后的RTL电路如图4‑20所示,和图4‑17一样。
图4‑20 DS1302基础模块RTL
图4‑21 DS1302基础模块调用建模图
图4‑21是DS1302基础模块调用建模图。核心操作先初始化 DS1302 基础模块,然后无间断从哪里读取时钟,分钟还有秒钟,最后驱动至 SMG 基础模块。具体内容让我们来看代码吧。
代码4‑4
1.//****************************************************************************//
2.//# @Author: 碎碎思
3.//# @Date:   2019-05-19 01:42:42
4.//# @Last Modified by:   zlk
5.//# @WeChat Official Account: OpenFPGA
6.//# @Last Modified time: 2019-05-19 21:39:15
7.//# Description:
8.//# @Modification History: 2019-05-19 01:52:19
9.//# Date                By             Version             Change Description:
10.//# ========================================================================= #
11.//# 2019-05-19 01:52:19
12.//# ========================================================================= #
13.//# |                                                                       | #
14.//# |                                OpenFPGA                               | #
15.//****************************************************************************//
16.module ds1302_demo
17.(
18.    input CLOCK, RST_n,
19.     output RTC_NRST, RTC_SCLK,
20.     inout RTC_DATA,
21.     output [7:0]SMG_Data,
22.     output [5:0]Scan_Sig
23.);
24.     wire DoneU1;
25.     wire [7:0]DataU1;
26.
27.
28.     ds1302_basemod U1
29.    (
30.        .CLOCK( CLOCK ),
31.         .RST_n( RST_n ),
32.          .RTC_NRST( RTC_NRST ),
33.         .RTC_SCLK( RTC_SCLK ),
34.         .RTC_DATA( RTC_DATA ),
35.         .iCall( isCall ),
36.         .oDone( DoneU1 ),
37.         .iData( D1 ),
38.         .oData( DataU1 )
39.    );
40.
41.     smg_interface U2
42.     (
43.         .CLOCK( CLOCK ),
44.          .RST_n( RST_n ),
45.          .SMG_Data( SMG_Data ),          // > top
46.          .Scan_Sig( Scan_Sig ),          // > top
47.          .Number_Sig( Number_Sig )          // < core
48.     );
49.
50.   reg [3:0]i;
51.    reg [7:0]isCall;
52.    reg [7:0]D1;
53.    reg [23:0]Number_Sig;
54.
55.    always @ ( posedge CLOCK or negedge RST_n )
56.        if( !RST_n )
57.             begin
58.                  i <= 4'd0;
59.                  isCall <= 8'd0;
60.                    D1 <= 8'd0;
61.                    Number_Sig <= 24'd0;
62.              end
63.         else
64.             case( i )
65./***********************************************************************
66.以下内容为核心操作的部分内容,步骤 0 关闭写保护,步骤 1 初始化时钟,步骤 2 初始
67.化分钟,步骤 3 初始化秒钟并且开启计时。
68.***********************************************************************/
69.                  0:
70.                    if( DoneU1 ) begin isCall[7] <= 1'b0; i <= i + 1'b1; end
71.                    else begin isCall[7] <= 1'b1; D1 <= 8'h00; end
72.
73.                    1:
74.                    if( DoneU1 ) begin isCall[6] <= 1'b0; i <= i + 1'b1; end
75.                    else begin isCall[6] <= 1'b1; D1 <= { 4'd2, 4'd1 }; end
76.
77.                    2:
78.                    if( DoneU1 ) begin isCall[5] <= 1'b0; i <= i + 1'b1; end
79.                    else begin isCall[5] <= 1'b1; D1 <= { 4'd5, 4'd9 }; end
80.
81.                    3:
82.                    if( DoneU1 ) begin isCall[4] <= 1'b0; i <= i + 1'b1; end
83.                    else begin isCall[4] <= 1'b1; D1 <= { 4'd5, 4'd0 }; end
84.
85./***********************************************************************
86.步骤 4 读取秒钟然后暂存至 D2[7:0],步骤 5 读取分钟然后暂存至 D2[15:8],步骤 6 读
87.取时钟然后暂存至 D2[23:16]。
88.***********************************************************************/
89.                    4:
90.                    if( DoneU1 ) begin Number_Sig[7:0] <= DataU1; isCall[0] <= 1'b0; i <= i + 1'b1; end
91.                    else begin isCall[0] <= 1'b1; end
92.
93.                    5:
94.                    if( DoneU1 ) begin Number_Sig[15:8] <= DataU1; isCall[1] <= 1'b0; i <= i + 1'b1; end
95.                    else begin isCall[1] <= 1'b1; end
96.
97.                    6:
98.                    if( DoneU1 ) begin Number_Sig[23:16] <= DataU1; isCall[2] <= 1'b0; i <= 4'd4; end
99.                    else begin isCall[2] <= 1'b1; end
100.
101.
102.              endcase
103.
104.endmodule
综合完毕后下载程序,如果数码管从 21-59-50 开始起跑,表示实验成功。
(0)

相关推荐