简介:
简单双向二线制,同步串行总线。
scl:串行时钟线,用于同步通讯数据。
sda:双向串行数据线。
物理层:
1,支持挂载多设备。
2,二线制。
3,每个设备有其单独的地址。
4,空闲时,sda会被上拉电阻拉高。
5,存在多个主机时,通过仲裁逻辑决定那个主机控制总线。
6,三个速度模式:标准模式(100kb/s);快速模式(400kb/s);高速模式(3.4Mb/s)
地址:
器件地址。7bit,最后1bit为读写控制位。
存储地址:分为单字节和双字节,与存储设备容量有关。就是有多少byte的容量,用几位二进制地址表示。
读写地址。
时序总结:
在scl为高时,若sda变化,则为起始或终止信号。
在scl为低时,(已启动读时隙),sda在scl低电平变化,高电平对sda采样。
读时序:分为随机读(单字节读)和顺序读(页读)。
写时序:单字节写和页写。
框图:
时序图也画了,很多很大,就不放了。
代码:
iic时序驱动模块+指令控制模块+按键消抖+顶层;
/************************************************************
**************** iic 模块说明 ************************
**************** 驱动接口模块 ************************
*输入端口:
*sys_clk : 1Mhz时钟信号。
*iic_start : 开始进行读写通信标志信号。
*en_w : 写使能信号,与iic_start同时拉高,iic模块启动写时序。
*addr : 地址信号,读写公用一个地址信号。
*data_w : 要通过iic协议写入从机的8bit数据。
*en_r : 读使能信号,与iic_start同时拉高,iic模块启动读时序。
*addr_num : 由于地址有单byte和双byte情况,addr_num == 0表示单。
*输出端口:
*scl : iic协议的同步时钟信号。串行时钟线,用于同步通讯数据。时钟频率为250kHz
*sda : 双向端口,双向串行数据线。
*data_out : 读取到的1byte数据。
*iic_end : 完成ibyte数据的读写标志信号。
*/
module iic (
input wire sys_clk , // 虽然写的是sys_clk但是例化时要接iic_clk
input wire sys_rst_n ,
input wire iic_start ,
input wire en_w ,
input wire en_r ,
input wire [15:0] byte_addr ,
input wire [7:0] data_w ,
input wire addr_num ,
inout wire sda ,
output reg scl ,
output reg [7:0] data_out ,
output reg iic_end
);
// parameter
parameter DEVICE_ADDR = 7'b1010_011 ; // 器件地址,最后一位要根据读写,来决定。[6:0]
wire [7:0] FIRST_ADDR ; // AT24C64
wire [7:0] SECOND_ADDR ; // 可在此设置读写地址。
assign FIRST_ADDR = byte_addr[15:8] ;
assign SECOND_ADDR = byte_addr[ 7:0] ;
// localparam
localparam IDLE =4'b0000 ,
START1 =4'b0001 ,
SEND_DEVICE_ADDR =4'b0011 ,
ACK1 =4'b0010 ,
SEND_FIRST_ADDR =4'b0110 ,
ACK2 =4'b0111 ,
SEND_SECOND_ADDR =4'b0101 ,
ACK3 =4'b0100 ,
WR_DATA =4'b1100 ,
ACK4 =4'b1101 ,
STOP =4'b1111 ,
START2 =4'b1110 ,
SEND_READ_DEVICE_ADDR =4'b1010 ,
ACK5 =4'b1011 ,
READ_DATA =4'b1001 ,
NO_ACK =4'b1000 ;
// wire signal define
wire sda_en ;
wire IDLEtoSTART1 ;
wire START1toSEND_DEVICE_ADDR ;
wire SEND_DEVICE_ADDRtoACK1 ;
wire ACK1toSEND_FIRST_ADDR ;
wire ACK1toSEND_SECOND_ADDR ;
wire SEND_FIRST_ADDRtoACK2 ;
wire ACK2toSEND_SECOND_ADDR ;
wire SEND_SECOND_ADDRtoACK3 ;
wire ACK3toWR_DATA ;
wire ACK3toSTART2 ;
wire WR_DATAtoACK4 ;
wire ACK4toSTOP ;
wire STOPtoIDLE ;
wire START2toSEND_READ_DEVICE_ADDR;
wire SEND_READ_DEVICE_ADDRtoACK5 ;
wire ACK5toREAD_DATA ;
wire READ_DATAtoNO_ACK ;
wire NO_ACKtoSTOP ;
// reg signal define
reg [3:0] state_c ;
reg [3:0] state_n ;
reg [1:0] cnt_iic ; // 关键计数器。很多信号赋值都与他有关。
reg [2:0] cnt_bit ; // bit计数器,计数值0-7
reg sda_out ;
/***********************************************************************/
// 状态机描述
// reg [3:0] state_c ;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
state_c <= IDLE ;
else
state_c <= state_n ;
end
// reg [3:0] state_n ;
always @(*) begin
case(state_c)
IDLE : if(IDLEtoSTART1)
state_n = START1 ;
else
state_n = IDLE ;
START1 : if(START1toSEND_DEVICE_ADDR)
state_n = SEND_DEVICE_ADDR ;
else
state_n = START1 ;
SEND_DEVICE_ADDR : if(SEND_DEVICE_ADDRtoACK1)
state_n = ACK1 ;
else
state_n = SEND_DEVICE_ADDR ;
ACK1 : if(ACK1toSEND_FIRST_ADDR)
state_n = SEND_FIRST_ADDR ;
else if(ACK1toSEND_SECOND_ADDR)
state_n = SEND_SECOND_ADDR ;
else
state_n = ACK1 ;
SEND_FIRST_ADDR : if(SEND_FIRST_ADDRtoACK2)
state_n = ACK2 ;
else
state_n = SEND_FIRST_ADDR ;
ACK2 : if(ACK2toSEND_SECOND_ADDR)
state_n = SEND_SECOND_ADDR ;
else
state_n = ACK2 ;
SEND_SECOND_ADDR : if(SEND_SECOND_ADDRtoACK3)
state_n = ACK3 ;
else
state_n = SEND_SECOND_ADDR ;
ACK3 : if(ACK3toWR_DATA)
state_n = WR_DATA ;
else if(ACK3toSTART2)
state_n = START2 ;
else
state_n = ACK3 ;
WR_DATA : if(WR_DATAtoACK4)
state_n = ACK4 ;
else
state_n = WR_DATA ;
ACK4 : if(ACK4toSTOP)
state_n = STOP ;
else
state_n = ACK4 ;
STOP : if(STOPtoIDLE)
state_n = IDLE ;
else
state_n = STOP ;
START2 : if(START2toSEND_READ_DEVICE_ADDR)
state_n = SEND_READ_DEVICE_ADDR ;
else
state_n = START2 ;
SEND_READ_DEVICE_ADDR: if(SEND_READ_DEVICE_ADDRtoACK5)
state_n = ACK5 ;
else
state_n = SEND_READ_DEVICE_ADDR ;
ACK5 : if(ACK5toREAD_DATA)
state_n = READ_DATA ;
else
state_n = ACK5 ;
READ_DATA : if(READ_DATAtoNO_ACK)
state_n = NO_ACK ;
else
state_n = READ_DATA ;
NO_ACK : if(NO_ACKtoSTOP)
state_n = STOP ;
else
state_n = NO_ACK ;
default : state_n = IDLE ;
endcase
end
// 状态转移条件赋值:
assign IDLEtoSTART1 = (state_c == IDLE ) && (iic_start == 1'b1) ;
assign START1toSEND_DEVICE_ADDR = (state_c == START1) && (cnt_iic == 3) ;
assign SEND_DEVICE_ADDRtoACK1 = (state_c == SEND_DEVICE_ADDR) && (cnt_iic == 3 && cnt_bit == 7) ;
assign ACK1toSEND_FIRST_ADDR = (state_c == ACK1 ) && (cnt_iic == 3 && sda == 1'b0 && addr_num == 1) ; //&& sda == 1'b0 由于仿真模型没有相应ack功能,所以要自己模拟。
assign ACK1toSEND_SECOND_ADDR = (state_c == ACK2 ) && (cnt_iic == 3 && sda == 1'b0 && addr_num == 0) ; //&& sda == 1'b0
assign SEND_FIRST_ADDRtoACK2 = (state_c == SEND_FIRST_ADDR) && (cnt_iic == 3 && cnt_bit == 7) ;
assign ACK2toSEND_SECOND_ADDR = (state_c == ACK2 ) && (cnt_iic == 3 && sda == 0) ; //&& sda == 0
assign SEND_SECOND_ADDRtoACK3 = (state_c == SEND_SECOND_ADDR) && (cnt_iic == 3 && cnt_bit == 7) ;
assign ACK3toWR_DATA = (state_c == ACK3 ) && (cnt_iic == 3 && en_w && sda == 0) ; // && sda == 0
assign ACK3toSTART2 = (state_c == ACK3 ) && (cnt_iic == 3 && en_r && sda == 0) ; // && sda == 0
assign WR_DATAtoACK4 = (state_c == WR_DATA ) && (cnt_iic == 3 && cnt_bit == 7) ;
assign ACK4toSTOP = (state_c == ACK4 ) && (cnt_iic == 3 && sda == 0) ; // && sda == 0
assign STOPtoIDLE = (state_c == STOP ) && (cnt_iic == 3 && cnt_bit == 3) ;
assign START2toSEND_READ_DEVICE_ADDR = (state_c == START2) && (cnt_iic == 3) ;
assign SEND_READ_DEVICE_ADDRtoACK5 = (state_c == SEND_READ_DEVICE_ADDR) && (cnt_iic == 3 && cnt_bit == 7) ;
assign ACK5toREAD_DATA = (state_c == ACK5 ) && (cnt_iic == 3 && sda == 0) ; //&& sda == 0
assign READ_DATAtoNO_ACK = (state_c == READ_DATA) && (cnt_iic == 3 && cnt_bit == 7) ;
assign NO_ACKtoSTOP = (state_c == NO_ACK) && (cnt_iic == 3 && sda == 1) ;
// reg [1:0] cnt_iic ; // 关键计数器。很多信号赋值都与他有关。
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
cnt_iic <= 2'd0 ;
else if(state_c != IDLE)
cnt_iic <= cnt_iic + 1'b1 ;
else
cnt_iic <= 1'b0 ;
end
// reg [2:0] cnt_bit ; // bit计数器,计数值0-7
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
cnt_bit <= 3'd0 ;
else if(state_c != IDLE && state_c != START1 && state_c != START2 && state_c != NO_ACK && state_c != ACK1 && state_c != ACK2 && state_c != ACK3 && state_c != ACK4 && state_c != ACK5 && cnt_iic == 3)
cnt_bit <= cnt_bit + 1'b1 ;
else if(state_c != IDLE && state_c != START1 && state_c != START2 && state_c != NO_ACK && state_c != ACK1 && state_c != ACK2 && state_c != ACK3 && state_c != ACK4 && state_c != ACK5)
cnt_bit <= cnt_bit ;
else
cnt_bit <= 3'd0 ;
end
// reg sda_out ;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
sda_out <= 1'b1 ;
else
case (state_c)
IDLE : sda_out <= 1'b1 ;
START1 : if(cnt_iic == 0)
sda_out <= 1'b0 ;
else
sda_out <= sda_out ;
SEND_DEVICE_ADDR : if(cnt_iic == 0 && cnt_bit != 7)
sda_out <= DEVICE_ADDR[6 - cnt_bit] ;
else if(cnt_iic == 0 && cnt_bit == 7)
sda_out <= 1'b0 ; // 写控制位。
ACK1 : sda_out <= 1'b0 ;
SEND_FIRST_ADDR : if(cnt_iic == 0)
sda_out <= FIRST_ADDR[7 - cnt_bit] ;
else
sda_out <= sda_out ;
ACK2 : sda_out <= 1'b0 ;
SEND_SECOND_ADDR : if(cnt_iic == 0)
sda_out <= SECOND_ADDR[7 - cnt_bit] ;
else
sda_out <= sda_out ;
ACK3 : sda_out <= 1'b0 ;
WR_DATA : if(cnt_iic == 0)
sda_out <= data_w[7 - cnt_bit] ;
else
sda_out <= sda_out ;
ACK4 : sda_out <= 1'b0 ;
STOP : if(cnt_iic == 0 && cnt_bit == 0)
sda_out <= 1'b0 ;
else if(cnt_iic == 2 && cnt_bit == 0)
sda_out <= 1'b1 ;
else
sda_out <= sda_out ;
START2 : if(cnt_iic == 0)
sda_out <= 1'b1 ;
else if(cnt_iic == 2)
sda_out <= 1'b0 ;
else
sda_out <= sda_out ;
SEND_READ_DEVICE_ADDR: if(cnt_iic == 0 && cnt_bit != 7)
sda_out <= DEVICE_ADDR[6 - cnt_bit] ;
else if(cnt_iic == 0 && cnt_bit == 7)
sda_out <= 1'b1 ; // 读控制位。
ACK5 : sda_out <= 1'b0 ;
READ_DATA : sda_out <= 1'b0 ;
NO_ACK : sda_out <= 1'b1 ;
default : sda_out <= 1'b1 ;
endcase
end
// wire sda_en
assign sda_en = ((state_c == ACK1) || (state_c == ACK2) || (state_c == ACK3) || (state_c == ACK4) || (state_c == ACK5) || (state_c == READ_DATA)) ? 1'b0 : 1'b1 ;
/***************************************************************************/
// wire sda ,
assign sda = (sda_en == 1) ? sda_out : 1'bz ;
// reg scl ,
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
scl <= 1'b1 ;
else
if(state_c != IDLE && state_c != STOP && state_c != START1) begin
if(cnt_iic == 1 || cnt_iic == 3)
scl <= ~scl ;
else
scl <= scl ;
end
else if(state_c == IDLE)
scl <= 1'b1 ;
else if(state_c == STOP && (cnt_bit == 0 && cnt_iic == 1))
scl <= 1'b1 ;
else if(state_c == STOP)
scl <= scl ;
else if(state_c == START1 && cnt_iic == 3)
scl <= ~scl ;
else if(state_c == START1)
scl <= scl ;
else
scl <= 1'b1 ;
end
// reg sda_data ;
// always @(posedge sys_clk or negedge sys_rst_n) begin
// if(~sys_rst_n)
// sda_data <= 1'b0 ;
// else if(state_c == READ_DATA && cnt_iic == 0)
// sda_data <= ~sda_data ;
// else
// sda_data <= sda_data ;
// end
// reg [7:0] data_out
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
data_out <= 8'd0 ;
else if(state_c == READ_DATA && cnt_iic == 2 && scl == 1)
data_out <= {data_out[6:0],sda} ; // 这里也需要自己模拟 sda_data
else
data_out <= data_out ;
end
// wire iic_end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
iic_end <= 1'b0 ;
else if(state_c == STOP && cnt_iic == 3 && cnt_bit == 3)
iic_end <= 1'b1 ;
else
iic_end <= 1'b0 ;
end
endmodule
/************************************************************
**************** iic_instruct 模块说明 ************************
**************** 产生接口时序模块的控制信号,并存储读到的数据,并把数据传给数码管显示模块。
*/
module iic_instruct (
input wire sys_clk , // 20ns
input wire sys_rst_n ,
input wire iic_clk , // 1000ns
input wire flag_w ,
input wire flag_r ,
input wire iic_end ,
input wire [7:0] data_r , // iic 模块读到的1byte数据。
output reg iic_start ,
output reg en_w , // 写使能,往eeprom中写数据的使能信号。
output reg en_r , // 读使能,从eeprom中读数据的使能信号。
output reg [15:0] byte_addr , // 读写操作的数据地址。
output reg [7:0] data_w , // 往eeprom中写入的数据。
output wire addr_num , // eeprom的存储地址是几个byte。
output wire [7:0] data_out // 传给数码管显示的数据。
);
parameter ADDR_START = 16'h00_00 ,
DATA_WRITE = 8'd00 , // 写入的起始数据。
CNT_MAX_START = 49999 , // 5ms
CNT_MAX_1S = 1_000_000 ,
CNT_MAX_WRITE_BYTE = 10 ,
CNT_MAX_READ_BYTE = 10 ;
/******************************************************/
// 第一步:处理输入信号,实现快速时钟域标志信号同步到慢速时钟域。
// 也就是保证慢速时钟域可以检测到标志信号。
reg valid_write ;
reg [7:0] cnt_write ;
reg valid_read ;
reg [7:0] cnt_read ;
reg [15:0] cnt_read_byte ;
reg [15:0] cnt_start ;
reg [15:0] cnt_write_byte ; // 写入eeprom字节计数器
wire empty ;
wire full ;
wire [9:0] usedw ;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
valid_write <= 1'b0 ;
else if(flag_w)
valid_write <= 1'b1 ;
else if(cnt_write == 199)
valid_write <= 1'b0 ;
else
valid_write <= valid_write ;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
cnt_write <= 8'd0 ;
else if(valid_write && cnt_write == 199)
cnt_write <= 8'd0 ;
else if(valid_write)
cnt_write <= cnt_write + 1'b1 ;
else
cnt_write <= 8'd0 ;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
valid_read <= 1'b0 ;
else if(flag_r)
valid_read <= 1'b1 ;
else if(cnt_read == 199)
valid_read <= 1'b0 ;
else
valid_read <= valid_read ;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
cnt_read <= 8'd0 ;
else if(valid_read && cnt_read == 199)
cnt_read <= 8'd0 ;
else if(valid_read)
cnt_read <= cnt_read + 1'b1 ;
else
cnt_read <= 8'd0 ;
end
assign addr_num = 1'b1 ;
/**********************************************************************************/
// 第二步:产生写数据相关信号的产生。在iic_clk时钟域下。
// en_w
always @(posedge iic_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
en_w <= 1'b0 ;
else if(iic_end && (cnt_write_byte == CNT_MAX_WRITE_BYTE - 1))
en_w <= 1'b0 ;
else if(valid_write)
en_w <= 1'b1 ;
else
en_w <= en_w ;
end
//reg iic_start
always @(posedge iic_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
iic_start <= 1'b0 ;
else if(en_w == 0 && valid_write == 1 || cnt_start == CNT_MAX_START - 1)
iic_start <= 1'b1 ;
else
iic_start <= 1'b0 ;
end
// reg [15:0] cnt_start ;
always @(posedge iic_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
cnt_start <= 16'd0 ;
else if(((en_w == 1) && ((cnt_start == CNT_MAX_START - 1)
|| (iic_end == 1 && cnt_write_byte == CNT_MAX_WRITE_BYTE - 1)))
|| ((en_r == 1) && ((cnt_start == CNT_MAX_START - 1)
|| (iic_end == 1 && cnt_read_byte == CNT_MAX_READ_BYTE - 1))))
cnt_start <= 16'd0 ;
else if(en_w == 1 || en_r)
cnt_start <= cnt_start + 1'b1 ;
else
cnt_start <= 16'd0 ;
end
// [15:0] byte_addr // 目前只完成了写地址,
always @(posedge iic_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
byte_addr <= ADDR_START ;
else if((iic_end == 1 && cnt_write_byte == CNT_MAX_WRITE_BYTE - 1)
|| (iic_end == 1 && cnt_read_byte == CNT_MAX_READ_BYTE - 1))
byte_addr <= ADDR_START ;
else if(iic_end == 1)
byte_addr <= byte_addr + 1'b1 ;
else
byte_addr <= byte_addr ;
end
// [7:0] data_w
always @(posedge iic_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
data_w <= DATA_WRITE ;
else if(iic_end == 1 && cnt_write_byte == CNT_MAX_WRITE_BYTE - 1)
data_w <= DATA_WRITE ;
else if(en_w && iic_end == 1)
data_w <= data_w + 1'b1 ;
else
data_w <= data_w ;
end
// [15:0] cnt_write_byte
always @(posedge iic_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
cnt_write_byte <= 16'd0 ;
else if(en_w && iic_end == 1 && cnt_write_byte == CNT_MAX_WRITE_BYTE - 1)
cnt_write_byte <= 16'd0 ;
else if(en_w && iic_end == 1)
cnt_write_byte <= cnt_write_byte + 1'b1 ;
else
cnt_write_byte <= cnt_write_byte ;
end
/*****************************************************************************/
// 读相关控制信号产生
// en_r
always @(posedge iic_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
en_r <= 1'b0 ;
else if(iic_end == 1 && cnt_read_byte == CNT_MAX_READ_BYTE - 1)
en_r <= 1'b0 ;
else if(valid_read)
en_r <= 1'b1 ;
else
en_r <= en_r ;
end
// [15:0] cnt_read_byte
always @(posedge iic_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
cnt_read_byte <= 16'd0 ;
else if(en_r && iic_end == 1 && cnt_read_byte == CNT_MAX_READ_BYTE - 1)
cnt_read_byte <= 16'd0 ;
else if(en_r && iic_end == 1)
cnt_read_byte <= cnt_read_byte + 1'b1 ;
else
cnt_read_byte <= cnt_read_byte ;
end
/*******************************************************************************/
reg valid_fifo_read ;
reg [19:0] cnt_1s ;
reg fifo_rd_en ;
// valid_fifo_read
always @(posedge iic_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
valid_fifo_read <= 1'b0 ;
else if(valid_fifo_read == 1 && usedw == 0)
valid_fifo_read <= 1'b0 ;
else if(usedw > (CNT_MAX_READ_BYTE - 1))
valid_fifo_read <= 1'b1 ;
else
valid_fifo_read <= valid_fifo_read ;
end
// [19:0] cnt_1s
always @(posedge iic_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
cnt_1s <= 20'd0 ;
else if(valid_fifo_read == 1 && cnt_1s == CNT_MAX_1S - 1)
cnt_1s <= 20'd0 ;
else if(valid_fifo_read == 1)
cnt_1s <= cnt_1s + 1'b1 ;
else
cnt_1s <= 20'd0 ;
end
// fifo_rd_en
always @(posedge iic_clk or negedge sys_rst_n) begin
if(~sys_rst_n)
fifo_rd_en <= 1'b0 ;
else if(valid_fifo_read == 1 && cnt_1s == CNT_MAX_1S - 1)
fifo_rd_en <= 1'b1 ;
else
fifo_rd_en <= 1'b0 ;
end
fifo_8x1024 fifo_8x1024_inst(
.clock ( iic_clk ) ,
.data ( data_r ) ,
.rdreq ( fifo_rd_en ) ,
.wrreq ( en_r && iic_end ) ,
.empty ( empty ) ,
.full ( full ) ,
.q ( data_out ) ,
.usedw ( usedw )
);
endmodule
module top (
input wire sys_clk ,
input wire sys_rst_n ,
input wire key_write ,
input wire key_read ,
inout wire sda ,
output wire scl ,
output wire ds ,
output wire oe ,
output wire shcp ,
output wire stcp
);
// 例化间连线
wire clk_50mHz ;
wire clk_1mHz ;
wire locked ;
wire rst_n ;
wire flag_write ;
wire flag_read ;
wire [05:00] point ;
wire sign ;
assign point = 5'd0 ;
assign sign = 1'b0 ;
assign rst_n = sys_rst_n && locked ;
pll pll_isnt(
.areset ( ~sys_rst_n ) ,
.inclk0 ( sys_clk ) ,
.c0 ( clk_50mHz ) ,
.c1 ( clk_1mHz ) ,
.locked ( locked )
);
key_filter key_filter_inst_w(
.sys_clk ( clk_50mHz ) ,
.sys_rst_n ( rst_n ) ,
.key_in ( key_write ) ,
.key_out ( flag_write)
);
key_filter key_filter_inst_r(
.sys_clk ( clk_50mHz ) ,
.sys_rst_n ( rst_n ) ,
.key_in ( key_read ) ,
.key_out ( flag_read )
);
wire iic_start ;
wire en_w ;
wire en_r ;
wire [15:0] byte_addr ;
wire [7:0] data_w ;
wire addr_num ;
wire [7:0] data_out ;
wire iic_end ;
wire [7:0] data_r ;
iic_instruct iic_instruct_inst(
.sys_clk ( clk_50mHz ) , // 20ns
.sys_rst_n ( rst_n ) ,
.iic_clk ( clk_1mHz ) , // 1000ns
.flag_w ( flag_write ) ,
.flag_r ( flag_read ) ,
.iic_end ( iic_end ) ,
.data_r ( data_r ) , // iic 模块读到的1byte数据。
.iic_start ( iic_start ) ,
.en_w ( en_w ) , // 写使能,往eeprom中写数据的使能信号。
.en_r ( en_r ) , // 读使能,从eeprom中读数据的使能信号。
.byte_addr ( byte_addr ) , // 读写操作的数据地址。
.data_w ( data_w ) , // 往eeprom中写入的数据。
.addr_num ( addr_num ) , // eeprom的存储地址是几个byte。
.data_out ( data_out ) // 传给数码管显示的数据。
);
iic iic_inst(
.sys_clk ( clk_1mHz ) , // 虽然写的是sys_clk但是例化时要接iic_clk
.sys_rst_n ( rst_n ) ,
.iic_start ( iic_start ) ,
.en_w ( en_w ) ,
.en_r ( en_r ) ,
.byte_addr ( byte_addr ) ,
.data_w ( data_w ) ,
.addr_num ( addr_num ) ,
.sda ( sda ) ,
.scl ( scl ) ,
.data_out ( data_r ) ,
.iic_end ( iic_end )
);
seg_595_dynamic seg_595_dynamic_isnt(
.sys_clk ( clk_50mHz ) ,
.sys_rst_n ( rst_n ) ,
.data ( {12'd0,data_out} ) ,
.point ( point ) ,
.sign ( sign ) ,
.seg_en ( rst_n ) ,
.ds ( ds ) ,
.oe ( oe ) ,
.shcp ( shcp ) ,
.stcp ( stcp )
);
endmodule
仿真测试,要用到 M24C64仿真模型。文章来源:https://www.toymoban.com/news/detail-715206.html
仿真验证通过,上板验证通过。文章来源地址https://www.toymoban.com/news/detail-715206.html
到了这里,关于FPGA project : IIC_wr_eeprom的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!