这两天学习IIC读取MPU6050,小有心得,分享一下。
话不多说,先上效果:
上图用匿名上位机,用自定义帧通过串口1接收dmp处理后的四元数(航向角,翻滚角,俯仰角)。同时读取三轴加速度。
先做一些基础介绍:
iic:一种通讯协议,一般用于主机和从机通讯,总线上可以挂载多个主机和从机。通讯速率不高,距离近,但是只用到两根数据线节省资源。
物理层:由两根线构成 数据线(sda)和时钟线(scl)。闲时都为高电平,一般两跟通讯线都接上拉电阻来维持高电平。电压通常在3.3-5.0V之间。总线上的设备都有一个固定的ID地址用来接收数据。
协议层:一个完整的IIC通讯过程是这样的:
主机给指定ID从机发起通讯(开始信号+7位地址+1一位读写) --->从机收到并产生应答信号反馈给主机-->主机开始发送一个字节数据-->从机收到一个字节数据后产生应答--->主机发送结束信号
-
起始信号
//在SCL为高电平的时候,SDA产生下降沿 void IIC_Start(void) { SDA_OUT(); //设置数据线方向输出 SCL=1;SDA=0; IIC_Delay(); //让SCL稳定保持高电平 SDA=1; //产生上升沿 IIC_Delay(); // 产生稳定上升沿 }
-
结束信号
///在SCL为高电平的时候,SDA产生上升沿 1、设置数据线方向输出 2、设置SCL为高电平,SDA为低电平 3、延时 4、SDA拉高产生上升沿 5、延时
3.应答信号(从机产生,此处模块自己产生)
//主机发送一个字节数据后,从机在第九个时钟脉冲到来之前拉低SDA
1、设置SDA方向输出
2、SCL=0;SDA=0;
3、延时
4、SCL=1;产生第九个时钟脉冲
5、延迟
6、SDA=0;持续拉低SDA
-
不应答信号(NACK)
SDA持续为高
IIC协议发送一个字节:
void MPU_IIC_Send_Byte(u8 txd)
{
u8 t;
MPU_SDA_OUT();
MPU_IIC_SCL=0;//拉低时钟开始数据传输
for(t=0;t<8;t++)
{
MPU_IIC_SDA=(txd&0x80)>>7;
txd<<=1;
MPU_IIC_SCL=1;
MPU_IIC_Delay();
MPU_IIC_SCL=0;
MPU_IIC_Delay();
}
}
IIC协议读取一个字节
u8 MPU_IIC_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
MPU_SDA_IN();//SDA设置为输入
for(i=0;i<8;i++ )
{
MPU_IIC_SCL=0;
MPU_IIC_Delay();
MPU_IIC_SCL=1;
receive<<=1;
if(MPU_READ_SDA)receive++;
MPU_IIC_Delay();
}
if (!ack)
MPU_IIC_NAck();//发送nACK
else
MPU_IIC_Ack(); //发送ACK
return receive;
}
给从机通讯的时候,发送的第一个一个字节数据中前7位是从机地址ID,第八位是读写信号。第八位为0表示要读取从机数据,为1表示给从机发送数据。流程如下:
发送第一个字节函数如下:
MPU_IIC_Send_Byte((MPU_ADDR<<1)|0);//发送器件地址+写命令
发送完后,等待从机产生应答信号。主机接收到应答信号后开始发送数据。如果是读取命令
则发送一个字节,该字节是所要读取的寄存器地址,然后进入读取一个字节数据。如果是写入命令。则会连续发送两个字节数据。第一个是所要写入的寄存器地址,第二个是要写入的数据。两个字节之间需要等待从机的ACK信号。最终等从机ACK,通讯完毕,主机发起结束信号
PS:未完待续…
+WX:w15136355113 共同解决疑问。