IIC时序程序

合集下载

FPGA_IIC时序实验

FPGA_IIC时序实验

FPGA_IIC时序实验概述:这篇文章通过FPGA实现对EEPROM的读写操作,演示了如何看懂芯片时序和结构建模风格的verilog实现的一般方法。

以对IIC总线的FPGA实现为例子,揭示了芯片时序的分析的一般方法,和结构化建模风格的verilog实现如何对算法进行描述以及如何对时序的精确控制的一般方法。

这篇文章分为两个部分,第一个部分是如何看懂时序图,第二个部分是结构化建模风格的verilog如何对算法进行描述和对时序进行精确控制。

第一个部分尽量独立于第二个部分,也就是说这里的如何看懂时序图不仅仅适合FPGA对时序的描述,也同样适合单片机等控制器对时序的描述。

我觉得说明时序图是如何看懂的,和代码是如何思考和写出来的,比分析个别时序和解释个别代码如何工作更具有普遍性。

所以这篇文章主要是记录如何看懂时序图和如何把时序图写成对应的verilog模块。

接下来一部分主要讲结构化建模的思考方式。

对如何看懂时序感兴趣的可以直接跳到时序分析部分。

对如何通过verilog实现IIC总线感兴趣的可以直接跳过到代码分析部分。

建模的首要任务是管理复杂度。

管理复杂度可以通过以下方法来实现。

一般思路是首先找出要实现功能对应的抽象数据对象(ADT),然后通过建立原型的方法搭建模块的骨架,以增量式的开发方式构建肌肉、神经、血管和皮肤,然后构成完整的功能模块。

增量式的开发原则是每一步以能够最快的实现预期现象为目的进行的。

如果不能以最快的看到预期现象为目的,只是搭建完成各模块的后进行整合直接看结果的话,通常结果是什么都没有的。

这里借用了软件开发的一个原理,提高软件工程效率有效方法是把错误产生时间和解决的时间控制在越早,整个软件工程的代价就越小;否则,解决问题的时间离产生问题的时间越晚,整个软件工程的代价会成指数增长,最终会导致整个工程崩溃。

增量式开发的原则中的最快的实现预期现象,要运用到测试和调试的方法。

这里需要注意的一点是要看到实际的现象,而不仅仅是仿真的时序图符合预想。

verilog实现IIC时序逻辑控制

verilog实现IIC时序逻辑控制

