声明

本文大部分内容为转载,因此标定为转载

源地址:

http://www.cnblogs.com/zym0805/archive/2011/07/31/2122890.html

http://blog.csdn.net/lxl123/article/details/22884719

I2C协议

简介

I2C是由Philips公司发明的一种串行数据通信协议,仅使用两根信号线:SerialClock(简称SCL)和SerialData(简称SDA)。I2C是总线结构,1个Master,1个或多个Slave,各Slave设备以7位地址区分,地址后面再跟1位读写位,表示读(=1)或者写(=0),所以我们有时也可看到8位形式的设备地址,此时每个设备有读、写两个地址,高7位地址其实是相同的。

数据格式

I2C数据格式如下:

无数据:SCL=1,SDA=1;

开始位(Start):当SCL=1时,SDA由1向0跳变;

停止位(Stop):当SCL=1时,SDA由0向1跳变;

数据位:当SCL由0向1跳变时,由发送方控制SDA,此时SDA为有效数据,不可随意改变SDA;

当SCL保持为0时,SDA上的数据可随意改变;

地址位:定义同数据位,但只由Master发给Slave;

应答位(ACK):当发送方传送完8位时,发送方释放SDA,由接收方控制SDA,且SDA=0;

否应答位(NACK):当发送方传送完8位时,发送方释放SDA,由接收方控制SDA,且SDA=1。

传输过程

当数据为单字节传送时,格式为:

开始位,8位地址位(含1位读写位),应答,8位数据,应答,停止位。

当数据为一串字节传送时,格式为:

开始位,8位地址位(含1位读写位),应答,8位数据,应答,8位数据,应答,……,8位数据,应答,停止位。

注意事项

  1. SCL一直由Master控制,SDA依照数据传送的方向,读数据时由Slave控制SDA,写数据时由Master控制SDA。当8位数据传送完毕之后,应答位或者否应答位的SDA控制权与数据位传送时相反。
  2. 开始位“Start”和停止位“Stop”,只能由Master来发出。
  3. 地址的8位传送完毕后,成功配置地址的Slave设备必须发送“ACK”。否则否则一定时间之后Master视为超时,将放弃数据传送,发送“Stop”。
  4. 当写数据的时候,Master每发送完8个数据位,Slave设备如果还有空间接受下一个字节应该回答“ACK”,Slave设备如果没有空间接受更多的字节应该回答“NACK”,Master当收到“NACK”或者一定时间之后没收到任何数据将视为超时,此时Master放弃数据传送,发送“Stop”。
  5. 当读数据的时候,Slave设备每发送完8个数据位,如果Master希望继续读下一个字节,Master应该回答“ACK”以提示Slave准备下一个数据,如果Master不希望读取更多字节,Master应该回答“NACK”以提示Slave设备准备接收Stop信号。
  6. 当Master速度过快Slave端来不及处理时,Slave设备可以拉低SCL不放(SCL=0将发生“线与”)以阻止Master发送更多的数据。此时Master将视情况减慢或结束数据传送。

伪代码实现

起始位,停止位

/*
函数:I2C_Start()
功能:产生I2C总线的起始状态
说明:
SCL处于高电平期间,当SDA出现下降沿时启动I2C总线
不论SDA和SCL处于什么电平状态,本函数总能正确产生起始状态
本函数也可以用来产生重复起始状态
本函数执行后,I2C总线处于忙状态
*/
void I2C_Start()
{
EA=0; I2C_SCL = 1;
I2C_Delay();
I2C_SDA = 1;
I2C_Delay(); //起始条件建立时间大于4.7us延时
I2C_SDA = 0; //发送起始信号
I2C_Delay();
I2C_SCL = 0; //钳住I2C总线,准备发送或接收数据
I2C_Delay();
I2C_Delay();
I2C_Delay();
} /*
函数:I2C_Stop()
功能:产生I2C总线的停止状态
说明:
SCL处于高电平期间,当SDA出现上升沿时停止I2C总线
不论SDA和SCL处于什么电平状态,本函数总能正确产生停止状态
本函数执行后,I2C总线处于空闲状态
*/
void I2C_Stop()
{
unsigned int t = I2C_STOP_WAIT_VALUE; I2C_SDA = 0; //发送结束条件的数据信号
I2C_Delay(); I2C_SCL = 1; //发送结束条件的时钟信号
I2C_Delay();
I2C_SDA = 1; //发送I2C总线结束信号
I2C_Delay();
EA=1;
while ( --t != 0 ); //在下一次产生Start之前,要加一定的延时
}

