一.MPU6050介绍
* |" U8 u9 A+ E! L1.MPU6050与陀螺仪、加速度计的关系:
: n: J& \0 v1 [4 @MPU6050是InvenSense公司推出的一款全球首款的整合性9轴运动处理传感器,其最大的特色就是:消除了陀螺仪和加速度计的误差,将陀螺仪和加速度计组合在一起,而且缩小了空间。
7 o: F7 U7 X/ S+ g" o1 E# H( u3 M( u! c) N6 n6 u2 o0 w, f
2.整体概括! o8 b7 W3 u. w' ~$ o: C3 u$ e
MPU6050内部整合了三轴MEMS陀螺仪、三轴MEMS加速度计以及一个可扩展的数字运动处理器DMP,而且还可以连接一个第三方数字传感器(比如:磁力计),这样的话,就可以通过IIC接口输出一个9轴信号。
$ d* f8 W2 T. j1 g* P! n更加方便的是,有了DMP,可以结合InvenSense公司提供的运动处理资料库,实现姿态解算。通过自带的DMP,可以通过IIC接口输出9轴融合演算的数据,大大降低了运动处理运算对操作系统的负荷,同时也降低了开发难度。
, r$ @ n, R j, ?/ I+ _9 M& Z I' Z; i
; J7 d5 X, v# \4 f8 k; E特点:
1 @! r3 {/ V, c" O① 以数字形式输出 6 轴或 9 轴(需外接磁传感器)的旋转矩阵、四元数(quaternion)、欧
! T4 C& E$ |) `2 x& y! M拉角格式(Euler Angle forma)的融合演算数据(需 DMP 支持)3 q% c# t. n z4 ?4 L, j0 p
② 具有 131 LSBs/° /sec 敏感度与全格感测范围为±250、±500、±1000 与±2000° /sec# A5 C2 q- R* T2 N! l
的 3 轴角速度感测器(陀螺仪)2 M! s* D& }7 x2 M6 a% V
③ 集成可程序控制,范围为±2g、±4g、±8g 和±16g 的 3 轴加速度传感器 |5 W6 Z" d3 C
④ 移除加速器与陀螺仪轴间敏感度,降低设定给予的影响与感测器的飘移+ n, o( x. T+ \+ c$ t
⑤ 自带数字运动处理(DMP: Digital Motion Processing)引擎可减少 MCU 复杂的融合演算( A X* |' B" y2 I) z' |* R
数据、感测器同步化、姿势感应等的负荷
7 q" ~! S4 G) Q⑥ 内建运作时间偏差与磁力感测器校正演算技术,免除了客户须另外进行校正的需求4 Y" g5 S. g1 [* [ b9 @9 N: f
⑦ 自带一个数字温度传感器9 ?! I1 S% @5 N, T4 ?+ E
⑧ 带数字输入同步引脚(Sync pin)支持视频电子影相稳定技术与 GPS
) C* E* C5 `9 |7 O⑨ 可程序控制的中断(interrupt),支持姿势识别、摇摄、画面放大缩小、滚动、快速下降8 `$ f. [9 M3 [6 B4 a& X
中断、 high-G 中断、零动作感应、触击感应、摇动感应功能9 `& J u* E# A6 J: _1 w& Y) }
⑩ VDD 供电电压为 2.5V±5%、 3.0V±5%、 3.3V±5%; VLOGIC 可低至 1.8V± 5%
% O6 q% ]$ T% x5 [⑪ 陀螺仪工作电流: 5mA,陀螺仪待机电流: 5uA; 加速器工作电流: 500uA,加速器省1 N& q: y* L* L E9 V/ P, u
电模式电流: 40uA@10Hz" `" E0 h; L( y
⑫ 自带 1024 字节 FIFO,有助于降低系统功耗; g& F3 z1 J z
⑬ 高达 400Khz 的 IIC 通信接口
0 T$ v8 P8 W$ t⑭ 超小封装尺寸: 4x4x0.9mm(QFN)" P2 B0 ?: L1 z! J
8 h/ l' c& `8 G$ \其检测轴如图所示:! c" h, l9 j) u$ r: e5 q
( |4 f4 z8 Y; P% U1 [2 Q% e p
% R9 }/ ], _: ~# G% ^2 C2 z2 i# i8 O( j" M
' s% z8 d3 a; b2 o
3.引脚说明
# I1 h. M x: Y& A7 g* `& c0 P' X& a, v7 ~0 M
: N" E8 M0 l4 }& @( l. V7 z8 d) L( t2 Z
' k4 D) t- U2 |. q如图,MPU6050一共有8个引脚,实际上输出六轴数据时,只用了5个:VCC、GND、SCL、SDA、AD0。下面介绍一下引脚:
5 t @- a, x/ j" u# J. kVCC:供电,3.3V即可
4 U, s' T) x$ j" Y% k& cGND:接地
# x, R: M* }" j$ CSCL:连接MCU的IIC时钟接口/ I& s) `5 Y( Z0 q" y$ ]
SAD:连接MCU的IIC数据接口6 L& @# v7 j: B) t B5 u
XCL:连接外部设备的IIC时钟接口$ f$ w* e% R# S; H( m6 F
XAD:连接外部设备的IIC数据接口
7 S, I9 m0 A) @+ C8 q C/ K/ oAD0:地址控制引脚(控制地址的最低位)
# n% ]) C, T3 CINT:中断触发接口(不用)6 x* \! H4 K. Z* H4 J
XCL、XDA只有在连接外部设备(比如磁力计的时候才用),AD0用来控制MPU6050的地址,如果AD0低电平,地址就是0X68;如果AD0高电平,地址就是0X69。
8 C) p5 c* u( E8 h% x$ y) T/ Q
. k, p/ z. P j- P$ ?+ \4 F4.基本配置及相关寄存器
5 j7 P% ]9 @5 _+ _- pMCU与MPU6050的通信是建立在IIC通信机制上的,在IIC的基础上,可以实现对MPU6050的寄存器的操作,而MPU6050的运作就是过对寄存器进行读写。所以,了解相关的寄存器和对寄存器的操作是很有必要的。MPU6050的寄存器相关资料都可以在数据手册中查到,下面介绍一下几个重要的寄存器:
' `9 `/ J; b) `$ f+ O8 A
\# \- {7 x2 ^, m电源管理寄存器10 [1 y$ M5 |9 y& ^: r
地址:0X68! a' }/ W( a) T f
3 Q, `9 X. n- a9 ?0 i W2 r# k0 \! f2 ~" Z' ]( _5 r5 J2 P- O
8 ?! U) w \3 o5 B
1 s% e# O; N; i* Z' A) T
主要位的功能:9 N$ ?% B& o+ i* |& Y$ Z
DEVICE_RESET:控制复位,1表示复位,复位后会自动清零;9 B1 K" Q) G. M, A0 A
SLEEP:控制MPU6050工作模式,1表示睡眠模式,0表示正常工作模式,复位后改位为1,要手动将改位清零;/ c3 R) Y$ E. Z6 _
TEMP_DIS:使能温度传感器位,0代表使能;% I6 v9 q" E! y! s
CLKSEL[2:0]:选择系统时钟源,一般采用PLL_X轴陀螺作为参考,具体的时钟源选择及相应位的值如图:3 G. J7 i1 n: V- P
7 t& j0 h3 S! q. S; [2 l
4 f. v" M9 V$ {$ C" y3 N. `
6 i; `+ O' h1 O5 F2 T: |. I: H: A& G
陀螺仪配置寄存器
* z L5 t( \) B" e" g t地址:0X1B, Y' N; c5 U2 w
) ?2 t. A- e1 S; b# w
1 W- @0 N/ @& Q5 [" y9 P9 u8 `: _$ g5 M- }) Q6 i. C2 k; J2 n( Z
主要位的功能:
. {$ J6 V- @5 r( q4 BFS_SEL[1:0]:设置陀螺仪满量程范围:为0代表±250° /S、为1代表±500° /S、为2代表±1000° /S为3代表±2000° /S;$ q9 v) l8 U, q0 _2 Z% p# ~: g1 o
% G0 \8 A& D- V* j% a! x% e* P: \
陀螺仪的分辨率是16位,所以在最大量程下灵敏度为: 65536/4000=16.4LSB/(° /S)。+ U! g, S3 H2 d* |3 C
' C1 M9 X6 _6 h/ x9 c& Z }4 ]加速度计配置寄存器
: r o1 ]4 C9 F# U. A地址:0X1C4 [+ X" E M% p& D
D8 z5 `8 }. J' i
4 p9 E: i% g8 p$ k
' T2 e) ]2 x2 y- \7 k主要位的功能:; i! B, Q& s7 r0 G6 Z( w+ z
AFS_SEL[1:0]:设置加速度计满量程范围:为 0代表±2g、为1代表±4g、为 2代表±8g、为 3代表±16g;
9 C1 x# E8 J$ Y* C% t8 Z& D. q- s8 Q
FIFO使能寄存器3 R9 c5 ?9 m, t% n. W
地址:0X23
C' p8 \9 `6 V) \+ }3 J% E7 B" k |' c
: b- T; d; V% k9 Q* M8 t! U
4 R- B3 J* h) d i用来控制FIFO功能,相应位对应着相应的传感器FIFO功能,为0代表禁止,为1代表使能。注意:加速度传感器的三个轴的FIFO功能由一个位ACCEL_FIFO_EN控制。在简单读取传感器数据的情况下可以不使用FIFO。+ V& s* o- f s ~
8 ? W1 Q9 U3 l" I
陀螺仪采样率分频寄存器
6 h( J6 ]% h/ R! a2 x- z' A Q地址:0X19& P% q* w6 U# r0 A6 z# i- D0 b8 E/ y
1 L! J# X* [/ L; [7 j& Y
% R8 m/ B" n! o
* @$ \4 Y! k# D4 d! X改寄存器用来设置MPU6050陀螺仪的采样频率,与之相关的是陀螺仪的输出频率,俩者关系是:采样频率 = 陀螺仪输出频率 / (1+SMPLRT_DIV)
" _( C, v- x7 n3 ]( Z陀螺仪输出频率与数字低通滤波器(DLPF)有关,DLPF滤波频率一般设置为采样率的一半。4 x( J4 X/ j6 M- J
$ F3 b1 Z$ [$ i! S3 w温度传感器寄存器
* Y* p: l4 k! O3 E! O" G+ A地址:高八位0X41、低八位0X422 Y4 L( B. R# P/ n
直接通过读取寄存器中的值来得到温度数据,温度换算公式为:; J r S q0 T# X; _, z
Temperature = 36.53 + regval/3402 w% R& i% b- }# c& e
F7 N& w. S- \
二.代码详解, b8 p& m7 U/ `4 o, l
1.框架
. {, \ q) P$ R8 s* o, C0 N, \我是用STM32驱动MPU6050,MPU6050输出原始的六轴数据,经过DMP处理(有库)得到四元数,再由四元数算出欧拉角:yaw、roll、pitch。由串口打印在电脑屏幕上。
: X d, c2 H: s, l" i( g) `2 q首先,要做底层的IIC驱动,用来和MPU6050建立通信,我在mpu_iic.c中实现了;
: [; A( e+ B3 D3 e然后,有了底层的驱动,就要写一些函数来与MPU6050交流了(通过读写寄存器),还可以写入命令、配置MPU6050、读取原始数据等等,这些操作我都写在mpu6050.c中,当然在mpu6050.h头文件中还包含了MPU各寄存器地址和相关指令。
* A1 ?; }7 T' D2 I通过mpu6050.c的实现,就可以读出原始六轴数据,下一步就是通过DMP将原始数据转换为四元数,这一步的DMP算法我水平有限,只能移植InvenSense公司提供的例程。关于移植DMP算法,由于DMP算法本质也是对MPU6050的操作,所以我们只需要向移植过来的算法提供:对MPU6050寄存器执行读和写的函数接口即可,最后通过移植过来的函数直接读出四元数!
, k1 I9 V% I' b& Q" Q8 L然后,就是将四元数转换为欧拉角了,这个比较简单,一个函数就可以实现。0 E. `% e7 i3 Y2 ~5 H5 ]
最后,打印串口到屏幕。) g7 [0 P" L5 l, z
2 v# o' t0 q% d) _下面给出各函数文件5 \. e m0 T; s/ Y) K5 t
/ ~: n: U4 g$ W% q. F" [
2.mpu_iic.c/mpu_iic.h7 X6 [1 R$ Q$ L0 l' e
mpu_iic.h5 {2 I: Z- R4 L% N) F, Y
主要是宏定义对引脚电平的操作和进行函数声明。
* ]; [4 N9 U: _' Y# a5 U! i- #ifndef __MPU_IIC_H1 L' N; U. S; z' d
- #define __MPU_IIC_H
# u0 ]- o3 M2 J y# w
2 h% G; c! `" M8 [- #include "stm32f10x.h"( S. a: X2 ]9 e+ h6 j# G
- #include "delay.h"/ Y: D/ f$ A' N" E$ H% A- S- n4 b6 D
- 9 I. s2 | t ]/ i4 G
- /* 宏定义引脚电平操作函数 */" _8 u- K( w3 |, J; C
- #define MPU_SDA_IN() {GPIOB->CRH&=0XFFFF0FFF;GPIOB->CRH|=8<<12;}
. k) E/ e6 \) D& F8 I, y" Z - #define MPU_SDA_OUT() {GPIOB->CRH&=0XFFFF0FFF;GPIOB->CRH|=3<<12;}
" ]$ V/ T6 }$ I0 J" c, v5 u$ e - . C% J6 \3 G* Z. N- M% L6 \1 C! q
" w7 O+ U6 X; c) X; p0 H- #define MPU_IIC_SDA_1() GPIO_SetBits( GPIOB, GPIO_Pin_11 )
9 k- H. |7 U% T9 `, D - #define MPU_IIC_SDA_0() GPIO_ResetBits( GPIOB, GPIO_Pin_11 )
$ `: ~) a7 {5 h1 M1 }4 U' k* l5 a
+ X% [9 n2 [- b% i- #define MPU_IIC_SCL_1() GPIO_SetBits( GPIOB, GPIO_Pin_10 )
3 e+ Q4 k' U/ | |4 P$ ] - #define MPU_IIC_SCL_0() GPIO_ResetBits( GPIOB, GPIO_Pin_10 )
2 O* n8 H+ F0 a9 y* i6 x+ [
# v `( ?+ o4 L* r( g- #define MPU_IIC_AD0_1() GPIO_SetBits( GPIOA, GPIO_Pin_15 ) G- I; L5 I/ v4 k/ Q2 V
- #define MPU_IIC_AD0_0() GPIO_ResetBits( GPIOA, GPIO_Pin_15 )
" Z5 R- _; {0 X* { - 7 o( D; g' n1 P
- #define MPU_IIC_SDA_READ() GPIO_ReadInputDataBit( GPIOB, GPIO_Pin_11 )6 d) Q, X- d: ~! c I* H8 _9 W
- 3 F1 g/ l. l9 R* |
- #define MPU_IIC_Delay() delay_us(2)% z* s% T2 V, g
% Y: o4 q0 o2 F7 \- /* 函数声明 */
, ~7 w- f4 X. h b - void MPU_IIC_Init( void );
5 }8 L4 J0 T: I, _9 d - void MPU_IIC_Start( void );
. L" k r5 R3 f' n8 z5 o* I - void MPU_IIC_Stop( void );
, I' t9 Z2 `# Y' c" D( M# ^+ X - uint8_t MPU_IIC_Wait_Ack( void );. c- f/ e1 [0 z' L/ T6 W
- void MPU_IIC_Ack( void );
]. P9 T- u, z - void MPU_IIC_NAck( void );+ ?7 I/ q9 I" P6 a: Q# m5 ~
- void MPU_IIC_Send_Byte( uint8_t data );$ l2 O4 S, K7 |# n0 X6 H
- uint8_t MPU_IIC_Read_Byte( uint8_t ack );) `* a& p, D! g; w
/ O% |& s7 P' g6 t7 H- #endif. v) p1 v- s% [
- & ]8 W' L: J$ y! ]! A; L
复制代码
7 v& N! V# L: x6 f3 Ympu_iic.c
' r0 P) S {5 C9 t通过软件模拟IIC的代码,没什么好说的。
/ X0 P" ]) @0 P; R# [- #include "mpu_iic.h"
/ ~+ u# y1 M8 ] - #include "usart.h"( \: q* I8 M' _6 [
- . y- b! U- F% q- H8 a2 i; o' f- s
- /*
+ h/ I. T: U7 m \0 Z" o - IIC接口引脚配置
) q" _: E# J3 ]" W& m - SDA:PB11" b. ?/ k4 a1 i0 |. V
- SCL:PB10+ X/ E! q. ?4 d, U4 a/ u
- AD0:PB29 {4 \: ^' Z7 G# N/ @4 E
- */
4 U- M9 N" C; ~1 y6 w8 T) F/ E - void MPU_IIC_Init( void )
. g5 b4 f+ s; E0 i4 j - {
9 q( A$ b+ O9 j# }- v! U - GPIO_InitTypeDef GPIO_InitStruct;' e! Q! V6 q, N* y/ z1 K
-
, [3 M6 ^% h9 T3 {0 V - RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );
% E; {4 R: e7 W: J2 e" J -
7 G( E: i: s( f( R) O2 e- V - GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
% E" @% T' e) Q7 P - GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
' y8 s% s8 L2 r( ^3 u, c/ }! X - GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11;
& V4 Z* d: X8 \6 p, h V' g. h6 t - GPIO_Init( GPIOB, &GPIO_InitStruct );
. r) d& }. }1 Z2 j1 z/ { -
, [5 _9 e, ]. O8 L* { - MPU_IIC_SDA_1();
3 y$ G! j5 ^) h# }2 [ - MPU_IIC_SCL_1();6 j, f7 K2 P: c
- 1 O/ T7 y: B' e' @' U. y
- }7 F- [* Y7 k6 b9 k
0 w/ F; @; Z! C- % ~5 J3 F9 S; Z
- void MPU_IIC_Start( void )
- \- [: k8 ?+ M* ~7 v5 m - {! v0 c7 z* K/ ^1 t
- MPU_SDA_OUT();
' H3 }* E+ ~+ k3 h J& { -
( e$ l4 Q# Z/ _7 a - MPU_IIC_SDA_1();# ]6 b* H5 c$ l. j
- MPU_IIC_SCL_1();9 j) J) ~5 ?% J* b8 c& n2 q
- delay_us(2);( k$ I* P+ B- c$ y! I7 y
- MPU_IIC_SDA_0();$ Q* [3 n9 P1 O4 i* L0 y
- delay_us(2);/ {$ }% t+ c$ \ o
- MPU_IIC_SCL_0();# v4 G2 K4 j; ]. Y( {% b6 c1 c
- }
5 r5 s* p9 q" Y* B - 4 ~$ Z: l( }8 } I$ c
- void MPU_IIC_Stop( void )
; r! G. j& Z$ `0 v* ^5 ]! J; ] - {. h" k1 T9 D7 P8 T$ r+ Y0 L
- MPU_SDA_OUT();9 ]7 S3 k+ O7 W( S8 |) U
- 4 Q: @, Q% `1 j0 B; P
- MPU_IIC_SDA_0();- h' o& P5 o3 h* ], C9 Q
- MPU_IIC_SCL_1();
: y0 l# L$ ~! w - delay_us(2);+ c+ S* d' i8 _% G
- MPU_IIC_SDA_1();2 C- j* A1 S W0 f. K
- MPU_IIC_SCL_1();$ i+ E+ S/ S+ i+ S( D
- delay_us(2);( Q" V# G6 ~7 I9 q) }7 \8 D
- & L& K0 e- t/ U: I/ T' }
- }( {6 r) u6 N K6 [
- : M- {8 g9 S4 F0 ]3 F
- /* 由从设备在SCL为高电平的时候拉低SDA作为应答
6 w$ | o% [4 Q6 B - 返回值:1:未应答
! X* F8 c) a. S* Q - 0:已应答! W1 u, q2 j3 w
- */% R: \9 X, {; _
- uint8_t MPU_IIC_Wait_Ack( void )- k# M `9 _/ b. N8 }6 J- P5 @: X
- {
! L2 t0 B4 D. Q" y - uint8_t count;2 V+ ~$ H0 ^, O7 c+ a
- MPU_SDA_IN();
6 L" y# t& i! r7 n* y; r - ) D$ s6 u( \2 A) P, N
- MPU_IIC_SCL_1();
( Z( |4 I; x: g+ |6 Y. \ - delay_us(2);( m! a0 ?4 E, i* R! A
- MPU_IIC_SDA_1();
, i5 j/ @/ X& S% s - delay_us(2);
8 Q* P% ^) G/ e4 N - ! A; @. ` U: E5 J- I
- while( MPU_IIC_SDA_READ()==1 )
$ `# l1 }/ r8 c# C# \( ? - {
4 k3 V! v k# ?& V# o - count++;
8 V2 i1 S% A% V' Y - if( count>250 )* c+ }7 h( ^# ?6 f1 v5 _
- {, D5 r8 N8 P3 [9 w! B$ V
- MPU_IIC_Stop();
0 Z: _/ U; p2 z - return 1;
8 K% V( Q4 o3 f - }7 ?; E- u+ }$ {
- } 1 X' I' J. L: b, B# x
- MPU_IIC_SCL_0();
8 g) V6 d" {$ O9 \, R% u - return 0;
5 R. D6 s0 h3 q1 [; M: N - }6 @1 C) u8 u! C% {% K
% k* z8 R" {( o1 `! S! H- ! G( s2 f. l1 B5 D" r
- void MPU_IIC_Ack( void )8 z! c9 d, ?- w! @8 H/ G
- {' `; p/ t2 r4 b2 X& P. B
-
C9 W: [1 W# X, W; f/ S - MPU_IIC_SCL_0();
8 z) A" @! O1 S, U& q) X - MPU_SDA_OUT();4 H: {: A" N, u' }$ z: s
- MPU_IIC_SDA_0();. m' n( z m, D* A0 }! Q
- delay_us(2);
, x" u' l L2 H2 }( @ - MPU_IIC_SCL_1();, G( k! A* v/ w2 w" D
- delay_us(2);4 D1 k: t# z q* g
- MPU_IIC_SCL_0();
4 ?5 m7 k3 J2 M- u - $ \7 ~& E/ i2 y0 y" _' j+ o7 V( a
- }
# W' ^! n. @- J( C! n
4 p. p l' n$ A1 d' f- 4 O* z9 ~; k# z) }
- void MPU_IIC_NAck( void )
5 \. p$ C( s0 ^4 k% r0 t; C6 l. O - {
# C2 n4 N3 c. ]1 \* b -
9 V' K. S% K! Q$ H4 ` -
4 U+ a) S/ w2 i% _+ ^1 U9 a - MPU_IIC_SCL_0();
8 U) R; r) q6 }. \ - MPU_SDA_OUT();) b* \* ^, |% L4 T# X* W
- MPU_IIC_SDA_1();
7 B: z( F: O; r; P - delay_us(2); a/ i! O z P0 t! T1 F/ W
- MPU_IIC_SCL_1();
2 O9 [" l( e6 @6 j, i - delay_us(2);
8 X# z( o- `% i0 ~5 n0 y# O& f - MPU_IIC_SCL_0();
: A% ?! T; J0 L* D9 y8 b5 i0 O2 R# u - }
% f2 S( ^) t% o% s) t. j2 {
% r+ b' \- k: ]' }" i% D
/ Z6 z5 O5 b: v- /* 发送一个字节数据,高位先行 */- n; v* M" V$ Z
- void MPU_IIC_Send_Byte( uint8_t data )$ i9 [ u/ s9 g1 D+ a9 O
- {
5 U1 Y6 W |$ ?; W' t) k/ } - uint8_t t;, U \) B) D, B9 X$ G% B5 ]4 ~6 d
- MPU_SDA_OUT();
& V, h5 w" I! U. i -
( w9 z4 m$ K& Y m. U) T( Z! y) ] - MPU_IIC_SCL_0();
- t& H) o2 c) Q- }9 d4 I6 S# f - for( t=0;t<8;t++ )
' s C! A5 [/ r+ P2 B) J- K; ` - {
* J J4 @* T7 Z3 [6 k' g - if( ((data&0x80)>>7)==1 )6 }0 Y+ _4 y/ k2 v, t( l
- MPU_IIC_SDA_1();2 C0 K, z# ]; _& V
- else ?' |. Q; f4 o/ e4 s8 v
- MPU_IIC_SDA_0();" c! j* |% m2 b7 j, L
- data<<=1;( \" Z5 A6 n1 L4 H4 K2 m
- MPU_IIC_SCL_1();
5 F F+ ?- g- R( r: ] - delay_us(2);
0 s4 d' _' e* u) Q2 _1 ? - MPU_IIC_SCL_0();2 {3 M' N( d! ~
- delay_us(2);4 w: R/ O- B: P. R9 d. c, b% Z
- }
- P* c* |* d2 b6 O& t8 {2 V W: \0 a0 r - }
+ [2 z+ ?. I S& I3 ]: p - 0 {8 E/ q1 y8 B" m. { t, y; R
- Q7 j$ l6 t1 L% ^- ^: S/ H, `- /* 读取一个字节,ack=1时,读取完成后主机发送应答 */+ r1 K% ?1 o. ?$ d% j
- uint8_t MPU_IIC_Read_Byte( uint8_t ack ): E. V& g0 y" X. A, K s
- {$ k4 o$ U! r3 |0 ~% C
- uint8_t t,data=0;/ O. S4 H0 r8 I+ J' X% P
- MPU_SDA_IN();) Z/ F1 M1 ~* \, |8 J- R% j; \5 }
- for( t=0;t<8;t++ )' C6 F: Q3 s+ F! Q5 y- B
- {- [3 B4 U' w# p# m( [0 E& v8 R0 B( p
- MPU_IIC_SCL_0();
& h0 h: E. A7 A0 I9 w9 Y0 O6 F& [ - delay_us(2);//等待SDA的变化, x( J: a0 f2 j8 o- c# m2 Q V
- MPU_IIC_SCL_1();
. Q7 | o( y% c0 h4 d) T - : G, B0 Y: B4 u! }
- data<<=1;//必须在读取前面,因为之后一位读取后就不再移位
0 b t# g& W. ]+ W1 Z9 G8 ?5 B8 Q - if( MPU_IIC_SDA_READ()==1 )# _* J) P& k: b# b0 ^4 {- m, ^6 D
- data++;
9 T! _6 ~) a& e -
4 g' g1 B1 I3 O1 E" ?$ W - delay_us(2);//等待SDA的变化
0 b+ t# a& w" K# |7 q -
$ g( @" S; n) N9 @+ ~ - }
& _5 w7 g- l8 K9 F - 9 c" L- F4 g7 i" i
- if( !ack )
3 [0 }+ k1 x. C0 D |/ C2 T - MPU_IIC_NAck();//发送nACK
5 ~& t" {5 T# }& ^ - else
) o2 G6 |9 |6 f4 n s% h& q$ ` - MPU_IIC_Ack(); //发送ACK 6 s/ \; Z: B3 k4 D4 K9 t8 k( X
- return data;
* S* N a4 D, m7 D' x' ` - }4 z( R' O8 [; y. ?5 u
- ; S: B2 Q6 u) S* x( M
- 4 T+ F& M+ g: c7 ]- s7 s1 L
复制代码 , Z+ t6 V" [" B+ y2 r
3.mpu6050.c/mpu6050.h
, d% K/ r+ l+ D' O$ pmpu6050.h
# Q* u& ^5 |* M" q3 G+ |* b G主要是定义MPU相关寄存器的地址,和进行函数声明。( c5 ~& Y3 A# b9 a) X
- #ifndef __MPU6050_H
1 _2 o1 U4 z( v% ? - #define __MPU6050_H
) `: k% s' j* h. s+ p9 \7 O - 7 p; V6 e( d" [3 T
- #include "stm32f10x.h"
: i, ~! u U# U' V& C% w0 d$ E - #include "mpu_iic.h"# C* ]" z& j8 W- c+ R% f3 }/ k
- ( ^3 J5 \0 O, `; {1 Z
- - f5 @4 E2 m1 t l
- /* AD0接地,MPU6050的IIC地址为0x68 接3.3V就为0x69*/0 ?9 l* `/ d8 S+ }
- #define MPU_ADDR 0X68
1 V* f) _* O$ c - ( P6 x+ u ~" u* c
- /************** MPU6050相关寄存器地址 *********************/
1 c& K# D0 y$ M1 d3 y z - #define MPU_ACCEL_OFFS_REG 0X06 //accel_offs寄存器,可读取版本号,寄存器手册未提到
1 X2 L% l: d& |, L - #define MPU_PROD_ID_REG 0X0C //prod id寄存器,在寄存器手册未提到
2 ?1 F( I2 `- F5 e7 w - #define MPU_SELF_TESTX_REG 0X0D //自检寄存器X! |' ?; t/ a; ]. W3 u# t
- #define MPU_SELF_TESTY_REG 0X0E //自检寄存器Y. @5 [+ j" K+ X
- #define MPU_SELF_TESTZ_REG 0X0F //自检寄存器Z
, x, _ M( A$ U c- b9 } - #define MPU_SELF_TESTA_REG 0X10 //自检寄存器A9 Y7 G2 a+ t7 C( B" n% ^4 s
- #define MPU_SAMPLE_RATE_REG 0X19 //采样频率分频器
) X' i1 L5 Q3 _ - #define MPU_CFG_REG 0X1A //配置寄存器* r- D- \ ^. s7 v3 ~* V
- #define MPU_GYRO_CFG_REG 0X1B //陀螺仪配置寄存器8 B7 ^1 `" I3 h, M
- #define MPU_ACCEL_CFG_REG 0X1C //加速度计配置寄存器% q1 e8 c+ C9 Y, V) u" p. ^$ _2 Y i
- #define MPU_MOTION_DET_REG 0X1F //运动检测阀值设置寄存器1 B; h! V$ f; Z6 n$ @5 L4 Y/ t
- #define MPU_FIFO_EN_REG 0X23 //FIFO使能寄存器
* \) d Q) a' k% c$ X - #define MPU_I2CMST_CTRL_REG 0X24 //IIC主机控制寄存器 q$ _9 l2 w# H% Q( _* v
- #define MPU_I2CSLV0_ADDR_REG 0X25 //IIC从机0器件地址寄存器
1 j5 ~ m9 Y, a" Q! [" `* N: p - #define MPU_I2CSLV0_REG 0X26 //IIC从机0数据地址寄存器
% B% I! h" a& G% ~' d, Y - #define MPU_I2CSLV0_CTRL_REG 0X27 //IIC从机0控制寄存器! E5 m% s1 q5 S, k
- #define MPU_I2CSLV1_ADDR_REG 0X28 //IIC从机1器件地址寄存器3 ^: U9 `! ? ]+ b: v( P- D" E
- #define MPU_I2CSLV1_REG 0X29 //IIC从机1数据地址寄存器' L( m' ]2 D& K+ o: b' |
- #define MPU_I2CSLV1_CTRL_REG 0X2A //IIC从机1控制寄存器5 a4 s# S, h7 X: ^/ H
- #define MPU_I2CSLV2_ADDR_REG 0X2B //IIC从机2器件地址寄存器/ e6 z7 X+ n3 P8 d- \
- #define MPU_I2CSLV2_REG 0X2C //IIC从机2数据地址寄存器' o" e; R1 y. _( b& Z
- #define MPU_I2CSLV2_CTRL_REG 0X2D //IIC从机2控制寄存器$ |* d7 Y9 w9 {$ d" n8 N
- #define MPU_I2CSLV3_ADDR_REG 0X2E //IIC从机3器件地址寄存器
3 B1 u; V- g4 Q9 h l$ s# ? - #define MPU_I2CSLV3_REG 0X2F //IIC从机3数据地址寄存器6 k) p/ E& E: i
- #define MPU_I2CSLV3_CTRL_REG 0X30 //IIC从机3控制寄存器
4 U: l3 s1 j. j) v- i' ^ - #define MPU_I2CSLV4_ADDR_REG 0X31 //IIC从机4器件地址寄存器
; t3 g/ U2 q+ G1 h; A. A - #define MPU_I2CSLV4_REG 0X32 //IIC从机4数据地址寄存器
: a, K5 j% z, U1 q; J3 ? - #define MPU_I2CSLV4_DO_REG 0X33 //IIC从机4写数据寄存器
+ t4 j5 E" ]3 Y6 q p) j4 x - #define MPU_I2CSLV4_CTRL_REG 0X34 //IIC从机4控制寄存器
4 R& T/ c5 O# V2 X6 u - #define MPU_I2CSLV4_DI_REG 0X35 //IIC从机4读数据寄存器
8 {( ]. i4 ~$ E - ; S+ G8 |; B+ ]2 w2 t" h- \" ^
- #define MPU_I2CMST_STA_REG 0X36 //IIC主机状态寄存器
& D2 {, [" @/ M1 f - #define MPU_INTBP_CFG_REG 0X37 //中断/旁路设置寄存器% Z$ _: ~) @% b1 m% u* L
- #define MPU_INT_EN_REG 0X38 //中断使能寄存器( E! I; ?. `+ g: i; _2 S
- #define MPU_INT_STA_REG 0X3A //中断状态寄存器
) S* n( O# h* c F - * O; D$ }% A! _7 P' i
- #define MPU_ACCEL_XOUTH_REG 0X3B //加速度值,X轴高8位寄存器
- a- ^$ w) F. k" c - #define MPU_ACCEL_XOUTL_REG 0X3C //加速度值,X轴低8位寄存器, F& `6 s& m) k; c
- #define MPU_ACCEL_YOUTH_REG 0X3D //加速度值,Y轴高8位寄存器: Z* S2 _% D' }
- #define MPU_ACCEL_YOUTL_REG 0X3E //加速度值,Y轴低8位寄存器& ^% y- z5 H* f
- #define MPU_ACCEL_ZOUTH_REG 0X3F //加速度值,Z轴高8位寄存器
, `$ ?, O1 R2 J$ v6 V; B - #define MPU_ACCEL_ZOUTL_REG 0X40 //加速度值,Z轴低8位寄存器8 p( E& g$ {* c+ f' N& u$ d# q
- 1 D, u8 n2 n! W% m& A/ W
- #define MPU_TEMP_OUTH_REG 0X41 //温度值高八位寄存器- s9 d! l# j6 v5 A& u7 g8 D4 O
- #define MPU_TEMP_OUTL_REG 0X42 //温度值低8位寄存器: v3 X9 k z. J; N c, }
% ]; U8 }! o6 J- |" |6 D/ K, T- #define MPU_GYRO_XOUTH_REG 0X43 //陀螺仪值,X轴高8位寄存器
3 k. r/ ?' J7 M9 L9 W1 ~$ g: _ - #define MPU_GYRO_XOUTL_REG 0X44 //陀螺仪值,X轴低8位寄存器* ?) W; P8 X9 e- ^4 Q$ [, z
- #define MPU_GYRO_YOUTH_REG 0X45 //陀螺仪值,Y轴高8位寄存器1 d; d" ~% f& N# v4 n9 j5 o
- #define MPU_GYRO_YOUTL_REG 0X46 //陀螺仪值,Y轴低8位寄存器/ n( b/ x+ B4 O, d2 g6 i. l3 w
- #define MPU_GYRO_ZOUTH_REG 0X47 //陀螺仪值,Z轴高8位寄存器
0 G) M% c7 l2 ~ - #define MPU_GYRO_ZOUTL_REG 0X48 //陀螺仪值,Z轴低8位寄存器
/ W. w1 C8 v* A4 [% a
( D T1 Q* v4 M2 ~ A# y& i* F- #define MPU_I2CSLV0_DO_REG 0X63 //IIC从机0数据寄存器
* X$ k7 ?4 X: t# r - #define MPU_I2CSLV1_DO_REG 0X64 //IIC从机1数据寄存器* L7 i* F, E" h. f- E4 H
- #define MPU_I2CSLV2_DO_REG 0X65 //IIC从机2数据寄存器5 o" y2 f. ]6 {6 A8 H" U- v6 q' c
- #define MPU_I2CSLV3_DO_REG 0X66 //IIC从机3数据寄存器
6 I7 H3 K8 |- o0 M
/ G' k \- ]7 ]% r- #define MPU_I2CMST_DELAY_REG 0X67 //IIC主机延时管理寄存器- u# k" ^3 [" t& W; H/ m+ t% j
- #define MPU_SIGPATH_RST_REG 0X68 //信号通道复位寄存器0 M" J5 B' C: X
- #define MPU_MDETECT_CTRL_REG 0X69 //运动检测控制寄存器
0 E6 u) j) v# q0 T2 \* B - #define MPU_USER_CTRL_REG 0X6A //用户控制寄存器
) i" P& z+ K6 V3 z: Q - #define MPU_PWR_MGMT1_REG 0X6B //电源管理寄存器1
N' h Q7 O8 W+ N! L3 x - #define MPU_PWR_MGMT2_REG 0X6C //电源管理寄存器2
7 l' D; [ n9 k. s$ r9 M) d/ J - #define MPU_FIFO_CNTH_REG 0X72 //FIFO计数寄存器高八位# C' B0 L5 w0 \% H8 R
- #define MPU_FIFO_CNTL_REG 0X73 //FIFO计数寄存器低八位5 ^8 z+ s6 `# M* v0 I
- #define MPU_FIFO_RW_REG 0X74 //FIFO读写寄存器
6 A4 ~$ Y. h& Q/ c - #define MPU_DEVICE_ID_REG 0X75 //器件ID寄存器
: }: _7 v4 _+ J# u# M; ~
% U' ] F7 M( g) ~2 b; P- ; m$ m! A4 R$ h' z7 f* U
& R/ x" O$ n$ W: S5 A- + j4 f; }- x w
- /* 函数声明 */; c8 I, \1 W! b9 Q: ?" ?
- uint8_t MPU_Read_Byte( uint8_t reg );
( S, I+ |7 Q/ y, h9 D0 k - uint8_t MPU_Write_Byte( uint8_t reg, uint8_t data );8 h' a+ ~7 @9 n* x
- uint8_t MPU_Read_Continue( uint8_t addr, uint8_t reg, uint8_t len, uint8_t *buf );
3 q# l0 @, E" Y2 b9 ]5 J - uint8_t MPU_Write_Continue( uint8_t addr, uint8_t reg, uint8_t len, uint8_t *buf );- e6 P+ M% k) s
) o) C! o5 }6 `- uint8_t MPU_Init( void );' P8 P( N8 R, A% _3 F' a1 s& i
- . u/ i% a5 |, C9 F6 b+ G4 k: e/ V
% V) [, X ]5 k5 [! Z! h- uint8_t MPU_Set_Gyro_Fsr( uint8_t fsr );4 E6 K3 O9 w, D& t; I+ k. G
- uint8_t MPU_Set_Accel_Fsr( uint8_t fsr );
5 l! U) e. w7 ^1 [+ X$ l. P/ ` - uint8_t MPU_Set_LPF( uint16_t lpf );; ?8 H- X9 M. a9 f5 o* N
- uint8_t MPU_Set_Rate( uint16_t rate );) D. P! M: d' a
- short MPU_Get_Temperature( void );! N% B8 s' \9 D( J; U1 U$ I d' k& x
- uint8_t MPU_Get_Gyroscope( short *gx, short *gy, short *gz );
* b; i8 N& y$ B) V- {3 ] - uint8_t MPU_Get_Accelerometer( short *ax, short *ay, short *az );
3 s8 _0 G1 v# N, M- n* A& z$ r# ] - 6 k3 g2 S/ T+ N; O8 G3 q
- #endif
8 n/ r y6 B9 Q$ V
& @! L2 F3 A3 E3 c% k
复制代码 8 G& k: R! O8 m- K
mpu6050.c! T- J3 {# o- r9 k: n
最为重要的一部分代码,包括了对MPU6050的一系列基本配置和读取原始数据的操作,代码都注解的很详细了。
; T) `1 W! ^' r5 ~AD0引脚用了PA15,所以要GPIO_Remap_SWJ_JTAGDisable,换个引脚也可以。. l- @, _( h) U; V
- #ifndef __MPU6050_H% q. y, }+ \- n+ r7 t: n
- #define __MPU6050_H
& F+ P6 W. I4 K( ?. ?- n
4 L. J/ x' J) S4 n0 A- #include "stm32f10x.h"- K" j) ~ n" u- P/ k" A2 Y2 V
- #include "mpu_iic.h"
# s6 G# G" Z2 w) ]& R3 { @! W
8 K0 C* C% ^3 V# j( y8 P: q
& J2 V% ?- Z0 l! g+ g: C- /* AD0接地,MPU6050的IIC地址为0x68 接3.3V就为0x69*/
& b% X) @! A8 U+ h! I+ L - #define MPU_ADDR 0X68; k C W* \: b) U8 A( _: K
" O |; l# w9 @' Q" Y7 e" H- /************** MPU6050相关寄存器地址 *********************/
3 n2 E H- S+ E7 @* h8 b0 } - #define MPU_ACCEL_OFFS_REG 0X06 //accel_offs寄存器,可读取版本号,寄存器手册未提到
! u" e& _' W o - #define MPU_PROD_ID_REG 0X0C //prod id寄存器,在寄存器手册未提到
?$ }7 z4 K, B: c) b- [' { - #define MPU_SELF_TESTX_REG 0X0D //自检寄存器X1 d% ], {% N* m2 b0 l
- #define MPU_SELF_TESTY_REG 0X0E //自检寄存器Y
$ ? B$ \% V& B1 x; T - #define MPU_SELF_TESTZ_REG 0X0F //自检寄存器Z8 r' v! S+ m/ P
- #define MPU_SELF_TESTA_REG 0X10 //自检寄存器A- Q# I0 D/ o. j X- ?
- #define MPU_SAMPLE_RATE_REG 0X19 //采样频率分频器- f1 y/ I8 j. N/ u+ [2 R
- #define MPU_CFG_REG 0X1A //配置寄存器- f; G* u; _4 q: K2 m
- #define MPU_GYRO_CFG_REG 0X1B //陀螺仪配置寄存器2 l3 n# k" z5 t& F9 p' E/ F
- #define MPU_ACCEL_CFG_REG 0X1C //加速度计配置寄存器
' Y- `7 D& S |& R0 s3 y6 k# J - #define MPU_MOTION_DET_REG 0X1F //运动检测阀值设置寄存器5 [& v' O) z5 W8 G9 |
- #define MPU_FIFO_EN_REG 0X23 //FIFO使能寄存器
0 q( [! C% k Q+ F/ v - #define MPU_I2CMST_CTRL_REG 0X24 //IIC主机控制寄存器
) a: E' A i& P0 j# i& h2 G) {. c E' N - #define MPU_I2CSLV0_ADDR_REG 0X25 //IIC从机0器件地址寄存器7 B9 ~1 N' P# X( ]
- #define MPU_I2CSLV0_REG 0X26 //IIC从机0数据地址寄存器
6 e# Z u3 Y4 _$ p - #define MPU_I2CSLV0_CTRL_REG 0X27 //IIC从机0控制寄存器8 o% U8 S. \6 t, H- k. U1 ^
- #define MPU_I2CSLV1_ADDR_REG 0X28 //IIC从机1器件地址寄存器# `! |$ c) z9 _7 |! T0 {
- #define MPU_I2CSLV1_REG 0X29 //IIC从机1数据地址寄存器
- }+ f3 m% s" Q" h& H - #define MPU_I2CSLV1_CTRL_REG 0X2A //IIC从机1控制寄存器' _7 o' u; q' j! |" n% `) W( z$ P
- #define MPU_I2CSLV2_ADDR_REG 0X2B //IIC从机2器件地址寄存器
2 d. P. T; _9 G/ ^) z ?5 M - #define MPU_I2CSLV2_REG 0X2C //IIC从机2数据地址寄存器
8 S( Z2 x3 }! c+ n" ]7 ~ - #define MPU_I2CSLV2_CTRL_REG 0X2D //IIC从机2控制寄存器
! G* k1 S' @2 E2 n8 z6 l& t' \6 | - #define MPU_I2CSLV3_ADDR_REG 0X2E //IIC从机3器件地址寄存器8 H* N2 W! A4 g0 i
- #define MPU_I2CSLV3_REG 0X2F //IIC从机3数据地址寄存器/ h( {5 q! b# @/ v- w
- #define MPU_I2CSLV3_CTRL_REG 0X30 //IIC从机3控制寄存器1 {8 Y. j- A5 I1 d% H
- #define MPU_I2CSLV4_ADDR_REG 0X31 //IIC从机4器件地址寄存器3 p; p5 }1 {0 T) I
- #define MPU_I2CSLV4_REG 0X32 //IIC从机4数据地址寄存器
c) Q. \* [/ e+ L - #define MPU_I2CSLV4_DO_REG 0X33 //IIC从机4写数据寄存器
) W& x" d" ]4 ~8 |" G: H) ]4 ^# L - #define MPU_I2CSLV4_CTRL_REG 0X34 //IIC从机4控制寄存器9 P( s* W- v8 |5 e/ a; ^
- #define MPU_I2CSLV4_DI_REG 0X35 //IIC从机4读数据寄存器
. x: W& |0 t+ s3 Z8 u) c - . e( u. T: u" o! x) E) S, x
- #define MPU_I2CMST_STA_REG 0X36 //IIC主机状态寄存器
' ?( t+ B- A& ?- o1 ~ - #define MPU_INTBP_CFG_REG 0X37 //中断/旁路设置寄存器
- @* l" d7 b; {4 e/ E4 l - #define MPU_INT_EN_REG 0X38 //中断使能寄存器, y# T `0 D. I. T" \. Q
- #define MPU_INT_STA_REG 0X3A //中断状态寄存器
- b$ y5 c% L& c - 8 |: {' B. M) v/ n# J. M
- #define MPU_ACCEL_XOUTH_REG 0X3B //加速度值,X轴高8位寄存器
5 s6 m: d5 q$ T$ Q* Z - #define MPU_ACCEL_XOUTL_REG 0X3C //加速度值,X轴低8位寄存器
6 E2 e% W: y- ~7 H0 ?) c' P; P% o - #define MPU_ACCEL_YOUTH_REG 0X3D //加速度值,Y轴高8位寄存器2 Q6 m1 |* H: a3 s- U% I- _6 O
- #define MPU_ACCEL_YOUTL_REG 0X3E //加速度值,Y轴低8位寄存器' x! V0 n0 q1 Q" ^, x. c4 G, \
- #define MPU_ACCEL_ZOUTH_REG 0X3F //加速度值,Z轴高8位寄存器
3 h6 A1 D3 q9 M$ u, k$ N( C - #define MPU_ACCEL_ZOUTL_REG 0X40 //加速度值,Z轴低8位寄存器1 t5 X* C) F3 w- }5 f2 v; q# W
: i& H0 E) r r. j J- #define MPU_TEMP_OUTH_REG 0X41 //温度值高八位寄存器
+ q6 K2 S6 a+ i+ L1 Q - #define MPU_TEMP_OUTL_REG 0X42 //温度值低8位寄存器
8 ?* h5 U& m. B+ C - * I, k% u" n K+ P- L d
- #define MPU_GYRO_XOUTH_REG 0X43 //陀螺仪值,X轴高8位寄存器& t- Z; i, ?0 j$ ^. _+ S% g1 W
- #define MPU_GYRO_XOUTL_REG 0X44 //陀螺仪值,X轴低8位寄存器
! N E( K1 N, O2 q - #define MPU_GYRO_YOUTH_REG 0X45 //陀螺仪值,Y轴高8位寄存器" q# p0 _2 a2 k$ s" X+ `6 F
- #define MPU_GYRO_YOUTL_REG 0X46 //陀螺仪值,Y轴低8位寄存器
) j+ e2 V. h$ r - #define MPU_GYRO_ZOUTH_REG 0X47 //陀螺仪值,Z轴高8位寄存器0 h# }- |$ h! {* K, o7 I
- #define MPU_GYRO_ZOUTL_REG 0X48 //陀螺仪值,Z轴低8位寄存器
" r8 ]4 t7 K' s2 Z
: r4 t; ^* c) L# t" L, S- #define MPU_I2CSLV0_DO_REG 0X63 //IIC从机0数据寄存器, J6 b. r. x0 S3 T9 @
- #define MPU_I2CSLV1_DO_REG 0X64 //IIC从机1数据寄存器
5 M0 t* G+ O' h3 F# U( l, ]$ @ - #define MPU_I2CSLV2_DO_REG 0X65 //IIC从机2数据寄存器8 u1 m: Z4 t8 ?$ Q% b
- #define MPU_I2CSLV3_DO_REG 0X66 //IIC从机3数据寄存器
0 U$ V4 ]& g- r$ O/ ~
+ o* z% B5 Q: T8 j D2 b) \. ~5 V- #define MPU_I2CMST_DELAY_REG 0X67 //IIC主机延时管理寄存器
2 q' ]8 s |$ q+ D: b b - #define MPU_SIGPATH_RST_REG 0X68 //信号通道复位寄存器
; I" [4 q# ?( r/ E: h1 _0 g0 N2 y - #define MPU_MDETECT_CTRL_REG 0X69 //运动检测控制寄存器
7 \ N: S! s- l9 h& \, v, P - #define MPU_USER_CTRL_REG 0X6A //用户控制寄存器8 _$ ?/ C2 h7 K9 T3 H0 R
- #define MPU_PWR_MGMT1_REG 0X6B //电源管理寄存器19 F I5 t8 N; ?2 B4 p( N" T" k
- #define MPU_PWR_MGMT2_REG 0X6C //电源管理寄存器2 7 W, W( Q# q( x7 h
- #define MPU_FIFO_CNTH_REG 0X72 //FIFO计数寄存器高八位7 D; j- w' ~5 w3 X- h
- #define MPU_FIFO_CNTL_REG 0X73 //FIFO计数寄存器低八位% v: I: s# n S
- #define MPU_FIFO_RW_REG 0X74 //FIFO读写寄存器
0 T0 ?, {/ w; R1 P! d6 {/ u - #define MPU_DEVICE_ID_REG 0X75 //器件ID寄存器
) r, D, B9 L! |: x( U3 k: H
% z0 O+ O1 P$ t4 t- t- . X0 W1 v+ V& y1 G
4 f+ C+ r5 |/ S3 D3 J
/ r. L$ y7 n1 _# u- /* 函数声明 *// v; N b# _ q) y
- uint8_t MPU_Read_Byte( uint8_t reg );' U; _' m& F5 e
- uint8_t MPU_Write_Byte( uint8_t reg, uint8_t data );) \$ a' X) C, }2 h8 r3 N$ X
- uint8_t MPU_Read_Continue( uint8_t addr, uint8_t reg, uint8_t len, uint8_t *buf );( o* R w) V' h+ c$ z& b
- uint8_t MPU_Write_Continue( uint8_t addr, uint8_t reg, uint8_t len, uint8_t *buf );/ u$ K. {4 v# a$ a$ M6 O
- 6 Q# n4 g( D8 X. f& [
- uint8_t MPU_Init( void );
- V: N1 ]7 |$ j4 f' @4 D& i0 K - 7 J @. `! N9 F9 s
% \1 N, V. _0 W+ U- uint8_t MPU_Set_Gyro_Fsr( uint8_t fsr );1 Q7 q5 i$ C+ |4 m# i1 s" L
- uint8_t MPU_Set_Accel_Fsr( uint8_t fsr );- E7 |" K) v2 N6 |
- uint8_t MPU_Set_LPF( uint16_t lpf );' B% g8 _; d5 n$ l
- uint8_t MPU_Set_Rate( uint16_t rate );
$ T* {& N! y% K( O - short MPU_Get_Temperature( void );
, ?! R6 ]# X$ z+ P4 t2 G) w - uint8_t MPU_Get_Gyroscope( short *gx, short *gy, short *gz );" K2 p0 h; ~3 C( H: g9 t, l
- uint8_t MPU_Get_Accelerometer( short *ax, short *ay, short *az );
8 Y. v& @$ K1 p) N( {: d% } - 9 l# [- |* I7 c, M, M
- #endif4 ~" [9 p( e5 N! z( g5 e8 l. b2 a
6 y8 [/ a( [. z6 F
复制代码 ! _; b+ q0 G+ x
4.DMP相关代码6 F4 k# c9 V8 b N" |$ v5 s
要想使用DMP求欧拉角的代码,包含下面这几个文件即可,下面列出接口函数,到时候使用时直接使用接口函数即可。5 c" S* e+ L+ H" E. x6 {: n6 G
x* y6 c$ J; q. v2 s- w- G$ ^' H H
* S) f: ^4 \, E. \; [% |% {3 n& q9 ~' \. o" q3 o' p, B* d- S2 x2 Z
向DMP算法提供的接口宏定义! |% e- n* `3 q% C
只需要提供:对MPU6050的读写操作函数和延时函数即可; D( N4 q, J' s/ m6 u% B
- #define i2c_write MPU_Write_Continue
1 F* e* {: x) ~4 ?$ K3 _) B% g - #define i2c_read MPU_Read_Continue
( ~& B9 A! F" Z/ Z$ q% [% k - #define delay_ms delay_ms+ H/ g1 n; l$ W' a
复制代码
8 O9 {9 `6 E5 Z9 e. mDMP初始化) M: Z$ @/ N6 H: u7 z
- //mpu6050,dmp初始化7 R% ?' P# X, L
- //返回值:0,正常
( x5 J; s( |2 V - // 其他,失败- _1 j; z7 Z- P& u! G0 u/ u0 L) ]
- uint8_t mpu_dmp_init(void)
6 i$ m, S4 A7 V - {6 L# O+ w/ o" \) V8 B) |
- uint8_t res=0;- d a! a, ~/ e8 D6 [0 Z
- MPU_IIC_Init(); //初始化IIC总线
1 `! d) I# d2 G- \6 h - if(mpu_init()==0) //初始化MPU60507 v# R& k* g, t; T5 o( |% ~' r, r( Q
- { 2 {) ]3 L( D3 ]9 j4 O) e% T% l# i' n
- res=mpu_set_sensors(INV_XYZ_GYRO|INV_XYZ_ACCEL);//设置所需要的传感器5 ~/ g6 e5 o3 k2 J
- if(res)return 1; - |+ I( \1 ~ T0 v/ E% Y j+ i
- res=mpu_configure_fifo(INV_XYZ_GYRO|INV_XYZ_ACCEL);//设置FIFO
+ }3 c/ O/ c9 o8 _) T- Q% \ - if(res)return 2; 0 k$ Y' W2 X6 g( t& A
- res=mpu_set_sample_rate(DEFAULT_MPU_HZ); //设置采样率
, b: ~( }5 c- H4 Y - if(res)return 3;
* c# H# Q: C: L* a5 |& m8 @0 N - res=dmp_load_motion_driver_firmware(); //加载dmp固件( h C/ y7 \5 t! J& @/ n) F
- if(res)return 4; & h. G" U; f- X
- res=dmp_set_orientation(inv_orientation_matrix_to_scalar(gyro_orientation));//设置陀螺仪方向% S( J1 s6 Q' Q$ M& \
- if(res)return 5; % m# v6 s( W" j# A+ }
- res=dmp_enable_feature(DMP_FEATURE_6X_LP_QUAT|DMP_FEATURE_TAP| //设置dmp功能
# P7 r% {' P8 L6 J# `: G8 I - DMP_FEATURE_ANDROID_ORIENT|DMP_FEATURE_SEND_RAW_ACCEL|DMP_FEATURE_SEND_CAL_GYRO|
7 D8 O& M$ Q# [/ N6 A { - DMP_FEATURE_GYRO_CAL);
$ z5 R2 H; B) F: X - if(res)return 6; 4 r+ \6 g1 l( c H, y
- res=dmp_set_fifo_rate(DEFAULT_MPU_HZ); //设置DMP输出速率(最大不超过200Hz)' T0 M* `7 |9 x* Q1 [
- if(res)return 7; 6 V9 D. W+ j+ S1 @
- res=run_self_test(); //自检
2 {9 Q, h# C% B m5 F2 n8 w - if(res)return 8; # g3 V( k- f% ^ E; b& N
- res=mpu_set_dmp_state(1); //使能DMP( i: b* A: _8 w2 K, K
- if(res)return 9;
( |8 H/ Q2 C* [' ~! a4 _% p0 n - }else return 10;
: b2 [8 \0 h1 _' u- @0 V - return 0;
. } M' ?' k1 i3 O& } w% u - }7 u+ b; t! ?) A; p6 w1 F. v6 ?
复制代码
2 W' e. T& V4 s获取欧拉角0 p& Q# i) W3 X t6 Z
- //得到dmp处理后的数据(注意,本函数需要比较多堆栈,局部变量有点多)9 F0 G+ s8 D; t8 G8 z+ e- g3 g0 ~
- //pitch:俯仰角 精度:0.1° 范围:-90.0° <---> +90.0°
; \9 ~6 i" g1 f7 c - //roll:横滚角 精度:0.1° 范围:-180.0°<---> +180.0°5 Q- {$ Q6 d/ M
- //yaw:航向角 精度:0.1° 范围:-180.0°<---> +180.0°
/ \6 U/ ` R. U# N - //返回值:0,正常
( D) z7 v. X3 K - // 其他,失败2 n; u& d, l1 C) Q$ X* Z; M
- uint8_t mpu_dmp_get_data(float *pitch,float *roll,float *yaw)
9 K. k; k: q0 T% U0 {0 v - {
* f8 v* G2 p& _" }8 H0 a9 N; s - float q0=1.0f,q1=0.0f,q2=0.0f,q3=0.0f;, d e; _# O) _7 E! n$ s1 u
- unsigned long sensor_timestamp;) J4 H. ?" D! }( E+ u
- short gyro[3], accel[3], sensors;" B9 v5 V I1 W$ c6 F2 Y9 a' U
- unsigned char more;
, E, M. q# a: a. M( t2 \. _- D0 a% j - long quat[4]; 7 x0 b/ w& O$ \
- if(dmp_read_fifo(gyro, accel, quat, &sensor_timestamp, &sensors,&more))return 1;
7 ~! m4 [- _0 L- L1 V @' Q - /* Gyro and accel data are written to the FIFO by the DMP in chip frame and hardware units.
7 q+ W$ Z; r& u" f8 P+ u) Z" Z - * This behavior is convenient because it keeps the gyro and accel outputs of dmp_read_fifo and mpu_read_fifo consistent.
4 s0 H* J. O# F; `1 U - **/; m0 h0 \# E! ~; @, T
- /*if (sensors & INV_XYZ_GYRO ): k: i2 A, U0 I$ L! F
- send_packet(PACKET_TYPE_GYRO, gyro);
; E! v) o# A1 z( N5 |* E% x - if (sensors & INV_XYZ_ACCEL)
2 q }2 H- f. X7 l - send_packet(PACKET_TYPE_ACCEL, accel); */
6 H5 g7 T( ?4 }# _$ O" z - /* Unlike gyro and accel, quaternions are written to the FIFO in the body frame, q30.
% J) a% I% V! f" p - * The orientation is set by the scalar passed to dmp_set_orientation during initialization. / a6 Y+ s7 \0 j* L
- **/# |- K0 m: |4 ^+ d3 H* [0 P
- if(sensors&INV_WXYZ_QUAT) + D3 k+ `- y# y; i' f; r/ j
- {; F; }: o0 x* P) f, }" P4 e; X% a0 t
- q0 = quat[0] / q30; //q30格式转换为浮点数
6 v `% i/ U0 Z' h( ~8 w - q1 = quat[1] / q30;
1 i! _9 e8 T# O. x/ Z% @ - q2 = quat[2] / q30;
/ M, b# t% Z) U# K6 p - q3 = quat[3] / q30; ) ], P9 ?$ v3 ~; ~4 K
- //计算得到俯仰角/横滚角/航向角
$ Q/ A' w, P4 f# U - *pitch = asin(-2 * q1 * q3 + 2 * q0* q2)* 57.3; // pitch/ R0 N, z) @8 E% ]% ]8 o) [ }
- *roll = atan2(2 * q2 * q3 + 2 * q0 * q1, -2 * q1 * q1 - 2 * q2* q2 + 1)* 57.3; // roll. \# e0 [0 R$ F2 f" A
- *yaw = atan2(2*(q1*q2 + q0*q3),q0*q0+q1*q1-q2*q2-q3*q3) * 57.3; //yaw
+ S4 t9 j2 [, v - }else return 2;
, ^/ Q% z+ d7 v8 t2 F - return 0;
% W7 r# v/ s* t) l. n+ P - }
& t1 s4 m3 j$ L, p# V - & X9 a: D# Y3 {( z" W
复制代码 ) ~5 V$ N: A) O7 U
5.mian()函数
# E: w& U* _. P8 a/ p主函数中对MPU6050进行初始化后,对DMP也进行初始化,然后就可以直接使用mpu_dmp_get_data()获取欧拉角,还可以获取温度值。
& U8 [- k. a* E( s @* k, s- #include "stm32f10x.h"
9 v0 A l4 Z0 ~7 p$ l - #include "usart.h"
1 y* p; `1 \8 Q - #include "delay.h"6 m7 c ]& l% R. y
- #include "mpu6050.h"
: R7 q1 D$ L4 r2 } - #include "inv_mpu.h"2 J( e' P* j3 b
- #include "inv_mpu_dmp_motion_driver.h"
4 n0 @3 H; b( i4 _9 o# a - & q2 Y$ ?. l6 w5 B. x/ @6 R$ G, w) h
- int main(void)# ]' H. m1 e0 x1 t$ I4 ]
- {! g4 T8 {+ t8 ]* ?9 t7 C
- uint8_t x=0;! Q$ n, |. h4 H. P4 _, Y3 N6 G: y
- float pitch,roll,yaw; //欧拉角
( u2 b9 @3 P- [, u - short aacx,aacy,aacz; //加速度传感器原始数据9 z8 }1 H8 S$ ?. }3 _% d8 n) b
- short gyrox,gyroy,gyroz; //陀螺仪原始数据
; U/ E, C* X' ?) X+ R" d8 b: [ - short temp; //温度) q+ ]1 v( G7 q2 O- Q8 v& Z
-
- b* Z4 Z' |: Z3 _/ Q4 ? - NVIC_PriorityGroupConfig( 2 );
: A2 R% J9 c7 v. K7 j - delay_init();
' ?7 u$ |0 g( F5 ^7 O* y: k$ z - USART1_Init(115200); $ Q( A$ v' Q" s" A( B7 Y
- printf("程序开始\n");: o/ X. U% n% {7 ~, I4 Z: l
-
5 g! H% _" i: h. y1 O! F1 h z - if( MPU_Init()!=0 )
' G# t8 c& _3 K2 R" d4 ]# T: Y7 x* P - {
3 \- v- B! W* y; r - printf("MPU6050初始化错误!\n");
/ q+ n q, g8 H. \+ J6 D - return 0;
: B5 j5 k4 Q. q" r( S - }
1 m$ G, i3 B) P( X( d* C2 L0 o, m: Q - ' M8 W6 G7 J( m- |( X4 O
- if( mpu_dmp_init() )0 a, M$ s5 b, Y" U; [4 i4 h) F
- {
+ x5 R. a+ w0 n1 h" ~! X" E; _ - printf("DMP初始化错误!\n");
" ?2 q6 z( P4 b M2 ]/ u I8 I - return 0;0 O2 E0 |; [# z( B/ F. B8 N
- }
! ~( d0 ~' q# M9 |1 X - while(1)# Z0 z1 @9 p9 k$ l9 p
- {
Z* U- K& m+ i; O+ T - if(mpu_dmp_get_data(&pitch,&roll,&yaw)==0)# v8 B& r& I8 B- t5 Q$ s
- { / O0 p8 y% O& a1 [
- temp=MPU_Get_Temperature(); //得到温度值7 ?* s0 y* M4 Y( s6 _) Q# Q
- MPU_Get_Accelerometer(&aacx,&aacy,&aacz); //得到加速度传感器数据- }# P/ G" h3 V9 _8 s
- MPU_Get_Gyroscope(&gyrox,&gyroy,&gyroz); //得到陀螺仪数据& w: }. U/ U/ S- H) h( h) o" M8 Y
- }
, q) \# N( V# [3 [. J: y* e - delay_ms(100);
2 [- U5 A; M- u$ \' @ - printf("pitch:%02f roll:%02f yaw:%02f\n",pitch,roll,yaw);9 y" ]6 w: o! F- Q& S" R0 h
- }
! [! _6 T5 t: T2 Y
* |5 r8 B5 r* A9 r& C3 A- }
) O2 A# _5 z r6 K
复制代码 - e4 N3 P( S2 `) n: V: N
这就是我理解的MPU6050,后续做平衡小车的时候要读取欧拉角,先总结一下
8 p* K5 Z! T. s% z3 H————————————————1 N* e) B k: F$ n: b
版权声明:Aspirant-GQ( a0 C# P$ Q8 w7 ^
如有侵权请联系删除
+ b5 d7 Y& @( ?1 |1 Y$ |
9 T5 R" r: c: m
1 ^% T* u7 B' H |