IIC通信详解 —— 基于MPU6050模块

从IIC通信原理到使用 —— MPU6050

IIC通信可以简单地理解成就是数据的通信,就是单片机(主机)与设备(从机)之间的一种通信协议,两者必须遵从这个协议才能正确的相互读写数据,它这个通信过程只要两根线就能给完成,分别是SCL(时钟线)和SDA(数据线);

这个主机与从机的关系一定要理解好,因为下一次不一定是单片机,有些从机也可以作为主机,可以先把主机理解成能够向其他设备发送指令/命令的一方,比如如果你作为主机,你是想读的时候才去读的,想写的时候就去写,比较主动;而如果你作为从机,这就由不得你,你只能听从主机的命令,主机说要读,你就要把数据给出去,主机说要写,你就得乖乖被写

现在假设单片机作为主机,连接在SDA和SCL的两条线上的设备均是它的从机,比如下面图所示:

到这里我们已经能够有一个IIC主从设备的概念了,那么假如单片机想要通过IIC来读取从设备的信息应该都要做什么呢?也就是说,整个IIC通信过程应该是怎么样子实现的?

一、IIC通信协议

在解释之前,可以先知道一个这个协议不协议的到底是怎么实现的,打比喻说只有一个主机一个从机时,大家先定一个协议,如果某根线的电平怎么怎么样,同时另外一根线的电平又怎么怎么样的时候,对应的是要读?还是要写?还是其他什么?上面这个过程也就相当于主机发出的指令,从机通过两根线的电平状态来确定主机的指令是什么。(注意,不要简单地理解为 00 01 10 11 四种状态)。指令是通过两根线来发送,里面的数据也是通过那两根线,所以你至少要定义你什么时候是指令什么时候是数据吧?所以就会有协议这种东西。

IIC总线在传输数据的过程中一共有三种类型信号(指令),分别为:开始信号、结束信号和应答信号。这些信号中,起始信号是必需的,结束信号和应答信号,都可以不要。同时我们还要介绍其空闲状态、数据的有效性、数据传输。看到协议不要害怕,我们只需要先知道它内部的原理,至于怎么来实现,后面再看代码进行解释。

①. 空闲状态
当SDA和SCL两条信号线同时处于高电平时,规定为总线的空闲状态。这种状态就相当于没有设备在占用通信通道,大家各自在自家互不搭理。正常情况下,当系统开始工作,如果主从不通信时就希望它是空闲状态,也就是说开机后默认是空闲状态,那么这两个高电平可以由上拉电阻来完成。

②. 开始信号
当SCL为高期间,SDA由高到低的跳变;启动信号是一种电平跳变时序信号,而不是一个电平信号。
③. 结束信号
当SCL为高期间,SDA由低到高的跳变;停止信号也是一种电平跳变时序信号,而不是一个电平信号。

④. 应答信号
发射器 定义要发送数据的一端为发射器,当主机往从机写命令时,可以理解成主机作为发射器,当主机读取从机数据时,可以理解成从机往主机写数据,这时候从机就是发射器;
实现过程 发送器每发送一个字节(1byte = 8bit),8个时钟脉冲用来储存数据内容,在第9个时钟脉冲释放数据线,由接收器反馈一个应答信号。应答信号为低电平时,规定为有效应答位(ACK,简称应答位),表示接收器已经成功地接收了该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。

⑤. 数据的有效性
在数据传送时,SCL为高电平期间,SDA上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。 即:数据在SCL的上升沿到来之前就需准备好。并在在下降沿到来之前必须稳定。

以上就是协议的一些内容,在发送数据时必须得遵守协议,开启读取、读取完成之后一定要发送停止信号来释放总线。我们可以接着看数据的发送过程是怎么实现的。

二、通过IIC协议实现收发

因为在总线上可能会有很多从设备,不止一个,所以主机在发送或者接受数据的时候,必须要知道从机的设备地址(不同设备有自己不同的设备物理地址),相当于如果你要去某个人的家,至少你要先知道他们家的地址。

