最近给朋友调试了STM32F407驱动VL53L0的激光测距,安装在机器人上的,遇到一些问题,这里发帖纪录一下。
# |. Q" C$ X# `关于VL53L0的资料和代码在正点原子那里都有,但是正点原子只是驱动了一路VL53L0,很多问题都需要我们自己解决,一路的VL53L0非常简单,随便参考一下例程就能完美解决,但是一旦涉及到多路设备,就会出现一堆问题,最突出最主要的就是多个VL53L0的地址设置,把握不住就会出现只有一路能正常使用的问题。
9 f, x/ P2 m! {
; g- i" ?7 L% q& b } H$ ]VL53L0X 简介
% G0 i. _: ^" x9 WVL53L0X 是 ST 公司推出的新一代 ToF 激光测距传感器,采用了第二代 FlightSenseTM技术,利用飞行时间(ToF)原理,通过光子的飞行来回时间与光速的计算,实现测距应用。较比上一代 VL6180X,新的器件将飞行时间测距长度扩展至 2 米,测量速度更快,能效更高。除此之外,为使集成度过程更加快捷方便, ST 公司为此也提供了 VL53L0X 软件 API(应用编程接口)以及完整的技术文档,通过主 IIC 接口,向应用端输出测距的数据,大大降低了开发难度。9 d% L$ ~% z% \& ^) t& L* V1 c6 B
VL53L0X 特点包括:2 [& r% o1 l# |; H
①, 使用 940nm 无红光闪烁激光器,该频段的激光为不可见光,且不危害人眼。
9 I% g' E K0 `9 q' A$ G②,系统视野角度(FOV)可达 25 度,传感器的感测有效工作直径扩展到 90 厘米。3 I4 o1 C6 X/ N. G$ S' |4 D
③,采用脉冲式测距技术,避免相位式测距检测峰值的误差,利用了相位式检测中除波峰以外的光子。6 ^0 A1 U/ [5 ~* y6 Z
④,多种精度测量和工作模式的选择。& Q! J. q' u$ Q
⑤,测距距离能扩至到 2 米。
4 b5 j% S {+ l) Q⑥, 正常工作模式下功耗仅 20mW,待机功耗只有 5uA。
; l5 C4 D/ C& [5 T; O& U( S⑦,高达 400Khz 的 IIC 通信接口。) M( O* E" g5 V# R1 i7 N
⑧,超小的封装尺寸: 2.4mm × 4.4mm × 1mm。. O+ ?' p( f0 t0 e5 {; I
VL53L0X 工作模式
7 P' }. @, l& M4 [' cVL53L0X 传感器提供了 3 种测量模式, Single ranging(单次测量)、 Continuous ranging(连续测量)、以及 Timed ranging(定时测量),下面我们将简单介绍下:
7 I" N X! W) J4 b- O# ]! b% b(1) Single ranging(单次测量),在该模式下只触发执行一次测距测量,测量结束后,VL53L0X 传感器会返回待机状态,等待下一次触发。. {+ @; F) B7 M/ A- B6 \
(2) Continuous ranging(连续测量),在该模式下会以连续的方式执行测距测量。一旦测量结束,下一次测量就会立即启动,用户必须停止测距才能返回到待机状态,最后的一次测量在停止前完成。0 g+ X+ R% d* H
(3) Timed ranging(定时测量),在该模式下会以连续的方式执行测距测量。测量结束后,在用户定义的延迟时间之后,才会启动下一次测量。用户必须停止测距才能返回到待机状态,最后的一次测量在停机前完成。根据以上的测量模式, ST 官方提供了 4 种不同的精度模式,如表格所示: 
/ [: A2 \. V8 {/ ~% U1 V7 s5 I# s5 f
从表格可以看到,针对不同的精度模式,测量时间也是有所区别的,测量时间最快为高速模式,只需 20ms 内就可以采样一次,但精度确存在有±5%的误差范围。而在长距离精度模式下,测距距离能达到 2m,测量时间在 33ms 内,但测量时需在黑暗条件(无红外线)的环境下。所以在实际的应用中,需根据当前的要求去选择合适的精度模式,以达到最佳的测量效果。; L8 r; s! z+ g! ]3 R) I, l
以上资料来源于正点原子的《AN1703C ATK-VL53L0X 激光测距模块使用说明》。这里摘录一部分,方便进入主题。- r+ H% R4 i; k! B. o. V
因为今天是调试多路的VL53L0X设备,这里不完全借鉴正点原子的例程,但是官方提供的驱动我们还是必须要用的。+ c: \3 g8 D# b" u( B
如果想要快速上手,文末直接下载我的代码,我的驱动库经过自己的修改,和正点原子有些不同。8 G9 ~/ l0 U6 S
我们直接从代码入手吧!
4 P$ W$ x5 s# E( x( ^在初始化VL53L0X之前,我们必须初始化IIC外设,此次遵循正点原子的方法,用模拟IIC。 - #ifndef _VL53L0X_I2C_H
4 a5 M1 W& @. o) J z8 j' U: J - 9 i# L- M' @$ Y- m- @' z: u0 L2 C
- #define _VL53L0X_I2C_H
9 g% H7 z* r- C0 c" ~, e - ; N0 q, c! y# C
- 0 ]" K" I5 P! }6 s3 H- f
- . N2 C- M- U( ^! s
- #include "stm32f10x.h", d% S" p$ d6 n
- 3 q1 i ?% k! n2 A; |8 c* k
- #include "stm32f10x_i2c.h"; u F1 }, | y! Q) t6 E
- : n+ i. K/ }. v
- ' L& N' D5 U$ {3 b7 |
-
4 y2 \, V! Z! X - //四个VL53L0挂载在同一个IIC总线下,所以使用四个片选信号--2019/10/302 t6 }) i- R3 A- \
-
$ L7 U' A. D2 L/ a E% d - //!!!!!!!注意:重新使能设备后,设备iic的地址会恢复为默认值0x52--2019/10/30
& u: Y2 r, M, F+ n# O -
( C+ n. E) s" w$ ]) t - //VL53L0 0
7 u0 {6 y4 b6 S4 R' G+ I -
5 {0 X' m) O: M8 g* D - #define I2C_SCL_GPIO GPIOB5 r) i0 G0 b$ ~) w
- " N7 o; N/ Z4 H8 ~8 t" |+ t4 N# n
- #define I2C_PIN_SCL GPIO_Pin_8
( k# t% M; @# |' }$ j# U& v# h4 Y - " q" i" A" o, u
- #define I2C_SCL_HIGH() GPIO_SetBits(I2C_SCL_GPIO,I2C_PIN_SCL) , k e. q I4 \; r
- - v0 p* {5 ?$ l+ Y: A" h+ y
- #define I2C_SCL_LOW() GPIO_ResetBits(I2C_SCL_GPIO,I2C_PIN_SCL)
+ [3 Z. c# y3 V% C% q - ! _5 C% X% _. x! z( G" [1 D
-
3 K4 p% V6 c! u+ E C0 P - 6 a! c) v' @! J" L/ A; m
- #define I2C_SDA_GPIO GPIOB4 j3 \. E: ]% F5 g* F; q* K
-
! ]: h @- }& g+ h. P3 u - #define I2C_PIN_SDA GPIO_Pin_9
; ~* a0 |2 J7 V( @ - + @# N3 g9 P. w$ m
- #define I2C_SDA_HIGH() GPIO_SetBits(I2C_SDA_GPIO,I2C_PIN_SDA) * a" L+ J, W) z
-
$ t' n6 ?$ D/ C. c' `8 N6 @6 v$ ?9 t - #define I2C_SDA_LOW() GPIO_ResetBits(I2C_SDA_GPIO,I2C_PIN_SDA)
1 a( P6 r/ P% }) G. U( ` -
. E/ e. G: X& {5 {7 Q% O' e9 } - #define I2C_SDA_STATE GPIO_ReadInputDataBit(I2C_SDA_GPIO,I2C_PIN_SDA)( d* k& d" Y- r
- - P2 x1 l3 D- h: _& X4 A8 d: k
-
; H `4 Y# f5 k) |( K - - ?+ O0 D, t) C9 i) J: w/ H2 t* L
- //片选使能--2019/10/30 g, U7 R- I0 ]
- . |5 m* G' L/ D: f& z) @3 v& a
- #define I2C_X_GPIO GPIOB
' |$ A% o' i1 ~# |1 a# ? - , q1 k+ o+ O3 L( U/ f
- #define I2C_PIN_X0 GPIO_Pin_12/ _7 `& w7 V A. A( X% q
- 0 C- D$ `6 J9 }, }9 R
- #define I2C_X0_HIGH() GPIO_SetBits(I2C_X_GPIO,I2C_PIN_X0)
! @+ b1 A& j* w% L0 \7 V - 2 G$ I) U$ U; h& h/ _
- #define I2C_X0_LOW() GPIO_ResetBits(I2C_X_GPIO,I2C_PIN_X0)
# [) T- Y4 z4 x% f3 \( \$ v& x - $ i& c1 P! s3 i# ~
- , g( D Y! j! B/ ^& O
-
1 c% d3 q6 r+ D3 { - #define I2C_PIN_X1 GPIO_Pin_13
: {+ G" C( \- M H- E+ z - $ r1 K2 S9 _+ z2 D
- #define I2C_X1_HIGH() GPIO_SetBits(I2C_X_GPIO,I2C_PIN_X1)
) C* X4 i+ ?0 `* _- _/ ]. j -
1 J9 }$ Q" k5 G7 t - #define I2C_X1_LOW() GPIO_ResetBits(I2C_X_GPIO,I2C_PIN_X1)
. r5 K$ s& e& w% z, c4 g - ; D2 b+ M, B" u9 e8 a/ Q/ C& }: ]) @
-
4 R5 O* R+ z9 z -
. L+ G6 u# s$ F - #define I2C_PIN_X2 GPIO_Pin_14+ {: G( r: Z. [! E0 E
-
: s& A" n* Z, X' L& e6 P - #define I2C_X2_HIGH() GPIO_SetBits(I2C_X_GPIO,I2C_PIN_X2) : R ~7 x4 V) `2 A+ D+ o% t2 X
-
: @9 m5 Z6 H3 k! `0 [3 N - #define I2C_X2_LOW() GPIO_ResetBits(I2C_X_GPIO,I2C_PIN_X2)
, t& G& ^ {6 _/ q6 | -
: o+ l" X' E: j - 2 e9 k, l* ~3 G; p& i6 Y
- 9 V% A! M" f' {1 _( ?" y
- #define I2C_PIN_X3 GPIO_Pin_15
( h# M7 @$ ` _; d! K' N% h! N - $ `; C$ {- a, W" B2 _6 m
- #define I2C_X3_HIGH() GPIO_SetBits(I2C_X_GPIO,I2C_PIN_X3) : k% e+ _1 z( c$ u' y6 \8 E
- , w) ~( } i/ i. w# V9 I
- #define I2C_X3_LOW() GPIO_ResetBits(I2C_X_GPIO,I2C_PIN_X3)6 r) m0 A5 ~# W0 i2 d/ I: ~ M2 O
-
: {5 Z' P+ L) n' m, }7 p/ Q - 2 m4 Z* ^4 n4 `2 ?
- * u9 J1 P6 D/ |) V' E$ i m( _
- void i2c_init(void);
4 L c9 `, |3 |- Q - 8 {" j: |1 r" @& g. q& g3 t
- uint8_t i2c_write(uint8_t addr, uint8_t reg, uint32_t len, uint8_t * data);
# J, }1 F5 k9 c2 V - / o8 L# l, K. |5 v, t( p
- uint8_t i2c_read(uint8_t addr, uint8_t reg, uint32_t len, uint8_t *buf);0 z' Z8 T" w, t9 Z5 w
- / g8 I1 `% O! ]$ b$ g
-
1 j& M; {- q h. r' n5 p - * N5 E2 Y. t# ] q
-
3 Y9 V7 d- f: G) Q, D* c - 2 `: g& |8 W( E1 L9 J
- #endif
复制代码- void i2c_init(void)! |0 y7 I5 a2 m- Z1 }
- . V/ a6 o# b( X+ h
- {, [* h, k( X7 S0 t: t5 Y9 [
-
4 F. c+ g D+ V" J - GPIO_InitTypeDef GPIO_InitStructure;" o# f5 Y3 u* I E* D
-
6 X9 e) ^0 N4 ? - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);, T, I- r7 h& T1 w' `
-
- k6 ~4 U* Q. b2 x - . }& E- t# p0 l& _& ], F4 d" \1 U
- ) T5 c2 P6 m% Q4 v9 M. ?& H
- //模拟iic配置
% u* R& U) ~; J: c0 {+ x - ) _) b2 G- L/ q( J: ?* j
- GPIO_InitStructure.GPIO_Pin = I2C_PIN_SCL;% u* S$ ?. X8 B }; h( U7 o
-
* p1 D F4 Z( @1 o - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;3 o3 l, }$ e. q; k+ L3 R$ g% w
- " w! m c. |: X' t: r
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;) i6 M. F1 s) T& W+ h6 I
-
, Q. ?* Q3 t' J - GPIO_Init(I2C_SCL_GPIO, &GPIO_InitStructure);. @. q8 r- f- `7 e
- " v- M9 I3 }* J# [$ O& `2 v
-
6 C4 J8 R) u) c9 Y. P -
+ z" _' l& j4 M' h; n4 u8 b - GPIO_InitStructure.GPIO_Pin = I2C_PIN_SDA;
- R. x# G" ~$ [% o' d - 9 i# f( d: B/ s' z, g N
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;. T1 T: Y3 P4 h: d) n4 r
- 6 k5 M* M, Z k$ o# r$ v
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
- b4 q1 I! R3 o. i& s - 7 [, K0 I. |- w% K. O
- GPIO_Init(I2C_SDA_GPIO, &GPIO_InitStructure);
4 z6 O) w" O" r; t5 o4 O - 2 T3 b) Y* ^8 g2 x/ V& v' M
-
9 a+ w5 k6 p: e% ^ L - 3 t9 T: P+ H& r3 {5 d' ^; p" _
- //片选使能配置' r- K6 W" A/ ~. V
- 2 j9 c. a r e* x. ]. B4 w
- GPIO_InitStructure.GPIO_Pin = I2C_PIN_X0;
' q8 b+ p$ }6 u, Y* z% A$ M9 M - 3 r) x4 @" N' d4 J. ~1 Z. S
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;3 L/ B( I+ u2 J, N) Z
- # y3 M2 _& h2 ^8 A6 p
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
! }5 O# k1 |6 f7 ~# T% C% R* \ -
6 W' f- V5 ~0 |% v- {: u$ L - GPIO_Init(I2C_X_GPIO, &GPIO_InitStructure);. _& f& x! y b! ]. i" T9 S2 J' ]1 E
-
3 n9 `5 m/ o. S - / C8 s& _# s! f, K
-
6 ?3 K7 {$ _6 P0 d5 m( z - GPIO_InitStructure.GPIO_Pin = I2C_PIN_X1;6 c, r! E: _$ s& I: M) y7 s0 k7 `; c
-
) O6 m" _. P3 {" g - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
" c5 } q; ]/ k2 T - 8 ]7 Q" ^ {; M2 `
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;1 j% l! r" u+ J: B9 X+ w J9 J/ _
- * K7 B7 C4 s8 U- w
- GPIO_Init(I2C_X_GPIO, &GPIO_InitStructure);
1 v' m( s3 B5 C C# C" F; x - + H" G0 g* P! [& ^3 F Z) j
- 3 Q7 o9 X G; n
- / i% J$ i' }7 b8 v# D% y# ^; b
- GPIO_InitStructure.GPIO_Pin = I2C_PIN_X2;
" T2 |, b7 i9 Q" { - 9 C; g1 I$ R. \% v, C1 P# b) ?
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;5 H% w' I" q$ M* |
-
|/ h; M+ D5 v) a+ A - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;% Q$ {3 ^- @4 E. H
-
) `3 A: x+ h' z0 W' _) Z" R/ F1 ~3 a - GPIO_Init(I2C_X_GPIO, &GPIO_InitStructure);$ J0 c" H1 C& Q. p# R9 s
- $ U: z; W' a* w( t' h* t3 T$ |
-
* h6 m( L. L* A- A- R9 g( u* b0 F - 3 Z; Q6 Y5 ~* E/ `8 c0 N
- GPIO_InitStructure.GPIO_Pin = I2C_PIN_X3;
# `9 b3 ^$ V5 f0 n -
% l7 I* O9 d! V - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;7 g' b3 G$ ?" b$ K4 o4 ?2 K
-
' }, G" Q" {( |0 T+ X - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;' ]- ^9 t- ~3 Q- |/ f4 x7 w& \% P3 t
- " E; J- m; X+ m2 w
- GPIO_Init(I2C_X_GPIO, &GPIO_InitStructure); T2 j2 \* [% h' G: C" t2 a3 w1 `
- . M8 \% c4 T3 s" ~) a, r- I
-
% y8 ~# E) I2 K$ b - 4 n+ y1 Z" {( s6 E: n
- I2C_X0_LOW(); 9 r9 O- s9 ~2 ?
- 4 g2 E5 h" t% Q, p
- I2C_X1_LOW();6 s9 s2 K3 N" M) T
-
; s. _( c' E: h( b) t8 d1 r* X5 B - I2C_X2_LOW(); 7 c* K) c4 O3 e' e. a4 I3 R
- ) f G4 X/ v$ \4 _0 p& S, g
- I2C_X3_LOW();
5 a0 R! W' z2 h& f7 G2 x - ! t! o1 y& G2 Z3 L" P5 q& {& {
- delay_ms(20);3 ]: U3 L) I0 J
-
) P9 P; D, A: U - }
复制代码
7 |2 R8 }) K& n0 j- Q# Z4 b$ t# ]8 R9 Y
在模块初始化时调用IIC外设初始化,同时初始化4个测距模块。 -
& \0 P3 m5 Z: q8 H+ ?% ^3 H - {! K9 v( U6 B2 c6 @. z
- , T _' M7 Y. v/ `
-
, [! d1 d. |. \1 j -
9 i, I( Z* \ Q* i- r( p - VL53L0X_Error Status = VL53L0X_ERROR_NONE; //初始值赋值为0
: ` F" P9 Q0 _1 w1 U - 3 {( a t4 b' N* U) |
- ' ^, b5 H3 L$ q; y
-
& A0 p, a9 e' K! n$ X# d - //初始化一定按照这个顺序执行,否则不成功
9 s' X! }' i* A- p -
2 N# e: q4 [* g0 | - VL53L0X_i2c_init();
1 M) C) _( G' Z+ m -
8 y' i( E0 h( G - vl53l0x_initX(&vl53l0x_dev0,0);7 o i6 f2 W P" R/ g, Y
- 5 o- q X2 T2 k j3 O
- vl53l0x_initX(&vl53l0x_dev1,1);( b" u3 q& |9 _% v" u
- ^0 U; c/ x' E, I/ D
- vl53l0x_initX(&vl53l0x_dev2,2);
^3 |' ?5 x+ x; @* i - ! B" K, g3 s+ w9 X1 X
- vl53l0x_initX(&vl53l0x_dev3,3);3 N! |, b/ S; b; K
- 2 e9 ?5 U' Z Q7 q; i# Y+ G2 u5 w4 J
- + s1 Y& Q" F+ g% w
- & V2 q! K5 X' A' k9 c& ? J+ L
- return Status; //返回0' r6 V+ J5 ~( x: k# B9 A/ N6 ^
-
( c1 L' f$ J0 r( N4 Y8 Y - }
复制代码
+ Z' w2 h+ @' Q, n* I [7 m/ C8 ~& T$ Y/ \. Z8 g# e3 e
在vl53l0x_initX()函数便去别去正点原子的驱动,这里是全文的重点,很多单设备发展到多设备这里都会出问题,在初始化设备时一定要设置设备的IIC地址。
/ b: ]5 e3 ]8 p4 J, V4 E8 C//单个VL53L0初始化# u3 P* B5 W- U) r% ?" f! P
VL53L0X_Error vl53l0x_initX( VL53L0X_Dev_t *pMyDevice ,u8 vl53l0_x_id)
2 `2 ^! r$ Z! e{" W7 k; \: t9 N2 _5 n
VL53L0X_Error Status = VL53L0X_ERROR_NONE; //初始值赋值为0 V! m0 B( c2 o* J7 A- u, J
# Y$ N* `+ Y) A8 |2 k, u
pMyDevice->I2cDevAddr = 0x52; //iic地址 0x52是默认地址,要初始化必须先写0x52,才能初始化,之后再通过软件修改$ Y& r2 o* @7 W- ?% D
pMyDevice->comms_type = 1; //选择IIC还是SPI iic=1;SPI=0
/ [4 @6 P2 Z: r# [" C pMyDevice->comms_speed_khz = 400; //iic速率
+ N& T7 I n2 d4 ^8 o1 P 5 c, H0 a* D6 G) K q) Z1 u2 u
" n! G! I- I- o/ s: s' R# L3 b+ C //正点原子的VL53L0用户手册上写明了再次使能时地址会恢复为0x52,所以只能使能一次,设置好地址即可,这里是核心
$ M1 i9 t5 a4 C/ P& @6 I9 E! f/ |; ~ switch(vl53l0_x_id)
0 i# [, }# n7 q* @/ y7 C& r2 e& L, e3 F {
% d6 a- `& G& z- F( d case 0: # L4 F1 a& r# a5 ?2 _
I2C_X0_HIGH(); - L0 C( X! p$ R- S$ F' }+ n
delay_ms(20);% n* ]" L, z/ Q6 X) x* g! N
vl53l0x_Addr_set(pMyDevice,0x60);//设置第一个VL53L0X传感器I2C地址5 N2 ~1 z7 L+ n! ^: R
break;) n- e( U: g* v; ?- e( Z! Y
case 1: # g1 {: g2 o8 S. T3 H
I2C_X1_HIGH();, ^# P( }& \. o, X* j% c; R
delay_ms(20);
) j j9 j* D8 d8 d( } vl53l0x_Addr_set(pMyDevice,0x62);//设置第一个VL53L0X传感器I2C地址
; u- M- a& ]$ {' f; b5 u/ y8 P break;
8 P9 G8 f P( o case 2: 5 k; E7 o' O& E/ y. ^* {
I2C_X2_HIGH();
9 f: L; y0 R) X3 z* x# V! x delay_ms(20);: R2 p, b" K" V* m7 O
vl53l0x_Addr_set(pMyDevice,0x64);
+ H% O' B5 L* Y* Q6 u break;! _7 d9 {0 q5 k9 L, [9 L
case 3: ' {# k I+ R- N: t9 s8 d
I2C_X3_HIGH();
9 |$ J6 T* X# a7 A- u1 }* f delay_ms(20);
1 w- W/ s9 M6 z vl53l0x_Addr_set(pMyDevice,0x66);
1 s" T. F- |, n- ^& k/ U) R break;; T" ~: T9 K7 Z [) i# Y$ q
}
9 \ [5 m- q3 L# H
' _( \+ R; }4 @. g. _- L9 W6 P Status = VL53L0X_DataInit(pMyDevice); // Data initialization //VL53L0X_DataInit:一次设备的初始化,初始化成功返回0. t$ z! j3 @' O3 `1 l L5 J# v7 b
if(Status != VL53L0X_ERROR_NONE){ //判断如果状态不为0 打印错误信息1 T, r% m$ L& }; O m7 S6 |& }/ Z
print_pal_error(Status);, t1 C4 a8 \/ s, c6 Z
return Status; // 返回错误值 可通过此值DEBUG查找错误位置, f0 ~1 R6 |% }7 R8 l# N
}
" n$ P# M, _2 q f4 B, L
5 l1 P4 z5 L$ {& k8 \/ ~; x Status = VL53L0X_GetDeviceInfo(pMyDevice, &vl53l0x_dev_info); //读取给定设备的设备信息- i5 j5 e3 ], q, A% W% e: H
if(Status != VL53L0X_ERROR_NONE){
; j6 P% s5 m8 ` print_pal_error(Status);) E# \1 T& O$ k2 S
return Status;
$ y$ E5 r E- L2 y; k }
7 Z: ?( K) m6 o5 Z printf("VL53L0X_GetDeviceInfo:\n");" c% O7 i" X9 M% n
printf("Device Name : %s\n", vl53l0x_dev_info.Name); //设备名
9 G1 [1 `/ n% G' B, r! e3 b printf("Device Type : %s\n", vl53l0x_dev_info.Type); //产品类型VL53L0X = 1, VL53L1 = 2
! I8 `4 x* X( u printf("Device ID : %s\n", vl53l0x_dev_info.ProductId); // 设备ID: D. p+ b0 g) A6 p: v- J. j
printf("ProductRevisionMajor : %d\n", vl53l0x_dev_info.ProductRevisionMajor);9 ^4 }% w8 h- P: F, N5 s
printf("ProductRevisionMinor : %d\n", vl53l0x_dev_info.ProductRevisionMinor);% u& q7 W8 T6 b% b
3 N% i: w. @) G# d; O+ r5 y% O
if ((vl53l0x_dev_info.ProductRevisionMajor != 1) && (vl53l0x_dev_info.ProductRevisionMinor != 1)){5 } X; x" i; t/ ^; v) d& n* Q
printf("Error expected cut 1.1 but found cut %d.%d\n",: S- K* M- V( ^
vl53l0x_dev_info.ProductRevisionMajor, vl53l0x_dev_info.ProductRevisionMinor);; ^7 J4 c" O) _9 |) a. H) l
Status = VL53L0X_ERROR_NOT_SUPPORTED;6 y8 x- Z" z7 T6 t4 M
print_pal_error(Status);1 W. c- E- M( d% o% a" V/ ~
return Status;6 ^! F6 ]5 y4 C' ~
}
/ ?7 K" I& ?) s* }$ M8 L" D8 d, V# u* N& N# a- s
Status = vl53l0x_measure_init(pMyDevice); //测量配置
0 {: a* c9 N8 y6 M4 W2 }$ z0 [ vl53l0x_status = Status;* ~1 _6 d; p7 d7 M
if(Status != VL53L0X_ERROR_NONE){ //判断如果不为0打印错误信息
2 C8 |% C; g" D6 l7 f/ h5 ?! \" g1 \! u print_pal_error(Status);
2 U8 S9 [( Z9 K4 b. S return Status;
3 l# e% p1 {4 [ } , p! W6 S2 d5 A* Z3 C/ T+ c7 G. c
} 模块的初始化顺序是:使用默认地址初始化设备---修改传感器IIC地址---再次初始化---测量配置
& d- {9 V" H1 z2 F X% p @! [所以在这个传感器的初始化中我们先用默认的0X52地址将VL53L0X模块初始化,初始化完成后方可修改其地址,这里使用SWITCH函数判断用户配置的地址,避免函数重写,减小代码尺寸。修改完地址调用VL53L0X_DataInit()函数进行模块的再次初始化,使修改生效。注意:VL53L0X不能保存地址,如果掉电后地址会恢复为默认的0X52,同时修改完地址后只能执行一次初始化,更多的初始化次数会也会导致地址复位。这在硬件的处理上要加倍注意。
/ y1 g! H# f+ f8 G/ P- r" e$ W在这里我翻车了,因为硬件不在我的手边,我都是远程帮助调试,没看到硬件,我的朋友一直反应各种问题,最多的就是测距有问题,测出的数据都是错的,或者只有一个传感器可以使用。我检查了很多遍的代码,始终找不到原因,还好他自己也想到了硬件的问题(因为他们硬件干过很多错事,都是一些小白容易犯的,但是那个老员工比较粗心,也会犯错),最后发现是线的质量太差,线的长度太长,IVL53L0X模块安装的位置不好,因为模块安装在可动部件上的,导致每次移动都会导致模块短暂的掉电,导致地址复位。后来加装模块的减震装置更换屏蔽线解决问题。
: M X4 W# Y1 K2 r, s g复位完成便可以测试: 
5 ?$ ?, ^& ]5 ~7 [+ G# u8 s' h/ y! \
5 o( r7 Y6 T$ p* w. j$ p
- VL53L0X_Error vl53l0x_start_single_test(VL53L0X_Dev_t *pdev, \
. c, A7 a4 L9 f& }" R. L0 H! U5 i -
+ f& v# x9 ^4 ~' I2 y, M2 ` - VL53L0X_RangingMeasurementData_t *pdata)8 h3 f/ x- H/ j4 ]3 l! Z
- + k: {; o# l; h5 E% S) S
- {9 y% \/ P4 m# h* ?. I( p! {/ V
- 5 U& n. O6 l9 ^( e8 x
- int i=0,j=0,sum=0;$ N7 U3 }& ~3 T& S- O3 }' S9 r
- 6 L7 A! ~7 I' X
- VL53L0X_Error status = VL53L0X_ERROR_NONE;
9 c: D- u4 T" q& d -
8 U( ?5 `% ~1 i -
; w0 a* l. T1 P - . H7 L' H- E, L) x: b. }
- if(vl53l0x_status != VL53L0X_ERROR_NONE)
0 X7 A8 o% w" m' {8 s -
, E* n9 ]# u4 Y# \4 M - return vl53l0x_status;
/ w5 q: f" L7 u: J6 G8 ]/ p -
+ o t _5 }* `( u0 B+ f - : o6 h0 I% C: j2 j
- / Y: r; t% D8 n2 s, x% M& N3 u3 M
- status = VL53L0X_PerformSingleRangingMeasurement(pdev, pdata); 执行单次测距并获取测距测量数据
( p& A- L2 s+ p! F# ` -
. o4 B6 ?# N: o. [5 h5 { - if(status != VL53L0X_ERROR_NONE){; G' A$ k5 r9 b% m+ t# s& V
-
. X& ~3 `2 X4 S* l* \, N# t6 r - printf("error:Call of VL53L0X_PerformSingleRangingMeasurement\n");* T- P0 ]2 x# b+ c9 n& x
-
3 @# k8 u1 ]' p1 X( d - return status;
0 F$ G4 b2 \9 ^ -
& O: b1 v) I1 j# C' E - }( X: k n1 g3 Y! R. v( |/ @
- 6 |! |4 E7 J# x# p- i0 F
- ) ]' y. T1 a; x" ]) X5 _) M
-
4 _4 q5 |% H' R6 x% P) e4 b c - for(i=0;i<5;i++)
; ]6 Y( f( l* u& {: j - : ]0 R: Q! }. z: G3 |9 {3 b
- sum+=pdata->RangeMilliMeter;
: H, O/ t; X( s7 k- ?% B& ]$ `" R -
. V) j, a) f: X$ Y - pdata->RangeMilliMeter=sum/5;+ ?3 i- u# \ n) \# C2 g- G
- , n+ r& X o: T" n( a
- printf("%d\r\n",pdata->RangeMilliMeter);
; ?9 z# y* b2 d2 t" i' O - }" n% E9 u3 ^: V, u
- return status;
1 k' `- ^* h2 W; v0 j) B! [ -
: }2 _# t+ Q: U- C0 u& f3 Z - }
复制代码 / v: h- r# r+ v6 |# ^, \
% b# L, ?; B2 e0 g; a/ b6 b
打印测试结果,通过! 
, O' P% B# ?/ {" L6 n5 [4 P主函数循环测试,因为项目对代码的速度要求不高,所以一些状态判断代码中还有保留,这里跟着原子走,没做太多改变。
! d2 J7 q) i" @4 t/ r6 c因为这个项目是帮助朋友做的调试,而且他们的项目还在研发期,太多的东西不能介绍,照片啥的都放弃了。一个简短的帖子,希望能帮到大家把握住该模块,蟹蟹。
9 O3 Q: I6 R2 e* E" O3 ?---------------------7 }# P5 r5 d" ~) `+ M; ?
作者:呐咯密密 . D: \$ l% ~ _; \# ?+ [
|