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