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

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

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

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

  1. #ifndef _VL53L0X_I2C_H8 I3 @2 s. l; r" Y. E* L
  2. 1 P+ l' g$ N' f: M; D! r
  3. #define _VL53L0X_I2C_H
    ! b6 G% S9 ~! N

  4. 6 E4 c0 ]3 h  `& h' G% L& ^

  5. ' N0 S: l  O6 \. O5 _6 h% }" S
  6. 3 D/ c4 ~5 p# P1 d2 m, w- u
  7. #include "stm32f10x.h"# X0 ^* ?( n+ j7 j
  8. 5 B. U0 r& @: D8 V
  9. #include "stm32f10x_i2c.h"
    8 ~( g8 y6 N1 {) F$ I0 k

  10. ( P$ N2 C! ?  Q7 a2 [1 {9 `
  11. / R% w! [& S  Z8 u% o
  12. 8 T* f1 {+ J- G/ t0 ?
  13. //四个VL53L0挂载在同一个IIC总线下,所以使用四个片选信号--2019/10/30, d, [9 f2 X* L

  14. 8 h, E" I! R' ~. x% X
  15. //!!!!!!!注意:重新使能设备后,设备iic的地址会恢复为默认值0x52--2019/10/30
    * y/ D, i8 h+ x; I9 I3 H2 r  b' ?: J

  16. : e+ t, y+ I( U: A+ i2 Z% Y% c* X
  17. //VL53L0 0& v) v0 e2 q3 p

  18. ! _/ R, Q7 i" b: Y4 h
  19. #define I2C_SCL_GPIO               GPIOB3 `; _2 m: \7 Q3 Y$ S( d

  20. & R  E$ r' Q, R% L
  21. #define        I2C_PIN_SCL               GPIO_Pin_8
    7 ?) \: B' g( p% I5 t4 K5 y% S3 L! Z  s

  22. ( `; b5 U# g0 {" ]+ `# [* _
  23. #define I2C_SCL_HIGH()      GPIO_SetBits(I2C_SCL_GPIO,I2C_PIN_SCL)
    ( x: x. ]0 @9 g: Q8 i3 W

  24. . p- w2 p( {9 R2 \$ C
  25. #define I2C_SCL_LOW()              GPIO_ResetBits(I2C_SCL_GPIO,I2C_PIN_SCL): z) A3 @/ W# P: m6 C) R
  26. ! X8 P* |& B( c1 u5 E: ]
  27. % T6 k8 F" z" T  N( Z

  28. : k4 c, W# T) s& ~
  29. #define I2C_SDA_GPIO               GPIOB
    & e% d3 C+ E9 s; H

  30. 3 x2 ?1 [8 i3 M9 s6 i" l) N
  31. #define        I2C_PIN_SDA               GPIO_Pin_9
    6 x( {8 _0 E' s
  32. * ]# e2 m0 f2 l, W1 a* F9 v
  33. #define I2C_SDA_HIGH()      GPIO_SetBits(I2C_SDA_GPIO,I2C_PIN_SDA)   L6 I/ ~' T# x

  34. 5 I/ X) R- B5 E
  35. #define I2C_SDA_LOW()              GPIO_ResetBits(I2C_SDA_GPIO,I2C_PIN_SDA)
    4 E! P1 f6 H( K; C5 h) M

  36. : ~- D4 u9 Y* K2 I
  37. #define I2C_SDA_STATE       GPIO_ReadInputDataBit(I2C_SDA_GPIO,I2C_PIN_SDA)
    ) G! i$ F& Z" M- y$ W- l: F$ z" q

  38. , M3 l4 I  n" ~; N. _( H* U# g
  39. $ x$ _; e  c; p2 p- c5 b0 h5 }+ R

  40. ( W! U; I' n1 p
  41. //片选使能--2019/10/30
    ; C7 u7 i8 _" O/ x1 b- k

  42. ' J9 O+ ~2 `8 f" `2 s3 B$ ^7 o
  43. #define I2C_X_GPIO               GPIOB* p9 M. g! E$ k1 B1 H

  44. # N* G4 j# h" `' a: d+ m
  45. #define        I2C_PIN_X0               GPIO_Pin_12
    - W, K  G3 N. \! d

  46. # j0 c7 }) k( x) V6 L7 [1 d
  47. #define I2C_X0_HIGH()       GPIO_SetBits(I2C_X_GPIO,I2C_PIN_X0)
    / s  ~- Z+ b- f% i

  48. ; W, s) x3 Z% N9 p5 \$ [
  49. #define I2C_X0_LOW()              GPIO_ResetBits(I2C_X_GPIO,I2C_PIN_X0)
    ' t! w7 M: t( g. }5 T& E
  50. 2 W/ c) a1 \) m- m7 F
  51. " U/ V- Q9 ?9 G! g

  52. ' ^8 c1 B. u- s: X' J0 [
  53. #define        I2C_PIN_X1               GPIO_Pin_13
    2 p5 l6 ]$ x. w* F6 _9 E  t

  54. 8 E+ s9 j) p% _: x- m: `" Q, m. {5 Y8 k' Y
  55. #define I2C_X1_HIGH()       GPIO_SetBits(I2C_X_GPIO,I2C_PIN_X1)
    0 b1 t  j; E* S- q
  56. # Q4 d: Z/ [! {  G
  57. #define I2C_X1_LOW()              GPIO_ResetBits(I2C_X_GPIO,I2C_PIN_X1)* C/ V3 Z- {- C, A7 c( u

  58. ; M+ e1 @4 h1 U
  59. 7 h, V. n5 V5 d& c
  60. 5 |+ h! `: q$ ^6 u7 l% n3 K
  61. #define        I2C_PIN_X2               GPIO_Pin_146 Z; O, M# A+ v/ [; g

  62. * v5 L) w4 ]1 w  U; u) Q! W9 i
  63. #define I2C_X2_HIGH()       GPIO_SetBits(I2C_X_GPIO,I2C_PIN_X2)   R* v6 _) {/ k( N) |

  64. ' L- [/ o5 ]% V: E" k
  65. #define I2C_X2_LOW()              GPIO_ResetBits(I2C_X_GPIO,I2C_PIN_X2): S: m6 `, V. n2 Y, A+ @% ]
  66. 0 b- R. h* i, b

  67. ; V' D: f+ j1 d% Z' Z2 i

  68. * [7 U% y# m- a' `
  69. #define        I2C_PIN_X3               GPIO_Pin_15
    ) L- C; v& M6 o
  70. ) e. j5 I: N/ C. y
  71. #define I2C_X3_HIGH()       GPIO_SetBits(I2C_X_GPIO,I2C_PIN_X3)
    7 c  W) U5 N$ s! e5 r+ o

  72. 8 W1 a  c, y6 r
  73. #define I2C_X3_LOW()              GPIO_ResetBits(I2C_X_GPIO,I2C_PIN_X3)
    1 R5 \  Y3 s1 p9 O

  74. 1 ]$ w) k' ?+ P6 N( k' v

  75.   y* _% W- \9 J3 H2 }

  76. # l3 i( w" Q  e( R, b, [
  77. void i2c_init(void);4 @5 W) R( z9 L6 Q- H
  78. & }# c" [8 ~8 f2 b8 @" ?; ^
  79. uint8_t i2c_write(uint8_t addr, uint8_t reg, uint32_t len, uint8_t * data);. U$ }* q, r- |" \/ |
  80. 5 a1 Y, F& b- @7 b5 [9 r
  81. uint8_t i2c_read(uint8_t addr, uint8_t reg, uint32_t len, uint8_t *buf);9 ~4 a! Y0 P. g0 E6 ^
  82.   E; L2 C) W) f0 O  R- v+ y2 M' R

  83. / F' d5 W& I) ~; m+ l" n& G

  84. + v% @' P/ O' F* x6 _3 @5 v7 n2 L
  85. 1 L3 p* W7 ~; h$ N# d6 }
  86. * e) o- I$ k, l) b# z. B' J; H
  87. #endif
复制代码
  1. void i2c_init(void)
    1 {, w: H$ V. B8 L( n8 U
  2. + a" |+ C/ e  C0 I7 b% A' M
  3. {
    0 y. l, ]- ~/ b% q
  4. 5 i* ~7 h2 h7 F/ X
  5.     GPIO_InitTypeDef GPIO_InitStructure;
    2 H! x0 ^- j- X

  6. 4 G8 j" K' V3 }+ ?4 a2 n( [
  7.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);3 m& b" k2 }/ R9 }' B# V
  8. # ^# }& e& n1 T0 m& q. `% j9 |
  9.     : \: k3 y! ~2 p+ h3 }
  10. + S) `8 r2 U: C( V7 J
  11.         //模拟iic配置
    : d& P- P; ?' n, q- x

  12. / X0 Q* f: L* ]( A6 Q1 {/ E
  13.     GPIO_InitStructure.GPIO_Pin = I2C_PIN_SCL;
    6 T8 T7 [: f5 u2 b0 k

  14. * z; c1 z4 m( \9 n$ Y: g1 v2 l
  15.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;- L" Q+ t4 B) O/ G0 A- Y

  16. 5 j3 M; ]  R6 _
  17.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    3 t  x  r3 j  j' Q, |( G

  18. % I$ m% ]2 w! S
  19.     GPIO_Init(I2C_SCL_GPIO, &GPIO_InitStructure);
    + T- Z. [) E3 q1 P# S# S3 P, u
  20. - @9 c. m7 _: Z8 u/ w/ ]; l- X
  21. $ ]+ p( f" C3 a7 q
  22. # ?& v6 I! u2 l
  23.     GPIO_InitStructure.GPIO_Pin = I2C_PIN_SDA;
    . c! E+ \8 \' o: e2 S( b: }- D
  24. # k( W$ {7 H7 n& ~! ?
  25.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
    " X. [7 U9 T/ O  d* ?- X
  26. 5 \4 T$ ^5 @& h& U2 U
  27.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;. r% z  p' k& P- X4 a
  28. 3 p9 g- @/ A! {# N/ F' d$ F* r
  29.     GPIO_Init(I2C_SDA_GPIO, &GPIO_InitStructure);3 W& n* Y  F. [$ T+ O  Z
  30. , }7 {! ]* O" m" i
  31.         , G& t& O6 p( ?5 j

  32. + q! [- h4 ]3 k$ A2 _. R2 s
  33.         //片选使能配置
    ) v! _) L; [8 I4 F1 q) i1 E4 g! x& H

  34. & D9 u* Q7 N2 O
  35.         GPIO_InitStructure.GPIO_Pin = I2C_PIN_X0;
    : Y, d  N' W0 c, K2 |# h* Y) P

  36. 5 f8 A; U3 g3 H7 Q9 s/ M4 o
  37.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
    7 ]- D2 P$ D  f
  38. . w4 I; w+ W! I# }3 c
  39.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;4 ?8 b; ~5 W+ f$ n3 O1 n

  40.   i1 l9 D, c( B/ w
  41.     GPIO_Init(I2C_X_GPIO, &GPIO_InitStructure);
    $ d1 j/ b( T. _8 |
  42. ) b# g7 q2 x; l3 \
  43.         
    $ D1 f* ?" K: D, v% q5 ?! D8 `2 q
  44. 4 `7 j! \% O6 j" ]% F7 @
  45.         GPIO_InitStructure.GPIO_Pin = I2C_PIN_X1;9 f* l$ \  v8 a; l3 [
  46. 0 Z, ^: r4 F- `( ~2 R7 C
  47.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
    2 O4 n* l1 G8 N4 g
  48. - f- e/ W. X6 i/ X- G
  49.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    & |9 J+ z& M! ?
  50. , p" j1 J2 w5 G
  51.     GPIO_Init(I2C_X_GPIO, &GPIO_InitStructure);
    : r+ v! H; Y+ u) r5 o
  52. ( Q3 L5 A* t+ s/ o
  53.         ' V+ F& d& y! q/ |& Z# ?: x% y
  54. 5 u8 X+ C! k3 {0 {5 Y
  55.     GPIO_InitStructure.GPIO_Pin = I2C_PIN_X2;
    7 T- J& m, h3 T! p

  56. ) R& A- l+ a- {# C9 B) Q1 p
  57.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;6 U& e" n2 E2 V8 P
  58. : T3 E% P' P- Y$ b* F! n# p: t
  59.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    ' u3 K( x: I( Q/ ]& d8 _7 v

  60. 9 \; M9 S/ H  |2 H1 c" v
  61.     GPIO_Init(I2C_X_GPIO, &GPIO_InitStructure);( L. K% `: R2 O
  62. 3 h, d8 T, \9 l. `; e; h5 V
  63.         ; h/ v1 u4 S7 p

  64. 6 h, ]4 W; i4 b  p' G$ [' @1 ]9 B
  65.         GPIO_InitStructure.GPIO_Pin = I2C_PIN_X3;
    : p# F0 G# {- C. h; J
  66. & f* {/ w( M$ ~9 }" D( v5 U5 ?
  67.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;* S3 V) D7 ~/ |: E" H) ]: U

  68. ! p, k- ]: E# o% o- @9 F
  69.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;4 y3 ]/ r; Y! _  \2 M

  70. % J, e0 ]7 G( ~* e
  71.     GPIO_Init(I2C_X_GPIO, &GPIO_InitStructure);+ i# {% O1 Z0 _* T0 b1 M$ \5 [; c: V

  72. ( ]. l5 s# d/ A0 A% }! c# Y" V/ M" ?  H
  73.     3 o( A8 H# v3 B# q

  74. . X0 D6 G* h  B7 H/ u
  75.         I2C_X0_LOW();        6 F) S" W8 W/ S& r. ?3 F9 h
  76. . z/ i& t( w& |# R3 K
  77.         I2C_X1_LOW();# ], y& x; k2 F9 w+ ~1 ]1 l; {7 z! _

  78. 8 N! H- _. ]' s' r  ^+ h
  79.     I2C_X2_LOW();        
    7 m3 a9 H4 |5 H7 }. ?( W9 V$ ~8 |

  80. ' P, c9 k3 c9 |, b9 [/ i8 T% d
  81.         I2C_X3_LOW();
    ' b( l$ Z% Z4 I+ u; P

  82. 3 _$ M$ q8 U- |$ P- k0 K
  83.         delay_ms(20);4 O/ c- H+ Z- i
  84. # q$ W7 P3 y9 V
  85. }
复制代码
0 W8 ~( {& l# w: n

; X7 f8 [% |& C! h1 f

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

  1. 3 `7 M. |/ |% u4 Z$ E
  2. {4 a. T5 k" R6 ]8 s" B3 A5 G
  3. 9 o7 w# [* z5 L) Y& x2 e
  4.         
    ! j6 t3 [6 A, ~5 C" q* U

  5. 3 y+ q5 q2 u1 S$ F5 S2 N0 Z0 K' X
  6.     VL53L0X_Error Status = VL53L0X_ERROR_NONE;   //初始值赋值为0  ]( l( Q4 `$ `
  7. & j5 x, f4 H% z: B, }+ d! k

  8. 6 {' X0 E0 @4 c) R- p7 {
  9. 2 G) P* v& r* i0 H( W+ @) u. l
  10.          //初始化一定按照这个顺序执行,否则不成功6 F  _* B+ a! h6 Q) f

  11. & `. c+ S. E& s7 j9 A) N
  12.          VL53L0X_i2c_init();
    7 J4 L( |. x3 u6 C/ \5 R/ D

  13. + [* t) r8 W: |9 ~" O" w3 I# ^
  14.      vl53l0x_initX(&vl53l0x_dev0,0);
    ; M  d. \! ]  n4 T9 F. S
  15. 6 b: S* @7 g4 K  q& [% q* c/ b/ f
  16.          vl53l0x_initX(&vl53l0x_dev1,1);
    & w& {: ]- S8 G- ~/ u( ?

  17. 3 ~% y( w( }9 t8 t
  18.          vl53l0x_initX(&vl53l0x_dev2,2);, q. S, d$ o: X7 F5 R& B
  19. ; [% R2 @# b7 |9 z$ X
  20.          vl53l0x_initX(&vl53l0x_dev3,3);* M1 q# h& M/ E
  21. ( D* \7 Q  I* M# O
  22.            ' Y$ U! [  E- h8 I
  23. , G0 V" D; K! l8 U! n8 m$ R+ C) L. i
  24.     return Status;           //返回0
    : }4 q3 {! Z" O/ S; }) |* _3 v
  25. 8 o" ?+ H) J& D/ ~, e
  26. }
复制代码

. 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

  1. VL53L0X_Error vl53l0x_start_single_test(VL53L0X_Dev_t *pdev, \
    3 o$ o7 `' q* w; I7 }4 s" f/ N
  2. ' {, U7 A6 n* y$ B- K  b
  3.                             VL53L0X_RangingMeasurementData_t *pdata)6 |4 Z+ B- e$ L# r

  4. 6 z- D3 ~5 P; w! X
  5. {
    4 C* }1 z& \7 W8 y: a1 e
  6. * _6 n+ c8 v' P. W. t* E2 b
  7.         int i=0,j=0,sum=0;9 M$ L8 R  F. @0 f4 E, ]. C
  8. - P# _" q( H' y5 P# ]
  9.     VL53L0X_Error status = VL53L0X_ERROR_NONE;
    4 m& B" }* t5 q- }. {

  10. / n+ p( L4 T4 z  i/ f7 V/ c6 D1 m
  11.     $ S0 w) T# z4 S1 M1 O

  12. ' I- e' P! q% m- [
  13.     if(vl53l0x_status != VL53L0X_ERROR_NONE)8 d5 I- N. a0 S% f" @& s; a; L

  14. ) n/ d2 Y$ x8 _! B; b' k
  15.         return vl53l0x_status;
    8 V# y. j& D* K! o8 G" m) _
  16. 4 B) s' |) V" C7 R
  17. $ e4 h# D3 F) ]' s0 Q/ ~, O/ F

  18. & [1 Z( x/ O  ]% O' h
  19.     status = VL53L0X_PerformSingleRangingMeasurement(pdev, pdata);   执行单次测距并获取测距测量数据& C  m2 ^( j: u, X4 Y" Z, w

  20. ) J5 s5 p! C# j- ^& M
  21.     if(status != VL53L0X_ERROR_NONE){
    : E+ f! K+ ~4 d: X/ l
  22. 2 D, a& a! M( Z2 X0 x& m
  23.         printf("error:Call of VL53L0X_PerformSingleRangingMeasurement\n");5 N: n  I% J5 S% Q, W& h+ o$ P
  24. 4 \6 c2 j! _' q- T$ L5 R& ^
  25.         return status;: w- J4 z* [- l2 s; A3 _2 b/ L% m

  26. - Q$ }; a' U: n; D( \
  27.     }
    ; {$ C# f6 e( F5 w: W5 S/ ~# A
  28. * m2 r0 Y% |% R. E3 ^
  29. . `, M% @; L1 \. u; Y
  30. ! v# h& a: V# h$ ?! q8 a" T4 t- }$ k
  31.                 for(i=0;i<5;i++)1 N' A/ ]+ P$ ^6 L; P

  32. ( f  M0 _' E- E& r, @
  33.                         sum+=pdata->RangeMilliMeter;
    % W9 T- w; R4 p5 T- N2 Y! p/ [

  34. 9 W1 C" m1 y4 m  W" L  @
  35.                 pdata->RangeMilliMeter=sum/5;
    , J- _; z( l5 K# N
  36. 9 E6 l: J# t+ Z1 B
  37.         printf("%d\r\n",pdata->RangeMilliMeter);
    # K) j0 O1 k& M( [+ f( P4 m" B

  38. & A* _% T/ S. N9 ]: a
  39.     return status;: \' ~4 ^0 `, R% N7 L( k3 M, E0 A

  40. 1 ~- {5 ^! Q% l) z5 {, i
  41. }
复制代码

' 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& ?
收藏 评论0 发布时间:2022-12-10 23:00

举报

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