前言7 D9 D2 e. W6 W* K) a" ?: a
我在上一篇文章中驱动了HC-SR501红外人体传感模块,但在测试过程中发现,这个模块的热释电探头过于灵敏了,甚至有的时候往上哈气,会因为检测到类似于人体的温度而误判为感应到人体,所以为了减少误判概率,我打算再添加一个测距模块,在红外感应到人体时,再次判断人体与传感器的距离,在满足预设的距离范围时,才确定有人体接近,进行后续操作。+ z6 w8 `. v7 N0 x C
一、模块简介+ w' z3 E$ k- H# d/ x
HC-SR501红外人体感应模块资料介绍:7 E9 Q* s/ R; F0 u3 Z; K- i: P
探究人体红外传感器HC-SR5013 Z* ?% a% w- y' V
9 s' c1 `- N. Z, D
HC-SR04超声波测距模块资料介绍:
. k' [ P+ o; T. F! O: V9 l
2 ^# v3 t' M: q( @# ~
* O! Z/ e1 L& {% O- H
. a. y0 Y4 p3 @$ a" ~! @
8 u+ d( ~/ Q- O! Q* L/ X( c
1 C( c7 i. b! T, H% T工作原理:4 S. X3 l& s/ |; r! j) c3 o
3 ]6 Q4 a& q+ I/ Y
( A+ _5 r9 j7 E9 @9 Z6 V: r: R6 R+ M, l) ?' H4 q0 n4 q
8 w' U* h" d) x3 b6 f4 }3 {3 h" F6 A: V, L
简而言之: u. {+ c" h% ]
给Trig一个10μS以上的高电平,模块开始工作,模块内自动发送八个40khz方波,并自主检测是否有电波返回。此时需要检测Echo处的电平,当为高电平的时候记一个时间;当Echo出为低电平的时候再记一个时间,这两个时间的差就是高电平持续的时间,最后用测距公式进行计算。
, x% B. E1 f1 r0 T( O, ^$ q
: k( r/ a( w# }5 o7 U二、配置CubeMX
0 y6 P8 M0 M4 Y1 t- i2 x1、新建工程;0 ?, C/ m- s4 P+ t! s, X; V
2、配置时钟源,在RCC里面的HSE配置的是晶振时钟;. Y. P5 K6 Z" Q5 O- L. a
3、配置程序烧录引脚SYS为SWD模式;
5 B. P9 n; P3 G1 Z q: d4、配置GPIO输出口,配置一个LED灯(我的板子是PC13),起到检测到人体时的指示作用;9 n0 m! w# q `: m5 _* m; r
5、配置GPIO输入口,用来读取HC-SR501模块的输出电平,我选的是PA1口;
, H# R H6 v4 r$ f8 D6、配置GPIO输入口,用来检测HC-SR04超声波测距模块的回响信号输出,我选择PB5口,命名为HC_SR04_Echo_Pin;
0 }5 a( Y# q/ L4 e( S: C2 S* M7、配置GPIO输出口,用来触发HC-SR04超声波测距模块,我选择PB4口,命名为HC_SR04_Trig_Pin;
* j; X- t% |! t: T- r8、使能定时器,用来实现微秒延时,和测量HC-SR04模块高电平时间,我选择TIM2,并使能TIM2中断;# J* g- S1 b8 j
+ F/ ^5 K. K/ p* q0 z, r8 J0 w5 M
0 g+ W j1 s7 `: v/ i! ?& a
; }) ^" \2 ]+ STIM2挂载在APB1,时钟来源频率为36MHz,故取预分频系数PSC=36-1,计数周期Counter设为60000-1。即此时定时器频率为36M/36=1MHz,每60ms进一次中断,60000μs对应实际测距范围大概为10m,远远超过我的需求。
1 T0 J% ~2 ~6 M" R% R$ ~0 G' K0 E1 e& M6 q" u# M6 P
! l/ ~( ?1 i) J7 L7 @2 J0 T" w4 ], E, ]' j; G, ~6 `% w
+ M" J, @6 P; I
7 q) Z5 U/ s; q* _9、配置串口收发引脚;
1 X ]$ C' M; f7 K* n; A+ j3 v10、配置时钟树,我还是开到最高的72MHz;8 w7 q' k _% z6 g
11、进行项目设置,最后生成代码,CubeMX部分就大功告成了- \2 q; I' t; \% k" B
7 O- L- `6 L: [1 ]) J: E+ P0 |
( a. Y. g3 R; v9 z8 Z
8 j& p% R. w9 d
三、硬件连线部分
: ~4 V% ] w( h* e5 U! A$ BCH340 ↔ STM32F103C8T6最小系统板:1 U, N- E* @7 _: G+ ]0 q
TX ↔ RX0 M( {0 m: ^: m' X5 h/ n4 z
RX ↔ TX
6 L9 S/ f, x, o$ Z' s+ b3 [* O" N$ L. |. D: B4 E" [
DAP-LINK ↔ STM32F103C8T6最小系统板, ]+ P* V; }) e6 o' ]! M3 p- M/ r
3.3V ↔ VCC' L, S2 _8 J8 a A+ w; v6 F
GND ↔ GND6 ?/ p% s8 k9 {/ ^
SWIO ↔ SWIO* j7 c$ E5 A8 b! @6 [ T2 J2 y7 U
SWCLK ↔ SWCLK0 F1 d3 ~3 S2 W
' l. @+ _; E4 A7 H7 A4 ?$ wHC-SR501模块 ↔ STM32F103C8T6最小系统板' r: n+ f" W) C/ \
OUT ↔ PA1
. j. v7 K8 |9 o, C! ~ GND ↔ GND3 I. z0 n1 O- j
& p) Y) h% f& v: c
HC-SR501模块 ↔ DAP-LINK (这里注意模块供电范围为4.5V-20V,用3.3V无法驱动): O& u( r. Y9 ]/ L$ Z( j
VCC ↔ 5V; m! g6 L2 c( J& E! K. L
: G4 q% z' P. r; p1 ~HC-SR04模块 ↔ CH340
1 e/ f( ^% J* c& V" }1 A: \4 e6 \ VCC ↔ 5V
2 a6 \( N# b; l/ S: F' u! b8 r5 P
HC-SR04模块 ↔ STM32F103C8T6最小系统板
J! Y/ O0 A$ ]1 U Trig ↔ PB4
0 Z& f9 b6 v3 a Echo ↔ PB5# m8 |: k1 f9 j: a) e7 _
GND ↔ GND
0 h; K' p) U; i0 e# t* |9 H! z# i2 f9 E& P
四、逻辑代码部分
$ J ?4 ^/ X9 Q% T5 `代码框架是基于上一篇HC-SR501红外人体感应模块修改而成的,想要完整代码的话可以和上篇文章一起看。
. q* ^+ w# a9 E& o8 o$ }( f
6 D, b; l$ t" H8 iHC_SR04.c2 m0 j+ t; L' i! p1 R
- #include "main.h" u' M8 D% _% @+ M! o+ W
- #include "HC_SR04.h"
8 u2 ]; M! @, s- t4 T% v. O3 c - #include "stm32f1xx_hal.h"( D/ O. c& p" A. b$ l
- #include "stm32f1xx_it.h"
' _4 r+ W ?# k9 B. K6 ` ~ - 1 D* h# l A& y9 H9 U; m3 X+ v
- static float distance_result;
8 o/ F4 [/ a/ B9 [& P7 h8 k - /*) C- x. G6 ~$ H Q
- ********************************************************** a7 C: m' |1 ~3 P |
- 函数原型:void Delay_us(uint16_t time)
4 E$ U! i; W& `/ p) z& U - 函数输入:无符号整形9 D2 W: M" b$ J: ^5 w( w5 ~- v5 F! |
- 函数输出:无
# d1 t; b6 p- n2 S2 u" h* K - 函数功能:利用定时器实现微秒级延时
( z: U4 C9 d# K1 ?3 [ - *********************************************************
+ V. Q# D% ?0 W( @/ E2 i; U - */
0 W) A# k$ g8 N$ { - void Delay_us(uint16_t time)+ h* r/ V3 E' C; n" z
- {8 }2 n2 F8 n1 c, T: Y, D
- uint16_t a1=TIM2->CNT;
. Z4 T# J) K& G: C+ A5 m( r - while(TIM2->CNT-a1<time);0 r3 x" [4 n: y# S
- }& ?3 ?+ Z5 l4 K' j9 a) C$ n3 f
- /*
8 |* V$ y z% q* k+ x - *********************************************************3 C. W s1 ~" s9 `! F0 e. G, t
- 函数原型:void HC_SR04_startrange(void)2 C4 [4 z- ]% l/ P( v0 b
- 函数输入:无
1 X# ^% }6 P& D9 s - 函数输出:无1 z; r, C% T( K* i0 L
- 函数功能:从trig引脚生成一个不小于10us的高电平触发测距,触发后模块自动产生8个40kHz方波,自动检测是否有信号返回
- Y* o$ R) C1 X, J* c! t7 c! N' ? - *********************************************************
) T0 f2 U: X# v4 ?! b1 r# Q - */
8 D9 O: [ l9 X$ u" K3 Q+ s - void HC_SR04_startrange(void)) ^1 {- c% B2 I6 ^) |
- {
% t6 w5 H7 ^- i& ~) ^% A, b - HAL_GPIO_WritePin(HC_SR04_Trig_GPIO_Port,HC_SR04_Trig_Pin,GPIO_PIN_SET);
6 s! V& Q$ M! q - //HAL_Delay(5);4 m+ h' Z) }: i- x$ F# q
- Delay_us(10);: X2 s0 e/ v- W* E( c
- HAL_GPIO_WritePin(HC_SR04_Trig_GPIO_Port,HC_SR04_Trig_Pin,GPIO_PIN_RESET);
, N+ ^; U3 D$ e! b -
: u+ B: C9 I4 C7 d - }1 W! a$ z2 Z5 p0 r# ^8 u
- /*3 N) L) E1 }6 M1 p1 x7 o7 }) t
- *********************************************************, J( x2 W1 o4 T' T
- 函数原型:uint16_t HC_SR04_gettime(void)" K: {+ {, T! e- U ~
- 函数输入:无2 ] |! a4 b+ b, i# X
- 函数输出:无符号整型
1 b+ W5 l3 X" D( \% ?# l9 ^ - 函数功能:通过定时器获取当前时间
1 w: \' Q. D; G1 Q% U# P3 Q( Z$ H; f - *********************************************************# ?; W1 b) G' v, f8 _% G: j/ `, E
- */+ r* s- a( G0 \$ i1 Q. v, p
- uint16_t HC_SR04_gettime(void)( r0 B* q+ l4 M7 p2 r2 t. v0 x2 r
- {
7 Y4 o$ j- p% e8 H3 w! `0 s7 v - uint32_t a;/ G1 i1 ]( Z# i5 K) T5 l
- a=TIM2->CNT;
3 {8 J5 z8 A' t+ @: G/ J. @ - return a;
( C4 s' z( e+ |4 I - }1 Q! Z9 Y, c; L8 D
- /*) M8 H& H8 Q7 ?, v/ Q* e
- *********************************************************
2 A9 X V# |# t - 函数原型:float HC_SR04_getdistance(void)
: Z$ }# ]2 E+ k - 函数输入:无, _! u' d/ z3 j, t( Z' d" m9 a: c
- 函数输出:浮点型
2 s/ f+ Z: i' i9 i - 函数功能:获取与目标之间的距离1 l0 k, K9 C5 h4 J$ {7 U- t
- *********************************************************. K- q; w! p( g
- */
# h+ S; `: y% C0 @9 f - float HC_SR04_getdistance(void)+ \& J& y, a. U/ k$ O6 T
- { 6 b9 O; q& T1 l
- uint16_t time_node1;& N- V: ^/ F. Z$ n" M
- uint16_t time_node2;; b/ `1 v" c/ `1 _ |# Z, J
- uint16_t measure;+ q/ e6 S- Q$ @, v$ h8 I6 A: r
- + G1 l H. _: s& Q: }
- HC_SR04_startrange();7 w* n/ g5 O4 w1 ~; c; {, W1 v
- ~8 [/ r7 a6 D# n
- TIM2->CNT = 0;
6 F) n" T9 E3 f# i8 J - 3 z& i/ d' S& h* ], A
- //有信号返回则通过IO口Echo输出高电平,高电平持续时间即为超声波从发射到返回的时间,测试距离=( 高电平时间*声速(340m/s) )/ 2
5 W/ f) g' t( A9 _, R! c1 k8 |* V - while(HAL_GPIO_ReadPin(HC_SR04_Echo_GPIO_Port,HC_SR04_Echo_Pin)==RESET);
I( V Q2 ]6 E) W - time_node1=HC_SR04_gettime();& i% E) a0 e/ A; r% p
- 9 y1 v7 t, w: H( K8 c
- while(HAL_GPIO_ReadPin(HC_SR04_Echo_GPIO_Port,HC_SR04_Echo_Pin)==SET);# d1 b# a3 n9 ^9 u. I7 _$ o
- time_node2=HC_SR04_gettime();
5 R7 e: T) m+ A - 9 }) @5 M8 z+ N% s
- measure=time_node2-time_node1;
/ X6 n8 w) }- N/ b1 V -
; @8 R7 N3 S* e7 Y, \ - distance_result = measure * 17.0/1000;//距离=计数差值(us) / 1000000 * 340(m/s) * 100 / 2 = measure * 17/1000
2 ?1 E, [' I% J& c9 G* x
6 c: N& g; L |9 C. K3 W: ^/ G- return distance_result;
6 Z' Q4 \4 Z I" b% G2 r& @0 w - }
复制代码 + K" y0 e/ B/ w/ C
HC_SR04.h
4 _; \! C. k1 Y1 r# D- #ifndef _HC_SR04_H_
% T' S( F# Y( v5 c& I$ C" ~% u - #define _HC_SR04_H_$ z! y3 ?# ?2 n& ?- N
- void Delay_us(uint16_t time); K* ?0 }# E+ D
- void HC_SR04_startrange(void);
& x3 g2 u* ]; ~ S - float HC_SR04_getdistance(void);0 N# U) e8 O3 G
- uint16_t HC_SR04_gettime(void);
& K* r; `( S& t- }9 a j/ c - #endif
复制代码
( K& m: f; b+ T! T" ~- _main.c
2 d, K8 o7 n' T3 i" e- /* USER CODE BEGIN 2 */
: T6 r6 S8 y+ o& a' G - HAL_TIM_Base_Start_IT(&htim2);
2 m& p8 Y; w) m$ X - /* USER CODE END 2 */
复制代码- while (1)! c, V6 [2 b- L) ?! C8 O6 x
- {
( Q9 N* D- N" h, X/ o/ p - /* USER CODE END WHILE */: J5 F; K; q) ^4 L2 n
- 3 C' e: y& Z& u
- /* USER CODE BEGIN 3 */
3 s5 z. w9 L9 c ?3 M - if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == 1)
{6 r! l$ ^. W" W0 z- i! x - {
1 J% q6 j3 ~ h; Z - //HAL_Delay(50);
+ M& s4 n( z6 ]+ j5 P; B0 k - HC_SR04_distance=HC_SR04_getdistance();
7 P4 y+ u2 e8 E( n. A0 I8 S - HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);//灭灯! R9 q( X/ e0 S! u, E9 ?
- printf("有人,目前距离为:%.2f cm\r\n",HC_SR04_distance);
4 V5 z! Z: {5 r9 Z! {1 L - HAL_Delay(100);: S- v$ y+ U. a, J5 Y. b
- }
6 b8 E5 t" v, j# D" @ - 1 K; L2 g$ Q: J" i0 ?* N/ e
- else
! R4 e! K( ]* Z6 B2 Z: u. a - {
$ ^" l8 r/ S$ d4 ^ G4 t4 k! E - HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);//亮灯* ?$ S p& J# t/ g& ]
- printf("没人\r\n");- ~- H# Z, t4 S1 u
- HAL_Delay(1000);% y$ Y) C0 |" x7 Y; ]/ z( E2 \: q
- }( o4 Z7 f; q) f" J. x, }9 r! C0 n2 q
-
5 d0 m1 c* r+ [0 Q5 @; M; o - // printf("hellp\r\n");) [% B+ ?& s7 W6 V# c/ }1 ~+ p
- // HAL_Delay(1000);; R; x: S7 y# @& z0 `9 x s
- }; T8 D" t$ t( J- @- e
-
3 l. U4 r) C. D - /* USER CODE END 3 */
4 B5 y# o4 L* Z4 c9 `, K) L - }
复制代码 7 g" B b4 ^9 a: a4 J5 o
现象:6 x$ M+ y' h, o- D: }
2 h8 Q# ]$ o1 x* _3 ?* a) r
感应到人体,板载LED绿灯亮,同时串口打印测距结果。
! @& X+ ^) v5 J( G5 E) L! c1 {6 k. @5 y& w% r
?3 X, A* ^# `2 h$ k* Q, B5 B1 X& K* u2 V% i$ U" }
注意:
- j$ [8 L# ?9 R0 U% x0 \重定义printf后,必须在target里面勾选上MicroLIB,调用一下这个微型库,不然一直卡在里面。
# E& Z4 Z2 O( {$ |3 a6 h) @. I8 N p1 p' m3 r
9 q) }8 S' e( |) @* h. s' g
) W8 z/ W: `( X
$ b7 v- G* D( X# X% O6 k
0 s) N- J& L9 f4 w5 u, ]2 I |