I2C协议中SCL用于同布,当某一方发送/接收数据时,另一方将会发应答表示数据已收到。
一主多从:类似于老师是主在讲课,学生是从机,只有老师点名学生才能应答,否则不能自己应答。
之后是硬件电路的设置
对于SCL来说是一主多从不会出现什么问题,但是这个协议中SDA属于半双工,主机和从机的状态都是在输出和输入中跳转,当时序没有协调好时,可能会出现一个输出高电平、一个输出低电平,两者相遇就会造成电路短路的情况。因此为防止这种情况下面的2、3条用于限制
第二条的意思就是从机默认输出低电平且无驱动能力,避免主从的相互干扰
右图是从机内部结构,左边是SCL,右边是SDA
以下是SCL数据输入时,电路无影响
本节设置为开漏输出模式,保留低电平开关,无高电平开关,低电平开关按下时,导通低电平,
当低电平开关断开时,处于浮空状态,因此
假设有一根杆子,本来有向下拉和向上推两种状态,但是在这里规定任何人都不能向上推,只有向下拉和放手两种状态,向下拉时是低电平导通,而放手则是上方有一个弹簧(弱上拉)会有向上的状态。此时杆子不会同时出现强拉和强推现象。
输入是拉杆子或者放手;输出是放手观察杆子高低,输出高电平
只要其中一个输出低电平,总线就输出低电平。
之后是软件部分:只有主机能产生起始和终止
之后由主机发送字节时,SCL向下拉处于低电平时SDA的数据可为0/1,当SCL放手后,从机开始读取数据,8次后传输一个字节,主机发送从机接收。从高位开始发送。
SCL和SDA都由主机控制,从机只是被动读取
过程类似就是主从位置互换,主机接收前,需要释放SDA从才能输入数据
实线是主机控制,虚线是从机控制!
假设主机在发送一个字节后,把SDA放手,如果有从机接收那么SDA就会被下拉,如果SDA一直是放手状态,就说明数据无人接收。
主机接收数据时,从机发送应答,如果主机没向下拉SDA,从机就会交出SDA控制权,防止干扰主机后续操作。
之后是I2C的时序:
首先是起始条件,之后对从机地址进行输入(7位从机地址+一位读写位)R为1,W为0;
之后输入应答位,0代表从机响应
之后输入寄存器的地址,表示要对从机的这个地址下的寄存器进行数据输入,然后发送应答位
最后输入数据,如果完毕就发送终止条件。
之后是:
只输入从机地址,相当于从机的数据是一个线性结构,当得到读指令时就给地址指针当前指向的数据,之后地址自增1。假如在上一部分的写操作中,在0X19寄存器中写入数据,此时变成读指令,地址指针就会先自增到0X1A,读取数据,如果继续读,就是在OX1B的寄存器读取数据。
用途不多。
此时主机给SA表示非应答,此时主机不再接受其他数据,从机释放SDA权利,否则从机继续给数据让主机读。
第三种:
采用复合模式,先将指定地址写的前两部分放到指定地址读时序前,然后再输入从机地址+读写位再读出数据。Sr表示重复起始条件。
I2C规定格式:先起始——重复起始——停止
之后是MPU6050芯片的介绍
6轴:3个轴的加速度+3个轴的角速度(9轴:再加3个轴的磁场强度,10轴:再加一个气压)
加速度计A:可以想象成一个正方体里边放着一个相同质量的小球,小球放在里边相当于底面受力,此时Z轴为正值,具有静态稳定性
陀螺仪传感器G:可以想象成游乐场的飞椅,通过旋转产生两个相对的飞椅夹角,合起来就是中间轴的角速度,进行积分就是角度(存在一定漂移),具有动态稳定性
量化范围和以下两种的量程是一一线性对应的
对于从机地址有两种说法
对于1101000来说:1、没有融入读写位,相当于7位0110 1000,直接转换为16进制为0X68,之后需要将地址位左移一位,加入读写位
2、融入读写位的地址,例如是写操作,1101 0000,为0XD0地址
以下是芯片的硬件电路:
左下角的XCL和XDA可以用来外接芯片,如无人机需要气压信息时,需要10轴,这两个就可以直接接其他芯片,将信息输入到6050芯片内进行姿态解算等完成功能,如果不需要姿态解算,也可直接与6050芯片的SCL和SDA连接一个气压计/磁力计等。
MPU6050内部就有上拉电阻,因此不需要再额外加电阻,直接与SCL和SDA连接,即可
应用场景:
除了以下两个寄存器地址外,其余寄存器地址均为0X00
之后是代码和实验部分:
主要是以下三个部分,先是编写I2C的GPIO口初始化、6个时基单元(起始条件、终止条件、发送一个字节、接收一个字节、发送应答、接收应答)
之后写MPU6050中指定位置读、指定位置写、写寄存器对芯片进行配制、读寄存器得到传感器数据
最后是主程序中初始化OLED和I2C,读取数据、显示数据
先对I2C进行编辑:
1、初始化GPIO口,SCL和SDA都选用开漏输出模式
2、分别编写6个时基单元
为方便,此处增加三个函数,分别是SCL的写和SDA的读、写
其中写函数SCL和SDA格式一致只有引脚不一样,只有SDA需要读
之后是起始条件,根据理论知识可得,起始条件:释放SDA(1)——SCL(1)——SDA(0)——SCL(0),保证SDA有下降沿
终止条件:SDA(0)——SCL(1)——SDA(1),保证SDA有上升沿
发送一个字节,采用高位发送,一位一位发,首先发送数据的最高位,此时SCL为低电平,立马将数据放在SDA上,
Byte&0X80采用按位与操作,例如i=0时,此时Byte&10000000,后7位都是0,最高位与1相与,如果是1输出1,如果是0输出0,得到Byte的最高一位值,之后采用右移方法,0X80右移一位为0X40即0100 0000 与Byte取出次高位从,以此类推,从而将1个字节中的每一位取出并发送
之后是接收字节:例如当读取的第一位为1时,执行Byte或等于0X80,此时Byte最高位是1,如果读取的第一位不为1,if不成立,Byte最高位直接为0,以此类推得到8位数据。
发送应答:发一位,0表示应答,此时SCL低电平,把AckBit放在SDA上进行传输,SCL高电平读取,之后拉低进行后续操作
接收应答:接1位,0表示应答
之后是MPU6050芯片的代码编写:
首先是指定地址写:
根据以上理论知识发送一个字节:起始条件——从机地址+写——应答——指定寄存器地址——应答——发送数据——应答——终止条件
指定地址读1个字节:
起始条件——从机地址+写——应答——制定寄存器地址——应答——重复起始条件——从机地址+读——应答——接收数据——非应答——终止条件
测试写寄存器能否实现:首先解除睡眠模式给0X6B输入0X00,之后随机找一个寄存器写入随机内容,并读取显示在OLED上看写功能是否实现:
之后对寄存器进行初始化配置:DIV为10分频,陀螺仪和加速度都选择最大量程
再加上ID号的函数
之后编写6轴的数据代码,采用指针方式,先分别读取高8位和低8位然后将高8位左移8位与低8位拼接成16位数据之后返回给指针,6个操作都相同。
对于主函数来说:
通过指针变量不断读取数据并显示
实验结果如下所示:
对于加速度而言,类比于一个放在正方体内的一个小球的受力情况:
首先是水平放置时,只有Z轴受力,X、Y近似为0
水平放置
之后是X轴上倾为正、下倾为负
上倾
下倾
Y轴左倾为正,右倾为负
左倾
右倾
Z轴翻转之后为负
翻转面包板
通过上述实验,充分理解了软件发送和接收数据的过程,之后将学习硬件的操作。