你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验之谈】基于STM32F4驱动4路VL53L0测距的经验分享

[复制链接]
STMCU小助手 发布时间:2022-12-10 23:00

最近给朋友调试了STM32F407驱动VL53L0的激光测距,安装在机器人上的,遇到一些问题,这里发帖纪录一下。2 R: F$ v+ l, s  f% U, X
关于VL53L0的资料和代码在正点原子那里都有,但是正点原子只是驱动了一路VL53L0,很多问题都需要我们自己解决,一路的VL53L0非常简单,随便参考一下例程就能完美解决,但是一旦涉及到多路设备,就会出现一堆问题,最突出最主要的就是多个VL53L0的地址设置,把握不住就会出现只有一路能正常使用的问题。
( i1 @6 s/ r7 z& E
, Y, z( R( J( \. ^6 |  {' ^VL53L0X 简介
: @' i3 A. R0 D. g6 K) ~9 qVL53L0X 是 ST 公司推出的新一代 ToF 激光测距传感器,采用了第二代 FlightSenseTM技术,利用飞行时间(ToF)原理,通过光子的飞行来回时间与光速的计算,实现测距应用。较比上一代 VL6180X,新的器件将飞行时间测距长度扩展至 2 米,测量速度更快,能效更高。除此之外,为使集成度过程更加快捷方便, ST 公司为此也提供了 VL53L0X 软件 API(应用编程接口)以及完整的技术文档,通过主 IIC 接口,向应用端输出测距的数据,大大降低了开发难度。. X# O7 c- O2 ]. w* |
VL53L0X 特点包括:
; ~7 _3 C! j  l, X" b2 Y①, 使用 940nm 无红光闪烁激光器,该频段的激光为不可见光,且不危害人眼。6 s& U8 p+ x9 o/ R. W
②,系统视野角度(FOV)可达 25 度,传感器的感测有效工作直径扩展到 90 厘米。) h3 E/ N( w( V: I% s( U$ y
③,采用脉冲式测距技术,避免相位式测距检测峰值的误差,利用了相位式检测中除波峰以外的光子。
- |) P  k/ }1 N④,多种精度测量和工作模式的选择。+ ^. ^+ I8 l* z/ x
⑤,测距距离能扩至到 2 米。
: E: _9 {! x0 E⑥, 正常工作模式下功耗仅 20mW,待机功耗只有 5uA。
- O4 L. X7 {- D- [' j  }% J⑦,高达 400Khz 的 IIC 通信接口。  @3 r, N7 V1 V& Z4 r4 G
⑧,超小的封装尺寸: 2.4mm × 4.4mm × 1mm。
6 h/ S- S% B( GVL53L0X 工作模式  p  `' Q$ c; r1 E( `- }& F6 @
VL53L0X 传感器提供了 3 种测量模式, Single ranging(单次测量)、 Continuous ranging(连续测量)、以及 Timed ranging(定时测量),下面我们将简单介绍下:
0 O' N* t) C+ V7 G7 J# W& W(1) Single ranging(单次测量),在该模式下只触发执行一次测距测量,测量结束后,VL53L0X 传感器会返回待机状态,等待下一次触发。6 I0 `! F# Z6 @2 z% ~5 p
(2) Continuous ranging(连续测量),在该模式下会以连续的方式执行测距测量。一旦测量结束,下一次测量就会立即启动,用户必须停止测距才能返回到待机状态,最后的一次测量在停止前完成。
: n( n4 g5 L  j0 j, B* p(3) Timed ranging(定时测量),在该模式下会以连续的方式执行测距测量。测量结束后,在用户定义的延迟时间之后,才会启动下一次测量。用户必须停止测距才能返回到待机状态,最后的一次测量在停机前完成。根据以上的测量模式, ST 官方提供了 4 种不同的精度模式,如表格所示:


# P) O) Z1 Y9 @+ c6 \8 \7 M从表格可以看到,针对不同的精度模式,测量时间也是有所区别的,测量时间最快为高速模式,只需 20ms 内就可以采样一次,但精度确存在有±5%的误差范围。而在长距离精度模式下,测距距离能达到 2m,测量时间在 33ms 内,但测量时需在黑暗条件(无红外线)的环境下。所以在实际的应用中,需根据当前的要求去选择合适的精度模式,以达到最佳的测量效果。
2 A3 p5 V: K% o以上资料来源于正点原子的《AN1703C ATK-VL53L0X 激光测距模块使用说明》。这里摘录一部分,方便进入主题。/ u9 e4 q. e4 z
因为今天是调试多路的VL53L0X设备,这里不完全借鉴正点原子的例程,但是官方提供的驱动我们还是必须要用的。, v  E3 y- U4 @* k. V# v' q! M
如果想要快速上手,文末直接下载我的代码,我的驱动库经过自己的修改,和正点原子有些不同。: D0 D9 K6 I, ?% K9 G* `
我们直接从代码入手吧!
1 f" W' R: o% r1 {& \" b9 Q7 ~在初始化VL53L0X之前,我们必须初始化IIC外设,此次遵循正点原子的方法,用模拟IIC。

  1. #ifndef _VL53L0X_I2C_H- j/ o) d7 \1 c) e
  2. ; ]! o9 a3 ~3 c6 e6 f
  3. #define _VL53L0X_I2C_H
    ; z9 U3 b3 u# Y$ N

  4. " r( t( ]/ n; k8 W; o- e0 a/ N

  5. 3 }+ h$ z, a) c( v6 _4 j! y

  6. " R& h9 D: e, F& g  A% P2 L
  7. #include "stm32f10x.h"/ j5 h8 G3 }7 a

  8. ! R( W0 n) r% x+ g3 k
  9. #include "stm32f10x_i2c.h"
    ; s0 F2 q$ m( ?9 @" H6 M1 C, n5 ~
  10. - V  a# j" d7 h6 e5 U' I

  11. # g; s/ ]: s5 V' {% [. c6 m7 f# `
  12. 5 s% g& r& z3 \
  13. //四个VL53L0挂载在同一个IIC总线下,所以使用四个片选信号--2019/10/30
    7 P7 _4 Z& ]6 V# E. M* M4 D
  14. ! t( U( x* m9 @6 I
  15. //!!!!!!!注意:重新使能设备后,设备iic的地址会恢复为默认值0x52--2019/10/30; n9 s# s" m# p$ P

  16. 0 o  n0 n3 y4 f* W7 Q% N- C
  17. //VL53L0 0
    2 @0 B# b7 }9 l
  18. ( P2 T( \# f" Q. O$ c
  19. #define I2C_SCL_GPIO               GPIOB
    : o' K. U* q% N- B) X

  20. 2 y* A' G9 K) f+ A3 S
  21. #define        I2C_PIN_SCL               GPIO_Pin_8
    $ @/ n& {, N$ J+ X' {
  22. 3 b- E- ]; B# p9 k" w& d& w* q' g
  23. #define I2C_SCL_HIGH()      GPIO_SetBits(I2C_SCL_GPIO,I2C_PIN_SCL) + Q9 p- y$ a- K8 E  N7 l

  24. # Y5 w. S' C  k/ o: H9 O
  25. #define I2C_SCL_LOW()              GPIO_ResetBits(I2C_SCL_GPIO,I2C_PIN_SCL)
    + T+ U4 d: D+ G9 \6 \1 ^& z( Y

  26. * ~& i* P, D2 _, U+ f! [& L
  27. , U2 r7 u0 h% B/ U, {3 H; T

  28. , i5 s, g  A/ O1 R; ?9 Y4 E& d/ ]
  29. #define I2C_SDA_GPIO               GPIOB
    ) y. w7 Q, b. l' L0 B* P
  30. 8 u) G: e& J$ I+ O
  31. #define        I2C_PIN_SDA               GPIO_Pin_9
    / T9 l( }( i8 @" l) E- s% z

  32. ; W1 ]9 \/ I5 ^# R" f4 Y. p
  33. #define I2C_SDA_HIGH()      GPIO_SetBits(I2C_SDA_GPIO,I2C_PIN_SDA)
    " ^2 w. t% R' @8 l
  34. 2 F1 C5 ~. j  w1 V0 ]) s
  35. #define I2C_SDA_LOW()              GPIO_ResetBits(I2C_SDA_GPIO,I2C_PIN_SDA)
    + ]) T) v! u7 ^- y/ P

  36. 5 k  L# Z! q4 R/ ]2 [2 D
  37. #define I2C_SDA_STATE       GPIO_ReadInputDataBit(I2C_SDA_GPIO,I2C_PIN_SDA)
    * L7 x/ ^" l5 d% O' N  G

  38. . }& s- i2 n' U9 k
  39. 2 }6 j, L+ q; ]$ H8 d

  40. 6 X( t) z' w3 o. b6 n
  41. //片选使能--2019/10/30
    6 Y$ }) t( Z8 T8 a
  42. : l$ Y" ^6 L. s7 p
  43. #define I2C_X_GPIO               GPIOB; A/ _' j' y$ V+ b+ ~2 j4 v/ e, R
  44. + ^0 U2 W6 P' L
  45. #define        I2C_PIN_X0               GPIO_Pin_12
      b4 W% T5 ~( q$ }/ o

  46. 4 e: W. r, Y% Z( Y' x3 Q1 d
  47. #define I2C_X0_HIGH()       GPIO_SetBits(I2C_X_GPIO,I2C_PIN_X0) " A9 A0 i+ B, t' m' }1 l

  48. 3 I4 Z8 O2 c  t4 J) K+ @+ J6 H$ @* r3 _
  49. #define I2C_X0_LOW()              GPIO_ResetBits(I2C_X_GPIO,I2C_PIN_X0)
    / a1 J1 P! E9 g3 N4 V, n
  50. / x  S* x3 D" U2 P; B7 d  X, b

  51. : l, p+ t) y. Z5 O+ p' F8 M. l+ ~
  52. # l. `! E9 i& j# B
  53. #define        I2C_PIN_X1               GPIO_Pin_132 k3 p8 u5 K( L: C; y  N' b3 B

  54.   ^5 n1 x! ^% g$ ?- w
  55. #define I2C_X1_HIGH()       GPIO_SetBits(I2C_X_GPIO,I2C_PIN_X1)
    % m! `% T; k2 l
  56.   w" ~3 f& \6 @0 d  S% B
  57. #define I2C_X1_LOW()              GPIO_ResetBits(I2C_X_GPIO,I2C_PIN_X1)
    6 u- }/ X' t" l' f- g
  58. 8 e8 b1 {0 o, x- {' x$ ^( x

  59. # Z: |) C2 C: i9 |, }+ X
  60. 2 w& J. V- Q8 |6 Q
  61. #define        I2C_PIN_X2               GPIO_Pin_14- x& e! W0 ?' v/ f" {' K  S

  62. * Q: V/ ?* ]; d. _( g9 ~0 g
  63. #define I2C_X2_HIGH()       GPIO_SetBits(I2C_X_GPIO,I2C_PIN_X2)
    1 H3 d$ g' U9 V' Z8 J3 F

  64. & C8 B* O5 U; B- E7 }
  65. #define I2C_X2_LOW()              GPIO_ResetBits(I2C_X_GPIO,I2C_PIN_X2)
    0 Z: ]  r: _$ Y! E% B6 x
  66. - o. j5 `6 }! ~/ X5 J- g5 ]2 t
  67. ! Q1 {- ~( Z2 B& s

  68. 3 N* c# b0 M5 k7 O2 O
  69. #define        I2C_PIN_X3               GPIO_Pin_15
    6 w( e5 G- z- b# ]: b  E- Z( d: I
  70. % A* \6 b/ O* h6 T$ R$ l. {
  71. #define I2C_X3_HIGH()       GPIO_SetBits(I2C_X_GPIO,I2C_PIN_X3) - P1 k; c8 }0 u8 J

  72. 0 w% O9 D# S* U, y/ X, o
  73. #define I2C_X3_LOW()              GPIO_ResetBits(I2C_X_GPIO,I2C_PIN_X3)4 J$ M* u* ^1 e0 {

  74.   C4 t6 n9 c6 N- e
  75. 4 `% S% u5 W4 L! f: x$ B4 [

  76. : g# T% T/ G/ B* S! T$ ]
  77. void i2c_init(void);1 m' \% s0 c# m- B# V1 S0 r
  78. ! e( I* X. O$ _" U# d
  79. uint8_t i2c_write(uint8_t addr, uint8_t reg, uint32_t len, uint8_t * data);
    0 B$ \! l; s$ k

  80. $ o# O. s* y2 o% o' p
  81. uint8_t i2c_read(uint8_t addr, uint8_t reg, uint32_t len, uint8_t *buf);
    , s3 L2 m7 N% h8 @
  82. * F  w! R, t2 z' p8 Z+ w. U' j

  83. , u5 V' L2 k6 ?- m1 L' ^
  84. 6 ~% Q, g) i% Y* s
  85. ; Q6 ?% o$ J, a3 g

  86. + H- s) d6 x1 F
  87. #endif
复制代码
  1. void i2c_init(void)3 M, P; F( l: a& U- K7 A
  2. 1 [7 P8 A+ S$ _' b
  3. {4 F, q! m2 C' ]' ~7 L& z9 }
  4. 6 @: x/ O( c# v6 x/ A
  5.     GPIO_InitTypeDef GPIO_InitStructure;9 Z* x* i! _8 ^. w1 I; {3 w+ ]# A
  6. 0 H4 S' e6 G# \2 |4 w$ O) P/ W/ U2 Q; ^1 f
  7.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
    & O' F( J) S! c; D
  8. " L2 A7 ^+ J6 c% ^* K0 n- R8 X# b
  9.     0 A6 v/ f: U, r8 `) }* o

  10. " {1 ?5 y( ^* F$ N  k  c
  11.         //模拟iic配置( d: S* _2 _2 x& V% `7 X

  12. * Q$ g4 b# |7 g3 g2 a
  13.     GPIO_InitStructure.GPIO_Pin = I2C_PIN_SCL;7 N9 }: z+ s! h- U& ]# V* `

  14. 6 ^5 z8 t' H1 j% `
  15.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;* j+ f( \( s# Y$ I' \; y6 y
  16. 6 C, c; c1 Q; ~" Z
  17.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    4 b/ ~* d. _  K( o1 ~5 q% I

  18. 9 t5 h$ L* V( A4 i" O
  19.     GPIO_Init(I2C_SCL_GPIO, &GPIO_InitStructure);  R4 g7 x' l7 d' P" Y' s& O

  20. . |4 N* l( _; K, D
  21. ; q, x, }& [  V6 p) r- I* H
  22. . D$ ]) a. {1 w
  23.     GPIO_InitStructure.GPIO_Pin = I2C_PIN_SDA;( T; a/ i  ?6 e) z$ T, T' \

  24. 2 v; T% V$ H( \0 L
  25.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;0 B/ m9 `# N8 f2 m+ N* M$ \% ], d
  26. $ y, [3 M# x% u5 Y* r
  27.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;9 Y4 i/ q9 {, a7 p- Z! O

  28. 4 L. _' ?3 V4 x/ t8 ^6 a' W% V
  29.     GPIO_Init(I2C_SDA_GPIO, &GPIO_InitStructure);
    8 ^5 @: u# n, T6 J' Q$ }

  30. ; V! l' U+ X- w
  31.         7 `  w8 j. I, N) Q

  32. 6 C: d' ~; {- y& q! [
  33.         //片选使能配置
    ; u7 \' y: j, ^: f* s- x

  34. 5 ?( Q5 O1 |* e4 v) _8 u2 c
  35.         GPIO_InitStructure.GPIO_Pin = I2C_PIN_X0;
    8 [1 a4 _& K7 _9 |( O

  36. 5 o# F1 ^, S0 K) k
  37.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;! @/ r0 ?/ s+ S: h8 \1 J& U5 X% m
  38. 5 N# x& s* x" T0 K5 w1 c) T
  39.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    & N% U' }! P0 ~6 s$ t
  40.   F/ o) t8 S6 X* y" O
  41.     GPIO_Init(I2C_X_GPIO, &GPIO_InitStructure);* q' D4 s8 B7 C4 ]# V7 S7 t  i
  42. 6 C5 D' I4 L4 \" l$ f% ^
  43.         ( J. j8 o+ P; Z8 r3 Y* ]& d( x) S

  44. ( ?) @% w+ x2 @; L' [4 n: ]
  45.         GPIO_InitStructure.GPIO_Pin = I2C_PIN_X1;7 [" ?7 l- S9 I. B0 o' |* L
  46. " t3 @- {' ^6 |+ `* Z- x
  47.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;- e  o: ~, y! e

  48. 3 b4 Z5 Y' p$ }1 W  m
  49.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;/ {6 ^$ G) z# P" V5 N) L
  50. 3 ^7 o7 R$ S+ Z$ }2 o! [
  51.     GPIO_Init(I2C_X_GPIO, &GPIO_InitStructure);& h) N9 @- [. h1 W2 E

  52. 7 z% u' ?, y" k5 k8 C* j9 s' s) }
  53.         
    0 R0 f* K; R, B& t* ~* z
  54. % D8 I) C" M# A8 `
  55.     GPIO_InitStructure.GPIO_Pin = I2C_PIN_X2;$ e! R' r, N5 Y+ j8 ~- Q# n7 X

  56. $ P2 H7 i" r7 o# j. G& c1 v3 ?
  57.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
    + t! I( ?% z, n! ^7 {, x
  58. 7 p- }' q% b# m: s! v9 M: y/ U" n- q
  59.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;7 a- Y7 z* Z' F
  60. % L, C6 H; |1 v, t5 p/ c0 M
  61.     GPIO_Init(I2C_X_GPIO, &GPIO_InitStructure);
    & I% x8 A/ {5 h# o3 S6 W
  62. $ i1 r  e/ ]  _
  63.         
      b- L2 d* R6 e6 ~$ \

  64. ; [- `0 l* s  w$ ?
  65.         GPIO_InitStructure.GPIO_Pin = I2C_PIN_X3;
    1 ]+ @* f9 b0 M

  66. / v1 ]1 I8 V+ Y* j9 \
  67.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;" [; }7 {) b2 o( T% M. K& g
  68. : B. y# w- D) |, L! Q5 A5 `
  69.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;1 [, J/ i3 F; P6 ?3 U0 r) \# x
  70. + z3 k$ E2 O% f& W
  71.     GPIO_Init(I2C_X_GPIO, &GPIO_InitStructure);
    , {2 |2 Y" E( \+ l0 ]

  72. 1 h7 }$ J: A7 D7 ~
  73.    
    ! j2 G* \3 V; x4 F
  74. 7 s" C$ a7 {+ B7 q6 N% K
  75.         I2C_X0_LOW();        * @  X. }6 U( _  ~! L' B5 n) b0 g
  76. 5 X3 }/ C7 V" e4 h4 d
  77.         I2C_X1_LOW();
    2 G1 u" G+ d' C* x) V4 r( J

  78.   m$ l2 [0 Z3 r/ I% S6 c" q' e
  79.     I2C_X2_LOW();        
    $ f1 N! U9 H/ Z) _$ s( x/ n8 ~
  80. * i9 X- d; u# O5 @; ]
  81.         I2C_X3_LOW();
    ( q( \$ `* \8 G

  82. + ~+ T; }3 e7 {! u
  83.         delay_ms(20);: [3 k! u& G2 A1 @, z' o
  84. + B; X: ?0 ]! r' n
  85. }
复制代码
3 j4 C1 U1 J, q- l. x& X; y$ z

$ p% _% _' j/ I1 J1 j- B

在模块初始化时调用IIC外设初始化,同时初始化4个测距模块。


  1. ! p. G6 m) q- s/ ]
  2. {
    ; |$ }1 Y! A2 {/ a- u6 b0 M/ x5 u# O
  3. - ]/ A5 r: c8 @! M( z9 ?' l  w
  4.         / c, k" [; A  Z# e/ H

  5. / n9 ~' j8 m& p% G
  6.     VL53L0X_Error Status = VL53L0X_ERROR_NONE;   //初始值赋值为0$ n; i% X- X+ u5 C* q$ q

  7. ! l# S( u& @# Z0 r
  8. 3 H4 l: f  i) V  t# I
  9. ! U0 H, v- y" P% r# Z8 k
  10.          //初始化一定按照这个顺序执行,否则不成功
      s" M2 L0 ^' g( H6 X
  11. * Z$ U) J& c7 }9 \. t3 F
  12.          VL53L0X_i2c_init(); 2 S" V! }  q8 P

  13. $ v! I5 N4 S% s0 y
  14.      vl53l0x_initX(&vl53l0x_dev0,0);
    9 i: I; B8 N- j- r3 u5 n) s3 n
  15. " w6 p* S* Q6 G; N, S( N
  16.          vl53l0x_initX(&vl53l0x_dev1,1);/ M1 W7 @" G$ W* X& h

  17. ! b2 _! Z; `9 p
  18.          vl53l0x_initX(&vl53l0x_dev2,2);, y6 _3 A. d# [+ l

  19. 3 U: E1 V$ n% p+ Z) K# n# Z. w
  20.          vl53l0x_initX(&vl53l0x_dev3,3);
    1 L4 Z2 s' B* Z+ H8 K' W

  21.   Q. x9 v; n( [# l8 Y; p% x, W
  22.            1 R% C- [3 D  o# Q+ Z' e% F& z9 A
  23. " h0 V: H# z4 W$ R3 D
  24.     return Status;           //返回0
    + {1 V- }( n+ A6 y, @9 U

  25. ' H! S; F$ r+ Y" P
  26. }
复制代码
2 d% |* R& T. e0 r+ r0 H2 d
' B( ~6 a0 _) |/ R

在vl53l0x_initX()函数便去别去正点原子的驱动,这里是全文的重点,很多单设备发展到多设备这里都会出问题,在初始化设备时一定要设置设备的IIC地址。

2 \. h: r: e1 T9 A

//单个VL53L0初始化
8 e% r2 G/ {, e# EVL53L0X_Error vl53l0x_initX( VL53L0X_Dev_t *pMyDevice ,u8 vl53l0_x_id)1 x  m0 u0 V6 k5 h( ]. p
{  d  k4 E2 B' @
        VL53L0X_Error Status = VL53L0X_ERROR_NONE;   //初始值赋值为0
( ]6 r* w/ i% K1 O        
% d4 {* s; }- {7 t. D        pMyDevice->I2cDevAddr      = 0x52;            //iic地址  0x52是默认地址,要初始化必须先写0x52,才能初始化,之后再通过软件修改
1 D# k( u, r' i0 J  v3 d- K    pMyDevice->comms_type      =  1;              //选择IIC还是SPI    iic=1;SPI=0: N& O8 O- s2 j6 @* H  v/ {
    pMyDevice->comms_speed_khz =  400;            //iic速率   
% l( c! h8 P  j: I3 d3 z- v        8 c6 z- v* O; {* v
        
5 ?' G! `1 c  L& S/ R5 \+ g        //正点原子的VL53L0用户手册上写明了再次使能时地址会恢复为0x52,所以只能使能一次,设置好地址即可,这里是核心
9 ?& ?7 T) F9 o( V% w  x3 ^* H        switch(vl53l0_x_id)
/ M: f& w' B4 v: l" D          {- C- d4 b# {+ \$ d/ w: r# \  i
                case 0:  
8 P. y1 \9 [3 V/ v2 F0 R* [* t                   I2C_X0_HIGH();  
2 i- n2 a7 \1 [; I1 l                  delay_ms(20);+ z9 u3 o4 l- _' n; V- B' w
                   vl53l0x_Addr_set(pMyDevice,0x60);//设置第一个VL53L0X传感器I2C地址- R9 I2 }$ W) Z$ D
                   break;% i: G. M1 L8 e% P# T& q
                case 1:                       8 r/ l" j8 J$ u( n+ a0 R
               I2C_X1_HIGH();
0 P9 t+ }2 }3 F$ u. M% s  Y. ~                  delay_ms(20);6 ]* e! r( e5 i* m+ ]2 B+ U
                   vl53l0x_Addr_set(pMyDevice,0x62);//设置第一个VL53L0X传感器I2C地址, U, `# e' z$ H3 {3 E% R
                   break;& z+ U1 Q' a! g
                case 2:  
9 E4 L6 l$ |+ p' W- k! [                        I2C_X2_HIGH();  
3 Y! u2 z5 b+ Y                   delay_ms(20);% _7 r. b0 n. m8 P
                    vl53l0x_Addr_set(pMyDevice,0x64);. o3 o4 @. Z0 r
                        break;( l9 d: C) {" P& ]! e
                case 3:  8 R) H- M! J. A7 Z9 ^+ d1 [+ [
                        I2C_X3_HIGH();  
2 C" T4 `4 L* o% W; L  K, {) ?  C* }2 E                   delay_ms(20);
# m; w- h" P. t$ S9 }; e0 V6 l                    vl53l0x_Addr_set(pMyDevice,0x66);# x2 Y9 _+ Y5 l
                        break;4 F. }" h  U; @5 B" I0 P# c; n7 R4 u+ Y
          }$ G$ Y, y6 Q3 o: ~7 ^( b6 W
        ! j4 M) R. g; r6 \1 g% V5 t
    Status = VL53L0X_DataInit(pMyDevice); // Data initialization  //VL53L0X_DataInit:一次设备的初始化,初始化成功返回0
) b+ p' X6 k' d+ b) Z    if(Status != VL53L0X_ERROR_NONE){     //判断如果状态不为0   打印错误信息
$ x$ r. w6 Y- \        print_pal_error(Status);
( c) g& E1 @4 [' Y# J6 C: h        return Status;        //  返回错误值 可通过此值DEBUG查找错误位置
# d2 q6 N0 i0 {' _" Q, @    }5 U0 G7 Q8 N* _" h1 {
# S9 n) d9 d4 d) Y! i( O
    Status = VL53L0X_GetDeviceInfo(pMyDevice, &vl53l0x_dev_info);   //读取给定设备的设备信息
3 p1 L* A: k% l( {    if(Status != VL53L0X_ERROR_NONE){
  f: w4 I7 g$ @" Q3 {4 S8 i        print_pal_error(Status);
7 y5 @: O  ?+ ~9 D$ H& O4 Q7 m        return Status;: S. A* `) g* P8 Y, m0 M, L
    }
; Y4 l+ ?3 q  E: Y& h% }2 @    printf("VL53L0X_GetDeviceInfo:\n");
" y# p: p+ Q* a, {$ o    printf("Device Name : %s\n", vl53l0x_dev_info.Name);     //设备名
4 Y( `# b+ \. b    printf("Device Type : %s\n", vl53l0x_dev_info.Type);    //产品类型VL53L0X = 1, VL53L1 = 2
+ W1 E8 A: n. Q! c    printf("Device ID : %s\n", vl53l0x_dev_info.ProductId);   // 设备ID/ C" z4 v6 M8 Z
    printf("ProductRevisionMajor : %d\n", vl53l0x_dev_info.ProductRevisionMajor);& A/ S8 B# D- v# T
    printf("ProductRevisionMinor : %d\n", vl53l0x_dev_info.ProductRevisionMinor);
) r" t. O, k9 ~( [6 F9 Z3 m6 g' m- ^- X7 w
    if ((vl53l0x_dev_info.ProductRevisionMajor != 1) && (vl53l0x_dev_info.ProductRevisionMinor != 1)){
" W& N2 d( F4 G* c# w: M        printf("Error expected cut 1.1 but found cut %d.%d\n",
: M  y6 O; a( c: r! [' E& }2 a        vl53l0x_dev_info.ProductRevisionMajor, vl53l0x_dev_info.ProductRevisionMinor);
5 E5 D1 R: v4 R8 G* l$ ]        Status = VL53L0X_ERROR_NOT_SUPPORTED;
4 b( l6 B3 t' b$ h        print_pal_error(Status);  D( \. ?7 U) z( K; K$ D% X6 X
        return Status;, [4 G5 L, X, r3 }- q/ H) j9 z2 L
    }7 v) M5 H! D+ y
. ^9 ~  p5 R; T4 u
    Status = vl53l0x_measure_init(pMyDevice);   //测量配置
* P/ a8 P7 @) x5 a* U    vl53l0x_status = Status;, ~; D8 L! G: {" z% w* ^
    if(Status != VL53L0X_ERROR_NONE){    //判断如果不为0打印错误信息
# `) O  |6 V: {5 R, C        print_pal_error(Status);3 V: L, E7 ]* g/ u- s
        return Status;% [, X' f) Z# z  f6 G" [5 t
    }               ) E1 Y. ~$ I# |' m) h  {
}

模块的初始化顺序是:使用默认地址初始化设备---修改传感器IIC地址---再次初始化---测量配置! \2 Y  V  U( J3 M
所以在这个传感器的初始化中我们先用默认的0X52地址将VL53L0X模块初始化,初始化完成后方可修改其地址,这里使用SWITCH函数判断用户配置的地址,避免函数重写,减小代码尺寸。修改完地址调用VL53L0X_DataInit()函数进行模块的再次初始化,使修改生效。注意:VL53L0X不能保存地址,如果掉电后地址会恢复为默认的0X52,同时修改完地址后只能执行一次初始化,更多的初始化次数会也会导致地址复位。这在硬件的处理上要加倍注意。: N, `6 Z8 s& F  _8 C( `
在这里我翻车了,因为硬件不在我的手边,我都是远程帮助调试,没看到硬件,我的朋友一直反应各种问题,最多的就是测距有问题,测出的数据都是错的,或者只有一个传感器可以使用。我检查了很多遍的代码,始终找不到原因,还好他自己也想到了硬件的问题(因为他们硬件干过很多错事,都是一些小白容易犯的,但是那个老员工比较粗心,也会犯错),最后发现是线的质量太差,线的长度太长,IVL53L0X模块安装的位置不好,因为模块安装在可动部件上的,导致每次移动都会导致模块短暂的掉电,导致地址复位。后来加装模块的减震装置更换屏蔽线解决问题。
. ~7 U1 T& P; ]+ Q& T复位完成便可以测试:


8 s# t# ]' [$ Q5 `5 _. d8 c) z


. `) L: d* u- A8 \

  1. VL53L0X_Error vl53l0x_start_single_test(VL53L0X_Dev_t *pdev, \
    5 [8 I3 O  K0 E) j0 K; a
  2. 5 e/ q$ `- E7 y8 R+ J" W
  3.                             VL53L0X_RangingMeasurementData_t *pdata)
    : {  m2 ~5 s3 F3 M; R

  4. ( i2 @. n3 i9 w# q6 W$ u1 J( P5 H# f
  5. {+ N) r, |$ y, ~- E! Y0 |' p0 V, w: H
  6. " b  H: h! I' u, t: h& [) Y
  7.         int i=0,j=0,sum=0;5 f- P, s1 w) F
  8. , {6 p  t6 l2 J8 A  ]* @
  9.     VL53L0X_Error status = VL53L0X_ERROR_NONE;
    5 Z8 [% o+ j" U3 e
  10. # E% g- u& q, K* Z
  11.    
    # M) L! `! f7 J9 G; ^

  12. % X7 ]; _  @9 T& Q8 d6 i
  13.     if(vl53l0x_status != VL53L0X_ERROR_NONE): \/ W5 \" H, u
  14.   Y; p7 e* s8 B5 Y' F$ h: [
  15.         return vl53l0x_status;0 c+ m" F6 V! m( S* C4 p# s

  16. $ v( U2 m. e2 a0 K
  17. ; p  J. N: |% v& c8 Z4 w2 h

  18. 3 H  E7 s8 l. O' y, a3 O6 G7 p
  19.     status = VL53L0X_PerformSingleRangingMeasurement(pdev, pdata);   执行单次测距并获取测距测量数据
    4 K6 [, @( y7 T6 ^. P8 @
  20. & R' P2 U3 ?( B0 N
  21.     if(status != VL53L0X_ERROR_NONE){
    % ?0 U$ w) F( t# Y+ l  v6 m" O2 N6 F
  22. 9 Z) w0 r" K0 a( e( f
  23.         printf("error:Call of VL53L0X_PerformSingleRangingMeasurement\n");
    " A5 |$ k$ F8 z- l; l
  24. 6 x0 Q; x# {4 E3 C
  25.         return status;" j5 ]9 z1 @/ g: Y. A

  26. 3 T4 J1 T3 N* h5 Q
  27.     }
    * S+ Z0 F1 O2 I/ R. o7 z

  28. $ Z/ m& {1 f% y! j$ ~

  29.   t4 A  H: z. j' ?5 r( e
  30. . Q$ l$ }6 s: j! L- Y5 ]
  31.                 for(i=0;i<5;i++)0 m% L# d$ ?  d8 z/ C

  32. 9 Z, Y' M' f0 r( t' v. t+ G
  33.                         sum+=pdata->RangeMilliMeter;  J9 E! M2 B, N% N
  34.   d* l: s( m; f3 R' C+ t# u) [
  35.                 pdata->RangeMilliMeter=sum/5;; I) p7 j  y  e

  36. % T2 X( x* I" s2 D
  37.         printf("%d\r\n",pdata->RangeMilliMeter);6 X1 u: d5 m& T; b, i2 T3 ^% d

  38. . g. v8 d9 F* h; `
  39.     return status;- n( d) a% G; A

  40. , u5 y( ?+ U6 b* R; o
  41. }
复制代码
) k) u& |$ ~8 U  ]1 c


% Y1 Z2 u( I! ^

打印测试结果,通过!

. a% Q! d# S' l0 o% {9 @$ N
主函数循环测试,因为项目对代码的速度要求不高,所以一些状态判断代码中还有保留,这里跟着原子走,没做太多改变。# M( R% y  Q  {: {; I9 |
因为这个项目是帮助朋友做的调试,而且他们的项目还在研发期,太多的东西不能介绍,照片啥的都放弃了。一个简短的帖子,希望能帮到大家把握住该模块,蟹蟹。0 D- c+ r8 s( p8 ^7 b
---------------------$ z9 H7 Y7 U7 [$ w9 h% @; Z
作者:呐咯密密


; T: D  y/ h* b4 S6 y( ]* @' B
赞 收藏 评论0 发布时间:2022-12-10 23:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版