设计背景:
DS1302 是美国DALLAS公司推出的一种高性能、低功耗、带RAM的实时时钟电路,它可以对年、月、日、周、时、分、秒进行计时,具有闰年补偿功能,工作电压为2.5V~5.5V。采用三线接口与CPU进行同步通信,并可采用突发方式一次传送多个字节的时钟信号或RAM数据。DS1302内部有一个31×8的用于临时性存放数据的RAM寄存器。
设计原理:
DS1302芯片的封装如下:
它有8个引脚,在我们的设计中我们只要驱动3个引脚就可以了,另外的引脚都是我们的硬件相连接的,和FPGA连接的有时钟先sclk,串行数据数据接口IO,以及CE.。
其工作原理就是在数据的传送过程中先把CE拉高,在每个数据的上升沿写入数据,在下降沿输入数据,一次只能读写一位数据。最初我们通过一个8位的控制指令来选择读写,如果控制指令是单字节模式,连续的8个脉冲上升沿写入,下降沿读出数据,一次只能读取一个字节,如果是突发模式通过连续的脉冲一次性的写完7个字节的时间寄存器也可以一次性的读完8--328位的ram数据。
控制指令有8位,第七位必须为高,如果是0写入被禁止,第六位0是对时钟寄存器的读写操作,为1对是控制对RAM区的读写操作。
bit1 -- 5 是对相关寄存器的操作,bit0是读写操作。
各个寄存器的的设置,和每位的表示如下图,图中高速我们读写时控制字是多少以及写入寄存器的地址,和写入的8位的时间表示我们可以通过下表来设置一个初始的时间。
涓流寄存器主要决定了DS1302的充电特性,涓流充电选择位4--7位,1010涓流充电其他禁止充电,二级管选择位3--2位,电阻选择1--0位具体的选择如下表:
突发模式下,表示我们可以连续写,连读,连续写时必须写满7个时钟寄存器。时序图如下,是SPI通信。
下表表示数据传送过程中数据的延迟,时钟的周期等时间。
本次设计是通过配置DS1302芯片来实现实时时钟的监测,我们通过通过控制2个按键来选择我们要在数码管上显示的时间,按下按键1我们来显示周几,按下按键2来显示年月日,不按显示时分秒,这样显示复合我们的数字表的显示。
我的思路是先打开写保护,一个一个寄存器的写进去,然后关闭写保护,然后再读出数据。
设计架构图:
设计代码:
顶层模块
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
设计模块
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;//定义一个三态,来控制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 //读寄存器的设置
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 //在上升沿写入数据,我们就要在上升沿前准备数据,
71 //在下降沿读出数据,我们就要在下降沿后接收数据
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 //一下模块是控制模块,每当写完一个寄存器后,计数会到400+35*25
191 //然后跳转下一个状态执行下一个寄存器命令
192 //在读模式下,计数到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
数码管模块
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 //循坏扫描,选择那一个数码管显示哪一位
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
仿真图:
我们的测试图中我们可以清楚的看到我们在发送的寄存器命令,时收回总线控制权,读数据时释放了总线控制权。
下图中是突发读的时序图,我的设计是我们一个一个的写寄存器,必须写满7个时钟寄存器,然后突发的读,突发读的时候拉高ce然后不停的读接收数据就行了。
有兴趣的的朋友可以在我设计的基础上,做出突发读写,这样也是对大家的提高。
-
FPGA
+关注
关注
1624文章
21601浏览量
601065
发布评论请先 登录
相关推荐
评论