简单双向二线制,同步串行总线。
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仿真模型。
仿真验证通过,上板验证通过。