通过IIC控制EEPROM。
共6个模块(Module)。
module IIC( input wire clk , input wire rst_n , input wire start_iic , //开始信号,外部模块引入信号 input wire worr , //方向信号,用于状态跳转 input wire [7:0] sendnum , //单位字节,发送数据量,,用于多数据传输 input wire [7:0] recvnum , //接收的数据量 ,,用于多数据传输 input wire [7:0] data_i_icc , //要发送到rom的数据 output wire [7:0] data_o_iic , //读出的数据 output wire done_w , //写完成信号 output wire done_r , //接收字节完成的信号 output wire done_iic , //整体工作结束 output wire done_nack , //错误信号,即工作异常的时候出现 inout wire scl , inout wire sda ); parameter sysclk = 50_000_000, iicclk = 100_000, delay = sysclk/iicclk, MID = delay/2, //1/2节点 Q_MID = delay/4, //1/4节点 TQ_MID = MID + Q_MID; //3/4节点 parameter id_w = 8'b1010_0000, //写地址 id_r = 8'b1010_0001; //读地址 //变量 reg [9:0] cnt; //工作周期计数,1bit计数 reg [3:0] cnt_bit; //多少bit计数 reg [7:0] sendcnt; //发送字节个数计数器 reg [7:0] recvcnt; //接收字节个数计数器 reg [1:0] start_reg; //开始信号寄存 reg worr_reg; //方向信号寄存器 reg [7:0] sendnum_reg; //发送数据量寄存器 reg [7:0] recvnum_reg; //接收数据量寄存器 reg [7:0] data_reg; //发送数据寄存器 reg [7:0] data_temp; //接收数据寄存器 reg ack_flag; //应答信号寄存器 assign done_nack = ack_flag; //三态门 wire scl_in; reg scl_en,scl_out; assign scl = (scl_en)?scl_out:1'bz; assign scl_in = scl; wire sda_in; reg sda_en,sda_out; assign sda = (sda_en)?sda_out:1'bz; assign sda_in = sda; //开始信号寄存 always @(posedge clk) begin if(!rst_n) start_reg <= 2'b0; else start_reg <= {start_reg[0],start_iic}; end //状态机 localparam IDLE = 1 , START1 = 2 , IDW = 3 , ACK1 = 4 , WDATA = 5 , ACK2 = 6 , STOP = 7 , START2 = 8 , IDR = 9 , ACK3 = 10 , RDATA = 11 , ACK4 = 12 ; reg [3:0] c_state,n_state; // always@(posedge clk) if(!rst_n) c_state <= IDLE; else c_state <= n_state; // always @(*) begin if(!rst_n) n_state = IDLE; else case (c_state) IDLE :begin if(start_reg == 2'b01) n_state = START1; else n_state = c_state; end START1:begin if(cnt == delay + Q_MID - 1 && worr_reg == 0) n_state = IDW; else if(cnt == delay + Q_MID - 1 && worr_reg == 1) n_state = IDR; else n_state = c_state; end IDW :begin if(cnt == delay - 1 && cnt_bit == 7) n_state = ACK1; else n_state = c_state; end ACK1 :begin if(ack_flag == 1) n_state = IDLE; else if(cnt == delay - 1 && ack_flag == 0) n_state = WDATA; else n_state = c_state; end WDATA :begin if(cnt == delay - 1 && cnt_bit == 7) n_state = ACK2; else n_state = c_state; end ACK2 :begin if(ack_flag == 1) n_state = IDLE; else if(cnt == delay - 1 && ack_flag == 0 && sendnum_reg == sendcnt && recvnum_reg == 0) n_state = STOP; else if(cnt == delay - 1 && ack_flag == 0 && sendnum_reg == sendcnt && recvnum_reg != 0) n_state = START2; //实现写一个读一个效果 else if(cnt == delay - 1 && ack_flag == 0 && sendnum_reg > sendcnt) n_state = WDATA; else n_state = c_state; end STOP :begin if(cnt == delay + Q_MID - 1) n_state = IDLE; else n_state = c_state; end START2:begin if(cnt == delay + Q_MID - 1) n_state = IDR; else n_state = c_state; end IDR :begin if(cnt == delay - 1 && cnt_bit == 7) n_state = ACK3; else n_state = c_state; end ACK3 :begin if(ack_flag == 1) n_state = IDLE; if(cnt == delay - 1 && ack_flag == 0) n_state = RDATA; else n_state = c_state; end RDATA :begin if(cnt == delay - 1 && cnt_bit == 7) n_state = ACK4; else n_state = c_state; end ACK4 :begin if(cnt == delay - 1 && recvnum_reg == recvcnt) n_state = STOP; else if(cnt == delay - 1 && recvnum_reg > recvcnt) n_state = RDATA; else n_state = c_state; end default: n_state = IDLE; endcase end // always @(posedge clk) begin if(!rst_n)begin cnt <=0 ; //工作周期计数,1bit计数 cnt_bit <=0 ; //多少bit计数 sendcnt <=0 ; //发送字节个数计数器 recvcnt <=0 ; //接收字节个数计数器 worr_reg <=0 ; //方向信号寄存器 sendnum_reg <=0 ; //发送数据量寄存器 recvnum_reg <=0 ; //接收数据量寄存器 data_reg <=0 ; //发送数据寄存器 data_temp <=0 ; //接收数据寄存器 ack_flag <=0 ; //应答信号寄存器 scl_en <=0 ; //开关,都不工作,关闭 scl_out <=1 ; //高阻,1 sda_en <=0 ; //开关,都不工作,关闭 sda_out <=1 ; //高阻,1 end else case (c_state) IDLE : begin //寄存信号 cnt <=0 ; //工作周期计数,1bit计数 cnt_bit <=0 ; //多少bit计数 sendcnt <=0 ; //发送字节个数计数器 recvcnt <=0 ; //接收字节个数计数器 worr_reg <=worr ; //方向信号寄存器 sendnum_reg <=sendnum ; //发送数据量寄存器 recvnum_reg <=recvnum ; //接收数据量寄存器 data_reg <=data_i_icc ; //发送数据寄存器 data_temp <=0 ; //接收数据寄存器 ack_flag <=0 ; //应答信号寄存器 scl_en <=0 ; //开关,都不工作,关闭 sda_en <=0 ; //开关,都不工作,关闭 scl_out <=1 ; //高阻,1 sda_out <=1 ; //高阻,1 end START1,START2:begin //寄存信号 if(cnt == delay + Q_MID - 1) cnt <=0 ; //工作周期计数,1bit计数 else cnt <= cnt + 1; cnt_bit <=0 ; //多少bit计数 sendcnt <=0 ; //发送字节个数计数器 recvcnt <=0 ; //接收字节个数计数器 data_temp <=0 ; //接收数据寄存器 ack_flag <=0 ; //应答信号寄存器 scl_en <=1 ; //开关,主机工作,打开 sda_en <=1 ; //开关,主机工作,打开 //sda先拉低,scl后拉低 if(cnt >= delay -1) scl_out <=0 ; else scl_out <= 1; if(cnt >= MID - 1) sda_out <=0 ; else sda_out <=1 ; end IDW :begin //寄存信号 if(cnt == delay - 1) cnt <=0 ; //工作周期计数,1bit计数 else cnt <= cnt + 1; if(cnt == delay - 1)begin if(cnt_bit == 7) cnt_bit <=0 ; //多少bit计数 else cnt_bit <= cnt_bit + 1; end sendcnt <=0 ; //发送字节个数计数器 recvcnt <=0 ; //接收字节个数计数器 data_temp <=0 ; //接收数据寄存器 ack_flag <=0 ; //应答信号寄存器 scl_en <=1 ; //开关,主机工作,打开 sda_en <=1 ; //开关,主机工作,打开 //两边为低,中间为高 if(cnt <= Q_MID || cnt >= TQ_MID) scl_out <=0 ; else scl_out <= 1; //先发高位,低电平发送,高电平保持 if(cnt == 0) sda_out <=id_w[7 - cnt_bit] ; end ACK1,ACK3 :begin //寄存信号 if(cnt == delay - 1) cnt <=0 ; //工作周期计数,1bit计数 else cnt <= cnt + 1; cnt_bit <=0 ; //多少bit计数 sendcnt <=0 ; //发送字节个数计数器 recvcnt <=0 ; //接收字节个数计数器 data_temp <=0 ; //接收数据寄存器 if(cnt == MID) ack_flag <=sda_in ; //应答信号寄存器 scl_en <=1 ; //开关,主机工作,打开 sda_en <=0 ; //开关,主机工作,打开 //两边为低,中间为高 if(cnt <= Q_MID || cnt >= TQ_MID) scl_out <=0 ; else scl_out <= 1; //不工作 sda_out <=1 ; end WDATA :begin //寄存信号 if(cnt == delay - 1) cnt <=0 ; //工作周期计数,1bit计数 else cnt <= cnt + 1; if(cnt == delay - 1)begin if(cnt_bit == 7) cnt_bit <=0 ; //多少bit计数 else cnt_bit <= cnt_bit + 1; end recvcnt <=0 ; //接收字节个数计数器 data_temp <=0 ; //接收数据寄存器 ack_flag <=0 ; //应答信号寄存器 scl_en <=1 ; //开关,主机工作,打开 sda_en <=1 ; //开关,主机工作,打开 //两边为低,中间为高 if(cnt <= Q_MID || cnt >= TQ_MID) scl_out <=0 ; else scl_out <= 1; //先发送高位,低电平发送,高电平保持 if(cnt == 0) sda_out <=data_reg[7 - cnt_bit] ; //从高位开始 end ACK2 :begin //发送时钟,主机:接收应答,从机:更新数据;计数 if(cnt == delay - 1) cnt <=0 ; //工作周期计数,1bit计数 else cnt <= cnt + 1; cnt_bit <=0 ; //多少bit计数 if(cnt == MID) sendcnt <=sendcnt +1; //发送字节个数计数器 recvcnt <=0 ; //接收字节个数计数器 data_temp <=0 ; //接收数据寄存器 if(cnt == MID) ack_flag <=sda_in ; //应答信号寄存器 //更新数据 data_reg <= data_i_icc; scl_en <=1 ; //开关,主机工作,打开 sda_en <=0 ; //开关,从机工作,关闭 //两边为低,中间为高 if(cnt <= Q_MID || cnt >= TQ_MID) scl_out <=0 ; else scl_out <= 1; //不工作 sda_out <=1 ; end STOP :begin //寄存信号 if(cnt == delay + Q_MID - 1) cnt <=0 ; //工作周期计数,1bit计数 else cnt <= cnt + 1; cnt_bit <=0 ; //多少bit计数 sendcnt <=0 ; //发送字节个数计数器 recvcnt <=0 ; //接收字节个数计数器 data_temp <=0 ; //接收数据寄存器 ack_flag <=0 ; //应答信号寄存器 scl_en <=1 ; //开关,主机工作,打开 sda_en <=1 ; //开关,主机工作,打开 //sda后拉高,scl先拉高 if(cnt >= Q_MID -1) scl_out <=1 ; else scl_out <= 0; if(cnt >= TQ_MID - 1) sda_out <=1 ; else sda_out <=0 ; end IDR :begin //寄存信号 if(cnt == delay - 1) cnt <=0 ; //工作周期计数,1bit计数 else cnt <= cnt + 1; if(cnt == delay - 1)begin if(cnt_bit == 7) cnt_bit <=0 ; //多少bit计数 else cnt_bit <= cnt_bit + 1; end sendcnt <=0 ; //发送字节个数计数器 recvcnt <=0 ; //接收字节个数计数器 data_temp <=0 ; //接收数据寄存器 ack_flag <=0 ; //应答信号寄存器 scl_en <=1 ; //开关,主机工作,打开 sda_en <=1 ; //开关,主机工作,打开 //两边为低,中间为高 if(cnt <= Q_MID || cnt >= TQ_MID) scl_out <=0 ; else scl_out <= 1; //先发送高位,低电平发送,高电平保持 if(cnt == 0) sda_out <=id_r[7 - cnt_bit] ; end RDATA :begin //发送时钟,主机:接收数据 if(cnt == delay - 1) cnt <=0 ; //工作周期计数,1bit计数 else cnt <= cnt + 1; if(cnt == delay - 1)begin if(cnt_bit == 7) cnt_bit <=0 ; //多少bit计数 else cnt_bit <= cnt_bit + 1; end sendcnt <=0 ; //发送字节个数计数器 if(cnt == MID) data_temp[7-cnt_bit] <=sda_in ; //接收数据寄存器 ack_flag <=0 ; //应答信号寄存器 scl_en <=1 ; //开关,主机工作,打开 sda_en <=0 ; //开关,从机工作,关闭 //两边为低,中间为高 if(cnt <= Q_MID || cnt >= TQ_MID) scl_out <=0 ; else scl_out <= 1; //不工作 sda_out <=1 ; end ACK4 :begin //发送时钟,主机:接收应答,从机:更新数据;计数 if(cnt == delay - 1) cnt <=0 ; //工作周期计数,1bit计数 else cnt <= cnt + 1; cnt_bit <=0 ; //多少bit计数 sendcnt <=0; //发送字节个数计数器 if(cnt == Q_MID) recvcnt <= recvcnt + 1 ; //接收字节个数计数器 ack_flag <=0 ; //应答信号寄存器 scl_en <=1 ; //开关,主机工作,打开 sda_en <=1 ; //开关,主机工作,打开 //两边为低,中间为高 if(cnt <= Q_MID || cnt >= TQ_MID) scl_out <=0 ; else scl_out <= 1; //发送应答/非应答 if(recvnum_reg == recvcnt) sda_out <=1 ; else sda_out <= 0; end default: begin cnt_bit <=0 ; //多少bit计数 sendcnt <=0 ; //发送字节个数计数器 recvcnt <=0 ; //接收字节个数计数器 worr_reg <=0 ; //方向信号寄存器 sendnum_reg <=0 ; //发送数据量寄存器 recvnum_reg <=0 ; //接收数据量寄存器 data_reg <=0 ; //发送数据寄存器 data_temp <=0 ; //接收数据寄存器 ack_flag <=0 ; //应答信号寄存器 scl_en <=0 ; //开关,都不工作,关闭 scl_out <=1 ; //高阻,1 sda_en <=0 ; //开关,都不工作,关闭 sda_out <=1 ; //高阻,1 end endcase end assign data_o_iic = (c_state == ACK4)?data_temp:0; assign done_r = (c_state == ACK4 && cnt == MID)?1:0; assign done_w = (c_state == ACK2 && cnt == MID)?1:0; assign done_iic = (c_state == STOP && cnt == MID)?1:0; endmodulemodule ctrl_r( input wire clk , input wire rst_n , input wire done_r , input wire [7:0] data_o_iic , input wire done_tx , input wire done_iic , output wire [7:0] data_tx , //并行输入数据 output wire start_tx ); //fifo wire [7:0] data; wire wrreq; wire rdreq; wire empty; wire full; wire [7:0] q; wire [7:0] usedw; //写 assign data = data_o_iic; assign wrreq= done_r; //读 assign rdreq = ((done_iic || done_tx)&& !empty)?1:0; assign data_tx = q; reg rdreqr; always@(posedge clk) if(!rst_n) rdreqr<=0; else rdreqr<=rdreq; assign start_tx = (rdreqr) ?1:0; fifo fifo_r ( .aclr ( !rst_n), .clock ( clk ), .data ( data ), .rdreq ( rdreq ), .wrreq ( wrreq ), .empty ( empty ), .full ( full ), .q ( q ), .usedw ( usedw ) ); endmodulemodule ctrl_w( input clk , input rst_n , input wire [7:0] data_rx , //并行输出信号 input data_done , //数据完成标志 input done_iic , //数据结束,清空fifo条件 input done_w , //数据更新 input done_nack , //清空fifo output wire start_iic , //开始信号,外部模块引入信号 output wire worr , //方向信号,用于状态跳转 output wire [7:0] sendnum , //单位字节,发送数据量 output wire [7:0] recvnum , //接收的数据量 output wire [7:0] data_i_icc //要发送到rom的数据 ); /* 接收指令 如果iic工作异常 解析指令 */ //fifo reg [7:0] data; reg wrreq; wire rdreq; wire empty; wire full; wire [7:0] q; wire [7:0] usedw; localparam IDLE = 1, //识别包头 WORR = 2, //data_done方向信号 SENDNUM = 3, //data_done RECVNUM = 4, //data_done ADDR = 5, //data_done 识别包尾 DATA = 6, //data_done 识别包尾就不传输进fifo STOP = 7; // 直接跳到空闲 reg [3:0] c_state,n_state; reg worr_reg ; //读写信号标志,0是写,非0是读 reg [7:0] sendnum_reg ; //发送数据量 reg [7:0] recvnum_reg ; //接收数据量 reg [7:0] addr_reg ; //地址 reg [7:0] data_reg ; //数据 reg [7:0] data_temp; // always@(posedge clk) if(!rst_n) c_state <= 0; else c_state <= n_state; //二段状态机 always @(*) begin if(!rst_n) n_state = IDLE; else case (c_state) IDLE :begin if(data_done && data_rx==8'hfe ) // n_state = WORR; else n_state = c_state; end WORR :begin if(data_done ) n_state = SENDNUM; else n_state = c_state; end SENDNUM:begin if(data_done ) n_state = RECVNUM; else n_state = c_state; end RECVNUM:begin if(data_done ) n_state = ADDR; else n_state = c_state; end ADDR :begin if(data_done && data_rx == 8'hee) n_state = STOP; else if(data_done && data_rx != 8'hee) n_state = DATA; else n_state = c_state; end DATA :begin if(data_done && data_rx == 8'hee) n_state = STOP; else n_state = c_state; end STOP :begin /* if(done_iic) n_state = IDLE; else */ n_state = IDLE; end default: n_state = IDLE; endcase end //三段状态机,fifo写 always @(posedge clk) begin if(!rst_n)begin worr_reg <=0; sendnum_reg <=0; recvnum_reg <=0; addr_reg <=0; data <=0; wrreq <=0; end else case (c_state) IDLE :begin worr_reg <= worr_reg ; sendnum_reg <= sendnum_reg; recvnum_reg <= recvnum_reg; addr_reg <= addr_reg ; data <=0; wrreq <=0; end WORR :begin if(data_done) worr_reg <=data_rx; //给方向信号赋值 sendnum_reg <=0; recvnum_reg <=0; addr_reg <=0; data <=0; wrreq <=0; end SENDNUM:begin if(data_done) sendnum_reg <=data_rx; recvnum_reg <=0; addr_reg <=0; data <=0; wrreq <=0; end RECVNUM:begin if(data_done) recvnum_reg <=data_rx; addr_reg <=0; data <=0; wrreq <=0; end ADDR :begin if(data_done) addr_reg <=data_rx; data <=0; wrreq <=0; end DATA :begin if(data_done && data_rx != 8'hee)begin data <=data_rx; wrreq <=1; end else begin data <=0; wrreq <=0; end end STOP :begin data <=0; wrreq <=0; end default: begin worr_reg <=0; sendnum_reg <=0; recvnum_reg <=0; addr_reg <=0; data <=0; wrreq <=0; end endcase end assign rdreq = done_w; reg rdreqr; always@(posedge clk) if(!rst_n) rdreqr <= 0; else rdreqr <= rdreq; //数据交互 always@(posedge clk) if(!rst_n) data_temp <= 0; else if(rdreqr) data_temp <= q; else if(data_done && c_state == DATA) data_temp <= addr_reg; assign start_iic = (c_state == STOP)?1:0; assign worr = worr_reg; assign sendnum = sendnum_reg; assign recvnum = recvnum_reg; assign data_i_icc = data_temp; fifo fifo_w ( .aclr ( !rst_n || done_nack || done_iic ), .clock ( clk ), .data ( data ), .rdreq ( rdreq ), .wrreq ( wrreq ), .empty ( empty ), .full ( full ), .q ( q ), .usedw ( usedw ) ); endmodulemodule rx_check( input clk, input rst_n, input rx, //串行输入信号 output wire [7:0] data_rx, //并行输出信号,//8+1,奇偶校验位 output data_done //数据完成标志 ); parameter TIME = 50_000_000 , bps = 9600 , adtime = TIME / bps ; //5208个 parameter MODE = 0;//0:无校验;1:奇;2:偶;3:校验常为1;4:0; localparam IDLE = 5'b00001, //空闲 START = 5'b00010, //开始状态 DATA = 5'b00100, //数据传输状态 CHECK = 5'b01000, //校验核对状态 STOP = 5'b10000; //停止状态 //定义5个状态 reg [1:0] rx_reg ; //数据变化寄存,检测上升下降变化 reg [12:0] cnt_cout ; //存储一个数据时间周期的时间数据量,即计数5208 reg [3:0] cnt_bit ;//计数多少个数据 reg [7:0] data_reg ;//数据采样,计数一半采集数据 reg check_reg ;//校验位 reg check_num ;//校验计算 reg check_flag; //状态寄存器 reg [4:0] c_state,n_state; always@(posedge clk) if(!rst_n) c_state <= IDLE; else c_state<=n_state; //状态切换条件,组合逻辑 always@(*) if(!rst_n) n_state = IDLE; else case(c_state) IDLE :begin if(rx_reg == 2'b10) n_state = START; else n_state = c_state; end START :begin if(cnt_cout == adtime - 1) n_state = DATA; else n_state = c_state; end DATA :begin //对模式判断,是否进行数据校验 if(cnt_cout == adtime - 1 && cnt_bit == 7 && MODE != 0) n_state = CHECK; else if(cnt_cout == adtime - 1 && cnt_bit == 7 && MODE == 0) n_state = STOP; else n_state = c_state; end CHECK :begin if(cnt_cout == adtime - 1) n_state = STOP; else n_state = c_state; end STOP :begin if(cnt_cout == adtime/2 - 1) n_state = IDLE;//n_state = c_state;// else n_state = c_state; end default:n_state = IDLE; endcase //时序逻辑 always@(posedge clk) if(!rst_n)begin rx_reg <=2'b11; cnt_cout <=0; cnt_bit <=0; data_reg <=0; check_reg <=0; check_num <=0; end else case(c_state) IDLE :begin rx_reg <={rx_reg[0],rx};//2级寄存 cnt_cout <=0; cnt_bit <=0; data_reg <=0; check_reg <=0; check_num <=0; check_flag <= 0; end START :begin rx_reg <=2'b11; if(cnt_cout == adtime - 1) cnt_cout <=0; else cnt_cout <= cnt_cout + 1; cnt_bit <=0;//不需要计数数据 data_reg <=0; check_reg <=0; check_num <=0; check_flag <= 0; end DATA :begin rx_reg <=2'b11; if(cnt_cout == adtime - 1) cnt_cout <=0; else cnt_cout <= cnt_cout + 1; if(cnt_cout == adtime - 1)begin if(cnt_bit == 7) cnt_bit <=0; else cnt_bit <= cnt_bit + 1; end else cnt_bit <= cnt_bit; if(cnt_cout == adtime/2-1) data_reg[cnt_bit] <=rx; else data_reg <= data_reg; check_reg <=0; check_num <=0; check_flag <= 0; end CHECK :begin rx_reg <=2'b11; if(cnt_cout == adtime - 1) cnt_cout <=0; else cnt_cout <= cnt_cout + 1; cnt_bit <=0;// data_reg <=data_reg; if(cnt_cout == adtime/2-1) check_reg <=rx; else check_reg <= check_reg; case (MODE) 0:check_num <=0; 1:check_num <= ~^data_reg; 2:check_num <= ^data_reg; 3:check_num <=1; 4: check_num <=0; default: check_num <=0; endcase check_flag <= 0; end STOP :begin rx_reg <=2'b11; if(cnt_cout == adtime/2 - 1) cnt_cout <=0; else cnt_cout <= cnt_cout + 1; cnt_bit <=0;//不需要计数数据 data_reg <=data_reg; check_reg <=check_reg; check_num <=check_num; if(check_reg == check_num && cnt_cout == adtime/4) check_flag <= 1; else if(check_reg != check_num && cnt_cout == adtime/4) check_flag <= 0; else check_flag <= check_flag; end default:begin rx_reg <=2'b11; cnt_cout <=0; cnt_bit <=0; data_reg <=0; check_reg <=0; check_num <=0; end endcase assign data_rx = (check_flag == 1) ? data_reg : 0; assign data_done = (c_state == STOP && cnt_cout == adtime/2-1) ? 1 : 0; endmodulemodule tx_check( input clk , input rst_n , input [7:0] data_tx , //并行输入数据 input start_tx , //开始信号标志 output tx , output done_tx ); parameter TIME = 50_000_000 , bps = 9600 , delay = TIME / bps ; parameter MODE = 0;//0:无校验;1:奇;2:偶;3:校验常为1;4:0; reg [7:0] data_reg; //寄存并行数据,整个工作过程中数据保持不变 reg [12:0] cnt; //一个bit的计数 reg [3:0] cnt_bit; reg tx_reg; //发送寄存器 //reg check_num; //计算校验 localparam IDLE = 5'b00001, //空闲 START = 5'b00010, //开始状态 DATA = 5'b00100, //数据传输状态 CHECK = 5'b01000, //校验核对状态 STOP = 5'b10000; //停止状态 //定义5个状态 //状态寄存器 reg [4:0] c_state,n_state; always@(posedge clk) if(!rst_n) c_state <= IDLE; else c_state<=n_state; //状态切换条件,组合逻辑 always@(*) if(!rst_n) n_state = IDLE; else case(c_state) IDLE :begin if(start_tx) n_state = START; else n_state = c_state; end START:begin if(cnt == delay - 1) n_state = DATA; else n_state = c_state; end DATA :begin if(cnt == delay - 1 && cnt_bit == 8 && MODE != 0) n_state = CHECK; else if(cnt == delay - 1 && cnt_bit == 8 && MODE == 0) n_state = STOP; else n_state = c_state; end CHECK:begin if(cnt == delay - 1) n_state = STOP; else n_state = c_state; end STOP :begin if(cnt == delay - 1) n_state = IDLE; else n_state = c_state; end default:n_state = IDLE; endcase always@(posedge clk) if(!rst_n)begin data_reg <=0; //寄存并行数据,整个工作过程中数据保持不变 cnt <=0; //一个bit的计数 cnt_bit <=0; tx_reg <=1; //初值为1体现为空闲位 end else case(c_state) IDLE :begin if(start_tx) data_reg <=data_tx; //寄存并行数据,整个工作过程中数据保持不变 else data_reg <=data_reg; cnt <=0; //一个bit的计数 cnt_bit <=0; tx_reg <=1; //初值为1体现为空闲位 end START:begin data_reg <=data_reg; //寄存并行数据,整个工作过程中数据保持不变 if(cnt == delay - 1) cnt <=0; //一个bit的计数 else cnt <= cnt + 1; cnt_bit <=0; tx_reg <=0; //初值为0体现为起始位 end DATA :begin data_reg <=data_reg; //寄存并行数据,整个工作过程中数据保持不变 if(cnt == delay - 1) cnt <=0; //一个bit的计数 else cnt <= cnt + 1; if(cnt == delay - 1)begin if(cnt_bit == 8) cnt_bit <=0; //清零消除毛刺 else cnt_bit <= cnt_bit + 1; end else cnt_bit <= cnt_bit; tx_reg <=data_reg[cnt_bit]; //数据位的发送 end CHECK:begin data_reg <=data_reg; //寄存并行数据,整个工作过程中数据保持不变 if(cnt == delay - 1) cnt <=0; //一个bit的计数 else cnt <= cnt + 1; cnt_bit <= 0; case(MODE) 0:tx_reg <=0; //数据位的发送 1:tx_reg <=~^data_reg; //奇校验,同或 2:tx_reg <=^data_reg; //偶校验,异或 3:tx_reg <=1; // 4:tx_reg <=0; // default:tx_reg <=0; //数据位的发送 endcase end STOP :begin data_reg <=0; //寄存并行数据,整个工作过程中数据保持不变 if(cnt == delay - 1) cnt <=0; //一个bit的计数 else cnt <= cnt + 1; cnt_bit <=0; tx_reg <=1; //为1 end default:begin data_reg <=0; //寄存并行数据,整个工作过程中数据保持不变 cnt <=0; //一个bit的计数 cnt_bit <=0; tx_reg <=1; //初值为1体现为空闲位 end endcase assign tx = tx_reg; assign done_tx = (c_state == STOP & cnt == delay - 1)?1:0; endmodulemodule top( input wire clk , input wire rst_n, input wire rx , output wire RTC , output tx , inout wire scl , inout wire sda ); assign RTC = 0; //硬件复位 //rx wire [7:0] data_rx ; wire data_done; //ctrl_w wire start_iic ; wire worr ; wire [7:0] sendnum ; wire [7:0] recvnum ; wire [7:0] data_i_icc; //IIC wire [7:0] data_o_iic; wire done_w ; wire done_nack ; wire done_r ; wire done_iic ; //tx wire done_tx ; //ctrl_r wire [7:0] data_tx ; wire start_tx ; IIC IIC_inst( .clk (clk ), .rst_n (rst_n ), .start_iic (start_iic ), //开始信号,外部模块引入信号 .worr (worr ), //方向信号,用于状态跳转 .sendnum (sendnum ), //单位字节,发送数据量 .recvnum (recvnum ), //接收的数据量 .data_i_icc (data_i_icc), //要发送到rom的数据 .data_o_iic (data_o_iic), //读出的数据 .done_w (done_w ), //写完成信号 .done_r (done_r ), //接收字节完成的信号 .done_iic (done_iic ), //整体工作结束 .done_nack (done_nack ), .scl (scl ), .sda (sda ) ); ctrl_w ctrl_w_inst( .clk (clk ), .rst_n (rst_n ), .data_rx (data_rx ), //并行输出信号,//8+1,奇偶校验位 .data_done (data_done ), //数据完成标志 .done_iic (done_iic ), //数据结束 .done_w (done_w ), //数据更新 .start_iic (start_iic ), //开始信号,外部模块引入信号 .done_nack (done_nack ), .worr (worr ), //方向信号,用于状态跳转 .sendnum (sendnum ), //单位字节,发送数据量 .recvnum (recvnum ), //接收的数据量 .data_i_icc (data_i_icc) //要发送到rom的数据 ); ctrl_r ctrl_r_inst( .clk (clk ), .rst_n (rst_n ), .done_r (done_r ), .data_o_iic (data_o_iic), .done_tx (done_tx ), .done_iic (done_iic ), .data_tx (data_tx ), //并行输入数据 .start_tx (start_tx ) ); tx_check tx_check_inst( .clk (clk ), .rst_n (rst_n ), .data_tx (data_tx ), //并行输入数据 .start_tx (start_tx), //开始信号标志 .tx (tx ), .done_tx (done_tx ) ); rx_check rx_check_inst( .clk (clk ), .rst_n (rst_n ), .rx (rx ), //串行输入信号 .data_rx (data_rx ), //并行输出信号,//8+1,奇偶校验位 .data_done (data_done) //数据完成标志 ); endmodule