37_AC620开发板串行序列机IIC协议接口RTC时钟芯片PCF8563,时钟显示

一、I2C协议
I2C集成电路总线是一种串行通信总线,使用多主从架构,由飞利浦1980年设计,一般用在小数量场合,传输距离短。
在物理层面I2C接口需要两条总线线路,即SCL(串行时钟线)、SDA(串行数据线),I2C是半双工,任意时刻只有一个主机,每个I2C从机器件都有唯一一个器件地址。传输速率100Kb/s,快速模式可达到400kb/s,高速模式达3.4Mbit/s,
I2C协议规定
37_AC620开发板串行序列机IIC协议接口RTC时钟芯片PCF8563,时钟显示_第1张图片
时钟线路SCL低电平期间,数据线SDA发生改变
时钟线路SCL高电平期间,数据线SDA数据保持
37_AC620开发板串行序列机IIC协议接口RTC时钟芯片PCF8563,时钟显示_第2张图片

时钟线路SCL高电平期间,数据线SDA高低跳变,起始信号
时钟线路SCL高电平期间,数据线SDA低高跳变,停止信号
37_AC620开发板串行序列机IIC协议接口RTC时钟芯片PCF8563,时钟显示_第3张图片
37_AC620开发板串行序列机IIC协议接口RTC时钟芯片PCF8563,时钟显示_第4张图片