单字节读和写

/*
函数:I2C_Write()
功能:向I2C总线写1个字节的数据
参数:
dat:要写到总线上的数据
*/
void I2C_Write(unsigned char dat)
{
/*发送1,在SCL为高电平时使SDA信号为高*/
/*发送0,在SCL为高电平时使SDA信号为低*/
unsigned char t ;
for(t=0;t<8;t++)
{ I2C_SDA = (bit)(dat & 0x80);
I2C_Delay();
I2C_SCL = 1; //置时钟线为高,通知被控器开始接收数据位
I2C_Delay();
I2C_SCL = 0;
I2C_Delay();
dat <<= 1;
} } /*
函数:I2C_Read()
功能:从从机读取1个字节的数据
返回:读取的一个字节数据
*/
unsigned char I2C_Read()
{
unsigned char dat=0;
unsigned char t ;
bit temp;
I2C_Delay();
I2C_Delay();
I2C_SDA = 1; //在读取数据之前,要把SDA拉高 I2C_Delay(); for(t=0;t<8;t++)
{
I2C_SCL = 0; /*接受数据*/
I2C_Delay();
I2C_SCL = 1;//置时钟线为高使数据线上升沿数据有效
I2C_Delay();
temp = I2C_SDA;
dat <<=1;
if (temp==1) dat |= 0x01;
} I2C_SCL = 0;
I2C_Delay(); return dat;
}

ACK & NACK

/*
函数:I2C_GetAck()
功能:读取从机应答位
返回:
0:从机应答
1:从机非应答
说明:
从机在收到每个字节的数据后,要产生应答位
从机在收到最后1个字节的数据后,一般要产生非应答位
*/
bit I2C_GetAck()
{
bit ack;
unsigned char Error_time=255; I2C_Delay();
I2C_SDA = 1; /*8位发送完后释放数据线,准备接收应答位 释放总线*/
I2C_Delay();
I2C_SCL = 1; /*接受数据*/
I2C_Delay();
do
{
ack = I2C_SDA;
Error_time--;
if(Error_time==0)
{
I2C_SCL = 0;
I2C_Delay();
return 1;
}
}while(ack); //判断是否接收到应答信号 I2C_SCL = 0; //清时钟线,钳住I2C总线以便继续接收
I2C_Delay();
I2C_Delay();
I2C_Delay();
return 0;
} /*
函数:I2C_PutAck()
功能:主机产生应答位或非应答位
参数:
ack=0:主机产生应答位
ack=1:主机产生非应答位
说明:
主机在接收完每一个字节的数据后,都应当产生应答位
主机在接收完最后一个字节的数据后,应当产生非应答位
*/
void I2C_PutAck(bit ack)
{ I2C_SDA = ack; //在此发出应答或非应答信号
I2C_Delay();
I2C_SCL = 1; //应答
I2C_Delay(); I2C_SCL = 0; //清时钟线,钳住I2C总线以便继续接收 ,继续占用
I2C_Delay(); //等待时钟线的释放
I2C_Delay();
I2C_Delay();
I2C_Delay(); }

多字节读和写

