最近给朋友调试了STM32F407驱动VL53L0的激光测距,安装在机器人上的,遇到一些问题,这里发帖纪录一下。8 c% M7 D8 P8 \" |+ l$ |& o
关于VL53L0的资料和代码在正点原子那里都有,但是正点原子只是驱动了一路VL53L0,很多问题都需要我们自己解决,一路的VL53L0非常简单,随便参考一下例程就能完美解决,但是一旦涉及到多路设备,就会出现一堆问题,最突出最主要的就是多个VL53L0的地址设置,把握不住就会出现只有一路能正常使用的问题。/ {% l7 s6 _4 E" m# T, b: d3 z
9 ~* @: A; N! ^, `2 P3 y- L; IVL53L0X 简介
2 o; {: c2 z. }& F0 n6 wVL53L0X 是 ST 公司推出的新一代 ToF 激光测距传感器,采用了第二代 FlightSenseTM技术,利用飞行时间(ToF)原理,通过光子的飞行来回时间与光速的计算,实现测距应用。较比上一代 VL6180X,新的器件将飞行时间测距长度扩展至 2 米,测量速度更快,能效更高。除此之外,为使集成度过程更加快捷方便, ST 公司为此也提供了 VL53L0X 软件 API(应用编程接口)以及完整的技术文档,通过主 IIC 接口,向应用端输出测距的数据,大大降低了开发难度。
3 Y8 I- q9 w2 N' OVL53L0X 特点包括:
' J! |8 ]" E0 G! Z( }①, 使用 940nm 无红光闪烁激光器,该频段的激光为不可见光,且不危害人眼。$ W: p7 _: p1 o
②,系统视野角度(FOV)可达 25 度,传感器的感测有效工作直径扩展到 90 厘米。
# ^8 T6 ~+ d+ @, u③,采用脉冲式测距技术,避免相位式测距检测峰值的误差,利用了相位式检测中除波峰以外的光子。
' a3 ]1 g4 z0 _0 r) U* |6 p④,多种精度测量和工作模式的选择。, B4 D$ s! a! C. n! C& e9 M1 @
⑤,测距距离能扩至到 2 米。
$ l4 R3 w/ ]3 L$ U8 Y# b( v⑥, 正常工作模式下功耗仅 20mW,待机功耗只有 5uA。
- `' j9 S! {6 W' D3 E9 y8 F3 [⑦,高达 400Khz 的 IIC 通信接口。
6 P; I R) u) |; g⑧,超小的封装尺寸: 2.4mm × 4.4mm × 1mm。) X) Y L; W% v. v0 J" k& r
VL53L0X 工作模式& X( r, f5 G: T( q
VL53L0X 传感器提供了 3 种测量模式, Single ranging(单次测量)、 Continuous ranging(连续测量)、以及 Timed ranging(定时测量),下面我们将简单介绍下:- W6 Y0 \# C- y4 \/ C6 E0 L# T! Y( B9 e
(1) Single ranging(单次测量),在该模式下只触发执行一次测距测量,测量结束后,VL53L0X 传感器会返回待机状态,等待下一次触发。8 n: S J2 k( q& d& i5 j
(2) Continuous ranging(连续测量),在该模式下会以连续的方式执行测距测量。一旦测量结束,下一次测量就会立即启动,用户必须停止测距才能返回到待机状态,最后的一次测量在停止前完成。
- y2 P& f4 _, O7 M6 v R(3) Timed ranging(定时测量),在该模式下会以连续的方式执行测距测量。测量结束后,在用户定义的延迟时间之后,才会启动下一次测量。用户必须停止测距才能返回到待机状态,最后的一次测量在停机前完成。根据以上的测量模式, ST 官方提供了 4 种不同的精度模式,如表格所示: 
, X4 Z( V8 e( d- ?" D
从表格可以看到,针对不同的精度模式,测量时间也是有所区别的,测量时间最快为高速模式,只需 20ms 内就可以采样一次,但精度确存在有±5%的误差范围。而在长距离精度模式下,测距距离能达到 2m,测量时间在 33ms 内,但测量时需在黑暗条件(无红外线)的环境下。所以在实际的应用中,需根据当前的要求去选择合适的精度模式,以达到最佳的测量效果。
: y# V. ^, ^8 O% a) p- M' I以上资料来源于正点原子的《AN1703C ATK-VL53L0X 激光测距模块使用说明》。这里摘录一部分,方便进入主题。
3 I8 |1 T' `0 {1 d7 O" I) I因为今天是调试多路的VL53L0X设备,这里不完全借鉴正点原子的例程,但是官方提供的驱动我们还是必须要用的。
: H* E. U) h8 @3 N0 A4 S如果想要快速上手,文末直接下载我的代码,我的驱动库经过自己的修改,和正点原子有些不同。& y# T* A/ c( d: V
我们直接从代码入手吧!
2 V: W; `/ q" {, |: H在初始化VL53L0X之前,我们必须初始化IIC外设,此次遵循正点原子的方法,用模拟IIC。 - #ifndef _VL53L0X_I2C_H8 I3 @2 s. l; r" Y. E* L
- 1 P+ l' g$ N' f: M; D! r
- #define _VL53L0X_I2C_H
! b6 G% S9 ~! N -
6 E4 c0 ]3 h `& h' G% L& ^ -
' N0 S: l O6 \. O5 _6 h% }" S - 3 D/ c4 ~5 p# P1 d2 m, w- u
- #include "stm32f10x.h"# X0 ^* ?( n+ j7 j
- 5 B. U0 r& @: D8 V
- #include "stm32f10x_i2c.h"
8 ~( g8 y6 N1 {) F$ I0 k -
( P$ N2 C! ? Q7 a2 [1 {9 ` - / R% w! [& S Z8 u% o
- 8 T* f1 {+ J- G/ t0 ?
- //四个VL53L0挂载在同一个IIC总线下,所以使用四个片选信号--2019/10/30, d, [9 f2 X* L
-
8 h, E" I! R' ~. x% X - //!!!!!!!注意:重新使能设备后,设备iic的地址会恢复为默认值0x52--2019/10/30
* y/ D, i8 h+ x; I9 I3 H2 r b' ?: J -
: e+ t, y+ I( U: A+ i2 Z% Y% c* X - //VL53L0 0& v) v0 e2 q3 p
-
! _/ R, Q7 i" b: Y4 h - #define I2C_SCL_GPIO GPIOB3 `; _2 m: \7 Q3 Y$ S( d
-
& R E$ r' Q, R% L - #define I2C_PIN_SCL GPIO_Pin_8
7 ?) \: B' g( p% I5 t4 K5 y% S3 L! Z s -
( `; b5 U# g0 {" ]+ `# [* _ - #define I2C_SCL_HIGH() GPIO_SetBits(I2C_SCL_GPIO,I2C_PIN_SCL)
( x: x. ]0 @9 g: Q8 i3 W -
. p- w2 p( {9 R2 \$ C - #define I2C_SCL_LOW() GPIO_ResetBits(I2C_SCL_GPIO,I2C_PIN_SCL): z) A3 @/ W# P: m6 C) R
- ! X8 P* |& B( c1 u5 E: ]
- % T6 k8 F" z" T N( Z
-
: k4 c, W# T) s& ~ - #define I2C_SDA_GPIO GPIOB
& e% d3 C+ E9 s; H -
3 x2 ?1 [8 i3 M9 s6 i" l) N - #define I2C_PIN_SDA GPIO_Pin_9
6 x( {8 _0 E' s - * ]# e2 m0 f2 l, W1 a* F9 v
- #define I2C_SDA_HIGH() GPIO_SetBits(I2C_SDA_GPIO,I2C_PIN_SDA) L6 I/ ~' T# x
-
5 I/ X) R- B5 E - #define I2C_SDA_LOW() GPIO_ResetBits(I2C_SDA_GPIO,I2C_PIN_SDA)
4 E! P1 f6 H( K; C5 h) M -
: ~- D4 u9 Y* K2 I - #define I2C_SDA_STATE GPIO_ReadInputDataBit(I2C_SDA_GPIO,I2C_PIN_SDA)
) G! i$ F& Z" M- y$ W- l: F$ z" q -
, M3 l4 I n" ~; N. _( H* U# g - $ x$ _; e c; p2 p- c5 b0 h5 }+ R
-
( W! U; I' n1 p - //片选使能--2019/10/30
; C7 u7 i8 _" O/ x1 b- k -
' J9 O+ ~2 `8 f" `2 s3 B$ ^7 o - #define I2C_X_GPIO GPIOB* p9 M. g! E$ k1 B1 H
-
# N* G4 j# h" `' a: d+ m - #define I2C_PIN_X0 GPIO_Pin_12
- W, K G3 N. \! d -
# j0 c7 }) k( x) V6 L7 [1 d - #define I2C_X0_HIGH() GPIO_SetBits(I2C_X_GPIO,I2C_PIN_X0)
/ s ~- Z+ b- f% i -
; W, s) x3 Z% N9 p5 \$ [ - #define I2C_X0_LOW() GPIO_ResetBits(I2C_X_GPIO,I2C_PIN_X0)
' t! w7 M: t( g. }5 T& E - 2 W/ c) a1 \) m- m7 F
- " U/ V- Q9 ?9 G! g
-
' ^8 c1 B. u- s: X' J0 [ - #define I2C_PIN_X1 GPIO_Pin_13
2 p5 l6 ]$ x. w* F6 _9 E t -
8 E+ s9 j) p% _: x- m: `" Q, m. {5 Y8 k' Y - #define I2C_X1_HIGH() GPIO_SetBits(I2C_X_GPIO,I2C_PIN_X1)
0 b1 t j; E* S- q - # Q4 d: Z/ [! { G
- #define I2C_X1_LOW() GPIO_ResetBits(I2C_X_GPIO,I2C_PIN_X1)* C/ V3 Z- {- C, A7 c( u
-
; M+ e1 @4 h1 U - 7 h, V. n5 V5 d& c
- 5 |+ h! `: q$ ^6 u7 l% n3 K
- #define I2C_PIN_X2 GPIO_Pin_146 Z; O, M# A+ v/ [; g
-
* v5 L) w4 ]1 w U; u) Q! W9 i - #define I2C_X2_HIGH() GPIO_SetBits(I2C_X_GPIO,I2C_PIN_X2) R* v6 _) {/ k( N) |
-
' L- [/ o5 ]% V: E" k - #define I2C_X2_LOW() GPIO_ResetBits(I2C_X_GPIO,I2C_PIN_X2): S: m6 `, V. n2 Y, A+ @% ]
- 0 b- R. h* i, b
-
; V' D: f+ j1 d% Z' Z2 i -
* [7 U% y# m- a' ` - #define I2C_PIN_X3 GPIO_Pin_15
) L- C; v& M6 o - ) e. j5 I: N/ C. y
- #define I2C_X3_HIGH() GPIO_SetBits(I2C_X_GPIO,I2C_PIN_X3)
7 c W) U5 N$ s! e5 r+ o -
8 W1 a c, y6 r - #define I2C_X3_LOW() GPIO_ResetBits(I2C_X_GPIO,I2C_PIN_X3)
1 R5 \ Y3 s1 p9 O -
1 ]$ w) k' ?+ P6 N( k' v -
y* _% W- \9 J3 H2 } -
# l3 i( w" Q e( R, b, [ - void i2c_init(void);4 @5 W) R( z9 L6 Q- H
- & }# c" [8 ~8 f2 b8 @" ?; ^
- uint8_t i2c_write(uint8_t addr, uint8_t reg, uint32_t len, uint8_t * data);. U$ }* q, r- |" \/ |
- 5 a1 Y, F& b- @7 b5 [9 r
- uint8_t i2c_read(uint8_t addr, uint8_t reg, uint32_t len, uint8_t *buf);9 ~4 a! Y0 P. g0 E6 ^
- E; L2 C) W) f0 O R- v+ y2 M' R
-
/ F' d5 W& I) ~; m+ l" n& G -
+ v% @' P/ O' F* x6 _3 @5 v7 n2 L - 1 L3 p* W7 ~; h$ N# d6 }
- * e) o- I$ k, l) b# z. B' J; H
- #endif
复制代码- void i2c_init(void)
1 {, w: H$ V. B8 L( n8 U - + a" |+ C/ e C0 I7 b% A' M
- {
0 y. l, ]- ~/ b% q - 5 i* ~7 h2 h7 F/ X
- GPIO_InitTypeDef GPIO_InitStructure;
2 H! x0 ^- j- X -
4 G8 j" K' V3 }+ ?4 a2 n( [ - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);3 m& b" k2 }/ R9 }' B# V
- # ^# }& e& n1 T0 m& q. `% j9 |
- : \: k3 y! ~2 p+ h3 }
- + S) `8 r2 U: C( V7 J
- //模拟iic配置
: d& P- P; ?' n, q- x -
/ X0 Q* f: L* ]( A6 Q1 {/ E - GPIO_InitStructure.GPIO_Pin = I2C_PIN_SCL;
6 T8 T7 [: f5 u2 b0 k -
* z; c1 z4 m( \9 n$ Y: g1 v2 l - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;- L" Q+ t4 B) O/ G0 A- Y
-
5 j3 M; ] R6 _ - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
3 t x r3 j j' Q, |( G -
% I$ m% ]2 w! S - GPIO_Init(I2C_SCL_GPIO, &GPIO_InitStructure);
+ T- Z. [) E3 q1 P# S# S3 P, u - - @9 c. m7 _: Z8 u/ w/ ]; l- X
- $ ]+ p( f" C3 a7 q
- # ?& v6 I! u2 l
- GPIO_InitStructure.GPIO_Pin = I2C_PIN_SDA;
. c! E+ \8 \' o: e2 S( b: }- D - # k( W$ {7 H7 n& ~! ?
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
" X. [7 U9 T/ O d* ?- X - 5 \4 T$ ^5 @& h& U2 U
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;. r% z p' k& P- X4 a
- 3 p9 g- @/ A! {# N/ F' d$ F* r
- GPIO_Init(I2C_SDA_GPIO, &GPIO_InitStructure);3 W& n* Y F. [$ T+ O Z
- , }7 {! ]* O" m" i
- , G& t& O6 p( ?5 j
-
+ q! [- h4 ]3 k$ A2 _. R2 s - //片选使能配置
) v! _) L; [8 I4 F1 q) i1 E4 g! x& H -
& D9 u* Q7 N2 O - GPIO_InitStructure.GPIO_Pin = I2C_PIN_X0;
: Y, d N' W0 c, K2 |# h* Y) P -
5 f8 A; U3 g3 H7 Q9 s/ M4 o - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
7 ]- D2 P$ D f - . w4 I; w+ W! I# }3 c
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;4 ?8 b; ~5 W+ f$ n3 O1 n
-
i1 l9 D, c( B/ w - GPIO_Init(I2C_X_GPIO, &GPIO_InitStructure);
$ d1 j/ b( T. _8 | - ) b# g7 q2 x; l3 \
-
$ D1 f* ?" K: D, v% q5 ?! D8 `2 q - 4 `7 j! \% O6 j" ]% F7 @
- GPIO_InitStructure.GPIO_Pin = I2C_PIN_X1;9 f* l$ \ v8 a; l3 [
- 0 Z, ^: r4 F- `( ~2 R7 C
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
2 O4 n* l1 G8 N4 g - - f- e/ W. X6 i/ X- G
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
& |9 J+ z& M! ? - , p" j1 J2 w5 G
- GPIO_Init(I2C_X_GPIO, &GPIO_InitStructure);
: r+ v! H; Y+ u) r5 o - ( Q3 L5 A* t+ s/ o
- ' V+ F& d& y! q/ |& Z# ?: x% y
- 5 u8 X+ C! k3 {0 {5 Y
- GPIO_InitStructure.GPIO_Pin = I2C_PIN_X2;
7 T- J& m, h3 T! p -
) R& A- l+ a- {# C9 B) Q1 p - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;6 U& e" n2 E2 V8 P
- : T3 E% P' P- Y$ b* F! n# p: t
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
' u3 K( x: I( Q/ ]& d8 _7 v -
9 \; M9 S/ H |2 H1 c" v - GPIO_Init(I2C_X_GPIO, &GPIO_InitStructure);( L. K% `: R2 O
- 3 h, d8 T, \9 l. `; e; h5 V
- ; h/ v1 u4 S7 p
-
6 h, ]4 W; i4 b p' G$ [' @1 ]9 B - GPIO_InitStructure.GPIO_Pin = I2C_PIN_X3;
: p# F0 G# {- C. h; J - & f* {/ w( M$ ~9 }" D( v5 U5 ?
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;* S3 V) D7 ~/ |: E" H) ]: U
-
! p, k- ]: E# o% o- @9 F - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;4 y3 ]/ r; Y! _ \2 M
-
% J, e0 ]7 G( ~* e - GPIO_Init(I2C_X_GPIO, &GPIO_InitStructure);+ i# {% O1 Z0 _* T0 b1 M$ \5 [; c: V
-
( ]. l5 s# d/ A0 A% }! c# Y" V/ M" ? H - 3 o( A8 H# v3 B# q
-
. X0 D6 G* h B7 H/ u - I2C_X0_LOW(); 6 F) S" W8 W/ S& r. ?3 F9 h
- . z/ i& t( w& |# R3 K
- I2C_X1_LOW();# ], y& x; k2 F9 w+ ~1 ]1 l; {7 z! _
-
8 N! H- _. ]' s' r ^+ h - I2C_X2_LOW();
7 m3 a9 H4 |5 H7 }. ?( W9 V$ ~8 | -
' P, c9 k3 c9 |, b9 [/ i8 T% d - I2C_X3_LOW();
' b( l$ Z% Z4 I+ u; P -
3 _$ M$ q8 U- |$ P- k0 K - delay_ms(20);4 O/ c- H+ Z- i
- # q$ W7 P3 y9 V
- }
复制代码 0 W8 ~( {& l# w: n
; X7 f8 [% |& C! h1 f
在模块初始化时调用IIC外设初始化,同时初始化4个测距模块。 - 3 `7 M. |/ |% u4 Z$ E
- {4 a. T5 k" R6 ]8 s" B3 A5 G
- 9 o7 w# [* z5 L) Y& x2 e
-
! j6 t3 [6 A, ~5 C" q* U -
3 y+ q5 q2 u1 S$ F5 S2 N0 Z0 K' X - VL53L0X_Error Status = VL53L0X_ERROR_NONE; //初始值赋值为0 ]( l( Q4 `$ `
- & j5 x, f4 H% z: B, }+ d! k
-
6 {' X0 E0 @4 c) R- p7 { - 2 G) P* v& r* i0 H( W+ @) u. l
- //初始化一定按照这个顺序执行,否则不成功6 F _* B+ a! h6 Q) f
-
& `. c+ S. E& s7 j9 A) N - VL53L0X_i2c_init();
7 J4 L( |. x3 u6 C/ \5 R/ D -
+ [* t) r8 W: |9 ~" O" w3 I# ^ - vl53l0x_initX(&vl53l0x_dev0,0);
; M d. \! ] n4 T9 F. S - 6 b: S* @7 g4 K q& [% q* c/ b/ f
- vl53l0x_initX(&vl53l0x_dev1,1);
& w& {: ]- S8 G- ~/ u( ? -
3 ~% y( w( }9 t8 t - vl53l0x_initX(&vl53l0x_dev2,2);, q. S, d$ o: X7 F5 R& B
- ; [% R2 @# b7 |9 z$ X
- vl53l0x_initX(&vl53l0x_dev3,3);* M1 q# h& M/ E
- ( D* \7 Q I* M# O
- ' Y$ U! [ E- h8 I
- , G0 V" D; K! l8 U! n8 m$ R+ C) L. i
- return Status; //返回0
: }4 q3 {! Z" O/ S; }) |* _3 v - 8 o" ?+ H) J& D/ ~, e
- }
复制代码
. I& ]& q$ H# x: K' Q( e+ D7 \# \% p! w7 l7 ^
在vl53l0x_initX()函数便去别去正点原子的驱动,这里是全文的重点,很多单设备发展到多设备这里都会出问题,在初始化设备时一定要设置设备的IIC地址。
; N0 _3 F3 n# C$ H& E u6 z//单个VL53L0初始化
( S! @, T, r$ b. t. e# O5 s3 e" HVL53L0X_Error vl53l0x_initX( VL53L0X_Dev_t *pMyDevice ,u8 vl53l0_x_id)) I, g3 X9 B4 ~, `/ i
{
5 b+ A+ X7 E! Z! K. u VL53L0X_Error Status = VL53L0X_ERROR_NONE; //初始值赋值为0
- u4 w# |$ b, _9 A- N( l
% E/ K* p8 p+ s* B pMyDevice->I2cDevAddr = 0x52; //iic地址 0x52是默认地址,要初始化必须先写0x52,才能初始化,之后再通过软件修改, o' A" C. h6 I6 I( ~. l2 Y
pMyDevice->comms_type = 1; //选择IIC还是SPI iic=1;SPI=0
' Y: ]: F# G3 z c pMyDevice->comms_speed_khz = 400; //iic速率 9 D5 U, p" \' W4 _9 P, V7 k% f
0 N+ \7 P2 ~9 I ! ]/ E6 t7 {; d4 @3 l! w
//正点原子的VL53L0用户手册上写明了再次使能时地址会恢复为0x52,所以只能使能一次,设置好地址即可,这里是核心
! c7 H( e# @# H$ L! u% _ switch(vl53l0_x_id)
- s3 p) m- q8 k4 x6 O1 N: ~9 h4 G {9 }- K+ S5 ?' I, f( v
case 0:
: `6 b% [0 i& T* ?2 N( ]/ s, { I2C_X0_HIGH();
# z( z3 Y6 d7 R& W delay_ms(20);
' u0 P5 j* e. W; G. N) b vl53l0x_Addr_set(pMyDevice,0x60);//设置第一个VL53L0X传感器I2C地址
$ y: E0 Q9 r3 E( F5 K+ C6 B, p3 A5 N break;
! q5 Z u8 R* y2 R( b' U case 1:
. e5 n2 z! E# w( r. W5 l3 i" P. p I2C_X1_HIGH();
& V! S9 C8 G$ x" _5 ~* Y c. X delay_ms(20);
$ y3 G; `0 S$ k8 B vl53l0x_Addr_set(pMyDevice,0x62);//设置第一个VL53L0X传感器I2C地址; O2 D+ O" r. |) h
break;
+ y5 p% J% |6 S0 o9 z& w case 2: / }% d) J( l. ~2 Y4 G8 _
I2C_X2_HIGH();
( `5 K8 z# t0 Q- ^9 [ delay_ms(20);
/ R. b" i' V9 h3 _1 [/ ` vl53l0x_Addr_set(pMyDevice,0x64);
% y0 _1 J% D+ V7 Z9 L8 z# m break;
2 q# b+ Z* `' v- ^/ {& p$ c case 3:
9 R: Y, }- |' ^$ W+ c1 i I2C_X3_HIGH();
9 a3 d! p4 g0 f+ g# e. I7 w$ w delay_ms(20);
/ N: K5 E( ^* K$ x/ T vl53l0x_Addr_set(pMyDevice,0x66);- ?' v/ S5 ]+ h" O& F; {0 z" K& E$ i
break;
8 f/ Z) C# b" U% s5 o- o }& }/ e8 q$ w+ b4 X
, f- k6 v; k5 t6 w7 X7 o Status = VL53L0X_DataInit(pMyDevice); // Data initialization //VL53L0X_DataInit:一次设备的初始化,初始化成功返回0
" T* r: @! _& l if(Status != VL53L0X_ERROR_NONE){ //判断如果状态不为0 打印错误信息7 S" f3 n8 p3 N2 j) T
print_pal_error(Status);/ I: X& r" H4 m' [, @
return Status; // 返回错误值 可通过此值DEBUG查找错误位置
2 }1 P3 r. l* q! }- Q/ L4 s }- Z v5 c- Y$ z U+ V) g
: R0 I( t+ a- {0 z# ^) t Status = VL53L0X_GetDeviceInfo(pMyDevice, &vl53l0x_dev_info); //读取给定设备的设备信息" X! C- ^7 i% Q$ p; E0 ^8 T
if(Status != VL53L0X_ERROR_NONE){* g, W9 e# N3 |; ]# E5 p. L
print_pal_error(Status);
$ T. l, }$ _5 s return Status;
. a* O- c# B1 G J }
7 H) s! k9 ^3 V- W2 j4 q printf("VL53L0X_GetDeviceInfo:\n");
5 W q& F, j4 B0 r' c printf("Device Name : %s\n", vl53l0x_dev_info.Name); //设备名8 R6 j& @1 I0 d) b {8 {2 U
printf("Device Type : %s\n", vl53l0x_dev_info.Type); //产品类型VL53L0X = 1, VL53L1 = 20 ^0 g! J( l8 _( }( A- H
printf("Device ID : %s\n", vl53l0x_dev_info.ProductId); // 设备ID+ N9 i: l3 ?+ l- ~: G8 g- K5 Y
printf("ProductRevisionMajor : %d\n", vl53l0x_dev_info.ProductRevisionMajor);
7 b* c: F S: C" R2 G$ q printf("ProductRevisionMinor : %d\n", vl53l0x_dev_info.ProductRevisionMinor);. D2 t: F6 c6 L, Z
) {5 U0 ]7 x& N( ] z q G- Y0 ? z/ ]
if ((vl53l0x_dev_info.ProductRevisionMajor != 1) && (vl53l0x_dev_info.ProductRevisionMinor != 1)){
; A% k4 N( a/ N3 {) B printf("Error expected cut 1.1 but found cut %d.%d\n",3 d, Q" p* a9 O3 j, I+ x2 q8 L/ Z
vl53l0x_dev_info.ProductRevisionMajor, vl53l0x_dev_info.ProductRevisionMinor); Q5 h: s, {7 U8 L( Z. R( t: i/ c
Status = VL53L0X_ERROR_NOT_SUPPORTED;5 \% C) Q# L2 R) l C
print_pal_error(Status);4 m/ A$ C% p# C: C& z9 {
return Status;4 L( A3 h; p/ ?: x, B) M
}3 v4 `& r7 F) } O
[6 Q0 Q. ~7 k$ x: t Status = vl53l0x_measure_init(pMyDevice); //测量配置# L! Z0 Y5 B9 S0 E, Q
vl53l0x_status = Status;
3 A( Q. O& a; } if(Status != VL53L0X_ERROR_NONE){ //判断如果不为0打印错误信息
0 }8 d1 {4 w! A1 K print_pal_error(Status);
" @3 M4 F' D/ b6 O: `3 L return Status;
+ p- x4 B+ S3 }' g+ B9 r3 a } # r/ m E# Z3 ^" a/ [5 l5 x3 L
} 模块的初始化顺序是:使用默认地址初始化设备---修改传感器IIC地址---再次初始化---测量配置
2 I2 K8 k+ x! X9 e. d. L所以在这个传感器的初始化中我们先用默认的0X52地址将VL53L0X模块初始化,初始化完成后方可修改其地址,这里使用SWITCH函数判断用户配置的地址,避免函数重写,减小代码尺寸。修改完地址调用VL53L0X_DataInit()函数进行模块的再次初始化,使修改生效。注意:VL53L0X不能保存地址,如果掉电后地址会恢复为默认的0X52,同时修改完地址后只能执行一次初始化,更多的初始化次数会也会导致地址复位。这在硬件的处理上要加倍注意。, F2 l" `" [1 h3 j7 N. F3 G
在这里我翻车了,因为硬件不在我的手边,我都是远程帮助调试,没看到硬件,我的朋友一直反应各种问题,最多的就是测距有问题,测出的数据都是错的,或者只有一个传感器可以使用。我检查了很多遍的代码,始终找不到原因,还好他自己也想到了硬件的问题(因为他们硬件干过很多错事,都是一些小白容易犯的,但是那个老员工比较粗心,也会犯错),最后发现是线的质量太差,线的长度太长,IVL53L0X模块安装的位置不好,因为模块安装在可动部件上的,导致每次移动都会导致模块短暂的掉电,导致地址复位。后来加装模块的减震装置更换屏蔽线解决问题。* j% j) D# t% g$ o6 H6 z5 ?: \/ e
复位完成便可以测试: 
! h3 Q4 G2 d+ G; a
) h3 Q- `1 U& E- E" z) g
- VL53L0X_Error vl53l0x_start_single_test(VL53L0X_Dev_t *pdev, \
3 o$ o7 `' q* w; I7 }4 s" f/ N - ' {, U7 A6 n* y$ B- K b
- VL53L0X_RangingMeasurementData_t *pdata)6 |4 Z+ B- e$ L# r
-
6 z- D3 ~5 P; w! X - {
4 C* }1 z& \7 W8 y: a1 e - * _6 n+ c8 v' P. W. t* E2 b
- int i=0,j=0,sum=0;9 M$ L8 R F. @0 f4 E, ]. C
- - P# _" q( H' y5 P# ]
- VL53L0X_Error status = VL53L0X_ERROR_NONE;
4 m& B" }* t5 q- }. { -
/ n+ p( L4 T4 z i/ f7 V/ c6 D1 m - $ S0 w) T# z4 S1 M1 O
-
' I- e' P! q% m- [ - if(vl53l0x_status != VL53L0X_ERROR_NONE)8 d5 I- N. a0 S% f" @& s; a; L
-
) n/ d2 Y$ x8 _! B; b' k - return vl53l0x_status;
8 V# y. j& D* K! o8 G" m) _ - 4 B) s' |) V" C7 R
- $ e4 h# D3 F) ]' s0 Q/ ~, O/ F
-
& [1 Z( x/ O ]% O' h - status = VL53L0X_PerformSingleRangingMeasurement(pdev, pdata); 执行单次测距并获取测距测量数据& C m2 ^( j: u, X4 Y" Z, w
-
) J5 s5 p! C# j- ^& M - if(status != VL53L0X_ERROR_NONE){
: E+ f! K+ ~4 d: X/ l - 2 D, a& a! M( Z2 X0 x& m
- printf("error:Call of VL53L0X_PerformSingleRangingMeasurement\n");5 N: n I% J5 S% Q, W& h+ o$ P
- 4 \6 c2 j! _' q- T$ L5 R& ^
- return status;: w- J4 z* [- l2 s; A3 _2 b/ L% m
-
- Q$ }; a' U: n; D( \ - }
; {$ C# f6 e( F5 w: W5 S/ ~# A - * m2 r0 Y% |% R. E3 ^
- . `, M% @; L1 \. u; Y
- ! v# h& a: V# h$ ?! q8 a" T4 t- }$ k
- for(i=0;i<5;i++)1 N' A/ ]+ P$ ^6 L; P
-
( f M0 _' E- E& r, @ - sum+=pdata->RangeMilliMeter;
% W9 T- w; R4 p5 T- N2 Y! p/ [ -
9 W1 C" m1 y4 m W" L @ - pdata->RangeMilliMeter=sum/5;
, J- _; z( l5 K# N - 9 E6 l: J# t+ Z1 B
- printf("%d\r\n",pdata->RangeMilliMeter);
# K) j0 O1 k& M( [+ f( P4 m" B -
& A* _% T/ S. N9 ]: a - return status;: \' ~4 ^0 `, R% N7 L( k3 M, E0 A
-
1 ~- {5 ^! Q% l) z5 {, i - }
复制代码
' O6 g: a6 ~" r( Z9 m$ t/ o, L) G1 l, B! y0 w" C) Q0 R; P
打印测试结果,通过! 
% e2 J: b0 N0 W$ ] n* W5 v' u6 l
主函数循环测试,因为项目对代码的速度要求不高,所以一些状态判断代码中还有保留,这里跟着原子走,没做太多改变。
% ?5 K! \: h5 x( L. Y因为这个项目是帮助朋友做的调试,而且他们的项目还在研发期,太多的东西不能介绍,照片啥的都放弃了。一个简短的帖子,希望能帮到大家把握住该模块,蟹蟹。
+ j+ h- K" X2 @2 ~---------------------
2 ?" H/ {# U5 K! `作者:呐咯密密 9 b0 s6 G1 \4 R, g& h/ K& ?
|