I2C总线是飞利浦公司推出的一种串行总线,所有器件共用两根信号线,实现数据的传输。

总线接口接了上拉电阻,默认为高电平,所以就可以用“当低电平出现”来标记出一种起始信号。我个人把它想象成:许多人在一条走廊上的不同房间(器件)里,大家都把门打开,连出两根长长的听筒(小时候玩的那种),每个人都从两根大主线上各接一根到自己房间里。两根听筒平时都是安静的(1)。如果有某房间的人叫了一声(0),那剩下的人就知道,我们准备开始通话了。

为了保证秩序,大家选出一个人当领队,由他来主导通话的过程。这就是总线的主机,其他人就是从机。从机有多个,主机只有一个。

两根信号线,一根叫数据线SDA,一根叫时钟线SCL。顾名思义,数据线用来传输数据,时钟线用来管理顺序。

怎么样表示开始,怎么样表示结束,用下面的图表示。注意有严格的时间规定。

首先,我们知道怎么样算是通话的开始和结束(起始信号和终止信号)。然后,规定怎样算是回答“可以”,怎么算是回答“不可以”(应答和非应答)。

接着,我们要知道谁向谁喊话,所以要给每个房间的人都赋予一个名字,也就是地址。再用一个0或1表示方向,从谁到谁。

因此,数据传输的过程,大体就是如此:领队喊出“开始”,说出一个房间名,同时,所有房间的人确认是不是自己的。领队表明目的,说出是向他传数据,还是从他那读数据;然后,确认是自己房间的队员给出应答,可以就开始传输数据。完成后,主机/从机给出应答,表明收到了没有。

下面就是SDA上传送的数据格式。

(a)主机向从机发送数据

S表示起始信号。阴影表示主机发送。A表示应答,上加划线表示非应答。P表示停止。

(b)主机发送数据后,从从机读数据

(c)传输过程中,想改变方向

方法是,重复一次起始信号和从机地址,加一个方向位来改变方向。

SCL是用来管秩序的。只要SCL保持高电平状态,SDA正在传的数据就不能乱动,只有把它拉低以后,SDA才能变化。这样确保数据传输不会乱套,所以在实际的传输过程中,SCL会不断地翻转。

另外,如果存在许多一样的器件,怎么区分呢?方法是把前几位固定不能动,表示是同一种器件,后面的几位可以动(可编程)。假如后面空出3位,那么就是可编程8个,也就是允许有8个同种器件接到总线上。前面的地址叫“器件地址”,后面的地址叫“首地址”。所以,每次主从通信时,要先传器件地址,加方向位,等器件应答;再传首地址来寻找特定的器件,再加方向位,等待它应答。接着开始数据传输。

写入过程:

读出过程:

下面是对于I2C总线模拟的一些关键函数的注释。

