module ds1302(
sys_clk,
sys_rstn,
ds1302_scl,
ds1302_data,
ds1302_ce,
hour,
minute,
second
);
input sys_clk;
input sys_rstn;
output ds1302_scl;
inout ds1302_data;
output ds1302_ce;
output [7:0]hour;
output [7:0]minute;
output [7:0]second;
/*
//产生时钟 200x20ns = 4us
reg [7:0]count;
always @(posedge sys_clk or negedge sys_rstn)
begin
if(!sys_rstn)
count <= 8'b0;
else if(count == 199)
count <= 8'b0;
else count <= count + 1'b1;
end
reg ds1302_scl_r;
always @(posedge sys_clk or negedge sys_rstn)
begin
if(!sys_rstn)
ds1302_scl_r <= 1'b0;
else if(count == 0)
ds1302_scl_r <= 1'b0;
else if(count == 99)
ds1302_scl_r <= 1'b1;
end
assign ds1302_scl = ds1302_scl_r;
`define POS_POINT (count == 99)
`define NEG_POINT (count == 199)
`define HIGH_POINT (count == 149)
`define LOW_POINT (count == 49)
*/
//200循环计数,产生iic所需要的时钟,250khz
reg [7:0]cnt_delay;
always @(posedge sys_clk or negedge sys_rstn)
begin
if(!sys_rstn)
cnt_delay <= 8'b0;
else if(cnt_delay==8'd199)
cnt_delay <= 8'b0;
else cnt_delay <= cnt_delay + 1'b1;
end
reg [2:0]cnt;
always @(posedge sys_clk or negedge sys_rstn)
begin
if(!sys_rstn)
cnt <= 3'd5;
else
case (cnt_delay)
8'd49: cnt <= 3'd1; //高电平中间位置
8'd99: cnt <= 3'd2; //下降沿
8'd149: cnt <= 3'd3; //低电平中间位置
8'd199: cnt <= 3'd0; //上升沿
default: cnt <= 3'd5;
endcase
end
`define SCL_POS (cnt==3'd0) //上升沿
`define SCL_HIG (cnt==3'd1) //高电平中间位置用于数据采样
`define SCL_NEG (cnt==3'd2) //下降沿
`define SCL_LOW (cnt==3'd3) //低电平中间位置用于数据变化
reg scl_r;
always @(posedge sys_clk or negedge sys_rstn)
begin
if(!sys_rstn)
scl_r <= 1'b1;
else if(`SCL_NEG) //下降沿
scl_r <= 1'b0;
else if(`SCL_POS) //上升沿
scl_r <= 1'b1;
end
assign ds1302_scl = scl_r;
`define SECOND_READ_ADDR 8'h81;
parameter START = 4'd1;
parameter WRITE_SECOND_ADDR = 4'd2;
parameter READ_SECOND_DATA = 4'd3;
parameter STOP = 4'd4;
reg [3:0]state;
reg [3:0]num;
reg [7:0]dr;
reg ds1302_ce_r;
reg ds1302_data_r;
reg ds1302_data_link; //方向选择
reg [7:0]second_rr;
reg [7:0]second_r;
always @(posedge sys_clk or negedge sys_rstn)
begin
if(!sys_rstn)
begin
state <= START;
num <= 4'd0;
dr <= 8'b0;
ds1302_ce_r <= 1'b0;
ds1302_data_r <= 1'b0;
ds1302_data_link <= 1'b1; //output
second_r <= 8'b0;
end
else
case (state)
START:
begin
num <= 4'd0;
ds1302_ce_r <= 1'b0;
ds1302_data_r <= 1'b0;
dr <= `SECOND_READ_ADDR;
ds1302_data_link <= 1'b1; //output
ds1302_ce_r <= 1'b1;
state <= WRITE_SECOND_ADDR;
end
WRITE_SECOND_ADDR:
begin
if(`SCL_NEG) //下降沿准备好数据准备好
begin
if(num==8)
begin
num <= 4'b0;
state <= READ_SECOND_DATA;
ds1302_data_link <= 1'b0; //input
end
else
begin
num <= num + 1'b1;
case (num)
4'd0: ds1302_data_r <= dr[0];
4'd1: ds1302_data_r <= dr[1];
4'd2: ds1302_data_r <= dr[2];
4'd3: ds1302_data_r <= dr[3];
4'd4: ds1302_data_r <= dr[4];
4'd5: ds1302_data_r <= dr[5];
4'd6: ds1302_data_r <= dr[6];
4'd7: ds1302_data_r <= dr[7];
default :;
endcase
state <= WRITE_SECOND_ADDR;
end
end
else state <= WRITE_SECOND_ADDR;
end
READ_SECOND_DATA:
begin
if(`SCL_NEG)
begin
if(num == 8)
begin
num <= 4'b0;
state <= STOP;
second_r <= second_rr;
ds1302_data_link <= 1'b1; //output
end
else
begin
num <= num + 1'b1;
case (num)
4'd0: second_rr[0] <= ds1302_data;
4'd1: second_rr[1] <= ds1302_data;
4'd2: second_rr[2] <= ds1302_data;
4'd3: second_rr[3] <= ds1302_data;
4'd4: second_rr[4] <= ds1302_data;
4'd5: second_rr[5] <= ds1302_data;
4'd6: second_rr[6] <= ds1302_data;
4'd7: second_rr[7] <= ds1302_data;
default :;
endcase
state <= READ_SECOND_DATA;
end
end
else state <= READ_SECOND_DATA;
end
STOP:
begin
ds1302_ce_r <= 1'b0;
state <= START;
end
default:state <= START;
endcase
end
assign ds1302_data = ds1302_data_link ? ds1302_data_r : 1'bz;
assign second = second_r;
assign ds1302_ce = ds1302_ce_r;
endmodule
一直找不到问题
打赏帖 | |
---|---|
分享一种检测按键状态的方法被打赏20分 | |
周末总结一下,STM32C0系列的开发经验被打赏50分 | |
【换取手持数字示波器】MicrochipMPLABHarmony框架下定时器配置被打赏20分 | |
【换取手持数字示波器】MicrochipMPLABHarmony框架下PWM配置被打赏20分 | |
【Cortex-M】Systick Timer使用被打赏10分 | |
分享汽车防盗系统的组成与分类(一)被打赏5分 | |
VOFA+波形显示+JYD-31蓝牙发送和解析不定长数据被打赏10分 | |
【换取手持数字示波器】-STM32F4PWM控制LED灯管亮度被打赏22分 | |
【换取手持数字示波器】STM32F4驱动RPR-0521RS照度、接近一体型传感器被打赏23分 | |
宏定义和const关键字定义被打赏5分 |