/*
函数:I2C_Puts()
功能:主机通过I2C总线向从机发送多个字节的数据
参数:
SlaveAddr:从机地址(高7位是从机地址,最低位是写标志0)
SubAddr:从机的子地址
Size:数据的字节数
*dat:要发送的数据
返回:
0:发送成功
1:在发送过程中出现异常
*/
bit I2C_Puts(unsigned char SlaveAddr, unsigned char SubAddr, unsigned char Size, char *dat)
{
//检查长度
if ( Size == 0 ) return 0;
//确保从机地址最低位是0
SlaveAddr &= 0xFE;
//启动I2C总线
I2C_Start();
//发送从机地址
I2C_Write(SlaveAddr);
if ( I2C_GetAck() )
{
I2C_Stop();
return 1;
}
//发送子地址
I2C_Write(SubAddr);
if ( I2C_GetAck() )
{
I2C_Stop();
return 1;
}
//发送数据
do
{
I2C_Write(*dat++);
if ( I2C_GetAck() )
{
I2C_Stop();
return 1;
}
} while ( --Size != 0 );
//发送完毕,停止I2C总线,并返回结果
I2C_Stop();
return 0;
} /*
函数:I2C_Put()
功能:主机通过I2C总线向从机发送1个字节的数据
参数:
SlaveAddr:从机地址(高7位是从机地址,最低位是写标志0)
SubAddr:从机的子地址
dat:要发送的数据
返回:
0:发送成功
1:在发送过程中出现异常
*/
bit I2C_Put(unsigned char SlaveAddr, unsigned char SubAddr, char dat)
{
return I2C_Puts(SlaveAddr,SubAddr,1,&dat);
} /*
函数:I2C_Gets()
功能:主机通过I2C总线从从机接收多个字节的数据
参数:
SlaveAddr:从机地址(高7位是从机地址,最低位是读标志1)
SubAddr:从机的子地址
Size:数据的字节数
*dat:保存接收到的数据
返回:
0:接收成功
1:在接收过程中出现异常
*/
bit I2C_Gets(unsigned char SlaveAddr, unsigned char SubAddr, unsigned char Size, unsigned char *dat)
{ //检查长度
if ( Size == 0 ) return 0;
//确保从机地址最低位是0
SlaveAddr &= 0xFE; //确保最低位是0
//启动I2C总线
I2C_Start();
//发送从机地址
I2C_Write(SlaveAddr);
if ( I2C_GetAck() )
{
I2C_Stop();
return 1;
}
//发送子地址
I2C_Write(SubAddr);
if ( I2C_GetAck() )
{
I2C_Stop();
return 1;
}
//发送重复起始条件
I2C_Start();
//发送从机地址
SlaveAddr |= 0x01;
I2C_Write(SlaveAddr);
if ( I2C_GetAck() )
{
I2C_Stop();
return 1;
}
//接收数据
for (;;)
{
*dat++ = I2C_Read();
if ( --Size == 0 )
{
I2C_PutAck(1);
break;
}
I2C_PutAck(0);
} //接收完毕,停止I2C总线,并返回结果
I2C_Stop();
return 0;
} /*
函数:I2C_Get()
功能:主机通过I2C总线从从机接收1个字节的数据
参数:
SlaveAddr:从机地址(高7位是从机地址,最低位是读标志1)
SubAddr:从机的子地址
*dat:保存接收到的数据
返回:
0:接收成功
1:在接收过程中出现异常
*/
bit I2C_Get(unsigned char SlaveAddr, unsigned char SubAddr, unsigned char *dat)
{
return I2C_Gets(SlaveAddr,SubAddr,1,dat);
}

