主要内容:
& A3 S9 o% p7 q9 q1 t1)MPU6050简介;
# `* I, v9 Q5 ^. D! z* J" j2)MPU6050相关寄存器介绍;$ h6 t" n! }4 T# _, j
3)相关实验代码解读(除了案例可实现的功能外,主函数增加了在LCD屏上显示6轴的原始数据(含正负号)的功能)。& D( ?% C! v% e5 B
, ]# Y4 e5 \! m* c一、什么是MPU6050?
: l" G' C/ U8 g' D' Z# S0 V2 d) C; ?MPU6050是InvenSense公司推出的全球首款整合性6轴运动处理组件,内带3轴陀螺仪和3轴加速度传感器,并且含有一个第二IIC接口,可用于连接外部磁力传感器,利用自带数字运动处理器(DMP: Digital Motion Processor)硬件加速引擎,通过主IIC接口,可以向应用端输出完整的9轴姿态融合演算数据。* m( a- ~: l+ c- x. j
$ J% r! B4 B3 e8 [! ^/ X; f6 o二、MPU6050特点* E( K$ v6 W0 T6 r9 C; \8 Q7 Y
1)自带数字运动处理(DMP: Digital Motion Processing),输出6轴或9轴(需外接磁传感器)姿态解算数据;$ |3 q. E9 j. L0 O4 C* J" C
2)集成可程序控制,测量范围为±250、±500、±1000与±2000°/sec 的3轴角速度感测器(陀螺仪);
2 z1 z; `% \6 ~3 K; L9 @3)集成可程序控制,范围为±2g、±4g、±8g和±16g的3轴加速度传感器;% u- M* p3 q% H/ P O
4)自带数字温度传感器;+ q1 j$ G6 _7 D/ T5 n
5)可输出中断(interrupt),支持姿势识别、摇摄、画面放大缩小、滚动、快速下降中断、high-G中断、零动作感应、触击感应、摇动感应功能;/ E% n; d) H. z" c1 ]
6)自带1024字节FIFO,有助于降低系统功耗;
3 w) v; f+ e. `( L7)高达400Khz的IIC通信接口;
# w) W" I5 j- V) P1 h8)超小封装尺寸:4x4x0.9mm(QFN)。
5 X3 Z+ ` ^3 T2 b0 `) I" `1 K$ i7 Y, z
三、MPU6050框图
* o6 [7 h9 U9 G+ W+ [, \
3 a7 m W+ ]: T; CAD0=0对应器件物理地址=0X68
5 n! I0 `# b- x& P2 x2 O: f( b* T; bAD0=1对应器件物理地址=0X69
, t4 R+ n+ p# j7 x) i- y6 |
0 H/ C# M3 |2 o* m四、MPU6050初始化
1 H# K0 F6 ^$ L( z3 u9 L8 w( q1)初始化IIC接口;' i3 G! T* M' x" M
2)复位MPU6050,由电源管理寄存器1(0X6B)控制;1 W( |4 j% D# }$ y0 f$ j* Z
3)设置角速度和加速度传感器的满量程范围,由陀螺仪配置寄存器(0X1B)和加速度传感器配置寄存器(0X1C)设置 ;
$ W/ B) |, H( Z5 x" h4)设置其他参数:
6 w+ }7 H3 P* r5 i设置中断,由中断使能寄存器(0X38)控制;( D$ a1 H; U9 w2 r+ h; [. F w
设置AUX IIC接口,由户控制寄存器(0X6A)控制;' z: Q T" y* ~# D+ S; @
设置FIFO,由FIFO使能寄存器(0X23)控制;6 Z5 t' q0 I* i! _
设置陀螺仪采样率 ,由采样率分频寄存器(0X19)控制;
0 p& ?. X, }; K设置数字低通滤波器,由配置寄存器(0X1A)控制;
& i6 B8 ?5 Q- a3 n7 S0 v6 X- h5)设置系统时钟。由电源管理寄存器1(0X6B)控制。一般选择x轴陀螺PLL作为时钟源,以获得更高精度的时钟;
+ I8 i, Y) @' P6 J6 w$ K6)使能角速度传感器(陀螺仪)和加速度传感器。由电源管理寄存器2(0X6C)控制。 X8 g! D. k* ~) S% h
初始化完成后,即可读取陀螺仪、加速度传感器和温度传感器的数据了!!5 I% o2 c9 c* i. {6 Q
. y9 b, l# G" n五、主要的寄存器介绍
! E4 y6 D( ` h5.1)电源管理寄存器1(0X6B)/ d/ q) _9 z. J z p
/ F) Q7 O) ]! d! x5 V- E
& R( [ K: C; \2 j
- p( W6 q8 q2 c: B$ C7 {2 c \% Y
DEVICE_RESE=1,复位MPU6050,复位完成后,自动清零;
7 _( J( A9 l+ v% f6 ySLEEP=1,进入睡眠模式;SLEEP=0,正常工作模式;
: O$ I9 K( U, v* {; e/ c$ pTEMP_DIS,用于设置是否使能温度传感器,设置为0,则使能;& U( _/ {4 v8 ~/ {5 h6 G; k+ D
CLKSEL[2:0],用于选择系统时钟源,如下表所示:
6 I5 J3 P+ g2 B6 K4 v: v
5 M, s% T$ h+ I8 t
6 V1 j$ U, Q0 |' y: F7 d
- K4 K( ]: l* G0 R5.2)陀螺仪配置寄存器(0X1B). P+ v1 w3 s% b3 F( ^5 l9 G$ a2 ^
5 A$ K6 O; K3 X8 b* w0 ]6 q' q8 `
! d) t3 ?, K+ }; Z4 Z9 P% L7 P
8 e6 h& h' C5 R1 w主要关注FS_SEL[1:0]这两个位,用于设置陀螺仪的满量程范围:+ d. {" Z6 J0 n8 U2 f
0,±250°/S;1,±500°/S;2,±1000°/S;3,±2000°/S;
! w) I' J2 w0 ]一般设置为3,即±2000°/S,因为陀螺仪的ADC为16位分辨率,所以灵敏度为:65536/4000=16.4LSB/(°/S)。' s- s' E! j2 t
- w8 a( E/ \* {. P
5.3)加速度传感器配置寄存器(0X1C)5 m* S L* v$ ^8 q, {( `
. ` t6 [ ?' G# e$ ~# f
9 c( S4 g3 m" b. q; Q) {
) N6 Z& |4 a7 v主要关注AFS_SEL[1:0]这两个位,用于设置加速度传感器的满量程范围:
+ Y: U- H1 F0 Q) [9 g0,±2g;1,±4g;2,±8g;3,±16g;- p8 c- @8 |4 g7 I0 m" v
一般设置为0,即±2g,因为加速度传感器的ADC是16位,所以灵敏度为:65536/4=16384LSB/g。
" D. j. f+ A/ ]0 J9 ~, _3 g4 U) I _3 M# m! N5 D: L2 o' R
5.4)FIFO使能寄存器(0X23). D' ^' j9 ^; S3 p O6 q
# u, c/ W7 Y1 g; [$ C
. j7 ]$ l1 R# O/ U( E: Y. n; y! H0 \
该寄存器用于控制FIFO使能,在简单读取传感器数据的时候,可以不用FIFO,设置对应位为:0,即可禁止FIFO,设置为1,则使能FIFO。6 b: t* Y7 M' Y( c
注意:加速度传感器的3个轴,全由1个位(ACCEL_FIFO_EN)控制,只要该位置1,则加速度传感器的三个通道都开启FIFO了。& a# W8 j# K; k0 I# g* K/ O
- M- h, f" U7 P2 Z
5.5)陀螺仪采样率分频寄存器(0X19)
$ [ i0 \! `3 @4 k7 S
- k6 L+ S+ W/ \" t
4 Q) ~. h9 i9 c' O4 P
r6 r2 ~+ h$ n该寄存器用于设置MPU6050的陀螺仪采样频率,计算公式为:
$ T9 X- D: ~* J采样频率 = 陀螺仪输出频率 / (1+SMPLRT_DIV)2 U- J0 h+ V1 b) N( o% K
这里陀螺仪的输出频率,是1Khz或者8Khz,与数字低通滤波器(DLPF)的设置有关,当DLPF_CFG=0或7的时候,频率为8Khz,其他情况是1Khz。而且DLPF滤波频率一般设置为采样率的一半。采样率,我们假定设置为50Hz,那么:SMPLRT_DIV=1000/50-1=19。/ [) J9 A) f5 x
0 A$ _7 J, p, d; c9 T" |/ n5.6)配置寄存器(0X1A)
) M( o1 q6 Q; S8 {: F
2 Q0 Q' q" B: R# \# V; e6 B7 t
" m( {1 h' Y& \6 H
8 S. Q; O" g! ?$ W: d) b! N/ {1 ?4 ?重点看数字低通滤波器(DLPF)的设置位:DLPF_CFG[2:0],加速度计和陀螺仪,都是根据这三个位的配置进行过滤的,如下表所示:
6 r: A5 ?6 R! ]/ Z. g! |# A+ ^
6 U0 ], _! ~; }8 p: w7 e3 N- a. d( d! D& N+ Y. p
备注:带宽=1/2采样率6 }9 O/ Q8 L0 r8 u, A: O* y
3 Q( W$ J6 z' i+ G
5.7)电源管理寄存器2(0X6C)
( C1 v9 _) I; B0 m0 H4 x
7 Y7 G1 N( K8 K0 Z# q
4 q/ D [0 i$ P+ ^2 ]7 M4 Q
& d! M) r/ {4 C2 w/ q! _" o, K该寄存器的LP_WAKE_CTRL用于控制低功耗时的唤醒频率;
% W S" p- Y1 V/ r4 b, F% V剩下的6位,分别控制加速度和陀螺仪的x/y/z轴是否进入待机模式;2 q' |8 Y: v; u3 b7 |) C$ b$ u
本例程全部设置为:0 ,即可。
/ \. O V" R: d% e! M2 S6 H8 I
5.8)加速度传感器数据输出寄存器(0X3B~0X40)
1 F% i/ \* H. G' \
* w) V% k6 ]' `6 Y1 A
/ P3 Q$ ^9 Q1 V1 n
q3 h. X# A2 D# G' Y总共由6个寄存器组成,输出X/Y/Z三个轴的加速度传感器值,高字节在前,低字节在后。+ V9 j6 |5 H1 x, J" H
$ y4 b; j ~: `. X B/ O5.9)陀螺仪数据输出寄存器(0X43~0X48), M7 @+ R: f8 {- K' n# T+ w' G; o
; V& b& N0 H% Z |
" ~/ G5 \2 k& v+ K F
2 Z+ K; I% q6 g总共由6个寄存器组成,输出X/Y/Z三个轴的陀螺仪传感器数据,高字节在前,低字节在后。, _( H9 m8 h3 ^% \- _+ o
1 t0 i% h" ], ?) u D# s5.10)温度传感器数据输出寄存器(0X41~0X42)
) K3 k" V- J0 O$ z1 ?& ~3 c1 e0 x' W; `& o+ y6 o; w" A |. X
# |& @& \, q* G/ d( [6 x5 I+ }! D' k9 |! |
通过读取0X41(高8位)和0X42(低8位)寄存器得到,温度换算公式为:
* @8 R* d$ `+ N% E! z2 i. Q$ WTemperature = 36.53 +regval/340$ ?6 T! s$ w0 I R. g, t
其中,Temperature为计算得到的温度值,单位为℃,regval为从0X41和0X42读到的温度传感器值。
; R5 K. h2 I. c
1 ]' L+ I: V1 E# i六、DMP使用介绍
a/ v# g( J4 O实际使用时(比如做四轴),我们更希望得到姿态数据,即欧拉角:航向角(yaw)、横滚角(roll)和俯仰角(pitch)。/ j3 o* h2 C3 Z* m: l+ ^
要利用原始数据,需要进行姿态融合解算。MPU6050自带数字运动处理器,即DMP,并且InvenSense提供了一个MPU6050的嵌入式运动驱动库,结合MPU6050的DMP,可以基于原始数据直接转换成四元数输出,而得到四元数之后,便可很方便的计算出欧拉角,从而得到yaw、roll和pitch。
( f& K$ h0 X4 T& g3 G- z5 w备注:InvenSense提供的MPU6050运动驱动库是基于MSP430的,需要将其移植后才可以用到STM32上面。6 Q, W) j) C) O3 {/ D7 ~3 S a
: v9 s3 s- B+ I) L# ]移植细节:3 j- n$ J, v5 N: ]+ E1 F R
官方DMP驱动库移植,主要是实现这4个函数:i2c_write、i2c_read、delay_ms和get_ms。
/ _. ~) p5 ^8 R- ^3 m& |' ?移植后的驱动代码如下图:
9 _; Q: y$ P7 ?! Q6 Y# I" b( t! g' I$ R* Q1 t
0 `6 M# i7 r# T) w) o+ \# F7 R9 l7 \& ]
MPU6050 DMP输出的是姿态解算后的四元数,采用q30格式,即2的30次方,要得到欧拉角,需要做一个转换,代码如下:. C2 H. T, T6 k( X9 V& ~4 p; a4 J
% `( x) h% E7 ?- t- q0=quat[0] / q30; // q30格式转换为浮点数
, Z- R2 F* O; G% }. r0 ^" _& F$ | - q1=quat[1] / q30; // q30格式转换为浮点数/ n, M. n8 C; p3 K; X* L% y) B! |
- q2=quat[2] / q30; // q30格式转换为浮点数
" v4 w4 G% }/ Y6 [3 l6 z - q3=quat[3] / q30; // q30格式转换为浮点数
P: Z& k+ P m3 m - // 计算得到俯仰角/横滚角/航向角# x. p. ?- x I5 n* R6 s
- pitch=asin(-2 * q1 * q3 +2 * q0* q2)* 57.3; // 俯仰角
- v' R! r9 M$ [4 L( H - roll=atan2(2 * q2 * q3 +2 * q0 * q1, -2 * q1 * q1 - 2 * q2* q2 + 1)* 57.3; // 横滚角yaw=atan2(2*(q1*q2 +
3 ]6 ? a5 d" X# l9 u( R - q0*q3),q0*q0+q1*q1-q2*q2-q3*q3) * 57.3; // 航向角
复制代码
2 c7 p5 Y% Z2 K5 s2 h上述代码中:quat[0]~quat[3]:是MPU6050的DMP解算后的四元数,q30格式; q30:是一个常量:1073741824,即2的30次方; 57.3:是弧度转换为角度,即180/π,这样结果就是以度(°)为单位的。* x' r% I& d% t& r% x5 @, o: f
y- B& [! J4 E2 g/ W: m七、ATK-MPU6050模块0 T0 {- l% {# u/ g
ATK-MPU6050模块主要由MPU-6050芯片和RT9193-33芯片组成,原理图如下图所示:
8 ?/ w7 S& J8 I' w/ A
( G- S |1 y; M3 D+ [
8 q+ S3 @2 H# b( V
, \$ u; c2 d: s0 M' ^ s$ f
开发板通过ATK-MODULE接口外接MPU6050模块,硬件连接原理图如下:& s b0 \2 c5 C) D) a) b
8 w4 m4 ~6 ^1 D+ F9 ~! Q- S
( X' a. ^- r; Z& A4 Y# Y# I# n
5 L! V; X1 B* c' n4 \) ~6 C1 F- {八、重点关注的相关代码# E% p( h$ g6 A5 U/ ]: x ?
8.1)MPU-6050驱动代码% B. v. w3 x; m) j2 n- {
1,MPU6050 IIC接口驱动代码
$ V' B, s2 m9 J5 F0 H, h2,MPU_Init函数/ S2 d: U9 z- `% S9 N
3,MPU_Get_Gyroscope函数; S1 O( u+ Y6 o% L3 J/ ^
4,MPU_Get_Accelerometer函数
$ `$ e V5 c" A7 |% A3 t$ O5,MPU_Get_Temperature函数2 ]% S6 C; c1 b' g+ H6 `
8.2)DMP驱动代码& C8 L2 O" g! S5 L" C
1,DMP移植相关代码
3 E4 s- y3 ?- D( xi2c_write、i2c_read、delay_ms和get_ms." ]! i6 g) @+ s8 ]
2, mpu_dmp_init函数
# o+ K- F3 W* R$ l+ p3, mpu_dmp_get_data函数
; |; E0 O) I8 D( j, W
/ F8 y5 t& o Y- t九、MPU6050读写时序
1 \8 _) ` x4 @0 C: w- b- B; T9.1)单字节写入时序6 ?8 y) x+ R# X, n
' l; |4 Y7 g7 j' Z
) ?7 q! U" S0 Z1 }! R# J
% k, \, \8 h. ]: ?% l: [
9.2)连续写入时序5 y' Z, G9 a) q- i$ L0 n
. u+ W% }0 p) M4 p1 @
$ |9 N; ]1 R9 j. ~( z
3 d, y3 l( m: A s9.3)单字节读出时序
' C/ U7 H6 i0 F6 r3 g& t' C z" O3 `% q. W
- P0 E+ O: y1 F
" B _+ }. |, c9.4)连续读出时序
, }. H' h: v6 ]( k1 \% t0 t- K% T" L" s! H6 }, F
9 A' K0 e) M8 @- f. F3 }
# B7 |% q) U5 E: I3 }5 k: h
十、部分实验代码解读
5 A) L7 C6 W$ ?- K( a1 w10.1 mpuiic.h头文件函数6 ?/ n4 _$ p( E" v9 B) d
, X; t. H2 ]4 ^. o8 I- /**% p8 P* r. T( d5 T; T
- ******************************** STM32F10x *********************************
5 l2 A2 m" ]1 o6 ` - * @文件名称: mpuiic.h
2 R7 w. p$ p/ I; r, d - * @修改作者: Aaron
- ]; Y+ ?1 i/ p5 T% d. K0 F - * @库版本号: V3.5.0$ m+ b! }) w" m7 {7 [
- * @工程版本: V1.0.0* C# ^) `8 W7 w C R/ Y) g/ g! i
- * @开发日期: 2020年11月30日
- H, Q7 Z6 S f2 a. n4 @1 y - * @摘要简述: mpuiic头文件,主要跟MPU-6050模块进行IIC通讯时用
1 W* o' t) m5 x. X" v b - ******************************************************************************/. b: ^9 i/ h) P6 H1 q9 }
- /*-----------------------------------------------------------------------------
5 Q X _. `1 i% k R2 N( o$ v8 ? - * @更新日志:6 g$ e- C$ y4 d6 D
- * @无5 H% x% {. f9 T: ^$ ]
- * ---------------------------------------------------------------------------*/- H/ h& l) Q3 S( R5 j4 l
- #ifndef __MPUIIC_H
, ?+ i! L/ z$ C/ y" a - #define __MPUIIC_H& c* E T7 W! ?' w% c
- /* 包含的头文件 --------------------------------------------------------------*/; c8 t6 h, ^6 Y6 Y- ]9 t
- #include "sys.h"
7 N$ P0 L% }. M, c* \' _ - #include "stm32f10x.h"
7 Z* ]. N$ b+ D, h1 e; D% @. n2 W4 s: A - /* 寄存器方法控制GPIO管脚输入输出模式 ----------------------------------------*/
& D4 R' f% ?, ], \/ E' X3 y7 W5 A8 l. q - #define MPU_SDA_IN() {GPIOB->CRH&=0XFFFF0FFF;GPIOB->CRH|=8<<12;} // PB11 上拉输入模式
4 V: |, Y |5 V! X5 B8 m - #define MPU_SDA_OUT() {GPIOB->CRH&=0XFFFF0FFF;GPIOB->CRH|=3<<12;} // PB11 通用推挽输出模式,50MHz
3 b5 E+ o6 { v5 @1 y# m* D - /* 位操作方法定义 ------------------------------------------------------------*/
+ X* w1 S/ g1 Q, q$ @ - #define MPU_IIC_SCL PBout(10) // PB10对应SCL
% v& E" H1 D: j/ i' O8 w; n& r - #define MPU_IIC_SDA PBout(11) // PB11对应SDA,输出SDA
) v+ C" k+ k& e - #define MPU_READ_SDA PBin(11) // PB11对应SDA,输入SDA" w( s2 T) n5 H5 j" r/ e
- /* 定义IIC底层驱动程序 -------------------------------------------------------*/
1 m# @2 n! s6 w7 e - void MPU_IIC_Delay(void); // MPU IIC延时函数,延时 2 us
8 @3 j7 {$ m( L' y5 h. D - void MPU_IIC_Init(void); // 初始化IIC的IO口- P) Q# P8 o4 `7 [0 j
- void MPU_IIC_Start(void); // 发送IIC开始信号 ~+ m: Y+ V' A6 A: D: e4 X
- void MPU_IIC_Stop(void); // 发送IIC停止信号
& h6 i: w6 w- V6 O* u% \' u A - u8 MPU_IIC_Wait_Ack(void); // IIC等待ACK信号' u* B3 f) k) s6 w; e1 Q& q
- void MPU_IIC_Ack(void); // IIC发送ACK信号
* x+ e w5 _# \7 k$ H5 ~ R& a - void MPU_IIC_NAck(void); // IIC不发送ACK信号
. C- \9 c% w& B# p+ H - void MPU_IIC_Send_Byte(u8 txd); // IIC发送一个字节% G) I; [) X! c" G6 j. G
- u8 MPU_IIC_Read_Byte(unsigned char ack); // IIC读取一个字节
7 Y j; x: n. t+ i6 k: G j! q - #endif /* __MPUIIC_H */
3 B& m9 t0 p# ^ - /****** Copyright (C)2020 Aaron. All Rights Reserved ****** END OF FILE *******/
复制代码
" u+ Z/ `0 V( W, H& F0 c10.2 mpuiic.c源文件函数5 c# o. A" h: C: |4 a Z
! l" v5 Y/ N" M3 {4 _- r+ w- /**4 J. U- g( y7 Q% j/ N& w, f5 `4 a- F% w- U
- ******************************** STM32F10x *********************************0 u; m0 h3 n$ Q; j
- * @文件名称: mpuiic.c, w( Y8 E3 p Y, l4 {
- * @修改作者: Aaron
! \' i/ U ^: b, d% ` - * @库版本号: V3.5.0
) S$ i) f* l9 Z/ K4 I M- C - * @工程版本: V1.0.0
3 }; o; K7 E5 s: C2 t5 [ - * @开发日期: 2020年11月30日$ M6 s$ D; U9 r' ~8 @: z8 `
- * @摘要简述: mpuiic源文件,主要包含与MPU-6050进行IIC通讯的IIC底层驱动程序' \' r+ n+ |1 \3 x7 Q+ d& m; O/ R
- ******************************************************************************/; e0 S! P7 C+ h! ?6 d8 ^
- /*-----------------------------------------------------------------------------( O" h+ O" Y) l3 L* r
- * @更新日志:
0 |% g; [/ z! x) v4 g% E& g - * @无6 ]5 C+ o1 z" C4 f# t. O: a
- * ---------------------------------------------------------------------------*/8 g; r5 E' d% R0 d8 Y9 j9 M
- /* 包含的头文件 --------------------------------------------------------------*/
# p3 `' l I8 }% s' J0 k - #include "mpuiic.h"( a% b7 [8 |# N/ G
- #include "delay.h" r, g3 Z8 M3 f0 y! Y% A$ R* `
- /*********************************************************************
! s+ ?+ B$ K; b0 T7 u0 t. X - 函数名称:MPU_IIC_Delay()( D h8 b9 z0 ], w+ o! V
- 函数功能:延时函数,延时2微秒(us)6 E3 ^0 o( i4 ~0 X. W2 e7 ?
- 入口参数:无
. n$ M; v1 S# K8 m: H1 e3 R - 返回参数:无; Z6 t, f8 o+ `, r* V
- 修改开发:Aaron0 O6 P: j& Y7 ^# f7 v0 l
- **********************************************************************/
$ D: K" i9 h$ K" o, \ - void MPU_IIC_Delay(void)( C3 N; B- L* v/ U: ~
- {
4 E& a( W7 Z: @# d/ k - delay_us(2);
4 c- {/ b/ A6 M% L# w- M+ o4 G$ Y - }
3 V. z' P2 d, ]7 x B8 ` b, L- K - /*********************************************************************
0 b3 F4 }7 P! s$ T3 L' ~- m1 E - 函数名称:MPU_IIC_Init()* [+ ]! q; n+ b. G# } O4 l
- 函数功能:MPU_IIC管脚初始化配置5 j& Z7 N4 V8 U. |+ y
- 入口参数:无. l* |) m% i- \9 B1 b# D
- 返回参数:无
9 u( f: ~) E0 Y( i" Z w - 修改作者:Aaron. H# j v2 z. B- p, B
- **********************************************************************/
) F2 H1 }; ~2 d$ I) ]' P2 q - void MPU_IIC_Init(void)# i/ m% Z0 `& y/ B- W
- {
- W g( k$ U9 F - GPIO_InitTypeDef GPIO_InitStructure;
1 B' P1 L2 e9 b) u( ^8 ^ - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); // 使能外设IO PORTB时钟
2 \6 F: m! K1 B& o - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11; // 端口配置,管脚10和管脚11
" t0 r% X2 [( @1 W, {% U& f# { - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出& j9 I1 \* e0 v* x& O
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // IO口速度为50MHz
0 `! H6 Z( n+ b+ b/ n5 T - GPIO_Init(GPIOB, &GPIO_InitStructure); ) W' h6 m$ l* F/ L9 x$ G5 P4 D- o
- GPIO_SetBits(GPIOB,GPIO_Pin_10|GPIO_Pin_11); // PB10(SCL),PB11(SDA) 输出高
4 P/ V9 z( b" h - }. {. h4 N0 ^( y5 r; I0 d/ O0 U
- /*********************************************************************7 c* Y' S" w9 G, w; B; U+ p& p0 g
- 函数名称:MPU_IIC_Start()
, K$ h& l2 J6 ~3 H) u( s - 函数功能:MPU_IIC起始信号
+ J# {! T) t3 l& \ - 入口参数:无+ e% t; }8 U5 T3 [2 y
- 返回参数:无
: b5 E$ F# n6 t/ e - 修改作者:Aaron
' W; O- _' r2 r e - **********************************************************************/
9 B2 D/ H* \5 s6 J - void MPU_IIC_Start(void)) F8 ]8 Y6 \; ~! l/ b" U
- {" C# o2 M/ s: `* { W# p: r
- MPU_SDA_OUT(); // SDA线输出模式3 c( c/ H1 V* f4 N# i0 M
- MPU_IIC_SDA=1; // SDA输出高
. o$ ?. f$ j4 Y3 ]- t+ H) |: z - MPU_IIC_SCL=1; // SCL输出高,此时为空闲状态/ ~, K3 b3 J B9 y
- MPU_IIC_Delay(); // 延迟 2 us5 b3 A' j+ B. ]
- MPU_IIC_SDA=0; // 在SCL输出高的状态下,SDA由高至低跳变,IIC开始
: E; A+ ]0 ?9 M7 U - MPU_IIC_Delay(); // 延迟 2 us
* @3 u1 A9 T: E5 I3 z& h5 X - MPU_IIC_SCL=0; // 钳住I2C总线,准备发送或接收数据
) Y- k: c" ?0 a. {! A1 N - }
9 e. \/ n/ n' { e/ \0 B - /*********************************************************************
* O4 W Z5 G) H9 x E3 ], t - 函数名称:MPU_IIC_Stop()
0 ^ R. B1 K" } - 函数功能:MPU_IIC停止信号
+ h) C( t6 c' W3 U9 h6 e; L( | - 入口参数:无
, U; @8 S+ j/ q o - 返回参数:无
; s3 o5 ?+ o3 d1 c4 Q - 修改作者:Aaron
5 i% \" K4 d$ ]) ] - **********************************************************************// W8 W8 a) [" N( Y" w; N
- void MPU_IIC_Stop(void)
) V, ~' t) E/ S3 y- P" K" q - {
3 d9 R4 @$ e" e" p8 P - MPU_SDA_OUT(); // SDA线输出模式9 u' a; t# r7 Z0 V
- MPU_IIC_SCL=0; // SCL输出低" X( a1 Z8 \) o" P, v4 ], P& k5 F
- MPU_IIC_SDA=0; // SDA输出低 c1 c8 k# d6 L3 c! a% l8 V) R
- MPU_IIC_Delay(); // 延迟 2 us# o J2 _* ^0 F
- MPU_IIC_SCL=1; // 先SCL输出高,在SCL输出高的状态下,SDA一直是低电平# s/ U4 _& _/ _" c5 d
- MPU_IIC_SDA=1; // SDA输出高,发送I2C总线结束信号
1 d# g! y; Y0 S+ a; @ - MPU_IIC_Delay(); // 延迟 2 us 1 h2 k! b) ], J f7 @1 w: g3 Z
- }
1 k$ W( m1 D9 |6 ^ - /*********************************************************************3 m" J) B0 w( @4 ~( a+ a: e
- 函数名称:u8 MPU_IIC_Wait_Ack()3 a+ W' p8 G7 S# y/ f$ n+ U
- 函数功能:等待应答信号到来# M! n9 i0 y" B: W, B
- 入口参数:无; Z9 W: Y f- Z, h9 B6 |6 x4 k
- 返回参数:u8,1,接收应答失败,0,接收应答成功( [9 [# [7 g1 L8 t6 J3 S+ a
- 修改作者:Aaron
3 n |0 P% t( @( H - **********************************************************************/
$ V6 r1 N+ P w- @! C# J - u8 MPU_IIC_Wait_Ack(void)% i" O2 ^0 `3 N( a/ w( K ]$ \
- {, @, P2 y1 k( S2 `. v9 o, b# G
- u8 ucErrTime=0;# Y) v0 p+ j; g' |) b
- MPU_SDA_IN(); // SDA设置为输入 , c+ c7 o; A; s
- MPU_IIC_SDA=1; // SDA设高电平
2 G: O3 S# V* o3 E - MPU_IIC_Delay(); // 延迟 2 us
) v" Z g0 Z" c" Y7 Z4 w - MPU_IIC_SCL=1; // SCL设高电平
9 L7 _; \2 y9 X6 y& ^8 u - MPU_IIC_Delay(); // 延迟 2 us + k8 _; L! M9 E1 I5 |# p' h
- while(MPU_READ_SDA) // 读取PB11的值,一直读PB11=1,高电平,则不断循环,直到溢出; l) K! M/ t) b3 r
- {, f2 e) f% D1 n% S; @7 y
- ucErrTime++;
, _5 X, Z' H$ y8 @/ v - if(ucErrTime>250)- @- ^9 E# E5 D7 j
- {
3 t% B0 I% \5 }$ U! [* [! X6 T - MPU_IIC_Stop();
, w3 e7 `( z4 ?6 o9 S - return 1;
, y1 r6 n W( T* ] - }
1 S! x; }. [4 b+ D/ Y - }4 ?4 [9 `+ ]) E" H: l
- MPU_IIC_SCL=0; // SCL设低电平 5 {# R, x% @/ D" W( x
- return 0; + A+ {# z: ~8 r
- }
+ t2 w5 A' `2 l0 ] - /*********************************************************************
7 R4 k( o, o/ x1 j+ b* s9 D/ s - 函数名称:MPU_IIC_Ack()* d3 n- K4 a6 x% P! f# P2 @( {" L
- 函数功能:产生ACK应答
+ h# m' {) S! L2 G - 入口参数:无* u7 R# Q) f% e3 E5 _
- 返回参数:无0 ?; A$ N, E% n, {4 q7 \* H& u4 T4 q
- 修改作者:Aaron
& X! ]: K: a. o: a0 G* k& o - **********************************************************************/
1 M: }4 ~5 |; V+ `' | - void MPU_IIC_Ack(void)# S! R0 m; y% P5 |
- {( l) v" s! ^2 X2 `4 {5 S4 k w
- MPU_IIC_SCL=0; // SCL设低电平
0 M9 {6 y# e9 E5 b/ y% s* y - MPU_SDA_OUT(); // SDA输出模式
/ `6 t( e5 W A' ~ ? - MPU_IIC_SDA=0; // SDA设低电平
% K6 i9 c5 Q9 T- _) g - MPU_IIC_Delay(); // 延时 2 us5 O4 A1 e; A# d- u8 O. _
- MPU_IIC_SCL=1; // SCL设高电平
4 B ?: Z& O1 K, [# P* }1 u - MPU_IIC_Delay(); // 延时 2 us
/ a: `2 `0 N) g - MPU_IIC_SCL=0; // SCL设第电平,在SCL高电平期间,SDA为低电平,则说明有效应答) o# K8 R9 L5 z/ k( c" C
- }
6 V1 O; a) v) V( D& {1 O - /*********************************************************************; o6 j( o4 e; c& E
- 函数名称:MPU_IIC_NAck()
& O X, m% h- n% u% G9 g M - 函数功能:不产生ACK应答
6 `. P# e8 v- r5 Y* Y6 @/ _ - 入口参数:无
& h8 t$ {4 g% g, E' S - 返回参数:无
/ x; n& t$ ]/ K9 C0 }' @0 `. q - 修改作者:Aaron' S" b2 n0 K3 o D3 P
- **********************************************************************/
) j$ [, Q0 S! N7 F: h! R& p - void MPU_IIC_NAck(void)
0 |4 x0 ?. o! a( R1 j - {
7 v( [) @6 w/ c, B5 j u - MPU_IIC_SCL=0; // SCL设低电平- F; Z f; d$ j9 x- u; V7 x9 F W
- MPU_SDA_OUT(); // SDA输出模式
. X" U8 I0 z; K1 d - MPU_IIC_SDA=1; // SDA设高电平6 R8 x+ x+ |- Y6 M3 r
- MPU_IIC_Delay(); // 延时 2 us
3 y7 ]- C6 Y0 @* H( @ P - MPU_IIC_SCL=1; // SCL设高电平
% D w$ J$ G9 r. v' @7 K1 p9 z - MPU_IIC_Delay(); // 延时 2 us
) Z8 ~: G3 Z2 b+ }' N9 p - MPU_IIC_SCL=0; // SCL设低电平,在SCL高电平期间,SDA为高电平,则说明无效应答
6 h% h5 W- f& d; y, J" F. r - }
/ b& x' E8 Y% i - /*********************************************************************
3 w7 M8 Z8 t4 m7 V - 函数名称:MPU_IIC_Send_Byte(u8 txd)' ]' R% p/ p9 z9 h$ P
- 函数功能:IIC发送一个字节
. x) i8 y9 p- p/ g( x - 入口参数:u8 txd* R* n' V' f H) |. J
- 返回参数:无7 ~% b! e0 W+ c' \3 D" M. P$ K' ^
- 修改作者:Aaron* t1 h1 H7 ]( o0 ~6 e
- **********************************************************************/
9 U' D7 j( a9 Y3 ^& u) [1 A - void MPU_IIC_Send_Byte(u8 txd)
& [6 J% T% ]' G" z- ] - {
. W" Z( s% K2 e; g - u8 t; % }/ P+ Z6 C2 q0 k% ]
- MPU_SDA_OUT(); // SDA输出模式 ! ~7 R' |. s) w3 X
- MPU_IIC_SCL=0; // SCL设低电平,此时可改变SDA,以实现数据的有效传输
, j- j( x. ?, u& J - for(t=0;t<8;t++) // 发送一个字节,即8个bit
1 A/ T& Z1 D( V2 N& q - {
1 Y* w G! A4 e/ w - MPU_IIC_SDA=(txd&0x80)>>7; // 获取u8 txd的最高位(0或1),并右移7位,将最高位值给MPU_IIC_SDA+ b, k8 ^; ^# ]* l+ ~
- txd<<=1; ' O1 K- C X& `; V2 S- q: I- F
- MPU_IIC_SCL=1; // SCL设高电平
6 c' U: d8 s- z1 l! V - MPU_IIC_Delay(); // 延时 2 us
0 O( H2 o2 o0 ^; U4 u6 d - MPU_IIC_SCL=0; // SCL设低电平,传输SDA完成9 D5 j& I ^$ [3 Q
- MPU_IIC_Delay(); // 延时 2us
2 e) s4 {9 l; n' i; |8 c7 G' s - } ! k1 O/ j; Z, b! T J
- } i: `! Q6 U# S/ X; U3 S' z( A
- /*********************************************************************
* W1 I5 F3 U1 e# x; u - 函数名称:u8 MPU_IIC_Read_Byte(unsigned char ack)3 U6 x3 k. l( l
- 函数功能:IIC读取一个字节,ack=1时,发送ACK,ack=0,发送nACK ( A# [1 v& n9 e6 o* ~( W" `% s
- 入口参数:ack5 {5 u3 L0 y/ ^5 [2 h- C
- 返回参数:u8,
2 B" D! }5 @7 I' j+ m) Z - 修改作者:Aaron# E; U8 w& R- a0 R% v2 F
- **********************************************************************/
. g! B0 v6 G$ B1 p. k - u8 MPU_IIC_Read_Byte(unsigned char ack)
3 K- D2 y' V9 Y' R) b+ v( s* I, u - {
* ~( @$ K* o# K7 h - unsigned char i,receive=0;1 {. {6 d j8 g$ u4 R( p
- MPU_SDA_IN(); // SDA设置为输入模式
6 `$ {% C7 E- i ]) E' O/ h5 m: D - for(i=0;i<8;i++ ) // 读取一个字节,即8个bit4 b. I; | U* o* d
- {
0 o* x+ |5 Q' @; g. E! _( c! E - MPU_IIC_SCL=0; // SCL设为低电平
0 R2 ?- G6 R& f- e2 @5 T - MPU_IIC_Delay(); // 延时 2us
, R. s% A1 z3 I - MPU_IIC_SCL=1; // SCL设为高电平
# r6 | P* M7 H9 G& l+ v - receive<<=1;
- s& N" D* a" y6 | - if(MPU_READ_SDA) // 如果读取的SDA为1,则receive最低值+1,若读取的SDA为0,则receive最低值不变,即0
Y8 t: }' \( I$ I# K0 { - receive++; ' X8 Q# u4 X% p& l/ P
- MPU_IIC_Delay(); // 延时 2us. R7 g8 S8 F! e* z! _+ R0 c
- } , z* M6 _% `" ]* X" G4 X& i( O2 l
- if (!ack)
2 ?' k+ N+ C( h* V - MPU_IIC_NAck(); // 发送nACK
/ E' m! E; j6 ~4 V - else
& I2 _; ]9 ^8 S/ f1 J - MPU_IIC_Ack(); // 发送ACK
4 L, H9 Z7 [6 o6 N2 \" O' \6 o W) p - return receive;* _* h/ }$ }! n/ U" u! N
- }, n1 F' i+ Y& Y9 y: M8 p
- /****** Copyright (C)2020 Aaron. All Rights Reserved ****** END OF FILE *******/
复制代码
; z g! J7 G" _10.3 mp6050.h头文件函数4 T8 l2 _. b# r, G! J( }: T4 D
代码中标记“初学”的说明是前面寄存器介绍时讲到的。4 ?& i0 n6 R/ j/ y* k5 ^5 f/ A
5 v) v& E5 a- U' Q
- /**( ^; F' M6 a4 L) H2 L9 b3 g1 v
- ******************************** STM32F10x *********************************2 F0 O! w) v; {1 C9 L2 S8 m G
- * @文件名称: mpu6050.h
4 ]1 ]+ P! @ s - * @修改作者: Aaron7 y- l" E: _, n$ g
- * @库版本号: V3.5.0
: c- L/ M c0 S C' l - * @工程版本: V1.0.0
2 f/ K# J2 o6 b* Q2 Q! k' k0 q - * @开发日期: 2020年11月30日9 q! Z+ _1 e1 n0 S( v
- * @摘要简述: mpu6050头文件& x; K- m0 k3 l: m# D
- ******************************************************************************/% i. h# D/ b, n- A ^
- /*-----------------------------------------------------------------------------
! l: i1 z" W# O, `# r - * @更新日志:
- v# i3 y5 a5 k3 ] - * @无, A2 g3 _8 R+ U# [
- * ---------------------------------------------------------------------------*/- I2 Y! x! d" `6 o
- #ifndef __MPU6050_H
6 b- |4 T- ^ S - #define __MPU6050_H6 n' |. L+ i1 { {8 B" e7 [
- /* 包含的头文件 --------------------------------------------------------------*/
2 ^: K: l" [ u- T/ r" q - #include "mpuiic.h"
, z- D* H3 P! `5 u; |3 N P4 v$ G+ E0 m - /* 位操作控制PA15,对应MPU6050 AD0的高低电平 ----------------------------------*/
( [& e' U2 P/ e T4 T y" f - #define MPU_AD0_CTRL PAout(15) // 控制AD0电平,从而控制MPU-6050地址
4 x2 |3 A# w8 K# q1 l# T7 L - /* MPU6050 寄存器ID定义 ------------------------------------------------------*/3 t, E+ h3 ~3 j
- // #define MPU_ACCEL_OFFS_REG 0X06 // accel_offs寄存器,可读取版本号,寄存器手册未提到
1 n9 c. V# A, L! K - // #define MPU_PROD_ID_REG 0X0C // prod id寄存器,在寄存器手册未提到0 q( [4 f6 l( z# R/ D
- #define MPU_SELF_TESTX_REG 0X0D // 自检寄存器X ACC和G
" ~7 b7 Y, g, ?, X - #define MPU_SELF_TESTY_REG 0X0E // 自检寄存器Y ACC和G
3 a% c9 q6 }0 H, X% b# N7 g, `/ [ - #define MPU_SELF_TESTZ_REG 0X0F // 自检寄存器Z ACC和G
$ M1 l% }# _: P; v: O( ~6 n0 X- g j - #define MPU_SELF_TESTA_REG 0X10 // 自检寄存器X,Y,Z only ACC1 a, I' ?: {$ n: g' `6 g5 }
- #define MPU_SAMPLE_RATE_REG 0X19 // 陀螺仪采样频率分频器 **初学**
1 v* v9 p( L2 J6 _' }- B - #define MPU_CFG_REG 0X1A // 配置寄存器 **初学**$ S8 w+ c/ r: k% p# Y; L
- #define MPU_GYRO_CFG_REG 0X1B // 陀螺仪配置寄存器 **初学**
3 O# F2 C" N- S p. V6 } - #define MPU_ACCEL_CFG_REG 0X1C // 加速度计配置寄存器 **初学**0 N2 g1 t- g5 p3 R
- #define MPU_MOTION_DET_REG 0X1F // 运动检测阀值设置寄存器
6 l- [/ L) H5 j% z+ `" o- q* ~ - #define MPU_FIFO_EN_REG 0X23 // FIFO使能寄存器 **初学**7 R1 `; R- d& W4 C8 ~( U
- #define MPU_I2CMST_CTRL_REG 0X24 // IIC主机控制寄存器
* n7 b! L& ]. o z: z! @- w - #define MPU_I2CSLV0_ADDR_REG 0X25 // IIC从机0器件地址寄存器' P. z7 {# F8 ?1 T3 J
- #define MPU_I2CSLV0_REG 0X26 // IIC从机0数据地址寄存器
0 Y3 l2 b6 A0 k8 v7 n - #define MPU_I2CSLV0_CTRL_REG 0X27 // IIC从机0控制寄存器
$ i2 b& @2 u, Z, w* U - #define MPU_I2CSLV1_ADDR_REG 0X28 // IIC从机1器件地址寄存器) V. k5 ?1 t8 ~" f6 f
- #define MPU_I2CSLV1_REG 0X29 // IIC从机1数据地址寄存器
* M, m3 d% ^+ D - #define MPU_I2CSLV1_CTRL_REG 0X2A // IIC从机1控制寄存器
/ E. ^& s# l% f: Z b - #define MPU_I2CSLV2_ADDR_REG 0X2B // IIC从机2器件地址寄存器
/ O& D3 Z9 s* W* U- T8 T1 g - #define MPU_I2CSLV2_REG 0X2C // IIC从机2数据地址寄存器
) M( ?7 y2 }) Y - #define MPU_I2CSLV2_CTRL_REG 0X2D // IIC从机2控制寄存器
, z, `/ M# d+ B6 F9 N: \7 L H - #define MPU_I2CSLV3_ADDR_REG 0X2E // IIC从机3器件地址寄存器' j( ?# U4 E& V7 ]2 C! v b
- #define MPU_I2CSLV3_REG 0X2F // IIC从机3数据地址寄存器& c5 g* {8 F. v4 e
- #define MPU_I2CSLV3_CTRL_REG 0X30 // IIC从机3控制寄存器
% K3 |0 L* O5 s* s! R8 q& ` - #define MPU_I2CSLV4_ADDR_REG 0X31 // IIC从机4器件地址寄存器
$ `# Z2 k4 I5 Q! ~! U% _ - #define MPU_I2CSLV4_REG 0X32 // IIC从机4数据地址寄存器' I3 {1 ?" D& {2 f
- #define MPU_I2CSLV4_DO_REG 0X33 // IIC从机4写数据寄存器- a$ }- n4 A: |0 H% V
- #define MPU_I2CSLV4_CTRL_REG 0X34 // IIC从机4控制寄存器
- o: M; I1 p% K% [ - #define MPU_I2CSLV4_DI_REG 0X35 // IIC从机4读数据寄存器0 p& O; V1 v$ Y; |
- #define MPU_I2CMST_STA_REG 0X36 // IIC主机状态寄存器* A4 {( ?. \7 [/ A. n
- #define MPU_INTBP_CFG_REG 0X37 // 中断/旁路设置寄存器 ?: t0 @3 b1 h. z! ~' Z7 j; ]/ J
- #define MPU_INT_EN_REG 0X38 // 中断使能寄存器
+ t+ y( |! r$ J% x6 r - #define MPU_INT_STA_REG 0X3A // 中断状态寄存器
+ }6 i4 `" R2 r$ f" V" \ - #define MPU_ACCEL_XOUTH_REG 0X3B // 加速度值,X轴高8位寄存器 **初学**! ^4 G/ \2 k; _
- #define MPU_ACCEL_XOUTL_REG 0X3C // 加速度值,X轴低8位寄存器 **初学**/ I; K( C) {& z
- #define MPU_ACCEL_YOUTH_REG 0X3D // 加速度值,Y轴高8位寄存器 **初学**' ]+ H) u, |: ]& w/ e2 \
- #define MPU_ACCEL_YOUTL_REG 0X3E // 加速度值,Y轴低8位寄存器 **初学**
8 [" ]; w7 e! P3 ~8 S& |7 x1 J - #define MPU_ACCEL_ZOUTH_REG 0X3F // 加速度值,Z轴高8位寄存器 **初学**0 a- b: Q5 B' P3 p
- #define MPU_ACCEL_ZOUTL_REG 0X40 // 加速度值,Z轴低8位寄存器 **初学**/ L- s# i8 H3 {- a8 K) E I" P
- #define MPU_TEMP_OUTH_REG 0X41 // 温度值高八位寄存器 **初学**
/ I0 V- Z! R' e0 T - #define MPU_TEMP_OUTL_REG 0X42 // 温度值低八位寄存器 **初学**8 C3 I6 X( v$ ~3 z# k: w
- #define MPU_GYRO_XOUTH_REG 0X43 // 陀螺仪值,X轴高8位寄存器 **初学**
3 v% |2 L. u( d9 G+ n, h( J - #define MPU_GYRO_XOUTL_REG 0X44 // 陀螺仪值,X轴低8位寄存器 **初学**8 a6 ]% _' L0 H
- #define MPU_GYRO_YOUTH_REG 0X45 // 陀螺仪值,Y轴高8位寄存器 **初学**! z7 l+ i) ^5 R' ]( ~
- #define MPU_GYRO_YOUTL_REG 0X46 // 陀螺仪值,Y轴低8位寄存器 **初学**
+ e( ?1 U# M$ j" u( z - #define MPU_GYRO_ZOUTH_REG 0X47 // 陀螺仪值,Z轴高8位寄存器 **初学**
6 c+ w5 R5 V8 Z - #define MPU_GYRO_ZOUTL_REG 0X48 // 陀螺仪值,Z轴低8位寄存器 **初学**
! [7 Z' M% [' H+ V% h! I! w - #define MPU_I2CSLV0_DO_REG 0X63 // IIC从机0数据寄存器
9 u% u9 a: f; r+ H; l" U - #define MPU_I2CSLV1_DO_REG 0X64 // IIC从机1数据寄存器. }- H* v4 j3 ?# x
- #define MPU_I2CSLV2_DO_REG 0X65 // IIC从机2数据寄存器
- w& m$ m8 j8 } - #define MPU_I2CSLV3_DO_REG 0X66 // IIC从机3数据寄存器
4 z% O4 D: P9 O$ F: R, E - #define MPU_I2CMST_DELAY_REG 0X67 // IIC主机延时管理寄存器5 X2 B- w2 O/ ?: U! Y# m6 B
- #define MPU_SIGPATH_RST_REG 0X68 // 信号通道复位寄存器
) f' @2 }& L& y# B# Q. S# H - #define MPU_MDETECT_CTRL_REG 0X69 // 运动检测控制寄存器- @3 g0 X2 j0 Z' g* _+ `* S$ X y
- #define MPU_USER_CTRL_REG 0X6A // 用户控制寄存器
& `0 p% a' Z# @1 C - #define MPU_PWR_MGMT1_REG 0X6B // 电源管理寄存器1 **初学**0 j+ _2 D/ o1 W! y& |
- #define MPU_PWR_MGMT2_REG 0X6C // 电源管理寄存器2 **初学**
0 C; |8 c1 s: p4 R8 W+ Z - #define MPU_FIFO_CNTH_REG 0X72 // FIFO计数寄存器高八位2 r$ t# G' _, u/ ]7 ^ t
- #define MPU_FIFO_CNTL_REG 0X73 // FIFO计数寄存器低八位
: j% A" m9 n9 @ - #define MPU_FIFO_RW_REG 0X74 // FIFO读写寄存器1 x. ?7 ~- O# g2 u
- #define MPU_DEVICE_ID_REG 0X75 // 器件ID寄存器$ \/ s F6 r8 g+ Y- C
- // 备注:如果AD0脚(9脚)接地,0,IIC地址为0X68(不包含最低位);1 o I- H% B1 W" p
- // 如果接V3.3,则IIC地址为0X69(不包含最低位),
) }: F: @* \6 G) N) | - // 本开发板由PA15管脚控制,另PA15为低电平 $ ^) \$ `; X4 t9 M2 ?+ `
- #define MPU_ADDR 0X68" O9 f0 m5 \5 p& \7 b
- /* 函数申明 -----------------------------------------------------*/; O: t0 g# r! c. w: A3 y+ m$ g
- u8 MPU_Init(void); // 初始化MPU6050
7 \, M/ b- X3 Y. f( S - u8 MPU_Write_Len(u8 addr,u8 reg,u8 len,u8 *buf); // IIC连续写
0 \ o2 r& i% G* K/ q/ Q - u8 MPU_Read_Len(u8 addr,u8 reg,u8 len,u8 *buf); // IIC连续读 ( [5 ?, R( |0 a
- u8 MPU_Write_Byte(u8 reg,u8 data); // IIC写一个字节
: T0 S! F2 a) [. N( q& C - u8 MPU_Read_Byte(u8 reg); // IIC读一个字节8 e, o- q }& [/ |" t, J
- u8 MPU_Set_Gyro_Fsr(u8 fsr);5 }; }; F1 E* F: J+ D/ {
- u8 MPU_Set_Accel_Fsr(u8 fsr);& V9 i( ^! K6 o! P# N' ]
- u8 MPU_Set_LPF(u16 lpf);; V8 G5 H! y, u& m4 x$ {
- u8 MPU_Set_Rate(u16 rate);3 H; L4 E4 o: T% f! [" ? s
- u8 MPU_Set_Fifo(u8 sens);
) G; A* c% N9 j" ^9 o5 m/ t9 @ - short MPU_Get_Temperature(void);
# } R3 d7 G" O+ X - u8 MPU_Get_Gyroscope(short *gx,short *gy,short *gz);4 O8 z2 I# t0 v& V
- u8 MPU_Get_Accelerometer(short *ax,short *ay,short *az);0 f2 n3 `# R& D# D9 S
- #endif /* __MPU6050_H */
+ b% b1 }! T x3 _2 n& a - /****** Copyright (C)2020 Aaron. All Rights Reserved ****** END OF FILE *******/
复制代码
( b" [* g7 s Z$ b10.4 mpu6050.c源文件函数" Y7 `$ }9 T% x4 I. u2 K4 f
r7 d+ `% x4 |/ u1 Y- /*** x( {3 P8 t5 c/ D
- ******************************** STM32F10x *********************************
3 R5 @/ n6 C) m - * @文件名称: mpu6050.c
2 N$ R- v9 n2 b' j - * @修改作者: Aaron
2 c5 ^ j4 J' b* E! L - * @库版本号: V3.5.0
% j) D3 _9 w2 w6 S# i' J3 e - * @工程版本: V1.0.0
" y+ X) R# s! F+ I8 v, j# L - * @开发日期: 2020年11月30日
0 }3 ]5 g* J3 L - * @摘要简述: mpu6050源文件8 a6 b8 j9 B0 A& L) L
- ******************************************************************************/
/ k& V: _. g6 X% F - /*-----------------------------------------------------------------------------
" }' ^" R, ?4 d5 c+ I5 s: X8 U8 B5 G - * @更新日志:
% P7 Z9 C/ U% W - * @无
( [- T8 \ X* B( ?9 { - * ---------------------------------------------------------------------------*/
+ O/ J ^/ r1 U% D8 L" p$ _ - /* 包含的头文件 --------------------------------------------------------------*/0 @) c: O" `. j, |0 g
- #include "mpu6050.h" ^3 a5 d% V! M- a9 `
- #include "delay.h"# V O8 E4 P4 H& c1 E% l$ |
- /*********************************************************************% \ x, ^5 N4 X$ [
- 函数名称:u8 MPU_Init()4 ]1 d) W3 {% @* e- B' G
- 函数功能:初始化MPU60506 B- r3 R; {/ W
- 入口参数:无
# W3 A; B: o% H' d0 o, G2 Z0 b, c - 返回参数:0,成功,1失败
3 z$ X) V" B1 [1 t - 修改作者:Aaron( h- ^1 L. B0 Q
- **********************************************************************/
* q: E( Z# H9 k7 e - u8 MPU_Init(void)
, O4 h! @( I( ^" Y. a, C$ ^& G - { $ X/ ?+ @8 Y b9 }
- u8 res;( j! w6 D0 {1 u( `7 O! }
- GPIO_InitTypeDef GPIO_InitStructure;
: K: x& d$ @+ Q, H% @" s8 r; ?1 u - RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); // 使能AFIO时钟
% k: G* \& p) j9 H" W/ y - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); // 使能外设IO PORTA时钟 & Q8 P) i+ ^% \" J
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15; // 管脚15! u% v' a6 |& H' s7 u* ~
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出5 t: h8 s" Q- j! _/ _# V3 r
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // IO口速度为50MHz
8 B. `; `: U1 w) ]1 N7 s ?7 } - GPIO_Init(GPIOA, &GPIO_InitStructure); // 根据设定参数初始化PA15,对应MPU-6050芯片的AD0地址管脚% K& D$ w1 S* A& L: z
- GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); // 禁止JTAG,从而PA15可以做普通IO使用,否则PA15不能做普通IO!!!1 X4 n/ M( u0 m; \( p
- MPU_AD0_CTRL=0; // 控制MPU6050的AD0脚为低电平,则从机地址为:0X685 ]7 T( m1 ~$ Z c
- MPU_IIC_Init(); // 初始化IIC总线
, q$ q, I8 V% {1 x: u2 h; D - MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X80); // 对电源管理寄存器1输入0x80,复位MPU6050( T7 s; c$ P' {
- delay_ms(100);, B4 v( b( C& ?+ J. [: I" h6 I$ l
- MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X00); // 对电源管理寄存器1输入0x00,主要令[6]位设0,正常工作模式,即唤醒MPU6050 ! F' n* r! I2 _( ?& x- Q* f
- MPU_Set_Gyro_Fsr(3); // 设置陀螺仪传感器满量程范围,±2000dps
8 T8 Q2 \/ d `8 s1 [ - MPU_Set_Accel_Fsr(0); // 设置加速度传感器满量程范围,±2g* i9 b w+ F6 o5 n: _
- MPU_Set_Rate(50); // 设置采样率50Hz! X# l* F. ^) N% B2 H! {7 a
- MPU_Write_Byte(MPU_INT_EN_REG,0X00); // 对中断使能寄存器输入0x00,关闭所有中断/ i* j: Y4 b! Q4 f; S' n
- MPU_Write_Byte(MPU_USER_CTRL_REG,0X00); // 对用户控制寄存器输入0x00,I2C主模式关闭2 W: ?0 Y. ^$ p, T! h! b* N
- MPU_Write_Byte(MPU_FIFO_EN_REG,0X00); // 对FIFO使能寄存器输入0x00,关闭FIFO3 v# q H% f. y2 `- N
- MPU_Write_Byte(MPU_INTBP_CFG_REG,0X80); // 中断/旁路设置寄存器输入0x80,INT引脚低电平有效# \& g$ N( v" J1 W+ F* {0 d( ?6 {, O
- res=MPU_Read_Byte(MPU_DEVICE_ID_REG); // 读取器件ID寄存器值,传至res里) U% r* c, Q9 g+ u9 r$ Z
- if(res==MPU_ADDR) // 如果res=0x68,则器件ID正确
' }" F3 i4 p! Q6 _. E, v& n - {' r$ Q& l3 P3 G- x2 M G p# a5 X
- MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X01); // 对电源管理寄存器1输入0x01,设置CLKSEL,001,PLL X轴为参考. ?& e3 j0 o! A* ~1 c0 b! v
- MPU_Write_Byte(MPU_PWR_MGMT2_REG,0X00); // 对电源管理寄存器2输入0x00,加速度与陀螺仪都工作(都不待机)
1 H" h6 z, z' s - MPU_Set_Rate(50); // 设置采样率为50Hz
0 y8 x1 ~! N- t- _ - }
2 Q9 r$ W; m7 U* M - else $ W3 P' ~- m2 N* T
- return 1;
) U0 |4 Y2 |+ S - return 0;
& [8 W6 g1 a5 i. x( @ - }
! t8 S$ S' z! D( V - /*********************************************************************
' a( L2 I0 y3 `! |* Z - 函数名称:u8 MPU_Set_Gyro_Fsr(u8 fsr)
+ R' u( r) r) Y7 {& p - 函数功能:设置MPU6050陀螺仪传感器满量程范围' P- p, K& w4 m& D: Z a* E
- 入口参数:u8 fsr:0,±250dps;1,±500dps;2,±1000dps;3,±2000dps
3 m/ ]& x( h: l f( Z% @ - 返回参数:0,成功,1失败; @$ Q( P& X% I: k$ r' b4 a
- 修改作者:Aaron g: T! R) r+ E! d# g* e
- **********************************************************************/
6 _, z3 j3 S7 m( E - u8 MPU_Set_Gyro_Fsr(u8 fsr)2 A& ^! N7 k- g" `( k) D
- {
4 e! a6 }3 c: f2 I: T - return MPU_Write_Byte(MPU_GYRO_CFG_REG,fsr<<3); // 设置陀螺仪满量程范围为±2000dps : ]9 y! }# i) Q0 Z& G
- }
2 A8 y4 n. K! { - /*********************************************************************; j* k% j4 G. q2 j/ o, y/ z4 t9 _
- 函数名称:u8 MPU_Set_Accel_Fsr(u8 fsr)
" P9 S' i2 E* ?' ~% `- u4 d$ t - 函数功能:设置MPU6050加速度传感器满量程范围7 O% ?, }' P h" T
- 入口参数:fsr:0,±2g;1,±4g;2,±8g;3,±16g3 k/ e1 t. k9 z0 a$ m
- 返回参数:0,成功,1失败
+ O4 A8 h4 q* w% ~0 c - 修改作者:Aaron
) g" L! Q7 p0 ^. v% d+ ~ - **********************************************************************/2 E" U5 D& x4 _9 R* \
- u8 MPU_Set_Accel_Fsr(u8 fsr)
& z7 L& T, T% R3 X/ _+ ? - {
5 G3 k; D$ R" F - return MPU_Write_Byte(MPU_ACCEL_CFG_REG,fsr<<3); // 设置加速度传感器满量程范围为±2g 1 k/ |8 T. K; ]/ u
- }
$ D+ A) r' [3 q" S' t8 h - /*********************************************************************+ E/ Z! B1 b# G5 F
- 函数名称:u8 MPU_Set_LPF(u16 lpf)
9 ]) R4 [: Q( v/ q5 c% y - 函数功能:设置MPU6050的数字低通滤波器7 w2 r& q% o' s# U+ x/ t
- 入口参数:lpf:数字低通滤波频率(Hz)
" k- G, K2 G3 A0 X$ H% b) _: X0 { - 返回参数:0,成功,1失败
& d8 G7 m9 l' v - 修改作者:Aaron
0 i6 @, X3 A. ?# O - **********************************************************************/
% e. ?% }0 j9 @& E2 J; d8 @/ V" e+ } - u8 MPU_Set_LPF(u16 lpf)) _$ E( }5 P* e2 {/ H' j: W, N& h
- {$ z. |- M. K" M8 Z3 r
- u8 data=0;6 M; A) r* D7 A" L% h. b0 T0 u2 X
- if(lpf>=188) // 如果lpf≥188Hz,则data=1
5 b2 r, u! \: |" X" B+ S - data=1;4 T+ f/ I* Y O; c4 s
- else if(lpf>=98)* v- C+ c! R! u4 F. y+ [
- data=2;
2 p! h" K, }/ _! b# {! n - else if(lpf>=42)8 B4 V! C# B% o$ G1 ]. p
- data=3;
# W4 g# b2 Q2 h }3 y6 k$ n% F - else if(lpf>=20)
3 \0 Y6 }, [; ] - data=4;/ v0 o7 |0 S6 {# z- \8 [* t9 e1 n
- else if(lpf>=10)+ i8 I( a* Q( b. y* d" R: L7 w+ y
- data=5;1 P& u) ?, s+ y
- else
- B& L0 `" t3 r1 m! t8 m' h' b - data=6;
+ C0 T- w" x! F+ K! \ - return MPU_Write_Byte(MPU_CFG_REG,data); // 设置数字低通滤波器 - m& x( X# s% r' Q3 S, I* p
- }
2 P, |3 t6 @+ b+ v' P3 R) @ - 8 W- `* _ m) X& M, a9 K& b4 O
- /********************************************************************* U% l( B3 {3 O$ M
- 函数名称:u8 MPU_Set_Rate(u16 rate)& I; a2 K& K2 R: @* F6 r2 m
- 函数功能:设置MPU6050的陀螺仪采样率(只在陀螺仪输出频率Fs=1KHz时成立). h$ V3 O8 Z/ |! x1 ^
- 入口参数:rate:4~1000(Hz),陀螺仪采样频率7 s. w; i) i# i+ F' X, W; ~# B
- 返回参数:0,成功,1失败
" _2 a$ R1 L4 `' |5 I - 修改作者:Aaron
: S( Y' C& L6 c8 w - **********************************************************************/
5 Q# g" j; k! F$ Q4 v( I - u8 MPU_Set_Rate(u16 rate)
e+ Z: V- {* v1 n - {
& Z. Q' o5 O' D+ Y' P) C - u8 data;
; ?0 Z" I0 s1 [% h - if(rate>1000)
7 D% Y: |, o/ x- V' r - rate=1000;) ~9 a7 U8 d* C* C3 s
- if(rate<4)9 J- `0 N+ B/ w2 J1 `/ k
- rate=4;
/ f# q: C! D; F% t+ z - data=1000/rate-1;) Y `/ t# ] M- o4 y7 h) ]
- data=MPU_Write_Byte(MPU_SAMPLE_RATE_REG,data);
: M: q. h' Q" Y0 v - return MPU_Set_LPF(rate/2); // 自动设置LPF为采样率的一半, X! R$ j6 W1 D, [# R% v' n0 f
- }9 F7 R" k& q8 q4 ]$ T5 T* P8 A* b
- /*********************************************************************8 h/ g/ y" M7 g- A
- 函数名称:short MPU_Get_Temperature()
# i- R! u* Q" R+ |2 g0 h; o - 函数功能:得到温度值2 `; u- S1 Q3 g" b7 V
- 入口参数:rate:4~1000(Hz),陀螺仪采样频率
; D# g" N1 ~( u - 返回参数:温度值(扩大了100倍)
) f* E$ E5 n+ p- z - 修改作者:Aaron
o9 u6 m5 F7 }( g7 w# ` - **********************************************************************/! ]0 s$ `0 @% s$ [% y: H! C
- short MPU_Get_Temperature(void)9 a" g* g1 Y& @4 z v& t5 \
- {6 n" ^) c9 E. Y4 Y- j
- u8 buf[2];
. Z8 }$ J$ j" ]9 p6 b8 ] - short raw;
7 S/ _, S; ^- a - float temp;# o7 q# R7 Q& }$ Y# j
- MPU_Read_Len(MPU_ADDR,MPU_TEMP_OUTH_REG,2,buf); // addr:器件地址;reg:寄存器地址;len:写入长度;buf:数据区
$ c% x. b# G$ @4 s( \8 f - raw=((u16)buf[0]<<8)|buf[1]; 7 |1 Q$ g- n$ E- {' P3 ^$ K
- temp=36.53+((double)raw)/340;
' }! t2 @" T2 L0 K1 u! t, M6 k - return $ ?( g& t+ M |4 C
- temp*100;;( a/ G$ r( |* t3 y
- }
' L, k; r/ {6 w& Z ` - /*********************************************************************
1 w n5 Y% `( m - 函数名称:u8 MPU_Get_Gyroscope(short *gx,short *gy,short *gz)
, J" |- h7 p' B* }$ u0 v6 u - 函数功能:得到陀螺仪值(原始值)
# c7 n. M6 t* L0 e- x5 S1 @' i - 入口参数:gx,gy,gz:陀螺仪x,y,z轴的原始读数(带符号)
$ d& h, H$ O5 j# k0 z$ W- y- h - 返回参数:u8 0成功,1失败
! j( R ?" D5 @4 k1 i/ O - 修改作者:Aaron
& ?+ t+ n, `( ?4 X! c5 ]& J - **********************************************************************/
7 N; H! W! b3 A: I$ A - u8 MPU_Get_Gyroscope(short *gx,short *gy,short *gz): h6 V9 ]! s# Z
- {
2 q H! h3 m3 g# O2 q* Q - u8 buf[6],res;
& `8 X Z2 l: U4 z - res=MPU_Read_Len(MPU_ADDR,MPU_GYRO_XOUTH_REG,6,buf);
0 |7 m$ A/ ?* u) Q - if(res==0) A% b% X! C z& ]. S9 f
- {
1 x8 D) J- p R( r& }! M- X, @9 b. ~ - *gx=((u16)buf[0]<<8)|buf[1]; ! I) t5 i) }' Z s8 u
- *gy=((u16)buf[2]<<8)|buf[3]; 2 q' l, p2 m4 _+ c
- *gz=((u16)buf[4]<<8)|buf[5];
1 w2 O6 E. z( n: k' G: m - }
+ t+ e9 ~& S+ t3 N& G# a - return res;;
% ?; e) O4 v2 M5 E) k5 g7 ]8 | - }
0 l5 m i9 M* {- \3 s7 f - /*********************************************************************' h6 J# s2 P" g! Q) ~ ~6 c
- 函数名称:u8 MPU_Get_Accelerometer(short *ax,short *ay,short *az)
5 i" i2 M1 }. M$ @% j5 X# D - 函数功能:得到加速度值(原始值)
) t8 L8 n; \" ]; N& V - 入口参数:gx,gy,gz:陀螺仪x,y,z轴的原始读数(带符号)
/ A: K8 D8 b6 p/ V( G - 返回参数:u8 0成功,1失败7 C1 \# l6 W2 C/ t
- 修改作者:Aaron
^9 Y: x, w, w& F6 P - **********************************************************************/% x' [7 ^3 y# K4 J
- u8 MPU_Get_Accelerometer(short *ax,short *ay,short *az)
2 G5 o; v3 h6 n% w/ G% P5 T - {* d6 V# m- }: q% ]& K0 Y9 h0 J* |
- u8 buf[6],res;
8 Y( P A h" M9 {$ ?5 |" g6 ^+ b - res=MPU_Read_Len(MPU_ADDR,MPU_ACCEL_XOUTH_REG,6,buf);% u, n2 }0 x3 g* x! p( j
- if(res==0)
5 i/ ]8 `* o. g3 M X - {
2 {7 D- ]2 ?4 Q3 Q2 H9 e# T3 Q - *ax=((u16)buf[0]<<8)|buf[1];
/ O3 k( U: j" N; J! U6 u - *ay=((u16)buf[2]<<8)|buf[3];
+ Y/ U' ?% N0 ^ - *az=((u16)buf[4]<<8)|buf[5];$ B3 w: b8 e9 B$ k Y6 T9 ~
- }
, N$ @8 }. X% a - return res;;1 w; V( G5 t3 m" P
- }8 p9 u0 W6 f7 X! Y
- /*********************************************************************
, J# |' B. q& Q& j+ z - 函数名称:u8 MPU_Write_Len(u8 addr,u8 reg,u8 len,u8 *buf)
4 \. R4 z( _' \3 ~ - 函数功能:向MPU6050连续写入数据
5 ~! ?; t+ X3 T+ U# {" h - 入口参数:addr:器件地址;reg:寄存器地址;len:写入长度;buf:数据区
) Z3 G& @9 b l" K ^, A8 g - 返回参数:u8 0成功,1失败
: r( i: X* h! H8 e% p6 W$ ^; g+ [ - 修改作者:Aaron
6 o. `0 [ u3 @6 ^' P) s' z0 g1 O - **********************************************************************/! n% J$ i+ U( ]& L# _- f; G4 b$ U
- u8 MPU_Write_Len(u8 addr,u8 reg,u8 len,u8 *buf)
; Q% L1 e+ E: } n/ s2 Q5 M - {
9 Y" {) q2 n" s$ H+ |' B - u8 i;
& `3 D: ]/ f y( { - MPU_IIC_Start();
3 u9 S; w5 ]* g - MPU_IIC_Send_Byte((addr<<1)|0); // 发送器件地址+写命令
& c3 D6 L3 y! N, w s - if(MPU_IIC_Wait_Ack()) // 等待应答
: V8 u& m5 ]4 ^8 d* Y" o/ i - {! _% G7 o6 D" \) Q/ }
- MPU_IIC_Stop();
% m9 y6 X x, \8 C+ \ - return 1;
- D z/ Q7 a4 ^7 h7 X, \$ C - }, L) J3 }# B0 y5 x6 N* V L
- MPU_IIC_Send_Byte(reg); // 写寄存器地址
, e4 g; S0 O3 n5 x% C2 ^* P - MPU_IIC_Wait_Ack(); // 等待应答
" }' J/ ?2 [+ S% T0 }/ i# f - for(i=0;i<len;i++)% I) I# [7 l x# @* `
- {/ z4 D3 J: N( _$ a4 C7 h) r) e
- MPU_IIC_Send_Byte(buf); // 发送数据
# T) a5 m' t6 \% I# B - if(MPU_IIC_Wait_Ack()) // 等待应答" J% x! N( ~. B) h$ Z$ n
- {
5 D2 S3 w- f Z5 x9 E1 z7 R - MPU_IIC_Stop(); 7 Q4 i' {( C& m! x
- return 1;
K i4 [9 h2 t/ N' j0 {0 P9 s! W, ^ - }
1 i3 a+ N |, Q+ j/ @) a - } 7 {/ @* D* a. E. s7 c& S' K
- MPU_IIC_Stop();
: B. \: }& H1 n" A( i - return 0;
+ f. q& R. K; a A# V! T - }
9 E+ v1 ~4 Y W7 y0 s, ] - /*********************************************************************1 ~- }" D/ ]+ S
- 函数名称:u8 MPU_Read_Len(u8 addr,u8 reg,u8 len,u8 *buf)8 F+ P [0 w/ I9 M
- 函数功能:从MPU6050连续读数据! [3 n1 X, r) X | c" {% ?
- 入口参数:addr:器件地址;reg:要读取的寄存器地址;len:要读取的长度;buf:读取到的数据存储区
. {) A/ y% U( X) j5 o - 返回参数:u8 0正常,1错误% M1 {- Q" }" ^& m4 [3 o
- 修改作者:Aaron; ]/ K9 V3 A7 |) V# T. B
- **********************************************************************/
+ `% q7 B, F: T0 @# V8 C - u8 MPU_Read_Len(u8 addr,u8 reg,u8 len,u8 *buf)
p! G$ s! X, X. H: X8 T - { / \ O/ s: L. {4 X- x5 p
- MPU_IIC_Start(); 2 l2 O- d7 P& z9 J! c7 J3 T: C
- MPU_IIC_Send_Byte((addr<<1)|0); // 发送器件地址+写命令 : m4 T- @2 @4 b! y+ J
- if(MPU_IIC_Wait_Ack()) // 等待应答
- G$ A; l, p9 S$ ^1 p - {
, \. r) a o7 `* q4 V6 j - MPU_IIC_Stop();
1 b1 C; e/ m/ T1 s - return 1;
/ A L3 I: a( e3 Q! ?6 b+ V) a - }2 |8 F& C- ?! P: M; o1 N) W
- MPU_IIC_Send_Byte(reg); // 写寄存器地址6 O( l- G7 A. w4 M1 W$ J2 Y' d' o
- MPU_IIC_Wait_Ack(); // 等待应答4 ^% z$ C2 d- P( x" T" m6 d5 j J( [; g
- MPU_IIC_Start();
% \9 ~' D' A) J: Q: h - MPU_IIC_Send_Byte((addr<<1)|1); // 发送器件地址+读命令
2 V* I4 R) [! d; f* ? - MPU_IIC_Wait_Ack(); // 等待应答
1 N, T: P7 m+ N - while(len). V4 ~& m$ X' J) p" G
- {7 p e9 a6 z. J3 i, \
- if(len==1)*buf=MPU_IIC_Read_Byte(0); // 读数据,发送nACK
' ]! V! w$ ]+ W4 c6 [4 r - else *buf=MPU_IIC_Read_Byte(1); // 读数据,发送ACK
/ w$ Z" G5 s$ C5 ^3 ~ - len--;
. |; b0 W j1 |6 ?9 B& a' j; O - buf++;
! r' P2 T& `* B! r5 b! z - } + ~" _' h" k% K, @. m
- MPU_IIC_Stop(); // 产生一个停止条件 " \% C7 L: }; k e
- return 0; 1 M3 m- n" \3 Q# |0 |& y
- }, W4 `, _3 j) V$ }; E+ B& G% l
- /*********************************************************************0 q% o4 K r7 C6 R& ?/ i
- 函数名称:u8 MPU_Write_Byte(u8 reg,u8 data)
9 z/ ]4 `( ]. t; g* i% n9 B+ x - 函数功能:向MPU6050写一个字节 2 C7 N R9 s! h1 s+ K1 u
- 入口参数:reg:寄存器地址;data:数据5 t& T7 m( E3 r. w! ~ N9 b
- 返回参数:0,正常;1,失败7 W( ]; I1 f. k! B: z4 x( I
- 修改作者:Aaron- q6 E4 Y# C# v9 T" P
- **********************************************************************/* T! I, p C r. o0 z! R/ P- j
- u8 MPU_Write_Byte(u8 reg,u8 data) 7 I3 Q* S5 }0 ], {
- { 3 L5 r1 B. N$ E0 N6 c
- MPU_IIC_Start(); ( {9 _1 X8 p7 R
- MPU_IIC_Send_Byte((MPU_ADDR<<1)|0); // 发送器件地址+写命令
' R- r7 i6 N( g( c8 J8 W/ W6 V - if(MPU_IIC_Wait_Ack()) // 等待应答,0接收应答成功,1接收应答失败
$ W, l) E, D, s7 R5 B4 [% s0 z5 R - {8 \+ ] o* Q$ }6 `
- MPU_IIC_Stop(); // MPU_IIC停止信号% K! I7 Z& `% b3 s& y6 O V7 q
- return 1;
+ h+ _ _3 L" H& ?2 ~ - }
2 R2 I$ p! J/ e! ]+ p - MPU_IIC_Send_Byte(reg); // 写寄存器地址0 K; T/ {( ?8 B
- MPU_IIC_Wait_Ack(); // 等待应答 $ `+ z7 `9 ~* T( [) i; @
- MPU_IIC_Send_Byte(data); // 发送数据! G4 C. y! b! i/ x. e
- if(MPU_IIC_Wait_Ack()) // 等待应答- A$ a, G, j, m) l% Y( ^
- {1 v$ n$ H2 s( o& x' R* u8 P( b
- MPU_IIC_Stop();
$ d$ {, z# H) q4 b) z9 X# h - return 1; @/ q) N1 @1 {/ T
- }
5 E6 A7 E5 b' c! x0 J& w O - MPU_IIC_Stop();
0 d$ z5 ]1 K) q( L5 } - return 0;
9 ^5 Q/ |& L# z+ d4 Y% I0 } - }
8 N2 ]( Q% J* x9 m; Q% E - /*********************************************************************
* K1 e( U7 h, N8 A - 函数名称:u8 MPU_Read_Byte(u8 reg)2 U" q" A* {+ F$ v7 F4 C. X
- 函数功能:从MPU6050读一个字节
$ _) a; Q7 u6 e t& J7 | - 入口参数:reg:寄存器地址
* g8 ?, e/ g6 C* H& W. s$ g; K - 返回参数:u8 读到的数据
/ t$ h# Z6 C. {. G' H4 P7 ^ - 修改作者:Aaron
* Q4 f5 x( h" Y' _% P$ d, ]# m - **********************************************************************/& O+ e( N0 _: \+ t; z2 x
- u8 MPU_Read_Byte(u8 reg)2 G6 d8 h# E$ v z8 O( I
- {
' ?' `& E5 x4 o2 D$ B3 L - u8 res;6 A- b7 U( g2 }. Y: _0 H: D6 f
- MPU_IIC_Start(); & D+ M- h$ F1 c7 l) \
- // 开始标志(S)发出后,主设备会传送一个 7 位的 Slave 地址,并且后面跟着一个第 8 位,称为 Read/Write 位。 0写,1读。# s, `1 a2 w4 P
- MPU_IIC_Send_Byte((MPU_ADDR<<1)|0); // 发送器件地址+写命令
- c' ?! v1 a; E- x6 z - MPU_IIC_Wait_Ack(); // 等待应答
1 S+ s% g. O- l1 {2 T+ W# x6 } - MPU_IIC_Send_Byte(reg); // 写入要读取字节的寄存器首地址
7 _0 w. F5 i- O, y4 k) Q" P2 S - MPU_IIC_Wait_Ack(); // 等待应答
5 N ~ e/ ~* X% y7 w - MPU_IIC_Start();, R l8 L0 K* ?" _) h3 @
- MPU_IIC_Send_Byte((MPU_ADDR<<1)|1); // 发送器件地址+读命令 2 ? z' \. Z/ _
- MPU_IIC_Wait_Ack(); // 等待应答
; H9 P: [8 @2 n0 ]# B l - res=MPU_IIC_Read_Byte(0); // 读取一个字节的数据,发送nACK
, n8 _. C# G3 m. u3 H4 g* u - MPU_IIC_Stop(); // 产生一个停止条件 5 k) O. |- |% f) M+ [5 L7 G: o' n
- return res;
6 A9 N/ B8 d" U. b6 n - }
" O. z" T/ p" M - /****** Copyright (C)2020 Aaron. All Rights Reserved ****** END OF FILE *******/
复制代码
# t" B; N8 ?: n' t2 d" b10.5 main.c主函数5 `3 x9 w; ]6 P' Z
5 P0 R! U/ p6 }- d$ a3 G- U6 S- /**
1 X1 m& _3 u3 u+ ?+ h- I - ******************************** STM32F10x *********************************
8 B q* F- l8 H7 _$ J - * @文件名称: main.c
; K2 p6 J2 n* p" C. g0 O - * @修改作者: Aaron
1 w; J9 Y6 O4 G% b* S9 p8 J' ?5 E - * @库版本号: V3.5.03 W. b0 p. d4 v# W& ~& {
- * @工程版本: V1.0.0
% u8 T" J0 w% C6 p1 z - * @开发日期: 2020年11月30日
2 E7 i: |7 O1 p% Z9 E8 ~ - * @摘要简述: 主函数,增加了在LCD显示6轴的原始数据' G1 L6 z5 G. A/ `% o6 I1 S: m
- ******************************************************************************/
. f) L7 y, W/ L8 t) S9 H) W& ] - /*-----------------------------------------------------------------------------/ x- Y) U$ G% J! q
- * @更新日志:! H2 f6 n/ w7 }7 h0 f8 r9 Z
- * @无
! z' P& m6 g: } \ - * ---------------------------------------------------------------------------*/7 Z1 u: y( v) J- x# U1 }; Y& q
- /* 包含的头文件 --------------------------------------------------------------*// `! P" W3 ^1 M4 r. [) w: X2 i
- #include "led.h"
. F$ Q2 B! a( b2 d' o - #include "delay.h"2 Z$ }1 g$ i/ K+ i8 B& C% O9 f' F
- #include "key.h"; w" ^) |9 h }0 v
- #include "sys.h"$ }5 a" n+ l( x
- #include "lcd.h"; j. y/ p# v# g# r
- #include "serial_communication.h"
2 ^5 L6 N9 w3 Y, V - #include "mpu6050.h". O2 i4 [3 j2 P5 E2 B2 |# x( U
- #include "inv_mpu.h"
2 c; l5 B' X) q+ P* @7 o& L$ z; u - #include "inv_mpu_dmp_motion_driver.h"
- \( G) E6 g5 L/ X2 p1 H - /*********************************************************************
( c5 `, @5 f0 X, u1 U - 函数名称:usart1_send_char(u8 c)
4 J# R* o! H, r0 g' @ - 函数功能:串口1发送1个字符$ Z7 O/ g$ q$ y9 j0 e! K
- 入口参数:c:要发送的字符
) ~ c) E( }! x - 返回参数:0,成功,1失败
2 {' g3 t9 v! \9 D' S: ~% ] - 修改作者:Aaron
- k0 q1 s; K! Q6 ?3 Q! W - **********************************************************************/
! V5 `8 A5 Q+ g/ z9 l - void usart1_send_char(u8 c)5 e3 W( d6 F, r
- { ! _ S1 T" P3 ?' c, c
- while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET); // 循环发送,直到发送完毕 6 w8 ^7 e! g0 w
- USART_SendData(USART1,c); 3 ?4 H3 G. j7 x& {0 |7 g
- }
- w7 E6 L: N+ U0 K! V" ?( z) B( Z - /*********************************************************************
: b# ?+ G( l5 l5 k) | - 函数名称:usart1_niming_report(u8 fun,u8*data,u8 len)
( n9 V/ W8 G: x3 f2 [; x2 ^ - 函数功能:传送数据给匿名四轴上位机软件
0 q+ c2 k$ T; q4 M9 U7 j9 s5 s - 入口参数:fun:功能字.0XA0~0XAF;data:数据缓存区,最多28字节;len:data区有效数据个数
. ^( j, S( F* m6 r3 _, j1 |0 H - 返回参数:无6 c1 |' K& x& h: `9 t- v5 }
- 修改作者:Aaron. Z' @; r: ]7 Y# X1 v8 V: _ ]! i$ o
- **********************************************************************/2 O7 y& x& I. x( T1 U5 c
- void usart1_niming_report(u8 fun,u8*data,u8 len)& V7 R' m$ X" m- K; l
- {
" ~: g" a% R. e4 ` - u8 send_buf[32];" Y. M3 V8 k1 v$ n
- u8 i;
* h! [ @+ s% w" L - if(len>28)return; // 最多28字节数据
) |% T# w' O* x t, K( U- J, ] - send_buf[len+3]=0; // 校验数置零
/ k7 j) }# K7 f0 x - send_buf[0]=0X88; // 帧头# V4 X% F) ?3 l7 d+ t
- send_buf[1]=fun; // 功能字' t# U9 l2 M0 }& f- O; b: O. U) P
- send_buf[2]=len; // 数据长度: x3 S5 }% D$ G" m1 q, G
- for(i=0;i<len;i++)send_buf[3+i]=data; // 复制数据$ ~' C/ u( o$ q& ]! L
- for(i=0;i<len+3;i++)send_buf[len+3]+=send_buf; // 计算校验和
: J; u9 K y, U - for(i=0;i<len+4;i++)usart1_send_char(send_buf); // 发送数据到串口1
: P8 E2 n/ P6 A# I' h - }
7 Z2 Y4 p$ ]3 D& b - /*********************************************************************
3 u% S4 c7 W9 o$ \4 A) w- q - 函数名称:mpu6050_send_data(short aacx,short aacy,short aacz,short gyrox,short gyroy,short gyroz)6 y( ]- W+ L+ C, Z: _. h# k6 z
- 函数功能:发送加速度传感器数据和陀螺仪数据
/ S! }/ R- r* k - 入口参数:aacx,aacy,aacz:x,y,z三个方向上面的加速度值;gyrox,gyroy,gyroz:x,y,z三个方向上面的陀螺仪值
0 ]6 t( }+ q: y# _ - 返回参数:无
1 a4 X. |' ]2 a( X4 a - 修改作者:Aaron& v" Q- i+ l4 \7 h9 l$ E+ W
- **********************************************************************/- D0 P( w" A( y5 d
- void mpu6050_send_data(short aacx,short aacy,short aacz,short gyrox,short gyroy,short gyroz)
2 H, r& l2 @, K4 | - {
* h z8 f" ]6 U& ?" ]* D" E - u8 tbuf[12]; 5 t4 F. P. p! }# ~; P: ^/ T
- tbuf[0]=(aacx>>8)&0XFF;
- f8 X3 b, @" \2 Z) V" L - tbuf[1]=aacx&0XFF;
1 U# n# E s* @ - tbuf[2]=(aacy>>8)&0XFF;
6 J" }$ x9 D; O2 b* h - tbuf[3]=aacy&0XFF;$ Z8 z; ~3 ]5 L; K [ a. I4 }
- tbuf[4]=(aacz>>8)&0XFF;% @5 I# u8 p+ i) r- f7 \ ~" x7 v
- tbuf[5]=aacz&0XFF; : {- U) \* z9 I1 B( g
- tbuf[6]=(gyrox>>8)&0XFF;0 H- z5 Y+ e4 Z" d. a7 q6 D
- tbuf[7]=gyrox&0XFF;, V0 W" |6 u4 R G# V! u
- tbuf[8]=(gyroy>>8)&0XFF;* @% ?8 M0 l; g3 ?
- tbuf[9]=gyroy&0XFF;6 z; ]& V; n7 p$ Z {/ x
- tbuf[10]=(gyroz>>8)&0XFF;
P7 T/ ^: m8 B! m - tbuf[11]=gyroz&0XFF;" w5 U0 d J, {* e
- usart1_niming_report(0XA1,tbuf,12); // 自定义帧,0XA1
2 I& Q+ N. u% Y$ y - } 4 g3 Q' {! e. i- E
- /*********************************************************************( p7 d3 V1 Y% G- S
- 函数名称:mpu6050_send_data(short aacx,short aacy,short aacz,short gyrox,short gyroy,short gyroz)0 C& ], q, i; F
- 函数功能:通过串口1上报结算后的姿态数据给电脑4 r* _0 j) _) ~4 q( z9 H
- 入口参数:aacx,aacy,aacz:x,y,z三个方向上面的加速度值;gyrox,gyroy,gyroz:x,y,z三个方向上面的陀螺仪值;
# a% a% M, T# m+ q - roll:横滚角.单位0.01度。 -18000 -> 18000 对应 -180.00 -> 180.00度;) F- x: W3 F' E7 k' |
- pitch:俯仰角.单位 0.01度。-9000 - 9000 对应 -90.00 -> 90.00 度
, G0 ^" a w. `- J6 O; N# G - yaw:航向角.单位为0.1度 0 -> 3600 对应 0 -> 360.0度3 J( W9 C8 l1 r- @" ?8 T& c4 n
- 返回参数:无- ~9 ?) F* E; E5 Q
- 修改作者:Aaron
6 K0 T& ]+ M' y/ T8 G$ d! g! a - **********************************************************************/
* T6 _2 e* k- O - void usart1_report_imu(short aacx,short aacy,short aacz,short gyrox,short gyroy,short gyroz,short roll,short pitch,short yaw)2 L4 \1 I* g" c d* T* Y
- {" N, [( u% N, T& E# W
- u8 tbuf[28]; # g% ^2 q1 w# J/ }9 L
- u8 i;8 L+ l/ {1 F4 w _& k
- for(i=0;i<28;i++)tbuf=0; // 清00 e2 z( x. r# E; h
- tbuf[0]=(aacx>>8)&0XFF;9 @: i6 V# Z$ v0 t9 o; L" U* @ x( O$ ]
- tbuf[1]=aacx&0XFF;) e% J; o; T$ ?7 b, N
- tbuf[2]=(aacy>>8)&0XFF;
% `/ C x! a# o& ^* N - tbuf[3]=aacy&0XFF;( O- m5 A$ k4 h4 |( h ]2 D& B
- tbuf[4]=(aacz>>8)&0XFF;* K9 g \3 ?$ o/ u8 k4 L: q
- tbuf[5]=aacz&0XFF; # g/ G. p9 o. y% n% e' {. E& ^
- tbuf[6]=(gyrox>>8)&0XFF;
; G2 G( g( i) z" P, U9 ]* n. ^ T - tbuf[7]=gyrox&0XFF;6 B% \' B/ R2 B4 a# W+ W% q8 ~
- tbuf[8]=(gyroy>>8)&0XFF;
, g- F$ T% n8 |. {4 t- }0 J - tbuf[9]=gyroy&0XFF;
& C1 F j& A# X! p* h% F2 B! _( u - tbuf[10]=(gyroz>>8)&0XFF;
; S1 G, @/ ^( z* Z - tbuf[11]=gyroz&0XFF;
0 F% H; L! ]' P. L! Y - tbuf[18]=(roll>>8)&0XFF;( G z% `5 J0 p+ b
- tbuf[19]=roll&0XFF;
8 ?# \" v; `7 d, z6 c7 H8 } - tbuf[20]=(pitch>>8)&0XFF;- M& K( _8 B% I) l! [$ X: ~: L0 S) u
- tbuf[21]=pitch&0XFF;5 L. I- G; o- g2 j
- tbuf[22]=(yaw>>8)&0XFF;- M( B9 l* O, f- n7 H
- tbuf[23]=yaw&0XFF;
* w* I4 Y7 J2 ^7 \" u; P8 S T - usart1_niming_report(0XAF,tbuf,28); // 飞控显示帧,0XAF
% v, g7 J+ T7 C" ^! p9 n - }
' {/ Y0 A: B% U! Z - /*********************************************************************
/ g" D) ]+ K' w- K& z - 函数名称:int main()
2 Y8 J, e: [( m. _$ B! |# Q1 w - 函数功能:主函数,增加了在LCD屏上显示6轴原始数据的功能8 ]( l- _. c, @7 a8 O4 a
- 入口参数:无 W# c4 d$ u& `" x
- 返回参数:无
0 n" c0 z8 z& c9 }: h - 修改作者:Aaron; d4 y% ]& {2 k+ q7 k, T
- **********************************************************************/# h$ j' F* ^9 b5 F$ L. z; w1 o8 w- _
- int main(void)& I" r4 Z8 N$ Z1 R0 [$ }" |4 |
- { : r$ F7 }" o' W* }
- u8 t=0,report=1; // 默认开启上报,发给匿名四轴上位机软件6 X/ H- r9 A) P
- u8 key;" y; s" }( f b% @, {
- float pitch,roll,yaw; // 欧拉角
6 b4 t8 ~: [* W; C - short aacx,aacy,aacz; // 加速度传感器原始数据
+ N9 A$ m) [+ W- b* S( [! w5 g - short gyrox,gyroy,gyroz; // 陀螺仪原始数据5 K9 n- _- I9 m3 j2 i! ^# G, g) s
- short temp; // 温度 ' P. x0 k7 u' B
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 设置NVIC中断分组2:2位抢占优先级,2位响应优先级1 A1 _1 j) ^3 J' h
- My_USART1_Init(); // 串口初始化为500000
' ]' W. w; c$ B1 ?4 v6 J# c - delay_init(); // 延时初始化 9 L" ~) _- ~& q! H: o
- LED_Init(); // 初始化与LED连接的硬件接口
3 R! [6 z0 s0 G: t& x - KEY_Init(); // 初始化按键( Q7 C$ G8 H$ a' Z/ c/ z: Q
- LCD_Init(); // 初始化LCD 1 f/ }+ `$ R! L! x+ S
- MPU_Init(); // 初始化MPU6050
9 e9 V4 T5 j5 y/ [ - POINT_COLOR=RED; // 设置字体为红色
/ Y6 a& u8 f7 V* e2 j( A - LCD_ShowString(30,70,200,16,16,"MPU6050 TEST");
% V \5 | ?/ _6 }( X% p5 w8 K - LCD_ShowString(30,90,200,16,16,"2020/11/30");
" w, s- U5 a0 e* }, k - while(mpu_dmp_init())" D% B6 O! X( Y t/ B4 K! F
- {
% G# |( P- y' ?( r! X' R - LCD_ShowString(30,110,200,16,16,"MPU6050 Error");. W: W$ Y2 P! n2 G3 a- v
- delay_ms(200);* ~0 X* N2 j" W% Z" F% N
- LCD_Fill(30,110,239,130+16,WHITE);. k" }( K& I; {, c2 W+ d$ h
- delay_ms(200);
( ^3 f& c3 E, f6 C% K4 b( p9 \ - }
* K$ p, j+ O5 W6 {' S2 Q - LCD_ShowString(30,110,200,16,16,"MPU6050 OK");& P$ V& H4 @& ~) Z J' o9 A, M
- LCD_ShowString(30,130,200,16,16,"KEY0:UPLOAD ON/OFF");5 C8 ]8 k, B4 |8 N/ ~, f6 e" k
- POINT_COLOR=BLUE; // 设置字体为蓝色
4 M! m/ I0 B! ~( l, g- z - LCD_ShowString(30,170,200,16,16,"UPLOAD ON ");
! [' s4 U& U0 O. r4 d; t - LCD_ShowString(30,200,200,16,16," Temp: . C"); 1 Z/ o- l8 L1 S3 }
- LCD_ShowString(30,220,200,16,16,"Pitch: . C");
8 v6 {, g; R* _* z, \- A3 G - LCD_ShowString(30,240,200,16,16," Roll: . C");
* \- P! E q K' f t9 i+ H - LCD_ShowString(30,260,200,16,16," Yaw : . C");
% S6 X% U4 E5 x2 ^- P! E - while(1)) \' s& w" u1 E& v/ E+ }
- {2 X* v: z5 x; B
- key=KEY_Scan(0);- q1 {( h) v: L( _$ a) S. T3 F5 k
- if(key==KEY0_PRES)- X# S0 u3 S) B$ ?/ q$ @
- {
/ U6 _8 W1 \! \7 E( a& R* E4 c; _2 G" u - report=!report;
" t' m7 g* n6 y7 ^! t - if(report)
7 @$ N" O3 d, P3 N6 \ - LCD_ShowString(30,170,200,16,16,"UPLOAD ON ");
. I; g" X9 `# E! C) @+ J - else
* W+ \8 H7 i2 c - LCD_ShowString(30,170,200,16,16,"UPLOAD OFF");' `/ t8 A- j3 g0 `, E' G8 L
- }
2 P' Z' Q5 r5 l/ s. q - if(mpu_dmp_get_data(&pitch,&roll,&yaw)==0)
5 N1 D" k# z1 d0 G' V& {5 N - {
2 ~& U7 e x& y: l - temp=MPU_Get_Temperature(); // 得到温度值 & V6 Z* f6 Q: J& F
- MPU_Get_Accelerometer(&aacx,&aacy,&aacz); // 得到加速度传感器数据6 C0 |5 Y9 O, c! g
- MPU_Get_Gyroscope(&gyrox,&gyroy,&gyroz); // 得到陀螺仪数据) j& Z) O* g* ^4 l4 f
- if(report)0 U/ A k0 Z1 s6 b% {2 L2 K" ^3 L5 [, L
- mpu6050_send_data(aacx,aacy,aacz,gyrox,gyroy,gyroz); // 用自定义帧发送加速度和陀螺仪原始数据# k5 ]0 A! N" d/ h
- if(report)
# w" n- Z5 \4 s4 |& d' i - usart1_report_imu(aacx,aacy,aacz,gyrox,gyroy,gyroz,(int)(roll*100),(int)(pitch*100),(int)(yaw*10));
2 T( z* X3 ]4 z$ A - LCD_ShowString(30,300,200,16,16," aacx: "); ! X5 M( z: S9 m& s9 K# J5 v" M
- if(aacx<0)
; Q2 M, n& w; |& m2 q - {) V0 J8 \# y2 v8 H
- LCD_ShowChar(30+48,300,'-',16,0); // 显示负号6 G3 r1 B' |- ^, i+ S2 D
- aacx=-aacx; // 转为正数6 W& ^9 E% |# `0 a+ f% l
- }
# \; w+ t' m6 ~- | - else 1 S6 Y2 i7 t) o1 l
- LCD_ShowChar(30+48,300,' ',16,0); // 去掉负号 6 W8 `9 N. k- E6 K6 M1 q+ F
- LCD_ShowNum(30+48+8,300,aacx,10,16); // 显示aacx & y. [! H3 {+ m' N" K; Y. @
- LCD_ShowString(30,320,200,16,16," aacy: "); ' L! n& q" @6 d! s# y
- if(aacy<0)
8 N" E7 {: X! v( O - {# C% o/ ~; o2 i; X# p/ H
- LCD_ShowChar(30+48,320,'-',16,0); // 显示负号3 z2 Q2 c" A9 o7 K/ b- f* V# A0 P
- aacy=-aacy; // 转为正数
8 Z( r( _- O* ~. C - }
) U8 x, s* F) m9 g - else 7 D4 b/ h$ g6 F
- LCD_ShowChar(30+48,320,' ',16,0); // 去掉负号 2 M$ x& r$ C+ X+ h" @
- LCD_ShowNum(30+48+8,320,aacy,10,16); // 显示aacy
4 n; ~! f3 ^% d, b" Q5 Q - LCD_ShowString(30,340,200,16,16," aacz: ");
' y9 ~% b0 N% v; @0 L( M4 ~ - if(aacz<0)
) Z. f6 B6 x$ V; Z. P: ` - {
6 i, c* ~. f1 k$ p) @ - LCD_ShowChar(30+48,340,'-',16,0); // 显示负号
0 I! ? q) r( ~7 ]0 K$ r* v - aacz=-aacz; // 转为正数0 j4 L) K3 c% Q+ A
- }6 O2 d) }& V# w0 p
- else
: V( D$ f2 o) Z. w; Y8 e - LCD_ShowChar(30+48,340,' ',16,0); // 去掉负号
; t/ s3 ?" X* G% R - LCD_ShowNum(30+48+8,340,aacz,10,16); // 显示aacz ) M! ~' J9 n; r
- LCD_ShowString(30,360,200,16,16,"gyrox: ");
/ w9 V6 q' o3 t; {/ F9 t+ p7 I& P - if(gyrox<0). l1 S+ K* o. |: v
- {
9 C o5 X$ E1 o" E2 r+ g9 K - LCD_ShowChar(30+48,360,'-',16,0); // 显示负号+ @2 B& y; N H
- gyrox=-gyrox; // 转为正数3 |8 h) d* ^% r, \
- }
. M3 U" c) l& m, E5 S. r# n - else
( N) y- W V% n0 d - LCD_ShowChar(30+48,360,' ',16,0); // 去掉负号
: l4 I) o/ a# w3 Y) D' C - LCD_ShowNum(30+48+8,360,gyrox,10,16); // 显示gyrox
/ j6 u- t% G5 ^5 d - LCD_ShowString(30,380,200,16,16,"gyroy: "); 3 v* N8 H3 U6 @# o9 X. T
- if(gyroy<0)
7 D E) T1 f% x2 T - {3 n3 ^% f; C& x& B) D H7 M8 Z- r
- LCD_ShowChar(30+48,380,'-',16,0); // 显示负号- t% v. N# Y- J. d
- gyroy=-gyroy; // 转为正数2 P( q5 H* n. E6 V; h
- }& P7 A+ n. Y" p4 y6 ~
- else
: G+ e/ r8 `2 p1 }! c - LCD_ShowChar(30+48,380,' ',16,0); // 去掉负号
* Y8 }+ t7 ~- \+ z3 d9 k" \$ m - LCD_ShowNum(30+48+8,380,gyroy,10,16); // 显示gyroy , A0 J3 p+ D+ v d) I
- LCD_ShowString(30,400,200,16,16,"gyroz: ");
0 A; Y$ i" Y+ t, _1 z0 C - if(gyroz<0) N! U9 |# }+ N, A( H
- {
, Y4 E' B2 Z0 Y: Q2 v% j9 s$ j - LCD_ShowChar(30+48,400,'-',16,0); // 显示负号( g$ Q6 b5 Q" f
- gyroz=-gyroz; // 转为正数- W4 @4 W$ G' Z; [
- }
/ ~- \- B" t" u. s7 s - else ! I6 v1 C9 W/ S! B9 v2 G9 ^
- LCD_ShowChar(30+48,400,' ',16,0); // 去掉负号
4 i3 i, w) u1 M% @: R+ d) N - LCD_ShowNum(30+48+8,400,gyroz,10,16); // 显示gyroz * C% n/ S* j' Z2 f
- if((t%10)==0)
3 @, ]8 C8 k; \+ \, Z$ J - { % v4 p; O3 E) C3 ?+ `% B$ V
- if(temp<0), b+ l( {) K; Q2 {
- {8 Y( U+ X9 i! R+ H
- LCD_ShowChar(30+48,200,'-',16,0); // 显示负号/ ?7 r+ B" R$ W6 B
- temp=-temp; // 转为正数2 x! W4 ?2 t7 g# \
- }
& T& H% @' I7 K* [% R - else
; `! V3 r( e0 f - LCD_ShowChar(30+48,200,' ',16,0); // 去掉负号
; J" P1 y- i+ C1 N3 ^$ f& L+ L - LCD_ShowNum(30+48+8,200,temp/100,3,16); // 显示整数部分
0 Q; z% b) K3 x$ ?) _4 }& j - LCD_ShowNum(30+48+40,200,temp%10,1,16); // 显示小数部分
. G5 M) {" s, o - temp=pitch*10;
8 h! [9 D4 q! U9 D) | - if(temp<0)9 m1 Z* X- n" G' r" d
- {; T' i5 k$ z9 U9 |+ q- l
- LCD_ShowChar(30+48,220,'-',16,0); // 显示负号) J# T* b/ i3 [
- temp=-temp; // 转为正数
}/ j2 [: z* J8 ~, s - }3 f' g+ C7 ?( j( F/ Q
- else
. K7 p5 M; F! w: o: r6 D, m - LCD_ShowChar(30+48,220,' ',16,0); // 去掉负号
. n( Y |7 Q3 d5 }* F: K - LCD_ShowNum(30+48+8,220,temp/10,3,16); // 显示整数部分
1 N5 ?$ U: a5 B7 E9 f- b2 U2 Y - LCD_ShowNum(30+48+40,220,temp%10,1,16); // 显示小数部分
2 E ~0 n& ?% k( _$ p# Y - temp=roll*10;
: x% N) c {6 ^7 b* N - if(temp<0)/ y1 h2 q: a8 l J8 B) ~" n. r! l
- {" N: Z2 r, S% [# W y& Y- W
- LCD_ShowChar(30+48,240,'-',16,0); // 显示负号! x+ g5 O; ^5 A# x. L
- temp=-temp; // 转为正数6 T, w9 H- a* U( }% F. P
- }
5 R" _" |9 L4 \: ^# x - else
8 I) j+ l, V* d+ r - LCD_ShowChar(30+48,240,' ',16,0); // 去掉负号 8 x* ^! x0 Z! V# \3 q( j4 v
- LCD_ShowNum(30+48+8,240,temp/10,3,16); // 显示整数部分
9 i' w9 s. O4 P& U" j - LCD_ShowNum(30+48+40,240,temp%10,1,16); // 显示小数部分
$ ?; V. l4 W x$ m$ Q2 U - temp=yaw*10;
/ @7 L6 I* i$ ?' s: K) j& L - printf("temp=%d\r\n",temp);& m# z3 h# Q; ?7 @, M8 r: B6 E
- if(temp<0)
- f; W% X2 Q; v9 R" v - {" j; v" s- N% g. a/ F
- LCD_ShowChar(30+48,260,'-',16,0); // 显示负号) r$ C" Z. x' e" }
- temp=-temp; // 转为正数
# V% F& m4 P, f9 R! P" [' v$ y - }
! }9 [/ I2 R# u/ M/ Y8 I, _: W - else
6 `8 X* T' a1 K+ f7 D# O! _ - LCD_ShowChar(30+48,260,' ',16,0); // 去掉负号 * e8 R9 z" N a, |% B
- LCD_ShowNum(30+48+8,260,temp/10,3,16); // 显示整数部分 3 {; ?2 t/ x; u" h" ^( i
- LCD_ShowNum(30+48+40,260,temp%10,1,16); // 显示小数部分 8 c( @# X- \* k2 z; }6 O8 D
- t=0;
4 K( n( n! `! N. | [$ u& Q, s( Z. E - DS0=!DS0; // LED闪烁
; C, o7 y; E- r/ Y3 h - }# k U7 f% G; d+ p% D1 w$ U# N
- }: c" u6 e( J, j; ]: u/ M4 w6 }
- t++;
7 [- v* Q8 m, c7 r4 a. l: W - }
+ b; u' h" T% N8 @/ u# {9 f - }
2 q$ e6 S( a& P7 }% s7 a - /****** Copyright (C)2020 Aaron. All Rights Reserved ****** END OF FILE *******/
复制代码
6 B( y5 S1 Z7 j$ y10.6 移植文件. ^+ H$ h/ ~# E* `+ [0 [
文件中代码太多,这里主要关注:
4 }6 c( ^% q" v# z- O1)inv_mpu.c源文件中定义了四个函数:8 K) Z3 M% v* I9 c8 S0 I h
# r+ @: P# T1 B/ H
- #define i2c_write MPU_Write_Len // 对应mpu6050.c源文件里的MPU_Write_Len4 W( c) f" ^- H+ Q: \
- #define i2c_read MPU_Read_Len // 对应mpu6050.c源文件里的MPU_Read_Len: r2 {0 o8 K; Y0 ?3 ~
- #define delay_ms delay_ms // 对应delay.c源文件里的delay_ms4 ~# T, K1 a- B. |9 E5 V% `
- #define get_ms mget_ms // 这是一个空函数
复制代码 * f3 H9 d4 l) C) @" P) I! ]
2)inv_mpu.c源文件中u8 mpu_dmp_init()初始化函数:& P- l b3 V- r6 a
8 P# G1 b- B, ]2 z
- u8 mpu_dmp_init(void)
. s, K1 @- t x! [ - {* J4 B7 I8 [. \1 D) a2 M
- u8 res=0;) K4 }3 D; v* |2 n
- MPU_IIC_Init(); // 初始化IIC总线
( W# b6 O7 I6 L+ m' f7 i - if(mpu_init()==0) // 初始化MPU60509 ]- ~" }) b' w' ^' C: Y3 p
- { ; E& z! l6 B" t5 r) k9 [
- res=mpu_set_sensors(INV_XYZ_GYRO|INV_XYZ_ACCEL); // 设置所需要的传感器# m1 X. G2 @, q5 i
- if(res)return 1; " h0 ~0 ?4 ]! w& S0 T' `
- res=mpu_configure_fifo(INV_XYZ_GYRO|INV_XYZ_ACCEL); // 设置FIFO4 f1 h! J" U% K: V. `2 |9 V
- if(res)return 2;
! I6 F4 U0 _$ F0 D9 n - res=mpu_set_sample_rate(DEFAULT_MPU_HZ); // 设置采样率2 q' D8 s o; k. T: T' R c& r6 j( x
- if(res)return 3; J8 T- h9 c0 M
- res=dmp_load_motion_driver_firmware(); // 加载dmp固件/ M4 O+ j& [& Y
- if(res)return 4; 2 \4 @5 ]* m4 W0 |) }
- res=dmp_set_orientation(inv_orientation_matrix_to_scalar(gyro_orientation)); // 设置陀螺仪方向' h4 _1 N# W8 M8 V5 Z5 Z
- if(res)return 5; * ?! g* S* p1 R5 C6 X5 d: {; C
- res=dmp_enable_feature(DMP_FEATURE_6X_LP_QUAT|DMP_FEATURE_TAP| // 设置dmp功能
! |5 \+ H' c% [: X- k0 e2 x# r - DMP_FEATURE_ANDROID_ORIENT|DMP_FEATURE_SEND_RAW_ACCEL|DMP_FEATURE_SEND_CAL_GYRO|
5 J, W* p# w: }/ d. Q - DMP_FEATURE_GYRO_CAL);
+ v$ l3 D f: l9 ~- _/ a7 {& g3 H - if(res)return 6;
$ }4 V7 m: P3 {* {" Z G# ` - res=dmp_set_fifo_rate(DEFAULT_MPU_HZ); // 设置DMP输出速率(最大不超过200Hz)
/ L5 A6 S+ [( c - if(res)return 7; . N% f/ o5 Y- ^% y6 p- \ x) ~8 E
- res=run_self_test(); // 自检( b6 i. J3 s0 d1 o
- if(res)return 8; . D: X7 Z' m4 O6 L: Q6 }& a7 E/ W! p
- res=mpu_set_dmp_state(1); // 使能DMP y- y+ t6 w7 f, G+ N" Z9 o q, r
- if(res)return 9;
# X4 Q. M1 R6 Z: H - }else return 10;
0 m! @6 F4 p3 L+ @ - return 0;
- W; z$ p# r, O6 ]& m - }
复制代码
! ~4 @* n. A+ J/ o+ o/ ~3)inv_mpu.c源文件中u8 mpu_dmp_get_data(float *pitch,float *roll,float *yaw)获取欧拉角的函数:. L# d% r x; A& q; `5 }
, D0 L W& N w; l5 H# u0 S( `
- u8 mpu_dmp_get_data(float *pitch,float *roll,float *yaw), s+ Q: f2 T& b h* [% N, m
- {: q2 m% _8 j" b Y' u
- float q0=1.0f,q1=0.0f,q2=0.0f,q3=0.0f;5 W8 e) J6 ~ B7 _4 z/ i% b( @, P
- unsigned long sensor_timestamp;
* v1 z3 z: R) {. n+ o4 H6 h; \; t% S- _ - short gyro[3], accel[3], sensors;
4 k0 h5 r- {0 i$ n- J - unsigned char more;
8 U* z- c3 j, K5 j) T0 M0 I$ a - long quat[4]; & e4 T4 G- p# A4 A1 ]
- if(dmp_read_fifo(gyro, accel, quat, &sensor_timestamp, &sensors,&more))
g7 V3 j1 l) \0 D9 H8 i* I - return 1; : S& g8 F0 F7 E+ X% ?; d4 _. q
- ors&INV_WXYZ_QUAT)
; z5 s, h6 ^( [5 I8 ]+ A8 h$ U# W& [ - {& D6 G/ F6 w Y/ ~3 d1 j9 i6 }
- q0 = quat[0] / q30; // q30格式转换为浮点数
. t" n. [3 c% F+ M6 S - q1 = quat[1] / q30;
( H! I, Y: L3 R2 U: f' g9 Z - q2 = quat[2] / q30;& ?& G( k% s! c8 i) d, G" @
- q3 = quat[3] / q30; ) _- P' p5 ^0 \- H/ G
- // 计算得到俯仰角/横滚角/航向角
) t7 ^) |- X' T& x/ N0 A Q1 q - *pitch = asin(-2 * q1 * q3 + 2 * q0* q2)* 57.3; // pitch
: ~7 c8 c1 i ~2 G( N - *roll = atan2(2 * q2 * q3 + 2 * q0 * q1, -2 * q1 * q1 - 2 * q2* q2 + 1)* 57.3; // roll
& W, o1 ^& R- ^* Y B - *yaw = atan2(2*(q1*q2 + q0*q3),q0*q0+q1*q1-q2*q2-q3*q3) * 57.3; //yaw
5 G! `+ N( G2 D% r+ o% ] - }* A: n ~# C, n# M/ g ~1 s: L
- else ; _+ k3 y7 r, |6 j
- return 2;
7 _+ D* ^0 L$ s3 W9 L% P - return 0;: `* k2 l) |8 X6 c
- }
复制代码
! g8 f! ^1 r' t6 H5 E# }十一、实验结果% @' { k# V7 i- Y/ j( U
该程序可用匿名四轴上位机软件实时查看6轴的原始数据和姿态数据,即欧拉角:航向角(yaw)、横滚角(roll)和俯仰角(pitch)。(这里就不放截图了)。
( {5 z0 d6 y1 Q% z! e另外在LCD屏上,也可实时查看6轴的原始数据和姿态数据,如下图:
8 t* h& M0 v' u& w6 a, N
# T) {7 N4 x v8 X9 g8 H
; f9 } l0 D- V% X8 S————————————————: e6 N( J* B- C9 B- [4 w) L9 v7 C7 Y
版权声明:天亮继续睡
" I9 ^6 `# R5 H9 y2 V% n
' c" u- \- [; ?2 ~) ?, W. T( x
' z2 U/ E0 l. X% \5 Q S# w# Z2 C/ v7 r+ [) r" v( a
|