Verilog实现IIC时序逻辑控制代码(注释详细,验证可用)Email:xxxxx0901@Address: Haidian.Beijing.China2015-04-09Verilog实现IIC时序逻辑控制代码(注释详细,验证可用)2015-04-09一顶层模块:module iic_top(clk,rst_n,sw1,sw2,scl,sda,sm_cs1_n,sm_cs2_n,sm_db);input clk; // 50MHzinput rst_n; //复位信号,低有效input sw1,sw2; //按键1、2,(1按下执行写入操作,2按下执行读操作) output scl; // 24C02的时钟端口inout sda; // 24C02的数据端口output sm_cs1_n,sm_cs2_n; //数码管片选信号,低有效output[6:0] sm_db; //7段数码管(不包括小数点)wire[7:0] dis_data; //在数码管上显示的16进制数iic_com iic_com(.clk(clk),.rst_n(rst_n),.sw1(sw1),.sw2(sw2),.scl(scl),.sda(sda),.dis_data(dis_data));led_seg7 led_seg7(.clk(clk),.rst_n(rst_n),.dis_data(dis_data),.sm_cs1_n(sm_cs1_n),.sm_cs2_n(sm_cs2_n),.sm_db(sm_db));endmodule二IIC时序模块:module iic_com(clk,rst_n,sw1,sw2,scl,sda,dis_data);input clk; // 50MHzinput rst_n; //复位信号,低有效input sw1,sw2; //按键1、2,(1按下执行写入操作,2按下执行读操作)output scl; // 24C02的时钟端口inout sda; // 24C02的数据端口output[7:0] dis_data; //数码管显示的数据//--------------------------------------------//按键检测//--------------------------------------------reg sw1_r,sw2_r; //键值锁存寄存器,每20ms检测一次键值reg[19:0] cnt_20ms; //20ms计数寄存器always @ (posedge clk or negedge rst_n)if(!rst_n) cnt_20ms <= 20'd0;else cnt_20ms <= cnt_20ms+1'b1; //不断计数always @ (posedge clk or negedge rst_n)if(!rst_n) beginsw1_r <= 1'b1; //键值寄存器复位,没有键盘按下时键值都为1sw2_r <= 1'b1;endelse if(cnt_20ms == 20'hfffff) beginsw1_r <= sw1; //按键1值锁存sw2_r <= sw2; //按键2值锁存end//---------------------------------------------//分频部分//--------------------------------------------reg[2:0] cnt; // cnt=0:scl上升沿,cnt=1:scl高电平中间,cnt=2:scl下降沿,cnt=3:scl 低电平中间reg[8:0] cnt_delay; //500循环计数,产生iic所需要的时钟reg scl_r; //时钟脉冲寄存器always @ (posedge clk or negedge rst_n)if(!rst_n) cnt_delay <= 9'd0;else if(cnt_delay == 9'd499) cnt_delay <= 9'd0; //计数到10us为scl的周期,即100KHzelse cnt_delay <= cnt_delay+1'b1; //时钟计数always @ (posedge clk or negedge rst_n) beginif(!rst_n) cnt <= 3'd5;else begincase (cnt_delay)9'd124: cnt <= 3'd1; //cnt=1:scl高电平中间,用于数据采样9'd249: cnt <= 3'd2; //cnt=2:scl下降沿9'd374: cnt <= 3'd3; //cnt=3:scl低电平中间,用于数据变化9'd499: cnt <= 3'd0; //cnt=0:scl上升沿default: cnt <= 3'd5;endcaseendend`define SCL_POS (cnt==3'd0) //cnt=0:scl上升沿`define SCL_HIG (cnt==3'd1) //cnt=1:scl高电平中间,用于数据采样`define SCL_NEG (cnt==3'd2) //cnt=2:scl下降沿`define SCL_LOW (cnt==3'd3) //cnt=3:scl低电平中间,用于数据变化always @ (posedge clk or negedge rst_n)if(!rst_n) scl_r <= 1'b0;else if(cnt==3'd0) scl_r <= 1'b1; //scl信号上升沿else if(cnt==3'd2) scl_r <= 1'b0; //scl信号下降沿assign scl = scl_r; //产生iic所需要的时钟//---------------------------------------------//需要写入24C02的地址和数据`define DEVICE_READ 8'b1010_0001 //被寻址器件地址(读操作)`define DEVICE_WRITE 8'b1010_0000 //被寻址器件地址(写操作)`define WRITE_DATA 8'b1101_0001 //写入EEPROM的数据`define BYTE_ADDR 8'b0000_0011 //写入/读出EEPROM的地址寄存器reg[7:0] db_r; //在IIC上传送的数据寄存器reg[7:0] read_data; //读出EEPROM的数据寄存器//---------------------------------------------//读、写时序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 START2 = 4'd6;parameter ADD3 = 4'd7;parameter ACK3 = 4'd8;parameter DATA = 4'd9;parameter ACK4 = 4'd10;parameter STOP1 = 4'd11;parameter STOP2 = 4'd12;reg[3:0] cstate; //状态寄存器reg sda_r; //输出数据寄存器reg sda_link; //输出数据sda信号inout方向控制位reg[3:0] num; //always @ (posedge clk or negedge rst_n) beginif(!rst_n) begincstate <= IDLE;sda_r <= 1'b1;sda_link <= 1'b0;num <= 4'd0;read_data <= 8'b0000_0000;endelsecase (cstate)IDLE: beginsda_link <= 1'b1; //数据线sda为outputsda_r <= 1'b1;if(!sw1_r || !sw2_r) begin //SW1,SW2键有一个被按下db_r <= `DEVICE_WRITE; //送器件地址(写操作)cstate <= START1;endelse cstate <= IDLE; //没有任何键被按下endSTART1: beginif(`SCL_HIG) begin //scl为高电平期间sda_link <= 1'b1; //数据线sda为outputsda_r <= 1'b0; //拉低数据线sda,产生起始位信号cstate <= ADD1;num <= 4'd0; //num计数清零endelse cstate <= START1; //等待scl高电平中间位置到来endADD1: beginif(`SCL_LOW) beginif(num == 4'd8) beginnum <= 4'd0; //num计数清零sda_r <= 1'b1;sda_link <= 1'b0; //sda置为高阻态(input)cstate <= ACK1;endelse begincstate <= ADD1;num <= num+1'b1;case (num)4'd0: sda_r <= db_r[7];4'd1: sda_r <= db_r[6];4'd2: sda_r <= db_r[5];4'd3: sda_r <= db_r[4];4'd4: sda_r <= db_r[3];4'd5: sda_r <= db_r[2];4'd6: sda_r <= db_r[1];4'd7: sda_r <= db_r[0];default: ;endcase// sda_r <= db_r[4'd7-num]; //送器件地址,从高位开始endend// else if(`SCL_POS) db_r <= {db_r[6:0],1'b0}; //器件地址左移1bitelse cstate <= ADD1;endACK1: beginif(/*!sda*/`SCL_NEG) begin //注:24C01/02/04/08/16器件可以不考虑应答位cstate <= ADD2; //从机响应信号db_r <= `BYTE_ADDR; // 1地址endelse cstate <= ACK1; //等待从机响应endADD2: beginif(`SCL_LOW) beginif(num==4'd8) beginnum <= 4'd0; //num计数清零sda_r <= 1'b1;sda_link <= 1'b0; //sda置为高阻态(input)cstate <= ACK2;endelse beginsda_link <= 1'b1; //sda作为outputnum <= num+1'b1;case (num)4'd0: sda_r <= db_r[7];4'd1: sda_r <= db_r[6];4'd2: sda_r <= db_r[5];4'd3: sda_r <= db_r[4];4'd4: sda_r <= db_r[3];4'd5: sda_r <= db_r[2];4'd6: sda_r <= db_r[1];4'd7: sda_r <= db_r[0];default: ;endcase// sda_r <= db_r[4'd7-num]; //送EEPROM地址(高bit开始)cstate <= ADD2;endend// else if(`SCL_POS) db_r <= {db_r[6:0],1'b0}; //器件地址左移1bitelse cstate <= ADD2;endACK2: beginif(/*!sda*/`SCL_NEG) begin //从机响应信号if(!sw1_r) begincstate <= DATA; //写操作db_r <= `WRITE_DATA; //写入的数据endelse if(!sw2_r) begindb_r <= `DEVICE_READ; //送器件地址(读操作),特定地址读需要执行该步骤以下操作cstate <= START2; //读操作endendelse cstate <= ACK2; //等待从机响应endSTART2: begin //读操作起始位if(`SCL_LOW) beginsda_link <= 1'b1; //sda作为outputsda_r <= 1'b1; //拉高数据线sdacstate <= START2;endelse if(`SCL_HIG) begin //scl为高电平中间sda_r <= 1'b0; //拉低数据线sda,产生起始位信号cstate <= ADD3;endelse cstate <= START2;endADD3: begin //送读操作地址if(`SCL_LOW) beginif(num==4'd8) beginnum <= 4'd0; //num计数清零sda_r <= 1'b1;sda_link <= 1'b0; //sda置为高阻态(input)cstate <= ACK3;endelse beginnum <= num+1'b1;case (num)4'd0: sda_r <= db_r[7];4'd1: sda_r <= db_r[6];4'd2: sda_r <= db_r[5];4'd3: sda_r <= db_r[4];4'd4: sda_r <= db_r[3];4'd5: sda_r <= db_r[2];4'd6: sda_r <= db_r[1];4'd7: sda_r <= db_r[0];default: ;endcase// sda_r <= db_r[4'd7-num]; //送EEPROM地址(高bit开始)cstate <= ADD3;endend// else if(`SCL_POS) db_r <= {db_r[6:0],1'b0}; //器件地址左移1bitelse cstate <= ADD3;endACK3: beginif(/*!sda*/`SCL_NEG) begincstate <= DATA; //从机响应信号sda_link <= 1'b0;endelse cstate <= ACK3; //等待从机响应endDATA: beginif(!sw2_r) begin //读操作if(num<=4'd7) begincstate <= DATA;if(`SCL_HIG) beginnum <= num+1'b1;case (num)4'd0: read_data[7] <= sda;4'd1: read_data[6] <= sda;4'd2: read_data[5] <= sda;4'd3: read_data[4] <= sda;4'd4: read_data[3] <= sda;4'd5: read_data[2] <= sda;4'd6: read_data[1] <= sda;4'd7: read_data[0] <= sda;default: ;endcase// read_data[4'd7-num] <= sda; //读数据(高bit 开始)end// else if(`SCL_NEG) read_data <= {read_data[6:0],read_data[7]}; //数据循环右移endelse if((`SCL_LOW) && (num==4'd8)) beginnum <= 4'd0; //num计数清零cstate <= ACK4;endelse cstate <= DATA;endelse if(!sw1_r) begin //写操作sda_link <= 1'b1;if(num<=4'd7) begincstate <= DATA;if(`SCL_LOW) beginsda_link <= 1'b1; //数据线sda作为outputnum <= num+1'b1;case (num)4'd0: sda_r <= db_r[7];4'd1: sda_r <= db_r[6];4'd2: sda_r <= db_r[5];4'd3: sda_r <= db_r[4];4'd4: sda_r <= db_r[3];4'd5: sda_r <= db_r[2];4'd6: sda_r <= db_r[1];4'd7: sda_r <= db_r[0];default: ;endcase// sda_r <= db_r[4'd7-num]; //写入数据(高bit 开始)end// else if(`SCL_POS) db_r <= {db_r[6:0],1'b0}; //写入数据左移1bitendelse if((`SCL_LOW) && (num==4'd8)) beginnum <= 4'd0;sda_r <= 1'b1;sda_link <= 1'b0; //sda置为高阻态cstate <= ACK4;endelse cstate <= DATA;endendACK4: beginif(/*!sda*/`SCL_NEG) begin// sda_r <= 1'b1;cstate <= STOP1;endelse cstate <= ACK4;endSTOP1: beginif(`SCL_LOW) beginsda_link <= 1'b1;sda_r <= 1'b0;cstate <= STOP1;endelse if(`SCL_HIG) beginsda_r <= 1'b1; //scl为高时,sda产生上升沿(结束信号)cstate <= STOP2;endelse cstate <= STOP1;endSTOP2: beginif(`SCL_LOW) sda_r <= 1'b1;else if(cnt_20ms==20'hffff0) cstate <= IDLE;else cstate <= STOP2;enddefault: cstate <= IDLE;endcaseendassign sda = sda_link ? sda_r:1'bz;assign dis_data = read_data;//---------------------------------------------endmodule三数码管显示模块:module led_seg7(clk,rst_n,dis_data,sm_cs1_n,sm_cs2_n,sm_db);input clk; // 50MHzinput rst_n; // 复位信号,低有效input[7:0] dis_data; //显示数据output sm_cs1_n,sm_cs2_n; //数码管片选信号,低有效output[6:0] sm_db; //7段数码管(不包括小数点)reg[7:0] cnt;always @ (posedge clk or negedge rst_n)if(!rst_n) cnt <= 8'd0;else cnt <= cnt+1'b1;//------------------------------------------------------------------------------- /* 共阴极:不带小数点;0, 1, 2, 3, 4, 5, 6, 7,db 3fh,06h,5bh,4fh,66h,6dh,7dh,07h;8, 9, a, b, c, d, e, f , 灭db 7fh,6fh,77h,7ch,39h,5eh,79h,71h,00h*/ parameter seg0 = 7'h3f,seg1 = 7'h06,seg2 = 7'h5b,seg3 = 7'h4f,seg4 = 7'h66,seg5 = 7'h6d,seg6 = 7'h7d,seg7 = 7'h07,seg8 = 7'h7f,seg9 = 7'h6f,sega = 7'h77,segb = 7'h7c,segc = 7'h39,segd = 7'h5e,sege = 7'h79,segf = 7'h71;reg[6:0] sm_dbr; //7段数码管(不包括小数点)wire[3:0] num; //显示数据assign num = cnt[7] ? dis_data[7:4] : dis_data[3:0]; assign sm_cs1_n = cnt[7]; //数码管1常开assign sm_cs2_n = ~cnt[7]; //数码管2常开always @ (posedge clk)case (num) //NUM值显示在两个数码管上4'h0: sm_dbr <= seg0;4'h1: sm_dbr <= seg1;4'h2: sm_dbr <= seg2;4'h3: sm_dbr <= seg3;4'h4: sm_dbr <= seg4;4'h5: sm_dbr <= seg5;4'h6: sm_dbr <= seg6;4'h7: sm_dbr <= seg7;4'h8: sm_dbr <= seg8;4'h9: sm_dbr <= seg9;4'ha: sm_dbr <= sega;4'hb: sm_dbr <= segb;4'hc: sm_dbr <= segc;4'hd: sm_dbr <= segd;4'he: sm_dbr <= sege;4'hf: sm_dbr <= segf;default: ;endcase assign sm_db = sm_dbr; endmodule。

