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