1.what is I2C?

简单讲就是用来传输数据的两根线:一根数据线(SDA)一根时钟线(SCL)

2.I2C怎么传输的?

(1)基本过程:
1.主机发出开始信号
2.主机接着发出一字节的从机地址信息,其中最低位为读写控制码(1为读、0为写), 高七位为从机器件地址
3.从机发出认可信号
4.主机开始发送信号,每发完一字节后,从机发出认可信号给主机
5.主机发出停止信号

(2)对以上信号的具体说明:
开始信号:在时钟线为高电平期间,数据线由高变低,将产生一个开始信号
停止信号:在时钟线为高电平期间,数据线由低变高,将产生一个停止信号
应答信号:即认可信号,主机写从机时,每写完一个字节,如果正确从机将在下一个时钟周期将数据线拉低,以告诉主机操作有效。在主机读从机的时候,正确读完一个字节后,主机在下一个时钟周期同样也要将数据线拉低,发出认可信号,告诉从机所发数据已经收妥(注:读从机时主机在最后一个字节数据接收完后,不发应答,直接发停止信号)

注意:任何在时钟线为高电平期间的数据线上的电平改变都被认为是起始和停止信号,所以数据改变必须要在时钟为低电平时改变。

(3)数据格式:

I2C支持两种数据格式:

7bit/10bit寻址数据格式

7bit/10bit寻址和重复开始信号的格式

从设备地址:

总线上每个设备都有自己的一个addr,共7个bit,广播地址全0.
系统中可能有多个同种芯片,为此addr分为固定部分和可编程部份,细节视芯片而定,看datasheet。

硬件结构:

每一个I2C总线器件内部的SDA、SCL引脚电路结构都是一样的,引脚的输出驱动与输入缓冲连在一起。其中输出为漏极开路的场效应管、输入缓冲为一只高输入阻抗的同相器。这种电路具有两个特点:

(1)由于 SDA、SCL 为漏极开路结构,借助于外部的上拉电阻实现了信号的“线与”逻辑;
(2)引脚在输出信号的同时还将引脚上的电平进行检测,检测是否与刚才输出一致。为 “时钟同步”和“总线仲裁”提供硬件基础。

3.几个I2C的疑问

(1)模拟I2C与硬件I2C有什么区别

原理上:硬件I2C(提供专门的SDA,SCL口)的时钟是系统产生的,一般由晶振分频产生。模拟I2C通过编程模拟时钟线和数据线。

控制上:硬件I2C通过硬件中断实现各种操作。模拟I2C没有中断的概念,通过IO口电平置高置低来实现写入和读取。

性能上:硬件模式更高效更稳定。

(2)MPU6050和MPU9250的I2C

之前对于这两个芯片的通过I2C的操作地址有点乱,如要获取到加速度计的原始值,首先要发送开始信号,然后是发送从机地址(I2C的设备地址),然后发送寄存器的地址(这里很多人会搞乱了,因为要发两次地址,第一次是I2C设备地址,第二次是加速度计的地址),接下来才能获取到原始数据。

(3)slave address
i2c通讯是master下可能挂多个slave,每个slave拥有不同的slave address,master通过不同的address设置来遍历下挂的slave,每个i2c接口的芯片会有不同的slave addres配置。芯片厂商在设计i2c接口时会设计多个address配置,以避免多slave访问时地址重复,如下举例tmp513温控芯片slave address的设置:

4.怎么实现I2C?

之前的所有铺垫都是为了实现I2C通讯,所以怎么用代码实现也是尤为关键的一个问题。

下面是是I2C的读写流程:

写寄存器的标准流程为:

  1. Master发起START
  2. Master发送I2C addr(7bit)和w操作0(1bit),等待ACK
  3. Slave发送ACK
  4. Master发送reg addr(8bit),等待ACK
  5. Slave发送ACK
  6. Master发送data(8bit),即要写入寄存器中的数据,等待ACK
  7. Slave发送ACK
  8. 第6步和第7步可以重复多次,即顺序写多个寄存器
  9. Master发起STOP
