1. I2C简介

I2C(Inter-Integrated Circuit:内部集成电路)总线是由Philips公司开发的一种简单、双向二线制同步串行总线。(来源于百度百科)

总结其主要特点如下:

  1. 只需要两条总线:串行数据线(SDA)和串行时钟线(SCL),数据线即用来表示数据,时钟线用于数据收发同步。
  2. 每个连接到总线的设备都有一个独立地址,主机可以利用这个地址进行不同设备之间的访问。I2C总线支持最大从机数理论上为127个(7位寻址,112个非保留地址;10位寻址,1008个非保留地址)。
  3. 两条线都是开漏输出,因此总线通过上拉电阻接到单元。当I2C设备空闲时,会输出高阻态,而当所有设备都空闲,都输出高阻态时,由上拉电阻把总线拉成高电平。通常在标准模式下,使用10K上拉电阻;快速模式下使用2K上拉电阻(速度与电阻成反比)。
  4. 多个主机同时使用总线时,为了防止数据冲突,会利用仲裁方式(仲裁:由多个主机同时尝试控制总线但只允许其中一个控制总线并 使传输不被破坏的过程)决定由哪个设备占用总线。
  5. 具有三种传输模式:标准模式传输速率为 100kbit/s,快速模式为 400kbit/s,高速模式下可达 3.4Mbit/s(大多 I2C 设备不支持高速模式),超快速模式,5Mbit/s。
  6. 总线接口已经集成在芯片内部,不需要特殊的接口电路。

图(1)I2C通讯设备常用的连接方式

1.1 I2C数据传输协议与格式

I2C的协议定义了通信的起始、停止信号、数据有效性、响应、仲裁、时钟同步和地址广播等环节

1.1.1 起始信号

SCL(串行时钟线)为高电平期间,SDA(串行数据线)由高电平向低电平的下降沿表示为起始信号。起始信号是由主机发出的,在起始信号产生后,总线处于被占用状态。如下图所示:

图(2)I2C通讯起始信号

1.1.2 数据有效性规定

I2C总线进行数据传输时,SCL(串行时钟线)为高电平期间,数据线上的数据必须保持稳定,只有在SCL(串行时钟线)上的信号为低电平期间,数据线上的高低电平才允许变化,如下图所示:

图(3)I2C信号数据有效性示意图

1.1.3 应答响应

每当发送器件传输完一个字节(八位二进制)的数据后,必须紧跟一个校验位,此校验位是接收端控制SDA(串行数据线)来实现的,提醒发送端数据接收完成,可以继续进行下一字节传输。响应包括了 “ 应答(ACK:Acknowledgement)” 和 “ 非应答(NACK:Negative ACKnowledgment)”两种信号。

无论主从机,当作为数据接收端时,接收到一个字节数据或地址后,如果希望对方继续发送下一个字节数据,则需要向对方发送“应答(ACK)”信号;

反之,如果希望对方结束数据的传输,,则要向对方发送 “ 非应答(ACK)” 信号。

其中 “ 应答(ACK)” 信号为定义为发送数据端释放SDA(串行数据线),此时由于外部上拉电阻作用上拉为高电平。数据接收端再通过拉底SDA(串行数据线),即将SDA“置0”,发送端接收到接收端ACK应答信号后,则可继续传输数据。

图(4)I2C通讯ACK信号

“ 非应答(ACK)”信号定义为 :

图(5)I2C通讯NACK信号

1.1.4 停止信号

SCL(串行时钟线)为高电平期间,SDA(串行数据线)由低电平向高电平的变化表示停止信号。如下图所示:

图(6)I2C通讯停止信号

1.2 I2C的数据传输与数据帧

1.2.1 I2C数据传输的基本格式

I2C数据传输必须从开始信号开始,传输数据的每个字节必须保证长度是八位,且先传送最高位,每一个传送的自己后必须跟随一个应答位,即一帧有9位。

I2C数据帧有三种基本格式:

1.2.2 发送一帧数据

图(7)I2C通讯发送数据格式

将前面的各个数据传输格式按此数据帧组合,就可以得到I2C发送一帧数据的时序图,如假设向地址为1010101的从机写入大写字母V(对应ASCII码:10101100)时,其对应时序图如下:

图(8)I2C通讯给指定地址从机发送一字节数据

1.2.3 接收一帧数据

图(8)I2C通讯接收数据格式

需要有所注意的是,当读写控制位置1时,相当于把I2C总线控制权交予从机,因此在收到从机发送来的数据后,应是注意发送应答给从机,从机在收到ACK信号后,继续传输下一字节。因此当传输最后一个字节时,主机发送应答或是非应答都是可行的。如假设向地址为1010101的从机读出大写字母V(对应ASCII码:10101100)时,其对应时序图如下:

 图(9)I2C通讯接收指定地址从机一字节的数据

1.2.4 复合格式

图(10)I2C通讯复合格式

当我们使用I2C通讯时,复合格式即先发送再接收数据帧,其本质任可理解为接收数据,时序图略。

1.3 I2C的硬件电路

1.3.1 漏极开路输出OD输出(Open Drain)

漏极开路输出,即OD输出(Open Drain)其主要示意图如下:

图(11)开漏输出示意图

由上图可知,内部电路中控制场效应关的导通与关断,当导通时,输出电路直接与地相连,则直接输出低电平。而当内部电路控制关断时,场效应管成高阻态,由外部上拉电阻输出高电平,反过来说,若没有外部上拉电阻开漏输出则没有输出高电平能力。

图(11)左为场效应管关断时,右为场效应管导通时

1.3.2 为什么选择漏极开漏输出?

以常见单片机的推挽输出和开漏输出作比较

图(12)推挽输出电路示意图

可以知道,推挽输出电路无需上拉电阻就有输出高低电平的能力,当分析如下情况,有两个主机,且采用推挽输出时,一个主机输出高电平,而一个输出低电平时,直接构成短路。如下图所示:

除此之外,开漏输出还能做到 “ 线与 ” 。(关于 “ 线与 ” 内容可以查找更详细的资料)

2. AT24C02简介

2.1.1 2.1.1 AT24C02硬件特点

  • 宽范围的工作电压1.8V~5.5V
  • 存储器组织结构

- 24C02, 256 X 8 (2K bits)
        - 24C04, 512 X 8 (4K bits)
        - 24C08, 1024 X 8 (8K bits)
        - 24C16, 2048 X 8 (16K bits)
        - 24C32, 4096 X 8 (32K bits)
        - 24C64, 8192 X 8 (64K bits)

  • 两线 串行接口,完全兼容I2C总线

  • I2C时钟频率位1MHz(5V),400kHz(1.8V,2.5V,2.7V)
  • 内部写周期(最大5ms)

2.1.2 AT24C02引脚排列与说明

图(13)AT24C02引脚排列与说

2.1.2 AT24C02的电气特性

这里尤为注意写周期最大值

图(14)AT24C02的交流电气特性

2.1.3 AT24C02的器件地址

图(15)AT24CXX的器件地址

由以上可知AT24C02的器件地址高四位固定为1010,低三位可自定义。

2.2 AT24C02写操作

2.2.1 字节写

字节写即写入一个字节,其格式如下:

图(16)字节写

2.2.2 页写

在字节写基础上,不发送停止信号,而是接收到AT24C02应答后,继续发送7个数据,且没接收到一个数据,字地址的低3位,自动加1,值得注意的是:当写入数据总数超过8个,字地址将回转到首地址,先前写的字节将会被覆盖,其格式如下:

图(17)页写

2.3 AT24C02读操作

2.3.1 当前地址读

AT24C02内部带有地址计数器保存上一次访问时最后一个地址加1的值。只要芯片有电,该地址就一直保存。其格式如下:

图(18)当前地址读

2.3.2 随机地址读

随机读需要先写一个目标地址,发送完后,ATC24C02发送ACK信号,然后再重复一个开始信号,然后主机发送器件地址,再接收目标地址的数据,其格式类比于前文的复合格式。格式如下:

图(19)随机地址读

此外还有顺序读,这里不再描述。

3. 51单片机与AT24C02的I2C通讯

3.1 准备工作

首先要知道AT24C02的器件地址,与SCL、SDA和51单片机的连接方式,我使用的51单片机连接方式如下:

图(20)ATC24C02连线图

由上图与前文ATC24C02器件地址可知,高四位固定为1010,而低三位这里对应E0,E1,E2为000,因此该器件地址为1010000。其SCL,SDA连接再51单片机的P21,P20引脚。

3.2 代码实现与讲解

3.2.1 编写I2C.c文件

首先定义SCL与SDA引脚,可根据实际连线修改,代码如下:

#include <REGX52.h>sbit I2C_SCL = P2^1;
sbit I2C_SDA = P2^0;

根据I2C通讯的基本格式,我们可以拆分成6个独立的函数。

I2C_Start()对应I2C_开始信号

/*** @brief I2C开始*  @param 无   *   @retval    无* @notes  I2C为推挽输出,因此将引脚置1实际上是关断mos管,由上拉电阻拉高至高电平*         置0时对应,mos管导通,将输出拉底*/
void I2C_Start(void)
{I2C_SDA = 1;I2C_SCL = 1;//在开始之前,确保SDA、SCL为高电平状态,即空闲状态I2C_SDA = 0;//在SCL高电平期间,SDA由高电平置0表示I2C起始信号I2C_SCL = 0;//将SCL拉底,方便接下来的数据传输
}

I2C_SendByte()对应I2C发送一字节数据

/*** @brief I2C发送一个字节*  @param Byte 要发送的字节 *   @retval    无* @notes  */
void I2C_SendByte(unsigned char Byte)
{unsigned char i = 0;for (i=0;i<8;i++)         //循环8次,发送8位数据{I2C_SDA = Byte&(0x80>>i); //I2C数据传输由高位开始,0x80对应1000 0000//相与之后只保留最高位,右移i位//以此方法从高到低取出每一位I2C_SCL = 1;I2C_SCL = 0;}
}

I2C_ReceiveByte()对应I2C接收一字节数据

/*** @brief I2C接收一个字节*  @param 无  *    @retval    Byte 返回接收的字节* @notes  */
unsigned char I2C_ReceiveByte(void)
{unsigned char i ,Byte = 0x00;I2C_SDA = 1;                //将SDA控制权交于从机for(i=0;i<8;i++)            //循环8次,读取八位数据{            I2C_SCL = 1;if (I2C_SDA)            //如果SDA线上是高电平{ Byte |= (0x80>>i);  //0x80对应1000 0000,// |= 将数据存入Byte中}I2C_SCL = 0;}return Byte;
}

I2C_SendAck()对应I2C发送ACK应答信号

/*** @brief I2C发送应答*    @param AckBit 应答位 0为应答,1为不应达*   @retval    无* @notes  */
void I2C_SendAck(unsigned char AckBit)
{I2C_SDA = AckBit; I2C_SCL = 1;I2C_SCL = 0;
}

I2C_ReceiveAck()对应接收应答

/*** @brief I2C接收应答*    @param 无*  @retval    Ackbit 接收应答位* @notes  */
unsigned char I2C_ReceiveAck(void)
{unsigned char Ackbit;I2C_SDA = 1;        I2C_SCL = 1;       //先将SDA,SCL释放 Ackbit = I2C_SDA;  //在SCL高电平期间,SDA为0则表示接收到了从机应答I2C_SCL = 0;return Ackbit;
}

I2C_Stop()对应I2C停止信号

/*** @brief I2C停止*  @param 无 * @retval    无* @notes  */
void I2C_Stop(void)
{I2C_SDA = 0;//保证SDA为0I2C_SCL = 1;I2C_SDA = 1;//SCL高电平期间,将SDA从0置1为I2C停止信号,且结束后, //SDA、SCL均为高电平,表示为空闲状态
}

3.2.2 编写I2C.h文件

包含I2C.c各函数方便调用

#ifndef __I2C_H__
#define __I2C_H__
#include "REGX51.H"
void I2C_Start(void);
void I2C_Stop(void);
void I2C_SendByte(unsigned char Byte);
unsigned char I2C_GetByte(void);
void I2C_SendAck(unsigned char AckBit);
unsigned char I2C_GetAck(void);#endif

3.2.3 编写AT24C02.c文件

首先包含I2C.h头文件与定义AT24C02器件地址

