📄 i2c_top.v
字号:
`timescale 1ns/1ns
module i2c_top(clk,
rst_n,
sda,
scl,
data_rep
// hc_cp,
// hc_si
);
input clk;
input rst_n;
inout sda;
output scl;
output data_rep;
// output hc_cp;
// output hc_si;
reg wr; //write eeprom command
reg rd; //read eeprom command
reg [10:0] addr; //write or read address.
reg [7:0] data_w; //write data to eeprom
wire ack; //i2c write or read complete
wire [7:0] data_r; //read data from eeprom
reg [15:0] data_rep; //存储显示在七段数码管上的数据
reg show_ok; //正确显示后的标志
reg wr_flag; //记录是否已经发送过write,read command
reg [6:0] cs,ns;
parameter IDLE = 7'b0000001,
WR_BYTE = 7'b0000010,
WR_ACK = 7'b0000100,
DELAY = 7'B0001000,
RD_BYTE = 7'b0010000,
RD_ACK = 7'b0100000,
SHOW = 7'b1000000;
//-------------产生时钟clk分频-----------------------------------------------
reg [11:0] clk_cnt;
reg [12:0] clk_div_cnt;
reg clk_div;
always @ (posedge clk or negedge rst_n)
if (!rst_n)
clk_cnt <= 12'd0;
else if (clk_cnt == 12'd1250) //get 20khz SCL clock
clk_cnt <= 12'd0;
else
clk_cnt <= clk_cnt + 1'b1;
always @ (posedge clk or negedge rst_n)
if (!rst_n)
clk_div <= 1'b0;
else if (clk_cnt == 12'd1250)
clk_div <= ~clk_div; //20khz
always @ (posedge clk_div or negedge rst_n)
if (!rst_n)
clk_div_cnt <= 13'd0;
else
clk_div_cnt <= clk_div_cnt + 1'b1;
//---------State machine------------------
always @ (posedge clk_div or negedge rst_n)
if (!rst_n)
cs <= IDLE;
else
cs <= ns;
always @ ( * )
case (cs)
IDLE:
if (clk_div_cnt == 13'd1000)
ns = WR_BYTE;
else
ns = IDLE;
WR_BYTE:
if (ack)
ns = WR_ACK;
else
ns = WR_BYTE;
WR_ACK:
if (!ack)
ns = DELAY;
else
ns = WR_ACK;
DELAY://eeprom写数据需要时间,故:等待数据写完后再进行读操作
if (clk_div_cnt == 13'd1300)
ns = RD_BYTE;
else
ns = DELAY;
RD_BYTE:
if (ack)
ns = RD_ACK;
else
ns = RD_BYTE;
RD_ACK:
if (!ack)
ns = SHOW;
else
ns = RD_ACK;
SHOW:
if (show_ok)
ns = IDLE;
else
ns = SHOW;
default:
ns = IDLE;
endcase
always @ (posedge clk_div or negedge rst_n)
if (!rst_n)
begin
wr <= 1'b0;
rd <= 1'b0;
addr <= 11'd0;
data_w <= 8'd0;
// data_w <= 8'h58;
show_ok <= 1'b0;
wr_flag <= 1'b0;
end
else if (data_w == 8'd255) //计数到255就重新开始
begin
addr <= 11'd0;
data_w <= 8'd0;
// data_w <= 8'h58;
end
else
case (cs)
IDLE:
begin
wr <= 1'b0;
rd <= 1'b0;
show_ok <= 1'b0;
wr_flag <= 1'b0;
end
WR_BYTE:
if (wr_flag == 1'b0)
begin
wr <= 1'b1;
wr_flag <= 1'b1;
end
else
wr <= 1'b0;
WR_ACK:
wr_flag <= 1'b0;
DELAY:
begin
wr <= 1'b0;
rd <= 1'b0;
show_ok <= 1'b0;
wr_flag <= 1'b0;
end
RD_BYTE:
if (wr_flag == 1'b0)
begin
rd <= 1'b1;
wr_flag <= 1'b1;
end
else
rd <= 1'b0;
RD_ACK:
begin
wr_flag <= 1'b0;
show_ok <= 1'b1;
end
SHOW:
begin
show_ok <= 1'b0;
addr <= addr + 1'b1;
data_w <= data_w + 1'b1;
end
default:
begin
wr <= 1'b0;
rd <= 1'b0;
show_ok <= 1'b0;
wr_flag <= 1'b0;
end
endcase
always @ (posedge clk_div or negedge rst_n)
if (!rst_n)
data_rep <=16'h0000;
else if (show_ok)
data_rep <= {data_w,data_r}; //将写入eeprom和从eeprom中读出的数据进行对比输出
// ---------------------------------------------------------------------------
// 例化EEPROM: 24C02的驱动程序
// ---------------------------------------------------------------------------
i2c_wr i2c_wr_inst(
.clk (clk_div),
.rst_n (rst_n),
.wr (wr),
.rd (rd),
.addr (addr),
.data_w (data_w),
.data_r (data_r),
.ack (ack),
.scl (scl),
.sda (sda)
);
// ---------------------------------------------------------------------------
// 例化hc164的驱动程序
// ---------------------------------------------------------------------------
// hc164_driver hc164_driver_inst(
// .clk ( clk ),
// .rst_n ( rst_n ),
// .led ( {4{ ack }} ),
// .dot ( 4'b0000 ),
// .seg_value ( data_rep ),
// .hc_cp ( hc_cp ),
// .hc_si ( hc_si )
// );
endmodule
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -