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

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

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

最近给朋友调试了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。

  1. #ifndef _VL53L0X_I2C_H
    4 a5 M1 W& @. o) J  z8 j' U: J
  2. 9 i# L- M' @$ Y- m- @' z: u0 L2 C
  3. #define _VL53L0X_I2C_H
    9 g% H7 z* r- C0 c" ~, e
  4. ; N0 q, c! y# C
  5. 0 ]" K" I5 P! }6 s3 H- f
  6. . N2 C- M- U( ^! s
  7. #include "stm32f10x.h", d% S" p$ d6 n
  8. 3 q1 i  ?% k! n2 A; |8 c* k
  9. #include "stm32f10x_i2c.h"; u  F1 }, |  y! Q) t6 E
  10. : n+ i. K/ }. v
  11. ' L& N' D5 U$ {3 b7 |

  12. 4 y2 \, V! Z! X
  13. //四个VL53L0挂载在同一个IIC总线下,所以使用四个片选信号--2019/10/302 t6 }) i- R3 A- \

  14. $ L7 U' A. D2 L/ a  E% d
  15. //!!!!!!!注意:重新使能设备后,设备iic的地址会恢复为默认值0x52--2019/10/30
    & u: Y2 r, M, F+ n# O

  16. ( C+ n. E) s" w$ ]) t
  17. //VL53L0 0
    7 u0 {6 y4 b6 S4 R' G+ I

  18. 5 {0 X' m) O: M8 g* D
  19. #define I2C_SCL_GPIO               GPIOB5 r) i0 G0 b$ ~) w
  20. " N7 o; N/ Z4 H8 ~8 t" |+ t4 N# n
  21. #define        I2C_PIN_SCL               GPIO_Pin_8
    ( k# t% M; @# |' }$ j# U& v# h4 Y
  22. " q" i" A" o, u
  23. #define I2C_SCL_HIGH()      GPIO_SetBits(I2C_SCL_GPIO,I2C_PIN_SCL) , k  e. q  I4 \; r
  24. - v0 p* {5 ?$ l+ Y: A" h+ y
  25. #define I2C_SCL_LOW()              GPIO_ResetBits(I2C_SCL_GPIO,I2C_PIN_SCL)
    + [3 Z. c# y3 V% C% q
  26. ! _5 C% X% _. x! z( G" [1 D

  27. 3 K4 p% V6 c! u+ E  C0 P
  28. 6 a! c) v' @! J" L/ A; m
  29. #define I2C_SDA_GPIO               GPIOB4 j3 \. E: ]% F5 g* F; q* K

  30. ! ]: h  @- }& g+ h. P3 u
  31. #define        I2C_PIN_SDA               GPIO_Pin_9
    ; ~* a0 |2 J7 V( @
  32. + @# N3 g9 P. w$ m
  33. #define I2C_SDA_HIGH()      GPIO_SetBits(I2C_SDA_GPIO,I2C_PIN_SDA) * a" L+ J, W) z

  34. $ t' n6 ?$ D/ C. c' `8 N6 @6 v$ ?9 t
  35. #define I2C_SDA_LOW()              GPIO_ResetBits(I2C_SDA_GPIO,I2C_PIN_SDA)
    1 a( P6 r/ P% }) G. U( `

  36. . E/ e. G: X& {5 {7 Q% O' e9 }
  37. #define I2C_SDA_STATE       GPIO_ReadInputDataBit(I2C_SDA_GPIO,I2C_PIN_SDA)( d* k& d" Y- r
  38. - P2 x1 l3 D- h: _& X4 A8 d: k

  39. ; H  `4 Y# f5 k) |( K
  40. - ?+ O0 D, t) C9 i) J: w/ H2 t* L
  41. //片选使能--2019/10/30  g, U7 R- I0 ]
  42. . |5 m* G' L/ D: f& z) @3 v& a
  43. #define I2C_X_GPIO               GPIOB
    ' |$ A% o' i1 ~# |1 a# ?
  44. , q1 k+ o+ O3 L( U/ f
  45. #define        I2C_PIN_X0               GPIO_Pin_12/ _7 `& w7 V  A. A( X% q
  46. 0 C- D$ `6 J9 }, }9 R
  47. #define I2C_X0_HIGH()       GPIO_SetBits(I2C_X_GPIO,I2C_PIN_X0)
    ! @+ b1 A& j* w% L0 \7 V
  48. 2 G$ I) U$ U; h& h/ _
  49. #define I2C_X0_LOW()              GPIO_ResetBits(I2C_X_GPIO,I2C_PIN_X0)
    # [) T- Y4 z4 x% f3 \( \$ v& x
  50. $ i& c1 P! s3 i# ~
  51. , g( D  Y! j! B/ ^& O

  52. 1 c% d3 q6 r+ D3 {
  53. #define        I2C_PIN_X1               GPIO_Pin_13
    : {+ G" C( \- M  H- E+ z
  54. $ r1 K2 S9 _+ z2 D
  55. #define I2C_X1_HIGH()       GPIO_SetBits(I2C_X_GPIO,I2C_PIN_X1)
    ) C* X4 i+ ?0 `* _- _/ ]. j

  56. 1 J9 }$ Q" k5 G7 t
  57. #define I2C_X1_LOW()              GPIO_ResetBits(I2C_X_GPIO,I2C_PIN_X1)
    . r5 K$ s& e& w% z, c4 g
  58. ; D2 b+ M, B" u9 e8 a/ Q/ C& }: ]) @

  59. 4 R5 O* R+ z9 z

  60. . L+ G6 u# s$ F
  61. #define        I2C_PIN_X2               GPIO_Pin_14+ {: G( r: Z. [! E0 E

  62. : s& A" n* Z, X' L& e6 P
  63. #define I2C_X2_HIGH()       GPIO_SetBits(I2C_X_GPIO,I2C_PIN_X2) : R  ~7 x4 V) `2 A+ D+ o% t2 X

  64. : @9 m5 Z6 H3 k! `0 [3 N
  65. #define I2C_X2_LOW()              GPIO_ResetBits(I2C_X_GPIO,I2C_PIN_X2)
    , t& G& ^  {6 _/ q6 |

  66. : o+ l" X' E: j
  67. 2 e9 k, l* ~3 G; p& i6 Y
  68. 9 V% A! M" f' {1 _( ?" y
  69. #define        I2C_PIN_X3               GPIO_Pin_15
    ( h# M7 @$ `  _; d! K' N% h! N
  70. $ `; C$ {- a, W" B2 _6 m
  71. #define I2C_X3_HIGH()       GPIO_SetBits(I2C_X_GPIO,I2C_PIN_X3) : k% e+ _1 z( c$ u' y6 \8 E
  72. , w) ~( }  i/ i. w# V9 I
  73. #define I2C_X3_LOW()              GPIO_ResetBits(I2C_X_GPIO,I2C_PIN_X3)6 r) m0 A5 ~# W0 i2 d/ I: ~  M2 O

  74. : {5 Z' P+ L) n' m, }7 p/ Q
  75. 2 m4 Z* ^4 n4 `2 ?
  76. * u9 J1 P6 D/ |) V' E$ i  m( _
  77. void i2c_init(void);
    4 L  c9 `, |3 |- Q
  78. 8 {" j: |1 r" @& g. q& g3 t
  79. uint8_t i2c_write(uint8_t addr, uint8_t reg, uint32_t len, uint8_t * data);
    # J, }1 F5 k9 c2 V
  80. / o8 L# l, K. |5 v, t( p
  81. uint8_t i2c_read(uint8_t addr, uint8_t reg, uint32_t len, uint8_t *buf);0 z' Z8 T" w, t9 Z5 w
  82. / g8 I1 `% O! ]$ b$ g

  83. 1 j& M; {- q  h. r' n5 p
  84. * N5 E2 Y. t# ]  q

  85. 3 Y9 V7 d- f: G) Q, D* c
  86. 2 `: g& |8 W( E1 L9 J
  87. #endif
复制代码
  1. void i2c_init(void)! |0 y7 I5 a2 m- Z1 }
  2. . V/ a6 o# b( X+ h
  3. {, [* h, k( X7 S0 t: t5 Y9 [

  4. 4 F. c+ g  D+ V" J
  5.     GPIO_InitTypeDef GPIO_InitStructure;" o# f5 Y3 u* I  E* D

  6. 6 X9 e) ^0 N4 ?
  7.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);, T, I- r7 h& T1 w' `

  8. - k6 ~4 U* Q. b2 x
  9.     . }& E- t# p0 l& _& ], F4 d" \1 U
  10. ) T5 c2 P6 m% Q4 v9 M. ?& H
  11.         //模拟iic配置
    % u* R& U) ~; J: c0 {+ x
  12. ) _) b2 G- L/ q( J: ?* j
  13.     GPIO_InitStructure.GPIO_Pin = I2C_PIN_SCL;% u* S$ ?. X8 B  }; h( U7 o

  14. * p1 D  F4 Z( @1 o
  15.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;3 o3 l, }$ e. q; k+ L3 R$ g% w
  16. " w! m  c. |: X' t: r
  17.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;) i6 M. F1 s) T& W+ h6 I

  18. , Q. ?* Q3 t' J
  19.     GPIO_Init(I2C_SCL_GPIO, &GPIO_InitStructure);. @. q8 r- f- `7 e
  20. " v- M9 I3 }* J# [$ O& `2 v

  21. 6 C4 J8 R) u) c9 Y. P

  22. + z" _' l& j4 M' h; n4 u8 b
  23.     GPIO_InitStructure.GPIO_Pin = I2C_PIN_SDA;
    - R. x# G" ~$ [% o' d
  24. 9 i# f( d: B/ s' z, g  N
  25.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;. T1 T: Y3 P4 h: d) n4 r
  26. 6 k5 M* M, Z  k$ o# r$ v
  27.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
    - b4 q1 I! R3 o. i& s
  28. 7 [, K0 I. |- w% K. O
  29.     GPIO_Init(I2C_SDA_GPIO, &GPIO_InitStructure);
    4 z6 O) w" O" r; t5 o4 O
  30. 2 T3 b) Y* ^8 g2 x/ V& v' M
  31.         
    9 a+ w5 k6 p: e% ^  L
  32. 3 t9 T: P+ H& r3 {5 d' ^; p" _
  33.         //片选使能配置' r- K6 W" A/ ~. V
  34. 2 j9 c. a  r  e* x. ]. B4 w
  35.         GPIO_InitStructure.GPIO_Pin = I2C_PIN_X0;
    ' q8 b+ p$ }6 u, Y* z% A$ M9 M
  36. 3 r) x4 @" N' d4 J. ~1 Z. S
  37.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;3 L/ B( I+ u2 J, N) Z
  38. # y3 M2 _& h2 ^8 A6 p
  39.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    ! }5 O# k1 |6 f7 ~# T% C% R* \

  40. 6 W' f- V5 ~0 |% v- {: u$ L
  41.     GPIO_Init(I2C_X_GPIO, &GPIO_InitStructure);. _& f& x! y  b! ]. i" T9 S2 J' ]1 E

  42. 3 n9 `5 m/ o. S
  43.         / C8 s& _# s! f, K

  44. 6 ?3 K7 {$ _6 P0 d5 m( z
  45.         GPIO_InitStructure.GPIO_Pin = I2C_PIN_X1;6 c, r! E: _$ s& I: M) y7 s0 k7 `; c

  46. ) O6 m" _. P3 {" g
  47.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
    " c5 }  q; ]/ k2 T
  48. 8 ]7 Q" ^  {; M2 `
  49.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;1 j% l! r" u+ J: B9 X+ w  J9 J/ _
  50. * K7 B7 C4 s8 U- w
  51.     GPIO_Init(I2C_X_GPIO, &GPIO_InitStructure);
    1 v' m( s3 B5 C  C# C" F; x
  52. + H" G0 g* P! [& ^3 F  Z) j
  53.         3 Q7 o9 X  G; n
  54. / i% J$ i' }7 b8 v# D% y# ^; b
  55.     GPIO_InitStructure.GPIO_Pin = I2C_PIN_X2;
    " T2 |, b7 i9 Q" {
  56. 9 C; g1 I$ R. \% v, C1 P# b) ?
  57.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;5 H% w' I" q$ M* |

  58.   |/ h; M+ D5 v) a+ A
  59.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;% Q$ {3 ^- @4 E. H

  60. ) `3 A: x+ h' z0 W' _) Z" R/ F1 ~3 a
  61.     GPIO_Init(I2C_X_GPIO, &GPIO_InitStructure);$ J0 c" H1 C& Q. p# R9 s
  62. $ U: z; W' a* w( t' h* t3 T$ |
  63.         
    * h6 m( L. L* A- A- R9 g( u* b0 F
  64. 3 Z; Q6 Y5 ~* E/ `8 c0 N
  65.         GPIO_InitStructure.GPIO_Pin = I2C_PIN_X3;
    # `9 b3 ^$ V5 f0 n

  66. % l7 I* O9 d! V
  67.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;7 g' b3 G$ ?" b$ K4 o4 ?2 K

  68. ' }, G" Q" {( |0 T+ X
  69.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;' ]- ^9 t- ~3 Q- |/ f4 x7 w& \% P3 t
  70. " E; J- m; X+ m2 w
  71.     GPIO_Init(I2C_X_GPIO, &GPIO_InitStructure);  T2 j2 \* [% h' G: C" t2 a3 w1 `
  72. . M8 \% c4 T3 s" ~) a, r- I
  73.    
    % y8 ~# E) I2 K$ b
  74. 4 n+ y1 Z" {( s6 E: n
  75.         I2C_X0_LOW();        9 r9 O- s9 ~2 ?
  76. 4 g2 E5 h" t% Q, p
  77.         I2C_X1_LOW();6 s9 s2 K3 N" M) T

  78. ; s. _( c' E: h( b) t8 d1 r* X5 B
  79.     I2C_X2_LOW();        7 c* K) c4 O3 e' e. a4 I3 R
  80. ) f  G4 X/ v$ \4 _0 p& S, g
  81.         I2C_X3_LOW();
    5 a0 R! W' z2 h& f7 G2 x
  82. ! t! o1 y& G2 Z3 L" P5 q& {& {
  83.         delay_ms(20);3 ]: U3 L) I0 J

  84. ) P9 P; D, A: U
  85. }
复制代码

7 |2 R8 }) K& n0 j- Q

# Z4 b$ t# ]8 R9 Y

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


  1. & \0 P3 m5 Z: q8 H+ ?% ^3 H
  2. {! K9 v( U6 B2 c6 @. z
  3. , T  _' M7 Y. v/ `
  4.         
    , [! d1 d. |. \1 j

  5. 9 i, I( Z* \  Q* i- r( p
  6.     VL53L0X_Error Status = VL53L0X_ERROR_NONE;   //初始值赋值为0
    : `  F" P9 Q0 _1 w1 U
  7. 3 {( a  t4 b' N* U) |
  8. ' ^, b5 H3 L$ q; y

  9. & A0 p, a9 e' K! n$ X# d
  10.          //初始化一定按照这个顺序执行,否则不成功
    9 s' X! }' i* A- p

  11. 2 N# e: q4 [* g0 |
  12.          VL53L0X_i2c_init();
    1 M) C) _( G' Z+ m

  13. 8 y' i( E0 h( G
  14.      vl53l0x_initX(&vl53l0x_dev0,0);7 o  i6 f2 W  P" R/ g, Y
  15. 5 o- q  X2 T2 k  j3 O
  16.          vl53l0x_initX(&vl53l0x_dev1,1);( b" u3 q& |9 _% v" u
  17.   ^0 U; c/ x' E, I/ D
  18.          vl53l0x_initX(&vl53l0x_dev2,2);
      ^3 |' ?5 x+ x; @* i
  19. ! B" K, g3 s+ w9 X1 X
  20.          vl53l0x_initX(&vl53l0x_dev3,3);3 N! |, b/ S; b; K
  21. 2 e9 ?5 U' Z  Q7 q; i# Y+ G2 u5 w4 J
  22.            + s1 Y& Q" F+ g% w
  23. & V2 q! K5 X' A' k9 c& ?  J+ L
  24.     return Status;           //返回0' r6 V+ J5 ~( x: k# B9 A/ N6 ^

  25. ( c1 L' f$ J0 r( N4 Y8 Y
  26. }
复制代码

+ 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

  1. VL53L0X_Error vl53l0x_start_single_test(VL53L0X_Dev_t *pdev, \
    . c, A7 a4 L9 f& }" R. L0 H! U5 i

  2. + f& v# x9 ^4 ~' I2 y, M2 `
  3.                             VL53L0X_RangingMeasurementData_t *pdata)8 h3 f/ x- H/ j4 ]3 l! Z
  4. + k: {; o# l; h5 E% S) S
  5. {9 y% \/ P4 m# h* ?. I( p! {/ V
  6. 5 U& n. O6 l9 ^( e8 x
  7.         int i=0,j=0,sum=0;$ N7 U3 }& ~3 T& S- O3 }' S9 r
  8. 6 L7 A! ~7 I' X
  9.     VL53L0X_Error status = VL53L0X_ERROR_NONE;
    9 c: D- u4 T" q& d

  10. 8 U( ?5 `% ~1 i
  11.    
    ; w0 a* l. T1 P
  12. . H7 L' H- E, L) x: b. }
  13.     if(vl53l0x_status != VL53L0X_ERROR_NONE)
    0 X7 A8 o% w" m' {8 s

  14. , E* n9 ]# u4 Y# \4 M
  15.         return vl53l0x_status;
    / w5 q: f" L7 u: J6 G8 ]/ p

  16. + o  t  _5 }* `( u0 B+ f
  17. : o6 h0 I% C: j2 j
  18. / Y: r; t% D8 n2 s, x% M& N3 u3 M
  19.     status = VL53L0X_PerformSingleRangingMeasurement(pdev, pdata);   执行单次测距并获取测距测量数据
    ( p& A- L2 s+ p! F# `

  20. . o4 B6 ?# N: o. [5 h5 {
  21.     if(status != VL53L0X_ERROR_NONE){; G' A$ k5 r9 b% m+ t# s& V

  22. . X& ~3 `2 X4 S* l* \, N# t6 r
  23.         printf("error:Call of VL53L0X_PerformSingleRangingMeasurement\n");* T- P0 ]2 x# b+ c9 n& x

  24. 3 @# k8 u1 ]' p1 X( d
  25.         return status;
    0 F$ G4 b2 \9 ^

  26. & O: b1 v) I1 j# C' E
  27.     }( X: k  n1 g3 Y! R. v( |/ @
  28. 6 |! |4 E7 J# x# p- i0 F
  29. ) ]' y. T1 a; x" ]) X5 _) M

  30. 4 _4 q5 |% H' R6 x% P) e4 b  c
  31.                 for(i=0;i<5;i++)
    ; ]6 Y( f( l* u& {: j
  32. : ]0 R: Q! }. z: G3 |9 {3 b
  33.                         sum+=pdata->RangeMilliMeter;
    : H, O/ t; X( s7 k- ?% B& ]$ `" R

  34. . V) j, a) f: X$ Y
  35.                 pdata->RangeMilliMeter=sum/5;+ ?3 i- u# \  n) \# C2 g- G
  36. , n+ r& X  o: T" n( a
  37.         printf("%d\r\n",pdata->RangeMilliMeter);
    ; ?9 z# y* b2 d2 t" i' O
  38.   }" n% E9 u3 ^: V, u
  39.     return status;
    1 k' `- ^* h2 W; v0 j) B! [

  40. : }2 _# t+ Q: U- C0 u& f3 Z
  41. }
复制代码
/ 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% ~  _; \# ?+ [
收藏 评论0 发布时间:2022-12-10 23:00

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版