本文记录了我使用STM32F103结合VL53L0测距模块的一个学习过程。
( Z% l3 D. C) R! q8 X5 CVL53L0是由ST公司最新推出的一款飞行时间测距+手势检测的微型模块,它应用非常广泛包括:激光测距、避障检测、一维手势识别等;接下来我们重点介绍它的激光测距功能。' E6 `' K7 J' r
" j5 M/ N! p3 c
一、模块的硬件连接+ x0 U- _* q, I
$ O" P# @' r5 P2 h
6 Z- S: [# p5 D8 c
7 u" L. T/ P" q5 X" _7 v9 n. {% l: q* X/ M$ k, w& @, o
上图便是我所使用的测距模块GYVL53L0XV2,它预留了六个接口:
5 p8 O5 X. ?2 h* X1、VIN:供电电压,可在3V~5V范围内进行供电,但如果自己进行电路搭建的话,则需要一个线性稳压电路,将输入电压稳定在2.8V进行芯片供电和芯片I/O端口的上拉,这个可以自己看它的数据手册;
2 |1 v: M! i+ S! P& G2、GND:参考地;: r9 V; N+ N: j1 Q# C' t4 Z
3、SCL:I2C通信的时钟线;3 y: H) L$ K2 e! G: @( _! s
4、SDA:I2C通信的数据线;
9 L& ]8 b/ s9 z( f l5、XSHUT:芯片的使能管脚,电平1代表有效,电平0代表无效;0 K/ Q8 R m9 M9 K. ~
6、GPIO1:芯片的中断管脚。
5 B9 K( o0 C& E: H/ A3 F& O9 c4 s- M8 t" N2 A* H- j
本文与STM32F103的连线如下:
/ j& R; j" y# ?# s. i+ ?VIN--------------->3.3V
5 q2 o; w+ P- R8 K) pGND------------->GND; m' D0 M" ?6 j/ W
SCL-------------->PB6% O6 J! d' e) c. }- R
SDA-------------->PB7+ w9 }+ ~& I a2 ?4 m# a
- b8 ^& j5 w j# ]其中XSHUT与GPIO1没有连接,由电路可知,未连接时它们均上拉为高电平,XSHUT一直为高则代表芯片始终有效工作,如果有需要也可以进行连接,用单片机控制。在这里我没有使用到,因此直接不连接就行。" _2 e8 P8 N# @, t: W
$ [% D2 C9 }1 ]' m4 |% O( H+ v- E, W* Q$ h! {
二、程序代码
' H9 ?- H' z+ M; T# S- #ifndef _VL53L0_H+ t6 Y0 f3 k& W1 u( K# @1 w
- #define _VL53L0_H
( J5 i2 l. L5 G3 J, @" ^& z+ f
2 d+ a1 n. B- Q/ t( Q- #define VL53L0X_REG_IDENTIFICATION_MODEL_ID 0xc0
, N* B- t& F$ ]7 j8 J+ Q - #define VL53L0X_REG_IDENTIFICATION_REVISION_ID 0xc2% B4 |7 O7 D8 t- A+ E5 |# U
- #define VL53L0X_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD 0x50! q0 m7 x7 {; Y ^: A
- #define VL53L0X_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD 0x70
! [0 _6 B }% e - #define VL53L0X_REG_SYSRANGE_START 0x00. g( C# A: F+ ]+ W: p. x
- #define VL53L0X_REG_RESULT_INTERRUPT_STATUS 0x139 \* x J3 V4 \
- #define VL53L0X_REG_RESULT_RANGE_STATUS 0x147 E( O& `' M" M
- #define VL53L0X_Add 0x29
9 }4 J* }3 g+ [, \$ { - #include "stm32f10x.h"
1 D* K; l0 `: ]; r# { - #include "bsp_usart1.h"% T- U* C3 M3 x! g, M
- #include "bsp_i2c_gpio.h"
2 u2 J$ c& |& E) `0 e5 X2 [ - 0 x7 d; ], T5 m- ]2 `$ }3 l
- u8 VL53L0X_Write_Len(u8 addr,u8 reg,u8 len,u8 *buf);- ~4 B1 V# A- ~3 g F. L. {( v
- u8 VL53L0X_Read_Len(u8 addr,u8 reg,u8 len,u8 *buf);8 a, ?# O" P" L6 a/ B
- u8 VL53L0X_Write_Byte(u8 reg,u8 data);. d; k) f& Z s" u
- u8 VL53L0X_Read_Byte(u8 reg);9 |; C# }& z3 c
- uint16_t bswap(u8 b[]);
* ? `1 |0 L2 }1 L( }' l - uint16_t VL53L0X_decode_vcsel_period(short vcsel_period_reg); 9 }3 a, W9 |$ V$ K
- uint16_t makeuint16(int lsb, int msb);
; ?" f! O) m% i. a, d' |6 L
, q A8 b! @8 g- #endif7 H0 _8 U* E% M2 w3 h+ ?6 O$ K
- + F! j2 e! S7 z" q
- #include "VL53L0.h"
& i) @( d1 I1 u7 @, U' ~$ @! ?+ m J - uint16_t bswap(u8 b[])
* f0 Z% f1 N4 B+ B9 D - {8 Q3 b P/ ^8 e: C4 h# m. E2 G9 A
- uint16_t val = ((b[0]<< 8) & b[1]);
0 @5 Q- Q3 y3 h9 B+ H0 N( g - return val;
$ q# C9 }) I. h% w+ A - }
9 N8 a1 M* A$ T+ G - 1 @1 h& }! h( p4 D% {- r- u& q
- uint16_t VL53L0X_decode_vcsel_period(short vcsel_period_reg)8 T( Z1 v5 S6 t; Z: Z+ s/ j" N4 _# Y+ t
- {
) u, A6 S( L7 S0 h* J" h - uint16_t vcsel_period_pclks = (vcsel_period_reg + 1) <<1;& r: A) ^9 V+ ~, |4 q
- return vcsel_period_pclks;
+ |) ]1 l% S4 I: w& b% ^ - } H9 }( P9 ?8 p1 Y& H( b5 ^1 ~
- , D5 R0 n9 l1 d4 E2 r# b* e" d
- uint16_t makeuint16(int lsb, int msb)- ^$ v& Y8 K4 j0 k( C$ g/ h g0 u
- {
' c, h) c( L4 d3 ] - return ((msb & 0xFF) << 8) | (lsb & 0xFF);3 b q, A! O+ d
- }* G/ f$ _) _* N' }9 _3 R2 F
& p8 q& V8 M; \) p: B2 n- u8 VL53L0X_Write_Len(u8 addr,u8 reg,u8 len,u8 *buf)+ E" s) ~5 u" S; \0 V
- {
' @ {* ~. H3 s% ?7 A% ` - u8 i; 9 g: m& T5 I. v) Z
- i2c_Start(); " ~ H% ?4 O6 N+ q8 T
- i2c_SendByte((addr<<1)|0);
" j) M* K4 m( R# P( V - if(i2c_WaitAck())
) T* @0 A" c/ b5 d, Z - {' u. S# @% {" A0 @ }
- i2c_Stop();
7 ?# [0 T7 ^& e+ f- Z( M4 P - return 1; ( q2 v5 H0 ~: s4 v
- }
1 X3 C0 _, @% E, i - i2c_SendByte(reg);' r: E& B0 K1 h; x- n* U
- i2c_WaitAck();
/ F2 l, p1 q% h% Q% R: |) m - for(i=0;i<len;i++)
5 t2 F6 |/ t# p - {3 J5 l6 G: z' \6 D
- i2c_SendByte(buf[i]);
' ]- ~$ z x- I - if(i2c_WaitAck()) 8 L$ x7 F6 d# a5 J& h: N
- {/ d# }5 M& [7 ~- \
- i2c_Stop();
& h( A+ z- `5 a6 {( ` - return 1; ! T0 T. s8 X8 U+ ^8 U, T
- } - t; [! b8 ^. f3 a9 }0 H! _+ o( ?
- }
2 ?( V* I- R+ @0 O - i2c_Stop();
, w. P/ p; n+ R$ \- } - return 0;
- _7 W' T3 t5 c" T+ u+ M - } ! t4 T& s0 c2 @- @- S
9 `; ]: n9 _7 L# G- u8 VL53L0X_Read_Len(u8 addr,u8 reg,u8 len,u8 *buf)! I+ G s5 U* k+ V
- { - s; B1 x9 Z# ]3 a. Q, `
- i2c_Start();
( J# e6 c+ |8 ^ [. D9 ^/ }4 e. P5 } - i2c_SendByte((addr<<1)|0);; [- P5 ]" B2 T$ r1 \# K
- if(i2c_WaitAck()) : {" T) ^" A4 O" d' V* ~& K2 j
- i2c_Stop();
4 c& I$ k& E N8 d3 S9 @8 ~ - return 1; 0 z! q: A* q# T, b
- }$ \3 X4 m2 K0 }& A2 c. t1 e0 ~. x
- i2c_SendByte(reg);
! ~% k+ p% j* r/ R& n1 O - i2c_WaitAck(); ; n1 U* ^; `4 X' I8 q7 \" I
- i2c_Start();+ Y1 E) z' K) h4 v* |+ u6 _" W
- i2c_SendByte((addr<<1)|1); # D8 D9 z% p1 _! w
- i2c_WaitAck(); ( U- I$ n' }3 @4 u* l7 I; a# j
-
! ?0 {7 g/ U# @ - while(len)* T3 y5 W" v3 p3 \1 V$ A$ R( F. q
- {7 N3 S9 l! Y0 X3 k) Q
- if(len==1)
- ?% L$ A2 R2 j - {
# i9 D! \, P+ }3 j& R+ c& m - *buf=i2c_ReadByte();
9 L( G- S% y6 n0 o; m$ b: [. t% U - i2c_NAck();
- ^0 t9 m; p% Q m9 z& l8 H8 V8 K - }
3 l7 d D8 r" E+ N* n- ~ - else 4 N" `, |! f' c( z# T6 K! `
- {1 w( ?$ q: L1 D1 d# a
- *buf=i2c_ReadByte(); 8 _& |/ y, l& v2 `, d5 s! T- j
- i2c_Ack();/ v6 c+ W- Z$ d* W4 T
- }
$ y2 k. w, k B# T) w" r - len--;# X4 y0 Z; k* S8 Y) D( h- i$ d2 ?
- buf++; * d. P4 n4 e3 [' M8 W3 H
- }
& S) [( J6 ^ b9 x- I/ _9 n - i2c_Stop();8 H8 K# f7 s1 N1 K1 ^& r
- return 0; 9 G8 y I, \6 x- ]+ _
- }
' v/ M% c; h6 S - 3 ?9 g! j, c" Y
- //IIC写一个字节
) N' \; S% {; b. A- H - //reg:寄存器地址7 H9 O6 o% V* M5 {% @
- //data:数据
6 H# a6 U2 P! f) Z4 S8 S6 R - //·返回值:0,代表正常
8 R& |9 L! l+ T- r! ~8 j - // 其他,错误代码
# |, w" G" z* x- y - u8 VL53L0X_Write_Byte(u8 reg,u8 data) 7 K9 }9 {3 s, ^1 U
- {
% l |' g8 ^( R/ n. w8 m% t1 { - i2c_Start(); & g' @+ Q2 l6 L$ F4 Z, T
- i2c_SendByte((VL53L0X_Add<<1)|0);//发送器件地址+写命令
4 u5 ^( n% x2 X! a - if(i2c_WaitAck()) //等待应答
* g* f- q5 o# H0 p+ `0 \ - {
+ Y* X4 E7 W( o4 {5 ]) j - i2c_Stop(); & f6 W3 t" I- S% z
- return 1;
( _ y H- ^" _8 @4 t! `- A - }5 ~# t/ ^: j/ I3 o
- i2c_SendByte(reg); //写寄存器地址
1 X" U2 f! }' z - i2c_WaitAck(); //等待应答0 k e& L6 ~4 A, ~* L, p' ^# @( b
- i2c_SendByte(data);//发送数据7 V& H" L" P7 c, s3 E, N- x
- if(i2c_WaitAck()) //等待应答
c& N7 @! Z ^0 g, f$ j) ~3 S - {2 l" B, o+ B" B( g& s' n
- i2c_Stop(); * U% z3 Z! f8 m, ~
- return 1;
R1 e' I2 ~+ S& m0 K - } 8 {) u3 n2 ]. r& M+ m
- i2c_Stop();
' _5 a# P3 U: j9 u% m q" e) w; Q - return 0;8 W% F4 I/ N/ l
- }
" a, l. S6 u# A - //IIC读一个字节* v1 x$ w0 \+ N
- //reg:寄存器地址
$ F8 A6 K# p2 |# a) b - //返回值:读到的数据
$ x% Y) g j; S: N F - u8 VL53L0X_Read_Byte(u8 reg)
" J4 @( x1 |9 ]1 C - {
# g/ Y1 o) k4 c& V' [! K - u8 res;
3 l7 y; g1 t& K$ v - i2c_Start(); ) _$ R% ]" ?% n$ U" o( q! B. M
- i2c_SendByte(0x52);//发送器件地址+写命令
' E) `9 W& X4 s. O9 b( v3 J$ z9 n% Y - i2c_WaitAck(); //等待应答
6 J9 O; O) W: `8 B3 m - i2c_SendByte(reg); //写寄存器地址' l9 b a5 \- n& O$ ?3 @6 b
- i2c_WaitAck(); //等待应答8 [* O4 [% W- a& i$ u- G' n. y0 R
- i2c_Start();* b1 O5 y) v3 E8 g. s' `) E
- i2c_SendByte(0x53 );//发送器件地址+读命令
3 ^- D/ \4 y4 C9 R6 L7 @ - i2c_WaitAck();" E( B0 d$ A& k' i4 g! u
- i2c_SendByte(reg); //写寄存器地址
1 K+ L8 K1 f4 Y+ Z2 r* P - res=i2c_ReadByte(); //读取数据,发送nACK
( l" C! j1 \6 H( s/ g3 q - i2c_Stop(); //产生一个停止条件
& C) l% l x! q# K ]" } - return res; ! A% R5 V' g/ x8 b$ P$ D: C
- }8 }8 L- e* k2 J6 ^
- + f8 V$ _8 S$ e/ B- p* d
- main.c:
7 ]+ T& E$ u/ J) _5 k - #include "stm32f10x.h"* `# g% k; G+ i! |5 [( u: W) h
- #include "bsp_usart1.h"
3 Y+ c+ w$ a8 m C1 l - #include "bsp_i2c_gpio.h"
: k* B( p, K0 r( k# Q) ^. Q/ \' J - #include "VL53L0.h"* d5 R7 s t& M1 P6 a+ k1 n% |
- n5 N( x$ Z) v$ r$ d& J6 W
- uint8_t Rxflag=0;
! M8 H6 \: i# `. b4 g2 ^0 U" C - uint8_t ucTemp;" X" E+ y5 h+ f# g% z
! ~2 j$ R4 F5 s- ~- int main(void)+ P( H% I# \7 h
- { / u/ @5 f# P$ w' r' L3 G, Q
- ! P5 y! T* X7 Z, \8 J6 a: y
- u8 val = 0;
K" Y- w2 D8 Q - u8 gbuf[16];
9 @- t0 w2 {2 I) Z% P - u8 DeviceRangeStatusInternal;
( A% X+ m$ r% h- c/ C' t; l D - u8 tp=0;
! i+ O1 v- c4 u( j) l8 E( \6 s -
) ?7 G. w7 X8 t( @+ S - uint32_t cnt = 0;) _7 M+ n; R" M% l* I, u6 V. e
- uint16_t count[3];
! B. D, c( A! z - $ Z8 J0 O# C7 E+ i
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
3 D. {. z7 k9 E" s+ f$ W - USARTx_Config();
1 n( S7 {" R e. K/ I* d {1 q - NVIC_Configuration();( H5 e" o- N+ d3 m
- InitSysTick();
& d8 l1 y. w* n* L% j - bsp_InitI2C();/ s$ b! X5 G3 ^. T
- while(1)
7 l5 M% D2 k* K7 R- U* n - {9 [ |1 t0 l( L0 H
-
- P! `: R) k/ |) ~ - VL53L0X_Write_Byte(VL53L0X_REG_SYSRANGE_START, 0x01);1 W) d4 v/ Z u ?
-
+ H8 {- O7 |0 j/ l k) l# `# G - while(cnt < 100). I8 o/ r) o" Q; D" t2 A
- {/ B6 Y' }8 K4 e
- delay_ms(10);
* X! p+ w# S8 W1 T- e - val = VL53L0X_Read_Byte(VL53L0X_REG_RESULT_RANGE_STATUS);0 O; L5 r8 b; F, [ `3 \
- if( val & 0x01) break;) S8 X# V+ L- j6 |
- cnt++;
& p, ?% U9 h- @9 R$ j - }8 G' @7 S) ~" m; F* u$ R8 X
C" J/ l! B# j4 d$ P0 f; O, `. q2 B- if( val & 0x01)6 C0 X% B: h/ A, d* G- o" w C
- printf("\r\n readey \r\n");; A- }/ @: P! }4 k9 U; ~3 ?) ^6 n
- else1 T/ Z6 w% w$ G3 p
- printf("\r\n not readey \r\n");. t# o: S* O. B- s" c: C
- VL53L0X_Read_Len(VL53L0X_Add, 0x14 , 12, gbuf);/ H' p( U" K4 ]+ i" n0 k: g0 s" s6 c+ [
-
7 e. H$ c6 N8 B L - count[0] = makeuint16(gbuf[7], gbuf[6]);
+ t+ j6 c/ J) N1 ^' s8 l - count[1] = makeuint16(gbuf[9], gbuf[8]);
) r' H; D- \7 N) t' V# q3 N; s2 J8 c - count[2] = makeuint16(gbuf[11], gbuf[10]);
& t! ?# h8 Q" A8 K1 m4 O2 D o) ^ - DeviceRangeStatusInternal = ((gbuf[0] & 0x78) >> 3);
* V5 E! s6 w% ]* ~
) p' Q/ R, B: n' q' t- printf("\r\n ambient count = %4d signal count = %4d distance = %4d status = %d ",count[0],count[1],count[2],DeviceRangeStatusInternal);
0 L9 M: n& ]( _% ]5 t - # M0 |0 ?" v, }% u6 |. |+ ]
- delay_ms(1000);
8 _2 Q2 M0 p7 F" t' v$ q -
! I0 ~5 F8 i3 n1 K& d - ! a8 E ^! V3 D+ `: S
- }4 S7 C I/ s+ p0 ?* ? ^3 q% Q0 W: C
- }7 }% i# u$ p7 U* ~0 G- h8 u
- 1 P# V: e$ r9 f( w: C5 @
复制代码 6 w/ C1 \! |9 L! Y7 \5 m/ a: F
————————————————
) B1 K$ x5 Z3 A+ g; e4 o2 o7 {( Y) X版权声明:TangPeng_HanMO
6 L/ d/ h) U: _9 o$ q* r. k6 J5 ~- Y6 R- `, D: G2 Z
6 K4 B$ T2 N3 g3 l |