由于MPU6050只支持I2C通信接口,而且STM32的硬件I2C存在一些瑕疵,所以,用STM32做四旋翼的话,学习一下用IO口模拟I2C的方法还是很有必要的。
我们从下面几个方面熟悉如何软件模拟I2C:
(1)空闲状态
当SDA和SCL两条线同时都为高电平时,I2C总线处于空闲状态,一旦I2C总线上有一个从机拉低了SDA线,则I2C总线被占用,处于BUSY状态,其它的从机想要与主机通信就只能等I2C总线再次处于空闲状态。
(2)SDA与SCL为什么要配置成开漏模式?
开漏输出能够方便地实现“线与”逻辑功能,即多个开漏的引脚可以直接并在一起(不需要缓冲隔离)使用,只要有一个引脚变为低,则开漏线上的逻辑也就为0了,这也是I2C判断总线占用的原理。
(3)如何用一个引脚实现双向通信?
GPIO处于输出状态时,GPIO端口的施密特触发器处于开启状态,这意味着处理器可以从“输入数据寄存器”读到外部电路的信号,监控I/O端口的状态,从而实现虚拟的I/O端口双向通信,只要处理器输出逻辑“1”,I/O端口的电平将完全由外部电路决定。
(4)I2C通信开漏引脚为什么接上拉电阻?
因为开漏模式的输出“逻辑0”时,引脚被连接到GND,输出“逻辑1”时,引脚悬空,即只能输出低电平,所以要想有输出功能就必须接上拉电阻,通过上拉电阻将总线拉为高电平。
(5)主机怎样识别不同的从机?
每个I2C通信的设备都有一个7位从机地址,如MPU6050的从机地址为b110100X,第七位的值由AD0引脚的逻辑电平决定,如果AD0引脚接地,则从机地址就是b1101000,如果AD0引脚接高电平,则从机地址为b1101001,由于这个原因,两个MPU6050可以接到同一个I2C总线上,通过I2C通信的设备的从机地址一把都能在对应的数据手册查到,如下面的电路,它的从机地址就为b1101000:
(6)怎样确定数据的传输方向?
前面我们说到从机的地址是7位的,而数据传输一般都是以8位传输的,所以在向总线写从机地址的时候,在地址后面加一位构成一个8位的数据,0则表示主机写数据到从机,1则表示主机从从机读取数据,请看下面的图,AD表示地址,W表示写(在地址后面加一位:0),R表示读(在地址后面加一位:1):
(7)I2C通信速率
MPU6050的I2C规定的最大传输速率为400KHz,最低的标准速度为100KHz,则按照这个频率计算,脉冲的周期为2.5us~10us之间,比这个时间长不行,短了也不行,这个在编程时,需要重视。
(8)起始信号/停止信号
从上面的图中可以看到起始信号S的定义是:当主机的时钟信号SCL为高电平期间,SDA的电平有高电平变为低电平即为起始信号;
当主机的时钟信号SCL为高电平期间,SDA的电平从低变为高即为停止信号P。
(9)应答信号与非应答信号
从上图中可以看到:
当主机的时钟信号SCK为高电平,SDA的电平为低时是应答信号(acknowledge);当主机的时钟信号SCK为高,SDA为高电平时是非应答信号(not acknowledge)。
(10)模拟I2C起始信号时,需要注意:只有SCK为低电平时才能改变SDA的点电平状态,否则可能产生停止信号:
其中I2C_SDA_LOW、I2C_SCL_HIGH等是宏定义,如下:
(11)写完一个字节后要将SCL拉低,钳住SCL,使通信处于等待的状态,并且将SDA拉高,释放主机对SDA的控制,以便从机能够获得SDA的控制权,发出响应信号,所以下面几句代码必须要有:
(12)读取从机的数据时,读取最后一个字节后要向从机发送一个非应答信号,让从机释放SDA的控制权,以便主机能够获得SDA控制权并且发送停止信号,结束数据传输。
其他部分就不一一介绍了,参考时序图编写即可。
到这里,今天的内容就结束了。
如果有写的不合适的地方,还请大家多多指教。如果你有兴趣,也可以一起讨论,互相学习,共同进步。 (微信号 :c18093458455)
文章评论(0条评论)
登录后参与讨论