知道了这个物理地址后,也就相当于主机能在众多从设备中找到了想要找的从设备,但是一个完整设备意味着它有自己的芯片,有自己的储存单元,所以主机不仅仅只是要找到这个设备,还要找到该设备里的主机想要读写的存储单元(寄存器),相当于你要去某个人的家找一个人,你到了他家之后,还要在他众多的家人中找到你要找的那个人。

当主机确定了从机设备、从机设备的寄存器,就能往里面进行读写数据了,而这个读写数据的过程就必须得按照这个IIC协议来完成,这么说可能还比较抽象。下面先介绍MPU6050,再结合IIC来实现单片机从MPU6050读取数据。

三、MPU6050的介绍

MPU-60X0由以下几个关键块和功能组成
1、带有16位ADC和信号调理的三轴MEMS速率陀螺仪传感器
2、具有16位ADC和信号调理的三轴MEMS加速度传感器
3、数字运动处理器(DMP)引擎
4、传感器数据寄存器
5、FIFO
6、中断
7、数字输出温度传感器

首先要知道6050的内置模块。包括一个三轴MEMS(微机电系统(MEMS, Micro-Electro-Mechanical System))陀螺仪、三轴MEMS加速度计,一个数字运动处理引擎(DMP)、还有用于第三方数字传感器接口的辅助IIC端口,(GY-521上面的xda,xcl),常用于扩展磁力计,当辅助IIC接口连接到一个三轴磁力计上面时,6050能提供一个完整的九轴融合输出到其主IIC接口上。同时,6050内部还内置了一个可编程的低通滤波器,可用于传感器数据的滤波。

系统结构图
通过系统结构图只需要你大概知道有什么在里面就行了。

接线图
当不使用磁力计时(使用磁力计时,MPU6050作为主机去读取磁力计的数据,然后再以从机的身份向单片机主机发送加速度、陀螺仪和从磁力计读取的数据),只需要接电源线(5V)、地线、SCL和SDA即可,其他引脚均闲空。

关键功能介绍
① 带有16位ADC和信号调理的三轴MEMS陀螺仪

MPU-60X0由三个独立的振动MEMS速率陀螺仪组成,可检测旋转角度X轴,Y轴和Z轴。 当陀螺仪围绕任何感应轴旋转时,科里奥利效应就会产生电容式传感器检测到的振动。 所得到的信号被放大,解调和滤波产生与角速度成比例的电压。 该电压使用单独的片内数字化16位模数转换器(ADC)对每个轴进行采样。 陀螺仪传感器可以全面范围的被数字编程为每秒±250,±500,±1000或±2000度(dps)。 ADC样本速率可以从每秒8,000个采样点编程到每秒3.9个采样点,并且可由用户选择低通滤波器可实现广泛的截止频率。

这就是指模块内部自带了陀螺仪,经其内部的数模转换器可以将陀螺仪的模拟量转成可传输的数字量,并且存储在16位寄存器里(由两个8位寄存器组成),关于获取陀螺仪数据时,只需直接从对应的寄存器里读出数据即可,注意此时的数据并非是倾角。

简而言之,陀螺仪就是角速度检测仪。比如,一块板,以X轴为轴心,在一秒钟的时间转到了90度,那么它在X轴上的角速度就是 90度/秒 (DPS, 角速度单位,Degree Per Second的缩写°/S ,体现了转动的快慢)

② 具有16位ADC和信号调理的三轴MEMS加速度计

MPU-60X0的3轴加速度计为每个轴使用单独的检测质量。 加速沿着一条特定轴在相应的检测质量上引起位移,并且电容式传感器检测到该位移位移有差别。 MPU-60X0的架构降低了加速度计的敏感度制造变化以及热漂移。 当设备放置在平坦的表面上时,将进行测量在X和Y轴上为 0g,在Z轴上为+ 1g。 加速度计的比例因子在工厂进行校准并且在名义上与电源电压无关。 每个传感器都有一个专用的sigma-delta ADC来提供数字输出。 数字输出的满量程范围可以调整到±2g,±4g,±8g或±16g。

