蓝桥杯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

七、管脚约束

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

相关推荐
一条九漏鱼4 小时前
Verilog Test Fixture 时钟激励
fpga开发
ThreeYear_s7 小时前
基于FPGA婴儿安全监护系统(蓝牙小程序监测)
fpga开发·小程序
9527华安10 小时前
Altera系列FPGA实现图像视频采集转HDMI/LCD输出,提供4套Quartus工程源码和技术支持
fpga开发·ov5640·quartus·altera
wuqingshun31415911 小时前
蓝桥杯 20. 倍数问题
算法·职场和发展·蓝桥杯·深度优先
1560820721912 小时前
FPGA_Verilog实现QSPI驱动,完成FLASH程序固化
fpga开发
吃个早饭14 小时前
第十六届蓝桥杯大赛软件赛C/C++大学B组部分题解
c语言·c++·蓝桥杯
MVP-curry-萌神15 小时前
FPGA图像处理(四)------ 图像裁剪
图像处理·fpga开发
蓝天扶光16 小时前
蓝桥杯第十六届c组c++题目及个人理解
c++·蓝桥杯
平凡灵感码头16 小时前
基于智能家居项目 RGB彩灯(P9813)
单片机·fpga开发·智能家居