这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » anmko的进程贴:综合实验-基于DS1302的万年历LCD1602显示(最终版

共223条 17/23 |‹ 15 16 17 18 19 20 ›| 跳转至
工程师
2012-12-14 14:39:00     打赏
161楼
不错,FPGA的ROM使用还是比较简单的。用altera自带的ip直接设置好就可以用了

助工
2012-12-14 23:35:48     打赏
162楼

向大侠学习!!!


高工
2012-12-15 02:16:22     打赏
163楼

写的好详细 学习啦!


高工
2012-12-15 20:09:27     打赏
164楼
玩了两天,这家伙又更新了

工程师
2012-12-20 20:58:43     打赏
165楼
才来拜读!!顶楼主的帖子!学习啦!!

高工
2012-12-21 11:18:41     打赏
166楼
QII带的好多可视化工具,比直接写Verilog方便许多,熟练使用能省不少事。
光写Verilog知识和入门。再高级点的应用,肯定不会只有Verilog了
或许FPGA巅峰神人可以完全用Verilog搞定一切

高工
2012-12-23 11:51:04     打赏
167楼
试试能不能发帖

高工
2012-12-23 11:56:53     打赏
168楼
上 能发帖 门

高工
2012-12-27 22:32:51     打赏
169楼

26、DS1302实验

因为还没吧按键调节时间的弄好,就先上个图片吧




明天估计能上代码,,,嘻嘻

DS1302的驱动是这样的:

module ds1302_drive(clk,rst,srst,sclk,sdata,TimeData,DateData)

 input rst; //外部复位
 input clk; //输入时钟
 output srst; //ds1302复位
 output sclk; //ds1302时钟
 inout sdata; //ds1302数据口
 output[23:0] TimeData; //时间数据
 output[31:0] DateData; //日历数据
  
 reg data; //sdata的缓存,
 reg isOut; //因为sdata是双向口,所以需要标志位isOut来管理数据的输入输出
 assign sdata=(isOut)? data:1'bz; //isOut:1、输出;0、高阻

 parameter 
   IDLE  = 4'd0,
   WR_Sec = 4'd1,
   WR_Min = 4'd2,
   WR_Hour = 4'd3,
   WR_Week = 4'd4,
   WR_Day = 4'd5,
   WR_Mont = 4'd6,
   WR_Year = 4'd7;   

 parameter
   RD_Sec = 4'd8,
   RD_Min = 4'd9,
   RD_Hour = 4'd10,
   RD_Week = 4'd11,
   RD_Day = 4'd12,
   RD_Mont = 4'd13,
   RD_Year = 4'd14,
   CLOSE_W = 4'd15;

 parameter
   WR_state_0  = 5'd0,
   WR_state_1  = 5'd1,
   WR_state_2  = 5'd2,
   WR_state_3  = 5'd3,
   WR_state_4  = 5'd4,
   WR_state_5  = 5'd5,
   WR_state_6  = 5'd6,
   WR_state_7  = 5'd7,
   WR_state_8  = 5'd8,
   WR_state_9  = 5'd9,
   WR_state_a  = 5'd10,
   WR_state_b  = 5'd11,
   WR_state_c  = 5'd12,
   WR_state_d  = 5'd13,
   WR_state_e  = 5'd14,
   WR_state_f  = 5'd15,
   WR_state_10 = 5'd16;

 parameter
   RD_state_0  = 5'd0,
   RD_state_1  = 5'd1,
   RD_state_2  = 5'd2,
   RD_state_3  = 5'd3,
   RD_state_4  = 5'd4,
   RD_state_5  = 5'd5,
   RD_state_6  = 5'd6,
   RD_state_7  = 5'd7,
   RD_state_8  = 5'd8,
   RD_state_9  = 5'd9,
   RD_state_a  = 5'd10,
   RD_state_b  = 5'd11,
   RD_state_c  = 5'd12,
   RD_state_d  = 5'd13,
   RD_state_e  = 5'd14,
   RD_state_f  = 5'd15,
   RD_state_10 = 5'd16;

 reg[7:0]counter;
 reg clk_sta; //状态机的时钟8us/period
 
always@(posedge clk ) begin //or negedge rst) begin
/*  iRD_flag(!rst)
   begin
   counter <= 8'b0;
   clk_sta <= 1'b0;
   end
  else */if(counter<=100)
   counter<=counter+8'b1;
  else
   begin
   clk_sta<=~clk_sta;
   counter<=0;
   end
 end

 reg sclk_r;//ds1302的工作时钟
 always @ (negedge clk_sta ) begin//or negedge rst) begin
  if(!srst_r)
   sclk_r <= 1'b0;
  else
   sclk_r<=~sclk_r;
 end
 assign sclk=sclk_r;

 reg Rest_flag; //重新设置标志位
 reg [4:0]WR_state; //WR_SET的状态
 reg [4:0]RD_state; //RD_T任务的状态
 reg [23:0] TimeData_r;
 reg [31:0] DateData_r;
 reg RD_flag; //写任务的标志
 reg WR_flag; //读任务标志
 reg [7:0]CMD = 8'h00; //command
 reg [7:0]SEC = 8'h50; //时间/日历
 reg [7:0]MIN = 8'h59; //分钟
 reg [7:0]HOU = 8'h23; //小时
 reg [7:0]DAY = 8'h31; //天
 reg [7:0]Month = 8'h12; //月
 reg [7:0]Week = 8'h04; //星期
 reg [7:0]Year = 8'h12; //年
 reg [7:0]register1; //command
 reg [7:0]register3;
 reg [7:0]register4; //读进数据寄存器
 reg [3:0]state; //状态机
 reg srst_r;
 always @(posedge clk_sta ) begin
 if(rst==0)
  begin
  //初始化操作时,isOut<=0;所以输出呈现高阻态
   srst_r<=0;
   data<=0; //输出缓存器被清空
   WR_flag<=0; 
   RD_flag<=0; 
   state<=IDLE;
   isOut<=0;
   register1<=8'b10001110; //关闭写保护
   TimeData_r<=0;
   DateData_r<=0;
   Rest_flag<=1;
   WR_state<=0;
   RD_state<=0;
  end
 else  
  case(state)
    //IDLE状态选择工作状态还是初始设置状态
   IDLE : begin
      //Rest_flag==1时,重新设置数据
      if(Rest_flag == 1'b1)
       begin
       if(WR_flag == 1'b0)
        begin
        WR_SET(CMD);
        state <= IDLE;
        end
       else
        begin
        Rest_flag <= 1'b0;
        srst_r <= 1'b0;
        isOut <= 1'b0;
        WR_flag <= 1'b0;
        register1 <= 8'b1000_0000;////写时钟/日历寄存器
        state <= WR_Sec;
        end
       end
      else if(Rest_flag == 1'b0)
       begin
       register4 <= 8'b1000_0001;
       isOut <= 1'b0;
       srst_r <= 1'b0;
       RD_flag <= 1'b0;
       state <= RD_Sec;
       end
      else state <= IDLE;
      end 
   WR_Sec : begin
       if(WR_flag == 1'b0) WR_SET(SEC);//写秒
       else
        begin
        state <= WR_Min;
        isOut <= 1'b0;
        WR_flag <= 1'b0;
        register1 <= 8'b1000_0010;
        end
       end
   WR_Min : begin
       if(WR_flag == 1'b0) WR_SET(MIN);
       else
        begin
        state <= WR_Hour;
        isOut <= 1'b0;
        WR_flag <= 1'b0;
        register1 <= 8'b1000_0100;
        end
       end
   WR_Hour : begin
       if(WR_flag == 1'b0) WR_SET(HOU);
       else
        begin
        state <= WR_Week;
        isOut <= 1'b0;
        WR_flag <= 1'b0;
        register1 <= 8'b1000_1010;
        end
       end
   WR_Week : begin
       if(WR_flag == 1'b0) WR_SET(Week);
       else
        begin
        state <= WR_Day;
        isOut <= 1'b0;
        WR_flag <= 1'b0;
        register1 <= 8'b1000_0110;
        end
       end
   WR_Day : begin
       if(WR_flag == 1'b0) WR_SET(DAY);
       else
        begin
        state <= WR_Mont;
        isOut <= 1'b0;
        WR_flag <= 1'b0;
        register1 <= 8'b1000_1000;
        end
       end
   WR_Mont : begin
       if(WR_flag == 1'b0) WR_SET(Month);
       else
        begin
        state <= WR_Year;
        isOut <= 1'b0;
        WR_flag <= 1'b0;
        register1 <= 8'b1000_1100;
        end
       end 
   WR_Year : begin
       if(WR_flag == 1'b0) WR_SET(Year);
       else
        begin
        state <= CLOSE_W;
        isOut <= 1'b0;
        WR_flag <= 1'b0;
        register1 <= 8'b10001110;
        end
       end
   RD_Sec : begin
       if(RD_flag == 1'b0) RD_T;
       else
        begin
        TimeData_r[7:0] <= register3;
        srst_r <= 1'b0;
        RD_flag <= 1'b0;
        register4 <= 8'b1000_0011;
        state <= RD_Min;
        end
       end
   RD_Min : begin
       if(RD_flag == 1'b0) RD_T;
       else
        begin
        TimeData_r[15:8] <= register3;
        srst_r <= 1'b0;
        RD_flag <= 1'b0;
        register4 <= 8'b1000_0101;
        state <= RD_Hour;
        end
       end
   RD_Hour : begin 
       if(RD_flag == 1'b0)  RD_T;
       else
        begin
        TimeData_r[23:16] <= register3;
        srst_r <= 1'b0;
        RD_flag <= 1'b0;
        register4 <= 8'b1000_1011;
        state <= RD_Week;
        end
       end
   RD_Week : begin
       if(RD_flag == 1'b0)  RD_T;
       else
        begin
        DateData_r[7:0] <= register3;
        srst_r <= 1'b0;
        RD_flag <= 1'b0;
        register4 <= 8'b1000_0111;
        state <= RD_Day;
        end
       end
   RD_Day : begin
       if(RD_flag == 1'b0) RD_T;
       else
        begin
        DateData_r[15:8] <= register3;
        srst_r <= 1'b0;
        RD_flag <= 1'b0;
        register4 <= 8'b1000_1001;
        state <= RD_Mont;
        end
       end
   RD_Mont : begin
       if(RD_flag == 1'b0) RD_T;
       else
        begin
        DateData_r[23:16] <= register3;
        srst_r <= 1'b0;
        RD_flag <= 1'b0;
        register4 <= 8'b1000_1101;
        state <= RD_Year;
        end
       end
   RD_Year :  begin
       if(RD_flag == 1'b0) RD_T;
       else
        begin
        DateData_r[31:24] <= register3;
        srst_r <= 1'b0;
        RD_flag <= 1'b0;
        register4 <= 8'b1000_0001;
        state <= RD_Sec;
       // RD_flaglag_initial<=0;
        end
       end
   CLOSE_W : begin
       if(WR_flag == 1'b0) WR_SET(8'h10);
       else
        begin
        state <= IDLE;
        isOut <= 1'b0;
        WR_flag <= 1'b0;
        RD_flag <= 1'b0;
        Rest_flag <= 1'b0;  
        end
       end
   default : begin
       Rest_flag <= 1'b0;
       srst_r <= 1'b0;
       data <= 1'b0;
       WR_flag <= 1'b0;
       RD_flag <= 1'b0;
       state <= RD_Sec;
       register3 <= 1'b0;//接受数据的寄存器
       register4 <= 8'b1000_0001;//读任务的指令寄存器
       CMD <= 8'b0;
       end
   endcase
 end

 task RD_T;
  begin
  case(RD_state)
   RD_state_0 : begin
        if(!sclk_r)
         begin
         isOut <= 1'b1;
         srst_r <= 1'b1;
         data <= register4[0];
         RD_state <= RD_state_1;
         end
        else
         begin
         srst_r <= 1'b0;
         RD_state <= RD_state_0;
         data <= register4[0];
         isOut <= 1'b1;
         end
        end
   RD_state_1 : begin
        if(!sclk_r)
         begin
         data <= register4[1];
         RD_state <= RD_state_2;
         end
        else
         begin
         data <= data;
         RD_state <= RD_state;
         end
        end
   RD_state_2 : begin
        if(!sclk_r)
         begin
         data <= register4[2];
         RD_state <= RD_state_3;
         end
        else
         begin
         data <= data;
         RD_state <= RD_state;
         end
        end
   RD_state_3 : begin
        if(!sclk_r)
         begin
         data <= register4[3];
         RD_state <= RD_state_4;
         end
        else
         begin
         data <= data;
         RD_state <= RD_state;
         end
        end
   RD_state_4 : begin
        if(!sclk_r)
         begin
         data <= register4[4];
         RD_state <= RD_state_5;
         end
        else
         begin
         data <= data;
         RD_state <= RD_state;
         end
        end
   RD_state_5 : begin
        if(!sclk_r)
         begin
         data <= register4[5];
         RD_state <= RD_state_6;
         end
        else
         begin
         data <= data;
         RD_state <= RD_state;
         end
        end
   RD_state_6 : begin
        if(!sclk_r)
         begin
         data <= register4[6];
         RD_state <= RD_state_7;
         end
        else
         begin
         data <= data;
         RD_state <= RD_state;
         end
        end
   RD_state_7 : begin
        if(!sclk_r)
         begin
         data <= register4[7];
         RD_state <= RD_state_8;
         end
        else
         begin
         data <= data;
         RD_state <= RD_state;
         end
        end
   RD_state_8 : begin
        if(!sclk_r)
         begin
         isOut <= 1'b0;
         RD_state <= RD_state_9; 
         end
        else
         RD_state <= RD_state;
        end
   RD_state_9 : begin
        if(!sclk_r) RD_state <= RD_state_a;
        else RD_state <= RD_state;
        end
   RD_state_a : begin
        if(!sclk_r) RD_state <= RD_state_b;
        else RD_state <= RD_state;
        end
   RD_state_b : begin
        if(!sclk_r) RD_state <= RD_state_c;
        else RD_state <= RD_state;
        end
   RD_state_c : begin
        if(!sclk_r) RD_state <= RD_state_d;
        else RD_state <= RD_state;
        end
   RD_state_d : begin
        if(!sclk_r) RD_state <= RD_state_e;
        else RD_state <= RD_state;  
        end
   RD_state_e : begin
        if(!sclk_r) RD_state <= RD_state_f;
        else RD_state <= RD_state;
        end
   RD_state_f : begin
        if(!sclk_r) RD_state <= RD_state_10;
        else RD_state <= RD_state_f;
        end
   RD_state_10 : begin
        if(!sclk_r)
         begin//该begin end块不执行
         RD_flag <= 1'b1;
         srst_r <= 1'b0; 
         RD_state <= RD_state_0;//do not run
         end
        else
         begin
         RD_flag <= 1'b1;
         srst_r <= 1'b0;
         RD_state <= RD_state_0;
         end
        end
   default  : begin
        RD_state <= RD_state_0;
        end
  endcase
  end
 endtask

 always @( posedge sclk_r or negedge  rst) begin
  if(!rst)
   register3<= 8'b0;
  else
   begin
   case(RD_state)
    RD_state_9 : register3[0] <= sdata;
    RD_state_a  : register3[1] <= sdata;
    RD_state_b  : register3[2] <= sdata;
    RD_state_c  : register3[3] <= sdata;
    RD_state_d  : register3[4] <= sdata;
    RD_state_e  : register3[5] <= sdata;
    RD_state_f  : register3[6] <= sdata;
    RD_state_10 : register3[7] <= sdata;
    default  : register3 <= register3;
   endcase
   end
 end
  task WR_SET;
  input [7:0]reg_store;
  begin
   case(WR_state)
    WR_state_0 : begin
         if(!sclk_r)
          begin
          isOut <= 1'b1;
          srst_r <= 1'b1;//低电平时才可以将srst_r拉高
          data <= register1[0];
          WR_state <= WR_state_1;
          end
         else
          begin
          srst_r <= 1'b0;
          WR_state <= 1'b0;
          data <= register1[0];
          isOut <= 1'b0;
          end
         end
    WR_state_1 : begin
         if(!sclk_r)
          begin
          isOut <= 1'b1;
          data <= register1[1];
          WR_state <= WR_state_2;
          end
         else
          WR_state <= WR_state;
         end
    WR_state_2 : begin
         if(!sclk_r)
          begin
          isOut <= 1'b1;
          data <= register1[2];
          WR_state <= WR_state_3;
          end
         else
          WR_state <= WR_state;
         end
    WR_state_3 : begin
         if(!sclk_r)
          begin
          data <= register1[3];
          WR_state <= WR_state_4;
          end
          else
          WR_state <= WR_state;
         end
    WR_state_4 : begin
         if(!sclk_r)
          begin
           data <= register1[4];
           WR_state <= WR_state_5;
          end
         else
          WR_state <= WR_state;
         end
    WR_state_5 : begin
         if(!sclk_r)
          begin
          data <= register1[5];
          WR_state <= WR_state_6;
          end
         else
          WR_state <= WR_state;
         end
    WR_state_6 : begin
         if(!sclk_r)
          begin
          data <= register1[6];
          WR_state <= WR_state_7;
          end
         else
          WR_state <= WR_state;
         end
    WR_state_7 : begin
         if(!sclk_r)
          begin
          data <= register1[7];
          WR_state <= WR_state_8;
          end
         else
          WR_state <= WR_state;
         end
    WR_state_8 : begin
         if(!sclk_r)
          begin
          data <= reg_store[0];
          WR_state <= WR_state_9;
          end
         else
          WR_state <= WR_state;
         end
    WR_state_9 : begin
         if(!sclk_r)
          begin
          srst_r <= 1'b1;
          data <= reg_store[1];
          WR_state <= WR_state_a;
          end
         else
          WR_state <= WR_state;
         end
    WR_state_a : begin
         if(!sclk_r)
          begin
          data <= reg_store[2];
          WR_state <= WR_state_b;
          end
         else
          WR_state <= WR_state;
         end
    WR_state_b : begin
         if(!sclk_r)
          begin
          data <= reg_store[3];
          WR_state <= WR_state_c;
          end
         else
          WR_state <= WR_state;
         end
    WR_state_c : begin
         if(!sclk_r)
          begin
          data <= reg_store[4];
          WR_state <= WR_state_d;
          end
         else
          WR_state <= WR_state;
         end
    WR_state_d : begin
         if(!sclk_r)
          begin
          data <= reg_store[5];
          WR_state <= WR_state_e;
          end
         else
          WR_state <= WR_state;
         end
    WR_state_e : begin
         if(!sclk_r)
          begin
          data <= reg_store[6];
          WR_state <= WR_state_f;
          end
         else
          WR_state <= WR_state;
         end
    WR_state_f : begin
         if(!sclk_r)
          begin
          data <= reg_store[7];
          WR_state <= WR_state_10;
          end
         else
          WR_state <= WR_state;
         end
    WR_state_10 : begin
         if(!sclk_r)
          begin
          WR_state <= WR_state_0;
          WR_flag <= 1'b1;
          srst_r <= 1'b0;
          end
         else
          WR_state <= WR_state; //读完数据不能马上把延迟一段时间再srst_r拉低
         end
    default  : WR_state <= WR_state_0;
  endcase
  end 
 endtask 
//----------------------END of TASK------------------------

 assign TimeData = TimeData_r;
 assign DateData = DateData_r;
 assign srst = srst_r;


endmodule


高工
2012-12-28 22:28:58     打赏
170楼

27、基于DS1302的万年历LCD1602显示(最终修改版)

1、解决了上电时间复位的问题;
2、加上了LED校时指示。D1点亮为调节年;D2点亮为调节月;D3点亮为调节日;D4点亮为调节兴趣;D5点亮为调节时;D6点亮为调节分;D7点亮为调节秒;全灭的时候为读取时间模式。

一、实验名称:基于DS1302的万年历LCD1602显示
二、实验目的:通过DS1302通信读取时间;按键校时;并显示在LCD1602上。
三、设计的思路:按功能要求划分四大模块:按键模块、DS1302驱动、2选1选择器、LCD1602显示模块。如下框图所示:




1、按键模块:校时数据输入。一个有三个键:S1功能键;S2计数加键;S3计数减键。调用了按键例化模块(前面更新的)

      S1按键计数八种状态,分别为0)不校时、1)校对年、2)校对月、3)校对日、4)校对星期、5)校对时、6)校对分、7)校对秒。8个状态轮回一次则说明校时完毕,把校时的数据传递给DS1302驱动同时控制2选1选择器让LCD1602显示的是DS1302读出来的数据。
      S2按键对以上的1~7种状态进行计数加处理。
      S3按键对以上的1~7种状态进行计数加处理。

2、DS1302驱动:负责DS1302的读写控制,要求上电的时候数据不复位。

3、2选1选择器:这个是个下下选择,希望以后改进能把它去掉。在这里的作用是:校时的时候显示校时的时间数据;不校时的时候显示DS1302读出来的实时时间。
4、LCD1602显示:显示数据用的,具体的不细说了,前面已经在例化里介绍过。

四、相关代码:
1、顶层代码

module ds1302_lcd(clk,rst,lcd_en,lcd_rs,lcd_rw,lcd_data,key_in,Led_Out,SCLK,SCE,SIO);
 
 input clk;
 input rst;
 input[2:0] key_in;
 output lcd_en;
 output lcd_rs;
 output lcd_rw;
 output[7:0] lcd_data;
 output[6:0] Led_Out;
 
 output SCLK;
 output SCE;
 inout SIO;
 
 wire[23:0] TimeData;
 wire[31:0] DateData;
 wire[23:0] TimeData1;
 wire[31:0] DateData1;
 wire[23:0] TimeData2;
 wire[31:0] DateData2;
 
 wire Mode_flag;
 wire chanle;
 key_mode  Key
  (
   .clk(clk),
   .rst(rst),
   .key_in(key_in),
   .TimeData2Ds(TimeData2),
   .DateData2Ds(DateData2),
   .Mode_flag(Mode_flag),
   .Led_Out(Led_Out),
   .chanle_out(chanle)
  );
  
 ds1302_drive DS1302
  (
   .clk(clk),
   .rst(rst),
   .srst(SCE),
   .sclk(SCLK),
   .sdata(SIO),
   .TimeData(TimeData1),
   .DateData(DateData1),
   .TimeData_in(TimeData2),
   .DateData_in(DateData2),
   .WRTime_flag(Mode_flag)
  );

 TwoChanleToOne  Two2One
  (
   .clk(clk),
   .chanle_in(chanle),
   .TimeData1(TimeData1),
   .DateData1(DateData1),
   .TimeData2(TimeData2),
   .DateData2(DateData2),
   .TimeDataToDs(TimeData),
   .DateDataToDs(DateData)
  );
 
 lcd1602_driver  LCD
  (
   .clk(clk),
   .rst_n(rst),
   .Disp_data1(TimeData),
   .Disp_data2(DateData),  
   .lcd_en(lcd_en),  // lcd enable
   .lcd_rs(lcd_rs),  // record,statement
   .lcd_rw(lcd_rw),
   .lcd_data(lcd_data)
  );

endmodule

2、按键模块代码:
module key_mode(clk,rst,key_in,TimeData2Ds,DateData2Ds);
 input clk;
 input rst;
 input[2:0] key_in;
 output[23:0] TimeData2Ds;
 output[31:0] DateData2Ds;
 output Mode_flag;
 
 wire key_flag;
 wire[2:0] key_value;
 key_interface key_inter
 (
  .clk(clk),
  .rst(rst), 
  .key_trigger(key_in), //按键输入端口
  .key_flag(key_flag), //按键标识
  .key_value(key_value) //按键数值输出
 );
 
 reg[3:0] addr_seg_r = 4'b0;
 reg[7:0] Year = 8'b0;
 reg[7:0] Mont = 8'b0;
 reg[7:0] Day  = 8'b0;
 reg[7:0] Week = 8'b0;
 reg[7:0] Hour = 8'b0;
 reg[7:0] Min  = 8'b0;
 reg[7:0] Sec  = 8'b0;
 
 always @(posedge key_flag) begin
  
  case(key_value)
   3'b001 : begin
       if(addr_seg_r >= 3'd13) 
        begin
        addr_seg_r <= 3'd0;
        Mode_flag <= 1'b1;
        end
       else
        begin
        addr_seg_r <= addr_seg_r + 1'b1;
        Mode_flag <= 1'b0;
        end
       end
   3'b010 : begin
       case(addr_seg_r)
        3'd0 : begin
           if(Year >= 8'd99)
            Year <= 8'd0;
           else
            Year <= Year + 1'b1;
           end
        3'd1 : begin
           if(Mont >= 8'd12)
            Mont <= 8'd0;
           else
            Mont <= Mont + 1'b1;
           end
        3'd2 : begin
           case(Mont)
            8'd1,8'd3,8'd5,8'd7,8'd8,8'd10,8'd12: //31Day
              begin
               if(Day >= 8'd31)
                Day <= 8'd1;
               else
                Day <= Day + 1'b1;
              end
            8'd2 :  //28/29Day
              begin
               if(Year%4 == 8'd0) 
                begin
                if(Day >= 8'd29)
                 Day <= 8'd1;
                else
                 Day <= Day + 1'b1;
                end
               else
                begin
                if(Day >= 8'd28)
                 Day <= 8'd1;
                else
                 Day <= Day + 1'b1;
                end
               end           
            8'd4,8'd6,8'd9,8'd11: //30Day
              begin
               if(Day >= 8'd30)
                Day <= 8'd1;
               else
                Day <= Day + 1'b1;
              end
           endcase
           end
        3'd3 : begin
           if(Hour >= 8'd23)
            Hour <= 8'd0;
           else
            Hour <= Hour + 1'b1;
           end
        3'd5 : begin
           if(Min >= 8'd59)
            Min <= 8'd0;
           else
            Min <= Min + 1'b1;
           end
        3'd6 : begin
           if(Sec >= 8'd59)
            Sec <= 8'd0;
           else
            Sec <= Sec + 1'b1;
           end
        3'd7 : begin
           if(Week >= 8'd7)
            Week <= 8'd1;
           else
            Week <= Week + 1'b1;
           end
        default :;
       endcase
       end
   3'b100 : begin
       case(addr_seg_r)
        3'd0 : begin
           if(Year == 8'd0)
            Year <= 8'd99;
           else
            Year <= Year - 1'b1;
           end
        3'd1 : begin
           if(Mont == 8'd0)
            Mont <= 8'd12;
           else
            Mont <= Mont - 1'b1;
           end
        3'd2 : begin
           case(Mont)
            8'd1,8'd3,8'd5,8'd7,8'd8,8'd10,8'd12: //31Day
              begin
               if(Day == 8'd1)
                Day <= 8'd31;
               else
                Day <= Day - 1'b1;
              end
            8'd2 :  //28/29Day
              begin
               if(Year%4 == 8'd0) 
                begin
                if(Day == 8'd1)
                 Day <= 8'd29;
                else
                 Day <= Day - 1'b1;
                end
               else
                begin
                if(Day == 8'd1)
                 Day <= 8'd28;
                else
                 Day <= Day - 1'b1;
                end
               end           
            8'd4,8'd6,8'd9,8'd11: //30Day
              begin
               if(Day == 8'd1)
                Day <= 8'd30;
               else
                Day <= Day - 1'b1;
              end
           endcase
           end
        3'd3 : begin
           if(Hour == 8'd0)
            Hour <= 8'd23;
           else
            Hour <= Hour - 1'b1;
           end
        3'd5 : begin
           if(Min == 8'd0)
            Min <= 8'd59;
           else
            Min <= Min - 1'b1;
           end
        3'd6 : begin
           if(Sec == 8'd0)
            Sec <= 8'd59;
           else
            Sec <= Sec - 1'b1;
           end
        3'd7 : begin
           if(Week == 8'd1)
            Week <= 8'd7;
           else
            Week <= Week - 1'b1;
           end
        default :;
       endcase
       end
   default : ;
  endcase
 end
 
 always @(posedge key_flag) begin
  TimeData2Ds[3:0] <= Sec%10;
  TimeData2Ds[7:4] <= Sec/10;
  TimeData2Ds[11:8] <= Min%10;
  TimeData2Ds[15:12]<= Min/10;
  TimeData2Ds[19:16]<= Hour%10;
  TimeData2Ds[23:20]<= Hour/10;  
  DateData2Ds[7:0] <= Week;
  DateData2Ds[11:8] <= Day%10;
  DateData2Ds[15:12]<= Day/10;
  DateData2Ds[19:16]<= Mont%10;
  DateData2Ds[23:20]<= Mont/10;
  DateData2Ds[27:24]<= Year%10;
  DateData2Ds[31:28]<= Year/10;
 end

 reg Mode_flag_r1,Mode_flag_r0;
 always @(posedge clk or negedge rst) begin
  if(!rst)
   begin
   Mode_flag_r0 <= 1'b0;
   Mode_flag_r1 <= 1'b0;
   end
  else
   begin
   Mode_flag_r0 <= Mode_flag_r;
   Mode_flag_r1 <= Mode_flag_r0;
   end
 end
 
 assign Mode_flag = (!Mode_flag_r1) & Mode_flag_r0;
 
endmodule

3、DS1302驱动的最终代码:

module ds1302_drive(clk,rst,srst,sclk,sdata,TimeData,DateData,TimeData_in,DateData_in,WRTime_flag);

 input rst; //外部复位
 input clk; //输入时钟
 input[23:0] TimeData_in;
 input[31:0] DateData_in;
 input WRTime_flag;
 output srst; //ds1302复位
 output sclk; //ds1302时钟
 inout sdata; //ds1302数据
 output[23:0] TimeData; //时间数据
 output[31:0] DateData; //日历数据
 
// output clk_out;
  
 reg data; //sdata的缓存,
 reg isOut; //因为sdata是双向口,所以需要一个标志位isOut来管理数据的输入和输出
 assign sdata=(isOut)? data:1'bz; //isOut:1:允许输出;0:是高阻,输入

 parameter 
   IDLE = 4'd0,
   WR_Sec = 4'd1,
   WR_Min = 4'd2,
   WR_Hour = 4'd3,
   WR_Week = 4'd4,
   WR_Day = 4'd5,
   WR_Mont = 4'd6,
   WR_Year = 4'd7;   

 parameter
   RD_Sec = 4'd8,
   RD_Min = 4'd9,
   RD_Hour = 4'd10,
   RD_Week = 4'd11,
   RD_Day = 4'd12,
   RD_Mont = 4'd13,
   RD_Year = 4'd14,
   CLOSE_W = 4'd15;

 parameter
   WR_state_0  = 5'd0,
   WR_state_1  = 5'd1,
   WR_state_2  = 5'd2,
   WR_state_3  = 5'd3,
   WR_state_4  = 5'd4,
   WR_state_5  = 5'd5,
   WR_state_6  = 5'd6,
   WR_state_7  = 5'd7,
   WR_state_8  = 5'd8,
   WR_state_9  = 5'd9,
   WR_state_a  = 5'd10,
   WR_state_b  = 5'd11,
   WR_state_c  = 5'd12,
   WR_state_d  = 5'd13,
   WR_state_e  = 5'd14,
   WR_state_f  = 5'd15,
   WR_state_10 = 5'd16;

 parameter
   RD_state_0  = 5'd0,
   RD_state_1  = 5'd1,
   RD_state_2  = 5'd2,
   RD_state_3  = 5'd3,
   RD_state_4  = 5'd4,
   RD_state_5  = 5'd5,
   RD_state_6  = 5'd6,
   RD_state_7  = 5'd7,
   RD_state_8  = 5'd8,
   RD_state_9  = 5'd9,
   RD_state_a  = 5'd10,
   RD_state_b  = 5'd11,
   RD_state_c  = 5'd12,
   RD_state_d  = 5'd13,
   RD_state_e  = 5'd14,
   RD_state_f  = 5'd15,
   RD_state_10 = 5'd16;

 reg[7:0]counter;
 wire clk_sta; //状态机的时钟8us/period
 
always@(posedge clk ) begin //or negedge rst) begin
   if(counter <= 8'd100)
   counter <= counter + 1'b1;
  else
   begin
   counter <= 8'b0;
   end
 end
 assign clk_sta = counter == 8'd100;

 reg sclk_r;//ds1302的工作时钟
 always @ (posedge clk_sta) begin
  if(!srst_r)
   sclk_r <= 1'b0;
  else
   sclk_r<=~sclk_r;
 end
 assign sclk=sclk_r;
 
  always@ (posedge clk) begin
  SEC[7:0] <= TimeData_in[7:0];
  MIN[7:0] <= TimeData_in[15:8];
  HOU[7:0] <= TimeData_in[23:16];
  Week[7:0]<= DateData_in[7:0];
  DAY[7:0] <= DateData_in[15:8];
  Month[7:0]<= DateData_in[23:16];
  Year[7:0]<= DateData_in[31:24];
 end
 
 reg Rest_flag; //重新设置标志位
 reg [4:0]WR_state; //WR_SET的状态
 reg [4:0]RD_state; //RD_T任务的状态
 reg [23:0] TimeData_r;
 reg [31:0] DateData_r;
 reg RD_flag; //写任务的标志
 reg WR_flag; //读任务标志
 reg [7:0]CMD = 8'h00; //command
 reg [7:0]SEC = 8'h50; //时间/日历
 reg [7:0]MIN = 8'h59; //分钟
 reg [7:0]HOU = 8'h23; //小时
 reg [7:0]DAY = 8'h31; //天
 reg [7:0]Month = 8'h12; //月
 reg [7:0]Week = 8'h04; //星期
 reg [7:0]Year = 8'h12; //年
 reg [7:0]register1; //command
 reg [7:0]register2;
 reg [7:0]register3; //读进数据寄存器
 reg [3:0]state; //状态机
 reg srst_r;

 always @(posedge clk ) begin
 if(WRTime_flag)
  begin
  //初始化操作时,isOut<=0;所以输出呈现高阻态
   srst_r <= 1'b0;
   data <= 1'b0; //输出缓存器被清空
   WR_flag <= 1'b0; //WR_SET任务的标志位
   RD_flag <= 1'b0; //RD_T任务标志位
   state <= IDLE;
   isOut <= 1'b0;
   register1 <= 8'b10001110; //关闭写保护
   TimeData_r <= 24'b0;
   DateData_r <= 32'b0;
   Rest_flag <= 1'b1;
   WR_state <= 1'b0;
   RD_state <= 1'b0;
  end
 else if(clk_sta)
  begin
  case(state)
    //IDLE状态选择工作状态还是初始设置状态
   IDLE : begin
      //Rest_flag==1时,重新设置数据
      if(Rest_flag == 1'b1)
       begin
       if(WR_flag == 1'b0)
        begin
        WR_SET(CMD);
        state <= IDLE;
        end
       else
        begin
        Rest_flag <= 1'b0;
        srst_r <= 1'b0;
        isOut <= 1'b0;
        WR_flag <= 1'b0;
        register1 <= 8'b1000_0000;////写时钟/日历寄存器
        state <= WR_Sec;
        end
       end
      else if(Rest_flag == 1'b0)
       begin
       register3 <= 8'b1000_0001;
       isOut <= 1'b0;
       srst_r <= 1'b0;
       RD_flag <= 1'b0;
       state <= RD_Sec;
       end
      else state <= IDLE;
      end 
   WR_Sec : begin
       if(WR_flag == 1'b0) WR_SET(SEC);//写秒
       else
        begin
        state <= WR_Min;
        isOut <= 1'b0;
        WR_flag <= 1'b0;
        register1 <= 8'b1000_0010;
        end
       end
   WR_Min : begin
       if(WR_flag == 1'b0) WR_SET(MIN);
       else
        begin
        state <= WR_Hour;
        isOut <= 1'b0;
        WR_flag <= 1'b0;
        register1 <= 8'b1000_0100;
        end
       end
   WR_Hour : begin
       if(WR_flag == 1'b0) WR_SET(HOU);
       else
        begin
        state <= WR_Week;
        isOut <= 1'b0;
        WR_flag <= 1'b0;
        register1 <= 8'b1000_1010;
        end
       end
   WR_Week : begin
       if(WR_flag == 1'b0) WR_SET(Week);
       else
        begin
        state <= WR_Day;
        isOut <= 1'b0;
        WR_flag <= 1'b0;
        register1 <= 8'b1000_0110;
        end
       end
   WR_Day : begin
       if(WR_flag == 1'b0) WR_SET(DAY);
       else
        begin
        state <= WR_Mont;
        isOut <= 1'b0;
        WR_flag <= 1'b0;
        register1 <= 8'b1000_1000;
        end
       end
   WR_Mont : begin
       if(WR_flag == 1'b0) WR_SET(Month);
       else
        begin
        state <= WR_Year;
        isOut <= 1'b0;
        WR_flag <= 1'b0;
        register1 <= 8'b1000_1100;
        end
       end 
   WR_Year : begin
       if(WR_flag == 1'b0) WR_SET(Year);
       else
        begin
        state <= CLOSE_W;
        isOut <= 1'b0;
        WR_flag <= 1'b0;
        register1 <= 8'b10001110;
        end
       end
   RD_Sec : begin
       if(RD_flag == 1'b0) RD_T;
       else
        begin
        TimeData_r[7:0] <= register2;
        srst_r <= 1'b0;
        RD_flag <= 1'b0;
        register3 <= 8'b1000_0011;
        state <= RD_Min;
        end
       end
   RD_Min : begin
       if(RD_flag == 1'b0) RD_T;
       else
        begin
        TimeData_r[15:8] <= register2;
        srst_r <= 1'b0;
        RD_flag <= 1'b0;
        register3 <= 8'b1000_0101;
        state <= RD_Hour;
        end
       end
   RD_Hour : begin 
       if(RD_flag == 1'b0)  RD_T;
       else
        begin
        TimeData_r[23:16] <= register2;
        srst_r <= 1'b0;
        RD_flag <= 1'b0;
        register3 <= 8'b1000_1011;
        state <= RD_Week;
        end
       end
   RD_Week : begin
       if(RD_flag == 1'b0)  RD_T;
       else
        begin
        DateData_r[7:0] <= register2;
        srst_r <= 1'b0;
        RD_flag <= 1'b0;
        register3 <= 8'b1000_0111;
        state <= RD_Day;
        end
       end
   RD_Day : begin
       if(RD_flag == 1'b0) RD_T;
       else
        begin
        DateData_r[15:8] <= register2;
        srst_r <= 1'b0;
        RD_flag <= 1'b0;
        register3 <= 8'b1000_1001;
        state <= RD_Mont;
        end
       end
   RD_Mont : begin
       if(RD_flag == 1'b0) RD_T;
       else
        begin
        DateData_r[23:16] <= register2;
        srst_r <= 1'b0;
        RD_flag <= 1'b0;
        register3 <= 8'b1000_1101;
        state <= RD_Year;
        end
       end
   RD_Year :  begin
       if(RD_flag == 1'b0) RD_T;
       else
        begin
        DateData_r[31:24] <= register2;
        srst_r <= 1'b0;
        RD_flag <= 1'b0;
        register3 <= 8'b1000_0001;
        state <= RD_Sec;
       // RD_flaglag_initial<=0;
        end
       end
   CLOSE_W : begin
       if(WR_flag == 1'b0) WR_SET(8'h10);
       else
        begin
        state <= IDLE;
        isOut <= 1'b0;
        WR_flag <= 1'b0;
        RD_flag <= 1'b0;
        Rest_flag <= 1'b0;  
        end
       end
   default : begin
       Rest_flag <= 1'b0;
       srst_r <= 1'b0;
       data <= 1'b0;
       WR_flag <= 1'b0;
       RD_flag <= 1'b0;
       state <= RD_Sec;
       register2 <= 1'b0;//接受数据的寄存器
       register3 <= 8'b1000_0001;//读任务的指令寄存器
       CMD <= 8'b0;
       end
   endcase
  end
 end

 task RD_T;
  begin
  case(RD_state)
   RD_state_0 : begin
        if(!sclk_r)
         begin
         isOut <= 1'b1;
         srst_r <= 1'b1;
         data <= register3[0];
         RD_state <= RD_state_1;
         end
        else
         begin
         srst_r <= 1'b0;
         RD_state <= RD_state_0;
         data <= register3[0];
         isOut <= 1'b1;
         end
        end
   RD_state_1 : begin
        if(!sclk_r)
         begin
         data <= register3[1];
         RD_state <= RD_state_2;
         end
        else
         begin
         data <= data;
         RD_state <= RD_state;
         end
        end
   RD_state_2 : begin
        if(!sclk_r)
         begin
         data <= register3[2];
         RD_state <= RD_state_3;
         end
        else
         begin
         data <= data;
         RD_state <= RD_state;
         end
        end
   RD_state_3 : begin
        if(!sclk_r)
         begin
         data <= register3[3];
         RD_state <= RD_state_4;
         end
        else
         begin
         data <= data;
         RD_state <= RD_state;
         end
        end
   RD_state_4 : begin
        if(!sclk_r)
         begin
         data <= register3[4];
         RD_state <= RD_state_5;
         end
        else
         begin
         data <= data;
         RD_state <= RD_state;
         end
        end
   RD_state_5 : begin
        if(!sclk_r)
         begin
         data <= register3[5];
         RD_state <= RD_state_6;
         end
        else
         begin
         data <= data;
         RD_state <= RD_state;
         end
        end
   RD_state_6 : begin
        if(!sclk_r)
         begin
         data <= register3[6];
         RD_state <= RD_state_7;
         end
        else
         begin
         data <= data;
         RD_state <= RD_state;
         end
        end
   RD_state_7 : begin
        if(!sclk_r)
         begin
         data <= register3[7];
         RD_state <= RD_state_8;
         end
        else
         begin
         data <= data;
         RD_state <= RD_state;
         end
        end
   RD_state_8 : begin
        if(!sclk_r)
         begin
         isOut <= 1'b0;
         RD_state <= RD_state_9; 
         end
        else
         RD_state <= RD_state;
        end
   RD_state_9 : begin
        if(!sclk_r) RD_state <= RD_state_a;
        else RD_state <= RD_state;
        end
   RD_state_a : begin
        if(!sclk_r) RD_state <= RD_state_b;
        else RD_state <= RD_state;
        end
   RD_state_b : begin
        if(!sclk_r) RD_state <= RD_state_c;
        else RD_state <= RD_state;
        end
   RD_state_c : begin
        if(!sclk_r) RD_state <= RD_state_d;
        else RD_state <= RD_state;
        end
   RD_state_d : begin
        if(!sclk_r) RD_state <= RD_state_e;
        else RD_state <= RD_state;  
        end
   RD_state_e : begin
        if(!sclk_r) RD_state <= RD_state_f;
        else RD_state <= RD_state;
        end
   RD_state_f : begin
        if(!sclk_r) RD_state <= RD_state_10;
        else RD_state <= RD_state_f;
        end
   RD_state_10 : begin
        if(!sclk_r)
         begin
         RD_flag <= 1'b1;
         srst_r <= 1'b0; 
         RD_state <= RD_state_0;//do not run
         end
        else
         begin
         RD_flag <= 1'b1;
         srst_r <= 1'b0;
         RD_state <= RD_state_0;
         end
        end
   default  : begin
        RD_state <= RD_state_0;
        end
  endcase
  end
 endtask

 always @( posedge sclk_r or negedge  rst) begin
  if(!rst)
   register2<= 8'b0;
  else
   begin
   case(RD_state)
    RD_state_9 : register2[0] <= sdata;
    RD_state_a  : register2[1] <= sdata;
    RD_state_b  : register2[2] <= sdata;
    RD_state_c  : register2[3] <= sdata;
    RD_state_d  : register2[4] <= sdata;
    RD_state_e  : register2[5] <= sdata;
    RD_state_f  : register2[6] <= sdata;
    RD_state_10 : register2[7] <= sdata;
    default  : register2 <= register2;
   endcase
   end
 end

 task WR_SET;
  input [7:0]reg_store;
  begin
   case(WR_state)
    WR_state_0 : begin
         if(!sclk_r)
          begin
          isOut <= 1'b1;
          srst_r <= 1'b1;//低电平时才可以将srst_r拉高
          data <= register1[0];
          WR_state <= WR_state_1;
          end
         else
          begin
          srst_r <= 1'b0;
          WR_state <= 1'b0;
          data <= register1[0];
          isOut <= 1'b0;
          end
         end
    WR_state_1 : begin
         if(!sclk_r)
          begin
          isOut <= 1'b1;
          data <= register1[1];
          WR_state <= WR_state_2;
          end
         else
          WR_state <= WR_state;
         end
    WR_state_2 : begin
         if(!sclk_r)
          begin
          isOut <= 1'b1;
          data <= register1[2];
          WR_state <= WR_state_3;
          end
         else
          WR_state <= WR_state;
         end
    WR_state_3 : begin
         if(!sclk_r)
          begin
          data <= register1[3];
          WR_state <= WR_state_4;
          end
          else
          WR_state <= WR_state;
         end
    WR_state_4 : begin
         if(!sclk_r)
          begin
           data <= register1[4];
           WR_state <= WR_state_5;
          end
         else
          WR_state <= WR_state;
         end
    WR_state_5 : begin
         if(!sclk_r)
          begin
          data <= register1[5];
          WR_state <= WR_state_6;
          end
         else
          WR_state <= WR_state;
         end
    WR_state_6 : begin
         if(!sclk_r)
          begin
          data <= register1[6];
          WR_state <= WR_state_7;
          end
         else
          WR_state <= WR_state;
         end
    WR_state_7 : begin
         if(!sclk_r)
          begin
          data <= register1[7];
          WR_state <= WR_state_8;
          end
         else
          WR_state <= WR_state;
         end
    WR_state_8 : begin
         if(!sclk_r)
          begin
          data <= reg_store[0];
          WR_state <= WR_state_9;
          end
         else
          WR_state <= WR_state;
         end
    WR_state_9 : begin
         if(!sclk_r)
          begin
          srst_r <= 1'b1;
          data <= reg_store[1];
          WR_state <= WR_state_a;
          end
         else
          WR_state <= WR_state;
         end
    WR_state_a : begin
         if(!sclk_r)
          begin
          data <= reg_store[2];
          WR_state <= WR_state_b;
          end
         else
          WR_state <= WR_state;
         end
    WR_state_b : begin
         if(!sclk_r)
          begin
          data <= reg_store[3];
          WR_state <= WR_state_c;
          end
         else
          WR_state <= WR_state;
         end
    WR_state_c : begin
         if(!sclk_r)
          begin
          data <= reg_store[4];
          WR_state <= WR_state_d;
          end
         else
          WR_state <= WR_state;
         end
    WR_state_d : begin
         if(!sclk_r)
          begin
          data <= reg_store[5];
          WR_state <= WR_state_e;
          end
         else
          WR_state <= WR_state;
         end
    WR_state_e : begin
         if(!sclk_r)
          begin
          data <= reg_store[6];
          WR_state <= WR_state_f;
          end
         else
          WR_state <= WR_state;
         end
    WR_state_f : begin
         if(!sclk_r)
          begin
          data <= reg_store[7];
          WR_state <= WR_state_10;
          end
         else
          WR_state <= WR_state;
         end
    WR_state_10 : begin
         if(!sclk_r)
          begin
          WR_state <= WR_state_0;
          WR_flag <= 1'b1;
          srst_r <= 1'b0;
          end
         else
          WR_state <= WR_state; 
         end
    default  : WR_state <= WR_state_0;
  endcase
  end 
 endtask 

 assign TimeData = TimeData_r;
 assign DateData = DateData_r;
 assign srst = srst_r;

endmodule


五、实验效果:1、解决了上电时间复位的问题;2、加上了LED校时指示,至于其他bug肯定是有的,但还待发现。

下面是今天晚上照的实际效果,视频今晚刚刚给老王发过去,他们明天不上班,所以得等等了。





更新过后的sof,pof(我用的时钟输入引脚是129,大伙注意一下)
文件下载:
http://share.eepw.com.cn/share/download/id/83600


共223条 17/23 |‹ 15 16 17 18 19 20 ›| 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]