以下是DS1302的封装和管脚说明。


其中,主要就是控制CE,I/O,SCLK这三个信号。。其他都是电路固定接好的。不需要控制。这里要注意一下I/O这个管脚是双向口。所以在FPGA中要用inout端口表示。
然后就是时序。

以上就是读和写的时序。
无论是写还是读,都是在CE为高的时候操作,当CE为低的时候,读和写都不可操作。所以在读和写之前,首先要将CE拉高,并保持到操作结束。
另外要注意,在CE拉高之前,SCLK都是要保持低电平的。
写操作:
拉高CE,保持一段时间,然后SCLK开始产生固定周期的15个脉冲信号。在SCLK的上升沿,将I/O数据写入到DS1302中。前面8位是控制字,后面8位是数据。写是以LSB先行,即先发地位,再发高位。写完数据后,保持一段时间,在将CE拉低。结束一次写数据。这里要注意,要继续写的话,是要等CE拉低一段时间之后,才能继续写的。这个是时序规定的。
读操作:
拉高CE,保持一段时间,然后SCLK开始产生固定周期的16个脉冲信号。前8个脉冲式写数据,在SCLK的上升沿将数据写入到DS1302中。后8个脉冲式读数据,在SCLK的下降沿,I/O上产生读取的数据。所以在这个时候,要将数据进行读取。这里要注意,读的第一个数据,是在第8个时钟脉冲的下降沿的时候产生的.
总体来说,时序是比较简单的。只要注意到datasheet中规定的时序。

比如规定,SCLK的高电平和低电平的时间最小是250ns(5V供电下),那么设计的时候,就要保证SCLK的高电平和低电平的持续时间至少是250ns。不过一般要留一些余量。比如可以设置时间为1us。毕竟对于实时时钟,不需要这么快的操作速度。
然后是控制字的说明:

前面的8位就是控制寄存器,后面是表示这个寄存器的每一位表示的意思。主要用到的前8个。
这里有特殊的位:
秒寄存器的BIT7 定义为时间暂停位,当BIT7 为1 时,时钟振荡器停止工作,DS1302 进入低功耗模式,电源消耗小于100 微安,当BIT7 为0 时,时钟振荡器启动,DS1302 正常工作。所以如果要使DS1302正常工作,需要将最高位写0。
小时寄存器的BIT7 定义为12 或24 小时工作模式选择位,当BIT7 为高时,为12 小时工作模式,此时BIT5 为AM/PM 位,低电平标示AM,高电平标示PM,在24 小时模式下,BIT5 为第二个10 小时位标示(20~23 时)。
写保护寄存器的BIT7:WP 是写保护位,工作时,出WP 外的其他位都置为0,对时钟日历寄存器或RAM 进行写操作之前,WP 必须为0,当WP 为高电平的时候,不能对任何时钟/日历寄存器或RAM 进行写操作。
然后就开始设计程序了。
首先是信号列表:
+ 查看代码
module ds1302_module(
input clk,
input rst_n,
input enable, //enable operate DS1302
input [7:0] command, //send first byte command
input [7:0] write_data, //send second byte data
//ds1302 interface
output reg ds1302_ce, //ds1302 CE port
output reg ds1302_sclk, //ds1302 SCLK port
inout ds1302_data, //ds1302 I/O port
output reg[7:0] ds1302_read_data, //read byte data from ds1302
output reg finish, //operate DS1302 finish
output ds1302_data_look //input data when I/O is input
);
注释也比较清楚,至于最后一个信号,是用来chipscope调试用的。因为chipscope不能直接看inout信号,需要将inout信号分解成输入和输出。
然后就是状态机的设计:
+ 查看代码
//define state localparam idle_state = 'd0; localparam ready_state = 'd1; localparam write_command_state = 'd2; localparam write_data_state = 'd3; localparam read_data_state = 'd4; localparam finish_state = 'd5; //end define state
这里只有5个状态,从状态的命名也可以看出该状态是干嘛的。
然后是inout端口ds1302_data的处理
+ 查看代码
reg read_enable; reg ds1302_data_reg; assign ds1302_data = read_enable ? 1'bz:ds1302_data_reg; assign ds1302_data_look = read_enable ? ds1302_data:1'b0;
和IIC的处理一样。需要一个读使能信号。
然后就是定义一些变量,用来计数每个状态的持续时间,发送的哪一位,保存读取时候每一次移位的值和I/O输出的值。
+ 查看代码
//counter 100 to delay 2000ns
reg [7:0] delay_time;
reg [7:0] delay_time_next;
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
delay_time <= 'd0;
else
delay_time <= delay_time_next;
end
//record transfer which bit, serial transfer,so need a variable value
reg [2:0] bit_counter; //current transfer bit
reg [2:0] bit_counter_next; //next transfer bit
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
bit_counter <= 'd0;
else
bit_counter <= bit_counter_next;
end
//save the every shift data to read_data
reg [7:0] read_data;
reg [7:0] read_data_reg;
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
read_data <= 8'd0;
else
read_data <= read_data_reg;
end
//save the ds1302 I/O output value
reg ds1302_data_reg_reg;
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
ds1302_data_reg_reg <= 'd0;
else
ds1302_data_reg_reg <= ds1302_data_reg;
end
然后就是状态机的设计:
+ 查看代码
reg [2:0] state;
reg [2:0] state_next;
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
state <= idle_state;
else
state <= state_next;
end
always@(*) begin
state_next = state;
ds1302_ce = 1'b1;
delay_time_next = delay_time;
finish = 1'b0;
read_data_reg = read_data;
bit_counter_next = bit_counter;
ds1302_data_reg = ds1302_data_reg_reg;
read_enable = 0; //default ds1302_data is output
read_finish = 'b0;
case(state)
idle_state: begin
delay_time_next = 'd0;
ds1302_ce = 'b0;
bit_counter_next = 'd0;
read_data_reg = 'd0;
if(enable)
state_next = ready_state;
end
ready_state: begin
if(delay_time >= 99) //delay 2us
begin
state_next = write_command_state;
delay_time_next = 'd0;
end
else
begin
delay_time_next = delay_time + 1'b1;
end
end
//write byte command data
write_command_state: begin
if(delay_time == 50) //delay 1us ,let ds1302_data data meet setup and hold time
ds1302_data_reg = command[bit_counter];
if(delay_time >= 199) //delay 4us , 1-bits data transfer finish
begin
if(bit_counter_next >= 7) //send_8-bits data finish
begin
bit_counter_next = 'd0;
if(command[0] == 0)
state_next = write_data_state;
else
state_next = read_data_state;
delay_time_next = 'd0;
end
else
begin
bit_counter_next = bit_counter + 1'b1;
delay_time_next = 'd0;
end
end
else
delay_time_next = delay_time + 1'b1;
end
//write 8-bits data to ds1302
write_data_state: begin
if(delay_time == 50) //delay 1us ,let ds1302 data meet setup and hold time
ds1302_data_reg = write_data[bit_counter];
if(delay_time >= 199) //delay 4us , 1-bits data transfer finish
begin
if(bit_counter_next >= 7) //send_8-bits data finish
begin
bit_counter_next = 'd0;
state_next = finish_state;
delay_time_next = 'd0;
end
else
begin
bit_counter_next = bit_counter + 1'b1;
delay_time_next = 'd0;
end
end
else
delay_time_next = delay_time + 1'b1;
end
//read 8-bits data from ds1302
read_data_state: begin
read_enable = 1'b1; // set ds1302_data is input
if(delay_time == 50) //delay 1us ,let data meet setup and hold time
read_data_reg = {ds1302_data,read_data[7:1]};
if(delay_time >= 199) //delay 4us
begin
if(bit_counter_next >= 7) //read_8-bits data
begin
bit_counter_next = 'd0;
delay_time_next = 'd0;
//counter_number_next = counter_number + 1'b1;
state_next = finish_state;
end
else
begin
bit_counter_next = bit_counter + 1'b1;
delay_time_next = 'd0;
end
end
else
delay_time_next = delay_time + 1'b1;
end
finish_state: begin
ds1302_ce = 'b0;
if(delay_time == 150)
read_finish = 1'b1;
if(delay_time >= 199) //delay 2us
begin
state_next = idle_state;
finish = 1'b1;
end
else
delay_time_next = delay_time + 1'b1;
end
default: state_next = idle_state;
endcase
end
代码也比较简单。只需要主要在什么时候要将read_enable信号使能,是I/O为输入。
最后是SCLK的控制:
对于SCLK,只有在写命令,写数据和读数据的时候,才会产生脉冲,在其余时候,都是为低电平。所以这里只要判断状态即可。在写命令,写数据和读数据状态,在状态的前半段时候,SCLK为电平,后半段时候为高电平,这样就产生了脉冲。这里看网上有说,最后完成的时候,在CE拉低的时候,SCLK要保持高电平,否则不会正常工作。但是我试过,CE拉低,SCLK为低电平的时候也是可以正常工作的。可能不同厂家芯片有点不一样。
+ 查看代码
always@(*) begin
if(state == idle_state || state == ready_state)
ds1302_sclk = 1'b0;
else if(state == finish_state)
ds1302_sclk = 1'b1;
else
if(delay_time < 100)
ds1302_sclk = 1'b0;
else
ds1302_sclk = 1'b1;
end
最后就是读取数据的处理。
+ 查看代码
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
ds1302_read_data <= 'd0;
else
if(read_finish)
ds1302_read_data <= read_data;
end
因为read_data在读数据的时候,是一直在变的,而且在下一次读数据的时候,是会被清零的,所以就需要在读完时候保持该值。在读完数据后,read_finish会保持一个时钟的高电平,这样就可以将数据保存到ds1302_read_data,知道下一个数据读取结束。
最后就是编写顶层代码,去控制DS1302。
+ 查看代码
module ds1302_control(
input clk,
input rst_n,
//ds1302 interface
output ds1302_ce,
output ds1302_sclk,
inout ds1302_data,
output [7:0] sm_bit , //位选
output [7:0] sm_seg, //段选
output ds1302_data_look
);
localparam idle_state ='d0;
localparam cancel_write_protect_state ='d1;
localparam enable_ds1302_clock_state ='d2;
localparam read_second_state ='d3;
localparam read_minute_state ='d4;
localparam read_hour_state ='d5;
localparam finish_state ='d6;
//ds1302 interface
wire finish;
reg enable_ds1302;
wire [7:0] ds1302_read_data;
//ds1302 interface
wire enable = 1'b1;
reg[3:0] hour_units;
reg[1:0] hour_tens;
reg[3:0] minute_units;
reg[2:0] minute_tens;
reg[3:0] second_units;
reg[2:0] second_tens;
(* KEEP = "TRUE" *) reg [7:0] command;
(* KEEP = "TRUE" *) reg [7:0] write_data;
reg [2:0] state;
reg [2:0] state_next;
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
begin
state <= idle_state;
command <= 8'h8e;
write_data <= 8'd0;
hour_units <= 'd0;
hour_tens <= 'd0;
minute_units <= 'd0;
minute_tens <= 'd0;
second_units <= 'd0;
second_tens <= 'd0;
end
else
begin
case(state)
idle_state: begin
if(enable)
begin
state <= cancel_write_protect_state;
end
end
cancel_write_protect_state: begin
enable_ds1302 <= 1'b1;
command <= 8'h8e;
write_data <= 8'd0;
if(finish == 1)
begin
enable_ds1302 <= 1'b0;
state <= enable_ds1302_clock_state;
end
end
enable_ds1302_clock_state: begin
enable_ds1302 <= 1'b1;
command <= 8'h80;
write_data <= 8'h17;
if(finish == 1)
begin
enable_ds1302 <= 1'b0;
state <= read_second_state;
end
end
read_second_state: begin
enable_ds1302 <= 1'b1;
command <= 8'h81; //read second register
if(finish == 1)
begin
enable_ds1302 <= 1'b0;
second_units <= ds1302_read_data[3:0];
second_tens <= ds1302_read_data[6:4];
state <= read_minute_state;
end
end
read_minute_state: begin
enable_ds1302 <= 1'b1;
command <= 8'h83; //read minute register
if(finish == 1)
begin
enable_ds1302 <= 1'b0;
minute_units <= ds1302_read_data[3:0];
minute_tens <= ds1302_read_data[6:4];
state <= read_hour_state;
end
end
read_hour_state: begin
enable_ds1302 <= 1'b1;
command <= 8'h85; //read hour register
if(finish == 1)
begin
enable_ds1302 <= 1'b0;
hour_units <= ds1302_read_data[3:0];
hour_tens <= ds1302_read_data[5:4];
state <= finish_state;
end
end
finish_state: begin
state <= read_second_state;
end
default: state <= idle_state;
endcase
end
end
ds1302_module ds1302_module_1 (
.clk(clk),
.rst_n(rst_n),
.enable(enable_ds1302),
.command(command[7:0]),
.write_data(write_data[7:0]),
.ds1302_ce(ds1302_ce),
.ds1302_sclk(ds1302_sclk),
.ds1302_data(ds1302_data),
.ds1302_read_data(ds1302_read_data[7:0]),
.finish(finish),
.ds1302_data_look(ds1302_data_look)
);
digitron_dynamic_display digitron_dynamic_display_1 (
.clk(clk),
.rst_n(rst_n),
.display_data_1(second_units),
.display_data_2({1'b0,second_tens}),
.display_data_3(4'ha),
.display_data_4(minute_units),
.display_data_5({1'b0,minute_tens}),
.display_data_6(4'ha),
.display_data_7(hour_units),
.display_data_8({2'b0,hour_tens}),
.sm_bit(sm_bit),
.sm_seg(sm_seg)
);
endmodule
代码页比较简单,就是几个状态的跳转,首先是取消写保护,然后是使能振荡器,并初始化秒寄存器的值,这样芯片才能正常的计数。然后在读秒寄存器的值,读分寄存器的值,读时寄存器的值。读完之后,跳转到读秒寄存器状态。开始读秒寄存器值,然后在读。。。。。
在将读取的值通过数码管显示出来。
这里要注意,读完时状态后,是不能跳到idle_state状态的,因为这样会重新写秒寄存器的值,这样就不会计数了。
以下是chipscope抓取的波形:

可以看到是正常读取数据的,只不过操作比较快,所以看不到读取数据的变化。
以下附上整个DS1302代码:
+ 查看代码
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 15:08:24 11/24/2014
// Design Name:
// Module Name: ds1302_module
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module ds1302_module(
input clk,
input rst_n,
input enable, //enable operate DS1302
input [7:0] command, //send first byte command
input [7:0] write_data, //send second byte data
//ds1302 interface
output reg ds1302_ce, //ds1302 CE port
output reg ds1302_sclk, //ds1302 SCLK port
inout ds1302_data, //ds1302 I/O port
output reg[7:0] ds1302_read_data, //read byte data from ds1302
output reg finish, //operate DS1302 finish
output ds1302_data_look //input data when I/O is input
);
//define state
localparam idle_state = 'd0;
localparam ready_state = 'd1;
localparam write_command_state = 'd2;
localparam write_data_state = 'd3;
localparam read_data_state = 'd4;
localparam finish_state = 'd5;
//end define state
reg read_finish;
reg read_enable;
reg ds1302_data_reg;
assign ds1302_data = read_enable ? 1'bz:ds1302_data_reg;
assign ds1302_data_look = read_enable ? ds1302_data:1'b0;
//counter 100 to delay 2000ns
reg [7:0] delay_time;
reg [7:0] delay_time_next;
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
delay_time <= 'd0;
else
delay_time <= delay_time_next;
end
//record transfer which bit, serial transfer,so need a variable value
reg [2:0] bit_counter; //current transfer bit
reg [2:0] bit_counter_next; //next transfer bit
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
bit_counter <= 'd0;
else
bit_counter <= bit_counter_next;
end
//save the every shift data to read_data
reg [7:0] read_data;
reg [7:0] read_data_reg;
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
read_data <= 8'd0;
else
read_data <= read_data_reg;
end
//save the ds1302 I/O output value
reg ds1302_data_reg_reg;
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
ds1302_data_reg_reg <= 'd0;
else
ds1302_data_reg_reg <= ds1302_data_reg;
end
reg [2:0] state;
reg [2:0] state_next;
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
state <= idle_state;
else
state <= state_next;
end
always@(*) begin
state_next = state;
ds1302_ce = 1'b1;
delay_time_next = delay_time;
finish = 1'b0;
read_data_reg = read_data;
bit_counter_next = bit_counter;
ds1302_data_reg = ds1302_data_reg_reg;
read_enable = 0; //default ds1302_data is output
read_finish = 'b0;
case(state)
idle_state: begin
delay_time_next = 'd0;
ds1302_ce = 'b0;
bit_counter_next = 'd0;
read_data_reg = 'd0;
if(enable)
state_next = ready_state;
end
ready_state: begin
if(delay_time >= 99) //delay 2us
begin
state_next = write_command_state;
delay_time_next = 'd0;
end
else
begin
delay_time_next = delay_time + 1'b1;
end
end
//write byte command data
write_command_state: begin
if(delay_time == 50) //delay 1us ,let ds1302_data data meet setup and hold time
ds1302_data_reg = command[bit_counter];
if(delay_time >= 199) //delay 4us , 1-bits data transfer finish
begin
if(bit_counter_next >= 7) //send_8-bits data finish
begin
bit_counter_next = 'd0;
if(command[0] == 0)
state_next = write_data_state;
else
state_next = read_data_state;
delay_time_next = 'd0;
end
else
begin
bit_counter_next = bit_counter + 1'b1;
delay_time_next = 'd0;
end
end
else
delay_time_next = delay_time + 1'b1;
end
//write 8-bits data to ds1302
write_data_state: begin
if(delay_time == 50) //delay 1us ,let ds1302 data meet setup and hold time
ds1302_data_reg = write_data[bit_counter];
if(delay_time >= 199) //delay 4us , 1-bits data transfer finish
begin
if(bit_counter_next >= 7) //send_8-bits data finish
begin
bit_counter_next = 'd0;
state_next = finish_state;
delay_time_next = 'd0;
end
else
begin
bit_counter_next = bit_counter + 1'b1;
delay_time_next = 'd0;
end
end
else
delay_time_next = delay_time + 1'b1;
end
//read 8-bits data from ds1302
read_data_state: begin
read_enable = 1'b1; // set ds1302_data is input
if(delay_time == 50) //delay 1us ,let data meet setup and hold time
read_data_reg = {ds1302_data,read_data[7:1]};
if(delay_time >= 199) //delay 4us
begin
if(bit_counter_next >= 7) //read_8-bits data
begin
bit_counter_next = 'd0;
delay_time_next = 'd0;
//counter_number_next = counter_number + 1'b1;
state_next = finish_state;
end
else
begin
bit_counter_next = bit_counter + 1'b1;
delay_time_next = 'd0;
end
end
else
delay_time_next = delay_time + 1'b1;
end
finish_state: begin
ds1302_ce = 'b0;
if(delay_time == 150)
read_finish = 1'b1;
if(delay_time >= 199) //delay 2us
begin
state_next = idle_state;
finish = 1'b1;
end
else
delay_time_next = delay_time + 1'b1;
end
default: state_next = idle_state;
endcase
end
always@(*) begin
if(state == idle_state || state == ready_state)
ds1302_sclk = 1'b0;
else if(state == finish_state)
ds1302_sclk = 1'b1;
else
if(delay_time < 100)
ds1302_sclk = 1'b0;
else
ds1302_sclk = 1'b1;
end
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
ds1302_read_data <= 'd0;
else
if(read_finish)
ds1302_read_data <= read_data;
end
endmodule
畅学电子







