iic通信协议是什么

iic通信协议是什么 iic协议是二线制,信号线包含sda和scl,且信号线是双向的,开路结构,需要通过上拉电阻到vcc,具体的电阻值影响的是信号反应速度和驱动能力。
首先,iic通信与uart,还有spi统称为串行接口通信,不过它们之间还是有区别的,如uart的负电平逻辑,还有uart通信不需要时钟,只需要特定的波特率即可,spi与iic都可以有一个主机,多个从机的情况,不过iic适用于短距离传输,如片间通信,摄像头的配置等场景。
要搞定iic首先来看iic的硬件接口:
如图所示,我们知道iic一个主机可以悬挂多个从机,所以地址线a2,a1,a0 可以实行片选的功能,那么wp这个引脚的功能就是当wp悬空或者接地的时候,表示这时的eeprom既可以读,也可以写,当wp接电源时,则只可以读而不能写。
scl与sdl这两个引脚,必须上拉,否则驱动能力不够,无法进行正常的iic通信。
ok,硬件接口已经介绍清楚了,那么我们现在开始来看协议了。
首先iic分为字节读写和页面读写,首先来看字节读写的协议:
如上图所示,如果我们要向eeprom中写入一个字节的数据,得有如下几个步骤:
1.开始信号——在sclk的高电平器件,拉低sda的信号(由1 变为0)。
2.控制字节——即器件地址,就是你操作那一块eeprom。
3.ack信号——由从机发出,主机为接收,所以在此阶段,sda_link必须置为0,即为读取这个应答信号,所以在sclk的高点平期间。
4.字节地址——即某一块eeprom里面的哪一个地址。
5.ack信号——与上述相同。
6.数据信号——即你往某个地址里面写入的8位数据。
7.ack信号——上述相同。
8.结束信号——在sclk的高电平期间,拉高sda信号,表示通信结束。
再来看读的时序:
由上图可看出读时序的前面处理方式与写相同,不同的时在第三个ack信号来了之后,如果是读,那么会又有一个起始信号,紧接着读器件地址,然后应答,再然后读数据,再然后在sclk的低电平期间发送一个no ack信号,要记住这个信号由主机发出,然后紧接着一个结束信号。
由上述读写时序我们可知,通信的起始均在sclk的高电平期间发生跳变,这就据定了我们其他信号跳变均在sclk的下降沿,sclk高电平期间数据稳定,适用于读(即低电平改变数据,高电平采集数据)。
具体过程如下:
首先板子上电来个初始化需要来个延时,具体多少用计数器自己搞定。
代码如下:
reg [6:0] hadware_initial_delay;
wire hadware_initial_delay_done;
always@(posedge clk or negedge rst_n)
if(!rst_n)
hadware_initial_delay《=7’d0;
else
if(hadware_initial_delay《=7’d49)
hadware_initial_delay《=hadware_initial_delay+1;else
hadware_initial_delay《=hadware_initial_delay;assign hadware_initial_delay_done=(hadware_initial_delay==7’d50)?1’b1:1’b0;ok,我们要知道iic的速率一般就几百kh而我们的系统时钟为50m,所以需要分频:
代码如下:
reg [8:0] sclk_cnt;
always@(posedge clk or negedge rst_n)
if(!rst_n)
sclk_cnt《=9’d0;
else
if(hadware_initial_delay_done)
begin
if(sclk_cnt《9’d499)
sclk_cnt《=sclk_cnt+1;
else
sclk_cnt《=0;
end
assign sclk=(sclk_cnt《=9’d249)?1’b1:1’b0;ok,我们知道sclk高电平期间采集数据,低电平期间改变数据,那么当然,这个“期间”肯定时时钟沿中间最好啦,毕竟更容易满足建立时间与保持时间,很稳定的。
具体代码如下:
wire sclk_posedge_middle=(sclk_cnt==9’d124)?1’b1:1’b0;wire sclk_negedge_middle=(sclk_cnt==9’d374)?1’b1:1’b0;ok,读写定义了那么多个过程,当然需要状态机来搞定啦,定义变量如下:
parameter idle = 4’d0 ;
parameter start1 = 4’d1 ;
parameter add1 = 4’d2 ;
parameter ack1 = 4’d3 ;
parameter add2 = 4’d4 ;
parameter ack2 = 4’d5 ;
parameter data = 4’d6 ;
parameter ack3 = 4’d7 ;
parameter stop1 = 4’d8 ;
parameter start2 = 4’d9 ;
parameter add3 = 4’d10;
parameter ack4 = 4’d11;
parameter data_read = 4’d12;
parameter no_ack = 4’d13;
parameter stop2 = 4’d14;
ok,再来个宏定义,假设写入是这几个地址,这几个数据。
define device_read 8‘b1010_0001
define device_write 8’b1010_0000
define write_data 8’b0001_0001
define byte_addr 8’b0000_0011
sda双向端口,这个记住,一般这样搞;
reg sda_link;
reg sda_out_r;
assign sda=sda_link?sda_out_r:1’bz;
当作为输出时,对吧,使sda_link拉高,作为输入时,输入高阻。
各过程如下:
reg [3:0] current_state;
//reg [3:0] next_state;
reg [7:0] db_r;
reg [3:0] num;
reg [7:0] data_out_reg;
always@(posedge clk or negedge rst_n)
if(!rst_n)
begin
sda_link《=0;
db_r《=0;
num《=0;
current_state《=idle;
sda_out_r《=0;
data_out_reg《=8’b0;
end
else
begin
case(current_state)
idle:begin
sda_out_r《=1;
sda_link《=1;
if(!sw1_r||!sw2_r)
current_state《=start1;
else
current_state《=idle;
end
start1:if(sclk_posedge_middle)
begin
sda_out_r《=0;
db_r《=`device_write;
current_state《=add1;
end
else
current_state《=start1;
add1 :
if(sclk_negedge_middle)
begin
if(num==4‘d8)
begin
sda_link《=0;
num《=0;
current_state《=ack1;
sda_out_r《=1;
end
else
begin
current_state《=add1;
sda_out_r《=db_r[7-num];
num《=num+1;
end
end
else
current_state《=add1;
ack1:
if(sclk_posedge_middle)
// begin
// if(!sda)
// begin
begin // */current_state《=add2;
db_r《=`byte_addr;
end
else
current_state《=ack1;
add2:begin
sda_link《=1;
if(sclk_negedge_middle)begin
if(num==4’d8)
begin
sda_link《=0;
current_state《=ack2;
num《=4‘d0;
sda_out_r《=1;
end
else
begin
num《=num+1;
current_state《=add2;
sda_out_r《=db_r[7-num];
end
end
else
current_state《=add2;
end
ack2:
if(sclk_posedge_middle)
////begin
//if(!sda)
begin
begin
if(!sw1_r)
begin
db_r《=`write_data;
current_state《=data;
end
else
if(!sw2_r)
begin
current_state《=start2;
sda_out_r《=1;
end
end
else
current_state《=ack2;
data: begin
sda_link《=1;
if(sclk_negedge_middle)
begin
if(num==4’d8)
begin
num《=4‘d0;
current_state《=ack3;
sda_out_r《=1;
sda_link《=0;
end
else
begin
num《=num+1;
current_state《=data;
sda_out_r《=db_r[7-num];
end
end
else
current_state《=data;
end
ack3: if(sclk_posedge_middle)
// begin
// if(!sda)
current_state《=stop1;
// end
stop1:
begin
sda_link《=1;
sda_out_r《=0;
if(sclk_posedge_middle)
begin
sda_out_r《=1;
if(sw1_r)
// 你要是不等它松开才恢复初始状态,那么你一旦恢复初始状态sw1_r就为低电平,他又开始写了,所以为了避免重复写入数据。
current_state《=idle;
else
current_state《=stop1;
end
else
current_state《=stop1;
end
start2:begin
sda_link《=1;
if(sclk_posedge_middle)
begin
sda_out_r《=0;
sda_link《=1;
db_r《=`device_read;
current_state《=add3 ;
end
end
add3: begin
if(sclk_negedge_middle)
begin
if(num==4’d8)
begin
num《=0;
sda_link《=0;
sda_out_r《=1;
current_state《=ack4;
end
else
begin
num《=num+1;
sda_out_r《=db_r[7-num];
current_state《=add3;
end
end
else
current_state《=add3;
end
ack4:
if(sclk_posedge_middle)
// begin
// if(!sda)
current_state《=data_read;
else
current_state《=ack4;
// end
data_read:
begin
sda_link《=0;
if(sclk_posedge_middle)
begin
if(num==4‘d8)
begin
sda_link《=1;
sda_out_r《=1;
current_state《=no_ack;
num《=4’d0;
end
else
begin
num《=num+1;
current_state《=data_read;
data_out_reg[7-num]《=sda;
end
end
end
no_ack:
if(sclk_negedge_middle)
begin
sda_out_r《=1;
current_state《=stop2;
end
else
current_state《=no_ack;
stop2:begin
sda_out_r《=0;
sda_link《=1;
if(sclk_posedge_middle)
begin
sda_out_r《=1;
current_state《=idle;
end
else
current_state《=stop2;
end
default:current_state《=idle;
endcase
end
assign data_out=data_out_reg;
endmodule
仿真结果如下:

一款用MAX4410的高保真耳放
开关电源的输出电流如何决定_跟什么有关?
第二十二届中国高速公路信息化大会在重庆拉开序幕
华为P30 Pro和iQOO的快充和续航能力对比分析
TME Solution已成为最可靠的长期定制和标准泄漏测试仪器
iic通信协议是什么
燃气报警器电路图大全(六款模拟电路设计原理图详解)
新唐科技推出内置2Vrms驱动器的立体声DAC-NAU8402
全文详解IIR滤波器原理与设计方法
AMD处理器现在真的超越英特尔处理器了吗
IIC-China 2010参展商展前专访:银灿
思岚移动底盘5周年 新品雅典娜Athena即将面世
对称加密算法的四种模式以及优缺点
虹软科技再次入选2022金辑奖“中国汽车新供应链百强”
Linux 让你意想不到的用处
分享一个电子驱鼠电路
一加5、荣耀9、魅族MX7、OPPOR11即将亮相,高颜值、高性能、高配置你的钱包准备好了吗?
为什么加密货币价格的波动会让所有人都沉迷其中
光伏发电缓解电荒 指日可待?
ARM Cortex-M4内核架构概述