vivado验证简单的iic通信

关于iic的时序,之前已经讲过,这里纠正一个小错误就是inout类型的变量不可以用reg型,只能用wire型,之前在alter板子上reg可以也不知道为啥,反正vivado不行。由于博主很懒,就把之前写的代码照搬过来了,修改下,就可以在vivado上用了。

关于代码不做介绍,通过实验验证了我们的程序在连续写或读的时候都不会存在问题,有想修改的朋友直接照搬即可,然后自己修改测试程序就是,读和写单字节都封装的比较好可以不做修改。直接用就行了。也欢迎大家可以一起讨论,下面给出代码。

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2019/09/17 10:29:21
// Design Name: 
// Module Name: iic
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module iic(
clk,
rst,
choose,
device,
address,
data,
rdata,
slk,
sda_a,
isdone
);
inout wire sda_a;
input clk;
input rst;
input [1:0]choose;  //选择读、写
input [7:0]device;
input [7:0]address;
input [7:0]data;
output reg [7:0]rdata;
output reg slk;
reg sda;
output reg isdone;
 
assign sda_a=sda;
 
parameter r100K = 9'd500;
 
reg [5:0]i;
reg [15:0]clkcount;
reg isask;
always@(posedge clk or negedge rst)
if(!rst)
begin
	rdata<=8'b0;
	slk<=1'b1;
	sda<=1'b1;
	i<=6'd0;
	clkcount<=16'd0;
	isask<=1'b0;
	isdone<=1'b0;
