蓝桥杯FPGA赛道第二次模拟题代码

一、顶层文件

复制代码
module test(
input  wire sys_clk,
input  wire sys_rst,
input  wire [3:0]key_in,
output reg  [7:0]led,

output wire scl,
inout  wire sda,//i2c的信号

output wire [7:0]sel,
output wire [7:0]seg//数码管的驱动
);

wire [23:0] data ;
reg  [31:0] dsp_data;
reg  [23:0]	bcd;

wire S1_debounce,S1_debounce_reg;
wire S2_debounce,S2_debounce_reg;
wire S3_debounce,S3_debounce_reg;

localparam KEY1_STATE1=2'b00;//停止状态
localparam KEY1_STATE2=2'b01;//启动状态

localparam KEY2_STATE1=2'b00;
localparam KEY2_STATE2=2'b01;

reg [1:0] key1_state;//当前状态
reg [1:0] key2_state;//当前状态

//显示eeprom读取的数据
always @(posedge sys_clk or negedge sys_rst)begin
	if(!sys_rst)begin
		dsp_data <={4'd11,4'd10,4'd10,4'd10,4'd10,4'd10,4'd10,4'd10};//初始值,表示没有效数字时钟的显示
		led <=8'b11111111;
	end else begin
		if(S1_debounce_reg&&!S1_debounce)begin
	led[0]<=~led[0];
	end 
	
		bcd[7:4]<=data[7:0]/10;
		bcd[3:0]<=data[7:0]%10;
		
		bcd[11:8]<=data[15:8]%10;
		bcd[15:12]<=data[15:8]/10;
		
		bcd[19:16]<=data[23:16]%10;
		bcd[23:20]<=data[23:16]/10;
	  dsp_data<={4'd11,bcd[23:16],4'd10,bcd[15:8],4'd10,bcd[7:4]};
  end 
end 
//按键一的状态
always @(posedge sys_clk or negedge sys_rst)begin
	if(!sys_rst)begin 
	key1_state<=KEY1_STATE1;
	end else begin
	   if(S1_debounce_reg&&!S1_debounce) begin
			key1_state <= (key1_state ==KEY1_STATE1) ? KEY1_STATE2:KEY1_STATE1;
		end
	end 
end 
//检测按键二的状态
always @(posedge sys_clk or negedge sys_rst)begin
	if(!sys_rst)begin 
		key2_state<=KEY2_STATE1;
	end else begin
	   if(S2_debounce_reg&&!S2_debounce) begin
			key2_state <= (key2_state ==KEY2_STATE1) ? KEY2_STATE2:KEY2_STATE1;
		end
	end 
end

wire [23:0] rd_data;
wire  rd_data_vld;
//reg define
reg [23:0] wr_data;
reg  wr_req;
reg  rd_req=0;

//检测写入EEPROM的条件
always @(posedge sys_clk or negedge sys_rst)begin
 if(!sys_rst)begin
	wr_req<=1'b0;
 end 
    else if({key1_state==KEY1_STATE2&&(S1_debounce_reg&&!S1_debounce)}||{key1_state==KEY1_STATE1&&(S2_debounce_reg && !S2_debounce)})begin
		wr_data <=data;
	   wr_req <=1'b1;
 end 
 else 
     wr_req<=1'b0;
 end 
 
reg [3:0] state=0;
reg [15:0] debounce_couter=0;//去抖计数器
reg [15:0] debounce_couter2=0;//去抖计数器

//上电读取eeprom的数据
   always @(posedge sys_clk or negedge sys_rst)begin
	if(!sys_rst) begin
	state <=0;
	rd_req<=0;
	debounce_couter <=16'b0;
	end else begin 
		case(state)
		0:begin
		//状态0:等待读取开始
			state<=1;
		end 
	   1:begin
		//状态1;从EEprom读取数据
		 rd_req<=1;
		 if(debounce_couter<=16'hFFFF)
			debounce_couter <=debounce_couter+1;
		 else
			state <=2;
		   end
		2:begin
		//状态2:数据加载完毕
		//进一步处理逻辑
		rd_req<=0;
		debounce_couter<=16'b0;
		end 
		default:state <=0;
	 endcase
	end
end	
//eeprom module
eeprom inst_eeprom(
 .clk(sys_clk),
 .rst(sys_rst),
 .wr_req(wr_req),
 .rd_req((~key_in[2])||rd_req),//read data from EEProm
 .device_id(),
 .reg_addr(8'h03),
 .reg_addr_vld(1'b1),
 .wr_data(wr_data),
 .wr_data_vld(wr_req),
 .rd_data(rd_data),
 .rd_data_vld(rd_data_vld),
 .ready(),
 .scl(scl),
 .sda(sda)
);
//按键模块
key debounce_L1(
.sys_clk(sys_clk),
.rst(sys_rst),
.key_in(key_in[0]),
.S_debounce(S1_debounce),
.S_debounce_reg(S1_debounce_reg)
);

key debounce_L2(
.sys_clk(sys_clk),
.rst(sys_rst),
.key_in(key_in[1]),
.S_debounce(S2_debounce),
.S_debounce_reg(S2_debounce_reg)
);

key debounce_L3(
.sys_clk(sys_clk),
.rst(sys_rst),
.key_in(key_in[2]),
.S_debounce(S3_debounce),
.S_debounce_reg(S3_debounce_reg)
);
//时间计数模块
counter_time u_couter_time(
.clk(sys_clk),
.rst_n(sys_rst),
.key_in1(S1_debounce_reg &&!S1_debounce),
.key_in2(S2_debounce_reg &&!S2_debounce),
.key_in3(S3_debounce_reg &&!S3_debounce),
.rd_req(rd_req),
.rd_data(rd_data),
.din_out(data)
);
//数码管显示模块
segdisplay segdisplay_inst(
	.clk(sys_clk),
	.rst(sys_rst),
	.dsp_data(dsp_data),
	.seg(seg),
	.sel(sel)
);
endmodule 

二、数码管驱动

复制代码
module segdisplay
(
	input	   wire 		      clk						,
	input 	wire 			   rst						,
	input 	wire	[31:0] 	dsp_data				,
	output 	reg 	[7:0] 	seg					,//段选端
	output 	reg 	[7:0] 	sel					//位选段
);
	
localparam [7:0] DIGIT0 =8'b1100_0000 ;//16精制C0
localparam [7:0] DIGIT1 =8'b1111_1001 ;//F9
localparam [7:0] DIGIT2 =8'b1010_0100;//A4
localparam [7:0] DIGIT3 =8'b1011_0000;//B0
localparam [7:0] DIGIT4 =8'b1001_1001;//99
localparam [7:0] DIGIT5 =8'b1001_0010;//92
localparam [7:0] DIGIT6 =8'b1000_0010;//82
localparam [7:0] DIGIT7 =8'b1111_1000;//F8
localparam [7:0] DIGIT8 =8'b1000_0000;//80
localparam [7:0] DIGIT9 =8'b1001_0000 ;//90
localparam [7:0] DIGITX =8'b1011_1111 ;//
localparam [7:0] DIGOFF =8'b1111_1111 ;//FF
localparam [7:0] DIGITC =8'hC6 ;
localparam 		DSP_COUNT = 20'd50000; //

reg 	[19:0] 	dsp_count		;
reg 	[3:0]	   bits				;
reg 	[3:0]		bcd				;


//1ms的计数器		
always @(posedge clk or negedge rst)begin 	
	if(!rst)
		dsp_count <= 20'd0;
	else begin 
		if (dsp_count == DSP_COUNT-1) begin 
			dsp_count <= 20'd0;
		end else 
			dsp_count <= dsp_count + 20'd1;
		end	
end 		
//位选端	
always @(posedge clk or negedge rst) begin 
	 if(!rst)begin
	   sel <= 8'b1111_1111;
		bits <=4'd0;
	 end else begin 
	    if(dsp_count==DSP_COUNT-1)begin//每一毫秒更新一次
		 if(bits==4'd8)
		    bits <=4'd0;
		 else
			 bits<=bits+4'd1;
		 case(bits)
				 4'd0: begin sel<=8'b1111_1110;bcd<=dsp_data[31:28] ;end
				 4'd1: begin sel<=8'b1111_1101;bcd<=dsp_data[27:24] ;end
				 4'd2: begin sel<=8'b1111_1011;bcd<=dsp_data[23:20] ;end
				 4'd3: begin sel<=8'b1111_0111;bcd<=dsp_data[19:16] ;end
				 4'd4: begin sel<=8'b1110_1111;bcd<=dsp_data[15:12] ;end
				 4'd5: begin sel<=8'b1101_1111;bcd<=dsp_data[11:8] ;end
				 4'd6: begin sel<=8'b1011_1111;bcd<=dsp_data[7:4] ;end
				 4'd7: begin sel<=8'b0111_1111;bcd<=dsp_data[3:0] ;end
		 default:sel<=8'b1111_1111;
	    endcase
	 end 
  end
end 
//段选端
always @(posedge clk or negedge rst)begin
	if(!rst)
		seg<=DIGOFF;
  else begin 
		case(bcd)
			4'd0: seg<=DIGIT0;
			4'd1: seg<=DIGIT1;
			4'd2: seg<=DIGIT2;
			4'd3: seg<=DIGIT3;
			4'd4: seg<=DIGIT4;
			4'd5: seg<=DIGIT5;
			4'd6: seg<=DIGIT6;
			4'd7: seg<=DIGIT7;
			4'd8: seg<=DIGIT8;
			4'd9: seg<=DIGIT9;
			4'd10:seg<=8'b1011_1111;//-
			4'd11:seg<=8'b1000_1100;//p
		default: seg<=DIGOFF;
	endcase
  end 
end 
endmodule		

三、按键驱动

复制代码
module key(
    input   wire                sys_clk,
    input   wire                rst,
    input   wire    [0:0]       key_in,//按键输入信号,假设最多支持4个按键
	 output  reg      [0:0]       S_debounce,//去抖后的按键输出
	 output  reg      [0:0]		  S_debounce_reg //去抖的寄存器输出
);

	reg [15:0] debounce_counter;//去抖计数器
	//按键去抖模块
always @(posedge sys_clk or negedge rst)begin
	if(!rst)begin
		S_debounce<=0;
		S_debounce_reg<=0;
		debounce_counter<=16'b0;
	end else begin
		//针对每个按键经行去抖
		
		if(key_in==1'b0)begin//按键按下
			if(debounce_counter< 16'hFFFF)
				debounce_counter<=debounce_counter+1;
			else
				S_debounce_reg<=1'b1;//该按键去抖确认按下
			end else begin
				debounce_counter<=16'b0;
				S_debounce_reg<=1'b0;//按键松开
			end
		end
		//更新去抖后的按键输出
		S_debounce <=S_debounce_reg;
	end 
endmodule

四、计数器模块

复制代码
module counter_time(
input wire clk,
input wire rst_n,
input wire key_in1,//消抖后的脉冲信号,高有效
input wire key_in2,//消抖后的脉冲信号,高有效
input wire key_in3,//消抖后的脉冲信号,高有效
input wire [23:0]rd_data,
input wire rd_req,
output wire [23:0]din_out//输出当前计数值
);

parameter MAX_1MS=16'd49_999;//1ms
parameter MAX_1S=10'd999;//1ms*1000=1s
parameter MAX_1MIN=6'd59;//1s*60=1min
parameter MAX_1H=6'd59;//1min*60=1h

reg flag;//开始、暂停结束信号
reg [15:0]cnt_1ms;
wire add_cnt_1ms;
wire end_cnt_1ms;

reg [9:0]cnt_1s;
wire add_cnt_1s;
wire end_cnt_1s;

reg [5:0]cnt_1min;
wire add_cnt_1min;
wire end_cnt_1min;

reg [5:0]cnt_1h;
wire add_cnt_1h;
wire end_cnt_1h;

reg [7:0] data_min;//保存此时有多少分钟
reg [7:0] data_s;//保存此时有多少秒
reg [7:0] data_ms;//保存此时有多少毫秒,只取高两位

//flag
always @(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
				flag<=1'b0;
		end
		else if(key_in1) begin
		flag<=~flag;
		end
		else begin
			flag<=flag;
		end
	end 
//1ms计数器
always @(posedge clk or negedge rst_n or posedge key_in2) begin
	if(!rst_n||key_in2)begin
		cnt_1ms<=16'd0;
	end 
	else if(add_cnt_1ms)begin
		if(end_cnt_1ms)begin
			cnt_1ms<=16'd0;
		end 
		else begin
			cnt_1ms<=cnt_1ms+1'b1;
		end
	end 
end 

assign add_cnt_1ms=flag;
assign end_cnt_1ms=add_cnt_1ms&&{cnt_1ms==MAX_1MS};

//1S计数器
always @(posedge clk or negedge rst_n ) begin
	if(!rst_n)begin
		cnt_1s<=10'd0;
	end 
	else if(key_in3||rd_req)begin
	cnt_1s<=rd_data[7:0]*10;
	end
	else if(key_in2)begin
		cnt_1s<=0;
	end
 else if(add_cnt_1s)begin
    if(end_cnt_1s)begin
			cnt_1s<=10'd0;
	 end
	 else begin
			cnt_1s<=cnt_1s+1'b1;
	  end
	end
end 

assign add_cnt_1s=end_cnt_1ms;
assign end_cnt_1s=add_cnt_1s&&cnt_1s==MAX_1S;

//1min计数器
always @(posedge clk or negedge rst_n or posedge key_in2) begin
	if(!rst_n||key_in2)begin
		cnt_1min<=6'd0;
	end 
	else if(key_in3||rd_req)begin
	cnt_1min<=rd_data[23:16];
	end
 else if(add_cnt_1min)begin
    if(end_cnt_1min)begin
			cnt_1min<=6'd0;
	 end
	 else begin
			cnt_1min<=cnt_1min+1'b1;
	  end
	end
end 

assign add_cnt_1min=end_cnt_1s;
assign end_cnt_1min=add_cnt_1min&&cnt_1s==MAX_1MIN;
//1H计数器
always @(posedge clk or negedge rst_n or posedge key_in2) begin
	if(!rst_n||key_in2)begin
		cnt_1h<=6'd0;
	end 
	else if(key_in3||rd_req)begin
	cnt_1h<=rd_data[15:8];
	end
 else if(add_cnt_1h)begin
    if(end_cnt_1h)begin
			cnt_1h<=6'd0;
	 end
	 else begin
			cnt_1h<=cnt_1h+1'b1;
	  end
	end
end 

assign add_cnt_1h=end_cnt_1min;
assign end_cnt_1h=add_cnt_1h&&cnt_1h==MAX_1H;

//数据输出
always @(posedge clk or negedge rst_n)begin 
 if(!rst_n)
 begin
	data_min<=8'd3;
	data_s<=8'd7;
	data_ms<=8'd2;
end  
else 
begin
	data_min<=cnt_1h;
	data_s<=cnt_1min;
	data_ms<=cnt_1s/10;
 end 
end 
assign din_out={data_min,data_s,data_ms};
endmodule

五、I2C驱动

复制代码
module i2c( 
	   input						   clk			,
	   input						   rst		,
   	input       [7:0]   		wr_data 	,
   	input       [4:0]   		cmd     	,
   	input               		cmd_vld 	,
   	output      [7:0]   		rd_data 	,
   	output              		rd_data_vld	,
   	output  reg         		rev_ack 	,
   	output              		done    	,
   	output  reg         		scl     	,
   	inout               		sda      
);

//para define
localparam  IDLE        = 7'b0000001,
            START       = 7'b0000010,
            WR_DATA     = 7'b0000100,
            RD_DATA     = 7'b0001000,
            R_ACK       = 7'b0010000,
            T_ACK       = 7'b0100000,
            STOP        = 7'b1000000;
parameter   T = 100_000,
            SCL_MAX = 50_000_000 / T;
parameter   SCL_LOW_HALF  = (SCL_MAX * 1 / 4) - 1,
            SCL_HIGH_HALF = (SCL_MAX * 3 / 4) - 1;  
`define     START_BIT   5'b00001
`define     WRITE_BIT   5'b00010
`define     READ_BIT    5'b00100
`define     STOP_BIT    5'b01000
`define     ACK_BIT     5'b10000
`define     ACK         0
`define     NO_ACK      1

//reg define
reg	[6:0]	cstate     	;
reg	[6:0]	nstate     	;
reg	[4:0]	cmd_r       ;
reg	[7:0]	wr_data_r   ;
reg	[7:0]	rd_data_r   ;
reg			sda_out     ;
reg			OE          ;
reg	[8:0]	cnt_bit	   	;
reg	[3:0]   num         ;
reg	[3:0]	cnt_num	   	;

//wire define
wire			sda_in      	;
wire			add_cnt_bit		;
wire			end_cnt_bit		; 
wire			add_cnt_num		;
wire			end_cnt_num		;
wire    		IDLE_START      ;
wire    		START_WR_DATA   ;
wire    		WR_DATA_R_ACK   ;
wire    		R_ACK_IDLE      ;
wire    		IDLE_WR_DATA    ;
wire    		R_ACK_STOP      ;
wire    		STOP_IDLE       ;  

wire    		IDLE_RD_DATA    ;
wire    		RD_DATA_T_ACK   ;
wire    		T_ACK_IDLE      ;
wire    		T_ACK_STOP      ;

assign add_cnt_bit = cstate != IDLE;
assign end_cnt_bit = add_cnt_bit && cnt_bit == SCL_MAX - 1'd1;
assign add_cnt_num = end_cnt_bit;
assign end_cnt_num = add_cnt_num && cnt_num == num - 1;

assign  IDLE_START      = (cstate == IDLE)      && cmd_vld      && (cmd & `START_BIT)   	;
assign  START_WR_DATA   = (cstate == START)     && end_cnt_num  && (cmd_r & `WRITE_BIT) 	;
assign  WR_DATA_R_ACK   = (cstate == WR_DATA)   && end_cnt_num                          	;
assign  R_ACK_IDLE      = (cstate == R_ACK)     && end_cnt_num  && !(cmd_r & `STOP_BIT) 	;
assign  IDLE_WR_DATA    = (cstate == IDLE)      && cmd_vld      && (cmd & `WRITE_BIT) 		;
assign  R_ACK_STOP      = (cstate == R_ACK)     && end_cnt_num  && (cmd_r & `STOP_BIT)  	;
assign  STOP_IDLE       = (cstate == STOP)      && end_cnt_num                          	;
assign  IDLE_RD_DATA    = (cstate == IDLE)      && cmd_vld      && (cmd & `READ_BIT)    	;
assign  RD_DATA_T_ACK   = (cstate == RD_DATA)   && end_cnt_num                          	;
assign  T_ACK_IDLE      = (cstate == T_ACK)     && end_cnt_num  && !(cmd_r & `STOP_BIT) 	;
assign  T_ACK_STOP      = (cstate == T_ACK)     && end_cnt_num  && (cmd_r & `STOP_BIT)  	;

assign sda = OE ? sda_out : 1'bz;
assign sda_in = sda;
assign done = R_ACK_IDLE || T_ACK_IDLE || STOP_IDLE;
assign rd_data = rd_data_r;
assign rd_data_vld = T_ACK_IDLE || T_ACK_STOP;

//
always @(posedge clk or negedge rst) begin
	if (!rst) begin
		wr_data_r <= 'd0;
		cmd_r <= 'd0;
		end
	else if (cmd_vld) begin
		wr_data_r <= wr_data;
		cmd_r <= cmd;
		end
end

//
always @(posedge clk or negedge rst) begin 
	if(!rst)begin
		cnt_bit <= 'd0;
		end 
	else if(add_cnt_bit)begin 
		if(end_cnt_bit)begin 
			cnt_bit <= 'd0;
			end
		else begin 
			cnt_bit <= cnt_bit + 1'd1;
			end 
		end
end 
    
	 
//IIC_SCL
always @(posedge clk or negedge rst) begin
	if (!rst) begin
		scl <= 'd1;
		end
	else if (cnt_bit == (SCL_MAX - 1 ) >> 1 || STOP_IDLE) begin
		scl <= 'd1;
		end
	else if (end_cnt_bit) begin
		scl <= 'd0;
	end
end

//
always @(posedge clk or negedge rst)begin 
	if(!rst)begin
		cnt_num <= 'd0;
		end 
	else if(add_cnt_num)begin 
		if(end_cnt_num)begin 
			cnt_num <= 'd0;
			end
		else begin 
			cnt_num <= cnt_num + 1'd1;
		end 
	end
end 
    
//
always @(*) begin
	case (cstate)
		IDLE    : num = 1;
		START   : num = 1;
		WR_DATA : num = 8;
		RD_DATA : num = 8;
		R_ACK   : num = 1;
		T_ACK   : num = 1;
		STOP    : num = 1;
		default : num = 1;
	endcase
end

//
always @(posedge clk or negedge rst)begin 
	if(!rst)begin
		cstate <= IDLE;
		end 
	else begin 
		cstate <= nstate;
		end 
end

//
always @(*) begin
	case(cstate)
		IDLE    : begin
			if (IDLE_START) begin
				nstate = START;
				end
			else if (IDLE_WR_DATA) begin
				nstate = WR_DATA;
				end
			else if (IDLE_RD_DATA) begin
				nstate = RD_DATA;
				end
			else begin
				nstate = cstate;
				end
			end 
		START   : begin
			if (START_WR_DATA) begin
				nstate = WR_DATA;
				end
			else begin
				nstate = cstate;
				end
			end 
		WR_DATA : begin
			if (WR_DATA_R_ACK) begin
				nstate = R_ACK;
				end
			else begin
				nstate = cstate;
				end
			end 
		RD_DATA : begin
			if (RD_DATA_T_ACK) begin
				nstate = T_ACK;
				end
			else begin
				nstate = cstate;
				end
			end 
		R_ACK   : begin
			if (R_ACK_STOP) begin
				nstate = STOP;
				end
			else if (R_ACK_IDLE) begin
				nstate = IDLE;
				end
			else begin
				nstate = cstate;
				end
			end 
		T_ACK   : begin
			if (T_ACK_STOP) begin
				nstate = STOP;
				end
			else if (T_ACK_IDLE) begin
				nstate = IDLE;
				end
			else begin
				nstate = cstate;
				end
			end 
		STOP    : begin
			if (STOP_IDLE) begin
				nstate = IDLE;
				end
			else begin
				nstate = cstate;
				end
			end 
		default : nstate = cstate;
	endcase
end

//
always @(posedge clk or negedge rst) begin
	if (!rst) begin
		OE <= 'b0;
		end else if (IDLE_START || START_WR_DATA || IDLE_WR_DATA || R_ACK_STOP || RD_DATA_T_ACK) begin
		OE <= 'b1;
		end else if (IDLE_RD_DATA || WR_DATA_R_ACK || STOP_IDLE) begin
		OE <= 'b0;
	end
end

//
always @(posedge clk or negedge rst) begin
	if (!rst) begin
		sda_out <= 1;
		end
	else begin
		case (cstate)
			IDLE    :sda_out <= 1;
			START   :begin
				if (cnt_bit == SCL_LOW_HALF) begin
					sda_out <= 'b1;
					end
				else if (cnt_bit == SCL_HIGH_HALF) begin
					sda_out <= 'b0;
					end
				end
			WR_DATA :begin
				if (cnt_bit == SCL_LOW_HALF) begin
					sda_out <= wr_data_r[7 - cnt_num];
					end
				end
			T_ACK   :begin
				if (cnt_bit == SCL_LOW_HALF) begin
					if (cmd & `ACK_BIT) begin
						sda_out <= `NO_ACK;
						end
					else begin
						sda_out <= `ACK;
						end
					end
				end
			STOP    :begin
				if (cnt_bit == SCL_LOW_HALF) begin
					sda_out <= 'b0;
					end
				else if (cnt_bit == SCL_HIGH_HALF) begin
					sda_out <= 'b1;
					end
				end
			default: sda_out <= 'b1;
		endcase
	end
end

//
always @(posedge clk or negedge rst) begin
	if (!rst) begin
		rev_ack <= 0;
		rd_data_r <= 8'b0;
		end
	else begin
		case (cstate)
			RD_DATA:begin
				if (cnt_bit == SCL_HIGH_HALF) begin
					rd_data_r[7-cnt_num] <= sda_in;
					end
				end
			R_ACK  :begin
				if (cnt_bit == SCL_HIGH_HALF) begin
					rev_ack <= sda_in;
					end
				end
			default:; 
		endcase
	end
end


endmodule

六、eeprom模块

复制代码
module eeprom ( 
	input	wire					clk		    ,
	input	wire			        rst	    ,
	input   wire                   	wr_req      ,
	input   wire                    rd_req      ,

	input   wire   [6:0]            device_id   ,
	input   wire   [7:0]  			reg_addr    ,
	input   wire                    reg_addr_vld,
	
	input   wire   [7:0]    		wr_data     ,
	input   wire                    wr_data_vld ,
    
	output  wire   [7:0]            rd_data     ,
	output  wire                    rd_data_vld ,
	output  wire                    ready       ,
	
	output  wire                    scl         ,
	inout   wire                    sda         
);								 

//para define
`define     	START_BIT   5'b00001
`define     	WRITE_BIT   5'b00010
`define     	READ_BIT    5'b00100
`define     	STOP_BIT    5'b01000
`define     	ACK_BIT     5'b10000
localparam  	IDLE     = 6'b000001,
				WR_REQ   = 6'b000010,
				WR_WAIT  = 6'b000100,
				RD_REQ   = 6'b001000,
				RD_WAIT  = 6'b010000,
				DONE     = 6'b100000;
				
localparam 		WR_CTRL_BYTE = 8'b1010_0000;
localparam  	RD_CTRL_BYTE = 8'b1010_0001;

//wire define
wire    IDLE_WR_REQ     ;
wire    IDLE_RD_REQ     ;
wire    WR_REQ_WR_WAIT  ;
wire    RD_REQ_RD_WAIT  ;
wire    WR_WAIT_WR_REQ  ;
wire    WR_WAIT_DONE    ;
wire    RD_WAIT_RD_REQ  ;
wire    RD_WAIT_DONE    ;
wire    DONE_IDLE       ;
wire	done            ;
wire	add_cnt_byte	;
wire	end_cnt_byte	;

//reg define
reg	[5:0]	cstate     		;
reg	[5:0]	nstate     		;
reg	[2:0]	num             ;
reg	[4:0]	cmd             ;
reg			cmd_vld         ;
reg	[7:0]	op_wr_data      ;
reg	[15:0]	addr_r          ;
reg	[7:0]	wr_data_r       ;
reg	[2:0]	cnt_byte	   	;
reg			wr_req_r		;
reg			rd_req_r		;

assign add_cnt_byte = done;
assign end_cnt_byte = add_cnt_byte && cnt_byte == num - 1;
assign IDLE_WR_REQ    = (cstate == IDLE)    && wr_req_r;
assign IDLE_RD_REQ    = (cstate == IDLE)    && rd_req_r;
assign WR_REQ_WR_WAIT = (cstate == WR_REQ)  && 1;
assign RD_REQ_RD_WAIT = (cstate == RD_REQ)  && 1;
assign WR_WAIT_WR_REQ = (cstate == WR_WAIT) && done;
assign WR_WAIT_DONE   = (cstate == WR_WAIT) && end_cnt_byte;
assign RD_WAIT_RD_REQ = (cstate == RD_WAIT) && done;
assign RD_WAIT_DONE   = (cstate == RD_WAIT) && end_cnt_byte;
assign DONE_IDLE      = (cstate == DONE)    && 1;
assign ready = cstate == IDLE;         

//
always @(posedge clk or negedge rst) begin
	if (!rst) begin
		wr_req_r <=0;
		rd_req_r <= 0;
		end
	else begin
		wr_req_r <= wr_req;
		rd_req_r <= rd_req;
	end
end
    
//
always @(posedge clk or negedge rst) begin
	if (!rst) begin
		addr_r <= 'd0;
		end
	else if (reg_addr_vld) begin
		addr_r <= reg_addr;
	end
end

//
always @(posedge clk or negedge rst) begin
	if (!rst) begin
		wr_data_r <= 'd0;
		end
	else if (wr_req) begin
		wr_data_r <= wr_data;
	end
end

//
always @(posedge clk or negedge rst)begin 
	if(!rst)begin
		cnt_byte <= 'd0;
		end 
	else if(add_cnt_byte)begin 
		if(end_cnt_byte)begin 
			cnt_byte <= 'd0;
			end
		else begin 
			cnt_byte <= cnt_byte + 1'd1;
			end 
	end
end 
    
    
//
always @(posedge clk or negedge rst) begin
	if (!rst) begin
		num <= 1;
		end
	else if (wr_req) begin
		num <= 4;
		end
	else if (rd_req) begin
		num <= 5;
		end
	else if (end_cnt_byte) begin
		num <= 1;
		end
end
  
//
always @(posedge clk or negedge rst)begin 
	if(!rst)begin
		cstate <= IDLE;
		end 
	else begin 
		cstate <= nstate;
		end 
end
    
//
always @(*) begin
	case(cstate)
		IDLE    :begin
			if (IDLE_WR_REQ) begin
				nstate = WR_REQ;
				end
			else if (IDLE_RD_REQ) begin
				nstate = RD_REQ;
				end
			else begin
				nstate = cstate;
				end
			end 
		WR_REQ  :begin
			if (WR_REQ_WR_WAIT) begin
				nstate = WR_WAIT;
				end
			else begin
				nstate = cstate;
				end
			end 
		WR_WAIT :begin
			if (WR_WAIT_DONE) begin
				nstate = DONE;
				end
			else if (WR_WAIT_WR_REQ) begin
				nstate = WR_REQ;
				end
			else begin
				nstate = cstate;
				end
			end 
		RD_REQ  :begin
			if (RD_REQ_RD_WAIT) begin
				nstate = RD_WAIT;
				end
			else begin
				nstate = cstate;
				end
			end 
		RD_WAIT :begin
			if (RD_WAIT_DONE) begin
				nstate = DONE;
				end
			else if (RD_WAIT_RD_REQ) begin
				nstate = RD_REQ;
				end
			else begin
				nstate = cstate;
				end
			end 
		DONE    :begin
			if (DONE_IDLE) begin
				nstate = IDLE;
				end
			else begin
				nstate = cstate;
				end
			end 
		default : nstate = cstate;
	endcase
end

//                
always @(posedge clk or negedge rst) begin
	if (!rst) begin
		TX(0,4'h0,8'h00);
		end
	else begin
		case (cstate)
			RD_REQ:begin
				case (cnt_byte)
					0   :  TX(1,(`START_BIT | `WRITE_BIT),WR_CTRL_BYTE);
					1   :  TX(1,(`WRITE_BIT             ),addr_r[15:8]);
					2   :  TX(1,(`WRITE_BIT             ),addr_r[7:0] );
					3   :  TX(1,(`START_BIT | `WRITE_BIT),RD_CTRL_BYTE);
					4   :  TX(1,(`READ_BIT  | `STOP_BIT ),8'h00       );
					default: TX(0,cmd,op_wr_data);
				endcase
				end
			WR_REQ:begin
				case (cnt_byte)
					0   :  TX(1,(`START_BIT | `WRITE_BIT),WR_CTRL_BYTE);
					1   :  TX(1,(`WRITE_BIT             ),addr_r[15:8]);
					2   :  TX(1,(`WRITE_BIT             ),addr_r[7:0] );
					3   :  TX(1,(`WRITE_BIT | `STOP_BIT ),wr_data_r   );
					default: TX(0,cmd,op_wr_data);
				endcase
				end
			default: TX(0,cmd,op_wr_data);
		endcase
	end
end

i2c inst_i2c(
	.clk		 (clk),
	.rst	     (rst),
	.wr_data     (op_wr_data),
	.cmd         (cmd),
	.cmd_vld     (cmd_vld),
	.rd_data     (rd_data),
	.rd_data_vld (rd_data_vld),
	.done        (done),
	.scl         (scl),
	.sda         (sda)
    );
	 
task TX;
	input           task_cmd_vld    ;
	input   [3:0]   task_cmd        ;
	input   [7:0]   task_wr_data    ;
	begin
		cmd_vld     = task_cmd_vld  ;
		cmd         = task_cmd      ;
		op_wr_data  = task_wr_data  ;
	end
endtask

endmodule

七、管脚约束

声明: 本代码借鉴网络资料,如有侵权请联系作者删除,如有错误请在评论区或者私信作者纠正。

相关推荐
仲南音15 小时前
Xilinx FPGA——时钟IP核MMCM、PLL
fpga开发
I'm a winner1 天前
基于Xilinx FPGA的LVDS高速串行通信系统(三)--数据训练及握手机制【文末源码】
fpga开发
upper20201 天前
coremark移植坑之-nostartfiles -nostdlib参数
学习·fpga开发·coremark移植·riscv设计
Eloudy2 天前
Vivado 纯命令行构建 FPGA 项目教程
fpga开发
Rambo.xia2 天前
AXI跨时钟域与数据一致性——CDC FIFO深度不够、写后读冒险、多Master仲裁、乱序返回,出了Bug根本查不出来
fpga开发·bug
upper20202 天前
FPGA部署卷积神经网络识别MINST图片
fpga开发·卷积神经网络·minst·minst识别·部署神经网络·神经网络识别图片
你是我的解忧王子2 天前
嵌入式 ADC采样 原始数据分析上层(平均值 波动率 正态分布 线性补偿 系统误差)
fpga开发·数据挖掘·数据分析
9527华安3 天前
FPGA纯verilog代码ISP图像处理培训教程,基于IMX214,提供工程源码+视频教程+FPGA开发板
图像处理·fpga开发·isp·imx214·mipi
千寻xun3 天前
二、实战篇-NVME SSD控制之ZYNQ实现(六)-读写NVME SSD硬盘数据
fpga开发·nvme·nvme ssd
千寻xun3 天前
二、实战篇-NVME SSD控制之ZYNQ实现(三)
fpga开发·nvme ssd·nvme协议