設(shè)計背景:
DS1302 是美國DALLAS公司推出的一種高性能、低功耗、帶RAM的實時時鐘電路,它可以對年、月、日、周、時、分、秒進行計時,具有閏年補償功能,工作電壓為2.5V~5.5V。采用三線接口與CPU進行同步通信,并可采用突發(fā)方式一次傳送多個字節(jié)的時鐘信號或RAM數(shù)據(jù)。DS1302內(nèi)部有一個31×8的用于臨時性存放數(shù)據(jù)的RAM寄存器。
設(shè)計原理:
DS1302芯片的封裝如下:
它有8個引腳,在我們的設(shè)計中我們只要驅(qū)動3個引腳就可以了,另外的引腳都是我們的硬件相連接的,和FPGA連接的有時鐘先sclk,串行數(shù)據(jù)數(shù)據(jù)接口IO,以及CE.。
其工作原理就是在數(shù)據(jù)的傳送過程中先把CE拉高,在每個數(shù)據(jù)的上升沿寫入數(shù)據(jù),在下降沿輸入數(shù)據(jù),一次只能讀寫一位數(shù)據(jù)。最初我們通過一個8位的控制指令來選擇讀寫,如果控制指令是單字節(jié)模式,連續(xù)的8個脈沖上升沿寫入,下降沿讀出數(shù)據(jù),一次只能讀取一個字節(jié),如果是突發(fā)模式通過連續(xù)的脈沖一次性的寫完7個字節(jié)的時間寄存器也可以一次性的讀完8--328位的ram數(shù)據(jù)。
控制指令有8位,第七位必須為高,如果是0寫入被禁止,第六位0是對時鐘寄存器的讀寫操作,為1對是控制對RAM區(qū)的讀寫操作。
bit1 -- 5 是對相關(guān)寄存器的操作,bit0是讀寫操作。
各個寄存器的的設(shè)置,和每位的表示如下圖,圖中高速我們讀寫時控制字是多少以及寫入寄存器的地址,和寫入的8位的時間表示我們可以通過下表來設(shè)置一個初始的時間。
涓流寄存器主要決定了DS1302的充電特性,涓流充電選擇位4--7位,1010涓流充電其他禁止充電,二級管選擇位3--2位,電阻選擇1--0位具體的選擇如下表:
突發(fā)模式下,表示我們可以連續(xù)寫,連讀,連續(xù)寫時必須寫滿7個時鐘寄存器。時序圖如下,是SPI通信。
下表表示數(shù)據(jù)傳送過程中數(shù)據(jù)的延遲,時鐘的周期等時間。
本次設(shè)計是通過配置DS1302芯片來實現(xiàn)實時時鐘的監(jiān)測,我們通過通過控制2個按鍵來選擇我們要在數(shù)碼管上顯示的時間,按下按鍵1我們來顯示周幾,按下按鍵2來顯示年月日,不按顯示時分秒,這樣顯示復(fù)合我們的數(shù)字表的顯示。
我的思路是先打開寫保護,一個一個寄存器的寫進去,然后關(guān)閉寫保護,然后再讀出數(shù)據(jù)。
設(shè)計架構(gòu)圖:
設(shè)計代碼:
頂層模塊
0moduleds_1302(clk,rst_n,sclk,ce,data,sel ,seg7,key);
1
2 inputclk,rst_n;
3 wire[23:0]shi_fen_miao;
4 wire[23:0]nian_yue_ri;
5 wire[23:0]day;
6 outputsclk,ce;
7 inoutdata;
8 output[7:0]seg7;
9 output[5:0]sel;
10 input[1:0]key;
11
12 seg seg_dut(
13 .clk(clk),
14 .rst_n(rst_n),
15 .sel(sel),
16 .seg7(seg7),
17 .data_in(shi_fen_miao)
18 );
19
20 time_ce time_ce(
21 .clk(clk),
22 .rst_n(rst_n),
23 .data(data),
24 .sclk(sclk),
25 .show_data(shi_fen_miao),
26 .ce(ce),
27 .key(key)
28 );
29
30 endmodule
設(shè)計模塊
0moduletime_ce(clk,rst_n,data,sclk,show_data,ce,key);
1
2 inputclk,rst_n;
3 inoutdata;
4 outputregsclk;
5 outputregce;
6 input[1:0]key;
7
8 regbuff;
9 regflag;
10 reg[7:0]times;
11 outputreg[23:0]show_data;
12 reg[23:0]shi_fen_miao;
13 reg[23:0]nian_yue_ri;
14 reg[7:0]day;
15
16
17 assigndata =flag ?buff :1'bz;//定義一個三態(tài),來控制IO口的輸入輸出
18
19 parameterw_1302 =16'h8e00; //取消寫保護
20 parameterw_miao =16'h8030; // 30秒
21 parameterw_fen =16'h8211;//11分
22 parameterw_shi =16'h8408; //24小時制的 8 點
23 parameterw_ri =16'h8621; //21日
24 parameterw_yue =16'h8803; //3月
25 parameterw_nian =16'h8c17; //2017年
26 parameterw_day =16'h8a03; //星期3
27 parameterr_1302 =16'h8e80;//寫保護
28 parameterw_dian =16'h90a7;//二個二極管8
29
30 //讀寄存器的設(shè)置
31 parameterr_miao =8'h81;
32 parameterr_fen =8'h83;
33 parameterr_shi =8'h85;
34 parameterr_ri =8'h87;
35 parameterr_yue =8'h89;
36 parameterr_nian =8'h8d;
37 parameterr_day =8'h8b;
38
39 reg[14:0]count;
40 reg[15:0]reg_data;
41 regw_flag;
42 regr_flag;
43 reg[1:0]state_r;
44
45 //定義一個序列及,來控制讀寫的時序
46 always@(posedgeclk)
47 if(!rst_n)
48 begin
49 count <=0;
50 state_r <=0;
51 end
52 else
53 case(state_r)
54 0 : if(r_flag ||w_flag)
55 state_r <=1;
56 else
57 state_r <=0;
58 1 : if(count <(400+34*250))
59 count <=count +1;
60 else
61 begin
62 state_r <=0;
63 count <=0;
64 end
65 default:state_r <=0;
66 endcase
67
68 //開始ce為低,然后拉高,過上最少4US后拉高SCLK
69 //在寫的時候我們控制總線,寫入命令,讀的時候釋放總線
70 //在上升沿寫入數(shù)據(jù),我們就要在上升沿前準(zhǔn)備數(shù)據(jù),
71 //在下降沿讀出數(shù)據(jù),我們就要在下降沿后接收數(shù)據(jù)
72 reg[7:0]time_temp;
73 always@(posedgeclk)
74 if(!rst_n)
75 begin
76 sclk <=0;
77 ce <=0;
78 flag <=0;
79 times <=0;
80 buff <=0;
81 time_temp <=0;
82 end
83 else
84 case(count)
85 20 : begince <=1;flag <=1;end
86 400+1*250 : beginsclk <=0;buff <=reg_data[8];end
87 400+2*250 : beginsclk <=1;end
88 400+3*250 : beginsclk <=0;buff <=reg_data[9];end
89 400+4*250 : beginsclk <=1;end
90 400+5*250 : beginsclk <=0;buff <=reg_data[10];end
91 400+6*250 : beginsclk <=1;end
92 400+7*250 : beginsclk <=0;buff <=reg_data[11];end
93 400+8*250 : beginsclk <=1;end
94 400+9*250 : beginsclk <=0;buff <=reg_data[12];end
95 400+10*250 : beginsclk <=1;end
96 400+11*250 : beginsclk <=0;buff <=reg_data[13];end
97 400+12*250 : beginsclk <=1;end
98 400+13*250 : beginsclk <=0;buff <=reg_data[14];end
99 400+14*250 : beginsclk <=1;end
100 400+15*250 : beginsclk <=0;buff <=reg_data[15];end
101
102 400+16*250 : if(w_flag)
103 sclk <=1;
104 elseif(r_flag)
105 beginsclk <=1;end
106
107 400+17*250 : if(w_flag)
108 beginsclk <=0;buff <=reg_data[0];end
109 elseif(r_flag)
110 beginsclk <=0;flag <=0;end
111
112 400+18*250 : if(w_flag)
113 sclk <=1;
114 elseif(r_flag)
115 beginsclk <=1;times[0]<=data;end
116
117 400+19*250 : if(w_flag)
118 beginsclk <=0;buff <=reg_data[1];end
119 elseif(r_flag)
120 sclk <=0;
121
122 400+20*250 : if(w_flag)
123 sclk <=1;
124 elseif(r_flag)
125 beginsclk <=1;times[1]<=data;end
126
127
128 400+21*250 : if(w_flag)
129 beginsclk <=0;buff <=reg_data[2];end
130 elseif(r_flag)
131 sclk <=0;
132
133 400+22*250 : if(w_flag)
134 sclk <=1;
135 elseif(r_flag)
136 beginsclk <=1;times[2]<=data;end
137
138 400+23*250 : if(w_flag)
139 beginsclk <=0;buff <=reg_data[3];end
140 elseif(r_flag)
141 sclk <=0;
142
143 400+24*250 : if(w_flag)
144 sclk <=1;
145 elseif(r_flag)
146 beginsclk <=1;times[3]<=data;end
147
148 400+25*250 : if(w_flag)
149 beginsclk <=0;buff <=reg_data[4];end
150 elseif(r_flag)
151 sclk <=0;
152
153 400+26*250 : if(w_flag)
154 sclk <=1;
155 elseif(r_flag)
156 beginsclk <=1;times[4]<=data;end
157
158 400+27*250 : if(w_flag)
159 beginsclk <=0;buff <=reg_data[5];end
160 elseif(r_flag)
161 sclk <=0;
162
163 400+28*250 : if(w_flag)
164 sclk <=1;
165 elseif(r_flag)
166 beginsclk <=1;times[5]<=data;end
167
168 400+29*250 : if(w_flag)
169 beginsclk <=0;buff <=reg_data[6];end
170 elseif(r_flag)
171 sclk <=0;
172
173 400+30*250 : if(w_flag)
174 sclk <=1;
175 elseif(r_flag)
176 beginsclk <=1;times[6]<=data;end
177
178 400+31*250 : if(w_flag)
179 beginsclk <=0;buff <=reg_data[7];end
180 elseif(r_flag)
181 sclk <=0;
182
183 400+32*250 :beginsclk <=1;times[7]<=data;end
184 400+33*250:beginsclk <=0;if(w_flag)flag <=0;elseif(r_flag)flag <=1;end
185 400+34*250 :ce <=0;
186 400+35*250 : ce <=1;
187
188 endcase
189
190 //一下模塊是控制模塊,每當(dāng)寫完一個寄存器后,計數(shù)會到400+35*25
191 //然后跳轉(zhuǎn)下一個狀態(tài)執(zhí)行下一個寄存器命令
192 //在讀模式下,計數(shù)到400+35*25是表示讀出了一個時間我們接收
193 //放到寄存器中
194
195 reg[5:0]state;
196 always@(posedgeclk)
197 if(!rst_n)
198 begin
199 reg_data <=0;
200 w_flag <=0;
201 r_flag <=0;
202 state <=0;
203 end
204 else
205 case(state)
206 0 : begin
207 w_flag <=1;
208 reg_data <=w_1302;
209 state <=1;
210 end
211
212 1 : begin
213 if(count ==400+34*250)
214 begin
215 reg_data <=w_miao;
216 state <=2;
217 end
218 else
219 state <=1;
220 end
221
222 2 : begin
223 if(count ==400+34*250)
224 begin
225 reg_data <=w_fen;
226 state <=3;
227 end
228 else
229 state <=2;
230 end
231 3 : begin
232 if(count ==400+34*250)
233 begin
234 reg_data <=w_shi;
235 state <=4;
236 end
237 else
238 state <=3;
239 end
240
241 4 : begin
242 if(count ==400+34*250)
243 begin
244 reg_data <=w_ri;
245 state <=5;
246 end
247 else
248 state <=4;
249 end
250
251 5 : begin
252 if(count ==400+34*250)
253 begin
254 reg_data <=w_yue;
255 state <=6;
256 end
257 else
258 state <=5;
259 end
260
261 6 : begin
262 if(count ==400+34*250)
263 begin
264 reg_data <=w_nian;
265 state <=7;
266 end
267 else
268 state <=6;
269 end
270
271 7 : begin
272 if(count ==400+34*250)
273 begin
274 reg_data <=w_day;
275 state <=8;
276 end
277 else
278 state <=7;
279 end
280
281 8 : begin
282 if(count ==400+34*250)
283 begin
284 reg_data <=r_1302;
285 state <=9;
286 end
287 else
288 state <=8;
289 end
290
291
292 ///////////////////////
293
294 9 : begin
295 if(count ==(400+250*34-1))
296 begin
297 w_flag <=0;
298 r_flag =1;
299 state <=10;
300 end
301 else
302 state <=9;
303 end
304 /////////////////時分秒
305 10 : begin
306 state <=11;
307 end
308
309 11 : begin
310 if(count ==400+34*250)
311 begin
312 state <=12;
313 shi_fen_miao[7:0]<=times;
314 end
315 else
316 begin
317 state <=11;
318 reg_data[15:8]<=r_miao;
319 end
320 end
321
322 12 : begin
323 if(count ==400+34*250)
324 begin
325 state <=13;
326 shi_fen_miao[15:8]<=times;
327 end
328 else
329 begin
330 state <=12;
331 reg_data[15:8]<=r_fen;
332 end
333 end
334
335 13 : begin
336 if(count ==400+34*250)
337 begin
338 shi_fen_miao[23:16]<=times;
339 state <=14;
340 end
341 else
342 begin
343 reg_data[15:8]<=r_shi;
344 state <=13;
345 end
346 end
347
348 //////////////// 年月日
349 14 : begin
350 if(count ==400+34*250)
351 begin
352 state <=15;
353 nian_yue_ri[7:0]<=times;
354 end
355 else
356 begin
357 state <=14;
358 reg_data[15:8]<=r_ri;
359 end
360 end
361
362 15 : begin
363 if(count ==400+34*250)
364 begin
365 state <=16;
366 nian_yue_ri[15:8]<=times;
367 end
368 else
369 begin
370 state <=15;
371 reg_data[15:8]<=r_yue;
372 end
373 end
374
375 16 : begin
376 if(count ==400+34*250)
377 begin
378 nian_yue_ri[23:16]<=times;
379 state <=17;
380 end
381 else
382 begin
383 reg_data[15:8]<=r_nian;
384 state <=16;
385 end
386 end
387
388 ////////周
389 17 : begin
390 if(count ==400+34*250)
391 begin
392 day <=times;
393 state <=10;
394 end
395 else
396 begin
397 reg_data[15:8]<=r_day;
398 state <=17;
399 end
400 end
401
402 default:state <=0;
403 endcase
404
405 //按鍵判斷需要輸出的時間是什么
406 always@(posedgeclk)
407 if(!rst_n)
408 begin
409 show_data <=0;
410 end
411 elseif(!key[0])
412 show_data <=day;
413 elseif(!key[1])
414 show_data <=nian_yue_ri;
415 else
416 show_data <=shi_fen_miao;
417
418 endmodule
數(shù)碼管模塊
0moduleseg(clk,rst_n,sel,seg7,data_in);
1
2 inputclk;
3 inputrst_n;
4 input[23:0]data_in;
5 outputreg[5:0]sel;
6 outputreg[7:0]seg7;
7
8 parameters0 =3'b000;
9 parameters1 =3'b001;
10 parameters2 =3'b010;
11 parameters3 =3'b011;
12 parameters4 =3'b100;
13 parameters5 =3'b101;
14
15 `defineT1ms 50_000
16 //`define T1ms 5
17 reg[15:0]count;
18 regflag;
19
20 //分頻模塊 1K的時鐘
21 always@(posedgeclk ornegedgerst_n)
22 if(!rst_n)
23 begin
24 count <=16'd0;
25 flag <=1;
26 end
27 else
28 if(count ==(`T1ms/2-1))
29 begin
30 count <=16'd0;
31 flag <=~flag;
32 end
33 else
34 begin
35 count <=count +1'b1;
36 end
37
38 reg[2:0]state;
39 reg[3:0]num;
40
41 //循壞掃描,選擇那一個數(shù)碼管顯示哪一位
42 always@(posedgeflag ornegedgerst_n)
43 if(!rst_n)
44 begin
45 sel <=3'b0;
46 state <=3'b0;
47 num <=4'b0;
48 end
49 else
50 begin
51 case(state)
52 s0:begin
53 state <=s1;
54 sel <=6'b011111;
55 num <=data_in[23:20];
56 end
57 s1:begin
58 state <=s2;
59 sel <=6'b101111;
60 num <=data_in[19:16];
61 end
62 s2:begin
63 state <=s3;
64 sel <=6'b110111;
65 num <=data_in[15:12];
66 end
67 s3:begin
68
69 state <=s4;
70 sel <=6'b111011;
71 num <=data_in[11:8];
72
73 end
74 s4:begin
75 state <=s5;
76 sel <=6'b111101;
77 num <=data_in[7:4];
78 end
79 s5:begin
80 state <=s0;
81 sel <=6'b111110;
82 num <=data_in[3:0];
83 end
84 default:state <=s0;
85 endcase
86 end
87
88 //編碼
89 always@(*)
90 begin
91 case(num)
92 0:seg7 =8'b1100_0000;
93 1:seg7 =8'b1111_1001;
94 2:seg7 =8'b1010_0100;
95 3:seg7 =8'b1011_0000;
96 4:seg7 =8'b1001_1001;
97 5:seg7 =8'b1001_0010;
98 6:seg7 =8'b1000_0010;
99 7:seg7 =8'b1111_1000;
100 8:seg7 =8'b1000_0000;
101 9:seg7 =8'b1001_0000;
102 10:seg7 =8'b1000_1000;
103 11:seg7 =8'b1000_0011;
104 12:seg7 =8'b1100_0110;
105 13:seg7 =8'b1010_0001;
106 14:seg7 =8'b1000_0110;
107 15:seg7 =8'b1000_1110;
108 default:;
109 endcase
110 end
111endmodule
測試模塊
0`timescale1ns/1ps
1
2moduletb;
3
4 regclk,rst_n;
5
6 wiresclk,ce;
7 wiredata;
8 wire[7:0]seg7;
9 wire[5:0]sel;
10
11 initialbegin
12 clk =1;
13 rst_n =0;
14
15 #200.1rst_n =1;
16
17 end
18
19 always#10clk =~clk;
20
21
22 ds_1302 dut(
23 .clk(clk),
24 .rst_n(rst_n),
25 .sclk(sclk),
26 .ce(ce),
27 .data(data),
28 .sel (sel),
29 .seg7(seg7)
30 );
31
32endmodule
仿真圖:
我們的測試圖中我們可以清楚的看到我們在發(fā)送的寄存器命令,時收回總線控制權(quán),讀數(shù)據(jù)時釋放了總線控制權(quán)。
下圖中是突發(fā)讀的時序圖,我的設(shè)計是我們一個一個的寫寄存器,必須寫滿7個時鐘寄存器,然后突發(fā)的讀,突發(fā)讀的時候拉高ce然后不停的讀接收數(shù)據(jù)就行了。
有興趣的的朋友可以在我設(shè)計的基礎(chǔ)上,做出突發(fā)讀寫,這樣也是對大家的提高。
-
FPGA
+關(guān)注
關(guān)注
1626文章
21678瀏覽量
602006
發(fā)布評論請先 登錄
相關(guān)推薦
評論