这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » zhengchao20105进程贴:ds1302时钟

共2条 1/1 1 跳转至

zhengchao20105进程贴:ds1302时钟

菜鸟
2013-03-31 11:44:46     打赏

ds1302前前后后调试了两个星期才总算完成,实属不易。中间有很多bug都是用modelsim来解决的,尤其是相关的flag位及时清零。不得不说这真的是一个非常好用的调试工具,以ds1302为例,写testbench时,由于inout不好写,可以直接定义为output,这样把写数据的程序调通了,读数据自然也就好使了(两者差一个时钟周期)

Quartus的warning也要注意,比如变量被直接引用而没有被定义就会就出warning,但不会报错.

ds1302的时序很重要,刚开始调试完发现读出的数据总是少一位,后来严格按照时序,读完后及时将i/o脚置为高阻,问题得以解决。

下面的程序没有按键调节,以后可以增加。

最后显示效果

module ds1302_0317(
sys_clk,
rtc_clk,
rtc_rst,
rtc_data,
sel,
seg);
output [7:0] sel;
output [7:0] seg;
input sys_clk;
output rtc_clk;
reg rtc_clk;
output rtc_rst;
wire rtc_rst;
inout rtc_data;
reg rtc_data;
reg [31:0] cln_nouse;
reg [9:0] sub_clk;
reg [30:0] cln_sys_clk;//系统时钟count
reg [30:0] wcln_rtc_com;//rtc的时钟count,写命令时
reg [30:0] wcln_rtc_data;//rtc的时钟count,写数据时
reg [30:0] rcln_rtc_data;//rtc的时钟count,读数据时
reg rdata_flag;//读数据flag
reg wcom_flag;//写命令flag
reg wdata_flag;//写数据flag
reg wclk_flag;
reg rclk_flag;
parameter state_0     = 0;
parameter state_1     = 1;
parameter state_2     = 2;
parameter state_3     = 3;
parameter state_4     = 4;
parameter state_5     = 5;
parameter state_6     = 6;
parameter state_7     = 7;
parameter state_8     = 8;
parameter state_9     = 9;
parameter state_10     = 10;
parameter state_11     = 11;
parameter state_12     = 12;
parameter state_13     = 13;
parameter state_14     = 14;
parameter state_15     = 15;
assign rtc_rst=(cln_sys_clk>=31'd200)&&(cln_sys_clk<31'd2000)?1'b1:1'b0;//定义rct_rst的总共存在周期
always@(posedge sys_clk)
begin
    if(cln_sys_clk>31'd2250)
        cln_sys_clk<=0;
    else
        cln_sys_clk<=cln_sys_clk+1'b1;
end

//rtc_clk=500k=0.5Mhz
always@(posedge sys_clk)
    begin
    if((cln_sys_clk>=0)&&(cln_sys_clk<31'd250))
        begin
        rtc_clk<=0;
        sub_clk<=0;
        end
    else if((cln_sys_clk>=31'd250)&&(cln_sys_clk<31'd1800))
        begin
        if(sub_clk>=10'd49)
            begin
            sub_clk<=0;
            rtc_clk<=~rtc_clk;
            end
        else
            begin
            sub_clk<=sub_clk+1'b1;
            end
        end
    else if((cln_sys_clk>=31'd1800)&&(cln_sys_clk<31'd1850)&&(wclk_flag==1))//写数据时,多一个时钟
            begin
            rtc_clk<=1'b1;
            end
    else if((cln_sys_clk>=31'd1800)&&(cln_sys_clk<31'd1850)&&(rclk_flag==1))//读数据时,少一个时钟
            begin
            rtc_clk<=0;
            end
    else if((cln_sys_clk>=31'd1850)&&(cln_sys_clk<31'd2250))
        begin
        rtc_clk<=0;
        end
end

//以下为写命令

reg [7:0] wcom_state;
task write_com;
input [7:0] wcom;//命令形式
begin
    case(wcom_state)
    state_0:
            begin
            rtc_data<=0;//定义data的初始值为0
            wcom_flag<=0;
            rdata_flag<=0;
            wcom_state<=state_1;
            end
    state_1:
            begin
        //    rtc_rst<=1'b1;
            if((cln_sys_clk>=31'd0)&&(cln_sys_clk<31'd230))
              begin
              wcom_state<=state_1;
              end
            else
              begin
              wcom_state<=state_2;
              end
            end
    state_2:
            begin
            if((cln_sys_clk>=31'd230)&&(cln_sys_clk<31'd1030))
                begin
                if((cln_sys_clk>=31'd230)&&(cln_sys_clk<31'd330))//写八个命令
                    begin rtc_data<=wcom[0];wcom_state<=state_2;end
                else if((cln_sys_clk>=31'd330)&&(cln_sys_clk<31'd430))
                    begin rtc_data<=wcom[1];wcom_state<=state_2;end
                else if((cln_sys_clk>=31'd430)&&(cln_sys_clk<31'd530))
                    begin rtc_data<=wcom[2];wcom_state<=state_2;end
                else if((cln_sys_clk>=31'd530)&&(cln_sys_clk<31'd630))
                    begin rtc_data<=wcom[3];wcom_state<=state_2;end
                else if((cln_sys_clk>=31'd630)&&(cln_sys_clk<31'd730))
                    begin rtc_data<=wcom[4];wcom_state<=state_2;end
                else if((cln_sys_clk>=31'd730)&&(cln_sys_clk<31'd830))
                    begin rtc_data<=wcom[5];wcom_state<=state_2;end
                else if((cln_sys_clk>=31'd830)&&(cln_sys_clk<31'd930))
                    begin rtc_data<=wcom[6];wcom_state<=state_2;end
                else if((cln_sys_clk>=31'd930)&&(cln_sys_clk<31'd1030))
                    begin rtc_data<=wcom[7];wcom_state<=state_2;end
                end
            else
                begin
                wcom_state<=state_3;
                end
            end
    state_3:
            begin
            //rtc_rst<=1;
            wcom_flag<=1'b1;//写命令结束
            wdata_flag<=0;
            rdata_flag<=0;
            wcom_state<=state_0;
            end
        endcase
        end
endtask

//以下为写数据

reg [7:0] wdata_state;
task write_data;
input [7:0] wdata;//数据形式
begin
    case(wdata_state)
    state_0:
            begin
            wdata_flag<=0;
            rtc_data<=0;//定义data为输出
            wdata_state<=state_1;
            wclk_flag<=1'b1;
            rclk_flag<=0;
            end
    state_1:
            begin
            if((cln_sys_clk>=31'd1030)&&(cln_sys_clk<31'd1830))//1052~1852
                begin
                 if((cln_sys_clk>=31'd1030)&&(cln_sys_clk<31'd1130))//写八个数据
                    begin rtc_data<=wdata[0];wdata_state<=state_1;end
                else if((cln_sys_clk>=31'd1130)&&(cln_sys_clk<31'd1230))
                    begin rtc_data<=wdata[1];wdata_state<=state_1;end
                else if((cln_sys_clk>=31'd1230)&&(cln_sys_clk<31'd1330))
                    begin rtc_data<=wdata[2];wdata_state<=state_1;end
                else if((cln_sys_clk>=31'd1330)&&(cln_sys_clk<31'd1430))
                    begin rtc_data<=wdata[3];wdata_state<=state_1;end
                else if((cln_sys_clk>=31'd1430)&&(cln_sys_clk<31'd1530))
                    begin rtc_data<=wdata[4];wdata_state<=state_1;end
                else if((cln_sys_clk>=31'd1530)&&(cln_sys_clk<31'd1630))
                    begin rtc_data<=wdata[5];wdata_state<=state_1;end
                else if((cln_sys_clk>=31'd1630)&&(cln_sys_clk<31'd1730))
                    begin rtc_data<=wdata[6];wdata_state<=state_1;end
                else if((cln_sys_clk>=31'd1730)&&(cln_sys_clk<31'd1830))
                    begin rtc_data<=wdata[7];wdata_state<=state_1;end
                end
            else
                    begin
                    wdata_state<=state_2;
                    end
                end
    state_2:
                begin
                    if((cln_sys_clk>=31'd1830)&&(cln_sys_clk<31'd2250))//经历
                        begin
                        wdata_state<=state_2;
                        end
                    else
                        begin
                        wdata_flag<=1'b1;
                        wcom_flag<=0;//
                        rdata_flag<=0;
                        r_flag<=0;//
                        wclk_flag<=0;
                        rclk_flag<=0;
                        wdata_state<=state_0;
                        end
                end
            endcase
end
endtask

//以下为读数据

reg [7:0] rdata_state;
reg [7:0] rdata_buffer;//命令形式
task read_data;
begin
    case(rdata_state)
    state_0:
            begin
            rtc_data<=1'bz;//定义为输入
            rdata_flag<=0;
            wclk_flag<=0;
            rclk_flag<=1'b1;
            wcom_flag<=0;
            rdata_state<=state_1;
            end
    state_1:
            begin
            if((cln_sys_clk>=31'd1030)&&(cln_sys_clk<31'd1851))
            begin
                if((cln_sys_clk>=31'd1030)&&(cln_sys_clk<31'd1051))
                    begin rdata_state<=state_1;end
                else if((cln_sys_clk>=31'd1051)&&(cln_sys_clk<31'd1101))//读八个数据
                    begin rdata_buffer[0]<=rtc_data;rdata_state<=state_1;end
                else if((cln_sys_clk>=31'd1051)&&(cln_sys_clk<31'd1151))//读完后要设置成高阻
                    begin rtc_data<=1'bz;rdata_state<=state_1;end
                    
                else if((cln_sys_clk>=31'd1151)&&(cln_sys_clk<31'd1201))
                    begin rdata_buffer[1]<=rtc_data;wdata_state<=state_1;end
                else if((cln_sys_clk>=31'd1201)&&(cln_sys_clk<31'd1251))
                    begin rtc_data<=1'bz;rdata_state<=state_1;end
                    
                else if((cln_sys_clk>=31'd1251)&&(cln_sys_clk<31'd1301))
                    begin rdata_buffer[2]<=rtc_data;wdata_state<=state_1;end
                else if((cln_sys_clk>=31'd1301)&&(cln_sys_clk<31'd1351))
                    begin rtc_data<=1'bz;rdata_state<=state_1;end    
                    
                else if((cln_sys_clk>=31'd1351)&&(cln_sys_clk<31'd1401))
                    begin rdata_buffer[3]<=rtc_data;wdata_state<=state_1;end
                else if((cln_sys_clk>=31'd1401)&&(cln_sys_clk<31'd1451))
                    begin rtc_data<=1'bz;rdata_state<=state_1;end    
                    
                else if((cln_sys_clk>=31'd1451)&&(cln_sys_clk<31'd1501))
                    begin rdata_buffer[4]<=rtc_data;wdata_state<=state_1;end
                else if((cln_sys_clk>=31'd1501)&&(cln_sys_clk<31'd1551))
                    begin rtc_data<=1'bz;rdata_state<=state_1;end
                    
                else if((cln_sys_clk>=31'd1551)&&(cln_sys_clk<31'd1601))
                    begin rdata_buffer[5]<=rtc_data;wdata_state<=state_1;end
                else if((cln_sys_clk>=31'd1601)&&(cln_sys_clk<31'd1651))
                    begin rtc_data<=1'bz;rdata_state<=state_1;end    
                    
                else if((cln_sys_clk>=31'd1651)&&(cln_sys_clk<31'd1701))
                    begin rdata_buffer[6]<=rtc_data;wdata_state<=state_1;end
                else if((cln_sys_clk>=31'd1701)&&(cln_sys_clk<31'd1751))
                    begin rtc_data<=1'bz;rdata_state<=state_1;end    
                    
                else if((cln_sys_clk>=31'd1751)&&(cln_sys_clk<31'd1801))
                    begin rdata_buffer[7]<=rtc_data;wdata_state<=state_1;end
                else if((cln_sys_clk>=31'd1801)&&(cln_sys_clk<31'd1851))
                    begin rtc_data<=1'bz;rdata_state<=state_1;end
                end
            else
                    begin
                    rdata_state<=state_2;
                    end
            end
    state_2:
            begin
                if((cln_sys_clk>=31'd1851)&&(cln_sys_clk<31'd2250))//
                    begin
                    rdata_state<=state_2;
                    end
                else
                    begin
                    rdata_flag=1'b1;
                    wcom_flag<=0;
                    rtc_data<=0;
                    wclk_flag<=0;
                    rclk_flag<=0;
                    rdata_state<=state_0;
                    end
            end
        endcase
end
endtask

reg w_flag;
reg [7:0] w_state;
task w_ds1302;
begin
    case(w_state)
    state_0:
            begin
            w_flag<=0;
            wcom_flag<=0;
            w_state<=state_1;
            end
    state_1:
            begin
            if(wcom_flag==0)
                begin
                write_com(8'h8e);//写保护进制clear
                w_state<=state_1;
                end
            else
                begin
                w_state<=state_2;
                end
            end
    state_2:
            begin
                if(wdata_flag==0)
                begin
                write_data(8'h00);//写保护进制clear
                w_state<=state_2;
                end
            else
                begin
                w_state<=state_3;
                end
            end
    state_3:
            begin
            if(wcom_flag==0)
            begin
            write_com(8'h80);//写秒指令
            w_state<=state_3;
            end
            else
                begin
                w_state<=state_4;
                end
            end
    state_4:
            begin
            if(wdata_flag==0)
                begin
                write_data(8'h43);//写入43秒
                w_state<=state_4;
                end
            else
                begin
                w_state<=state_5;
                end
            end
    state_5:
            begin
            if(wcom_flag==0)
            begin
            write_com(8'h82);//写分指令
            w_state<=state_5;
            end
            else
                begin
                w_state<=state_6;
                end
            end
    state_6:
            begin
            if(wdata_flag==0)
                begin
                write_data(8'h25);//写入25分
                w_state<=state_6;
                end
            else
                begin
                w_state<=state_7;
                end
            end
    state_7:
            begin
            if(wcom_flag==0)
            begin
            write_com(8'h84);//写时指令
            w_state<=state_7;
            end
            else
                begin
                w_state<=state_8;
                end
            end
    state_8:
            begin
            if(wdata_flag==0)
                begin
                write_data(8'h08);//写入8时
                w_state<=state_8;
                end
            else
                begin
                w_state<=state_9;
                end
            end        
    state_9:
            begin
            w_flag<=1;
            w_state<=state_0;
            end
        endcase
    end
endtask

//读数据
reg [7:0] temp_hour;
reg [2:0] temp_hour_shi;
reg [3:0] temp_hour_ge;
reg [7:0] temp_minute;
reg [2:0] temp_minute_shi;
reg [3:0] temp_minute_ge;
reg [7:0] temp_seconds;
reg [2:0] temp_seconds_shi;
reg [3:0] temp_seconds_ge;
reg r_flag;
reg [7:0] r_state;
task r_data;
begin
    case(r_state)
    state_0:
            begin
            w_flag<=0;
            r_flag<=0;
            rdata_flag<=0;
            r_state<=state_1;
            wcom_flag<=0;
            end
    state_1:
            begin
            if(wcom_flag==0)
                begin
                write_com(8'h81);//读秒指令
                r_state<=state_1;
                end
                else
                    begin
                    r_state<=state_2;
                    end
            end
    state_2:
            begin
            if(rdata_flag==0)
                begin
                read_data;
                r_state<=state_2;
                end
            else
                begin
                temp_seconds[7:0]<=rdata_buffer;
                r_state<=state_3;
                end
            end
    state_3:
            begin
            temp_seconds_shi[2:0]<=temp_seconds[6:4];
            temp_seconds_ge[3:0]<=temp_seconds[3:0];
            r_state<=state_4;
            end
    state_4:
            begin
            if(wcom_flag==0)
                begin
                write_com(8'h83);//读分指令
                r_state<=state_4;
                end
                else
                    begin
                    r_state<=state_5;
                    end
            end
    state_5:
            begin
            if(rdata_flag==0)
                begin
                read_data;
                r_state<=state_5;
                end
            else
                begin
                temp_minute[7:0]<=rdata_buffer;
                r_state<=state_6;
                end
            end
    state_6:
            begin
            temp_minute_shi[2:0]<=temp_minute[6:4];
            temp_minute_ge[3:0]<=temp_minute[3:0];
            r_state<=state_7;
            end
    state_7:
            begin
            if(wcom_flag==0)
                begin
                write_com(8'h85);//读时指令
                r_state<=state_7;
                end
            else
                begin
                r_state<=state_8;
                end
            end
    state_8:
            begin
            if(rdata_flag==0)
                begin
                read_data;
                r_state<=state_8;
                end
            else
                begin
                temp_hour[7:0]<=rdata_buffer;
                r_state<=state_9;
                end
            end
    state_9:
            begin
            temp_hour_shi[2:0]<=temp_hour[6:4];
            temp_hour_ge[3:0]<=temp_hour[3:0];
            r_state<=state_10;
            end
    state_10:
            begin
            r_flag<=1'b1;
            r_state<=state_0;
            end
        endcase
    end
endtask

    //数码管设定//
reg [7:0] sel=8'b11111111;//turn off
reg [7:0] seg=0;
reg [27:0] delay_ms=0;
reg [3:0] state_ms=0;
reg sel_0_flag=0;
reg sel_1_flag=0;
reg sel_2_flag=0;    
reg sel_3_flag=0;
reg sel_4_flag=0;
reg sel_5_flag=0;    
reg sel_6_flag=0;
reg sel_7_flag=0;
//------------display delay  ms//
always@(posedge sys_clk)
begin
if(delay_ms>28'd9999)
delay_ms<=0;
else delay_ms<=delay_ms+1'b1;
end

always@(posedge sys_clk)
if(delay_ms==28'd9999)
begin
if(state_ms>=4'b0111)
state_ms<=1'b0;
else state_ms<=state_ms+1'b1;
end

always@(posedge sys_clk)
begin
    begin
    case (state_ms)
    4'b0000:
            begin
            sel<=8'b01111111;//select 0 tube
            sel_0_flag<=1;
            end
    
    4'b0001:
            begin
            sel<=8'b10111111;//select 1 tube
            sel_1_flag<=1;
            end
    4'b0010:
            begin
            sel<=8'b11011111;//select 2 tube
            sel_2_flag<=1;
            end
    4'b0011:
            begin
            sel<=8'b11101111;//select 3 tube
            sel_3_flag<=1;
            end
    4'b0100:
            begin
            sel<=8'b11110111;//select 4 tube
            sel_4_flag<=1;
            end
    4'b0101:
            begin
            sel<=8'b11111011;//select 5 tube
            sel_5_flag<=1;
            end
    4'b0110:
            begin
            sel<=8'b11111101;//select 6 tube
            sel_6_flag<=1;
            end
    4'b0111:
            begin
            sel<=8'b11111110;//select 7 tube
            sel_7_flag<=1;
            end
    endcase
    end

    if(sel_0_flag==1)//第0个数码管被选择
    begin
    case(temp_hour_shi)
    3'b000:seg<=8'hc0;//display 0
    3'b001:seg<=8'hf9;//display 1
    3'b010:seg<=8'ha4;//display 2
    endcase
    sel_0_flag<=0;
    end

    else if(sel_1_flag==1)//第一个数码管被选择
    begin
    case(temp_hour_ge)
    4'b0000:seg<=8'hc0;//display 0
    4'b0001:seg<=8'hf9;//display 1
    4'b0010:seg<=8'ha4;//display 2
    4'b0011:seg<=8'hb0;//display 3
    4'b0100:seg<=8'h99;//display 4
    4'b0101:seg<=8'h92;//display 5
    4'b0110:seg<=8'h82;//display 6
    4'b0111:seg<=8'hF8;//display 7
    4'b1000:seg<=8'h80;//display 8
    4'b1001:seg<=8'h90;//display 9
    endcase
    sel_1_flag<=0;
    end
    
    else if(sel_2_flag==1)//第二个数码管被选择
    begin
    seg<=8'h7f;//display .
    sel_2_flag<=0;
    end
    
    else if(sel_3_flag==1)//第三个数码管被选择
    begin
    case(temp_minute_shi)
    3'b000:seg<=8'hc0;//display 0
    3'b001:seg<=8'hf9;//display 1
    3'b010:seg<=8'ha4;//display 2
    3'b011:seg<=8'hb0;//display 3
    3'b100:seg<=8'h99;//display 4
    3'b101:seg<=8'h92;//display 5
    endcase
    sel_3_flag<=0;
    end
    
    else if(sel_4_flag==1)//第四个数码管被选择
    begin
    case(temp_minute_ge)
    4'b0000:seg<=8'hc0;//display 0
    4'b0001:seg<=8'hf9;//display 1
    4'b0010:seg<=8'ha4;//display 2
    4'b0011:seg<=8'hb0;//display 3
    4'b0100:seg<=8'h99;//display 4
    4'b0101:seg<=8'h92;//display 5
    4'b0110:seg<=8'h82;//display 6
    4'b0111:seg<=8'hF8;//display 7
    4'b1000:seg<=8'h80;//display 8
    4'b1001:seg<=8'h90;//display 9
    endcase
    sel_4_flag<=0;
    end
    
    else if(sel_5_flag==1)//第五个数码管被选择
    begin
    seg<=8'h7f;//display .
    sel_5_flag<=0;
    end
    
    else if(sel_6_flag==1)//第六个数码管被选择
    begin
    case(temp_seconds_shi)
    3'b000:seg<=8'hc0;//display 0
    3'b001:seg<=8'hf9;//display 1
    3'b010:seg<=8'ha4;//display 2
    3'b011:seg<=8'hb0;//display 3
    3'b100:seg<=8'h99;//display 4
    3'b101:seg<=8'h92;//display 5
    endcase
    sel_6_flag<=0;
    end
    
    else if(sel_7_flag==1)//第七个数码管被选择
    begin
    case(temp_seconds_ge)
    4'b0000:seg<=8'hc0;//display 0
    4'b0001:seg<=8'hf9;//display 1
    4'b0010:seg<=8'ha4;//display 2
    4'b0011:seg<=8'hb0;//display 3
    4'b0100:seg<=8'h99;//display 4
    4'b0101:seg<=8'h92;//display 5
    4'b0110:seg<=8'h82;//display 6
    4'b0111:seg<=8'hF8;//display 7
    4'b1000:seg<=8'h80;//display 8
    4'b1001:seg<=8'h90;//display 9
    endcase
    sel_7_flag<=0;
    end
end

//主程序
reg [7:0] process_state;
reg finish_flag;
always@(posedge sys_clk)
begin
        case(process_state)
        state_0:
            begin
            finish_flag<=0;
            if(w_flag==0)
                begin
                w_ds1302;
                process_state<=state_0;
                end
            else
                begin
                process_state<=state_1;
                end
            end
        state_1:
            begin
            if(r_flag==0)
                begin
                r_data;
                process_state<=state_1;
                end
            else
                begin
                process_state<=state_2;
                end
            end
        state_2:
                begin
                finish_flag<=1'b1;
                r_flag<=0;
                process_state<=state_1;
                end
            endcase
        end
endmodule




关键词: ds1302    

高工
2013-03-31 12:59:29     打赏
2楼
不错,加油!

共2条 1/1 1 跳转至

回复

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