• 【黑金原创教程】【FPGA那些事儿-驱动篇I 】实验二十三:DS1302模块


    实验二十三: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也有数据字节。

    clip_image002

    图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则返回步骤。

    clip_image004

    图23.2 写操作的理想时序(从机视角)。

    图23.2则是从机视角的写操作时序,从机任何时候都是利用上升沿读取数据。

    clip_image006

    图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次便搞定。

    clip_image008

    图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。

    clip_image010

    图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

       

    clip_image012

    图23.6 时序参数②。

    如表23.4是TCC还有TDC的时序参数,虽然两者都有 Setup 字眼,实际上它们都是推挤作用的时序参数。如图23.6的右图所示,那是物理时序图,TCC向右推挤SCLK信号,TDC向右推挤TDC信号。换做左图的理想时序图,TCC使SCLK被覆盖,TDC使DATA被覆盖。有些同学可能会被TCC的要求吓到,既然是1us。原理上,它是时钟周期的两倍,不过那是推挤作用的时序参数,只要操作结束之前一直拉高CS即可无视。

    clip_image013表23.4 DS1302的时序参数③。

       

    最小

    最大

    时序参数

    标示

    时间

    时钟(50Mhz)

    时间

    时钟(50Mhz)

    CLOCK to Data Delay

    TCDD

    200ns

    10

       

    Clock to Data Hold

    TCDH

    70ns

    3.5

       

    clip_image015

    图23.7 时序参数③。

    表23.4显示TCDD还有TCDH两只时序参数,如23.7的右图所示,那是物理时序。我们知道DS1302是下降沿设置(输出)数据,上升沿锁存数据,期间TCDD将数据向右推挤,TCDH则就是典型的 THold,即锁存数据以后的确保时间。如23.7的左图所示,那是理想时序,由于这两只都是小家伙,一般都无法完全覆盖数据。

    clip_image013[1]表23.5 DS1302的时序参数④

       

    最小

    最大

    时序参数

    标示

    时间

    时钟(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并不会立即输出高阻态,则是必须经历一段时间。至于高阻态的大小姨妈,一般都是硬件内部(从机)的纠纷,鲜少与驱动方(主机)扯上关系,所以我们在此聊聊就好。

    clip_image017

    图23.8 写操作的物理时序(时序参数)。

    clip_image019

    图23.9 读操作的物理时序(时序参数)。

    最后附上两张官方的原图23.8还有图23.9作为本说明的谢幕,读者就自己慢慢看着办吧。理解完毕,我们便可以开始建模了。

    clip_image021

    图23.10 DS1302基础模块的建模图。

    图23.10是DS1302基础模块的建模图,内容包含控制模块与功能模块,功能模块负责最基础的读写操作,控制模块则负责功能调度,准备访问字节等任务。换之,功能模块的右边是驱动硬件资源的顶层信号。其中,功能模块的oData穿过控制模块直接驱动外围。

    ds1302_funcmod.v

    clip_image023

    图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

    clip_image025

    图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

    clip_image027

    图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。对此,读者请自己探索然后尝试扩展该基础模块吧。

  • 相关阅读:
    C++ 重载运算符
    线段树
    矩阵的构造
    矩阵快速幂
    Fibnoccia 数列简单题
    权值线段树
    .net System.Net.Mail 之用SmtpClient发送邮件Demo
    poj-3087 Shuffle'm Up
    hdu-1548 A strange lift
    scu-4440 rectangle (非原创)
  • 原文地址:https://www.cnblogs.com/alinx/p/4470001.html
Copyright © 2020-2023  润新知