end
else if(choose[0]) //代表开始写一个数的地址
begin
	case(i)
		0:begin if(clkcount==16'd499)
				  begin
						clkcount<=16'd0;
						i<=i+1'b1;
				  end
				  else
						clkcount<=clkcount+1'b1;
					
				  if(clkcount==16'd0)
						slk<=1'b1;
				  else if(clkcount==16'd350)
						slk<=1'b0;
						
				  if(clkcount==16'd0)
						sda<=1'b1;
				  else if(clkcount==16'd250)
						sda<=1'b0;						
		end
		//写设备地址
	  1,2,3,4,5,6,7,8:begin if(clkcount==16'd499)
				  begin
						clkcount<=16'd0;
						i<=i+1'b1;
				  end
				  else
						clkcount<=clkcount+1'b1;
					
				  if(clkcount==16'd0)
						slk<=1'b0;
				  else if(clkcount==16'd100)
						slk<=1'b1;
				  else if(clkcount==16'd300)
						slk<=1'b0;
						
				  sda<=device[8-i];		
	  end
	  //释放总线设为高阻态
	  9:begin if(clkcount==16'd499)
				  begin
						clkcount<=16'd0;
						i<=i+1'b1;
						//总线重新让主机掌握
						sda<=1'b1;
				  end
				  else
						clkcount<=clkcount+1'b1;
					
				  if(clkcount==16'd0)
						slk<=1'b0;
				  else if(clkcount==16'd100)
						slk<=1'b1;
				  else if(clkcount==16'd300)
						slk<=1'b0;
						
				  sda<=1'bz;
				  if(clkcount==16'd200)
					   isask<=sda;
	  end
     10: if(isask!=0)
				i<=6'd0;
			else
				i<=i+1'b1;
	  //写字节地址
	  11,12,13,14,15,16,17,18:begin if(clkcount==16'd499)
				  begin
						clkcount<=16'd0;
						i<=i+1'b1;
				  end
				  else
						clkcount<=clkcount+1'b1;
					
				  if(clkcount==16'd0)
						slk<=1'b0;
				  else if(clkcount==16'd100)
						slk<=1'b1;
				  else if(clkcount==16'd300)
						slk<=1'b0;
						
				  sda<=address[18-i];		
	  end
	  //释放总线设为高阻态
	  19:begin if(clkcount==16'd499)
				  begin
						clkcount<=16'd0;
						i<=i+1'b1;
						//总线重新让主机掌握
						sda<=1'b1;
				  end
				  else
						clkcount<=clkcount+1'b1;
					
				  if(clkcount==16'd0)
						slk<=1'b0;
				  else if(clkcount==16'd100)
						slk<=1'b1;
				  else if(clkcount==16'd300)
						slk<=1'b0;
						
				  sda<=1'bz;
				  if(clkcount==16'd200)
					   isask<=sda;
	  end
     20: if(isask!=0)
				i<=6'd0;
			else
				i<=i+1'b1;
	  21,22,23,24,25,26,27,28: begin if(clkcount==16'd499)
				  begin
						clkcount<=16'd0;
						i<=i+1'b1;
				  end
				  else
						clkcount<=clkcount+1'b1;
					
				  if(clkcount==16'd0)
						slk<=1'b0;
				  else if(clkcount==16'd100)
						slk<=1'b1;
				  else if(clkcount==16'd300)
						slk<=1'b0;
						
				  sda<=data[28-i];		
	  end
	  //释放总线设为高阻态
	  29:begin if(clkcount==16'd499)
				  begin
						clkcount<=16'd0;
						i<=i+1'b1;
						//总线重新让主机掌握
						sda<=1'b0;
				  end
				  else
						clkcount<=clkcount+1'b1;
					
				  if(clkcount==16'd0)
						slk<=1'b0;
				  else if(clkcount==16'd100)
						slk<=1'b1;
				  else if(clkcount==16'd300)
						slk<=1'b0;
						
				  sda<=1'bz;
				  if(clkcount==16'd200)
					   isask<=sda;
	  end
     30: if(isask!=0)
				i<=6'd0;
			else
				i<=i+1'b1;
	  31:begin
	  if(clkcount==16'd499)
	  begin
			clkcount<=16'd0;
			i<=i+1'b1;
	  end
	  else
			clkcount<=clkcount+1'b1;
			
	  if(clkcount==16'd0)
			slk<=1'b0;
	  else if(clkcount==16'd200)
			slk<=1'b1;
			
	  if(clkcount==16'd0)
			sda<=1'b0;
	  else if(clkcount==16'd300)
			sda<=1'b1;
	  end
	  32: begin i<=i+1'b1;
					isdone<=1'b1;
	  end
	  33: begin i<=6'd0;
					isdone<=1'b0;
	  end
	endcase
end
else if(choose[1])
begin
	case(i)
		0: begin if(clkcount==16'd499)
				  begin
						clkcount<=16'd0;
						i<=i+1'b1;
				  end
				  else
						clkcount<=clkcount+1'b1;
					
				  if(clkcount==16'd0)
						slk<=1'b1;
				  else if(clkcount==16'd350)
						slk<=1'b0;
						
				  if(clkcount==16'd0)
						sda<=1'b1;
				  else if(clkcount==16'd250)
						sda<=1'b0;						
		end
		//写设备地址
	  1,2,3,4,5,6,7,8:begin if(clkcount==16'd499)
				  begin
						clkcount<=16'd0;
						i<=i+1'b1;
				  end
				  else
						clkcount<=clkcount+1'b1;
					
				  if(clkcount==16'd0)
						slk<=1'b0;
				  else if(clkcount==16'd100)
						slk<=1'b1;
				  else if(clkcount==16'd300)
						slk<=1'b0;
						
				  sda<=device[8-i];		
	  end
	  //释放总线设为高阻态
	  9:begin if(clkcount==16'd499)
				  begin
						clkcount<=16'd0;
						i<=i+1'b1;
						//总线重新让主机掌握
						sda<=1'b1;
				  end
				  else
						clkcount<=clkcount+1'b1;
					
				  if(clkcount==16'd0)
						slk<=1'b0;
				  else if(clkcount==16'd100)
						slk<=1'b1;
				  else if(clkcount==16'd300)
						slk<=1'b0;
						
				  sda<=1'bz;
				  if(clkcount==16'd200)
					   isask<=sda;
	  end
     10: if(isask!=0)
				i<=6'd0;
			else
				i<=i+1'b1;
	  //写字节地址
	  11,12,13,14,15,16,17,18:begin if(clkcount==16'd499)
				  begin
						clkcount<=16'd0;
						i<=i+1'b1;
				  end
				  else
						clkcount<=clkcount+1'b1;
					
				  if(clkcount==16'd0)
						slk<=1'b0;
				  else if(clkcount==16'd100)
						slk<=1'b1;
				  else if(clkcount==16'd300)
						slk<=1'b0;
						
				  sda<=address[18-i];		
	  end
	  //释放总线设为高阻态
	  19:begin if(clkcount==16'd499)
				  begin
						clkcount<=16'd0;
						i<=i+1'b1;
						//总线重新让主机掌握
						sda<=1'b1;
				  end
				  else
						clkcount<=clkcount+1'b1;
					
				  if(clkcount==16'd0)
						slk<=1'b0;
				  else if(clkcount==16'd100)
						slk<=1'b1;
				  else if(clkcount==16'd300)
						slk<=1'b0;
						
				  sda<=1'bz;
				  if(clkcount==16'd200)
					   isask<=sda;
	  end
     20: if(isask!=0)
				i<=6'd0;
			else
				i<=i+1'b1;
	 //再来一次起始信号
	  21: begin if(clkcount==16'd499)
				  begin
						clkcount<=16'd0;
						i<=i+1'b1;
				  end
				  else
						clkcount<=clkcount+1'b1;
					
				  if(clkcount==16'd0)
						slk<=1'b1;
				  else if(clkcount==16'd350)
						slk<=1'b0;
						
				  if(clkcount==16'd0)
						sda<=1'b1;
				  else if(clkcount==16'd250)
						sda<=1'b0;						
		end
		22,23,24,25,26,27,28: begin if(clkcount==16'd499)
				  begin
						clkcount<=16'd0;
						i<=i+1'b1;
				  end
				  else
						clkcount<=clkcount+1'b1;
					
				  if(clkcount==16'd0)
						slk<=1'b0;
				  else if(clkcount==16'd100)
						slk<=1'b1;
				  else if(clkcount==16'd300)
						slk<=1'b0;
						
				  sda<=device[29-i];		
	  end
	  29: begin if(clkcount==16'd499)
				  begin
						clkcount<=16'd0;
						i<=i+1'b1;
				  end
				  else
						clkcount<=clkcount+1'b1;
					
				  if(clkcount==16'd0)
						slk<=1'b0;
				  else if(clkcount==16'd100)
						slk<=1'b1;
				  else if(clkcount==16'd300)
						slk<=1'b0;
				   //最后一位表示读	
				  sda<=1'b1;		
	  end
	  //释放总线设为高阻态
	  30:begin if(clkcount==16'd499)
				  begin
						clkcount<=16'd0;
						i<=i+1'b1;
						//总线重新让主机掌握
						//sda<=1'b1;
				  end
				  else
						clkcount<=clkcount+1'b1;
					
				  if(clkcount==16'd0)
						slk<=1'b0;
				  else if(clkcount==16'd100)
						slk<=1'b1;
				  else if(clkcount==16'd300)
						slk<=1'b0;
						
				  sda<=1'bz;
				  if(clkcount==16'd200)
					   isask<=sda;
	  end
     31: if(isask!=0)
				i<=6'd0;
			else
				i<=i+1'b1;
		//开始读数据
	  32,33,34,35,36,37,38,39: begin if(clkcount==16'd499)
				  begin
						clkcount<=16'd0;
						i<=i+1'b1;
				  end
				  else
						clkcount<=clkcount+1'b1;
					
				  if(clkcount==16'd0)
						slk<=1'b0;
				  else if(clkcount==16'd100)
						slk<=1'b1;
				  else if(clkcount==16'd300)
						slk<=1'b0;
					
				  if(clkcount==16'd200)
						rdata[39-i]<=sda;
						
				  sda<=1'bz;	
				 end
		 //释放总线设为高阻态
	  40:begin if(clkcount==16'd499)
				  begin
						clkcount<=16'd0;
						i<=i+1'b1;
				  end
				  else
						clkcount<=clkcount+1'b1;
					
				  if(clkcount==16'd0)
						slk<=1'b0;
				  else if(clkcount==16'd100)
						slk<=1'b1;
				  else if(clkcount==16'd300)
						slk<=1'b0;
						
				  sda<=1'b0;
	  end
	  41: begin
	  if(clkcount==16'd499)
	  begin
			clkcount<=16'd0;
			i<=i+1'b1;
	  end
	  else
			clkcount<=clkcount+1'b1;
			
	  if(clkcount==16'd0)
			slk<=1'b0;
	  else if(clkcount==16'd200)
			slk<=1'b1;
			
	  if(clkcount==16'd0)
			sda<=1'b0;
	  else if(clkcount==16'd300)
			sda<=1'b1;
	  end
	  42: begin i<=i+1'b1;
					isdone<=1'b1;
	  end
	  43: begin i<=6'd0;
					isdone<=1'b0;
	  end
	endcase
end
endmodule
`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2019/09/17 10:35:01
// Design Name: 
// Module Name: iic_test
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module iic_test(
clk,
rst,
led,
slk,
sda_a
);
 
input clk;
input rst;
output reg [3:0]led;
output slk;
inout sda_a;
 
 
wire isdone;
wire [7:0]rdata;
iic(
.clk(clk),
.rst(rst),
.choose(choose),
.device(device),
.address(address),
.data(data),
.rdata(rdata),
.slk(slk),
.sda_a(sda_a),
.isdone(isdone)
);
 
reg [1:0]choose;
reg [2:0]i;
reg [7:0]device;
reg [7:0]address;
reg [7:0]data;
reg [27:0]count;
always@(posedge clk or negedge rst)
if(!rst)
begin
	choose<=2'b00;
	i<=3'b0;
	device<=8'b0;
	address<=8'b0;
	data<=8'b0;
	led<=4'd0;
	count<=28'd0;
end
else 
	case(i)
		0: if(isdone)
		begin
			choose<=2'b00;
			i<=i+1'b1;
		end
		else
		begin
			choose<=2'b01;
			device<=8'b10100000;
			address<=8'b00000000;
			data<=8'h4e;
		end
		1: if(isdone)
            begin
                choose<=2'b00;
                i<=i+1'b1;
            end
            else
            begin
                choose<=2'b01;
                device<=8'b10100000;
                address<=8'b00000001;
                data<=8'h3a;
            end
		2: if(isdone)
		begin
			choose<=2'b00;
			i<=i+1'b1;
		end
		else
		begin
			choose<=2'b10;
			device<=8'b10100000;
			address<=8'b00000000;
			//data<=8'h2a;
		end
		3: 
		if(count==28'd50000000)
		begin
		  count<=28'd0;
		  i<=i+1'b1;
		end
		else
		begin 
		  led<=~rdata[3:0];
		  count<=count+1'b1;
		end
		4: 
        if(count==28'd50000000)
        begin
          count<=28'd0;
          i<=i+1'b1;
        end
        else
        begin 
          led<=~rdata[7:4];
          count<=count+1'b1;
        end
        5: if(isdone)
        begin
            choose<=2'b00;
            i<=i+1'b1;
        end
        else
        begin
            choose<=2'b10;
            device<=8'b10100000;
            address<=8'b00000001;
            //data<=8'h2a;
        end 
        6: 
        if(count==28'd50000000)
        begin
          count<=28'd0;
          i<=i+1'b1;
        end
        else
        begin 
          led<=~rdata[3:0];
          count<=count+1'b1;
        end
        7: 
        begin 
          led<=~rdata[7:4];
        end 
	endcase
//assign led=rdata[3:0];
endmodule

验证很简单,通过led指示灯变化来判断数据是否对。上电测试结果正确。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值