总而言这,加速度传感器,其实是力传感器。用来检查上下左右前后哪几个面都受了多少力(包括重力),然后计算角度。

③ 数字运动处理器(DMP)

DMP就是指MPU6050内部集成的处理单元,可以直接运算出四元数和姿态,而不再需要另外进行数学运算。四元数就是4个数,可以表征姿态,经过几个数学公式之后就可以的出姿态,姿态包括pitch,roll,yaw。DMP的使用大大简化了代码设计,可想而知mpu9150(mpu6050)并不单单是一款传感器,其内部还包含了可以独立完成姿态解算算法的处理单元。
由DMP实现姿态解算算法将单片机从算法处理的压力中解放出来,单片机所要做的是等待DMP解算完成后产生的外部中断,在外部中断里去读取姿态解算的结果。这样单片机有大量的时间来处理其他任务,提高了系统的实时性。综上,dmp之后直接出结果,可以直接用,当然你如果有特殊需要自己还要加滤波也没有问题。

但是听说DMP的参考平面有点蛋疼。他解算出来的姿态角是以上电时的平面为基准平面的。也就是说每次上电都要把装置摆到绝对水平。但这有点困难。

④ 传感器数据寄存器

传感器数据寄存器包含最新的陀螺仪,加速度计,辅助传感器和温度测量数据。 它们是只读寄存器,可通过串行接口访问。 这些寄存器的数据可以随时读取。 但是,可以使用中断函数来确定新数据何时可用。

存储这些数据的寄存器均只是可读状态,称之为数据寄存器,注意:关于陀螺仪和加速度的寄存器均是16位的,也就是说在读取他们数据时,需要知道加速度/陀螺仪对应的两个寄存器的内部地址,并且读取出来的数据需要通过转换合成。

上图是陀螺仪数据寄存器,通过读取这6个寄存器,就可以读到陀螺仪 x/y/z 轴的值,比如 x 轴的数据,可以通过读取 0X43(高 8 位)和 0X44(低 8 位)寄存器得到,其他轴以此类推。

上图是加速度数据寄存器,通过读取这6个寄存器,就可以读到加速度传感器 x/y/z 轴的值,比如读 x 轴的数据,可以通过读取 0X3B(高 8 位)和0X3C(低8位)寄存器得到,其他轴以此类推。

⑤ 关于其他寄存器的设置及介绍
我是从这篇帖子里学习的,我已经码出来分享给大家
--------》 传送门

知道以上寄存器很重要,要知道寄存器每个位什么值对应着什么样的功能,还要知道其对应的内存地址,以供主机进行寻找。

⑥ FIFO缓冲器

MPU-60X0包含一个可通过串行接口访问的1024字节FIFO寄存器。 FIFO配置寄存器决定哪个数据写入FIFO。 可能的选择包括陀螺仪数据,加速计数据,温度读数,辅助传感器读数和 FSYNC 输入。 FIFO 计数器跟踪 FIFO 中包含的有效数据字节数。 FIFO寄存器支持突发读取。 中断功能可用于确定新数据何时可用。

⑦ 中断

中断功能通过中断配置寄存器进行配置。 可配置的项目包括INT引脚配置,中断锁存和清除方法以及中断触发器。 可触发中断的项目有:
(1)时钟发生器锁定到新的参考振荡器(用于切换时钟源);
(2)可以读取新数据(来自FIFO和数据寄存器);
(3)加速度计事件中断;
(4)MPU-60X0 没有收到辅助传感器的确认I2C总线。

中断状态可以从中断状态寄存器读取。

至此,了解了MPU6050的一些基础知识后,我们就可以通过代码建立IIC通信,让单片机与MPU6050进行通信。

四、单片机与MPU6050的IIC实现

在贴代码之前,需要明确以下几点:

A. 关于地址
---- 从设备的地址是用7bit来表示的,但是一个寄存器里有8个位,所以最终这个设备的地址是由已知的7位和第8位组成,那么第8位到底是什么呢?

