前言3 m! m9 r8 a% w9 U6 ~
我在上一篇文章中驱动了HC-SR501红外人体传感模块,但在测试过程中发现,这个模块的热释电探头过于灵敏了,甚至有的时候往上哈气,会因为检测到类似于人体的温度而误判为感应到人体,所以为了减少误判概率,我打算再添加一个测距模块,在红外感应到人体时,再次判断人体与传感器的距离,在满足预设的距离范围时,才确定有人体接近,进行后续操作。' O* z* M5 t, u# b3 X
一、模块简介3 Q9 b! k) M5 P; c3 k7 c* t
HC-SR501红外人体感应模块资料介绍:
/ ~2 h, |3 _# @/ H5 O# H- n: q! q探究人体红外传感器HC-SR501
1 | E+ P U" P: n! q) b/ I+ p) w- A8 }
HC-SR04超声波测距模块资料介绍:
5 b) w" C! |4 V* |: a
; X$ o+ B5 @1 ~2 N f$ _
' D, e; b, Q' a. n
; m; e5 q/ M0 E$ @
* t6 V# U9 B( F- r/ ]7 n7 X
4 q9 F3 r+ U+ i$ x4 r3 g+ o* }* y
工作原理:
/ d, i- b: w; F5 E# ]% p, E' k/ ~2 a1 B) e. g$ n
+ B9 u; L3 P5 c+ @' m5 c' X
0 ?; Y, N8 l' Y5 U
6 f2 q4 X8 S3 X n) q& Q5 c" q, j* y. Y" u
简而言之:
' S% l# P2 R0 f1 Y* w9 l给Trig一个10μS以上的高电平,模块开始工作,模块内自动发送八个40khz方波,并自主检测是否有电波返回。此时需要检测Echo处的电平,当为高电平的时候记一个时间;当Echo出为低电平的时候再记一个时间,这两个时间的差就是高电平持续的时间,最后用测距公式进行计算。
( h- Z+ ~- ^6 h) ^6 j
& y$ \8 Y. T7 r! l7 m: T' x二、配置CubeMX
2 R1 _' H3 a( P$ ^/ F% Z. _1、新建工程;
3 @% D" [3 t# Y% `% n+ v2 q! d2、配置时钟源,在RCC里面的HSE配置的是晶振时钟;
, y4 X+ ^( y$ c- Z6 R3、配置程序烧录引脚SYS为SWD模式;
( q4 J6 k* v$ t3 U4、配置GPIO输出口,配置一个LED灯(我的板子是PC13),起到检测到人体时的指示作用;
# n% Y+ v* k1 b# `6 W, u5、配置GPIO输入口,用来读取HC-SR501模块的输出电平,我选的是PA1口;
: ]; e$ b5 U; z7 _6、配置GPIO输入口,用来检测HC-SR04超声波测距模块的回响信号输出,我选择PB5口,命名为HC_SR04_Echo_Pin;+ @; K8 N/ |" \/ h1 ]+ x N6 C$ h% k
7、配置GPIO输出口,用来触发HC-SR04超声波测距模块,我选择PB4口,命名为HC_SR04_Trig_Pin;( I$ C C- ^$ W) Q5 j7 Y
8、使能定时器,用来实现微秒延时,和测量HC-SR04模块高电平时间,我选择TIM2,并使能TIM2中断;
9 J, F& k; _. {! _4 p% Y" u: F. |# D i
! `! s& ]7 l1 o+ w7 {" P- h5 \) N1 T2 ]+ U: @
TIM2挂载在APB1,时钟来源频率为36MHz,故取预分频系数PSC=36-1,计数周期Counter设为60000-1。即此时定时器频率为36M/36=1MHz,每60ms进一次中断,60000μs对应实际测距范围大概为10m,远远超过我的需求。9 b& R' O/ x% ?/ f" I
% Y/ P/ S5 r, ]7 l' A" a4 G- P
) e, Y: T7 W0 L# r/ ^8 m. L
# M2 x# G4 d1 D! D, T! a) z9 R
5 X+ i; p& G7 G+ l& G0 ?
( R, g$ `4 v# ~3 O# r+ {9、配置串口收发引脚;
* w- }& q* n6 p" ]# j/ p10、配置时钟树,我还是开到最高的72MHz;2 E7 H* P# |" P
11、进行项目设置,最后生成代码,CubeMX部分就大功告成了0 e% C% |+ s1 b
& Q( S+ L! ~2 D- W0 ]& x
' y" e2 F0 Y" U9 ^% K6 x2 p" f' i8 j+ ]. ?0 F( ^0 x4 x
三、硬件连线部分' b& t. K8 Q7 _4 G- X$ X- r
CH340 ↔ STM32F103C8T6最小系统板:
% M3 t- [( p* Y. A( f9 L2 T. s5 \ TX ↔ RX
" P/ p" B4 h# y0 [: v RX ↔ TX$ u% T% c1 [ v" w$ T2 N2 Z
* y: R3 O) o' C' nDAP-LINK ↔ STM32F103C8T6最小系统板6 x" m. L/ h q) c2 z
3.3V ↔ VCC7 ?9 Y1 x! t) \ E
GND ↔ GND
r# F7 R! b3 u# A! k SWIO ↔ SWIO" L; i0 @* j# q0 Q7 [/ c; f1 }+ g
SWCLK ↔ SWCLK, y5 F( |- ^8 ^7 G
4 @# ]+ p5 D( |6 B; X7 v% ~HC-SR501模块 ↔ STM32F103C8T6最小系统板
" D! d7 {6 S; P OUT ↔ PA1
6 I( _5 k, W2 S! G7 d GND ↔ GND
% ]3 |3 u' h9 z1 a& {+ t
) M3 y( k: J( o2 b( c' IHC-SR501模块 ↔ DAP-LINK (这里注意模块供电范围为4.5V-20V,用3.3V无法驱动). I/ Z$ ?6 I1 }) @, u9 ?
VCC ↔ 5V" x6 ^! [0 G0 [- Z. H) G
/ L' A% i- @( p6 {3 L/ {: sHC-SR04模块 ↔ CH3405 t4 X, P$ I0 u% Y
VCC ↔ 5V- r5 `" }3 t! n% Z
; _+ l/ f: O# }& h
HC-SR04模块 ↔ STM32F103C8T6最小系统板9 H. r" Q$ F5 ^
Trig ↔ PB4
, N5 h( x4 b* p# l: E( R# P Echo ↔ PB5
8 Z1 M. R; x6 B: ]3 o% P: e GND ↔ GND
4 U) I% P0 M& e1 p( g$ A, ^3 j- O* b
四、逻辑代码部分6 w; G4 N& a+ T$ n7 ?
代码框架是基于上一篇HC-SR501红外人体感应模块修改而成的,想要完整代码的话可以和上篇文章一起看。
8 i- Z. t6 h8 w; X) c) H) Y7 X( y8 G3 H) y! W2 u' e
HC_SR04.c. m* Q5 o: O- m, r4 I
- #include "main.h"6 B7 j4 U. r/ ^/ G0 ]
- #include "HC_SR04.h"' x3 f" M0 G: y: V5 v, Z# D+ b
- #include "stm32f1xx_hal.h": z3 l: V# V P1 ^* O, R* }
- #include "stm32f1xx_it.h"9 G2 G! j/ E' _" U: ` _; A8 k) q
- 0 E2 \+ S6 y" A$ L, k7 f
- static float distance_result;; k9 F- D4 Q0 ?/ v+ z* ~
- /*
. z5 y6 W2 u d4 F6 Y' N0 t - *********************************************************8 }6 c" h# g/ o P7 P l5 ]
- 函数原型:void Delay_us(uint16_t time)
0 H: d. H: J! x7 Y. _( N x) ^- y - 函数输入:无符号整形
4 v% M4 K# K- h4 p - 函数输出:无
/ N1 X" V( |- a0 { - 函数功能:利用定时器实现微秒级延时
: }* G. ~8 |9 p( Z - *********************************************************9 i5 l$ B* H: ^* H: E3 r
- */
/ c, u9 \% N8 k - void Delay_us(uint16_t time)
7 [ C8 F. q0 t5 Y$ N: n1 b2 q; ^. X7 o - {
& q3 u6 I1 @9 q8 u- T* e - uint16_t a1=TIM2->CNT;
- |9 o4 W/ w- |9 y - while(TIM2->CNT-a1<time);
9 K7 U" I7 o9 M8 x) j - }2 `0 Z6 s6 B/ Q, O
- /*+ A0 I6 w) s, X* }* X
- *********************************************************
2 ]( K5 s2 w2 V4 v' ` - 函数原型:void HC_SR04_startrange(void)
% T: J6 Q6 Y5 t7 n3 I, V - 函数输入:无; e7 R( _0 }6 d9 ~+ j
- 函数输出:无! l. F3 ~: Y; c6 r
- 函数功能:从trig引脚生成一个不小于10us的高电平触发测距,触发后模块自动产生8个40kHz方波,自动检测是否有信号返回
4 D* u6 s" ^/ A; e0 x" P0 { - *********************************************************
h5 }% l* \" d# f) D - */
6 e/ b& W* g5 {" c2 x7 F - void HC_SR04_startrange(void)1 L- E! J! H( q
- {
; m; ~# m0 E% u2 p% M) Y1 U6 C - HAL_GPIO_WritePin(HC_SR04_Trig_GPIO_Port,HC_SR04_Trig_Pin,GPIO_PIN_SET);
0 T3 [, Z" q1 Z3 f, q* h - //HAL_Delay(5);
# ~ N {1 `: c3 F - Delay_us(10);
l+ L# s8 Y8 i. a - HAL_GPIO_WritePin(HC_SR04_Trig_GPIO_Port,HC_SR04_Trig_Pin,GPIO_PIN_RESET);
8 y% o8 b9 D/ [8 s6 q- `8 j - ' N- C/ I3 w1 l+ D' O6 c. E7 [" U! _
- }, s$ T* _( @. t U. k8 F
- /*8 X8 [, S9 d0 z, S
- *********************************************************
4 i6 j1 K, K+ C7 z) X. l - 函数原型:uint16_t HC_SR04_gettime(void)
1 [# p, h9 Y# | E - 函数输入:无, q' _% Q* u; R7 n" U4 B
- 函数输出:无符号整型/ v, t: s$ ^2 [
- 函数功能:通过定时器获取当前时间
. @# r g1 v- u& `% d) _) r - *********************************************************
; W N5 ^: A5 O H - */
0 m2 N, X1 v1 `5 m; f, W' j - uint16_t HC_SR04_gettime(void)6 G5 J0 N6 ] W2 n7 J* ^4 s
- {. K! M% a, Y! E
- uint32_t a;
. O0 y8 d7 |* q: B( n4 u* T1 S9 h - a=TIM2->CNT;
; g. ]. |# j. L( l+ y - return a;, F" n, T. J' D6 T& o
- }- T9 q% E' u4 j1 \! {! C
- /*
) ]* `4 B$ _3 b, r2 K - *********************************************************
& A4 f6 L6 d+ ~4 F- r - 函数原型:float HC_SR04_getdistance(void)
. n6 M" ~' D, U; [; ]% x% y; E" q" Q - 函数输入:无
, z1 Y' G) u8 n) @# v - 函数输出:浮点型
# E% C* P7 J$ P+ h, f - 函数功能:获取与目标之间的距离; b9 v' q& \" a7 ^ X$ k; ~% K
- *********************************************************
( @- V2 H; V$ I4 B, Y - */
: c1 S4 I2 g/ p! h9 T* Q% } - float HC_SR04_getdistance(void)+ {" f, [6 R+ \. V( W" M3 [2 s' f
- { & S: S$ M" ~$ r3 P7 Q9 q
- uint16_t time_node1;
7 j( @4 h5 e4 e) J8 B ` - uint16_t time_node2;
4 v- R! q+ Y& v3 R! A - uint16_t measure;; Y* Q8 n1 S' F# [3 n' Y% h: @! A
-
( c$ F* G! Q' X3 C) N( ^ - HC_SR04_startrange();
3 C4 ~8 ?. w: `1 T8 }$ y, c: I1 J - & B6 Y' L+ ?: m- w! k( y: A4 B k
- TIM2->CNT = 0;3 f) b8 V' @* w0 |; R
- . u6 U6 ?3 _: D" `
- //有信号返回则通过IO口Echo输出高电平,高电平持续时间即为超声波从发射到返回的时间,测试距离=( 高电平时间*声速(340m/s) )/ 2 / D! f; T' O2 q: K, V/ M
- while(HAL_GPIO_ReadPin(HC_SR04_Echo_GPIO_Port,HC_SR04_Echo_Pin)==RESET);6 S5 @- O9 _" r+ T) j, l
- time_node1=HC_SR04_gettime();
5 Q# I( o* \6 [! }* V P - 8 M) A& n' ^" V' Z" e K: z
- while(HAL_GPIO_ReadPin(HC_SR04_Echo_GPIO_Port,HC_SR04_Echo_Pin)==SET);9 D9 p# f0 W# _2 Y) g& I5 K- v
- time_node2=HC_SR04_gettime();
( z6 t1 d4 e) p -
5 l! b: p7 a5 J3 g# @ - measure=time_node2-time_node1;
+ i% k p8 y) u0 E- x - 0 i" \# P% {/ n+ _/ y; ]
- distance_result = measure * 17.0/1000;//距离=计数差值(us) / 1000000 * 340(m/s) * 100 / 2 = measure * 17/1000
& I; m8 B. `7 q6 P - & L( @% r4 H* |) D
- return distance_result;3 Z- x" \+ m4 Y5 Q/ }; q: e
- }
复制代码 ! p8 x6 t: {) ]
HC_SR04.h
( S8 Z5 Z3 `' y! [) ~- #ifndef _HC_SR04_H_
5 ^# ]9 l+ p* m8 R4 A8 | - #define _HC_SR04_H_7 ]/ @$ b" h# y4 E
- void Delay_us(uint16_t time);
% [2 _3 A3 F; _ - void HC_SR04_startrange(void);
0 Y: R m0 N' z; A9 g7 F - float HC_SR04_getdistance(void);( G8 h5 \, T- O, V, C# f
- uint16_t HC_SR04_gettime(void);( v* m8 u# F8 P8 e
- #endif
复制代码 # P: X+ v+ g2 H4 F3 F
main.c/ J* F3 [* i/ X1 J
- /* USER CODE BEGIN 2 */6 ^# |0 D( f0 M- ?- C
- HAL_TIM_Base_Start_IT(&htim2);8 k+ I- F; M4 V& V. m3 [' `
- /* USER CODE END 2 */
复制代码- while (1)
& ?/ Y0 V' b2 B+ c* i. o - {3 \3 v) g' W4 Q' ?' C" s$ p
- /* USER CODE END WHILE */5 z! a- R, b3 a( H, C
' M9 P0 n4 n# X' H+ `9 J- /* USER CODE BEGIN 3 */. _" K+ |$ q/ t) C4 @& @/ u5 R8 r- w
- if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == 1)
" g. E5 J$ Z V! c7 Z: p; i - {
: j6 W3 S/ V1 i- F - //HAL_Delay(50);
/ y; j2 K0 I' w2 L+ x - HC_SR04_distance=HC_SR04_getdistance();! t$ Q8 ?- M: S
- HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);//灭灯 x3 O9 X/ ^5 t* S
- printf("有人,目前距离为:%.2f cm\r\n",HC_SR04_distance);
4 t" X- H. q6 l# M7 h$ m9 J - HAL_Delay(100);
5 I D. Y! d) O( S" e* s+ g - }/ W5 Z: m% j: X6 V7 `6 f) ?
6 k: W) Z1 w& J0 z" w+ \) L( G9 t- else
1 z) W- z' c. B9 i0 a - {
& e7 f8 G9 p6 h - HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);//亮灯* X% S2 {% ] Z8 \+ G0 Q) k' w
- printf("没人\r\n");4 X" e: _% H! X( a _
- HAL_Delay(1000);
) Z) F8 G3 q0 o - }! A j! X/ [6 D6 k/ D$ `
- ; l8 Y. s; A! e7 T- h
- // printf("hellp\r\n");
: k! O" z( k- _, H/ f. F( Q8 } - // HAL_Delay(1000);" T# T) g6 e! z( }' K
- }( p9 C( h9 E( m$ ~* ~% N6 O! |
- " ]$ L! c1 w G0 W+ I) E
- /* USER CODE END 3 */( l( L+ K1 Q+ I. D. ?
- }
复制代码
% Y" J- H+ K; {1 {$ {现象:
0 T; s- {; j( C# S% R( O
8 |0 ?1 n* n/ x1 w$ }% }感应到人体,板载LED绿灯亮,同时串口打印测距结果。
. k! P% a5 p ~; Z) t' ~ J
' ^2 K: |9 N$ t$ L# N$ }
% U L5 t* A$ L- Y" {( A
2 u1 |) {. J8 S- n: n# U. C5 [注意:9 ~8 [, U0 D9 i
重定义printf后,必须在target里面勾选上MicroLIB,调用一下这个微型库,不然一直卡在里面。% e, y! m5 d( |- k( R& ~
5 e, [9 O2 }- ]! F" s/ F+ z
' n9 V7 ~: t) W$ v
' f8 n, g: J0 M$ [! p
/ q4 S4 _/ e L% K6 @3 B, X2 v9 u* w
|