#include "I2C.h"
#define AT24C02_ADDRESS 0xa0 //0xa0对应1010 000 0,最后一位置0,为写模式

AT24C02_WriteByte()AT24C02写一字节数据

/*** @brief AT24C02写一字节数据*  @param WordAddress 写入字节的地址* @param    Data 写入的数据   *  @retval    无* @notes  */
void AT24C02_WriteByte(unsigned char WordAddress, unsigned char Data)
{I2C_Start();                   //I2C开始I2C_SendByte(AT2402_ADDRESS);  //找到ATAT24C02的器件地址I2C_ReceiveAck();              //接收AT24C02应答  I2C_SendByte(WordAddress);     //写入数据的地址I2C_ReceiveAck();              //接收AT24C02应答    I2C_SendByte(Data);            //写入数据I2C_ReceiveAck();              //接收AT24C02应答    I2C_Stop();                    //I2C停止
}

ATC2402_ReadByte()读取一字节

/*** @brief AT24C02读取一字节数据* @param WordAddress  读取字节的8位地址 *    @retval    Data 读取的字节* @notes  */
unsigned char AT24C02_ReadByte(unsigned char WordAddress)
{unsigned char Data;I2C_Start();                    //I2C开始I2C_SendByte(AT2402_ADDRESS);    //找到ATAT24C02的器件地址I2C_ReceiveAck();             //接收AT24C02应答  I2C_SendByte(WordAddress);       //写入数据的地址I2C_ReceiveAck();              //接收AT24C02应答I2C_Start();                       //I2C开始        I2C_SendByte(AT2402_ADDRESS | 0x01);//7位器件地址,第八位置1,表示读模式I2C_ReceiveAck();              //接收AT24C02应答   Data = I2C_ReceiveByte();          //读取AT24C02的数据I2C_SendAck(1);                 //不发送应答,发送与不发生都可以I2C_Stop();                       //I2C停止return Data;
}

3.2.4 编写AT24C02.h文件

#ifndef ___AT24C02_H__
#define __AT24C02_H__
void AT24C02_WriteByte(unsigned char WordAddress, unsigned char Data);
unsigned char AT24C02_ReadByte(unsigned char WordAddress);
#endif

4. 代码验证

在main.c中编写程序,通过LCD1602验证是否能读取出存入AT24C02的数据,此部分可以自行修改,这里只作为验证。

#include <REGX52.H>
#include "LCD1602.h"
#include "AT24C02.h"
unsigned char Data;
void main()
{LCD_Init();AT24C02_WriteByte(1,66);Data = AT24C02_ReadByte(1);LCD_ShowNum(2,1,Data,3);//在LCD第1行,第1列显示显示读出的数据,长度为3while(1){}
}

实验现象:

图(21)实验现象

程序本应该显示的是写入的66,但是却显示错误,这里就需要回到AT24C02的电气特性了,其规定了写周期最大为5ms,而写入之后马上读取,可以理解为,数据还没有真正存进AT24C02中,所以要加入延时环节,这里延时5ms后才读取。

修改main.c程序如下:

#include <REGX52.H>
#include "LCD1602.h"
#include "AT24C02.h"
#include "Delay.h"
unsigned char Data;
void main()
{LCD_Init();AT24C02_WriteByte(1,66);Delayms(5);Data = AT24C02_ReadByte(1);LCD_ShowNum(1,1,Data,3);while(1){}
}

实验现象:

图(21)实验现象

实验成功。

本文到此结束,本文如有错误之处,希望大家不吝赐教,欢迎批评指正!