IIC通信协议

IIC通信协议

IIC通信协议协议名称:IIC通信协议一、介绍IIC(Inter-Integrated Circuit)通信协议是一种用于短距离数字通信的串行总线协议。

它由飞利浦公司于1982年推出,旨在实现在数字集成电路之间的高速、简单、低成本的通信。

本协议规定了IIC总线的物理层和数据链路层的规范,确保了不同设备之间的互操作性和兼容性。

二、协议规范1. 物理层规范IIC总线使用两根线进行通信,分别为SDA(Serial Data Line)和SCL(Serial Clock Line)线。

SDA线用于数据传输,而SCL线用于时钟同步。

这两根线都是双向的,并且通过上拉电阻连接到正电源。

2. 数据链路层规范IIC总线采用主从结构,其中主设备负责发起通信,而从设备则被动地响应通信请求。

通信过程中,主设备通过发送起始信号来启动通信,然后发送地址和读/写位,最后发送数据和接收应答。

3. 通信流程(1)起始信号:主设备将SDA线从高电平拉低,然后再拉低SCL线,表示发起通信。

(2)地址和读/写位:主设备发送从设备的地址,并指明读或写操作。

(3)数据传输:主设备发送数据,从设备接收并发送应答信号。

若从设备成功接收到数据,则拉低SDA线作为应答;否则,保持SDA线为高电平表示无应答。

(4)终止信号:主设备在完成通信后,将SDA线从低电平拉高,再拉高SCL 线,表示终止通信。

4. 时序要求IIC通信协议的时序要求如下:(1)起始信号:SDA线保持高电平时,SCL线由高电平转为低电平。

(2)数据传输:SDA线上的数据必须在SCL线为低电平时保持稳定,直到SCL线变为高电平。

(3)应答信号:应答信号由被动设备在SCL线为低电平时拉低SDA线发送。

(4)终止信号:SDA线保持低电平时,SCL线由低电平转为高电平。

三、应用范围IIC通信协议广泛应用于各种数字集成电路之间的通信,特别适用于连接多个从设备到单个主设备的场景。

常见的应用包括传感器、存储器、显示器、温度控制器等。

iic应答时序

iic应答时序

iic应答时序【原创版】目录1.IIC 应答时序概述2.IIC 应答时序的工作原理3.IIC 应答时序的应用实例4.IIC 应答时序的优缺点正文I.IIC 应答时序概述IIC(Inter-Integrated Circuit),即内部集成电路,是一种串行双向通信总线,它是由 Philips 公司(现在的 NXP 半导体公司)于 1980 年代开发的。

IIC 用于在微控制器(MCU)和周边设备(如 EEPROM、LCD 显示器、传感器等)之间进行低速通信。

在 IIC 通信中,设备分为主设备和从设备,主设备负责发起通信和生成时钟信号,从设备则根据主设备的指令进行回应。

IIC 应答时序是指从设备在接收到主设备的指令后,进行回应的时间顺序和时序要求。

了解和掌握 IIC 应答时序对于设计和开发基于 IIC 通信的电子设备至关重要。

II.IIC 应答时序的工作原理IIC 通信采用主从模式,主设备发起通信,从设备响应。

在通信过程中,主设备会发送起始信号、读/写操作位、设备地址和数据,从设备收到这些信号后,会在规定的时间内发出应答信号(ACK)。

从设备在接收到主设备的指令后,需要按照规定的时序进行回应,这个过程称为 IIC 应答时序。

具体来说,IIC 应答时序包括以下几个步骤:1.主设备发出起始信号,从设备检测到起始信号后,开始准备接收后续信号。

2.主设备发送设备地址,从设备接收到设备地址后,根据地址判断是否是自己需要响应的设备,如果是,则进入下一步。

