我所使用的测距模块是HC-SR04,C-SR04超声波测距模块可提供2cm-400cm的非接触式距离感测功能,测
?; G9 z5 n0 ^' n距精度可达高到3mm;模块包括超声波发射器、接收器与控制电路。 ) `$ E2 t3 o e
HC-SR04基本工作原理:
4 M( p, C( D' z(1)采用IO口TRIG触发测距,给最少10us的高电平信呈。
9 i8 U9 L6 y/ l8 b& J(2)模块自动发送8个40khz的方波,自动检测是否有信号返回;
6 |7 |3 h6 T n6 a" K(3)有信号返回, 通过IO口ECHO输出一个高电平, 高电平持续的时间就是超声波从发射到返回的时间。 测试距离=(高电平时间*声速(340M/S))/2。
7 |2 M: f8 R5 Q( E& k/ G程序编写思路是:1、配置好使用到的GPIO以及定时器;0 T6 @; S) d: ^+ O
2、给模块TRIG端口发送大于10us的高电平信号,当收、收到ECHO回响信号是,打开定时器开始定时;, f: n+ |' O( V$ p9 J
3、当回响信号消失,关闭定时器;
* b. h9 O* J1 N& e8 k4、通过定时器定时时间来确定距离。
% ?' N+ x% D- r" P
8 \3 _- l3 {' C9 w9 u
5 V' X- M. P! ~3 b* t* N! _* C) h
. M1 e3 |( m. Q0 D; W! c上时序图表明你只需要提供一个 10uS以上脉冲触发信号,该模块内部将发出8个 40kHz周期电平并检测回波。一旦检测到有回波信号则输出回响信号。回响信号的脉冲宽度与所测的距离成正比。 由此通过发射信号到收到的回响信号时间间隔可以计算得到距离。 公式: uS/58=厘米或者uS/148=英寸; 或是: 距离=高电平时间*声速( 340M/S) /2; 建议测量周期为 60ms以上, 以防止发射信号对。6 F5 |8 [5 i5 z& g! h
& v' }( h& J7 y' o( u
回响信号的影响
* Z& F8 v5 R7 I: Z& x |0 h
" h8 \% t r. ^% M+ S具体程序如下:
% k+ y0 \, \! P: O0 A$ \- <font style="font-size: 18px">#include "cs.h"
# d5 x0 \6 T# F4 X. |3 J7 R - #include "stm32f10x.h"% w/ h9 z/ X( n f+ l' a
- #include "delay.h"7 U6 L" Y, i2 m) Z9 i
- #include "usart.h"
! t6 k) g0 o1 S" y0 r: ]9 _- q: j) ] - C3 H& G& V( ? l! W2 m
- /*记录定时器溢出次数*/# g4 a) B# q7 m2 `( ~( o& j0 M3 b
- uint overcount=0;</font>1 N% U7 w9 H0 O" C0 z5 j2 j
- <font style="font-size: 18px">
; Y+ g$ d- l! d7 q. M) A& n0 |% O+ I - /*设置中断优先级*/) v0 U+ O& W9 K" E
- void NVIC_Config(void)
" T, G4 V& [9 q - {4 o- B4 ], Z4 i+ K* X( U+ s6 \
- NVIC_InitTypeDef NVIC_InitStructer;
& o& n6 q) j9 o' i7 w2 n/ @" A
4 M" T( _$ d6 Y* g6 B7 q- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
+ L( Q2 M* V, S" I! m
# _; H/ f# U5 d% C- h2 [" _$ x2 [+ _- NVIC_InitStructer.NVIC_IRQChannelPreemptionPriority=0;
+ [' u6 V6 s9 X - NVIC_InitStructer.NVIC_IRQChannelSubPriority=0;
3 ]. W. P" n: \6 d - NVIC_InitStructer.NVIC_IRQChannel=TIM2_IRQn;" Q7 x" e {! w) \; |
- NVIC_InitStructer.NVIC_IRQChannelCmd=ENABLE;6 r. w* A2 e! w
- p2 j3 f4 u/ v# \
- NVIC_Init(&NVIC_InitStructer);
4 t4 s) N T- \. J6 H - }5 T& h o0 S4 A. m1 B/ }
0 I& L0 ^9 T3 V( _+ Y! l- /*初始化模块的GPIO以及初始化定时器TIM2*/
; ?1 c$ y* r- b - void CH_SR04_Init(void)' A! R8 c' [4 {9 a9 f0 V+ R/ v
- {7 ?6 w- {" d4 X
- GPIO_InitTypeDef GPIO_InitStructer;1 F9 B7 V) V' u( {( e0 J2 n u w
- TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructer;! O+ e7 s3 p- H& B3 V& b: W
- 6 j: [; O. @0 ~, u3 u
- RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE);2 q A% R3 c# z' @0 ^3 Z
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);, g' Q( R Q+ P6 a& ]5 z
- 0 L9 [, k, k$ h7 y) m9 _' G
- /*TRIG触发信号*/2 B: l3 q$ T( G1 W: {, x$ y& s- Z
- GPIO_InitStructer.GPIO_Speed=GPIO_Speed_50MHz;7 ]- T/ f. D! p* j9 x- c
- GPIO_InitStructer.GPIO_Mode=GPIO_Mode_Out_PP;
% s Z* {" Y8 f' y" i - GPIO_InitStructer.GPIO_Pin=GPIO_Pin_8;2 a; {, G' Q. u
- GPIO_Init(GPIOB, &GPIO_InitStructer);' I' }* z: \- W4 Y4 |: A9 p
- & m- L8 ~( b/ U+ l
- /*ECOH回响信号*/+ X0 [/ U0 g7 }2 N9 @8 O# k& M
- GPIO_InitStructer.GPIO_Mode=GPIO_Mode_IN_FLOATING;
( Y1 z$ @) S l0 x/ i, }6 j - GPIO_InitStructer.GPIO_Pin=GPIO_Pin_9;" g9 _# i- j. f" q$ X
- GPIO_Init(GPIOB, & GPIO_InitStructer);
( i O; d6 ]/ [! \5 ?0 C
2 y2 _+ r, N9 i- /*定时器TIM2初始化*/; z3 R7 {8 s4 g2 v; h3 O. y' m' E
- TIM_DeInit(TIM2);
% X3 d$ C8 v2 z, ?! n - TIM_TimeBaseInitStructer.TIM_Period=999;//定时周期为1000' Y2 _- {5 d; F8 n% H( P
- TIM_TimeBaseInitStructer.TIM_Prescaler=71; //分频系数72, r+ M% G% O8 ]! V# X. m' y" W5 }
- TIM_TimeBaseInitStructer.TIM_ClockDivision=TIM_CKD_DIV1;//不分频
" g* g6 E+ V+ f0 T - TIM_TimeBaseInitStructer.TIM_CounterMode=TIM_CounterMode_Up;
. X7 _ f1 i1 n! l. D# O$ j - TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructer);
2 Y# ?" T* n3 J - - ?2 t! a: {1 ^
- TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//开启更新中断4 j+ m! l. ]8 u
- NVIC_Config();
, ]. b& I+ _8 B. x4 G$ A8 r x" n - TIM_Cmd(TIM2,DISABLE);//关闭定时器使能
* Y$ U" n( n# w# H' J* o
1 ^ k6 I1 W, h1 X. A; J: q- }
+ v4 c2 m8 c. B) o+ l) p O/ [ - 2 ~2 Z; A0 ^0 I3 e& Z9 H
- float Senor_Using(void)
& M: p2 A8 }: }0 o, P) E - {
- M5 w+ n; I) ?( f3 L9 O$ [; ? - float length=0,sum=0;! x2 p V5 Z$ U4 ^* r9 [) S' T/ l! U
- u16 tim;
* t3 B. P2 r0 |1 { - uint i=0;6 ?% G" U& y& k4 {0 _( n( h
- /*测5次数据计算一次平均值*/# r. g' g/ {. s6 q' w
- while(i!=5)- c* s" ~! g! ~: r$ F" z
- {
1 ~ ?4 \8 ^: k" W; [9 r& o - PBout(8)=1; //拉高信号,作为触发信号
. O, y' N- }6 \- `7 P" K$ W$ l - delay_us(20); //高电平信号超过10us( { m! J4 A0 l2 H4 o* [
- PBout(8)=0;. Z, f s9 t+ n- ~: O: P7 a
- /*等待回响信号*/
; }( |& R' @- i4 e( Q - while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_9)==RESET);( c& l* `) J0 {! z+ i+ D
- TIM_Cmd(TIM2,ENABLE);//回响信号到来,开启定时器计数3 N. Z. j- l4 ]$ [6 E
" V; S# z8 `/ J6 W% n Y- i+=1; //每收到一次回响信号+1,收到5次就计算均值
7 j/ L ~" T8 \7 `- |1 f - while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_9)==SET);//回响信号消失; ] O' |' ^$ ^
- TIM_Cmd(TIM2,DISABLE);//关闭定时器
" _! r7 j4 S2 O
& C) Y& ^; g, b- tim=TIM_GetCounter(TIM2);//获取计TIM2数寄存器中的计数值,一边计算回响信号时间+ m C2 a: `; ^! \# K
, z* a1 s6 F" N- Q2 z0 i! n0 G- length=(tim+overcount*1000)/58.0;//通过回响信号计算距离
9 F* C- g; W3 i3 q - 6 B! G5 b: l+ y: w8 s
- sum=length+sum;
1 H: Z$ s9 _$ \' \9 R7 n' a( M - TIM2->CNT=0; //将TIM2计数寄存器的计数值清零
% x8 X( f) C& V/ `3 e* i8 s - overcount=0; //中断溢出次数清零
5 D% T, m! i& U) h7 H6 F - delay_ms(100);
T& U; o5 `( k7 J* |) m( E - }9 L4 u5 h% e' b* l
- length=sum/5;. a% S( r7 l. c
- return length;//距离作为函数返回值
! f) s4 R1 R( J% n2 ` - }
5 M c2 i& u9 T" a8 e7 y1 Y - 6 u& ?! }0 `0 c8 z
- void TIM2_IRQHandler(void) //中断,当回响信号很长是,计数值溢出后重复计数,用中断来保存溢出次数. M% Q, A) D/ x6 c% U
- {, @8 X6 ]- i7 e( u' `9 s" @$ f% x: T C
- if(TIM_GetITStatus(TIM2,TIM_IT_Update)!=RESET)& n9 h) A2 a7 i: ~
- {
. K9 ^8 c2 l5 z5 L) M - TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//清除中断标志6 B8 d7 h4 _/ A3 W: e u) j2 |
- overcount++;4 |2 F( H2 f. o" l2 ~$ x2 g. I
- }) j0 a6 ?. X; K4 S `4 K
- }4 k; Z% b; X9 K* Z) I; n
- </font>
复制代码
) t% A" ?7 _( A. Y4 m9 D上面的代码是超声波测距的代码,cs.h是头文件,内容如下:3 j, |8 L H/ V( s3 U
- #ifndef _CS_H
' T2 j6 ^2 B* p8 T' W' S: | - #define _CS_H) Q4 Z0 r5 J2 Q+ T& |3 l7 q
. O$ t1 H. P+ Q# Z% f- #include "sys.h"
6 L/ J& S: J& m, [ - #define uint unsigned int" N4 {4 m: t% l9 v5 j- H4 [8 ?
- #define TRIG_Send PBout(8)
, b0 k. q: U, h9 H* ~ - #define ECHO_Reci PBin(9) j1 G# T! w. n6 L* j7 w
' ?# K. [' N: Q; v- ]3 A& h- void CH_SR04_Init(void);
& L' F; k# y& Q" ? - float Senor_Using(void);1 g" ? I, Z+ E W6 L4 x% Q
- void NVIC_Config(void);
" Y. x& i: M7 s3 i0 C: f, p - #endif
复制代码
! ?3 B- Y0 l+ A- z( ^/ f2 x L- U6 D' w( L
这些代码已经能够测距了,Senor_Using()返回值就是距离。具体如何把测得数据显示,就按照各自需求来做就行了。5 }$ d: u5 b' V0 ~1 \: r
) q5 o1 O9 V5 S7 L1 Q+ X
|