I2C总线原理和应用实例(51单片机和AT24C02的I2C通讯)相关推荐

  1. 通过 I2C 驱动 LCD1602 液晶屏(51单片机)

    通过 I2C 驱动 LCD1602 液晶屏(51单片机) 硬件实物 原理图 3.程序 #include <reg51.h> #include <intrins.h>#defin ...

  2. SGP30传感器示例程序(基于51单片机、IO模拟I2C)

    SGP30传感器示例程序(基于51单片机.IO模拟I2C) SGP30传感器I2C地址:0x58 说明:这里采用使用IO模拟的方式来实现I2C 点击这里下载SGP30测试源码及数据手册 /*SGP30 ...

  3. I2C 总线原理与架构

    一.I2C总线原理 I2C是一种常用的串行总线,由串行数据线SDA 和串行时钟线SCL组成.I2C是一种多主机控制总线,它和USB总线不同,USB是基于master-slave机制,任何设备的通信必须 ...

  4. 51单片机系列--AT24C02(总线)

    存储器介绍 易失性存储器/RAM 非易失性存储器/ROM SRAM(静态RAM) Mask ROM(掩膜ROM) DRAM(动态RAM) PROM(可编程ROM) EPROM(可擦除可编程ROM ) ...

  5. 步进电机应用c语言程序设计实例,51单片机调节步进电机应用C语言程序设计

    51单片机调节步进电机应用C语言程序设计 //步进电机应用C语言程序设计 #include #define uchar unsigned char sbit dula=P2^6; //数码管显示段选I ...

  6. I2C总线原理及总线信号的实现

    目录 1. I2C总线简介 1.1 I2C电路规范 1.2 I2C总线的通信过程 1.3 I2C的寻址方式 1.4 起始信号与停止信号 1.5  字节传送与应答 1.6 主机向从机发数据 1.7 从机 ...

  7. FPGA ——I2C总线 原理详解

    目录 I2C传输模式 同步总线&异步总线 I2C硬件 I2C总线协议 I2C数据写流程 I2C数据读流程 I2C总线为PHILIPS公司推出的串行通信总线,具有接线少,控制方式简单,通信速率高 ...

  8. (十一)51单片机——用AT24C02实现存储秒表数据(附成果展示)

    目录 存储器 RAM ROM 存储器简化模型 AT24C02介绍 引脚及应用电路 内部结构框图 I2C总线 I2C总线介绍 I2C电路规范 I2C时序结构 起始条件 终止条件 发送一个字节 接受一个字 ...

  9. 51单片机使用AT24C02

    前言 本篇文章将带大家了解一个常用的存储器件AT24C02,使用此器件可以帮助我们保存一些数据,在单片机掉电后可以将需要的数据保存下来. 一.AT24C02介绍 AT24C02是Atmel公司推出的一 ...

最新文章

  1. DEV为什么不能输出小数 浮点数?
  2. Non-ASCII character '\xe6'
  3. 破译手势在对话中的意义
  4. mysql关联查询去重_MySQL外键和高级查询(连接查询、联合查询、子查询、去重查询)...
  5. 互联网医院 2020年突出成就_资讯丨2020中国医院互联网影响力排行榜
  6. 基于HTML5 WebGL实现 json工控风机叶轮旋转
  7. 编写一个 SQL 查询,找出每个部门工资最高的员工。
  8. iOS开发中常见的性能优化技巧
  9. 成考期末计算机组成原理,2020年10月自考02318计算机组成原理真题及答案
  10. 【学习 OpenCV】—— 图像减色(color reduced)
  11. jenkins 2.121.1 部署项目
  12. Abaqus取消汉化(汉译英,英译汉)
  13. 计算机-flash遮罩层动画,flash遮罩层动画作业
  14. 氚云CRM产品的详细介绍
  15. mac u盘重装系统(monterey)
  16. 像素坐标转换实际坐标python_像素坐标转世界坐标的计算
  17. python填空题_《Python程序设计》题库 - 填空题
  18. 小岚rabbit_radish(兔仔-萝卜)
  19. 汉信码今发布:国家自主研发的二维码技术
  20. 华为手机助手 无法访问服务器,EMUI4.X手机及windowsXP系统无法正常使用华为手机助手问题...

热门文章

  1. 关于zheng项目的学习步骤{ 转载 }
  2. 效果最好的助眠好物,帮助睡眠的好方法
  3. 读《借助开源项目,学习软件开发》总结
  4. Leetcode.463 岛屿的周长
  5. 国内外著名的云计算厂商平台
  6. 模拟浏览器抓取淘宝书籍数据
  7. 用MATLAB对图形进行水平和垂直灰度投影
  8. Linux 内存管理(1)--物理内存初始化
  9. 产品经理需要具备哪些素质?
  10. Mindjet MindManager 2021中文版注册序列号