使用verilog完成对IIC总线的编写,采用三段式状态机,完成测试

一、IIC总线开始状态
IIC开始状态
IIC总线开始状态应该是SCL在高电平的期间,SDA出现下降沿,表示为开始状态

二、IIC总线结束状态
IIC结束状态
IIC总线结束状态应该是在SCL为高电平期间,SDA出现上升沿,表示结束状态

三、数据传输状态

写数据状态
在这里插入图片描述
读数据状态

总线数据传输
IIC总线对于数据传输的要求为在SCL为低电平的情况下进行数据的改变,因此为了避免产生误差,选择在SCL低电平的中间位置进行数据的写入,在SCL为高电平的时候进行数据的保持

四、读写状态的状态转换图
写状态状态转移图
读状态状态转移图
五、测试结果

写状态开始状态
写状态开始状态
写状态写入从机地址
写状态写入从机地址
写状态写入寄存器地址
写状态写入寄存器地址
写状态写入数据
写状态写入数据
写状态停止状态
写状态停止状态
读状态第一个开始信号
读状态第一个开始信号
读状态第一次写从机地址
读状态第一次写从机地址
读状态写入寄存器地址
读状态写入寄存器地址
读状态第一次停止
读状态第一次停止
读状态第二次开始
读状态第二次开始
读状态第二次写入从机地址
读状态第二次写入从机地址]
读状态读数据
读状态读数据
读状态第二次停止
读状态第二次停止
测试过程中我选择的从机地址是7’h3c,寄存器地址是8‘h00,写入的数据是8’h10,根据测试结果可以看到不仅成功的将数据写入到了寄存器之中,并且将写入的数据读取了出来,完成了整体的设计

六、代码

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2021/09/14 19:45:40
// Design Name: 
// Module Name: IIC_CODE
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module IIC_Code(

	input wire clk_i,
	input wire rst_i,
	input wire send_i,					//IIC开始信号
	input wire wr_i,					//读写控制信号,1为写,0为读
	input wire [6:0] Slv_Addr_i,			//从机的地址数据
	input wire [7:0] Reg_Addr_i,			//寄存器的地址数据
	input wire [7:0] Data_i,				//将要写入的数据
	output reg IIC_Busy_o,				//IIC工作标志信号
	output reg [7:0] IIC_Read_Data_o,		//IIC读出来的数据
	inout wire sda,
	inout wire scl
    );

parameter DIV = 2500;					//分频计数器的分频系数
parameter T1 = DIV / 4;					//第一个标志位
parameter T2 = DIV *3/4;				//第二个标志位

reg [11:0] cnt_clk;						//clk计数器
reg [3:0] cnt_scl;						//scl计数器,表示传送数据的位数
reg sda_tri;							//三态控制信号
reg sda_o;								//sda总线传输数据的寄存器
reg scl_o;								//scl时钟总线
reg [4:0] current_state;				//当前状态
reg [4:0] next_state;					//下个状态

assign sda = sda_tri ? 1'bz : sda_o;
assign scl = scl_o;

parameter IDLE 			= 5'd0;
parameter W_START 		= 5'd1;
parameter W_SLV_ADDR 	= 5'd2;
parameter W_WR 			= 5'd3;
parameter W_ACK1 		= 5'd4;
parameter W_REG_ADDR 	= 5'd5;
parameter W_ACK2 		= 5'd6;
parameter W_DATA 		= 5'd7;
parameter W_ACK3 		= 5'd8;
parameter W_STOP 		= 5'd9;
parameter R_START1 		= 5'd10;
parameter R_SLV_ADDR1	= 5'd11;
parameter R_WR1			= 5'd12;
parameter R_ACK1		= 5'd13;
parameter R_REG_ADDR	= 5'd14;
parameter R_ACK2		= 5'd15;
parameter R_STOP1		= 5'd16;
parameter R_START2		= 5'd17;
parameter R_SLV_ADDR2	= 5'd18;
parameter R_WR2			= 5'd19;
parameter R_ACK3		= 5'd20;
parameter R_DATA 		= 5'd21;
parameter R_ACK4		= 5'd22;
parameter R_STOP2		= 5'd23;