规定在IIC通信开始发送一帧数据时,前面7bit是设备或者寄存器的地址,第8位则是读或者写的方向命令位,0为写命令,1为读命令。

就比如从官方所给资料来看,MPU6050的地址是0x68或者0x69,拿0x68举例,其表示如下:

7bit 6bit 5bit 4bit 3bit 2bit 1bit 0bit
1 1 0 1 0 0 0 AD0

前面7位(110 1000)构成从设备的地址0x68,而最后一位是未知的,或者说,是由用户自己定义设置的(AD0引脚),比如如果在MPU6050模块的AD0引脚接地,则最后一位表示0,那么加进去以后,地址就变成了1101 0000,转换成十六进制也就是0xD0,此处也代表写命令。

所以以后在主机寻找MPU6050这个设备时,需要写入一帧数据以表示寻找从机,这一帧数据就是0xD0,说明白点,0xD0是由设备物理地址+命令来构成最终的“门牌”,主机以后就是通过这个门牌来找到MPU6050,主机只要把“门牌”发送出去,系统的状态就代表着主机向从机写数据,一直持续到停止信号。

与设备物理地址不同,设备内部的寄存器地址是由8位构成,因此只需要在开启信号发起时,发送寻找MPU6050的“门牌”(相当于告诉了设备主机打算写入数据,只要还没有停止信号就代表后面的操作一直都是写信号),接着就可以继续发送寄存器的内存地址(8位地址,最后一位不再是表示读写命令,因为停止信号还没到来,所以状态一直是写的命令)。

B. 关于通信过程

主机写数据给从机时,先“广播”从机地址(相当于找到对应从机),再发送从机内部寄存器的地址(相当于找到对应从机的对应寄存器),然后主机再发送数据到该寄存器,主机发送完一字节数据后,从机需要发出一个应答信号(这个过程是从机把应答信号发送至主机的CY位)来告诉主机已接收完成一帧数据。

主机读从机数据时,要先"广播"从机地址,再发送从机内部寄存器的地址(相当于要找到数据的来源),然后直接读取一字节数据,读取完一字节数据后,主机向从机发送应答信号(相当于主机告诉从机已经读取到一字节)

综上,不管是从机还是主机,只要是被写入数据,当被写入完一字节数据时,都需要向对方发送应答信号。(相当于读别人的数据,这个过程比如:可以把主机给从机写数据的过程理解成从机读取主机的数据,同样,主机读取从机数据时可以理解成从机往主机里些数据)

代码实现及注释

STC89C52 + MPU6050 + LCD1602.