应答,当主机把8位数据或者命令送出后,会将数据总线SDA释放,即设置为输入,等待从机应答(低电平0表示应答1表示非应答
数据帧格式:
IIC器件通讯的时候,首先发送“起始信号”,紧跟着七位器件地址,第位为传输方向(0表示写,1表示读),接着等待从机的应答信号,等传输结束,结束信号由主机产生。

发送数据时,应在SCL变高之前数据就已经准备好了

二、SPI通讯RTC芯片PCF8563
AC620板子上的RTC芯片 PCF8563驱动程序,使用IIC读写数据,将时间显示在数码管上。
原理图
37_AC620开发板串行序列机IIC协议接口RTC时钟芯片PCF8563,时钟显示_第5张图片
37_AC620开发板串行序列机IIC协议接口RTC时钟芯片PCF8563,时钟显示_第6张图片

37_AC620开发板串行序列机IIC协议接口RTC时钟芯片PCF8563,时钟显示_第7张图片

顶层都文件Clcok_PCF8563_top.v

/*使用说明
	1、下载sof程序,数码管默认显示从PCF8563中读取到的时间信息
	2、按下按键S1,切换到显示日期数据上,释放S1切回显示时间
	3、按下按键S0,将预设时间(2019.01.01.01 12:00:00)写入PCF8563
*/

module Clcok_PCF8563_top(
	Clk,				//系统时钟输出 50Mhz
	Rst_n,			//复位按键输入
	Key,				//按键输入

	i2c_sclk,		//I2C的时钟管脚
	i2c_sdat,		//I2C的数据管脚
	
	SH_CP,			//数码管显示需要
	ST_CP,			//数码管显示需要
	DS					//数码管显示需要
); 

	input Clk;
	input Rst_n;
	input [1:0]Key;			//双按键,一个按键控制需要输入的初始化时钟和日期,一个按键控制显示日期/时间
	
	output i2c_sclk;			//输出时钟
	inout i2c_sdat;			//双向口数据线
	
	output SH_CP;				//shift clock
	output ST_CP;				//latch data clock
	output DS;					//shift serial data
	
	wire Set_Time;				//按下写入预定时间
	wire [23:0]Time_to_Set;		//需要写入的时间
	wire Set_Date;				//按下写入预设日期
	wire [31:0]Date_to_Set;		//需要写入的日期
	wire Read;
	wire [23:0]Time_Read;		//从RTC中读取的时间信息
	wire [31:0]Date_Read;		//从RTC中读取的日期信息
	
	wire Cmd_Done;
	wire key_flag;					// 按键状态
	wire key_state;				//	按键状态
	
	//PCF8563驱动
	PCF8563 PCF8563(
		.Clk(Clk),
		.Rst_n(Rst_n),		
		.Set_Time(Set_Time),
		.Time_to_Set(Time_to_Set),
		.Set_Date(Set_Date),
		.Date_to_Set(Date_to_Set),
		.Read(Read),
		.Time_Read(Time_Read),
		.Date_Read(Date_Read),
		.Cmd_Done(Cmd_Done),
		.i2c_sclk(i2c_sclk),
		.i2c_sdat(i2c_sdat)
	);
	
	//独立按键消抖模块
	key_filter key_filter0(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.key_in(Key[0]),
		.key_flag(key_flag),
		.key_state(key_state)
	);
	
	//数码管显示驱动
	wire [31:0]disp_data;
	HEX_top HEX_top(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.disp_data(disp_data),
		.SH_CP(SH_CP),
		.ST_CP(ST_CP),
		.DS(DS)
	);
	
	assign Set_Time = key_flag & (!key_state);	//按下写入预设时间
	assign Set_Date = key_flag & (key_state);		//释放写入预设日期
	
	assign Time_to_Set = 24'h08_30_00;	//时间为08:30:00
	assign Date_to_Set = 32'h92_09_03_16;	//92年09月周三16日
	
	wire [31:0]Time_to_Disp;	//需要送到数码管上显示的带格式的时间数据
	wire [31:0]Date_to_Disp;	//需要送到数码管上显示的带格式的日期数据
	
	assign Time_to_Disp = {Time_Read[23:16], 4'hf, Time_Read[15:8], 4'hf, Time_Read[7:0]};	//f对应显示-
	assign Date_to_Disp = {8'h19,Date_Read[31:24],Date_Read[23:16],Date_Read[7:0]};
	
	//按下按键1可以切换到显示日期
	assign disp_data = Key[1]? Time_to_Disp : Date_to_Disp;

	//设定一个定时器,大概每20ms读取一次PCF8563的日期和时间寄存器	
	reg [19:0]cnt;
	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		cnt <= 0;
	else
		cnt <= cnt + 1'b1;
		
	assign Read = (cnt == 20'hfffff);
	
endmodule

RTC芯片PCF8563模块
PCF8563.v

module PCF8563(
	Clk,
	Rst_n,
	
	Set_Time,
	Time_to_Set,

	
	Set_Date,
	Date_to_Set,
	
	Read,
	Time_Read,
	Date_Read,
	
	Cmd_Done,
	
	i2c_sclk,
	i2c_sdat
);


	input Clk;
	input Rst_n;

	input Set_Time;
	input [23:0]Time_to_Set;

	input Set_Date;
	input [31:0]Date_to_Set;

	input Read;
	output reg[23:0]Time_Read;
	output reg[31:0]Date_Read;
	
	output reg Cmd_Done;
	
	output i2c_sclk;
	inout i2c_sdat;
	
	localparam PCF8563_Address_Control_Status_1 = 8'h00;  //控制/状态寄存器1
	localparam PCF8563_Address_Control_Status_2 = 8'h01;  //控制/状态寄存器2
	localparam PCF8563_Address_CLKOUT    = 8'h0d;  //CLKOUT频率寄存器
	localparam PCF8563_Address_Timer     = 8'h0e;  //定时器控制寄存器
	localparam PCF8563_Address_Timer_VAL = 8'h0f;  //定时器倒计数寄存器

	localparam PCF8563_Address_Years     = 8'h08;  //年
	localparam PCF8563_Address_Months    = 8'h07;  //月
	localparam PCF8563_Address_Days      = 8'h05;  //日
	localparam PCF8563_Address_WeekDays  = 8'h06;  //星期
	localparam PCF8563_Address_Hours     = 8'h04;  //小时
	localparam PCF8563_Address_Minutes   = 8'h03;  //分钟
	localparam PCF8563_Address_Seconds   = 8'h02;  //秒

	localparam PCF8563_Alarm_Minutes     = 8'h09;  //分钟报警
	localparam PCF8563_Alarm_Hours       = 8'h0a;  //小时报警
	localparam PCF8563_Alarm_Days        = 8'h0b;  //日报警
	localparam PCF8563_Alarm_WeekDays    = 8'h0c;  //星期报警
	
	reg wrreg_req, rdreg_req;
	reg [7:0]addr,wrdata;
	wire RW_Done;
	wire [7:0]rddata;
	
	i2c_control i2c_control(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.wrreg_req(wrreg_req),
		.rdreg_req(rdreg_req),
		.addr(addr),
		.addr_mode(0),
		.wrdata(wrdata),
		.rddata(rddata),
		.device_id(8'ha2),
		.RW_Done(RW_Done),
		.ack(),		
		.i2c_sclk(i2c_sclk),
		.i2c_sdat(i2c_sdat)
	);
	
	reg [8:0]state;
	reg [3:0]cnt;
	
	localparam
		IDLE = 9'b000000001,
		SET_RTC_TIME = 9'b000000010,
		WAIT_TIME_SET_DONE = 9'b000000100,
		SET_RTC_DATE = 9'b000001000,
		WAIT_DATE_SET_DONE = 9'b000010000,
		READ_RTC = 9'b000100000,
		WAIT_RTC_READ_DONE = 9'b001000000,
		INIT_RTC = 9'b010000000,
		WAIT_RTC_INIT_DONE = 9'b100000000;
	
	reg init_state;
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)begin
		state <= IDLE;
		cnt <= 0;
		Cmd_Done <= 1'b0;
		wrreg_req <= 1'b0;
		rdreg_req <= 1'b0;
		init_state <= 0;
	end
	else begin
		case(state)
			IDLE:
				begin
					Cmd_Done <= 1'b0;
					wrreg_req <= 1'b0;
					rdreg_req <= 1'b0;
					cnt <= 0;
					if(!init_state)
						state <= INIT_RTC;
					else if(Set_Time)
						state <= SET_RTC_TIME;
					else if(Set_Date)
						state <= SET_RTC_DATE;
					else if(Read)
						state <= READ_RTC;
				end
					
			SET_RTC_TIME:
				begin
					state <= WAIT_TIME_SET_DONE;
					case(cnt)
						0:write_reg(PCF8563_Address_Seconds, Time_to_Set[7:0]);
						1:write_reg(PCF8563_Address_Minutes, Time_to_Set[15:8]);
						2:write_reg(PCF8563_Address_Hours, Time_to_Set[23:16]);
						default:;
					endcase
				end
				
			WAIT_TIME_SET_DONE:
				begin
					wrreg_req <= 1'b0;
					if(RW_Done)begin
						if(cnt < 2)begin
							cnt <= cnt + 1'b1;
							state <= SET_RTC_TIME;
						end
						else begin
							cnt <= 0;
							Cmd_Done <= 1'b1;
							state <= IDLE;
						end
					end
					else
						state <= WAIT_TIME_SET_DONE;
				end
				
			SET_RTC_DATE:
				begin
					state <= WAIT_DATE_SET_DONE;
					case(cnt)
						0:write_reg(PCF8563_Address_Days, Date_to_Set[7:0]);
						1:write_reg(PCF8563_Address_WeekDays, Date_to_Set[15:8]);
						2:write_reg(PCF8563_Address_Months, Date_to_Set[23:16]);
						3:write_reg(PCF8563_Address_Years, Date_to_Set[31:24]);
						default:;
					endcase
				end
				
			WAIT_DATE_SET_DONE:
				begin
					wrreg_req <= 1'b0;
					if(RW_Done)begin
						if(cnt < 3)begin
							cnt <= cnt + 1'b1;
							state <= SET_RTC_DATE;
						end
						else begin
							cnt <= 0;
							Cmd_Done <= 1'b1;
							state <= IDLE;
						end
					end
					else
						state <= WAIT_DATE_SET_DONE;
				end
				
			READ_RTC:
				begin
				state <= WAIT_RTC_READ_DONE;
					case(cnt)
						0:read_reg(PCF8563_Address_Days);
						1:read_reg(PCF8563_Address_WeekDays);
						2:read_reg(PCF8563_Address_Months);
						3:read_reg(PCF8563_Address_Years);
						4:read_reg(PCF8563_Address_Seconds);
						5:read_reg(PCF8563_Address_Minutes);
						6:read_reg(PCF8563_Address_Hours);
						default:;
					endcase
				end
			
			WAIT_RTC_READ_DONE:
				begin
					rdreg_req <= 1'b0;
					if(RW_Done)begin
						case(cnt)
							0:Date_Read[7:0] <= rddata;
							1:Date_Read[15:8] <= rddata;
							2:Date_Read[23:16] <= rddata;
							3:Date_Read[31:24] <= rddata;
							4:Time_Read[7:0] <= rddata;
							5:Time_Read[15:8] <= rddata;
							6:Time_Read[23:16] <= rddata;
							default:;
						endcase
						if(cnt < 6)begin
							cnt <= cnt + 1'b1;
							state <= READ_RTC;
						end
						else begin
							cnt <= 0;
							Cmd_Done <= 1'b1;
							state <= IDLE;
						end
					end
					else
						state <= WAIT_RTC_READ_DONE;
				end
			
			INIT_RTC:
				begin
					write_reg(PCF8563_Address_Control_Status_1, 0);
					state <= WAIT_RTC_INIT_DONE;
					
				end
				
			WAIT_RTC_INIT_DONE:
				begin
					wrreg_req <= 1'b0;
					if(RW_Done)begin
						state <= IDLE;
						init_state <= 1;
					end
					else
						state <= WAIT_RTC_INIT_DONE;
				end
			
			default:;
		endcase
	end
	
	task write_reg;
		input [7:0]reg_addr;
		input [7:0]reg_data;
		begin
			wrreg_req <= 1'b1;
			addr = reg_addr;
			wrdata = reg_data;
		end
	endtask
	
	task read_reg;
		input [7:0]reg_addr;
		begin
			rdreg_req <= 1'b1;
			addr = reg_addr;
		end
	endtask
	


endmodule

PCF8563.v

module PCF8563(
	Clk,
	Rst_n,
	
	Set_Time,
	Time_to_Set,

	
	Set_Date,
	Date_to_Set,
	
	Read,
	Time_Read,
	Date_Read,
	
	Cmd_Done,
	
	i2c_sclk,
	i2c_sdat
);


	input Clk;
	input Rst_n;

	input Set_Time;
	input [23:0]Time_to_Set;

	input Set_Date;
	input [31:0]Date_to_Set;

	input Read;
	output reg[23:0]Time_Read;
	output reg[31:0]Date_Read;
	
	output reg Cmd_Done;
	
	output i2c_sclk;
	inout i2c_sdat;
	
	localparam PCF8563_Address_Control_Status_1 = 8'h00;  //控制/状态寄存器1
	localparam PCF8563_Address_Control_Status_2 = 8'h01;  //控制/状态寄存器2
	localparam PCF8563_Address_CLKOUT    = 8'h0d;  //CLKOUT频率寄存器
	localparam PCF8563_Address_Timer     = 8'h0e;  //定时器控制寄存器
	localparam PCF8563_Address_Timer_VAL = 8'h0f;  //定时器倒计数寄存器

	localparam PCF8563_Address_Years     = 8'h08;  //年
	localparam PCF8563_Address_Months    = 8'h07;  //月
	localparam PCF8563_Address_Days      = 8'h05;  //日
	localparam PCF8563_Address_WeekDays  = 8'h06;  //星期
	localparam PCF8563_Address_Hours     = 8'h04;  //小时
	localparam PCF8563_Address_Minutes   = 8'h03;  //分钟
	localparam PCF8563_Address_Seconds   = 8'h02;  //秒

	localparam PCF8563_Alarm_Minutes     = 8'h09;  //分钟报警
	localparam PCF8563_Alarm_Hours       = 8'h0a;  //小时报警
	localparam PCF8563_Alarm_Days        = 8'h0b;  //日报警
	localparam PCF8563_Alarm_WeekDays    = 8'h0c;  //星期报警
	
	reg wrreg_req, rdreg_req;
	reg [7:0]addr,wrdata;
	wire RW_Done;
	wire [7:0]rddata;
	
	i2c_control i2c_control(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.wrreg_req(wrreg_req),
		.rdreg_req(rdreg_req),
		.addr(addr),
		.addr_mode(0),
		.wrdata(wrdata),
		.rddata(rddata),
		.device_id(8'ha2),
		.RW_Done(RW_Done),
		.ack(),		
		.i2c_sclk(i2c_sclk),
		.i2c_sdat(i2c_sdat)
	);
	
	reg [8:0]state;
	reg [3:0]cnt;
	
	localparam
		IDLE = 9'b000000001,
		SET_RTC_TIME = 9'b000000010,
		WAIT_TIME_SET_DONE = 9'b000000100,
		SET_RTC_DATE = 9'b000001000,
		WAIT_DATE_SET_DONE = 9'b000010000,
		READ_RTC = 9'b000100000,
		WAIT_RTC_READ_DONE = 9'b001000000,
		INIT_RTC = 9'b010000000,
		WAIT_RTC_INIT_DONE = 9'b100000000;
	
	reg init_state;
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)begin
		state <= IDLE;
		cnt <= 0;
		Cmd_Done <= 1'b0;
		wrreg_req <= 1'b0;
		rdreg_req <= 1'b0;
		init_state <= 0;
	end
	else begin
		case(state)
			IDLE:
				begin
					Cmd_Done <= 1'b0;
					wrreg_req <= 1'b0;
					rdreg_req <= 1'b0;
					cnt <= 0;
					if(!init_state)
						state <= INIT_RTC;
					else if(Set_Time)
						state <= SET_RTC_TIME;
					else if(Set_Date)
						state <= SET_RTC_DATE;
					else if(Read)
						state <= READ_RTC;
				end
					
			SET_RTC_TIME:
				begin
					state <= WAIT_TIME_SET_DONE;
					case(cnt)
						0:write_reg(PCF8563_Address_Seconds, Time_to_Set[7:0]);
						1:write_reg(PCF8563_Address_Minutes, Time_to_Set[15:8]);
						2:write_reg(PCF8563_Address_Hours, Time_to_Set[23:16]);
						default:;
					endcase
				end
				
			WAIT_TIME_SET_DONE:
				begin
					wrreg_req <= 1'b0;
					if(RW_Done)begin
						if(cnt < 2)begin
							cnt <= cnt + 1'b1;
							state <= SET_RTC_TIME;
						end
						else begin
							cnt <= 0;
							Cmd_Done <= 1'b1;
							state <= IDLE;
						end
					end
					else
						state <= WAIT_TIME_SET_DONE;
				end
				
			SET_RTC_DATE:
				begin
					state <= WAIT_DATE_SET_DONE;
					case(cnt)
						0:write_reg(PCF8563_Address_Days, Date_to_Set[7:0]);
						1:write_reg(PCF8563_Address_WeekDays, Date_to_Set[15:8]);
						2:write_reg(PCF8563_Address_Months, Date_to_Set[23:16]);
						3:write_reg(PCF8563_Address_Years, Date_to_Set[31:24]);
						default:;
					endcase
				end
				
			WAIT_DATE_SET_DONE:
				begin
					wrreg_req <= 1'b0;
					if(RW_Done)begin
						if(cnt < 3)begin
							cnt <= cnt + 1'b1;
							state <= SET_RTC_DATE;
						end
						else begin
							cnt <= 0;
							Cmd_Done <= 1'b1;
							state <= IDLE;
						end
					end
					else
						state <= WAIT_DATE_SET_DONE;
				end
				
			READ_RTC:
				begin
				state <= WAIT_RTC_READ_DONE;
					case(cnt)
						0:read_reg(PCF8563_Address_Days);
						1:read_reg(PCF8563_Address_WeekDays);
						2:read_reg(PCF8563_Address_Months);
						3:read_reg(PCF8563_Address_Years);
						4:read_reg(PCF8563_Address_Seconds);
						5:read_reg(PCF8563_Address_Minutes);
						6:read_reg(PCF8563_Address_Hours);
						default:;
					endcase
				end
			
			WAIT_RTC_READ_DONE:
				begin
					rdreg_req <= 1'b0;
					if(RW_Done)begin
						case(cnt)
							0:Date_Read[7:0] <= rddata;
							1:Date_Read[15:8] <= rddata;
							2:Date_Read[23:16] <= rddata;
							3:Date_Read[31:24] <= rddata;
							4:Time_Read[7:0] <= rddata;
							5:Time_Read[15:8] <= rddata;
							6:Time_Read[23:16] <= rddata;
							default:;
						endcase
						if(cnt < 6)begin
							cnt <= cnt + 1'b1;
							state <= READ_RTC;
						end
						else begin
							cnt <= 0;
							Cmd_Done <= 1'b1;
							state <= IDLE;
						end
					end
					else
						state <= WAIT_RTC_READ_DONE;
				end
			
			INIT_RTC:
				begin
					write_reg(PCF8563_Address_Control_Status_1, 0);
					state <= WAIT_RTC_INIT_DONE;
					
				end
				
			WAIT_RTC_INIT_DONE:
				begin
					wrreg_req <= 1'b0;
					if(RW_Done)begin
						state <= IDLE;
						init_state <= 1;
					end
					else
						state <= WAIT_RTC_INIT_DONE;
				end
			
			default:;
		endcase
	end
	
	task write_reg;
		input [7:0]reg_addr;
		input [7:0]reg_data;
		begin
			wrreg_req <= 1'b1;
			addr = reg_addr;
			wrdata = reg_data;
		end
	endtask
	
	task read_reg;
		input [7:0]reg_addr;
		begin
			rdreg_req <= 1'b1;
			addr = reg_addr;
		end
	endtask
	


endmodule

IIC控制模块
i2c_control.v

module i2c_control(
	Clk,
	Rst_n,
	
	wrreg_req,
	rdreg_req,
	addr,
	addr_mode,
	wrdata,
	rddata,
	device_id,
	RW_Done,
	
	ack,
	
	i2c_sclk,
	i2c_sdat
);

	input Clk;
	input Rst_n;
	
	input wrreg_req;
	input rdreg_req;
	input [15:0]addr;
	input addr_mode;
	input [7:0]wrdata;
	output reg[7:0]rddata;
	input [7:0]device_id;
	output reg RW_Done;
	
	output reg ack;

	output i2c_sclk;
	inout i2c_sdat;
	
	reg [5:0]Cmd;
	reg [7:0]Tx_DATA;
	wire Trans_Done;
	wire ack_o;
	reg Go;
	wire [15:0]reg_addr;
	
	wire [7:0]Rx_DATA;
	
	localparam 
		WR =  6'b000001,	// 写请求
		STA = 6'b000010,	//起始位请求
		RD =  6'b000100,	//读请求
		STO = 6'b001000,	//停止位请求
		ACK = 6'b010000,	//应答位请求
		NACK = 6'b100000;	//无应答请求
	
	i2c_bit_shift i2c_bit_shift(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.Cmd(Cmd),
		.Go(Go),
		.Rx_DATA(Rx_DATA),
		.Tx_DATA(Tx_DATA),
		.Trans_Done(Trans_Done),
		.ack_o(ack_o),
		.i2c_sclk(i2c_sclk),
		.i2c_sdat(i2c_sdat)
	);
	
	reg [6:0]state;
	reg [7:0]cnt;
	
	localparam
		IDLE = 7'b0000001,
		WR_REG = 7'b0000010,
		WAIT_WR_DONE = 7'b0000100,
		WR_REG_DONE = 7'b0001000,
		RD_REG = 7'b0010000,
		WAIT_RD_DONE = 7'b0100000,
		RD_REG_DONE = 7'b1000000;
		
	assign reg_addr = addr_mode?addr:{addr[7:0],addr[15:8]};
	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)begin
		Cmd <= 6'd0;
		Tx_DATA <= 8'd0;
		Go <= 1'b0;
		rddata <= 0;
		state <= IDLE;
		ack <= 0;
	end
	else begin
		case(state)
			IDLE:
				begin
					cnt <= 0;
					ack <= 0;
					RW_Done <= 1'b0;					
					if(wrreg_req)
						state <= WR_REG;
					else if(rdreg_req)
						state <= RD_REG;
					else
						state <= IDLE;
				end
			
			WR_REG:
				begin
					state <= WAIT_WR_DONE;
					case(cnt)
						0:write_byte(WR | STA, device_id);
						1:write_byte(WR, reg_addr[15:8]);
						2:write_byte(WR, reg_addr[7:0]);
						3:write_byte(WR | STO, wrdata);
						default:;
					endcase
				end
						
			WAIT_WR_DONE:
				begin
					Go <= 1'b0; 
					if(Trans_Done)begin
						ack <= ack | ack_o;
						case(cnt)
							0: begin cnt <= 1; state <= WR_REG;end
							1: 
								begin 
									state <= WR_REG;
									if(addr_mode)
										cnt <= 2; 
									else
										cnt <= 3;
								end
									
							2: begin
									cnt <= 3;
									state <= WR_REG;
								end
							3:state <= WR_REG_DONE;
							default:state <= IDLE;
						endcase
					end
				end
								
			WR_REG_DONE:
				begin
					RW_Done <= 1'b1;
					state <= IDLE;
				end
				
			RD_REG:
				begin
					state <= WAIT_RD_DONE;
					case(cnt)
						0:write_byte(WR | STA, device_id);
						1:if(addr_mode)
								write_byte(WR, reg_addr[15:8]);
							else
								write_byte(WR, reg_addr[15:8]);
						2:write_byte(WR, reg_addr[7:0]);
						3:write_byte(WR | STA, device_id | 8'd1);
						4:read_byte(RD | NACK | STO);
						default:;
					endcase
				end
				
			WAIT_RD_DONE:
				begin
					Go <= 1'b0; 
					if(Trans_Done)begin
						if(cnt <= 3)
							ack <= ack | ack_o;
						case(cnt)
							0: begin cnt <= 1; state <= RD_REG;end
							1: 
								begin 
									state <= RD_REG;
									if(addr_mode)
										cnt <= 2; 
									else
										cnt <= 3;
								end
									
							2: begin
									cnt <= 3;
									state <= RD_REG;
								end
							3:begin
									cnt <= 4;
									state <= RD_REG;
								end
							4:state <= RD_REG_DONE;
							default:state <= IDLE;
						endcase
					end
				end
				
			RD_REG_DONE:
				begin
					RW_Done <= 1'b1;
					rddata <= Rx_DATA;
					state <= IDLE;				
				end
			default:state <= IDLE;
		endcase
	end
	
	task read_byte;
		input [5:0]Ctrl_Cmd;
		begin
			Cmd <= Ctrl_Cmd;
			Go <= 1'b1; 
		end
	endtask
	
	task write_byte;
		input [5:0]Ctrl_Cmd;
		input [7:0]Wr_Byte_Data;
		begin
			Cmd <= Ctrl_Cmd;
			Tx_DATA <= Wr_Byte_Data;
			Go <= 1'b1; 
		end
	endtask

endmodule

IIC模块
i2c_bit_shift.v

module i2c_bit_shift(
	Clk,
	Rst_n,
	
	Cmd,
	Go,
	Rx_DATA,
	Tx_DATA,
	Trans_Done,
	ack_o,
	i2c_sclk,
	i2c_sdat
);
	input Clk;
	input Rst_n;
	
	input [5:0]Cmd;
	input Go;
	output reg[7:0]Rx_DATA;
	input [7:0]Tx_DATA;
	output reg Trans_Done;
	output reg ack_o;
	output reg i2c_sclk;
	inout i2c_sdat;
	
	reg i2c_sdat_o;

	//系统时钟采用50MHz
	parameter SYS_CLOCK = 50_000_000;
	//SCL总线时钟采用400kHz
	parameter SCL_CLOCK = 400_000;
	//产生时钟SCL计数器最大值
	localparam SCL_CNT_M = SYS_CLOCK/SCL_CLOCK/4 - 1;
	
	reg i2c_sdat_oe;
	
	localparam 
		WR =  6'b000001,	// 写请求
		STA = 6'b000010,	//起始位请求
		RD =  6'b000100,	//读请求
		STO = 6'b001000,	//停止位请求
		ACK = 6'b010000,	//应答位请求
		NACK = 6'b100000;	//无应答请求
		
	reg [19:0]div_cnt;
	reg en_div_cnt;
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		div_cnt <= 20'd0;
	else if(en_div_cnt)begin
		if(div_cnt < SCL_CNT_M)
			div_cnt <= div_cnt + 1'b1;
		else
			div_cnt <= 0;
	end
	else
		div_cnt <= 0;

	wire sclk_plus = div_cnt == SCL_CNT_M;
	
	assign i2c_sdat = i2c_sdat_oe?i2c_sdat_o:1'bz;
		
	reg [7:0]state;
	
	localparam
		IDLE = 		8'b00000001,
		GEN_STA = 	8'b00000010,
		WR_DATA = 	8'b00000100,
		RD_DATA = 	8'b00001000,
		CHECK_ACK = 8'b00010000,
		GEN_ACK = 	8'b00100000,
		GEN_STO = 	8'b01000000;
		
	reg [4:0]cnt;
		
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)begin
		Rx_DATA <= 0;
		i2c_sdat_oe <= 1'd0;
		en_div_cnt <= 1'b0;
		i2c_sdat_o <= 1'd1;
		Trans_Done <= 1'b0;
		ack_o <= 0;
		state <= IDLE;
		cnt <= 0;
	end
	else begin
		case(state)
			IDLE:
			begin
				Trans_Done <= 1'b0;
				i2c_sdat_oe <= 1'd1;
				if(Go)begin
					en_div_cnt <= 1'b1;
					if(Cmd & STA)
						state <= GEN_STA;
					else if(Cmd & WR)
						state <= WR_DATA;
					else if(Cmd & RD)
						state <= RD_DATA;
					else
						state <= IDLE;
				end
				else begin
					en_div_cnt <= 1'b0;
					state <= IDLE;
				end
			end
				
			GEN_STA:
				begin
					if(sclk_plus)begin
						if(cnt == 3)
							cnt <= 0;
						else
							cnt <= cnt + 1'b1;
						case(cnt)
							0:begin i2c_sdat_o <= 1; i2c_sdat_oe <= 1'd1;end
							1:begin i2c_sclk <= 1;end
							2:begin i2c_sdat_o <= 0; i2c_sclk <= 1;end
							3:begin i2c_sclk <= 0;end
							default:begin i2c_sdat_o <= 1; i2c_sclk <= 1;end
						endcase
						if(cnt == 3)begin
							if(Cmd & WR)
								state <= WR_DATA;
							else if(Cmd & RD)
								state <= RD_DATA;
						end
					end
				end
				
			WR_DATA:
				begin
					if(sclk_plus)begin
						if(cnt == 31)
							cnt <= 0;
						else
							cnt <= cnt + 1'b1;
						case(cnt)
							0,4,8,12,16,20,24,28:begin i2c_sdat_o <= Tx_DATA[7-cnt[4:2]]; i2c_sdat_oe <= 1'd1;end	//set data;
							1,5,9,13,17,21,25,29:begin i2c_sclk <= 1;end	//sclk posedge
							2,6,10,14,18,22,26,30:begin i2c_sclk <= 1;end	//sclk keep high
							3,7,11,15,19,23,27,31:begin i2c_sclk <= 0;end	//sclk negedge
/*							
							0 :begin i2c_sdat_o <= Tx_DATA[7];end
							1 :begin i2c_sclk <= 1;end	//sclk posedge
							2 :begin i2c_sclk <= 1;end	//sclk keep high
							3 :begin i2c_sclk <= 0;end	//sclk negedge
							
							4 :begin i2c_sdat_o <= Tx_DATA[6];end
							5 :begin i2c_sclk <= 1;end	//sclk posedge
							6 :begin i2c_sclk <= 1;end	//sclk keep high
							7 :begin i2c_sclk <= 0;end	//sclk negedge
							
							8 :begin i2c_sdat_o <= Tx_DATA[5];end
							9 :begin i2c_sclk <= 1;end	//sclk posedge
							10:begin i2c_sclk <= 1;end	//sclk keep high
							11:begin i2c_sclk <= 0;end	//sclk negedge
							
							12:begin i2c_sdat_o <= Tx_DATA[4];end
							13:begin i2c_sclk <= 1;end	//sclk posedge
							14:begin i2c_sclk <= 1;end	//sclk keep high
							15:begin i2c_sclk <= 0;end	//sclk negedge
							
							16:begin i2c_sdat_o <= Tx_DATA[3];end
							17:begin i2c_sclk <= 1;end	//sclk posedge
							18:begin i2c_sclk <= 1;end	//sclk keep high
							19:begin i2c_sclk <= 0;end	//sclk negedge
							
							20:begin i2c_sdat_o <= Tx_DATA[2];end
							21:begin i2c_sclk <= 1;end	//sclk posedge
							22:begin i2c_sclk <= 1;end	//sclk keep high
							23:begin i2c_sclk <= 0;end	//sclk negedge	
							
							24:begin i2c_sdat_o <= Tx_DATA[1];end
							25:begin i2c_sclk <= 1;end	//sclk posedge
							26:begin i2c_sclk <= 1;end	//sclk keep high
							27:begin i2c_sclk <= 0;end	//sclk negedge	
							
							28:begin i2c_sdat_o <= Tx_DATA[0];end
							29:begin i2c_sclk <= 1;end	//sclk posedge
							30:begin i2c_sclk <= 1;end	//sclk keep high
							31:begin i2c_sclk <= 0;end	//sclk negedge
*/							
							default:begin i2c_sdat_o <= 1; i2c_sclk <= 1;end
						endcase
						if(cnt == 31)begin
							state <= CHECK_ACK;
						end
					end
				end
				
			RD_DATA:
				begin
					if(sclk_plus)begin
						if(cnt == 31)
							cnt <= 0;
						else
							cnt <= cnt + 1'b1;
						case(cnt)
							0,4,8,12,16,20,24,28:begin i2c_sdat_oe <= 1'd0; i2c_sclk <= 0;end	//set data;
							1,5,9,13,17,21,25,29:begin i2c_sclk <= 1;end	//sclk posedge
							2,6,10,14,18,22,26,30:begin i2c_sclk <= 1; Rx_DATA <= {Rx_DATA[6:0],i2c_sdat};end	//sclk keep high
							3,7,11,15,19,23,27,31:begin i2c_sclk <= 0;end	//sclk negedge						
							default:begin i2c_sdat_o <= 1; i2c_sclk <= 1;end
						endcase
						if(cnt == 31)begin
							state <= GEN_ACK;
						end
					end
				end
			
			CHECK_ACK:
				begin
					if(sclk_plus)begin
						if(cnt == 3)
							cnt <= 0;
						else
							cnt <= cnt + 1'b1;
						case(cnt)
							0:begin i2c_sdat_oe <= 1'd0; i2c_sclk <= 0;end
							1:begin i2c_sclk <= 1;end
							2:begin ack_o <= i2c_sdat; i2c_sclk <= 1;end
							3:begin i2c_sclk <= 0;end
							default:begin i2c_sdat_o <= 1; i2c_sclk <= 1;end
						endcase
						if(cnt == 3)begin
							if(Cmd & STO)
								state <= GEN_STO;
							else begin
								state <= IDLE;
								Trans_Done <= 1'b1;
							end								
						end
					end
				end
			
			GEN_ACK:
				begin
					if(sclk_plus)begin
						if(cnt == 3)
							cnt <= 0;
						else
							cnt <= cnt + 1'b1;
						case(cnt)
							0:begin 
									i2c_sdat_oe <= 1'd1;
									i2c_sclk <= 0;
									if(Cmd & ACK)
										i2c_sdat_o <= 1'b0;
									else if(Cmd & NACK)
										i2c_sdat_o <= 1'b1;
								end
							1:begin i2c_sclk <= 1;end
							2:begin i2c_sclk <= 1;end
							3:begin i2c_sclk <= 0;end
							default:begin i2c_sdat_o <= 1; i2c_sclk <= 1;end
						endcase
						if(cnt == 3)begin
							if(Cmd & STO)
								state <= GEN_STO;
							else begin
								state <= IDLE;
								Trans_Done <= 1'b1;
							end
						end
					end
				end
			
			GEN_STO:
				begin
					if(sclk_plus)begin
						if(cnt == 3)
							cnt <= 0;
						else
							cnt <= cnt + 1'b1;
						case(cnt)
							0:begin i2c_sdat_o <= 0; i2c_sdat_oe <= 1'd1;end
							1:begin i2c_sclk <= 1;end
							2:begin i2c_sdat_o <= 1; i2c_sclk <= 1;end
							3:begin i2c_sclk <= 1;end
							default:begin i2c_sdat_o <= 1; i2c_sclk <= 1;end
						endcase
						if(cnt == 3)begin
							Trans_Done <= 1'b1;
							state <= IDLE;
						end
					end
				end
			default:state <= IDLE;
		endcase
	end
	
endmodule

数码管模块
HEX_top.v

/***************************************************
*	Module Name		:	HEX_top		   
*	Engineer		   :	小梅哥
*	Target Device	:	EP4CE10F17C8
*	Tool versions	:	Quartus II 13.0
*	Create Date		:	2017-3-31
*	Revision		   :	v1.0
*	Description		:  三线制数码管显示顶层设计
**************************************************/

module HEX_top(
	Clk,
	Rst_n,
	disp_data,
	SH_CP,
	ST_CP,
	DS
);

	input Clk;	//50M
	input Rst_n;
	
	output SH_CP;	//shift clock
	output ST_CP;	//latch data clock
	output DS;	//shift serial data
	
	input [31:0]disp_data;
	
	wire [7:0] sel;//数码管位选(选择当前要显示的数码管)
	wire [6:0] seg;//数码管段选(当前要显示的内容)	

	HEX8 HEX8(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.En(1'b1),
		.disp_data(disp_data),
		.sel(sel),
		.seg(seg)
	);
	
	
	HC595_Driver HC595_Driver(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.Data({1'b1,seg,sel}),
		.S_EN(1'b1),
		.SH_CP(SH_CP),
		.ST_CP(ST_CP),
		.DS(DS)
	);
	
endmodule

数码管模块
HEX8.v

/***************************************************
*	Module Name		:	HEX8		   
*	Engineer		   :	小梅哥
*	Target Device	:	EP4CE10F17C8
*	Tool versions	:	Quartus II 13.0
*	Create Date		:	2017-3-31
*	Revision		   :	v1.0
*	Description		:  8位7段数码管显示设计
**************************************************/

module HEX8(
		Clk,
		Rst_n,
		En,
		disp_data,
		sel,
		seg
	);

	input Clk;	//50M
	input Rst_n;
	input En;	//数码管显示使能,1使能,0关闭
	
	input [31:0]disp_data;
	
	output [7:0] sel;//数码管位选(选择当前要显示的数码管)
	output reg [6:0] seg;//数码管段选(当前要显示的内容)
	
	reg [14:0]divider_cnt;//25000-1
	
	reg clk_1K;
	reg [7:0]sel_r;
	
	reg [3:0]data_tmp;//数据缓存

//	分频计数器计数模块
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		divider_cnt <= 15'd0;
	else if(!En)
		divider_cnt <= 15'd0;
	else if(divider_cnt == 24999)
		divider_cnt <= 15'd0;
	else
		divider_cnt <= divider_cnt + 1'b1;

//1K扫描时钟生成模块		
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		clk_1K <= 1'b0;
	else if(divider_cnt == 24999)
		clk_1K <= ~clk_1K;
	else
		clk_1K <= clk_1K;
		
//8位循环移位寄存器
	always@(posedge clk_1K or negedge Rst_n)
	if(!Rst_n)
		sel_r <= 8'b0000_0001;
	else if(sel_r == 8'b1000_0000)
		sel_r <= 8'b0000_0001;
	else
		sel_r <=  sel_r << 1;
		
	always@(*)
		case(sel_r)
			8'b0000_0001:data_tmp = disp_data[3:0];
			8'b0000_0010:data_tmp = disp_data[7:4];
			8'b0000_0100:data_tmp = disp_data[11:8];
			8'b0000_1000:data_tmp = disp_data[15:12];
			8'b0001_0000:data_tmp = disp_data[19:16];
			8'b0010_0000:data_tmp = disp_data[23:20];
			8'b0100_0000:data_tmp = disp_data[27:24];
			8'b1000_0000:data_tmp = disp_data[31:28];
			default:data_tmp = 4'b0000;
		endcase
		
	always@(*)
		case(data_tmp)
			4'h0:seg = 7'b1000000; /*0*/
			4'h1:seg = 7'b1111001; /*1*/
			4'h2:seg = 7'b0100100; /*2*/
			4'h3:seg = 7'b0110000; /*3*/
			4'h4:seg = 7'b0011001; /*4*/
			4'h5:seg = 7'b0010010; /*5*/
			4'h6:seg = 7'b0000010; /*6*/
			4'h7:seg = 7'b1111000; /*7*/
			4'h8:seg = 7'b0000000; /*8*/
			4'h9:seg = 7'b0010000; /*9*/
			4'ha:seg = 7'b0001000; /*a*/
			4'hb:seg = 7'b0000011; /*b*/
			4'hc:seg = 7'b1000110; /*c*/
			4'hd:seg = 7'b0100001; /*d*/
			4'he:seg = 7'b0000110; /*e*/
			4'hf:seg = 7'b0111111; /*-*/
		endcase
		
	assign sel = (En)?sel_r:8'b0000_0000;

endmodule

595驱动
HC595_Driver.v

/***************************************************
*	Module Name		:	HC595_Driver		   
*	Engineer		   :	小梅哥
*	Target Device	:	EP4CE10F17C8
*	Tool versions	:	Quartus II 13.0
*	Create Date		:	2017-3-31
*	Revision		   :	v1.0
*	Description		:  74HC595移位寄存器驱动设计
**************************************************/

module HC595_Driver(
	Clk,
	Rst_n,
	Data,
	S_EN,
	SH_CP,
	ST_CP,
	DS
);

	parameter DATA_WIDTH = 16;

	input Clk;
	input Rst_n;
	input [DATA_WIDTH-1 : 0] Data;	//data to send
	input S_EN;	//send en
	output reg SH_CP;	//shift clock
	output reg ST_CP;	//latch data clock
	output reg DS;	//shift serial data
	
	parameter CNT_MAX = 4;
	
	
	reg [15:0] divider_cnt;//分频计数器
	wire sck_pluse;
	
	reg [4:0]SHCP_EDGE_CNT;//SH_CP EDGE counter
	
	reg [15:0]r_data;
	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		r_data <= 16'd0;
	else if(S_EN)
		r_data <= Data;
	else
		r_data <= r_data;
		
	//clock divide
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		divider_cnt <= 16'd0;
	else if(divider_cnt == CNT_MAX)
		divider_cnt <= 16'd0;
	else
		divider_cnt <= divider_cnt + 1'b1;
		
	assign sck_pluse = (divider_cnt == CNT_MAX);
	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		SHCP_EDGE_CNT <= 5'd0;
	else if(sck_pluse)begin
		if(SHCP_EDGE_CNT ==  5'd31)
			SHCP_EDGE_CNT <= 5'd0;
		else
			SHCP_EDGE_CNT <= SHCP_EDGE_CNT + 1'd1;
	end
	else
		SHCP_EDGE_CNT <= SHCP_EDGE_CNT;
		
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)begin
		SH_CP <= 1'b0;
		ST_CP <= 1'b0;
		DS <= 1'b0;	
	end
	else begin
		case(SHCP_EDGE_CNT)
			5'd0 :begin SH_CP <= 1'b0; ST_CP <= 1'b1; DS <= r_data[15]; end
			5'd1 :begin SH_CP <= 1'b1; ST_CP <= 1'b0;end
			5'd2 :begin SH_CP <= 1'b0; DS <= r_data[14];end
			5'd3 :begin SH_CP <= 1'b1; end
			5'd4 :begin SH_CP <= 1'b0; DS <= r_data[13];end
			5'd5 :begin SH_CP <= 1'b1; end
			5'd6 :begin SH_CP <= 1'b0; DS <= r_data[12];end
			5'd7 :begin SH_CP <= 1'b1; end
			5'd8 :begin SH_CP <= 1'b0; DS <= r_data[11];end
			5'd9 :begin SH_CP <= 1'b1; end
			5'd10:begin SH_CP <= 1'b0; DS <= r_data[10];end
			5'd11:begin SH_CP <= 1'b1; end
			5'd12:begin SH_CP <= 1'b0; DS <= r_data[9];end
			5'd13:begin SH_CP <= 1'b1; end
			5'd14:begin SH_CP <= 1'b0; DS <= r_data[8];end
			5'd15:begin SH_CP <= 1'b1; end
			5'd16:begin SH_CP <= 1'b0; DS <= r_data[7];end
			5'd17:begin SH_CP <= 1'b1; end
			5'd18:begin SH_CP <= 1'b0; DS <= r_data[6];end
			5'd19:begin SH_CP <= 1'b1; end
			5'd20:begin SH_CP <= 1'b0; DS <= r_data[5];end
			5'd21:begin SH_CP <= 1'b1; end
			5'd22:begin SH_CP <= 1'b0; DS <= r_data[4];end
			5'd23:begin SH_CP <= 1'b1; end
			5'd24:begin SH_CP <= 1'b0; DS <= r_data[3];end
			5'd25:begin SH_CP <= 1'b1; end
			5'd26:begin SH_CP <= 1'b0; DS <= r_data[2];end
			5'd27:begin SH_CP <= 1'b1; end
			5'd28:begin SH_CP <= 1'b0; DS <= r_data[1];end
			5'd29:begin SH_CP <= 1'b1; end
			5'd30:begin SH_CP <= 1'b0; DS <= r_data[0];end
			5'd31:begin SH_CP <= 1'b1; end
		endcase	
	end

endmodule

按键模块
key_filter.v

/***************************************************
*	Module Name		:	key_filter		   
*	Engineer		   :	小梅哥
*	Target Device	:	EP4CE10F17C8
*	Tool versions	:	Quartus II 13.0
*	Create Date		:	2017-3-31
*	Revision		   :	v1.0
*	Description		:  单按键消抖设计
**************************************************/

module key_filter(
	Clk,      //50M时钟输入
	Rst_n,    //模块复位
	key_in,   //按键输入
	key_flag, //按键标志信号
	key_state //按键状态信号
);

	input Clk;
	input Rst_n;
	input key_in;
	
	output reg key_flag;
	output reg key_state;
	
	localparam
		IDEL		= 4'b0001,
		FILTER0	= 4'b0010,
		DOWN		= 4'b0100,
		FILTER1 	= 4'b1000;
		
	reg [3:0]state;
	reg [19:0]cnt;
	reg en_cnt;	//使能计数寄存器
	
//对外部输入的异步信号进行同步处理
	reg key_in_sa,key_in_sb;
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)begin
		key_in_sa <= 1'b0;
		key_in_sb <= 1'b0;
	end
	else begin
		key_in_sa <= key_in;
		key_in_sb <= key_in_sa;	
	end
	
	reg key_tmpa,key_tmpb;
	wire pedge,nedge;
	reg cnt_full;//计数满标志信号
	
//使用D触发器存储两个相邻时钟上升沿时外部输入信号(已经同步到系统时钟域中)的电平状态
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)begin
		key_tmpa <= 1'b0;
		key_tmpb <= 1'b0;
	end
	else begin
		key_tmpa <= key_in_sb;
		key_tmpb <= key_tmpa;	
	end

//产生跳变沿信号	
	assign nedge = !key_tmpa & key_tmpb;
	assign pedge = key_tmpa & (!key_tmpb);
	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)begin
		en_cnt <= 1'b0;
		state <= IDEL;
		key_flag <= 1'b0;
		key_state <= 1'b1;
	end
	else begin
		case(state)
			IDEL :
				begin
					key_flag <= 1'b0;
					if(nedge)begin
						state <= FILTER0;
						en_cnt <= 1'b1;
					end
					else
						state <= IDEL;
				end
					
			FILTER0:
				if(cnt_full)begin
					key_flag <= 1'b1;
					key_state <= 1'b0;
					en_cnt <= 1'b0;
					state <= DOWN;
				end
				else if(pedge)begin
					state <= IDEL;
					en_cnt <= 1'b0;
				end
				else
					state <= FILTER0;
					
			DOWN:
				begin
					key_flag <= 1'b0;
					if(pedge)begin
						state <= FILTER1;
						en_cnt <= 1'b1;
					end
					else
						state <= DOWN;
				end
			
			FILTER1:
				if(cnt_full)begin
					key_flag <= 1'b1;
					key_state <= 1'b1;
					state <= IDEL;
					en_cnt <= 1'b0;
				end
				else if(nedge)begin
					en_cnt <= 1'b0;
					state <= DOWN;
				end
				else
					state <= FILTER1;
			
			default:
				begin 
					state <= IDEL; 
					en_cnt <= 1'b0;		
					key_flag <= 1'b0;
					key_state <= 1'b1;
				end
				
		endcase	
	end
	

	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		cnt <= 20'd0;
	else if(en_cnt)
		cnt <= cnt + 1'b1;
	else
		cnt <= 20'd0;
	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		cnt_full <= 1'b0;
	else if(cnt == 20'd999_999)
		cnt_full <= 1'b1;
	else
		cnt_full <= 1'b0;	

endmodule

M24LC04B模块
M24LC04B.v

// *******************************************************************************************************
// **                                                                           			**
// **   24LC04B.v - Microchip 24LC04B 4K-BIT I2C SERIAL EEPROM (VCC = +2.5V TO +5.5V)			**
// **                                                                           			**
// *******************************************************************************************************
// **                                                                           			**
// **			This information is distributed under license from Young Engineering.		**
// **                              COPYRIGHT (c) 2003 YOUNG ENGINEERING              			**
// **                                      ALL RIGHTS RESERVED                         			**
// **                                                                           			**
// **                                                                                                   **
// **   Young Engineering provides design expertise for the digital world                               **
// **   Started in 1990, Young Engineering offers products and services for your electronic design      **
// **   project.  We have the expertise in PCB, FPGA, ASIC, firmware, and software design.              **
// **   From concept to prototype to production, we can help you.                                       **
// **													**
// **	http://www.young-engineering.com/								**
// **													**
// *******************************************************************************************************
// **	This information is provided to you for your convenience and use with Microchip products only.  **
// **	Microchip disclaims all liability arising from this information and its use.  			**
// **													**
// **	THIS INFORMATION IS PROVIDED "AS IS." MICROCHIP MAKES NO REPRESENTATION OR WARRANTIES OF 	**
// **	ANY KIND WHETHER EXPRESS OR IMPLIED, WRITTEN OR ORAL, STATUTORY OR OTHERWISE, RELATED TO 	**
// **	THE INFORMATION PROVIDED TO YOU, INCLUDING BUT NOT LIMITED TO ITS CONDITION, QUALITY, 		**
// **	PERFORMANCE, MERCHANTABILITY, NON-INFRINGEMENT, OR FITNESS FOR PURPOSE.  			**
// **	MICROCHIP IS NOT LIABLE, UNDER ANY CIRCUMSTANCES, FOR SPECIAL, INCIDENTAL OR CONSEQUENTIAL 	**
// **	DAMAGES, FOR ANY REASON WHATSOEVER.								**
// **													**
// **	It is your responsibility to ensure that your application meets with your specifications.	**
// **													**
// *******************************************************************************************************
// **   Revision       : 1.3                                                    			**
// **   Modified Date  : 12/04/2006	                                            			**
// **   Revision History:                                                       			**
// **                                                                           			**
// **   02/01/2003:  Initial design                                             			**
// **   07/19/2004:  Fixed the timing checks and the open-drain modeling for SDA.			**
// **   01/06/2006:  Changed the legal information in the header					**
// **   12/04/2006:  Corrected timing checks to reference proper clock edges				**
// **                Added timing check for Tbuf (bus free time)					**
// **                                                                           			**
// *******************************************************************************************************
// **                                       TABLE OF CONTENTS                          			**
// *******************************************************************************************************
// **---------------------------------------------------------------------------------------------------**
// **   DECLARATIONS                                                          				**
// **---------------------------------------------------------------------------------------------------**
// **---------------------------------------------------------------------------------------------------**
// **   INITIALIZATION                                              					**
// **---------------------------------------------------------------------------------------------------**
// **---------------------------------------------------------------------------------------------------**
// **   CORE LOGIC                                                  					**
// **---------------------------------------------------------------------------------------------------**
// **   1.01:  START Bit Detection									**
// **   1.02:  STOP Bit Detection									**
// **   1.03:  Input Shift Register									**
// **   1.04:  Input Bit Counter									**
// **   1.05:  Control Byte Register									**
// **   1.06:  Byte Address Register									**
// **   1.07:  Write Data Buffer									**
// **   1.08:  Acknowledge Generator									**
// **   1.09:  Acknowledge Detect									**
// **   1.10:  Write Cycle Timer									**
// **   1.11:  Write Cycle Processor									**
// **   1.12:  Read Data Multiplexor									**
// **   1.13:  Read Data Processor									**
// **   1.14:  SDA Data I/O Buffer									**
// **                                                                           			**
// **---------------------------------------------------------------------------------------------------**
// **   DEBUG LOGIC                                                  					**
// **---------------------------------------------------------------------------------------------------**
// **   2.01:  Memory Data Bytes									**
// **   2.02:  Write Data Buffer									**
// **                                                                           			**
// **---------------------------------------------------------------------------------------------------**
// **   TIMING CHECKS                                                     				**
// **---------------------------------------------------------------------------------------------------**
// **                                                                           			**
// *******************************************************************************************************


`timescale 1ns/10ps

module M24LC04B (A0, A1, A2, WP, SDA, SCL, RESET);

   input 		A0;				// unconnected pin
   input 		A1;				// unconnected pin
   input 		A2;				// unconnected pin

   input		WP;				// write protect pin

   inout		SDA;				// serial data I/O
   input		SCL;				// serial data clock

   input		RESET;				// system reset


// *******************************************************************************************************
// **   DECLARATIONS                                                            			**
// *******************************************************************************************************

   reg			SDA_DO;				// serial data - output
   reg			SDA_OE;				// serial data - output enable

   wire			SDA_DriveEnable;		// serial data output enable
   reg			SDA_DriveEnableDlyd;		// serial data output enable - delayed

   reg	[03:00]		BitCounter;			// serial bit counter

   reg			START_Rcvd;			// START bit received flag
   reg			STOP_Rcvd;			// STOP bit received flag
   reg			CTRL_Rcvd;			// control byte received flag
   reg			ADDR_Rcvd;			// byte address received flag
   reg			MACK_Rcvd;			// master acknowledge received flag

   reg			WrCycle;			// memory write cycle
   reg			RdCycle;			// memory read cycle

   reg	[07:00]		ShiftRegister;			// input data shift register

   reg  [07:00]		ControlByte;			// control byte register
   wire			BlockSelect;			// memory block select
   wire			RdWrBit;			// read/write control bit

   reg	[08:00]		StartAddress;			// memory access starting address
   reg	[03:00]		PageAddress;			// memory page address

   reg	[07:00]		WrDataByte [0:15];		// memory write data buffer
   wire	[07:00]		RdDataByte;			// memory read data

   reg	[15:00]		WrCounter;			// write buffer counter

   reg	[03:00]		WrPointer;			// write buffer pointer
   reg	[08:00]		RdPointer;			// read address pointer

   reg			WriteActive;			// memory write cycle active

   reg	[07:00]		MemoryBlock0 [0:255];		// EEPROM data memory array
   reg	[07:00]		MemoryBlock1 [0:255];		// EEPROM data memory array

   integer		LoopIndex;			// iterative loop index

   integer 		tAA;				// timing parameter
   integer 		tWC;				// timing parameter


// *******************************************************************************************************
// **   INITIALIZATION                                                         				**
// *******************************************************************************************************

//----------------------------
//------写数据间隔改动----------
   initial tAA = 900;                                   // SCL to SDA output delay
   initial tWC = 500;                                   // memory write cycle time

//   initial tAA = 900;					// SCL to SDA output delay
//   initial tWC = 5000000;				// memory write cycle time

   initial begin
      SDA_DO = 0;
      SDA_OE = 0;
   end

   initial begin
      START_Rcvd = 0;
      STOP_Rcvd  = 0;
      CTRL_Rcvd  = 0;
      ADDR_Rcvd  = 0;
      MACK_Rcvd  = 0;
   end

   initial begin
      BitCounter  = 0;
      ControlByte = 0;
   end

   initial begin
      WrCycle = 0;
      RdCycle = 0;

      WriteActive = 0;
   end


// *******************************************************************************************************
// **   CORE LOGIC                                                    					**
// *******************************************************************************************************
// -------------------------------------------------------------------------------------------------------
//      1.01:  START Bit Detection
// -------------------------------------------------------------------------------------------------------

   always @(negedge SDA) begin
      if (SCL == 1) begin
         START_Rcvd <= 1;
         STOP_Rcvd  <= 0;
         CTRL_Rcvd  <= 0;
         ADDR_Rcvd  <= 0;
         MACK_Rcvd  <= 0;

         WrCycle <= #1 0;
         RdCycle <= #1 0;

         BitCounter <= 0;
      end
   end

// -------------------------------------------------------------------------------------------------------
//      1.02:  STOP Bit Detection
// -------------------------------------------------------------------------------------------------------

   always @(posedge SDA) begin
      if (SCL == 1) begin
         START_Rcvd <= 0;
         STOP_Rcvd  <= 1;
         CTRL_Rcvd  <= 0;
         ADDR_Rcvd  <= 0;
         MACK_Rcvd  <= 0;

         WrCycle <= #1 0;
         RdCycle <= #1 0;

         BitCounter <= 10;
      end
   end

// -------------------------------------------------------------------------------------------------------
//      1.03:  Input Shift Register
// -------------------------------------------------------------------------------------------------------

   always @(posedge SCL) begin
      ShiftRegister[00] <= SDA;
      ShiftRegister[01] <= ShiftRegister[00];
      ShiftRegister[02] <= ShiftRegister[01];
      ShiftRegister[03] <= ShiftRegister[02];
      ShiftRegister[04] <= ShiftRegister[03];
      ShiftRegister[05] <= ShiftRegister[04];
      ShiftRegister[06] <= ShiftRegister[05];
      ShiftRegister[07] <= ShiftRegister[06];
   end

// -------------------------------------------------------------------------------------------------------
//      1.04:  Input Bit Counter
// -------------------------------------------------------------------------------------------------------

   always @(posedge SCL) begin
      if (BitCounter < 10) BitCounter <= BitCounter + 1;
   end

// -------------------------------------------------------------------------------------------------------
//      1.05:  Control Byte Register
// -------------------------------------------------------------------------------------------------------

   always @(negedge SCL) begin
      if (START_Rcvd & (BitCounter == 8)) begin
         if (!WriteActive & (ShiftRegister[07:04] == 4'b1010)) begin
            if (ShiftRegister[00] == 0) WrCycle <= 1;
            if (ShiftRegister[00] == 1) RdCycle <= 1;

            ControlByte <= ShiftRegister[07:00];

            CTRL_Rcvd <= 1;
         end

         START_Rcvd <= 0;
      end
   end

   assign BlockSelect = ControlByte[01];
   assign RdWrBit     = ControlByte[00];

// -------------------------------------------------------------------------------------------------------
//      1.06:  Byte Address Register
// -------------------------------------------------------------------------------------------------------

   always @(negedge SCL) begin
      if (CTRL_Rcvd & (BitCounter == 8)) begin
         if (RdWrBit == 0) begin
            StartAddress <= {BlockSelect,ShiftRegister[07:00]};
            RdPointer    <= {BlockSelect,ShiftRegister[07:00]};

            ADDR_Rcvd <= 1;
         end

         WrCounter <= 0;
         WrPointer <= 0;

         CTRL_Rcvd <= 0;
      end
   end

// -------------------------------------------------------------------------------------------------------
//      1.07:  Write Data Buffer
// -------------------------------------------------------------------------------------------------------

   always @(negedge SCL) begin
      if (ADDR_Rcvd & (BitCounter == 8)) begin
         if ((WP == 0) & (RdWrBit == 0)) begin
            WrDataByte[WrPointer] <= ShiftRegister[07:00];

            WrCounter <= WrCounter + 1;
            WrPointer <= WrPointer + 1;
         end
      end
   end

// -------------------------------------------------------------------------------------------------------
//      1.08:  Acknowledge Generator
// -------------------------------------------------------------------------------------------------------

   always @(negedge SCL) begin
      if (!WriteActive) begin
         if (BitCounter == 8) begin
            if (WrCycle | (START_Rcvd & (ShiftRegister[07:04] == 4'b1010))) begin
               SDA_DO <= 0;
               SDA_OE <= 1;
            end 
         end
         if (BitCounter == 9) begin
            BitCounter <= 0;

            if (!RdCycle) begin
               SDA_DO <= 0;
               SDA_OE <= 0;
            end
         end
      end
   end 

// -------------------------------------------------------------------------------------------------------
//      1.09:  Acknowledge Detect
// -------------------------------------------------------------------------------------------------------

   always @(posedge SCL) begin
      if (RdCycle & (BitCounter == 8)) begin
         if ((SDA == 0) & (SDA_OE == 0)) MACK_Rcvd <= 1;
      end
   end

   always @(negedge SCL) MACK_Rcvd <= 0;

// -------------------------------------------------------------------------------------------------------
//      1.10:  Write Cycle Timer
// -------------------------------------------------------------------------------------------------------

   always @(posedge STOP_Rcvd) begin
      if (WrCycle & (WP == 0) & (WrCounter > 0)) begin
         WriteActive = 1;
         #(tWC);
         WriteActive = 0;
      end
   end

   always @(posedge STOP_Rcvd) begin
      #(1.0);
      STOP_Rcvd = 0;
   end

// -------------------------------------------------------------------------------------------------------
//      1.11:  Write Cycle Processor
// -------------------------------------------------------------------------------------------------------

   always @(negedge WriteActive) begin
      for (LoopIndex = 0; LoopIndex < WrCounter; LoopIndex = LoopIndex + 1) begin
         if (StartAddress[08] == 0) begin
            PageAddress = StartAddress[03:00] + LoopIndex;

            MemoryBlock0[{StartAddress[07:04],PageAddress[03:00]}] = WrDataByte[LoopIndex[03:00]];
         end
         if (StartAddress[08] == 1) begin
            PageAddress = StartAddress[03:00] + LoopIndex;

            MemoryBlock1[{StartAddress[07:04],PageAddress[03:00]}] = WrDataByte[LoopIndex[03:00]];
         end
      end
   end

// -------------------------------------------------------------------------------------------------------
//      1.12:  Read Data Multiplexor
// -------------------------------------------------------------------------------------------------------

   always @(negedge SCL) begin
      if (BitCounter == 8) begin
         if (WrCycle & ADDR_Rcvd) begin
            RdPointer <= StartAddress + WrPointer + 1;
         end
         if (RdCycle) begin
            RdPointer <= RdPointer + 1;
         end
      end
   end

   assign RdDataByte = RdPointer[08] ? MemoryBlock1[RdPointer[07:00]] : MemoryBlock0[RdPointer[07:00]];

// -------------------------------------------------------------------------------------------------------
//      1.13:  Read Data Processor
// -------------------------------------------------------------------------------------------------------

   always @(negedge SCL) begin
      if (RdCycle) begin
         if (BitCounter == 8) begin
            SDA_DO <= 0;
            SDA_OE <= 0;
         end
         else if (BitCounter == 9) begin
            SDA_DO <= RdDataByte[07];

            if (MACK_Rcvd) SDA_OE <= 1;
         end
         else begin
            SDA_DO <= RdDataByte[7-BitCounter];
         end
      end
   end

// -------------------------------------------------------------------------------------------------------
//      1.14:  SDA Data I/O Buffer
// -------------------------------------------------------------------------------------------------------

   bufif1 (SDA, 1'b0, SDA_DriveEnableDlyd);

   assign SDA_DriveEnable = !SDA_DO & SDA_OE;
   always @(SDA_DriveEnable) SDA_DriveEnableDlyd <= #(tAA) SDA_DriveEnable;


// *******************************************************************************************************
// **   DEBUG LOGIC                                                           				**
// *******************************************************************************************************
// -------------------------------------------------------------------------------------------------------
//      2.01:  Memory Data Bytes
// -------------------------------------------------------------------------------------------------------

   wire [07:00]	MemoryByte0_00 = MemoryBlock0[00];
   wire [07:00]	MemoryByte0_01 = MemoryBlock0[01];
   wire [07:00]	MemoryByte0_02 = MemoryBlock0[02];
   wire [07:00]	MemoryByte0_03 = MemoryBlock0[03];
   wire [07:00]	MemoryByte0_04 = MemoryBlock0[04];
   wire [07:00]	MemoryByte0_05 = MemoryBlock0[05];
   wire [07:00]	MemoryByte0_06 = MemoryBlock0[06];
   wire [07:00]	MemoryByte0_07 = MemoryBlock0[07];

   wire [07:00]	MemoryByte0_08 = MemoryBlock0[08];
   wire [07:00]	MemoryByte0_09 = MemoryBlock0[09];
   wire [07:00]	MemoryByte0_0A = MemoryBlock0[10];
   wire [07:00]	MemoryByte0_0B = MemoryBlock0[11];
   wire [07:00]	MemoryByte0_0C = MemoryBlock0[12];
   wire [07:00]	MemoryByte0_0D = MemoryBlock0[13];
   wire [07:00]	MemoryByte0_0E = MemoryBlock0[14];
   wire [07:00]	MemoryByte0_0F = MemoryBlock0[15];

   wire [07:00]	MemoryByte1_00 = MemoryBlock1[00];
   wire [07:00]	MemoryByte1_01 = MemoryBlock1[01];
   wire [07:00]	MemoryByte1_02 = MemoryBlock1[02];
   wire [07:00]	MemoryByte1_03 = MemoryBlock1[03];
   wire [07:00]	MemoryByte1_04 = MemoryBlock1[04];
   wire [07:00]	MemoryByte1_05 = MemoryBlock1[05];
   wire [07:00]	MemoryByte1_06 = MemoryBlock1[06];
   wire [07:00]	MemoryByte1_07 = MemoryBlock1[07];

   wire [07:00]	MemoryByte1_08 = MemoryBlock1[08];
   wire [07:00]	MemoryByte1_09 = MemoryBlock1[09];
   wire [07:00]	MemoryByte1_0A = MemoryBlock1[10];
   wire [07:00]	MemoryByte1_0B = MemoryBlock1[11];
   wire [07:00]	MemoryByte1_0C = MemoryBlock1[12];
   wire [07:00]	MemoryByte1_0D = MemoryBlock1[13];
   wire [07:00]	MemoryByte1_0E = MemoryBlock1[14];
   wire [07:00]	MemoryByte1_0F = MemoryBlock1[15];

// -------------------------------------------------------------------------------------------------------
//      2.02:  Write Data Buffer
// -------------------------------------------------------------------------------------------------------

   wire [07:00]	WriteData_0 = WrDataByte[00];
   wire [07:00]	WriteData_1 = WrDataByte[01];
   wire [07:00]	WriteData_2 = WrDataByte[02];
   wire [07:00]	WriteData_3 = WrDataByte[03];
   wire [07:00]	WriteData_4 = WrDataByte[04];
   wire [07:00]	WriteData_5 = WrDataByte[05];
   wire [07:00]	WriteData_6 = WrDataByte[06];
   wire [07:00]	WriteData_7 = WrDataByte[07];
   wire [07:00]	WriteData_8 = WrDataByte[08];
   wire [07:00]	WriteData_9 = WrDataByte[09];
   wire [07:00]	WriteData_A = WrDataByte[10];
   wire [07:00]	WriteData_B = WrDataByte[11];
   wire [07:00]	WriteData_C = WrDataByte[12];
   wire [07:00]	WriteData_D = WrDataByte[13];
   wire [07:00]	WriteData_E = WrDataByte[14];
   wire [07:00]	WriteData_F = WrDataByte[15];


// *******************************************************************************************************
// **   TIMING CHECKS                                                           			**
// *******************************************************************************************************

   wire TimingCheckEnable = (RESET == 0) & (SDA_OE == 0);

	
//--------------------------------
//-------仿真时时序约束需改动--------
//--------------------------------
   specify
      specparam
         tHI = 600,                                     // SCL pulse width - high
//         tLO = 1300,                                    // SCL pulse width - low
         tLO = 600, 
			tSU_STA = 600,                                 // SCL to SDA setup time
         tHD_STA = 600,                                 // SCL to SDA hold time
         tSU_DAT = 100,                                 // SDA to SCL setup time
         tSU_STO = 600,                                 // SCL to SDA setup time
//         tBUF = 1300;                                   // Bus free time
         tBUF = 600;
			
      $width (posedge SCL, tHI);
      $width (negedge SCL, tLO);

      $width (posedge SDA &&& SCL, tBUF);

      $setup (posedge SCL, negedge SDA &&& TimingCheckEnable, tSU_STA);
      $setup (SDA, posedge SCL &&& TimingCheckEnable, tSU_DAT);
      $setup (posedge SCL, posedge SDA &&& TimingCheckEnable, tSU_STO);

      $hold  (negedge SDA &&& TimingCheckEnable, negedge SCL, tHD_STA);
   endspecify

endmodule


你可能感兴趣的:(ZYNQ嵌入式系统1)