赞
踩
I²C(Inter-Integrated Circuit)即集成电路总线,它其实是I²C Bus简称,所以中文应该叫集成电路总线,它是一种串行通信总线,使用多主从架构,由飞利浦公司在1980年代为了让主板、嵌入式系统或手机用以连接低速周边设备而发展。I²C的正确读法为“I平方C”("I-squared-C"),而“I二C”("I-two-C")则是另一种错误但被广泛使用的读法。自2006年10月1日起,使用I²C协议已经不需要支付专利费,但制造商仍然需要付费以获取I²C从属设备地址。--------维基百科
一、
1.1
1.2 位传输
由于连接到
1.2.1 数据的有效性
SDA线上的数据必须在时钟的高电平周期保持稳定。数据线的高或低电平状态只有在SCL线的时钟信号是低电平时才能改变。
图2中给出了SDA上数据何时改变的示意图,由图可知,在SCL高电平期间,数据必须保持稳定;在SCL为低电平期间,才允许SDA上数据发生改变。
1.2.2 起始和停止条件
起始条件:在SCL为高电平器件,SDA由高电平跳变为低电平,此情况表示起始条件。
停止条件:在SCL为高电平期间,SDA由低电平跳变为高电平,此情况表示停止条件。
起始条件和停止条件一般由主机产生。起始条件和停止条件如图3所示:
图3中S表示起始条件,此时,SCL为高电平,SDA由高电平跳变为低电平;P表示结束条件,此时,SCL为高电平,由低电平跳变为高电平。
1.2.3 数据发送过程
在检测到起始条件后,接下来可以进行数据的发送,发送到SDA线上的每个字节必须为8位。每次传输可以发送的字节数量不受限制。每个字节后必须跟一个响应信号。首先传输的是数据的最高位。
响应:在一个字节发送完毕后后面必须跟一个响应信号。想关的响应时钟脉冲由主机产生。在响应的时钟脉冲期间,主机释放SDA线(此时SDA为输入类型),此时若从机发通过SDA数据线传入一个低电平,则从机响应;从机相应后可以继续进行数据的传输,若不在进行数据传输,此时只需要在从机响应后主机再产生一个停止信号即可。
图4中通过是
二、IIC总线数据发送的VERILOG描述
由图4可知,IIC发送数据的过程包括以下步骤:1、主控器发送开始信号—>2、主控器发送8位命令—>3、被控器应答—>4、主控器发送8位数据—>5、被控器应答—>6、主控器发送结束信号(如果还有数据要发送只需继续重复步骤4和5,待所有数据发送完后执行步骤6)。因此,IIC协议发送过程有明显的先后顺序关系,可以使用状态机来描述数据发送的整个过程。
对应的状态机如图5所示:
在复位信号rst有效时进入IDLE状态,在IDLE状态,初始化SCL、SDA以及SDA_link(控制SDA是输入还是输出);IIC发送数据开始信号wr_en有效时,进入START状态,在该状态产生IIC发送数据的起始条件start(SCL为高时,SDA由高变为低);start有效时,进入ADDR0,在该状态,加载待发送的8位地址,并将最高位发送出去,i用来计数发送几个地址的第几位(由于SCL是i计数器的时钟的2分频,因此这里使用ADDR1和ADDR2这两个状态来完成数据的发送,ADDR1发送数据,ADDR2无操作);当8个地址发送完毕后,进入ACK1 状态,此状态,主机释放SDA,从机给出应答信号,并加载下一次待发送的数据;DATA0和DATA1用来实现8位数据信号的发送,DATA0状态对数据无操作,DATA1状态发送数据,当数据发送完毕后即i=16,进入ACK2状态,此时,主机释放SDA,从机给出应答;i=0时,进入STOP状态,该状态用于产生IIC发送数据的结束条件stop(SCL 为高时,SDA由低跳变为高);stop信号有效时进入DONE状态,表示数据发送完成,拉高done信号,然后进入IDLE状态,等待下一次数据的发送。
verilog描述如下所示:
I2C_MODULE:使用三段式状态机描述IIC数据发送过程,主要生成控制信号;同时例化实现过程中所需要的电路。
- module I2C_MODULE(input clk_50m,
- input clk_in,/用来同步SDA,使其在SCL低电平改变
- input rst_n,
- input wr_en,
- input [7:0]addr_in,
- input [7:0]data_in,
- output reg done,
- inout SDA,
- output SCL,
- output reg ack1,///仿真信号
- output reg ack2仿真信号
- );
- wire [4:0] i;
- wire sda_r;
- reg load_a;/SCl空闲时加载数据
- reg en_a;/产生SCL
- reg load_b;///加载待发送地址
- reg en_b;///地址移位寄存器使能
- reg load_c;///计数器加载数据
- reg en_c;计数器计数
- reg load_d;///加载待发送数据
- reg en_d;
- reg SDA_link;//1时SDA为输出,0时为输入
- reg sad_load;///sda_r空闲时加载数据
- reg sda_en_addr;//将地址赋值给sda_r
- reg sda_en_data;//将数据赋值给sda_r
- reg start;
- reg stop;
- //reg ack1;应答信号给ack1
- //reg ack2;///应答信号给ack2
- reg SDA_R = 'd0;
- assign SDA = SDA_link?SDA_R:1'b0/*Z*/;///实际应为z,为仿真方便设置为0
- always @(posedge clk_in)
- SDA_R <= sda_r;
- parameter [10:0]IDLE = 11'b000_0000_0001;
- parameter [10:0]STRAT = 11'b000_0000_0010;
- parameter [10:0]ADDR0 = 11'b000_0000_0100;加载待发送地址
- parameter [10:0]ADDR1 = 11'b000_0000_1000;/发送地址
- parameter [10:0]ADDR2 = 11'b000_0001_0000;/保持地址
- parameter [10:0]ACK1 = 11'b000_0010_0000;
- parameter [10:0]DATA0 = 11'b000_0100_0000;///加载待发送数据
- parameter [10:0]DATA1 = 11'b000_1000_0000;///发送数据
- parameter [10:0]ACK2 = 11'b001_0000_0000;///应答
- parameter [10:0]STOP = 11'b010_0000_0000;
- parameter [10:0]DONE = 11'b100_0000_0000;
- //parameter [11:0]DATA2 = 'b0001_0000_0000;///保持数据
- //parameter [11:0]ACK2 = 'b0010_0000_0000;
- //parameter [11:0]STOP = 'b0100_0000_0000;
- //parameter [11:0]DONE = 'b1000_0000_0000;
- reg [10:0]current_state = 'd0;
- reg [10:0]next_state = 'd0;
- 次态转移
- always @(posedge clk_50m or negedge rst_n)
- if(!rst_n)
- current_state <= IDLE;
- else
- current_state <= next_state;
- 状态跳变
- always @(*)
- case(current_state)
- IDLE: begin
- if(wr_en)
- next_state = STRAT;
- else
- next_state = IDLE;
- end
- STRAT: begin
- if(start)
- next_state = ADDR0;
- else
- next_state = STRAT;
- end
- ADDR0: begin
- if(i == 'd1)
- next_state = ADDR1;
- else
- next_state = ADDR0;
- end
- ADDR1: begin
- if(i == 'd16)
- next_state = ACK1;
- else if(i[0] == 'b0)//i为偶数
- next_state = ADDR2;
- else
- next_state = ADDR1;
- end
- ADDR2: begin
- if(i[0] == 'b1)
- next_state = ADDR1;
- else
- next_state = ADDR2;
- end
- ACK1: begin//ack1应答,同时将待发送的数据加载进移位寄存器
- if(i == 'd0)
- next_state = DATA0;
- else
- next_state = ACK1;
- end
- DATA0: begin
- if(i[0] == 'd1)
- next_state = DATA1;
- else
- next_state = DATA0;
- end
- DATA1: begin
- if(i == 'd16)
- next_state = ACK2;
- else if(i[0] == 'b0)
- next_state = DATA0;
- else
- next_state = DATA1;
- end
- ACK2: begin
- if(i == 'd0)
- next_state = STOP;
- else
- next_state = ACK2;
- end
- STOP: begin
- if(stop)
- next_state = DONE;
- else
- next_state = STOP;
- end
- DONE: begin
- if(done)
- next_state = IDLE;
- else
- next_state = DONE;
- end
- default: begin
- next_state = IDLE;
- end
- endcase
- //输出赋值
- always @(*)
- case(current_state)
- IDLE: begin
- load_a = 'd1;/SCl空闲时加载数据,初始化SCL
- en_a = 'd0;
- load_b = 'd0;///加载待发送地址
- en_b = 'd0;
- load_c = 'd1;///计数器加载数据
- en_c = 'd0;
- load_d = 'd0;///加载待发送地址
- en_d = 'd0;
- SDA_link = 'd1;//1时SDA为输出,0时为输入
- sad_load = 'd1;///sda_r空闲时加载数据,初始化SDA
- sda_en_addr = 'd0;//将地址赋值给sda_r
- // sda_en_ack1 = 'd0;//ack1时给sda_r赋值
- sda_en_data = 'd0;//将数据赋值给sda_r
- // sda_en_ack2 = 'd0;//ack2时给sda_r赋值
- start = 'd0;
- stop = 'd0;
- done = 'd0;
- ack1 = 'd0;
- ack2 = 'd0;
- end
- STRAT: begin
- load_a = 'd1;/SCl空闲时加载数据
- en_a = 'd0;
- load_b = 'd0;///加载待发送地址
- en_b = 'd0;
- load_c = 'd1;///计数器加载数据
- en_c = 'd0;
- load_d = 'd0;///加载待发送地址
- en_d = 'd0;
- SDA_link = 'd1;//1时SDA为输出,0时为输入
- sad_load = 'd1;///sda_r空闲时加载数据
- sda_en_addr = 'd0;//将地址赋值给sda_r
- // sda_en_ack1 = 'd0;//ack1时给sda_r赋值
- sda_en_data = 'd0;//将数据赋值给sda_r
- // sda_en_ack2 = 'd0;//ack2时给sda_r赋值
- start = 'd1;
- stop = 'd0;
- done = 'd0;
- ack1 = 'd0;
- ack2 = 'd0;
- end
- ADDR0: begin
- load_a = 'd0;/SCl空闲时加载数据
- en_a = 'd1;
- load_b = 'd1;///加载待发送地址
- en_b = 'd0;
- load_c = 'd0;///计数器加载数据
- en_c = 'd1;
- load_d = 'd0;///加载待发送地址
- en_d = 'd0;
- SDA_link = 'd1;//1时SDA为输出,0时为输入
- sad_load = 'd0;///sda_r空闲时加载数据
- sda_en_addr = 'd1;//将地址赋值给sda_r
- // sda_en_ack1 = 'd0;//ack1时给sda_r赋值
- sda_en_data = 'd0;//将数据赋值给sda_r
- // sda_en_ack2 = 'd0;//ack2时给sda_r赋值
- start = 'd0;
- stop = 'd0;
- done = 'd0;
- ack1 = 'd0;
- ack2 = 'd0;
- end
- ADDR1: begin
- load_a = 'd0;/SCl空闲时加载数据
- en_a = 'd1;/产生SCL
- load_b = 'd0;///加载待发送地址
- en_b = 'd1;///地址移位寄存器使能
- load_c = 'd0;///计数器加载数据
- en_c = 'd1;计数器计数
- load_d = 'd0;///加载待发送地址
- en_d = 'd0;
- SDA_link = 'd1;//1时SDA为输出,0时为输入
- sad_load = 'd0;///sda_r空闲时加载数据
- sda_en_addr = 'd1;//将地址赋值给sda_r
- // sda_en_ack1 = 'd0;//ack1时给sda_r赋值
- sda_en_data = 'd0;//将数据赋值给sda_r
- // sda_en_ack2 = 'd0;//ack2时给sda_r赋值
- start = 'd0;
- stop = 'd0;
- done = 'd0;
- ack1 = 'd0;
- ack2 = 'd0;
- end
- ADDR2: begin
- load_a = 'd0;/SCl空闲时加载数据
- en_a = 'd1;/产生SCL
- load_b = 'd0;///加载待发送地址
- en_b = 'd0;///地址移位寄存器使能
- load_c = 'd0;///计数器加载数据
- en_c = 'd1;计数器计数
- load_d = 'd0;///加载待发送地址
- en_d = 'd0;
- SDA_link = 'd1;//1时SDA为输出,0时为输入
- sad_load = 'd0;///sda_r空闲时加载数据
- sda_en_addr = 'd1;//将地址赋值给sda_r
- // sda_en_ack1 = 'd0;//ack1时给sda_r赋值
- sda_en_data = 'd0;//将数据赋值给sda_r
- // sda_en_ack2 = 'd0;//ack2时给sda_r赋值
- start = 'd0;
- stop = 'd0;
- done = 'd0;
- ack1 = 'd0;
- ack2 = 'd0;
- end
- ACK1: begin
- load_a = 'd0;/SCl空闲时加载数据
- en_a = 'd1;/产生SCL
- load_b = 'd0;///加载待发送地址
- en_b = 'd0;///地址移位寄存器使能
- load_c = 'd0;///计数器加载数据
- en_c = 'd1;计数器计数
- load_d = 'd1;///加载待发送数据
- en_d = 'd0;
- SDA_link = 'd0;//1时SDA为输出,0时为输入
- sad_load = 'd0;///sda_r空闲时加载数据
- sda_en_addr = 'd0;//将地址赋值给sda_r
- // sda_en_ack1 = 'd0;//ack1时给sda_r赋值
- sda_en_data = 'd0;//将数据赋值给sda_r
- // sda_en_ack2 = 'd0;//ack2时给sda_r赋值
- start = 'd0;
- stop = 'd0;
- done = 'd0;
- ack1 = !SDA;应答信号给ack1
- ack2 = 'd0;
- end
- DATA0: begin
- load_a = 'd0;/SCl空闲时加载数据
- en_a = 'd1;/产生SCL
- load_b = 'd0;///加载待发送地址
- en_b = 'd0;///地址移位寄存器使能
- load_c = 'd0;///计数器加载数据
- en_c = 'd1;计数器计数
- load_d = 'd0;///加载待发送数据
- en_d = 'd0;
- SDA_link = 'd1;//1时SDA为输出,0时为输入
- sad_load = 'd0;///sda_r空闲时加载数据
- sda_en_addr = 'd0;//将地址赋值给sda_r
- // sda_en_ack1 = 'd0;//ack1时给sda_r赋值
- sda_en_data = 'd1;//将数据赋值给sda_r
- // sda_en_ack2 = 'd0;//ack2时给sda_r赋值
- start = 'd0;
- stop = 'd0;
- done = 'd0;
- ack1 = 'd0;应答信号给ack1
- ack2 = 'd0;
- end
- DATA1: begin
- load_a = 'd0;/SCl空闲时加载数据
- en_a = 'd1;/产生SCL
- load_b = 'd0;///加载待发送地址
- en_b = 'd0;///地址移位寄存器使能
- load_c = 'd0;///计数器加载数据
- en_c = 'd1;计数器计数
- load_d = 'd0;///加载待发送数据
- en_d = 'd1;
- SDA_link = 'd1;//1时SDA为输出,0时为输入
- sad_load = 'd0;///sda_r空闲时加载数据
- sda_en_addr = 'd0;//将地址赋值给sda_r
- // sda_en_ack1 = 'd0;//ack1时给sda_r赋值
- sda_en_data = 'd1;//将数据赋值给sda_r
- // sda_en_ack2 = 'd0;//ack2时给sda_r赋值
- start = 'd0;
- stop = 'd0;
- done = 'd0;
- ack1 = 'd0;应答信号给ack1
- ack2 = 'd0;
- end
- ACK2: begin/应答后由于之后产生stop信号,所以此时应该就让SCL处于空闲状态;
- load_a = 'd1;/SCl空闲时加载数据
- en_a = 'd0;/产生SCL
- load_b = 'd0;///加载待发送地址
- en_b = 'd0;///地址移位寄存器使能
- load_c = 'd0;///计数器加载数据
- en_c = 'd1;计数器计数
- load_d = 'd0;///加载待发送数据
- en_d = 'd0;
- SDA_link = 'd0;//1时SDA为输出,0时为输入
- sad_load = 'd0;///sda_r空闲时加载数据
- sda_en_addr = 'd0;//将地址赋值给sda_r
- // sda_en_ack1 = 'd0;//ack1时给sda_r赋值
- sda_en_data = 'd1;//将数据赋值给sda_r
- // sda_en_ack2 = 'd0;//ack2时给sda_r赋值
- start = 'd0;
- stop = 'd0;
- done = 'd0;
- ack1 = 'd0;应答信号给ack1
- ack2 = !SDA;///应答信号给ack2
- end
- STOP: begin
- load_a = 'd1;/SCl空闲时加载数据
- en_a = 'd0;/产生SCL
- load_b = 'd0;///加载待发送地址
- en_b = 'd0;///地址移位寄存器使能
- load_c = 'd1;///计数器加载数据
- en_c = 'd0;计数器计数
- load_d = 'd0;///加载待发送数据
- en_d = 'd0;
- SDA_link = 'd1;//1时SDA为输出,0时为输入
- sad_load = 'd1;///sda_r空闲时加载数据
- sda_en_addr = 'd0;//将地址赋值给sda_r
- // sda_en_ack1 = 'd0;//ack1时给sda_r赋值
- sda_en_data = 'd0;//将数据赋值给sda_r
- // sda_en_ack2 = 'd0;//ack2时给sda_r赋值
- start = 'd0;
- stop = 'd1;
- done = 'd0;
- ack1 = 'd0;应答信号给ack1
- ack2 = 'd0;///应答信号给ack2
- end
- DONE: begin
- load_a = 'd1;/SCl空闲时加载数据
- en_a = 'd0;/产生SCL
- load_b = 'd0;///加载待发送地址
- en_b = 'd0;///地址移位寄存器使能
- load_c = 'd1;///计数器加载数据
- en_c = 'd0;计数器计数
- load_d = 'd0;///加载待发送数据
- en_d = 'd0;
- SDA_link = 'd1;//1时SDA为输出,0时为输入
- sad_load = 'd1;///sda_r空闲时加载数据
- sda_en_addr = 'd0;//将地址赋值给sda_r
- // sda_en_ack1 = 'd0;//ack1时给sda_r赋值
- sda_en_data = 'd0;//将数据赋值给sda_r
- // sda_en_ack2 = 'd0;//ack2时给sda_r赋值
- start = 'd0;
- stop = 'd0;
- done = 'd1;
- ack1 = 'd0;应答信号给ack1
- ack2 = 'd0;///应答信号给ack2
- end
- default: begin
- load_a = 'd1;/SCl空闲时加载数据
- en_a = 'd0;
- load_b = 'd0;///加载待发送地址
- en_b = 'd0;
- load_c = 'd1;///计数器加载数据
- en_c = 'd0;
- load_d = 'd0;///加载待发送地址
- en_d = 'd0;
- SDA_link = 'd1;//1时SDA为输出,0时为输入
- sad_load = 'd1;///sda_r空闲时加载数据
- sda_en_addr = 'd0;//将地址赋值给sda_r
- // sda_en_ack1 = 'd0;//ack1时给sda_r赋值
- sda_en_data = 'd0;//将数据赋值给sda_r
- // sda_en_ack2 = 'd0;//ack2时给sda_r赋值
- start = 'd0;
- stop = 'd0;
- done = 'd0;
- ack1 = 'd0;
- ack2 = 'd0;
- end
- endcase
- // Instantiate the module
- scl_generate scl_generate (
- .clk_50m(clk_50m),
- .load_a(load_a),
- .en_a(en_a),
- .scl(SCL)
- );
- // Instantiate the module
- ad_left_shifter ad_left_shifter (
- .clk_50m(clk_50m),
- .addr_in(addr_in),
- .load_b(load_b),
- .en_b(en_b),
- .addr_o(addr_o)
- );
- // Instantiate the module
- count_num count_num (
- .clk_50m(clk_50m),
- .load_c(load_c),
- .en_c(en_c),
- .count(i)
- );
- // Instantiate the module
- data_left_shifter data_left_shifter (
- .clk_50m(clk_50m),
- .data_in(data_in),
- .en_d(en_d),
- .load_d(load_d),
- .data_o(data_o)
- );
- // Instantiate the module
- SDA_strat_stop SDA_strat_stop (
- .clk_50m(clk_50m),
- .start(start),
- .stop(stop),
- .edge_detect(edge_detect)
- );
- // Instantiate the module
- sdar_signal sdar_signal (
- .clk_50m(clk_50m),
- .sad_load(sad_load),
- .start(start),
- .edge_detect(edge_detect),
- .sda_en_addr(sda_en_addr),
- .addr_o(addr_o),
- .sda_en_data(sda_en_data),
- .data_o(data_o),
- .stop(stop),
- .sda_r(sda_r)
- );
- endmodule
scl_generate:用于产生SCL
- module scl_generate(input clk_50m,
- input load_a,
- input en_a,
- output reg scl
- );
- always @(posedge clk_50m)
- if(load_a)
- scl <= 'd1;
- else if(en_a)
- scl <= ~scl;
- else
- scl <= scl;
- endmodule
ad_left_shifter:用于将并行的8位地址转换成串行的一位一位的发送出去
- module ad_left_shifter(input clk_50m,
- input [7:0]addr_in,
- input load_b,
- input en_b,
- output addr_o
- );
- reg [7:0]addr_reg = 'd0;
- always @(posedge clk_50m)
- if(load_b)
- addr_reg <= addr_in;
- else if(en_b=='b1)
- addr_reg <= {addr_reg[6:0],1'b0};
- else
- addr_reg <= addr_reg;
- assign addr_o = addr_reg[7];
- endmodule
count_num:计数器,用于计数发送地址或者数据的个数
- module count_num(input clk_50m,
- input load_c,
- input en_c,
- output reg[4:0]count
- );
- always @(posedge clk_50m)
- if(load_c)
- count <= 'd0;
- else if(en_c) begin
- if(count == 'd17)
- count <= 'd0;
- else
- count <= count + 'd1;
- end
- else
- count <= count;
- endmodule
data_left_shifter:用于将并行的8位数据转换成串行的一位一位的发送出去
- module data_left_shifter(input clk_50m,
- input [7:0]data_in,
- input en_d,
- input load_d,
- output data_o
- );
- reg [7:0]data_reg = 'd0;
- always @(posedge clk_50m)
- if(load_d)
- data_reg <= data_in;
- else if(en_d)
- data_reg <= {data_reg[6:0],1'b0};
- else
- data_reg <= data_reg;
- assign data_o = data_reg[7];
- endmodule
SDA_strat_stop:用于生成起始信号和结束信号
- module SDA_strat_stop(input clk_50m,
- input start,
- input stop,
- output reg edge_detect = 'd0
- );
- always @(posedge clk_50m)
- case({stop,start})
- 2'b01: edge_detect <= 'd0;
- 2'b10: edge_detect <= 'd1;
- default: edge_detect <= 'd0;
- endcase
- endmodule
sdar_signal:用于控制SDA发送的是地址信号、数据信号、开始信号还是结束信号
- module sdar_signal(input clk_50m,
- input sad_load,
- input start,
- input edge_detect,
- input sda_en_addr,
- input addr_o,
- input sda_en_data,
- input data_o,
- input stop,
- output reg sda_r
- );
- always @(*)
- if(sad_load)
- sda_r <= 'd1;
- else begin
- case({stop,sda_en_data,sda_en_addr,start})
- 4'b0001: sda_r <= edge_detect;
- 4'b0010: sda_r <= addr_o;
- 4'b0100: sda_r <= data_o;
- 4'b1000: sda_r <= edge_detect;
- default: sda_r <= 'd1;
- endcase
- end
-
- endmodule
仿真激励文件:
- module tb;
-
- // Inputs
- reg clk_50m;
- reg clk_in;
- reg rst_n;
- reg wr_en;
- reg [7:0] addr_in;
- reg [7:0] data_in;
-
- // Outputs
- wire done;
- wire SCL;
- wire ack1;
- wire ack2;
-
- // Bidirs
- wire SDA;
-
- // Instantiate the Unit Under Test (UUT)
- I2C_MODULE uut (
- .clk_50m(clk_50m),
- .clk_in(clk_in),
- .rst_n(rst_n),
- .wr_en(wr_en),
- .addr_in(addr_in),
- .data_in(data_in),
- .done(done),
- .SDA(SDA),
- .SCL(SCL),
- .ack1(ack1),
- .ack2(ack2)
- );
-
- initial begin
- // Initialize Inputs
- clk_50m = 0;
- clk_in = 0;
- rst_n = 0;
- wr_en = 0;
- addr_in = 0;
- data_in = 0;
-
- // Wait 100 ns for global reset to finish
- #100;
-
- // Add stimulus here
-
- end
- always #10 clk_50m = ~clk_50m;
- always #5 clk_in = ~clk_in;
- ///rst_n
- reg [3:0] cnt = 'd0;
- always @(posedge clk_50m)
- if(cnt == 'd10)
- cnt <= 'd10;
- else
- cnt <= cnt + 'd1;
- always @(posedge clk_50m)
- if(cnt=='d10)
- rst_n <= 'd1;
- else
- rst_n <= 'd0;
- ///
- reg[4:0]count = 'd0;
- always @(posedge clk_50m)
- if(done)
- count <= 'd0;
- else if(count == 'd30)
- count <= 'd30;
- else
- count <= count + 'd1;
- always @(posedge clk_50m)
- if(count == 'd29)
- wr_en <= 'd1;
- else
- wr_en <= 'd0;
- always @(posedge clk_50m)
- if(count == 'd30) begin
- addr_in <= 8'b10101010;
- data_in <= 8'b10101010;
- end
- else begin
- addr_in <= 'd0;
- data_in <= 'd0;
- end
-
- //always @(posedge clk_50m)
- // if(ack1||ack2)
- // SDA <= 'd0;
- // else
- // SDA <= SDA;
- endmodule
仿真波形:
从图中可以看出:空闲时SCL和SDA均处于高电平;在SCL有效时,SDA由高变为低(开始信号)后开始进行数据的发送,数据只在SCL的低电平发生变化;在ack时,SCL为高时,SDA为低,表示从机发送应答信号,当数据发送完毕后,在SCL有效时,SDA由低变为高(结束信号),之后done信号拉高,表示IIC发送一次数据完毕。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。