// 功能: 显示加速度计和陀螺仪的10位原始数据
//****************************************
// 晶振:11.0592M
// 显示:LCD1602#include <REG52.H>
#include <math.h>    //Keil library
#include <stdio.h>   //Keil library
#include <INTRINS.H>  //这个库需要_nop_()函数typedef unsigned char  uchar; //类型定义
typedef unsigned short ushort;
typedef unsigned int   uint;#define DataPort P0         //LCD1602数据端口
sbit    SCL=P1^0;           //IIC时钟引脚定义
sbit    SDA=P1^1;           //IIC数据引脚定义
sbit    LCM_RS=P2^0;        //LCD1602命令端口
sbit    LCM_RW=P2^1;        //LCD1602命令端口
sbit    LCM_EN=P2^2;        //LCD1602命令端口
uchar dis[4];               //显示数字(-511至512)的字符数组
int dis_data;               //变量//看以下变量的时候对应着寄存器里面名称,容易有印象
#define SMPLRT_DIV      0x19    //陀螺仪采样率,典型值:0x07(125Hz)
#define CONFIG          0x1A    //低通滤波频率,典型值:0x06(5Hz)
#define GYRO_CONFIG     0x1B    //陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s)
#define ACCEL_CONFIG    0x1C    //加速计自检、测量范围及高通滤波频率,典型值:0x01(不自检,2G,5Hz)
#define ACCEL_XOUT_H    0x3B    //X轴加速度数据寄存器1地址
#define ACCEL_XOUT_L    0x3C    //X轴加速度数据寄存器2地址
#define ACCEL_YOUT_H    0x3D    //Y轴加速度数据寄存器1地址
#define ACCEL_YOUT_L    0x3E    //Y轴加速度数据寄存器2地址
#define ACCEL_ZOUT_H    0x3F    //Z轴加速度数据寄存器1地址
#define ACCEL_ZOUT_L    0x40    //Z轴加速度数据寄存器2地址
#define TEMP_OUT_H      0x41    //温度传感器数据寄存器1地址
#define TEMP_OUT_L      0x42    //温度传感器数据寄存器2地址
#define GYRO_XOUT_H     0x43    //X轴陀螺仪数据寄存器1地址
#define GYRO_XOUT_L     0x44    //X轴陀螺仪数据寄存器2地址
#define GYRO_YOUT_H     0x45    //Y轴陀螺仪数据寄存器1地址
#define GYRO_YOUT_L     0x46    //Y轴陀螺仪数据寄存器2地址
#define GYRO_ZOUT_H     0x47    //Z轴陀螺仪数据寄存器1地址
#define GYRO_ZOUT_L     0x48    //Z轴陀螺仪数据寄存器2地址
#define PWR_MGMT_1      0x6B    //电源管理,典型值:0x00(正常启用)
#define SlaveAddress    0xD0    //IIC写入时的地址字节数据,+1为读取
//#define WHO_AM_I        0x75    //IIC地址寄存器(默认数值0x68,只读)//****************************************
//函数声明
//****************************************
void  delay(unsigned int k);   //延时
void  InitLcd();     //初始化lcd1602
void  lcd_printf(uchar *s,int temp_data); //把整数转成字符串
void  WriteDataLCM(uchar dataW);         //向LCD写入数据
void  WriteCommandLCM(uchar CMD,uchar Attribc);  //LCD指令
void  DisplayOneChar(uchar X,uchar Y,uchar DData); //显示一个字符
void  DisplayListChar(uchar X,uchar Y,uchar *DData,L); //显示字符串
void  InitMPU6050();    //初始化MPU6050
void  Delay5us();   //IIC协议用到的一些延迟
void  I2C_Start(); //开始信号
void  I2C_Stop();  //停止信号
void  I2C_SendACK(bit ack);  //单片机向MPU6050发送应答
bit   I2C_RecvACK();   //单片机接收MPU6050应答
void  I2C_SendByte(uchar dat);   //通过IIC,单片机向从机发送一字节数据
uchar I2C_RecvByte();  //通过IIC,单片机接收从机一字节数据
void  I2C_ReadPage();
void  I2C_WritePage();
void  display_ACCEL_x(); //LCD显示X轴加速度信息
void  display_ACCEL_y(); //LCD显示Y轴加速度信息
void  display_ACCEL_z(); //LCD显示Z轴加速度信息
uchar Single_ReadI2C(uchar REG_Address);    //读取I2C数据
void  Single_WriteI2C(uchar REG_Address,uchar REG_data); //向I2C写入数据//****************************************
//lcd相关
//****************************************
void lcd_printf(uchar *s,int temp_data)  //整数转字符串
{if(temp_data<0){temp_data=-temp_data;*s='-';}else *s=' ';*++s =temp_data/100+0x30;temp_data=temp_data%100;     //取余运算*++s =temp_data/10+0x30;     //转成ASCII码temp_data=temp_data%10;      //取余运算*++s =temp_data+0x30;
}void delay(unsigned int k)  //延迟函数
{                       unsigned int i,j;               for(i=0;i<k;i++){           for(j=0;j<121;j++);}
}void WaitForEnable(void)    //LCD1602写允许
{                   DataPort=0xff;      LCM_RS=0;LCM_RW=1;_nop_();LCM_EN=1;_nop_();_nop_();while(DataPort&0x80);   LCM_EN=0;
}  void WriteCommandLCM(uchar CMD,uchar Attribc)  //LCD1602写入命令
{                   if(Attribc)WaitForEnable(); LCM_RS=0;LCM_RW=0;_nop_();DataPort=CMD;_nop_();   LCM_EN=1;_nop_();_nop_();LCM_EN=0;
} void WriteDataLCM(uchar dataW)  //LCD1602写入数据
{                   WaitForEnable();        LCM_RS=1;LCM_RW=0;_nop_();DataPort=dataW;_nop_(); LCM_EN=1;_nop_();_nop_();LCM_EN=0;
}void DisplayOneChar(uchar X,uchar Y,uchar DData)  //LCD1602写入一个字符
{                       Y&=1;                       X&=15;                      if(Y)X|=0x40;                   X|=0x80;            WriteCommandLCM(X,0);       WriteDataLCM(DData);
} void DisplayListChar(uchar X,uchar Y,uchar *DData,L)  //LCD1602显示字符串
{uchar ListLength=0; Y&=0x1;                X&=0xF;                while(L--)             {                       DisplayOneChar(X,Y,DData[ListLength]);ListLength++;  X++;                        }
}void InitLcd()   //LCD1602初始化
{           WriteCommandLCM(0x38,1);  //设置8位格式,2行,5x7  WriteCommandLCM(0x08,1);  //关闭显示,检测忙信号  WriteCommandLCM(0x01,1);  //清除屏幕显示  WriteCommandLCM(0x06,1);  //设定输入方式,增量不移位  WriteCommandLCM(0x0c,1);  //整体显示,关光标,不闪烁DisplayOneChar(0,0,'A');  //显示A字符在第0行第0位DisplayOneChar(0,1,'G');  //总共有0,1两行,每行0~15个字符
} //****************************************
//IIC相关
//****************************************
void Delay5us()  //延时5微秒(STC90C52RC@12M)
{_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
}void I2C_Start()  //I2C起始信号
{SDA = 1;                    //拉高数据线SCL = 1;                    //拉高时钟线Delay5us();                 //延时SDA = 0;                    //产生下降沿Delay5us();                 //延时SCL = 0;                    //拉低时钟线
}void I2C_Stop()   //I2C停止信号
{SDA = 0;                    //拉低数据线SCL = 1;                    //拉高时钟线Delay5us();                 //延时SDA = 1;                    //产生上升沿Delay5us();                 //延时
}void I2C_SendACK(bit ack)   //I2C发送应答信号,(0:ACK 1:NAK)
{SDA = ack;                  //写应答信号SCL = 1;                    //拉高时钟线Delay5us();                 //延时SCL = 0;                    //拉低时钟线Delay5us();                 //延时
}bit I2C_RecvACK()  //I2C接收应答信号
{SCL = 1;                    //拉高时钟线Delay5us();                 //延时CY = SDA;                   //读应答信号,存在CY进位位SCL = 0;                    //拉低时钟线Delay5us();                 //延时return CY;
}void I2C_SendByte(uchar dat)  //向I2C总线发送一个字节数据
{uchar i;for (i=0; i<8; i++)         //8位计数器{dat <<= 1;              //移出数据的最高位SDA = CY;               //送数据口SCL = 1;                //拉高时钟线Delay5us();             //延时SCL = 0;                //拉低时钟线Delay5us();             //延时}I2C_RecvACK();
}uchar I2C_RecvByte()  //从I2C总线接收一个字节数据
{uchar i;uchar dat = 0;SDA = 1;                    //使能内部上拉,准备读取数据,for (i=0; i<8; i++)         //8位计数器{dat <<= 1;SCL = 1;                //拉高时钟线Delay5us();             //延时dat |= SDA;             //读数据               SCL = 0;                //拉低时钟线Delay5us();             //延时}return dat;
}void Single_WriteI2C(uchar REG_Address,uchar REG_data)//向I2C设备写入一个字节数据
{I2C_Start();                  //起始信号I2C_SendByte(SlaveAddress);   //发送设备地址+写信号I2C_SendByte(REG_Address);    //内部寄存器地址,这里的写信号由上面一行得来I2C_SendByte(REG_data);       //内部寄存器数据,I2C_Stop();                   //发送停止信号,持续到停止信号
}uchar Single_ReadI2C(uchar REG_Address)//从I2C设备读取一个字节数据
{uchar REG_data;I2C_Start();                   //起始信号I2C_SendByte(SlaveAddress);    //发送设备地址+写信号I2C_SendByte(REG_Address);     //发送存储单元地址,从0开始//上面先进行写命令(广播),找到寄存器位置先(数据的来源)  I2C_Start();                   //起始信号I2C_SendByte(SlaveAddress+1);  //发送设备地址+读信号REG_data=I2C_RecvByte();       //读出寄存器数据I2C_SendACK(1);                //向从机发送应答信号I2C_Stop();                    //停止信号return REG_data;
}void InitMPU6050()  //初始化MPU6050
{Single_WriteI2C(PWR_MGMT_1, 0x00);  //解除休眠状态Single_WriteI2C(SMPLRT_DIV, 0x07);  //设置陀螺仪采样率,典型值:0x07(125Hz)Single_WriteI2C(CONFIG, 0x06);      //低通滤波频率,典型值:0x06(5Hz)Single_WriteI2C(GYRO_CONFIG, 0x18); //陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s)Single_WriteI2C(ACCEL_CONFIG, 0x01);//加速计自检、测量范围及高通滤波频率,典型值:0x01(不自检,2G,5Hz)
}//****************************************
//主程序相关
//****************************************
int GetData(uchar REG_Address) //将MPU6050内部的两个数据寄存器的数据进行合成
{char H,L;H=Single_ReadI2C(REG_Address);L=Single_ReadI2C(REG_Address+1);return (H<<8)+L;   //合成数据,返回十六进制数
}void Display10BitData(int value,uchar x,uchar y)//在1602上显示10位数据
{value /= 64;                          //转换为10位数据lcd_printf(dis, value);         //转换数据显示,dis是dis[4]数组的头地址DisplayListChar(x,y,dis,4); //启始列,行,显示数组,显示长度
}void main()
{ delay(500);     //上电延时      InitLcd();      //液晶初始化InitMPU6050();  //初始化MPU6050delay(150);while(1){Display10BitData(GetData(ACCEL_XOUT_H),2,0);    //显示X轴加速度,第0行第2列Display10BitData(GetData(ACCEL_YOUT_H),7,0);    //显示Y轴加速度Display10BitData(GetData(ACCEL_ZOUT_H),12,0);   //显示Z轴加速度Display10BitData(GetData(GYRO_XOUT_H),2,1); //显示X轴角速度Display10BitData(GetData(GYRO_YOUT_H),7,1); //显示Y轴角速度Display10BitData(GetData(GYRO_ZOUT_H),12,1);    //显示Z轴角速度delay(500);}
}