always@(posedge clk_i)
begin 
	if(rst_i == 1'b1)
		current_state <= IDLE;
	else
		current_state <= next_state;
end

always@(*)
begin
	case(current_state)
		IDLE:
			begin
				if((send_i == 1'b1) && (wr_i == 1'b1))
					next_state <= W_START;
				else if((send_i == 1'b1) && (wr_i == 1'b0))
					next_state <= R_START1;
				else
					next_state <= current_state;
			end
		W_START:
			begin
				if(cnt_clk == 12'b0)
					next_state <= W_SLV_ADDR;
				else
					next_state <= current_state;
			end
		W_SLV_ADDR:
			begin
				if((cnt_clk == 12'b0) && (cnt_scl == 4'b0111))
					next_state <= W_WR;
				else
					next_state <= current_state;
			end
		W_WR:
			begin
				if(cnt_clk == 12'b0)
					next_state <= W_ACK1;
				else
					next_state <= current_state;
			end
		W_ACK1:
			begin
				if(cnt_clk == 12'b0)
					next_state <= W_REG_ADDR;
				else
					next_state <= current_state;
			end
		W_REG_ADDR:
			begin
				if((cnt_clk == 12'b0) && (cnt_scl == 4'b1000))
					next_state <= W_ACK2;
				else
					next_state <= current_state;
			end
		W_ACK2:
			begin
				if(cnt_clk == 12'b0)
					next_state <= W_DATA;
				else
					next_state <= current_state;
			end
		W_DATA:
			begin
				if((cnt_clk == 12'b0) && (cnt_scl == 4'b1000))
					next_state <= W_ACK3;
				else
					next_state <= current_state;
			end
		W_ACK3:
			begin
				if(cnt_clk == 12'b0)
					next_state <= W_STOP;
				else
					next_state <= current_state;
			end
		W_STOP:
			begin
				if(cnt_clk == 12'b0)
					next_state <= IDLE;
				else
					next_state <= current_state;
			end
		R_START1:
			begin
				if(cnt_clk == 12'b0)
					next_state <= R_SLV_ADDR1;
				else
					next_state <= current_state;
			end
		R_SLV_ADDR1:
			begin
				if((cnt_clk == 12'b0) && (cnt_scl == 4'b0111))
					next_state <= R_WR1;
				else
					next_state <= current_state;
			end
		R_WR1:
			begin
				if(cnt_clk == 12'b0)
					next_state <= R_ACK1;
				else
					next_state <= current_state;
			end
		R_ACK1:
			begin
				if(cnt_clk == 12'b0)
					next_state <= R_REG_ADDR;
				else
					next_state <= current_state;
			end
		R_REG_ADDR:
			begin
				if((cnt_clk == 12'b0) && (cnt_scl == 4'b1000))
					next_state <= R_ACK2;
				else
					next_state <= current_state;
			end
		R_ACK2:
			begin
				if(cnt_clk == 12'b0)
					next_state <= R_STOP1;
				else
					next_state <= current_state;
			end
		R_STOP1:
			begin
				if(cnt_clk == 12'b0)
					next_state <= R_START2;
				else
					next_state <= current_state;
			end
		R_START2:
			begin
				if(cnt_clk == 12'b0)
					next_state <= R_SLV_ADDR2;
				else
					next_state <= current_state;
			end
		R_SLV_ADDR2:
			begin
				if((cnt_clk == 12'b0) && (cnt_scl == 4'b0111))
					next_state <= R_WR2;
				else
					next_state <= current_state;
			end
		R_WR2:
			begin
				if(cnt_clk == 12'b0)
					next_state <= R_ACK3;
				else
					next_state <= current_state;
			end
		R_ACK3:
			begin
				if(cnt_clk == 12'b0)
					next_state <= R_DATA;
				else
					next_state <=current_state;
			end
		R_DATA:
			begin
				if((cnt_clk == 12'b0) && (cnt_scl == 4'b1000))
					next_state <= R_ACK4;
				else
					next_state <= current_state;
			end
		R_ACK4:
			begin
				if(cnt_clk == 12'b0)
					next_state <= R_STOP2;
				else
					next_state <= current_state;
			end
		R_STOP2:
			begin
				if(cnt_clk == 12'b0)
					next_state <= IDLE;
				else
					next_state <= current_state;
			end
		default: next_state <= IDLE;
	endcase 
end

always@(posedge clk_i)
begin
	if(rst_i == 1'b1)
		begin
			sda_tri 	<= 1'b0;
			scl_o 		<= 1'b1;
			sda_o 		<= 1'b1;
			cnt_clk 	<= 12'b0;
			IIC_Busy_o 	<= 1'b0;
			cnt_scl 	<= 4'b0;
		end
	else 
		begin
			case (next_state)
				IDLE:
					begin
						sda_tri 	<= 1'b0;
						scl_o 		<= 1'b1;
						sda_o 		<= 1'b1;
						cnt_clk 	<= 12'b0;
						IIC_Busy_o 	<= 1'b0;
						cnt_scl 	<= 4'b0;
					end
				W_START:
					begin
						sda_tri 	<= 1'b0;
						scl_o 		<= (cnt_clk<T2) ? 1'b1 : 1'b0; 
						sda_o 		<= (cnt_clk<T1) ? 1'b1 : 1'b0; 
						cnt_clk 	<= (cnt_clk>=DIV-1) ? 0 : cnt_clk+1;
						IIC_Busy_o 	<= 1'b1;
						cnt_scl 	<= 4'b0;
					end
				W_SLV_ADDR:
					begin
						sda_tri 	<= 1'b0;
						scl_o 		<= (cnt_clk<T1) ? 1'b0 : (cnt_clk<T2 ? 1'b1 : 1'b0); 
						sda_o 		<= Slv_Addr_i[6-cnt_scl]; 
						IIC_Busy_o 	<= 1'b1; 
						cnt_clk 	<= (cnt_clk>=DIV-1) ? 0 : cnt_clk+1; 
						cnt_scl 	<= (cnt_clk>=DIV-1) ? cnt_scl+ 1 : cnt_scl;
					end
				W_WR:
					begin
						sda_tri 	<= 1'b0;
						scl_o 		<= (cnt_clk<T1) ? 1'b0 : (cnt_clk<T2 ? 1'b1 : 1'b0); 
						sda_o 		<= 1'b0;
						IIC_Busy_o 	<= 1'b1;
						cnt_clk 	<= (cnt_clk>=DIV-1) ? 0 : cnt_clk+1;
						cnt_scl 	<= 4'b0;
					end
				W_ACK1:
					begin
						sda_tri 	<= 1'b1;
						scl_o 		<= (cnt_clk<T1) ? 1'b0 : (cnt_clk<T2 ? 1'b1 : 1'b0); 
						IIC_Busy_o 	<= 1'b1;
						cnt_clk 	<= (cnt_clk>=DIV-1) ? 0 : cnt_clk+1;
						cnt_scl 	<= 4'b0;
					end
				W_REG_ADDR:
					begin
						sda_tri 	<= 1'b0;
						scl_o 		<= (cnt_clk<T1) ? 1'b0 : (cnt_clk<T2 ? 1'b1 : 1'b0); 
						sda_o 		<= Reg_Addr_i[7- cnt_scl];
						IIC_Busy_o 	<= 1'b1;
						cnt_clk 	<= (cnt_clk>=DIV-1) ? 0 : cnt_clk+1;
						cnt_scl 	<= (cnt_clk>=DIV-1) ? cnt_scl+ 1 : cnt_scl;
					end
				W_ACK2:
					begin
						sda_tri 	<= 1'b1;
						scl_o 		<= (cnt_clk<T1) ? 1'b0 : (cnt_clk<T2 ? 1'b1 : 1'b0); 
						IIC_Busy_o 	<= 1'b1;
						cnt_clk 	<= (cnt_clk>=DIV-1) ? 0 : cnt_clk+1;
						cnt_scl 	<= 4'b0;
					end
				W_DATA:
					begin
						sda_tri 	<= 1'b0;
						scl_o 		<= (cnt_clk<T1) ? 1'b0 : (cnt_clk<T2 ? 1'b1 : 1'b0); 
						sda_o 		<= Data_i[7- cnt_scl];
						IIC_Busy_o 	<= 1'b1;
						cnt_clk 	<= (cnt_clk>=DIV-1) ? 0 : cnt_clk+1;
						cnt_scl 	<= (cnt_clk>=DIV-1) ? cnt_scl+ 1 : cnt_scl;
					end
				W_ACK3:
					begin
						sda_tri 	<= 1'b1;
						scl_o 		<= (cnt_clk<T1) ? 1'b0 : (cnt_clk<T2 ? 1'b1 : 1'b0);  
						IIC_Busy_o 	<= 1'b1;
						cnt_clk 	<= (cnt_clk>=DIV-1) ? 0 : cnt_clk+1;
						cnt_scl 	<= 4'b0;
					end
				W_STOP:
					begin
						sda_tri 	<= 1'b0;
						scl_o 		<= (cnt_clk<T1) ? 1'b0 : 1'b1; 
						sda_o 		<= (cnt_clk<T2) ? 1'b0 : 1'b1; 
						IIC_Busy_o 	<= 1'b1;
						cnt_clk 	<= (cnt_clk>=DIV-1) ? 0 : cnt_clk+1;
						cnt_scl 	<= 4'b0;
					end
				R_START1:
					begin
						sda_tri 	<= 1'b0;
						scl_o 		<= (cnt_clk<T2) ? 1'b1 : 1'b0; 
						sda_o 		<= (cnt_clk<T1) ? 1'b1 : 1'b0; 
						cnt_clk 	<= (cnt_clk>=DIV-1) ? 0 : cnt_clk+1;
						IIC_Busy_o 	<= 1'b1;
						cnt_scl 	<= 4'b0;
					end
				R_SLV_ADDR1:
					begin
						sda_tri 	<= 1'b0;
						scl_o 		<= (cnt_clk<T1) ? 1'b0 : (cnt_clk<T2 ? 1'b1 : 1'b0); 
						sda_o 		<= Slv_Addr_i[6-cnt_scl]; 
						IIC_Busy_o 	<= 1'b1; 
						cnt_clk 	<= (cnt_clk>=DIV-1) ? 0 : cnt_clk+1; 
						cnt_scl 	<= (cnt_clk>=DIV-1) ? cnt_scl+ 1 : cnt_scl;
					end
				R_WR1:
					begin
						sda_tri 	<= 1'b0;
						scl_o 		<= (cnt_clk<T1) ? 1'b0 : (cnt_clk<T2 ? 1'b1 : 1'b0); 
						sda_o 		<= 1'b0;
						IIC_Busy_o 	<= 1'b1;
						cnt_clk 	<= (cnt_clk>=DIV-1) ? 0 : cnt_clk+1;
						cnt_scl 	<= 4'b0;
					end
				R_ACK1:
					begin
						sda_tri 	<= 1'b1;
						scl_o 		<= (cnt_clk<T1) ? 1'b0 : (cnt_clk<T2 ? 1'b1 : 1'b0); 
						IIC_Busy_o 	<= 1'b1;
						cnt_clk 	<= (cnt_clk>=DIV-1) ? 0 : cnt_clk+1;
						cnt_scl 	<= 4'b0;
					end
				R_REG_ADDR:
					begin
						sda_tri 	<= 1'b0;
						scl_o 		<= (cnt_clk<T1) ? 1'b0 : (cnt_clk<T2 ? 1'b1 : 1'b0); 
						sda_o 		<= Reg_Addr_i[7- cnt_scl];
						IIC_Busy_o 	<= 1'b1;
						cnt_clk 	<= (cnt_clk>=DIV-1) ? 0 : cnt_clk+1;
						cnt_scl 	<= (cnt_clk>=DIV-1) ? cnt_scl+ 1 : cnt_scl;
					end
				R_ACK2:
					begin
						sda_tri 	<= 1'b1;
						scl_o 		<= (cnt_clk<T1) ? 1'b0 : (cnt_clk<T2 ? 1'b1 : 1'b0); 
						IIC_Busy_o 	<= 1'b1;
						cnt_clk 	<= (cnt_clk>=DIV-1) ? 0 : cnt_clk+1;
						cnt_scl 	<= 4'b0;
					end
				R_STOP1:
					begin
						sda_tri 	<= 1'b0;
						scl_o 		<= (cnt_clk<T1) ? 1'b0 : 1'b1; 
						sda_o 		<= (cnt_clk<T2) ? 1'b0 : 1'b1; 
						IIC_Busy_o 	<= 1'b1;
						cnt_clk 	<= (cnt_clk>=DIV-1) ? 0 : cnt_clk+1;
						cnt_scl 	<= 4'b0;
					end
				R_START2:
					begin
						sda_tri 	<= 1'b0;
						scl_o 		<= (cnt_clk<T2) ? 1'b1 : 1'b0; 
						sda_o 		<= (cnt_clk<T1) ? 1'b1 : 1'b0; 
						cnt_clk 	<= (cnt_clk>=DIV-1) ? 0 : cnt_clk+1;
						IIC_Busy_o 	<= 1'b1;
						cnt_scl 	<= 4'b0;
					end
				R_SLV_ADDR2:
					begin
						sda_tri 	<= 1'b0;
						scl_o 		<= (cnt_clk<T1) ? 1'b0 : (cnt_clk<T2 ? 1'b1 : 1'b0); 
						sda_o 		<= Slv_Addr_i[6-cnt_scl]; 
						IIC_Busy_o 	<= 1'b1; 
						cnt_clk 	<= (cnt_clk>=DIV-1) ? 0 : cnt_clk+1; 
						cnt_scl 	<= (cnt_clk>=DIV-1) ? cnt_scl+ 1 : cnt_scl;
					end
				R_WR2:
					begin
						sda_tri 	<= 1'b0;
						scl_o 		<= (cnt_clk<T1) ? 1'b0 : (cnt_clk<T2 ? 1'b1 : 1'b0); 
						sda_o 		<= 1'b1;
						IIC_Busy_o 	<= 1'b1;
						cnt_clk 	<= (cnt_clk>=DIV-1) ? 0 : cnt_clk+1;
						cnt_scl 	<= 4'b0;
					end
				R_ACK3:
					begin
						sda_tri 	<= 1'b1;
						scl_o 		<= (cnt_clk<T1) ? 1'b0 : (cnt_clk<T2 ? 1'b1 : 1'b0); 
						IIC_Busy_o 	<= 1'b1;
						cnt_clk 	<= (cnt_clk>=DIV-1) ? 0 : cnt_clk+1;
						cnt_scl 	<= 4'b0;
					end
				R_DATA:
					begin
						sda_tri 	<= 1'b1;
						scl_o 		<= (cnt_clk<T1) ? 1'b0 : (cnt_clk<T2 ? 1'b1 : 1'b0); 
						IIC_Busy_o 	<= 1'b1;
						cnt_clk 	<= (cnt_clk>=DIV-1) ? 0 : cnt_clk+1;
						cnt_scl 	<= (cnt_clk==DIV/2-1) ? cnt_scl+ 1 : cnt_scl;
						case(cnt_scl)
							4'b0000: IIC_Read_Data_o[7] <= sda;
							4'b0001: IIC_Read_Data_o[6] <= sda;
							4'b0010: IIC_Read_Data_o[5] <= sda;
							4'b0011: IIC_Read_Data_o[4] <= sda;
							4'b0100: IIC_Read_Data_o[3] <= sda;
							4'b0101: IIC_Read_Data_o[2] <= sda;
							4'b0110: IIC_Read_Data_o[1] <= sda;
							4'b0111: IIC_Read_Data_o[0] <= sda;
							default: ;
						endcase
					end
				R_ACK4:
					begin
						sda_tri 	<= 1'b1;
						scl_o 		<= (cnt_clk<T1) ? 1'b0 : (cnt_clk<T2 ? 1'b1 : 1'b0); 
						IIC_Busy_o 	<= 1'b1;
						cnt_clk 	<= (cnt_clk>=DIV-1) ? 0 : cnt_clk+1;
						cnt_scl 	<= 4'b0;
					end
				R_STOP2:
					begin
						sda_tri 	<= 1'b0;
						scl_o 		<= (cnt_clk<T1) ? 1'b0 : 1'b1; 
						sda_o 		<= (cnt_clk<T2) ? 1'b0 : 1'b1; 
						IIC_Busy_o 	<= 1'b1;
						cnt_clk 	<= (cnt_clk>=DIV-1) ? 0 : cnt_clk+1;
						cnt_scl 	<= 4'b0;
					end
				default : 
							begin
								sda_tri    <= 1'b0;
								scl_o      <= 1'b1;
								sda_o      <= 1'b1;
								cnt_clk    <= 12'b0;
								IIC_Busy_o <= 1'b0;
								cnt_scl    <= 4'b0;
							end
			endcase
		end
end


endmodule

  • 5
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值