FPGA学习系列:36.实时时钟的设计

描述

设计背景:

    DS1302 是美国DALLAS公司推出的一种高性能、低功耗、带RAM的实时时钟电路,它可以对年、月、日、周、时、分、秒进行计时,具有闰年补偿功能,工作电压为2.5V~5.5V。采用三线接口与CPU进行同步通信,并可采用突发方式一次传送多个字节的时钟信号或RAM数据。DS1302内部有一个31×8的用于临时性存放数据的RAM寄存器。


设计原理:     

    DS1302芯片的封装如下:

    FPGA


    它有8个引脚,在我们的设计中我们只要驱动3个引脚就可以了,另外的引脚都是我们的硬件相连接的,和FPGA连接的有时钟先sclk,串行数据数据接口IO,以及CE.。

    其工作原理就是在数据的传送过程中先把CE拉高,在每个数据的上升沿写入数据,在下降沿输入数据,一次只能读写一位数据。最初我们通过一个8位的控制指令来选择读写,如果控制指令是单字节模式,连续的8个脉冲上升沿写入,下降沿读出数据,一次只能读取一个字节,如果是突发模式通过连续的脉冲一次性的写完7个字节的时间寄存器也可以一次性的读完8--328位的ram数据。

    控制指令有8位,第七位必须为高,如果是0写入被禁止,第六位0是对时钟寄存器的读写操作,为1对是控制对RAM区的读写操作。

    bit1 -- 5 是对相关寄存器的操作,bit0是读写操作。

                 FPGA


                各个寄存器的的设置,和每位的表示如下图,图中高速我们读写时控制字是多少以及写入寄存器的地址,和写入的8位的时间表示我们可以通过下表来设置一个初始的时间。

    FPGA


    涓流寄存器主要决定了DS1302的充电特性,涓流充电选择位4--7位,1010涓流充电其他禁止充电,二级管选择位3--2位,电阻选择1--0位具体的选择如下表:

   FPGA


   突发模式下,表示我们可以连续写,连读,连续写时必须写满7个时钟寄存器。时序图如下,是SPI通信。

    


    下表表示数据传送过程中数据的延迟,时钟的周期等时间。


    FPGA


    FPGA


    本次设计是通过配置DS1302芯片来实现实时时钟的监测,我们通过通过控制2个按键来选择我们要在数码管上显示的时间,按下按键1我们来显示周几,按下按键2来显示年月日,不按显示时分秒,这样显示复合我们的数字表的显示。

    我的思路是先打开写保护,一个一个寄存器的写进去,然后关闭写保护,然后再读出数据。

    

    

设计架构图:

    FPGA


设计代码:

顶层模块

0  module ds_1302(clk, rst_n, sclk, ce, data, sel ,seg7, key);

1 

2  input clk, rst_n;

3  wire [23:0] shi_fen_miao;

4  wire [23:0] nian_yue_ri;

5  wire [23:0] day;

6  output  sclk, ce;

7  inout data;

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 

 

设计模块

0  module time_ce(clk, rst_n, data, sclk, show_data, ce, key);

1  

2   input clk, rst_n;

3   inout data;

4   output reg sclk;

5   output reg ce;

6   input [1:0] key;

7  

8   reg buff;

9   reg flag;

10  reg [7:0] times;