直接复制以上代码,即可成功运行。
如有理解错误,往大家多多指正,谢谢!

从IIC通信原理到使用 —— MPU6050相关推荐

  1. iic通信原理_电子知识之IIC通信原理和协议分享

    IIC 的一些特征: 两条总线:串行数据总线(SDA)和串行时钟总线(SCL) 真正的多主机总线 连接到相同总线的ic数量只受到总线的最大电容400pF限制. 串行8位双向数据在标准模式下可达100K ...

  2. STM32CubMX自学笔记(十)---IIC通信实验

    STM32CubMX自学笔记(十)-IIC通信实验 I2C通信协议的简介 引脚少,硬件实现简单,可扩展性强,不需要外部收发设备,广泛用在多个集成电路通信. 物理层特点: 信号线SDA和时钟线SCL 1 ...

  3. 学习记录--陀螺仪模块(MPU6050:IIC通信,us延时函数)

    一,mpu6050模块基础(参考HAL库开发指南) 二,CUBEMX配置 用模拟IIC,只需要打开一个串口打印数据就行,IO口的配置直接写在板级支持包的init里了 三,keil中代码(参考正点原子与 ...

  4. [转]从IIC实测波形入手,搞懂IIC通信

    (转载请删除括号里的内容) 玩单片机的朋友都知道IIC通信这个工具,但好多人只是会用,内部的原理不求甚解,或是想要了解其原理,但却对抽象的时序描述一头雾水.本文将从实测的IIC波形入手,带你看到真实的 ...

  5. STM32 TM1637驱动数码管 IIC通信

    最近在做iic实验的过程中发现手边刚好有一个数码管他的驱动正好是使用iic,话不多说直接上代码了 这里就不赘述iic通信的原理和时序图了,网上相关资源也很多这里就附一篇iic的文章,这篇文章相当详细. ...

  6. 51单片机开发板模拟实现IIC通信

    51单片机模拟实现IIC通信 IIC.h IIC.c main.c 总结 IIC.h #ifndef _iic_h_ #define _iic_h_ #include <reg52.h> ...

  7. STM32 PAJ7620U2手势识别模块(IIC通信)程序源码详解

    最近在自学设计下基于STM32单片机的项目,想用手势识别模块做一点好玩的,做个手势控制家居设备开关,另外正好借此巩固I²C 通信.因此,我想借这个机会在这里和大家分享一下自己学习STM32单片机时的所 ...

  8. 软件IIC通信以及源码解析(如何使用)

    以对读取MPU6050为例,解析如何采用IIC通信源码. IIC的的通信,通常三种用途读写.分为: 1: 2: 3: 注:其中最常用的就是1和3了. 对1进行讲解: 指定地址写,通常用作对状态机模块的 ...

  9. STC12C5A60S2使用模拟IIC通信与AT24C02芯片编程

    文章目录 一.前言 二.IIC通讯详解 2-1.IC协议简介 2-2.常用的IIC通讯设备 2-3.IIC物理层特点 2-4.IIC协议层特点 2-4-1.IIC基本读写过程 2-4-2.通讯起始和停 ...

最新文章

  1. 微信小程序 解决请求服务器手机预览请求不到数据的方法
  2. 结构损伤检测与智能诊断 陈长征_阜康危房检测价格
  3. python - 配置文件
  4. python pip 升级
  5. 微信小程序之通过Canvas生成图片保存到手机相册
  6. python Binary I/O
  7. C#學習基礎------事件和索引指示器
  8. 计算机上机单招试题及答案,全国高职单招计算机类模拟试卷考卷及答案
  9. C++实现 逆波兰表达式计算问题
  10. 第68天-内网安全-域横向 PTHPTKPTT 哈希票据传
  11. win10浏览器加载很慢_Win10 IE浏览器的网页加载速度很慢总是卡死怎么办
  12. 使用python lxml库中的xpath、etree爬取网页超链接
  13. Latex去掉proof后面显示的小白框 (\qed)
  14. core dumped 错误
  15. 乙女心,养的第一株多肉小植物
  16. visual basic 6 下载 和 Vb6sp6 下载
  17. python 人像素描_谁说程序员不懂浪漫的,直接用 Python 给女朋友画张素描
  18. YOLOv4论文中文翻译
  19. excel切片器_Excel切片器,让图表动起来
  20. 机器学习之线性回归原理详解、公式推导(手推)、简单实例

热门文章

  1. android vlc rtsp卡顿,VLC播放器 RTSP 卡顿解决
  2. Android动态链接库减小体积
  3. 航模电机UVW波形测量
  4. 结构光在3D SPI / AOI检测中的应用
  5. 财务自由:多少钱才算够?
  6. linux系统适合什么游戏,Linux 系统不适合运行主流游戏?这是为何
  7. 网易严选数据质量实践
  8. 知乎周源微信_每周源代码42-树修剪,插件和MEF
  9. .NET MEF托管可扩展框架
  10. 关于 tomcat9 下载后启动不了的问题