void Tmp513_Reg_Write(unsigned char regaddr, unsigned short regdata)
{ unsigned int i;unsigned int j;unsigned char opcode;unsigned char low_regdata;unsigned char high_regdata;low_regdata = regdata & 0xff;high_regdata = (regdata >> 8) & 0xff;TMP513_DATA_OUT;// START(TMP513_SDA->DATA) = 0;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 0;opcode = TMP513_WRITE_CODE;// Operation codefor(i = 0; i < 7; i++){(TMP513_SDA->DATA) = opcode;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 1;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 0;opcode = opcode >> 1;}(TMP513_SDA->DATA) = opcode;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 1;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 0;// Slave ACKTMP513_DATA_IN;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 1;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 0;// Reg addressTMP513_DATA_OUT;for(i = 0; i < 7; i++){(TMP513_SDA->DATA) = (regaddr >> (7-i));Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 1;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 0;}(TMP513_SDA->DATA) = regaddr;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 1;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 0;// Slave ACKTMP513_DATA_IN;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 1;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 0;// Write high byteTMP513_DATA_OUT;for(j = 0; j < 7; j++){(TMP513_SDA->DATA) = (high_regdata >> (7 - j));Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 1;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 0;}(TMP513_SDA->DATA) = high_regdata;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 1;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 0;// Slave ACKTMP513_DATA_IN;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 1;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 0;// Write low byteTMP513_DATA_OUT;for(j = 0; j < 7; j++){(TMP513_SDA->DATA) = (low_regdata >> (7 - j));Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 1;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 0;}(TMP513_SDA->DATA) = low_regdata;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 1;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 0;// Slave ACKTMP513_DATA_IN;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 1;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 0;// StopTMP513_DATA_OUT;(TMP513_SDA->DATA) = 0;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 1;Delay(TMP513_DELAY);(TMP513_SDA->DATA) = 1;TMP513_DATA_IN;
}

读寄存器的标准流程为:

  1. Master发送I2C addr(7bit)和w操作1(1bit),等待ACK
  2. Slave发送ACK
  3. Master发送reg addr(8bit),等待ACK
  4. Slave发送ACK
  5. Master发起START
  6. Master发送I2C addr(7bit)和r操作1(1bit),等待ACK
  7. Slave发送ACK
  8. Slave发送data(8bit),即寄存器里的值
  9. Master发送ACK
  10. 第8步和第9步可以重复多次,即顺序读多个寄存器

以上通讯流程模拟I2C跟硬件I2C都类似,不同的地方是读写:

附i2c读写过程驱动c代码:

unsigned short Tmp513_Reg_Read(unsigned char regaddr)
{ unsigned int i;unsigned int j;unsigned char opcode;unsigned short readdata;// Register pointer setTMP513_DATA_OUT;// START(TMP513_SDA->DATA) = 0;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 0;// Operation codeopcode = TMP513_WRITE_CODE;for(i = 0; i < 7; i++){(TMP513_SDA->DATA) = opcode;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 1;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 0;opcode = opcode >> 1;}(TMP513_SDA->DATA) = opcode;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 1;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 0;// Slave ACKTMP513_DATA_IN;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 1;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 0;// Reg addressTMP513_DATA_OUT;for(i = 0; i < 7; i++){(TMP513_SDA->DATA) = (regaddr >> (7-i));Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 1;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 0;}(TMP513_SDA->DATA) = regaddr;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 1;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 0;// Slave ACKTMP513_DATA_IN;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 1;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 0;// StopDelay(TMP513_DELAY);TMP513_DATA_OUT;(TMP513_SDA->DATA) = 0;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 1;Delay(TMP513_DELAY);(TMP513_SDA->DATA) = 1;TMP513_DATA_IN;// Read register// StartTMP513_DATA_OUT;Delay(TMP513_DELAY);(TMP513_SDA->DATA) = 0;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 0;// Operation codeopcode = TMP513_READ_CODE;for(i = 0; i < 7; i++){(TMP513_SDA->DATA) = opcode;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 1;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 0;opcode = opcode >> 1;}(TMP513_SDA->DATA) = opcode;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 1;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 0;// Slave ACKTMP513_DATA_IN;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 1;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 0;// Read reg's high bytereaddata = 0;for(j = 0; j < 8; j++){Delay(TMP513_DELAY);readdata =    readdata << 1;readdata = ((TMP513_SDA->DATA) & 0x00000001) | readdata;(TMP513_SCL->DATA) = 1;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 0;}// Master ACKDelay(TMP513_DELAY);TMP513_DATA_OUT;(TMP513_SDA->DATA) = 0;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 1;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 0;TMP513_DATA_IN;// Read reg's low bytefor(j = 0; j < 8; j++){Delay(TMP513_DELAY);readdata =     readdata << 1;readdata = ((TMP513_SDA->DATA) & 0x00000001) | readdata;(TMP513_SCL->DATA) = 1;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 0;}// Master NO ACKDelay(TMP513_DELAY);(TMP513_SCL->DATA) = 1;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 0;// StopTMP513_DATA_OUT;(TMP513_SDA->DATA) = 0;Delay(TMP513_DELAY);(TMP513_SCL->DATA) = 1;Delay(TMP513_DELAY);(TMP513_SDA->DATA) = 1;TMP513_DATA_IN;return readdata;
}