11  output reg [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  assign data = flag ? buff : 1'bz;     //定义一个三态,来控制IO口的输入输出

18 

19  parameter w_1302 = 16'h8e00;    //取消写保护

20  parameter w_miao = 16'h8030;    // 30

21  parameter w_fen = 16'h8211;    //11

22  parameter w_shi = 16'h8408;  //24小时制的 8

23  parameter w_ri = 16'h8621;   //21

24  parameter w_yue = 16'h8803;     //3

25  parameter w_nian = 16'h8c17;  //2017

26  parameter w_day = 16'h8a03;   //星期3

27  parameter r_1302 = 16'h8e80;   //写保护

28  parameter w_dian = 16'h90a7;  //二个二极管8

29 

30  //读寄存器的设置

31  parameter r_miao = 8'h81;

32  parameter r_fen = 8'h83;

33  parameter r_shi = 8'h85;

34  parameter r_ri = 8'h87;

35  parameter r_yue = 8'h89;

36  parameter r_nian = 8'h8d;

37  parameter r_day = 8'h8b;

38 

39  reg [14:0] count;

40  reg [15:0] reg_data;

41  reg w_flag;

42  reg r_flag;

43  reg [1:0] state_r;

44 

45  //定义一个序列及,来控制读写的时序

46  always @ (posedge clk)

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 @ (posedge clk)

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  : begin ce <=1; flag <= 1; end

86     400 + 1 * 250 : begin sclk <= 0; buff <= reg_data[8]; end

87     400 + 2 * 250 : begin sclk <= 1;  end

88     400 + 3 * 250 : begin sclk <= 0; buff <= reg_data[9];end

89     400 + 4 * 250 : begin sclk <= 1;  end

90     400 + 5 * 250 : begin sclk <= 0; buff <= reg_data[10]; end

91     400 + 6 * 250 : begin sclk <= 1; end

92     400 + 7 * 250 : begin sclk <= 0; buff <= reg_data[11]; end

93     400 + 8 * 250 : begin sclk <= 1; end

94     400 + 9 * 250 : begin sclk <= 0; buff <= reg_data[12];end

95     400 + 10 * 250 : begin sclk <= 1; end

96     400 + 11 * 250 : begin sclk <= 0; buff <= reg_data[13];end

97     400 + 12 * 250 : begin sclk <= 1; end

98     400 + 13 * 250 : begin sclk <= 0; buff <= reg_data[14]; end

99     400 + 14 * 250 : begin sclk <= 1;  end

100    400 + 15 * 250 : begin sclk <= 0; buff <= reg_data[15]; end  

101    

102    400 + 16 * 250 :  if(w_flag)

103            sclk <= 1; 

104          else if(r_flag)

105           begin  sclk <= 1;  end

106

107    400 + 17 * 250 : if(w_flag)

108           begin sclk <= 0; buff <= reg_data[0]; end

109          else if(r_flag)

110           begin sclk <= 0;flag <= 0;end

111      

112    400 + 18 * 250 :  if(w_flag)

113            sclk <= 1; 

114          else if(r_flag)

115           begin  sclk <= 1; times[0] <= data; end

116

117    400 + 19 * 250 : if(w_flag)

118           begin sclk <= 0; buff <= reg_data[1]; end

119          else if(r_flag)

120           sclk <= 0;  

121    

122    400 + 20 * 250 :  if(w_flag)

123            sclk <= 1; 

124          else if(r_flag)

125           begin  sclk <= 1; times[1] <= data; end

126

127

128    400 + 21 * 250 : if(w_flag)

129           begin sclk <= 0; buff <= reg_data[2]; end

130          else if(r_flag)

131           sclk <= 0;  

132    

133    400 + 22 * 250 :  if(w_flag)

134            sclk <= 1; 

135          else if(r_flag)

136           begin  sclk <= 1; times[2] <= data; end

137

138    400 + 23 * 250 : if(w_flag)

139           begin sclk <= 0; buff <= reg_data[3]; end

140          else if(r_flag)

141           sclk <= 0;  

142          

143    400 + 24 * 250 :  if(w_flag)

144            sclk <= 1; 

145          else if(r_flag)

146           begin sclk <= 1; times[3] <= data; end

147

148    400 + 25 * 250 : if(w_flag)

149           begin sclk <= 0; buff <= reg_data[4]; end

150          else if(r_flag)

151           sclk <= 0;  

152    

153    400 + 26 * 250 :  if(w_flag)

154            sclk <= 1; 

155          else if(r_flag)

156           begin sclk <= 1; times[4] <= data; end

157

158    400 + 27 * 250 : if(w_flag)

159           begin sclk <= 0; buff <= reg_data[5]; end

160          else if(r_flag)

161           sclk <= 0; 

162    

163    400 + 28 * 250 :  if(w_flag)

164            sclk <= 1; 

165          else if(r_flag)

166           begin sclk <= 1; times[5] <= data; end

167

168    400 + 29 * 250 : if(w_flag)

169           begin sclk <= 0; buff <= reg_data[6]; end

170          else if(r_flag)

171           sclk <= 0; 

172    

173    400 + 30 * 250 :  if(w_flag)

174            sclk <= 1; 

175          else if(r_flag)

176           begin sclk <= 1; times[6] <= data; end

177

178    400 + 31 * 250 : if(w_flag)

179           begin sclk <= 0; buff <= reg_data[7]; end

180          else if(r_flag)

181           sclk <= 0; 

182          

183    400 + 32 * 250 :  begin sclk <= 1;  times[7] <= data; end

184    400 + 33 * 250 :  begin sclk <= 0; if(w_flag) flag <= 0; else if(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 @ (posedge clk)

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 @ (posedge clk)

407  if(!rst_n)

408   begin

409    show_data <= 0;

410   end

411  else if (!key[0])

412   show_data <= day;

413  else if (!key[1])

414   show_data <= nian_yue_ri;

415  else

416   show_data <= shi_fen_miao;

417  

418 endmodule 

 

数码管模块

0  module seg(clk,rst_n,sel,seg7,data_in);

1  

2   input clk;

3   input rst_n;

4   input  [23:0] data_in;

5   output reg [5:0] sel;

6   output reg [7:0] seg7;

7  

8   parameter s0 = 3'b000;

9   parameter s1 = 3'b001;

10  parameter s2 = 3'b010;

11  parameter s3 = 3'b011;

12  parameter s4 = 3'b100;

13  parameter s5 = 3'b101;

14 

15  `define T1ms  50_000

16  //`define T1ms  5

17  reg [15:0] count;

18  reg  flag;

19 

20  //分频模块 1K的时钟

21  always @ (posedge clk or negedge rst_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 @ (posedge flag or negedge rst_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

111 endmodule

 

测试模块

0  `timescale 1ns/ 1ps

1 

2 module tb;

3 

4  reg clk, rst_n;

5 

6  wire  sclk, ce;

7  wire data;

8  wire [7:0] seg7;

9  wire [5:0] sel;

10

11 initial begin

12  clk = 1;

13  rst_n = 0;

14  

15  #200.1 rst_n = 1;

16  

17 end

18

19 always #10 clk = ~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

32 endmodule 

 

仿真图:

    


    我们的测试图中我们可以清楚的看到我们在发送的寄存器命令,时收回总线控制权,读数据时释放了总线控制权。

 

    下图中是突发读的时序图,我的设计是我们一个一个的写寄存器,必须写满7个时钟寄存器,然后突发的读,突发读的时候拉高ce然后不停的读接收数据就行了。


    


    

    有兴趣的的朋友可以在我设计的基础上,做出突发读写,这样也是对大家的提高。









    

 





打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分