//延时10微秒函数
void Delay10us(void)
{
unsigned char a,b;
for (b=1;b>0;b--)
for (a=2;a>0;a--)
;
} //I2C起始信号模拟
void I2cStart()
{
SDA = 1;
Delay10us();
SCL =1;
Delay10us();
SDA = 0;
Delay10us();
SCL =0;
Delay10us(); } //I2C停止信号模拟
void I2cStop()
{
SDA = 0;
Delay10us();
SCL =1;
Delay10us();
SDA = 1;
Delay10us(); } //I2C发送数据函数
unsigned char I2cSendByte(unsigned char dat)
{
unsigned char a = 0,b;
for(a=0;a<8;a++) //一位一位传输数据
{
SDA = dat>>7; //右移7位,最高位送给SDA
dat = dat<<1; //左移一位,次高位变成最高位
Delay10us();
SCL = 1;
Delay10us();
SCL = 0; //翻转SCL,SCL为低电平时传输的数据才能改变
Delay10us();
}
SDA = 1;
Delay10us();
SCL = 1; //释放数据线和时钟线
while(SDA) //等待从机应答,如应答则SDA拉低跳出循环
{
b++; //一段时间没有应答就认定为失败
if(b>200)
{
SCL = 0;
Delay10us();
return 0; //数据发送失败
}
}
SCL = 0;
Delay10us();
return 1; //数据发送成功 } //I2C读取数据函数
unsigned char I2cReadByte()
{
unsigned char a = 0;
SDA = 1; //拉高数据线,保持空闲等待数据
for(a=0;a<8;a++) //一位一位读取数据
{
SCL = 1; //拉高时钟线,保持数据稳定,准备接收
Delay10us();
dat<<=1; //左移一位,空出一位准备读数据
dat |= SDA; //或运算,dat空出的位为0,如SDA也为0则为0,SDA为1就为1,相当于保存SDA数据
Delay10us();
SCL = 0; //翻转时钟线,使下位数据能够改变
Delay10us();
}
return dat; //返回读取的数据
} //向At24C02芯片写数据函数
void At24c02Write(unsigned char addr,unsigned char dat)
{
I2cStart(); //起始信号
I2cSendByte(0xa0); //发送器件地址(固定)
I2cSendByte(addr); //发送首地址(自定)
I2cSendByte(dat); //发送数据
I2cStop(); //停止信号 } //读数据函数
unsigned char At24c02Read(unsigned char addr)
{
unsigned char num;
I2cStart(); //起始信号
I2cSendByte(0xa0); //发送器件地址(固定)
I2cSendByte(addr); //发送首地址(自定) I2cStart(); //加一个起始信号,用于改变数据传送方向
I2cSendByte(0xa1); //读取器件地址,最后一位表示方向
num = I2cReadByte(); //保存读取的数据
I2cStop(); //停止信号 return num;
}

  

51单片机I2C总线的更多相关文章

  1. 51单片机 | 1-Wire总线及应用实例

    ———————————————————————————————————————————— 1-Wire总线 - - - - - - - - - - - - - - - - - - - - - - - ...

  2. 51单片机 | 基于I2C总线的秒表模拟应用

    ———————————————————————————————————————————— 参考地址: http://blog.csdn.net/junyeer/article/details/4648 ...

  3. 自制单片机之六……串行I2C总线E2PROM AT24CXXX的应用

    这一篇介绍I2C存储器的使用.主要是介绍AT24CXX系列器件,它分为两类,主要是通过被存储容量地址来分的,一类是AT24C02-AT24C16,它的存储容量从256字节到2048字节.另一类是AT2 ...

  4. 单片机学习(十一)I2C总线和AT24C02的使用

    一. 存储器介绍 存储器分类图 1. RAM 这类存储器中的数据都是掉电即失的,例如计算机中的内存就是DRAM,但它们数据读写速度都是要比ROM要快得多的. SRAM:本质是电路,使用电路构成的触发器 ...

  5. [51单片机] EEPROM 24c02 [I2C代码封装-保存实现流水灯]

    这里把EEPROM 24c02封装起来,今后可以直接调用,其连线方式为:SDA-P2.1;SCL-P2.0;WP-VCC >_<:i2c.c /*--------------------- ...

  6. C51单片机模拟I2C总线驱动程序设计

    /********************************** I2C总线驱动 ******************************** 模块名:I2C总线驱动 型号:I2C 功能描述 ...

  7. 51单片机实现对24C02进行页写、顺序读取并显示验证

    //************************************************************************************* //**程序名称:51单 ...

  8. 基于51单片机IIC通信的PCF8591学习笔记

    引言 PCF8591 是单电源,低功耗8 位CMOS 数据采集器件,具有4 个模拟输入.一个输出和一个串行I2C 总线接口.3 个地址引脚A0.A1 和A2 用于编程硬件地址,允许将最多8 个器件连接 ...

  9. EEPROM读写学习笔记与I2C总线(转)

    reference:https://www.cnblogs.com/uiojhi/p/7565232.html 无论任何电子产品都会涉及到数据的产生与数据的保存,这个数据可能并不是用来长久保存,只是在 ...

随机推荐

  1. CPU有个禁区,内核权限也无法进入!

    神秘项目 我是CPU一号车间的阿Q,是的,我又来了. 最近一段时间,我几次下班约隔壁二号车间虎子,他都推脱没有时间,不过也没看见他在忙个啥. 前几天,我又去找他,还是没看到他人,却意外地在他桌上发现了 ...

  2. 后端队列生成pdf,发送到邮箱

    最开始可以先将你想要的pdf模板写好先,如testPage <!DOCTYPE html> <html> <head> <meta http-equiv=&q ...

  3. MSP430-LED中断闪烁代码详解

    使用MSP430F149的开发板,首先对LED闪烁灯的例程进行讲解,然后下边是自己写的,将部分代码写入了新建的led.c程序中 #include  <msp430x14x.h>       ...

  4. 阿里Java中级开发测试相关试题及答案

    ------------恢复内容开始------------ 1.JSP文件上传的HTML标签代码定义是? A. <input type="text" name=" ...

  5. Single Shot MultiBox Detector论文翻译【修改】

    这几天读了SSD论文的原理部分,看了别人的翻译,发现很多应该都是google直接翻译过来的,有些地方读的不是很通顺,自己就在自己的理解和搜索的基础上对我看的那篇翻译做了一些修改.[原文地址:http: ...

  6. oracle 11g 导入表时 提示 ***值太大错误

    导入数据库时,总是提示**值太大,实际值是**的错误. 具体忘了错误代码是什么了 ——! 经查询,这个是由于字符集设置的不是gbk的,导致导入时遇到中文字符出现的问题, 解决方法: 如果可以的话就把数 ...

  7. css动画实现吃豆豆

    话不多说,直接上代码:(作为一个初学者写的代码,多么0基础都能看的懂吧.) HTML部分 <!DOCTYPE html> <html lang=en> <head> ...

  8. Cocos Creator 性能优化:DrawCall

    前言 在游戏开发中,DrawCall 作为一个非常重要的性能指标,直接影响游戏的整体性能表现. 无论是 Cocos Creator.Unity.Unreal 还是其他游戏引擎,只要说到游戏性能优化,D ...

  9. ansible使用,常用模块

    使用ansible管理其他主机有两种方式: 1.命令行执行ansible ad-hoc命令 2.把要做的动作行为写入一个文件[playbook脚本],ansible读取脚本自动完成相应的任务. Ans ...

  10. 本周 GitHub 速览:自动化当道,破密、爬虫各凭本事

    作者:HelloGitHub-小鱼干 摘要:安全门外汉,如何在不知道密钥或密码的情况下,破解哈希得到原文,Ciphey 会告诉你当中的密码.说到 auto 智能爬虫会基于上一次的爬虫经历进一步学习以获 ...