i2c协议解读(附读写过程c代码)相关推荐

  1. I2C总线学习(四)--读写过程

    写入过程 单片机进行写操作时,首先发送该器件的7位地址码和写方向位"0"(共8位,即一个字节),发送完后释放SDA线并在SCL线上产生第9个时钟信号.被选中的存储器器件在确认是自己 ...

  2. 树莓派3B+使用0.96 oled 屏幕(附完整可运行代码)

    树莓派3B+使用 0.96寸oled 屏幕(附完整可运行代码) 一.基本配置 先阅读以下博客较为详解,完成基本配置以及相关代码的说明 0.96寸OLED 使用树莓派的I2C协议调用wiringPiI2 ...

  3. SDIO协议梳理附SD卡读写以及FATFS移植实例

    文章列表 嵌入式各协议标准按照OSI模型的思路进行逐个梳理,文章列表如下: 串行通信&UART协议梳理附STM32平台采用DMA以UART方式收发不定长信息 I²C总线协议梳理附STM32平台 ...

  4. STM32学习之I2C协议(读写EEPROM)

    关于STM32学习分享 第七章 I2C协议(读写EEPROM) 文章目录 关于STM32学习分享 前言 二.代码 1.i2c.c 2.i2c.h 3.main.c 总结 前言 开始!开始!单片机的I2 ...

  5. 基于Python的文件批量重命名(附详细过程解读)

    基于Python的文件批量重命名(附详细过程解读) 0.闲言碎语 hi ~ 欢迎关注公众号"壹贰叁言"! 啥都写,图一乐哈哈! 1.前因后果 前几日,我在用arcgis处理一些数据 ...

  6. siris 显著性排序网络代码解读(training过程)Inferring Attention Shift Ranks of Objects for Image Saliency

    阅前说明 前面已经出现的代码用 - 代替. 本文仅解析train部分的代码(inference的部分会后续更新). 不对网络结构做过多解释,默认已经熟悉 mrcnn 的结构以及读过这篇论文了. 另:i ...

  7. I2C 协议 代码详解

    I2C 协议   最后代码已上传!!!!   代码文章链接    github 代码链接在该文章最后 I2C 简要介绍 I2C 总线(I2C bus,Inter-IC bus)是一个双向的两线连续总线 ...

  8. 【数字IC】深入浅出理解I2C协议

    深入浅出理解I2C协议 一.什么是I2C协议 二.I2C,SPI,UART协议的区别 三.I2C的信号线 四.I2C的连接方式 4.1 单主设备,单从设备 4.2 单主设备,多从设备 4.3 多主设备 ...

  9. STM32CubeIDE开发(十六),I2C协议采集传感器数据(SHTC1、LTR-553ALS、BMP280、LSM6DSL、MMC3680KJ)

    目录 一.I2C总线协议 二.I2C协议的两种从机应对方式 三.传感器信息 四.工程创建及引脚配置 五.STCH1传感器实现 六.LTR_553ALS传感器(light sensor [ALS] an ...

最新文章

  1. c语言作业扩展名通常为什么,C语言的源程序通常的扩展名是( )
  2. linux启停was命令,linux下的启停脚本
  3. url模块和querystring模块
  4. 封装、继承和构造函数
  5. 一次代码审计实战案例【思路流程】
  6. 小学用计算机画画 说课,小学教师说课稿:《画画美丽的自然景色》
  7. 独立艺术家大谷spizher带你玩转PaddleGAN
  8. 20应用统计考研复试要点(part21)--概率论与数理统计
  9. IDEA导入旧版本项目maven不会自动下载依赖JAR包处理方法
  10. Linux Bash Shell学习(十八):String I/O——echo和printf
  11. SQLSERVER:sqlserver2008r2安装好后,自动提示功能不可以使用
  12. MySQL(6)--- 创建数据库
  13. Java之美[从菜鸟到高手演变]之JVM内存管理及垃圾回收
  14. java类转换异常,java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long
  15. UEFI开发探索22 – 环境搭建3(使用UDK2018搭建)
  16. TCP和UPD的理解
  17. 科目三: 济南章丘五号线
  18. 谷尼国际软件-企业竞争情报系统
  19. 计算机加域后数据库无法登录,[MDT] 解决因加域客户端 Windows 登录身份引发的无法打开登录所请求的数据库故障...
  20. 一位程序员搬家到新加坡的体验

热门文章

  1. 那些年被你亲手敲烂过的键盘
  2. Typora下载和安装
  3. spaceclaim简单建模2
  4. 浅谈微端游戏设计思路
  5. 【VRP问题】基于matlab模拟退火算法求解带容量的VRP问题(多车型)
  6. 一阶RC和二阶RC低通滤波器
  7. 树莓派3Python驱动TSL2561
  8. Exceeded limit on max bytes to buffer : 262144
  9. 维盟WayOS2017工控版Vmware虚拟机安装
  10. struts2中拦截器与过滤器