實驗二十三:DS1302模塊
DS1302這只硬件雖然曾在《建模篇》介紹過,所以重復的內容請怒筆者懶惰嘮叨了,筆者盡可以一笑帶過,廢話少說讓我們進入正題吧。DS1302是執行事實時鍾(Real Time Clock)的硬件,采用SPI傳輸。
表示23.1 訪問(地址)字節。
[7] |
[6] |
[5] |
[4] |
[3] |
[2] |
[1] |
[0] |
1 |
A5 |
A4 |
A3 |
A2 |
A1 |
A0 |
R/W |
DS1302作為從機任由主機蹂躪 ... 啊,是任由主機訪問才對。對此,訪問便有方向之分。如表23.1所示,訪問字節(地址字節)[0]為訪問方向1讀0寫。[6..1]為地址。[7]為常量1。除了訪問字節以外,DS1302也有數據字節。
圖23.1 寫操作的理想時序(主機視角)。
圖23.1是寫操作的理想時序圖,SCLK為串行時鍾,CS為拉高有效的片選(又名為RESET),DATA是數據進出的I/O。忘了說,DS1302由於使用SPI傳輸的關系,所以下降沿設置數據,上升沿鎖存數據。如圖23.1所示,左邊為訪問字節,右邊則是數據字節,CS拉高為寫操作有效。對此,主機先將訪問字節寫入,再將數據字節寫入指定的位置。閑置狀態,SCLK信號還有CS信號都是拉低發呆,而且讀寫數據都是由低至高。
至於Verilog則可以這樣描述,結果如代碼23.1所示:
1. 0:
2. begin { rRST,rSCLK } <= 2'b10; T <= iAddr; i <= FF_Write; Go <= i + 1'b1; end
3. 1:
4. begin T <= iData; i <= FF_Write; Go <= i + 1'b1; end
5. 2:
6. begin { rRST,rSCLK } <= 2'b00; i <= i + 1'b1; end
7. ...
8. 16,17,18,19,20,21,22,23:
9. begin
10. isQ = 1'b1;
11. rSIO <= T[i-16];
12. if( C1 == 0 ) rSCLK <= 1'b0;
13. else if( C1 == FHALF ) rSCLK <= 1'b1;
14. if( C1 == FCLK -1) begin C1 <= 6'd0; i <= i + 1'b1; end
15. else C1 <= C1 + 1'b1;
16. end
17. 24:
18. i <= Go;
代碼23.1
步驟0拉高片選,拉低時鍾,准備訪問字節,然后進入偽函數。步驟1准備數據字節,然后進入偽函數。步驟2拉低使能,拉低時鍾。
步驟16~23為寫入一個字節的偽函數,isQ為IO的輸出控制,rSIO為DATA的輸出驅動,rSCLK為SCLK的輸出驅動,FCLK為一個時鍾周期,FHALF為半周期。寫操作只要任由 T 全程驅動 rSIO即可,期間C1為0拉低時鍾,C1為半個周期便拉高時鍾。
步驟24則返回步驟。
圖23.2 寫操作的理想時序(從機視角)。
圖23.2則是從機視角的寫操作時序,從機任何時候都是利用上升沿讀取數據。
圖23.3 讀操作的理想時序(主機視角)。
圖23.3為讀操作的理想時序。T0~T7,主機寫入訪問字節並且指定讀出地址。T8~T15,從機讀出數據字節,期間DATA為輸入狀態,從機根據下降沿設置(更新)數據,主機為上升沿讀取。至於Verilog則可以這樣描述,結果如代碼23.2所示:
1. 0 :
2. begin { rRST,rSCLK } <= 2'b10; T <= iAddr; i <= FF_Write; Go <= i + 1'b1; end
3. 1:
4. begin i <= FF_Read; Go <= i + 1'b1; end
5. 2:
6. begin { rRST,rSCLK } <= 2'b00; D1 <= T; i <= i + 1'b1; end
7. ...
8. 16,17,18,19,20,21,22,23:
9. begin
10. isQ = 1'b1;
11. rSIO <= T[i-16];
12. if( C1 == 0 ) rSCLK <= 1'b0;
13. else if( C1 == FHALF ) rSCLK <= 1'b1;
14. if( C1 == FCLK -1) begin C1 <= 6'd0; i <= i + 1'b1; end
15. else C1 <= C1 + 1'b1;
16. end
17. 24:
18. i <= Go;
19. ...
20. 32,33,34,35,36,37,38,39:
21. begin
22. isQ = 1'b0;
23. if( C1 == 0 ) rSCLK <= 1'b0;
24. else if( C1 == FHALF ) begin rSCLK <= 1'b1; T[i-32] <= RTC_DATA; end
25. if( C1 == FCLK -1) begin C1 <= 6'd0; i <= i + 1'b1; end
26. else C1 <= C1 + 1'b1;
27. end
28. 40:
29. i <= Go;
代碼23.2
步驟0拉低使能,拉低時鍾,准備訪問字節,進入偽函數寫。步驟1准備讀數據,進入為函數讀。步驟2為讀取數據,拉低使能,拉低時鍾。步驟16~24為協議一個字節的偽函數,步驟32~40為讀取一個字節的偽函數。拉低isQ讓IO為輸入狀態,C1為0拉低 rSCLK,C1為半個周期拉高 rSCLK並且讀取數據,上述操作重復8次便搞定。
圖23.4 讀操作的理想時序(從機視角)。
圖23.4為從機視角的讀操作,從機在T0~T7利用上升沿讀取數據,然后在T8~T15利用下降沿輸出數據。
表23.2 訪問內容/寄存器內容。
訪問地址 |
寄存器內容 |
|||||||||
讀 |
寫 |
[7] |
[6] |
[5] |
[4] |
[3] |
[2] |
[1] |
[0] |
范圍 |
81H |
80H |
CH |
秒十位 |
秒個位 |
59~00 |
|||||
83H |
82H |
分十位 |
分個位 |
59~00 |
||||||
85H |
84H |
12/24 |
時十位 |
時個位 |
12/24~00 |
|||||
87H |
86H |
日十位 |
日個位 |
31~1 |
||||||
89H |
88H |
月十位 |
月個位 |
12~1 |
||||||
8BH |
8AH |
天 |
7~1 |
|||||||
8DH |
8CH |
年十位 |
年個位 |
99~00 |
||||||
8FH |
8EH |
讀保護 |
||||||||
C1H |
C0H |
FFH~00H |
||||||||
... |
... |
... |
||||||||
FDH |
FCH |
FFH~00H |
表23.2為DS1302的訪問內容,或者說為寄存器地址與寄存器內容,其中秒寄存器的[7]為0開始計時,為1則停止計時。調用過程大致如下:
初始化:
l 發送8EH訪問字節,關閉寫保護;
l 發送84H訪問字節,初始化“時種”;
l 發送82H訪問字節,初始化“分鍾”;
l 發送80H訪問字節,初始化“秒鍾”,開始計時。
調用:
l 發送81H訪問字節,讀取“秒鍾”內容;
l 發送83H訪問字節,讀取“分鍾”內容;
l 發送85H訪問字節,讀取“時種”內容;
l 重復上述內容。
至於詳細過程還有具體的寄存器內容,筆者已在《建模篇》解釋過,所以讀者自己看着辦吧。接下來,讓我們進入本實驗的重點內容吧。
表32.3 DS1302的時序參數①。
最小 |
最大 |
||||
時序參數 |
標示 |
時間 |
時鍾(50Mhz) |
時間 |
時鍾(50Mhz) |
Clock Frequency |
FCLK |
2Mhz |
25 |
||
Clock High Time |
TCH |
250ns |
12.5 |
||
Clock Low Time |
TCL |
250ns |
12.5 |
||
Clock Rise and Fall |
TR,TF |
0ns |
0 |
500ns |
25 |
首先讓我們先來瞧瞧相關的時序參數。表23.3為速率為2Mhz的時序參數。DS1302最高速率為2Mhz並且無下限,50Mhz的量化結果為25。時鍾信號拉高TCH或拉低TCL至少需要保持250ns,量化結果為12.5。至於時鍾信號上山TR或者下山TF最大時間為500ns,極端說是最小時間是0ns。
圖23.5 時序參數①。
如圖23.5所示,那是時鍾信號還有相關的時序參數,左圖為理想時序,右圖為物理時序。
TR+TH造就前半時鍾周期,TF+TL造就后半時鍾周期,然后TR+TH+TF+TL 為一個時鍾周期。
表23.4 DS1302的時序參數②。
最小 |
最大 |
||||
時序參數 |
標示 |
時間 |
時鍾(50Mhz) |
時間 |
時鍾(50Mhz) |
CE to Clock Setup |
TCC |
1us |
50 |
||
Data to Clock Setup |
TDC |
50ns |
2.5 |
圖23.6 時序參數②。
如表23.4是TCC還有TDC的時序參數,雖然兩者都有 Setup 字眼,實際上它們都是推擠作用的時序參數。如圖23.6的右圖所示,那是物理時序圖,TCC向右推擠SCLK信號,TDC向右推擠TDC信號。換做左圖的理想時序圖,TCC使SCLK被覆蓋,TDC使DATA被覆蓋。有些同學可能會被TCC的要求嚇到,既然是1us。原理上,它是時鍾周期的兩倍,不過那是推擠作用的時序參數,只要操作結束之前一直拉高CS即可無視。
最小 |
最大 |
||||
時序參數 |
標示 |
時間 |
時鍾(50Mhz) |
時間 |
時鍾(50Mhz) |
CLOCK to Data Delay |
TCDD |
200ns |
10 |
||
Clock to Data Hold |
TCDH |
70ns |
3.5 |
圖23.7 時序參數③。
表23.4顯示TCDD還有TCDH兩只時序參數,如23.7的右圖所示,那是物理時序。我們知道DS1302是下降沿設置(輸出)數據,上升沿鎖存數據,期間TCDD將數據向右推擠,TCDH則就是典型的 THold,即鎖存數據以后的確保時間。如23.7的左圖所示,那是理想時序,由於這兩只都是小家伙,一般都無法完全覆蓋數據。
最小 |
最大 |
||||
時序參數 |
標示 |
時間 |
時鍾(50Mhz) |
時間 |
時鍾(50Mhz) |
CE Inactive Time |
TCWH |
1us |
50 |
||
CE to I/O High Impedance |
TCDZ |
70ns |
3.5 |
||
SCLK to I/O High Impedance |
TCCZ |
70ns |
3.5 |
表23.5有3個比較奇怪的時序參數,TCWH為片選信號進入靜態所需的時間,也認為是釋放片選所需的最小時間。至於 TCDZ 與 TCCZ 都是與高阻態有關的時序參數,而高阻態也與I/O息息相關。感覺上,高阻態好比一只切斷輸出的大刀,而且這只大刀必須由人操縱,其中TCDZ就是CE切斷輸出狀態所需的最小時間,TCCZ就是SCLK切斷輸出狀態所需的最小時間。
具體而言,如代碼代碼23.3所示:
module (...)
...
input Call,
inout SIO,
...
assign SIO = !Call ? D1 : 1’bz;
endmodule
代碼23.3
代碼23.3告訴我們,SIO由 D1 驅動輸出,而且Call拉高便將SIO的輸出切斷。假設TSSZ(Call to I/O High Impedance)是Call切斷輸出所需的時間 ... 細心觀察,Call一旦拉低,SIO並不會立即輸出高阻態,則是必須經歷一段時間。至於高阻態的大小姨媽,一般都是硬件內部(從機)的糾紛,鮮少與驅動方(主機)扯上關系,所以我們在此聊聊就好。
圖23.8 寫操作的物理時序(時序參數)。
圖23.9 讀操作的物理時序(時序參數)。
最后附上兩張官方的原圖23.8還有圖23.9作為本說明的謝幕,讀者就自己慢慢看着辦吧。理解完畢,我們便可以開始建模了。
圖23.10 DS1302基礎模塊的建模圖。
圖23.10是DS1302基礎模塊的建模圖,內容包含控制模塊與功能模塊,功能模塊負責最基礎的讀寫操作,控制模塊則負責功能調度,准備訪問字節等任務。換之,功能模塊的右邊是驅動硬件資源的頂層信號。其中,功能模塊的oData穿過控制模塊直接驅動外圍。
ds1302_funcmod.v
圖23.11 DS1302功能模塊的建模圖。
圖23.11是DS1302功能模塊的建模圖,Call/Done位寬為2,其中 [1]為寫操作,[0]為讀操作。具體內容讓我們來看代碼吧:
1. module ds1302_funcmod
2. (
3. input CLOCK, RESET,
4. output RTC_NRST,RTC_SCLK,
5. inout RTC_DATA,
6. input [1:0]iCall,
7. output oDone,
8. input [7:0]iAddr,iData,
9. output [7:0]oData
10. );
以上內容為相關的出入端聲明。
11. parameter FCLK = 6'd25, FHALF = 6'd12; // 2Mhz,(1/2Mhz)/(1/50Mhz)
12. parameter FF_Write = 6'd16, FF_Read = 6'd32;
13.
以上內容為偽函數入口地址以及常量聲明。FCLK為一個周期,FHALF為半周期。
14. reg [5:0]C1;
15. reg [5:0]i,Go;
16. reg [7:0]D1,T;
17. reg rRST, rSCLK, rSIO;
18. reg isQ,isDone;
19.
20. always @ ( posedge CLOCK or negedge RESET )
21. if( !RESET )
22. begin
23. C1 <= 6'd0;
24. { i,Go } <= { 6'd0,6'd0 };
25. { D1,T } <= { 8'd0,8'd0 };
26. { rRST, rSCLK, rSIO } <= 3'b000;
27. { isQ, isDone } <= 2'b00;
28. end
以上內容為相關的寄存器還有復位操作。D1為暫存讀取結果,T為偽函數的操作空間,isQ為 IO的控制輸出。
29. else if( iCall[1] )
30. case( i )
31.
32. 0:
33. begin { rRST,rSCLK } <= 2'b10; T <= iAddr; i <= FF_Write; Go <= i + 1'b1; end
34.
35. 1:
36. begin T <= iData; i <= FF_Write; Go <= i + 1'b1; end
37.
38. 2:
39. begin { rRST,rSCLK } <= 2'b00; i <= i + 1'b1; end
40.
41. 3:
42. begin isDone <= 1'b1; i <= i + 1'b1; end
43.
44. 4:
45. begin isDone <= 1'b0; i <= 6'd0; end
46.
47. /******************/
48.
49. 16,17,18,19,20,21,22,23:
50. begin
51. isQ = 1'b1;
52. rSIO <= T[i-16];
53.
54. if( C1 == 0 ) rSCLK <= 1'b0;
55. else if( C1 == FHALF ) rSCLK <= 1'b1;
56.
57. if( C1 == FCLK -1) begin C1 <= 6'd0; i <= i + 1'b1; end
58. else C1 <= C1 + 1'b1;
59. end
60.
61. 24:
62. i <= Go;
63.
64. endcase
以上內容為部分核心操作。以上內容是寫操作,步驟16~24是寫一個字節的偽函數。步驟0拉高片選,准備訪問字節,並且進入偽函數。步驟1准備寫入數據並且進入偽函數。步驟2拉低片選,步驟3~4則是用來產生完成信號。
65. else if( iCall[0] )
66. case( i )
67.
68. 0 :
69. begin { rRST,rSCLK } <= 2'b10; T <= iAddr; i <= FF_Write; Go <= i + 1'b1; end
70.
71. 1:
72. begin i <= FF_Read; Go <= i + 1'b1; end
73.
74. 2:
75. begin { rRST,rSCLK } <= 2'b00; D1 <= T; i <= i + 1'b1; end
76.
77. 3:
78. begin isDone <= 1'b1; i <= i + 1'b1; end
79.
80. 4:
81. begin isDone <= 1'b0; i <= 6'd0; end
82.
83. /*********************/
84.
85. 16,17,18,19,20,21,22,23:
86. begin
87. isQ = 1'b1;
88. rSIO <= T[i-16];
89.
90. if( C1 == 0 ) rSCLK <= 1'b0;
91. else if( C1 == FHALF ) rSCLK <= 1'b1;
92.
93. if( C1 == FCLK -1) begin C1 <= 6'd0; i <= i + 1'b1; end
94. else C1 <= C1 + 1'b1;
95. end
96.
97. 24:
98. i <= Go;
99.
100. /*********************/
101.
102. 32,33,34,35,36,37,38,39:
103. begin
104. isQ = 1'b0;
105.
106. if( C1 == 0 ) rSCLK <= 1'b0;
107. else if( C1 == FHALF ) begin rSCLK <= 1'b1; T[i-32] <= RTC_DATA; end
108.
109. if( C1 == FCLK -1) begin C1 <= 6'd0; i <= i + 1'b1; end
110. else C1 <= C1 + 1'b1;
111. end
112.
113. 40:
114. i <= Go;
115.
116. endcase
117.
以上內容為部分核心操作。以上內容是讀操作,步驟16~24是寫一個字節的偽函數,步驟32~40則是讀一個字節的偽函數。步驟0拉高使能,准備訪問字節並且進入寫函數。步驟1進入讀函數。步驟2拉低使能之余,也將讀取結果暫存至D。步驟3~4用來產生完成信號。
118. assign { RTC_NRST,RTC_SCLK } = { rRST,rSCLK };
119. assign RTC_DATA = isQ ? rSIO : 1'bz;
120. assign oDone = isDone;
121. assign oData = D1;
122.
123. endmodule
以上內容為相關輸出驅動聲明,其中rSIO驅動RTC_DATA,D驅動oData。
ds1302_ctrlmod.v
圖23.11 DS1302控制模塊的建模圖。
圖23.11是該控制模塊的建模圖,右邊信號用來調用功能模塊,左邊信號則被調用,其中Call/Done 為8位寬,位寬內容如表23.6所示:
表23.6 Call/Done 的位寬內容。
位 |
內容 |
[7] |
關閉寫保護 |
[6] |
寫入時鍾 |
[5] |
寫入分鍾 |
[4] |
寫入秒鍾 |
[3] |
開啟寫保護 |
[2] |
讀取時鍾 |
[1] |
讀取分鍾 |
[0] |
讀取秒鍾 |
1. module ds1302_ctrlmod
2. (
3. input CLOCK, RESET,
4. input [7:0]iCall,
5. output oDone,
6. input [7:0]iData,
7. output [1:0]oCall,
8. input iDone,
9. output [7:0]oAddr, oData
10. );
以上內容為相關的出入端聲明。
11. reg [7:0]D1,D2;
12.
13. always @ ( posedge CLOCK or negedge RESET )
14. if( !RESET )
15. begin
16. D1 <= 8'd0;
17. D2 <= 8'd0;
18. end
19. else
20. case( iCall[7:0] )
21.
22. 8'b1000_0000 : // Write unprotect
23. begin D1 = 8'h8E; D2 = 8'b0000_0000; end
24.
25. 8'b0100_0000 : // Write hour
26. begin D1 = 8'h84; D2 = iData; end
27.
28. 8'b0010_0000 : // Write minit
29. begin D1 = 8'h82; D2 = iData; end
30.
31. 8'b0001_0000 : // Write second
32. begin D1 = 8'h80; D2 = iData; end
33.
34. 8'b0000_1000 : // Write protect
35. begin D1 = 8'h8E; D2 = 8'b1000_0000; end
36.
37. 8'b0000_0100 : // Read hour
38. begin D1 = 8'h85; end
39.
40. 8'b0000_0010 : // Read minit
41. begin D1 = 8'h83; end
42.
43. 8'b0000_0001 : // Read second
44. begin D1 = 8'h81; end
45.
46. endcase
47.
以上內容為准備訪問字節還有數據節還的周邊操作,它會根據iCall 的內容准備D1與D2。
48. reg [1:0]i;
49. reg [1:0]isCall;
50. reg isDone;
51.
52. always @ ( posedge CLOCK or negedge RESET )
53. if( !RESET )
54. begin
55. i <= 2'd0;
56. isCall <= 2'b00;
57. isDone <= 1'b0;
58. end
以上內容為相關寄存器聲明還有復位操作。
59. else if( iCall[7:3] ) // Write action
60. case( i )
61.
62. 0 :
63. if( iDone ) begin isCall[1] <= 1'b0; i <= i + 1'b1; end
64. else begin isCall[1] <= 1'b1; end
65.
66. 1 :
67. begin isDone <= 1'b1; i <= i + 1'b1; end
68.
69. 2 :
70. begin isDone <= 1'b0; i <= 2'd0; end
71.
72. endcase
以上內容為調用寫操作。
73. else if( iCall[2:0] ) // Read action
74. case( i )
75.
76. 0 :
77. if( iDone ) begin isCall[0] <= 1'b0; i <= i + 1'b1; end
78. else begin isCall[0] <= 1'b1; end
79.
80. 1 :
81. begin isDone <= 1'b1; i <= i + 1'b1; end
82.
83. 2 :
84. begin isDone <= 1'b0; i <= 2'd0; end
85.
86. endcase
87.
以上內容為調用讀操作。
88. assign oDone = isDone;
89. assign oCall = isCall;
90. assign oAddr = D1;
91. assign oData = D2;
92.
93. endmodule
以上內容為相關的輸出驅動。
ds1302_basemod.v
該模塊的連線部署請參考圖23.10。
1. module ds1302_basemod
2. (
3. input CLOCK, RESET,
4. output RTC_NRST, RTC_SCLK,
5. inout RTC_DATA,
6. input [7:0]iCall,
7. output oDone,
8. input [7:0]iData,
9. output [7:0]oData
10. );
11. wire [7:0]AddrU1;
12. wire [7:0]DataU1;
13. wire [1:0]CallU1;
14.
15. ds1302_ctrlmod U1
16. (
17. .CLOCK( CLOCK ),
18. .RESET( RESET ),
19. .iCall( iCall ), // < top
20. .oDone( oDone ), // > top
21. .iData( iData ), // > top
22. .oCall( CallU1 ), // > U2
23. .iDone( DoneU2 ), // < U2
24. .oAddr( AddrU1 ), // > U2
25. .oData( DataU1 ) // > U2
26. );
27.
28. wire DoneU2;
29.
30. ds1302_funcmod U2
31. (
32. .CLOCK( CLOCK ),
33. .RESET( RESET ),
34. .RTC_NRST( RTC_NRST ), // > top
35. .RTC_SCLK( RTC_SCLK ), // > top
36. .RTC_DATA( RTC_DATA ), // <> top
37. .iCall( CallU1 ), // < U1
38. .oDone( DoneU2 ), // > U1
39. .iAddr( AddrU1 ), // > U1
40. .iData( DataU1 ), // > U1
41. .oData( oData ) // > top
42. );
43.
44. endmodule
ds1302_demo.v
圖23.12 實驗二十三的建模圖。
圖23.12是實驗二十三的基礎模塊。核心操作先初始化DS1302基礎模塊,然后無間斷從哪里讀取時鍾,分鍾還有秒鍾,最后驅動至SMG基礎模塊。具體內容讓我們來看代碼吧。
1. module ds1302_demo
2. (
3. input CLOCK, RESET,
4. output RTC_NRST, RTC_SCLK,
5. inout RTC_DATA,
6. output [7:0]DIG,
7. output [5:0]SEL
8. );
以上內容為相關出入端聲明。
9. wire DoneU1;
10. wire [7:0]DataU1;
11.
12. ds1302_basemod U1
13. (
14. .CLOCK( CLOCK ),
15. .RESET( RESET ),
16. .RTC_NRST( RTC_NRST ), // > top
17. .RTC_SCLK( RTC_SCLK ), // > top
18. .RTC_DATA( RTC_DATA ), // > top
19. .iCall( isCall ), // < core
20. .oDone( DoneU1 ), // > core
21. .iData( D1 ), // < core
22. .oData( DataU1 ) // > core
23. );
24.
以上內容為DS1302基礎模塊的實例化。
25. smg_basemod U2
26. (
27. .CLOCK( CLOCK ),
28. .RESET( RESET ),
29. .DIG( DIG ), // > top
30. .SEL( SEL ), // > top
31. .iData( D2 ) // < core
32. );
以上內容為SMG基礎模塊的實例化。
34. reg [3:0]i;
35. reg [7:0]isCall;
36. reg [7:0]D1;
37. reg [23:0]D2;
38.
39. always @ ( posedge CLOCK or negedge RESET )
40. if( !RESET )
41. begin
42. i <= 4'd0;
43. isCall <= 8'd0;
44. D1 <= 8'd0;
45. D2 <= 24'd0;
46. end
47. else
以上內容為相關寄存器聲明還有復位操作。
48. case( i )
49.
50. 0:
51. if( DoneU1 ) begin isCall[7] <= 1'b0; i <= i + 1'b1; end
52. else begin isCall[7] <= 1'b1; D1 <= 8'h00; end
53.
54. 1:
55. if( DoneU1 ) begin isCall[6] <= 1'b0; i <= i + 1'b1; end
56. else begin isCall[6] <= 1'b1; D1 <= { 4'd2, 4'd1 }; end
57.
58. 2:
59. if( DoneU1 ) begin isCall[5] <= 1'b0; i <= i + 1'b1; end
60. else begin isCall[5] <= 1'b1; D1 <= { 4'd5, 4'd9 }; end
61.
62. 3:
63. if( DoneU1 ) begin isCall[4] <= 1'b0; i <= i + 1'b1; end
64. else begin isCall[4] <= 1'b1; D1 <= { 4'd5, 4'd0 }; end
65.
66. /*************/
67.
以上內容為核心操作的部分內容,步驟0關閉寫保護,步驟1初始化時鍾,步驟2初始化分鍾,步驟3初始化秒鍾並且開啟計時。
68. 4:
69. if( DoneU1 ) begin D2[7:0] <= DataU1; isCall[0] <= 1'b0; i <= i + 1'b1; end
70. else begin isCall[0] <= 1'b1; end
71.
72. 5:
73. if( DoneU1 ) begin D2[15:8] <= DataU1; isCall[1] <= 1'b0; i <= i + 1'b1; end
74. else begin isCall[1] <= 1'b1; end
75.
76. 6:
77. if( DoneU1 ) begin D2[23:16] <= DataU1; isCall[2] <= 1'b0; i <= 4'd4; end
78. else begin isCall[2] <= 1'b1; end
79.
80. endcase
81.
82. endmodule
步驟4讀取秒鍾然后暫存至D2[7:0],步驟5讀取分鍾然后暫存至D2[15:8],步驟6讀取時鍾然后暫存至D2[23:16]。綜合完畢情切下載程序,如果數碼管從21-59-50開始起跑,表示實驗成功。
細節一:完整的個體模塊
本實驗的DS1302基礎模塊雖然是就緒的完整模塊,不過依然無法滿足那些欲無止境的讀者 ... 例如,讀年或者讀天,還是利用DS1302的RAM。對此,讀者請自己探索然后嘗試擴展該基礎模塊吧。