3.主设备发送读/写操作位,从设备接收到读/写操作位后,根据操作位确定是读操作还是写操作。

4.主设备发送数据,从设备接收到数据后,进行相应的存储或处理。

5.从设备在规定的时间内发出应答信号(ACK),表示已经成功接收到主设备的指令。

III.IIC 应答时序的应用实例一个典型的 IIC 应答时序应用实例是使用 IIC 总线连接微控制器和EEPROM。

在这个实例中,微控制器作为主设备,负责发起通信和生成时钟信号,EEPROM 作为从设备,负责响应微控制器的指令。

iic应答时序

iic应答时序

IIC应答时序1. 什么是IIC?IIC(Inter-Integrated Circuit)是一种串行通信协议,由飞利浦(Philips)公司在1982年首次引入。

它是一种用于芯片间通信的简单、高效的方式,广泛应用于各种电子设备中。

2. IIC应答时序的概述在IIC通信中,主设备(Master)通过发送命令和数据来控制从设备(Slave)。

IIC应答时序指的是从设备接收到主设备发送的数据后,如何进行应答。

2.1 IIC通信的基本原理IIC通信基于两根线路:串行数据线(SDA)和串行时钟线(SCL)。

主设备产生时钟信号,并通过数据线发送和接收数据。

从设备在接收到时钟信号后,根据主设备的命令进行相应操作,并将结果通过数据线返回给主设备。

2.2 IIC应答模式在IIC通信中,从设备需要向主设备发送一个应答位来确认是否正确接收到了数据。

根据不同情况,可以分为两种应答模式:•ACK(Acknowledge)模式:表示从设备成功接收到了数据。

•NACK(Not Acknowledge)模式:表示从设备无法正确接收到数据。

3. IIC应答时序的详细过程IIC应答时序的详细过程如下:1.主设备发送起始信号(Start):主设备在SCL为高电平时,将SDA由高电平拉低,产生起始信号。

2.主设备发送从设备地址和读/写位:主设备在起始信号之后,依次发送从设备地址和读/写位。

从设备地址指示了要与哪个从设备进行通信,读/写位指示了数据的传输方向。

3.从设备接收并确认地址和读/写位:从设备在接收到主设备发送的地址和读/写位后,进行判断,并通过将SDA线拉低来发送应答信号。

4.主设备发送数据或命令:如果从设备成功确认了地址和读/写位,主设备就可以开始发送数据或命令。

5.从设备接收并确认数据或命令:从设备在接收到主设备发送的数据或命令后,进行处理,并通过拉低SDA线来发送应答信号。

6.重复步骤4和5直到完成所有的数据传输。

7.主设备产生停止信号(Stop):主设备在SCL为高电平时,将SDA由低电平拉高,产生停止信号。

基于VHDL的IIC时序电路设计

基于VHDL的IIC时序电路设计

基于VHDL的IIC时序电路设计iic 总线在设计时要看你所使用的器件的传输或接收时序只要会一个,其他的都一样以下是我在一本书上看到的,你看看就会用了library ieee;use ieee.std_logic_1164.all;use ieee.std_logic_arith.all;use ieee.std_logic_unsigned.all;entity reciver isport(reset,clk:in std_logic;sda,scl:inout std_logic;rd:out std_logic;tdata:in std_logic_vector(7 downto 0);rdata:out std_logic_vector(7 downto 0));end reciver;architecture one of reciver issignal rdatai:std_logic_vector(7 downto 0);type state is (start,transmit,ack,sub,ack1,start1,slave,ack2,reading,ack3); signal current:state;beginprocess(clk,reset)variable count:integer range 0 to 40;variable cnt:integer range 0 to 8;beginif reset='1'thensda<='1';scl<='1';rdata<="00000000";current<=start;cnt:=8;count:=0;elsif clk'event and clk='1' thencase current iswhen start=>count:=count+1;case count iswhen 1=>sda<='1';when 2=>scl<='1';when 3=>sda<='0';when 4=>scl<='0';when 10=>count:=0;current<=transmit;end case;when transmit=>count:=count+1;case count iswhen 1=>sda<=tdata(cnt);when 2=>scl<='1';when 3=>scl<='0';when 4=>cnt:=cnt-1;count:=0;if cnt=0 then cnt:=8;current<=ack;rd<='1'; else current<=transmit;rd<='0';end if;when others=>null;end case;when ack=>count:=count+1;case count iswhen 1=>sda<='0';when 2=>scl<='1';when 3=>scl<='0';when 4=>current<=sub;count:=0;when others=>null;end case;when sub=>count:=count+1;case count iswhen 1=>sda<=tdata(cnt);when 2=>scl<='1';when 3=>scl<='0';when 4=>cnt:=cnt-1;count:=0;if cnt=0 then cnt:=8;current<=ack1;rd<='1'; else current<=sub;rd<='0';end if;when others=>null;end case;when ack1=>count:=count+1;case count iswhen 1=>sda<='0';when 2=>scl<='1';when 4=>current<=start1;count:=0;when others=>null;end case;when start1=>count:=count+1;case count iswhen 1=>sda<='1';when 2=>scl<='1';when 3=>sda<='0';when 4=>scl<='0';when 5=>current<=slave;count:=0;when others=>null;end case;when slave=>count:=count+1;case count iswhen 1=>sda<=tdata(cnt);when 2=>scl<='1';when 3=>scl<='0';when 4=>cnt:=cnt-1;count:=0;if cnt=0 then cnt:=8;current<=ack2;rd<='1'; else current<=sub;rd<='0';end if;when others=>null;end case;when ack2=>count:=count+1;case count iswhen 1=>sda<='0';when 2=>scl<='1';when 3=>scl<='0';when 4=>current<=reading;count:=0;when others=>null;end case;when reading=>count:=count+1;case count iswhen 1=>sda<='1';when 4=>scl<='1';when 8=>rdatai(cnt)<=sda;when 10=>scl<='0';when 12=>cnt:=cnt-1;count:=0;if cnt=0 then cnt:=8;current<=ack3;rd<='1';else current<=reading;rd<='0';end if;when others=>null;end case;when ack3=>count:=count+1;case count iswhen 1=>sda<='0';when 2=>scl<='1';when 3=>scl<='0';when 4=>rdata<=rdatai;current<=start;count:=0;when others=>null;end case;end case;end if;end process;end architecture;TOP↑。

iic通信时序

iic通信时序

