本篇文章内容由个人编写、整理,图片参考了B站的江科大,当然,我并不是完全照般,所有的笔记都经过了个人的完善以及加上了个人的理解。在IIC原理以及对AT24C02、mpu6050的理解上,这篇文章对Arduino、STC89C51、STM32单片机的学习者都通用(包括但不仅次于)。同时,个人觉得这份笔记是大部分IIC文章中很不错的一篇,绝对会让初学者觉得非常通俗易懂,对老朋友来说,更会加深理解和记忆!起初整理这份IIC的笔记时,只是因为单纯害怕自己忘记(确实也如此),后来在整理这份笔记的时候,突然有想分享出去的念头,于是抱着分享经验的想法,我前前后后地反复修改笔记内容,致力于让大部分初学IIC的同学以简单通俗的方式入门和深入理解,不希望他们也想我那样啃了很久的IIC,并且印象不深刻。
不出意外的话,很多同学都会觉得我的笔记很啰嗦,但是,个人认为这么多啰嗦的地方总有一出是你特别想要的吧,这也是我为什么反复想改的原因,我很希望能把大部分初学者爱钻牛角尖的问题给解释出来,同时也是为了大家更好的理解IIC的原理,更重要的一点是IIC使用得挺普遍的。
一、IIC介绍
1.IIC的英文全称为Inter IC BUS,意为内部 集成电路 总线
2.IIC有两根通信线,包括SCL(Serial Clock)串行时钟和SDA(Serial Data)串行数据
二、IIC电路规范
1.设备的SCL和SDA引脚均要配置成开漏输出模式
开漏输出:IIC的SCL、SDA对应的IO只能输出:
①低电平(逻辑0,IO被接在GND上,只能是低电平)
②高阻态(逻辑1,IO可以被拉高或者拉低),而所谓的“高电平”其实是在输出逻辑1、IO为高阻态时,IO被外部或者内部上拉电阻拉高的。
- SDA=0时,SDA脚在IC内部被直接接在GND上,它只能是低电平,外部器件也无法把SDA脚拉高,这叫拉低。
- SDA=1时,SDA脚为高阻态,(相当于这个IO谁都不接,这就是高阻了),这时SDA可以被别的器件拉低或者拉高,即,这时SDA脚的控制权是“释放状态”,如果谁都不去管这个高阻态的脚,这个脚会被上拉电阻拉高以保证不会被空气里的电磁波干扰而高高低低乱跳。
例子解释:
2.SCL和SDA通信线上各接一个上拉电阻,阻值一般为4.7KΩ左右
3.因为IIC的SCL和SDA都要接上拉电阻,保证空闲状态的稳定,所以IIC总线在空闲状态下SCL和SDA都要保持高电平
4.发送应答、接收应答、接收非应答皆可省略,但是发送非应答不可省略,即,发送完数据要发送非应答,表示不再接收数据
三、IIC时序结构
3.1
void IIC_Start(void) { IIC_SDA=1;//为了更好的衔接复合格式下的IIC数据帧,先把SDA置1。在复合格式下,第二个Start开始前,SDA可能为1也可能为0(因为应答位可能为0也可能为1) IIC_SCL=1; Delay_ms(2);//保证一定的高电平或低电平时间 IIC_SDA=0;//起始条件:SCL高电平期间,SDA从高电平切换到低电平 IIC_SCL=0;//准备发送数据或接收数据 }
void IIC_Stop(void) { IIC_SDA=0;//终止条件:SCL高电平期间,SDA从低电平切换到高电平 Delay_ms(2);// 保证一定的高电平或低电平时间 IIC_SCL=1; //保证IIC结束后的空闲状态为高电平(在软件将SCL置1前,SCL在IIC_SendByte和IIC_ReceiveByte函数中已经软件写0,所以无需再在SCL前软件写0) IIC_SDA=1; }
3.2
void IIC_SendByte(unsigned char Byte) { unsigned char i; for(i=0;i<8;i++)//不能从i=1开始,否则影响右移的顺序 { IIC_SDA=Byte&(0x80>>i);//把Byte的第i位赋值给SDA IIC_SCL=1; Delay_ms(2);//保证一定的高电平或低电平时间 IIC_SCL=0; } }
3.3
unsigned char IIC_ReceiveByte(void) { unsigned char i, Byte=0x00; IIC_SDA=1;//主机在接收之前,需要释放SDA,将总线控制权交给SDA(参考二、IIC电路规范的第1点) for(i=0;i<8;i++) { IIC_SCL=1; if(IIC_SDA)//如果SDA的第i位数据是1 { Byte|=(0x80>>i);//把Byte第i位置1(i=0的时候,Byte=0x00) } IIC_SCL=0; Delay_ms(2);//保证一定的高电平或低电平时间 } return Byte; }
3.4
/*发送应答是主机在控制总线,不需要释放总线*/ void IIC_SendAck(unsigned char AckBit)//0为应答,1为非应答 { IIC_SDA=AckBit; IIC_SCL=1; IIC_SCL=0; Delay_ms(2);//保证一定的高电平或低电平时间 } /*接收应答是从机控制总线,需要释放总线*/ unsigned char IIC_ReceiveAck(void) { unsigned char AckBit; IIC_SDA=1;//释放总线 IIC_SCL=1; Delay_ms(2);//保证一定的高电平或低电平时间 AckBit=IIC_SDA; IIC_SCL=0;//(如图所示,此时的IIC_SDA位是应答位,可以是0也可以是1,故无需重新写IIC_SDA) Delay_ms(2);//保证一定的高电平或低电平时间 return AckBit; }
四、IIC数据帧
为了防止接收数据的丢失,采用先发送再接收数据的复合格式
即,主机发送一位数据,再接收从机发出的是否应答的信号,主机判断完之后再发送下一位数据
五、以51开发板上的AT24C02作为例子
5.1 AT24C02介绍
5.2 IIC一般的发送和接收完整数据帧
IIC完整通信协议图:
5.3、AT24C02示例代码
/*AT24C02数据帧-字节写*/
void AT24C02_WriteByte(unsigned char WordAddress,Data)
{
IIC_Start();
IIC_SendByte(AT24C02_Address);//发送从机地址(写)
IIC_ReceiveAck();
IIC_SendByte(WordAddress);//发送字地址
IIC_ReceiveAck();
IIC_SendByte(Data);
IIC_ReceiveAck();
IIC_Stop();
}
/*AT24C02数据帧-随机读*/
unsigned char AT24C02_ReadByte(unsigned char WordAddress)
{
unsigned char Data;
IIC_Start();
IIC_SendByte(AT24C02_Address);//发送从机地址(写)
IIC_ReceiveAck();
IIC_SendByte(WordAddress);//发送字地址
IIC_ReceiveAck();
IIC_Start();
IIC_SendByte(AT24C02_Address|0x01);//发送从机地址(读)
IIC_ReceiveAck();
Data=IIC_ReceiveByte();
IIC_SendAck(1);//发送非应答,表示不再接收数据
IIC_Stop();
return Data;
}
附:mpu6050讲解
一、mpu6050介绍
1.1引脚介绍(型号为六轴GY521)
管脚名称 | 说明 |
VCC | 3.3-5V(内部有稳压芯片) |
GND | 地线 |
SCL | MPU6050 作为从机时 IIC 时钟线 |
SDA | MPU6050 作为从机时 IIC 数据线 |
XCL | MPU6050 作为主机时 IIC 时钟线 |
XDA | MPU6050 作为主机时 IIC 数据线 |
AD0 | 地址管脚,该管脚决定了 IIC 地址的最低一位 |
INT | 中断引脚 |
1.这里重点讲解 AD0 的作用,I2C 通讯中从机是要有地址的,以区别多个从机。当 AD0 管脚接低电平的时候,从机地址是 0xD0。MPU6050 作为一个 IIC 从机设备的时候,有 8 位地址,高7 位的地址是固定的,最低的一位是由 AD0 的连线决定的。
2.除此之外,值得注意的是,MPU6050含有两个IIC接口,第一IIC接口可作为主接口给单片机传输数据;第二IIC接口用于连接一个第三方数字传感器(如外部磁力传感器等),然后通过这个IIC接口输出完整的9轴信号,否则只有6轴(6轴通常指的是三轴加速度计+三轴陀螺仪,9轴多了个三轴磁力计,用来定位设备方位),不需要接单片机。
1.2 Mpu6050 WHO_AM_I
1.3 mpu6050X、Y、Z轴的方向如图所示
附:51串口读取mpu6050原始数据(后续浏览量多再更新,网上也不少)
本篇文章的Word文档格式,也欢迎自取
链接:https://pan.baidu.com/s/1ewiFCJ-_lVulgQj0rPv0cA
提取码:fn17