i2c协议简要分析(转载)的更多相关文章

  1. InnoDB多版本(MVCC)实现简要分析(转载)

    http://hedengcheng.com/?p=148 基本知识 假设对于多版本(MVCC)的基础知识,有所了解.InnoDB为了实现多版本的一致读,采用的是基于回滚段的协议. 行结构 InnoD ...

  2. 微店APP协议简要分析

    1.通过抓包软件charles进行抓包,点击微信收款后,抓包内容都是加密处理过  2.加载分析定位这些字段的加密函数. WDTNThorParameterProcessor HTTPBody:task ...

  3. I2C总线协议图解(转载)

    转自:http://blog.csdn.net/w89436838/article/details/38660631 另外,https://blog.csdn.net/qq_38410730/arti ...

  4. iNode协议再次分析

    iNode协议再次分析 声明: 1)本报告由博客园bitpeach撰写,版权所有,免费转载,请注明出处,并请勿作商业用途. 2)若本文档内有侵权文字或图片等内容,请联系作者bitpeach删除相应部分 ...

  5. 转:InnoDB多版本(MVCC)实现简要分析

    InnoDB多版本(MVCC)实现简要分析 基本知识 假设对于多版本(MVCC)的基础知识,有所了解.InnoDB为了实现多版本的一致读,采用的是基于回滚段的协议. 行结构 InnoDB表数据的组织方 ...

  6. Android IOS WebRTC 音视频开发总结(八十六)-- WebRTC中RTP/RTCP协议实现分析

    本文主要介绍WebRTC中的RTP/RTCP协议,作者:weizhenwei ,文章最早发表在编风网,微信ID:befoio 支持原创,转载必须注明出处,欢迎关注我的微信公众号blacker(微信ID ...

  7. (原创) 巩固理解I2C协议(MCU,经验)

        题外话:这几天天气突然转冷了.今天已是11月23日了,查查黄历,昨天(11月22日)刚好是小雪,一夜温度骤降,果然老祖先的经验有灵验!冬天来了,还是多加加衣服,注意保暖! 1.Abstract ...

  8. Google发布SSLv3漏洞简要分析报告

    今天上午,Google发布了一份关于SSLv3漏洞的简要分析报告.根据Google的说法,该漏洞贯穿于所有的SSLv3版本中,利用该漏洞,黑客可以通过中间人攻击等类似的方式(只要劫持到的数据加密两端均 ...

  9. CVE-2015-5122 简要分析(2016.4)

    CVE-2015-5122 简要分析 背景 最近在学习Flash漏洞的分析,其与IE漏洞的分析还是有诸多的不同(不便)之处,折腾了一阵子终于克服了没有符号表.Flash的超时定时器等问题.所以找到了去 ...

随机推荐

  1. Flask最佳实践

    https://zhuanlan.zhihu.com/p/22774028?refer=python-cn

  2. Git——1

    集中式版本控制系统,版本库是集中存放在中央服务器的,而干活的时候,用的都是自己的电脑,所以要先从中央服务器取得最新的版本,然后开始干活,干完活了,再把自己的活推送给中央服务器.中央服务器就好比是一个图 ...

  3. SQL Server 2014 SP2发布下载:数十项更新修复

    微软发布了数据库工具SQL Server 2014 SP2服务包下载,本次更新集合了数十项更新修复,涉及安全和功能性补丁,使用SQL Server 2014的用户应该及时安装该服务包. 文件内容 版本 ...

  4. Javascript 实现HTML字符串的储存

    在js中使用HTML字符串时,可以不用理会字符串的单引号和双引号的转义,因为使用的注释,注释当然什么都可以写. PS:这个有点类似于 php中的 <<<语法(heredoc和nowd ...

  5. 物料主数据MRP4中的独立/集中

    转自悲守穷庐 http://blog.itpub.net/12287/viewspace-681569/ 从按订单还是按库存来考虑. (1)独立集中为空,即又上层决定独立集中情况 (2)独立集中为1: ...

  6. pip install tushare

    1.sudo apt-get install libxml2-dev libxslt1-dev python-dev apt-get install libevent-dev pip install ...

  7. Android开发-mac上使用三星S3做真机调试

    之前一直未使用真机进行Android开发,为准备明天的培训,拿出淘汰下来的s3准备环境,竟然发现无法连接mac,度娘一番找到答案,如下:mac 系统开发android,真机调试解决方案(无数的坑之后吐 ...

  8. 规则引擎集成接口(四)SQL执行语句

    SQL执行语句 右键点击数据库连接文件“hr”—“添加SQL执行语句”,如下图: 弹出窗体,如下图: 将显示名称改为“部门名称”,返回至类型设置为“string”,在编写sql语句,如下图: 点击确定 ...

  9. JS-安全检测JavaScript基本数据类型和内置对象的方法

    前言:在前端开发中经常会需要用到检测变量数据类型的需求,比如:判断一个变量是否为undefined或者null来进行下一步的操作,今天在阅读“编写高质量代码-改善JavaScript程序的188个建议 ...

  10. ASP.NET权限管理

    ASP.NET Web Forms权限管理: 我要将一个文件夹只能让一个用户组访问怎么办? 可否在网站根目录下的web.config里这样设置: <location path="adm ...