iic通信时序
iic通信时序
IIC(Inter-Integrated Circuit,又称为TWI(Two-Wire Interface),是被广泛应用在各种设备之间实现两线全双工通信的总线标准。

IIC总线由两个线组成,即SDA(数据线)和SCL(时钟线),其中,SCL负责传输控制信号,而SDA则负责传输数据。

具体的IIC通信时序如下:
1. Master端发出位置信号START:t首先,Master端需要发出一个位置信号START,确定一次slave发送操作的开始。

2. Master端发出从设备地址与操作动作:t之后,Master端还需要发出从设备地址和操作动作,使Slave端可以确定是谁发来的操作请求。

3. Slave端发出ACK应答:tSlave端收到Master端发出的地址信息及操作动作之后,会向Master端发出一个ACK应答,来表示该地址是有效的。

4. Master端发出Data:t接着,Master端会向Slave发出所要传输的data,进行数据传输。

5. Slave端发出ACK应答:tSlave端收到Master端发出的数据之后,会向Master端发出一个ACK应答,来表示数据已经收到。

6. Master端发出STOP信号:t最后,Master端发出一个STOP 信号,确定一次slave发送操作的结束。

iic标准时序

iic标准时序

iic标准时序
IIC(Inter-Integrated Circuit)是一种双线串行总线,也被称为I2C(发音为"I-squared C")。

它是由Philips公司开发的一种简单、双向、二线制同步串行总线。

IIC标准时序包括起始信号、数据传输、停止信号等步骤。

以下是IIC标准时序的基本步骤:
1.起始信号:当SCL线为高电平,SDA线由高电平跳变为低电平时,表示开始传输数据。

2.数据传输:在起始信号后,可以进行数据传输。

数据传输遵循以下规则:
在SCL线为高电平时,SDA线上的数据必须在稳定的电平状态,并且在SCL 线为低电平时,数据允许改变。

SDA线的数据在时钟信号SCL为高电平时保持稳定,在SCL为低电平时,数据可以改变。

3.停止信号:当SCL线为高电平,SDA线由低电平跳变为高电平时,表示停止传输数据。

4.应答信号:如果接收数据的设备能够正确接收数据,它将在SCL线的高电平期间将SDA线拉低,表示应答。

如果设备不能接收数据或发生错误,它不会拉低SDA线,表示非应答。

5.时钟同步:在数据传输过程中,主设备会生成时钟信号SCL,并用于同步数据传输。

从设备根据主设备的时钟信号来响应。

6.数据长度:一个IIC数据包中可以有1字节的数据,也可以有多个字节的数据。

多字节的数据必须以最高有效字节(MSB)在前的方式进行传输。

注意,上述是基本时序和规则,具体应用可能有所不同。

根据实际设备和具体需求,可能需要进一步了解和应用相关的具体参数和设置。

iic通信协议读写时序

iic通信协议读写时序

iic通信协议读写时序I2C(Inter-Integrated Circuit)是一种用于连接微控制器和各种外围设备的串行总线协议。

它只需要两根线:一根是双向的数据线SDA,另一根是时钟线SCL。

以下是I2C通信协议的基本读写时序:起始信号:当时钟线SCL为高电平时,数据线SDA由高电平变为低电平,表示开始传输。

这个信号只能由主设备(Master)发起。

地址传输:起始信号后,主设备发送一个7位的设备地址和一个读写位(共8位)。

设备地址用于寻址总线上的特定设备,读写位决定接下来的操作是读还是写。

应答信号:每个接收设备在接收到地址后,都会将其与自身的地址进行比较。

如果匹配,设备会产生一个应答信号(ACK)。

应答信号是在第9个时钟脉冲时,将SDA线拉低。

如果没有设备应答,主设备会检测到一个非应答信号(NACK),并可能终止传输或产生错误。

数据传输:在接收到应答信号后,主设备开始发送或接收数据。

数据是按字节传输的,每个字节后面都会跟随一个应答/非应答位。

数据的传输方向由起始信号后的读写位决定。

停止信号:当所有数据都传输完毕后,主设备会发送一个停止信号以结束传输。

停止信号是在时钟线SCL为高电平时,数据线SDA由低电平变为高电平。

对于写操作,主设备在发送完起始信号和设备地址(写)后,开始发送要写入的数据。

每个数据字节后面都需要等待一个应答信号。

当所有数据都发送完毕后,主设备发送停止信号。

对于读操作,主设备在发送完起始信号和设备地址(读)后,会释放SDA线并在SCL线上产生第9个时钟信号。

被选中的设备在确认是自己的地址后,开始在SDA线上传输数据。

主设备在每个数据字节后面都需要发送一个应答信号(除了最后一个字节)。

当读取完所有数据后,主设备发送一个非应答信号和一个停止信号。

以上是I2C通信协议的基本读写时序,但实际的实现可能会根据设备和需求有所不同。

IIC通信协议

IIC通信协议

IIC通信协议协议名称:IIC通信协议一、介绍IIC通信协议是一种串行通信协议,用于在数字集成电路(IC)之间进行数据传输。

它是一种简单、高效、可靠的通信协议,广泛应用于各种电子设备中,如传感器、存储器、显示器等。

二、协议规范1. 物理层规范IIC通信协议使用两根线进行通信,分别为时钟线(SCL)和数据线(SDA)。

SCL由主设备控制,用于传输时钟信号。

SDA用于传输数据信号,包括地址和数据内容。

2. 时序规范IIC通信协议使用起始位、数据位和停止位来组织数据传输。

传输过程中,数据线上的电平变化由主设备和从设备控制。

2.1 起始位起始位由主设备产生,即主设备将数据线上的电平从高变为低。

2.2 数据位数据位由主设备和从设备交替产生。

在每个时钟周期中,数据线上的电平保持稳定,直到下一个时钟周期开始。

数据位可以是地址位或数据内容位。

2.3 停止位停止位由主设备产生,即主设备将数据线上的电平从低变为高。

3. 地址和数据传输IIC通信协议中,地址用于标识从设备,数据用于传输具体内容。

3.1 地址传输主设备首先发送从设备的地址,地址由7位或10位组成,取决于具体的应用场景。

地址的最高位用于指示读取或写入操作,0表示写入,1表示读取。

3.2 数据传输主设备在发送地址之后,可以继续发送数据。

从设备接收到数据后,可以进行相应的处理。

数据的长度可以根据具体需求进行扩展。

4. 确认和应答在每个字节的传输结束后,接收设备需要发送一个应答信号,用于确认数据的接收情况。

应答信号由从设备产生,即从设备将数据线上的电平从低变为高。

5. 错误处理在数据传输过程中,如果发生错误,主设备可以发送重传请求,从设备接收到请求后,可以重新发送数据。

6. 时钟速率IIC通信协议支持不同的时钟速率,可以根据具体需求进行配置。

常用的时钟速率有100kHz和400kHz。

三、应用场景IIC通信协议广泛应用于各种电子设备中,包括但不限于以下场景:1. 传感器:用于传输传感器采集的数据,如温度、湿度、压力等。

i2c标准时序

i2c标准时序

I2C(Inter-Integrated Circuit)是一种常用的串行通信协议,用于在集成电路之间进行通信。

I2C协议定义了一种标准的时序,以下是I2C标准时序的一般流程:
1. 开始条件(Start Condition):由主设备发出一个低电平的SDA(Serial Data)信号,然后再发出一个低电平的SCL(Serial Clock)信号。

这表示一个新的传输周期的开始。

2. 地址传输(Address Transmission):主设备发送目标设备的地址,包括一个7位的设备地址和一个读/写位。

地址的最高位为1表示读操作,为0表示写操作。

3. 应答(Acknowledgement):在每个字节传输完成后,接收设备发送一个应答信号。

如果接收设备收到了正确的数据字节,它会拉低SDA线发送一个低电平的应答信号(ACK)。

如果接收设备没有正确接收到数据,它将不发送应答信号(NACK)。

4. 数据传输(Data Transmission):主设备通过SDA和SCL 线传输数据。

数据以8位为一个单位进行传输,每个字节的最高位先传输。

每个字节传输完成后,接收设备发送一个应答信号。

5. 停止条件(Stop Condition):由主设备发出一个高电平的SDA信号,然后再发出一个高电平的SCL信号。

这表示传输周期的结束。

以上是I2C标准时序的一般流程。

然而,具体的时序可
能会受到设备和应用的限制或要求而有所不同。

因此,在实际使用中,您可能需要参考特定设备的文档或规范来了解其精确的时序要求。

iic的工作原理

iic的工作原理

iic的工作原理集成电路(IIC)是一种用于数字通信的串行总线通信协议,其工作原理如下:1. 主从模式:IIC通信中包括一个主设备(Master)和一个或多个从设备(Slave)。

主设备负责发送起始和停止信号,以及控制通信的时序,而从设备根据主设备的控制来响应。

2. 起始和停止信号:IIC通信在传输数据之前,主设备发送起始信号(START),标志着通信的开始。

在数据传输完成后,主设备发送停止信号(STOP),表示通信结束。

3. 传输格式:IIC通信采用同步时分复用的方式,主设备通过时钟信号(SCL)控制数据的传输。

数据传输的格式包括地址位、读/写位、数据位和应答位。

主设备先发送从设备的地址以及读或写的标志位,然后根据需要传输数据,并在每个字节结束后,从设备发送应答位(ACK)来告知是否接收成功。

4. 时序控制:IIC通信中的时序非常重要,主设备通过控制时序来实现各种操作。

主设备先产生起始信号后,开始发送时钟信号,同时发送控制信号和数据。

从设备接收数据,并根据主设备的指令进行相应的处理,并在每个数据字节结束后产生应答信号。

主设备在接收到应答信号后才能继续发送下一个字节的数据。

5. 速率控制:IIC通信的速率可以通过控制时钟信号的频率来调节。

一般情况下,高速模式下的速率可达到400kHz,而低速模式下的速率较低。

6. 抗干扰能力:IIC通信线路一般使用两根导线(SDA和SCL),其中SDA线用于数据传输,SCL线用于时钟同步。

这种双线结构有较好的抗干扰能力,可以减少外界干扰对通信的影响。

总结:IIC通信通过主从模式、起始和停止信号、传输格式、时序控制、速率控制和抗干扰能力等方面实现了可靠的数字通信,广泛应用于各种电子设备中。

IIC基本概念和基本时序

IIC基本概念和基本时序

IIC基本概念和基本时序1. IIC基本概念和基本时序1.1 I2C串⾏总线概述I2C总线是PHLIPS公司推出的⼀种串⾏总线,是具备多主机系统所需的包括总线裁决和⾼低速器件同步功能的⾼性能串⾏总线。

1、I2C总线具有两根双向信号线,⼀根是数据线SDA,另⼀根是时钟线SCL2、IIC总线上可以挂很多设备:多个主设备,多个从设备(外围设备)。

上图中主设备是两个单⽚机,剩下的都是从设备。

3、多主机会产⽣总线裁决问题。

当多个主机同时想占⽤总线时,企图启动总线传输数据,就叫做总线竞争。

I2C通过总线仲裁,以决定哪台主机控制总线。

4、I2C总线通过上拉电阻接正电源,上拉电阻⼀般在4.7k~10k之间。

当总线空闲时,两根线均为⾼电平。

连到总线上的任⼀器件输出的低电平,都将使总线的信号变低,即各器件的SDA及SCL都是线“与”关系。

5、每个接到I2C总线上的器件都有唯⼀的地址。

主机与其它器件间的数据传输可以是由主机发送数据到其它器件,这时主机即为发送器,总线上收数据的器件则为接收器。

1.2 I2C总线的数据传送1.2.1 I2C总线数据位的有效性规定I2C总线进⾏数据传送时,时钟信号为⾼电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的⾼电平或低电平状态才允许变化。

1.2.2 起始与终⽌信号SCL为⾼电平期间SDA : 由⾼到低,起始信号SDA:由低到⾼,终⽌信号起始信号和终⽌信号都是由主机发送的。

在起始信号产⽣之后,总线就处于被占⽤的状态,在终⽌信号产⽣之后,总线就处于空闲状态。

连接到I2C总线上的器件,若具有I2C总线的硬件接⼝,则很容易检测到起始和终⽌信号。

接收器件收到⼀个完整的数据字节后,有可能需要完成⼀些其它⼯作,如处理内部中断服务等,可能⽆法⽴刻接收下⼀个字节,这时接收器件可以将SCL线拉成低电平,从⽽使主机处于等待状态。

直到接收器件准备好接收下⼀个字节时,再释放SCL线使之为⾼电平,从⽽使数据传送可以继续进⾏。

iic 标准通信时序

iic 标准通信时序

iic 标准通信时序IIC(Inter-Integrated Circuit)是一种通信协议,通常用于短距离数据传输。

它采用双总线(Serial Data Line - SDA 和 Serial Clock Line - SCL)结构,其中SDA用于数据传输,而SCL用于时钟同步。

在IIC通信中,主机设备控制总线并向从设备发送数据,从设备在主机设备的控制下接收和发送数据。

IIC标准通信时序是指IIC通信协议中的数据读取和写入的时间序列。

以下是IIC标准通信时序的相关参考内容:1. 起始信号:在通信开始之前,主机设备发送一个起始信号。

起始信号表示传输的开始。

它由一个低电平到高电平的跳变的边沿表示。

2. 从地址:主机设备在起始信号之后发送从地址。

从地址是从设备的唯一标识符。

它包含一个7位的地址和一个读/写指示位。

地址由主机设备发送并由从设备接收。

3. 确认信号:从设备在接收到从地址后,它会发送一个确认信号,表示它已经准备好进行通信。

确认信号是一个低电平的脉冲。

4. 数据传输:主机设备在确认信号之后,发送数据到从设备。

数据以字节为单位进行传输,每个字节包含8位。

主机设备发送一个字节,然后等待从设备发送一个确认信号。

如果从设备收到了正确的字节,它会发送一个高电平表示确认,否则发送一个低电平表示重新传输。

5. 时钟同步:主机设备通过在SCL线上产生时钟信号来同步数据传输,该时钟信号用于控制数据的传输速率。

时钟信号的频率由主机设备控制和同步。

6. 结束信号:在数据传输完成后,主机设备发送一个结束信号。

结束信号表示通信的结束。

它由一个高电平到低电平的跳变的边缘表示。

以上是关于IIC标准通信时序的一些基本参考内容。

注意,具体的时序细节和具体设备之间可以有所不同,因此在开发和使用IIC协议通信时,应仔细查阅相关的设备手册和规范。

I2C操作时序问题

I2C操作时序问题
读操作过程中需对将指令改写为读指令,在读取数据时需要写入指令指明需要读出数据时的存储器地址号
下面是对24C02的写操作和读操作
void write_add(uchar address,uchar date)
{
start();
write_byte(0xa0); //写指令
respons();
P1=read_add(23); //读入存储器地址号为23中的数据,并将数据赋值给P1口,通过数码管显示
while(1); //停留在此处
}
write_byte(address); //写入要操作的存储器地址
respons();
write_byte(date); //写入存储器数据
respons();
stop();
}
uchar read_add(uchar address)
{
uchar date;
start();
write_byte(0xa0); //写入指令
respons();
write_byte(address); //写入读取操作时,要读取的存储器地址
respons();
stop();
start();
write_byte(0xa1); //写入指令,进行读操作
s();
I2C总线操作(从高位开始进行读写操作)
写操作时序
启动之后先进行一个字节的指令写入操作,然后进行应答;在进行字节数据的传送;然后再进行应答;
I2C读操作时序
基本上与写操作相同,不同的是读操作只需进行指令的写入,不写数据(应该不绝对),
最后主机产生非应答信号,结束数据的读取;

iic通信协议时序

iic通信协议时序

iic通信协议时序
IIC(Inter-Integrated Circuit)通信协议是一种串行通信协议,
也称为I2C通信协议。

它由飞利浦公司开发,用于在集成电路之间进行通信。

IIC通信协议时序主要包括以下几个步骤:
1. SDA线和SCL线处于高电平状态。

在通信开始之前,需要
将SDA和SCL线都拉高。

2. 主设备发送起始信号。

主设备通过将SDA线从高电平拉为
低电平,然后再将SCL线拉低来发送起始信号。

这表示通信
即将开始。

3. 主设备发送设备地址和读写位。

主设备将设备地址和读写位发送给从设备,指示通信是要读取数据还是写入数据。

设备地址是从设备唯一的标识符。

4. 主设备发送数据。

如果是写入操作,主设备可以发送一系列需要写入从设备的数据。

5. 主设备发送停止信号。

主设备通过将SCL先拉高,再将
SDA拉高,发送停止信号表示通信结束。

6. 从设备发送应答信号。

在主设备发送设备地址、读写位和数据之后,从设备需要发送一个应答信号来确认数据的接收情况。

应答信号是通过将SDA线拉低一段时间来发送的。

7. 循环重复上述步骤。

主设备可以继续发送起始信号和数据,进行多次通信操作。

需要注意的是,IIC通信协议是在一个总线上进行通信的,可以连接多个从设备。

每个从设备都有自己的唯一设备地址,主设备在通信时需要选择要与之通信的从设备地址。

在发送数据时,主设备需要等待从设备发送应答信号来确认数据传输的成功。

IIC总线读写时序

IIC总线读写时序
{
I2cStart();
I2cSendByte(0xa0);//发送写器件地址
I2cSendByte(addr);//发送要写入内存地址
I2cSendByte(dat);//发送数据
I2cStop();
}
/*******************************************************************************
/*******************************************************************************
*函数名: delay
*函数功能:延时函数,i=1时,大约延时10us
*******************************************************************************/
void datapros()
{
disp[0]=smgduan[num/1000];//千位
disp[1]=smgduan[num%1000/100];//百位
disp[2]=smgduan[num%1000%100/10];//个位
disp[3]=smgduan[num%1000%100%10];
{
unsigned char a=0,dat=0;
SDA=1;//起始和发送一个字节之后SCL都是0
Delay10us();
for(a=0;a<8;a++)//接收8个字节
{
SCL=1;
Delay10us();
dat<<=1;
dat|=SDA;
Delay10us();
相关主题
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

I2C总线信号时序分析在I2C总线通信的过程中,参与通信的双方互相之间所传输的信息种类归纳如下。

主控器向被控器发送的信息种类有:启动信号、停止信号、7位地址码、读/写控制位、10位地址码、数据字节、重启动信号、应答信号、时钟脉冲。

被控器向主控器发送的信息种类有:应答信号、数据字节、时钟低电平。

下面对I2C总线通信过程中出现的几种信号状态和时序进行分析。

①总线空闲状态。

I2C总线总线的SDA和SCL两条信号线同时处于高电平时,规定为总线的空闲状态。

此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。

②启动信号。

在时钟线SCL保持高电平期间,数据线SDA上的电平被拉低(即负跳变),定义为I2C总线总线的启动信号,它标志着一次数据传输的开始。

启动信号是一种电平跳变时序信号,而不是一个电平信号。

启动信号是由主控器主动建立的,在建立该信号之前I2C总线必须处于空闲状态,如图1所示。

图1 I2C总线上的启动信号和停止信号③停止信号。

在时钟线SCL保持高电平期间,数据线SDA被释放,使得SDA返回高电平(即正跳变),称为I2C总线的停止信号,它标志着一次数据传输的终止。

停止信号也是一种电平跳变时序信号,而不是一个电平信号,停止信号也是由主控器主动建立的,建立该信号之后,I2C总线将返回空闲状态。

④数据位传送。

在I2C总线上传送的每一位数据都有一个时钟脉冲相对应(或同步控制),即在SCL串行时钟的配合下,在SDA上逐位地串行传送每一位数据。

进行数据传送时,在SCL呈现高电平期间,SDA上的电平必须保持稳定,低电平为数据0,高电平为数据1。

只有在SCL为低电平期间,才允许SDA上的电平改变状态。

逻辑0的电平为低电压,而逻辑1的电平取决于器件本身的正电源电压VDD(当使用独立电源时),如图2所示。

图2 I2C总线上的数据位传送⑤应答信号。

I2C总线上的所有数据都是以8位字节传送的,发送器每发送一个字节,就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。

应答信号为低电平时,规定为有效应答位(ACK简称应答位),表示接收器已经成功地接收了该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。

对于反馈有效应答位ACK的要求是,接收器在第9个时钟脉冲之前的低电平期间将SDA线拉低,并且确保在该时钟的高电平期间为稳定的低电平。

如果接收器是主控器,则在它收到最后一个字节后,发送一个NACK信号,以通知被控发送器结束数据发送,并释放SDA线,以便主控接收器发送一个停止信号P,如图3所示。

图3 I2C总线上的应答时序⑥插入等待时间。

如果被控器需要延迟下一个数据字节开始传送的时间,则可以通过把时钟线SCL电平拉低并且保持,使主控器进入等待状态。

一旦被控器释放时钟线,数据传输就得以继续下去,这样就使得被控器得到足够时间转移已经收到的数据字节,或者准备好即将发送的数据字节。

带有CPU的被控器在对收到的地址字节做出应答之后,需要一定的时间去执行中断服务子程序,来分析或比较地址码,其间就把SCL线钳位在低电平上,直到处理妥当后才释放SCL线,进而使主控器继续后续数据字节的发送,如图4所示。

图4 I2C总线上的插入等待时间⑦重启动信号。

在主控器控制总线期间完成了一次数据通信(发送或接收)之后,如果想继续占用总线再进行一次数据通信(发送或接收),而又不释放总线,就需要利用重启动Sr信号时序。

重启动信号Sr既作为前一次数据传输的结束,又作为后一次数据传输的开始。

利用重启动信号的优点是,在前后两次通信之间主控器不需要释放总线,这样就不会丢失总线的控制权,即不让其他主器件节点抢占总线。

⑧时钟同步。

如果在某一I2C总线系统中存在两个主器件节点,分别记为主器件1和主器件2,其时钟输出端分别为CLK1和CLK2,它们都有控制总线的能力。

假设在某一期间两者相继向SCL线发出了波形不同的时钟脉冲序列CLK1和CLK2(时钟脉冲的高、低电平宽度都是依靠各自内部专用计数器定时产生的),在总线控制权还没有裁定之前这种现象是可能出现的。

鉴于I2C总线的“线与”特性,使得时钟线SCL上得到的时钟信号波形,既不像主器件1所期望的CLK1,也不像主器件2所期望的CLK2,而是两者进行逻辑与的结果。

CLKI和CLK2的合成波形作为共同的同步时钟信号,一旦总线控制权裁定给某一主器件,则总线时钟信号将会只由该主器件产生,如图5所示。

图5 I2C总线上的时钟同步⑨总线冲突和总线仲裁。

假如在某I2C总线系统中存在两个主器件节点,分别记为主器件1和主器件2,其数据输出端分别为DATA1和DATA2,它们都有控制总线的能力,这就存在着发生总线冲突(即写冲突)的可能性。

假设在某一瞬间两者相继向总线发出了启动信号,鉴于:I2C总线的“线与”特性,使得在数据线SDA上得到的信号波形是DATA1和DATA2两者相与的结果,该结果略微超前送出低电平的主器件1,其DATA1的下降沿被当做SDA 的下降沿。

在总线被启动后,主器件1企图发送数据“101……”,主器件2企图发送数据“100101……”。

两个主器件在每次发出一个数据位的同时都要对自己输出端的信号电平进行抽检,只要抽检的结果与它们自己预期的电平相符,就会继续占用总线,总线控制权也就得不到裁定结果。

主器件1的第3位期望发送“1”,也就是在第3个时钟周期内送出高电平。

在该时钟周期的高电平期间,主器件1进行例行抽检时,结果检测到一个不相匹配的电平“0”,这时主器件1只好决定放弃总线控制杈;因此,主器件2就成了总线的惟一主宰者,总线控制权也就最终得出了裁定结果,从而实现了总线仲裁的功能。

从以上总线仲裁的完成过程可以得出:仲裁过程主器件1和主器件2都不会丢失数据;各个主器件没有优先级别之分,总线控制权是随机裁定的,即使是抢先发送启动信号的主器件1最终也并没有得到控制杈。

系统实际上遵循的是“低电平优先”的仲裁原则,将总线判给在数据线上先发送低电平的主器件,而其他发送高电平的主器件将失去总线控制权,如图6所示。

图6 I2C总线上的总线仲裁⑩总线封锁状态。

在特殊情况下,如果需要禁止所有发生在I2C总线上的通信活动,封锁或关闭总线是一种可行途径,只要挂接于该总线上的任意一个器件将时钟线SCL 锁定在低电平上即可。

//通用MSP430—I2C程序#include "MSP430x14x.h"//P3.2 SCL//P3.3 SDA#define SDA_1 P3OUT |= BIT3 //SDA = 1#define SDA_0 P3OUT &=~ BIT3 //SDA = 0#define SCL_1 P3OUT |= BIT2 //SCL = 1#define SCL_0 P3OUT &=~ BIT2 //SCL = 0#define DIR_IN P3DIR &=~ BIT3; SDA_1 //I/O口为输入#define DIR_OUT P3DIR |= BIT3 //I/0口为输出#define SDA_IN ((P3IN >> 3) & 0x01) //Read SDAunsigned int a[50];static void Delay(unsigned int n){unsigned int i;for (i=0; i<n;i++);}void Init(void){SCL_1;Delay(5);SDA_1;Delay(5);}void Start(void){SDA_1;Delay(5);SCL_1;Delay(5);SDA_0;Delay(5);SCL_0;Delay(5);}void Stop(void){SDA_0;Delay(5);SCL_1;Delay(5);SDA_1;Delay(5);}void WriteByte(unsigned char WritEDAta) {unsigned char i;for (i=0; i<8; i++){SCL_0;Delay(5);if (((WritEDAta >> 7) & 0x01) == 0x01){SDA_1;}else{SDA_0;}Delay(5);SCL_1;WriteData = WritEDAta << 1;Delay(5);}SCL_0;SDA_1;Delay(5);Delay(5);}unsigned char ReadByte(void){unsigned char i;unsigned char TempBit = 0;unsigned char TempData = 0;SCL_0;Delay(5);SDA_1;for (i=0; i<8; i++){Delay(5);SCL_1;Delay(5);DIR_IN;if (SDA_IN == 0x01 /*sda==1*/){TempBit = 1;}else{TempBit = 0;}DIR_OUT;TempData = (TempData << 1) | TempBit;SCL_0;}Delay(5);return(TempData);}void ReceiveAck(void){unsigned char i = 0;SCL_1;Delay(5);DIR_IN;while ((SDA_IN == 0x01 /*sda==1*/) && (i < 255)/*调试方便,可以不要*/) {i++;}DIR_OUT;SCL_0;Delay(5);}void Acknowledge(void){SCL_0;Delay(5);DIR_OUT;SDA_0;SCL_1;Delay(5);SCL_0;}unsigned int ReadWord(unsigned char unit/*address*/){unsigned char HighData = 0;unsigned char LowData = 0;unsigned int TempData = 0;Start();WriteByte(0xa0);ReceiveAck();WriteByte(unit);ReceiveAck();Start();WriteByte(0xa1);ReceiveAck();LowData = ReadByte();Acknowledge();HighData = ReadByte();Stop();TempData = (HighData << 8) + LowData;Delay(1000);return(TempData);}void ReadWords(unsigned char unit/*address*/) {unsigned char i;unsigned char HighData = 0;unsigned char LowData = 0;unsigned int TempData = 0;Start();WriteByte(0xa0);ReceiveAck();WriteByte(unit);ReceiveAck();Start();WriteByte(0xa1);ReceiveAck();for (i=0; i<49; i++){LowData = ReadByte();Acknowledge();HighData = ReadByte();Acknowledge();a[i]= (HighData << 8) + LowData;}LowData = ReadByte();Acknowledge();HighData = ReadByte();Stop();a[49] = (HighData << 8) + LowData;Delay(1000);}void WriteWord(unsigned char unit/*address*/, unsigned int WritEDAta) {unsigned char LowData = 0;unsigned char HighData = 0;LowData = (unsigned char)WritEDAta;HighData = (unsigned char)(WritEDAta >> 8);Start();WriteByte(0xa0);ReceiveAck();WriteByte(unit);ReceiveAck();WriteByte(LowData);ReceiveAck();WriteByte(HighData);ReceiveAck();Stop();Delay(2000);}。

相关文档
最新文档