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

STM32的超声波测距程序

[复制链接]
STMCU-管管 发布时间:2020-9-14 11:08
我所使用的测距模块是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
20200914110443.b83b784b010232ade30d0d46b19a0350.png

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$ \
  1. <font style="font-size: 18px">#include "cs.h"
    # d5 x0 \6 T# F4 X. |3 J7 R
  2. #include "stm32f10x.h"% w/ h9 z/ X( n  f+ l' a
  3. #include "delay.h"7 U6 L" Y, i2 m) Z9 i
  4. #include "usart.h"
    ! t6 k) g0 o1 S" y0 r: ]9 _- q: j) ]
  5.   C3 H& G& V( ?  l! W2 m
  6. /*记录定时器溢出次数*/# g4 a) B# q7 m2 `( ~( o& j0 M3 b
  7. uint overcount=0;</font>1 N% U7 w9 H0 O" C0 z5 j2 j
  8. <font style="font-size: 18px">
    ; Y+ g$ d- l! d7 q. M) A& n0 |% O+ I
  9. /*设置中断优先级*/) v0 U+ O& W9 K" E
  10. void NVIC_Config(void)
    " T, G4 V& [9 q
  11. {4 o- B4 ], Z4 i+ K* X( U+ s6 \
  12. NVIC_InitTypeDef NVIC_InitStructer;
    & o& n6 q) j9 o' i7 w2 n/ @" A

  13. 4 M" T( _$ d6 Y* g6 B7 q
  14. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    + L( Q2 M* V, S" I! m

  15. # _; H/ f# U5 d% C- h2 [" _$ x2 [+ _
  16. NVIC_InitStructer.NVIC_IRQChannelPreemptionPriority=0;
    + [' u6 V6 s9 X
  17. NVIC_InitStructer.NVIC_IRQChannelSubPriority=0;
    3 ]. W. P" n: \6 d
  18. NVIC_InitStructer.NVIC_IRQChannel=TIM2_IRQn;" Q7 x" e  {! w) \; |
  19. NVIC_InitStructer.NVIC_IRQChannelCmd=ENABLE;6 r. w* A2 e! w
  20.   p2 j3 f4 u/ v# \
  21. NVIC_Init(&NVIC_InitStructer);
    4 t4 s) N  T- \. J6 H
  22. }5 T& h  o0 S4 A. m1 B/ }

  23. 0 I& L0 ^9 T3 V( _+ Y! l
  24. /*初始化模块的GPIO以及初始化定时器TIM2*/
    ; ?1 c$ y* r- b
  25. void CH_SR04_Init(void)' A! R8 c' [4 {9 a9 f0 V+ R/ v
  26. {7 ?6 w- {" d4 X
  27. GPIO_InitTypeDef GPIO_InitStructer;1 F9 B7 V) V' u( {( e0 J2 n  u  w
  28. TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructer;! O+ e7 s3 p- H& B3 V& b: W
  29. 6 j: [; O. @0 ~, u3 u
  30. RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE);2 q  A% R3 c# z' @0 ^3 Z
  31. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);, g' Q( R  Q+ P6 a& ]5 z
  32. 0 L9 [, k, k$ h7 y) m9 _' G
  33. /*TRIG触发信号*/2 B: l3 q$ T( G1 W: {, x$ y& s- Z
  34. GPIO_InitStructer.GPIO_Speed=GPIO_Speed_50MHz;7 ]- T/ f. D! p* j9 x- c
  35. GPIO_InitStructer.GPIO_Mode=GPIO_Mode_Out_PP;
    % s  Z* {" Y8 f' y" i
  36. GPIO_InitStructer.GPIO_Pin=GPIO_Pin_8;2 a; {, G' Q. u
  37. GPIO_Init(GPIOB, &GPIO_InitStructer);' I' }* z: \- W4 Y4 |: A9 p
  38. & m- L8 ~( b/ U+ l
  39. /*ECOH回响信号*/+ X0 [/ U0 g7 }2 N9 @8 O# k& M
  40. GPIO_InitStructer.GPIO_Mode=GPIO_Mode_IN_FLOATING;
    ( Y1 z$ @) S  l0 x/ i, }6 j
  41. GPIO_InitStructer.GPIO_Pin=GPIO_Pin_9;" g9 _# i- j. f" q$ X
  42. GPIO_Init(GPIOB, & GPIO_InitStructer);
    ( i  O; d6 ]/ [! \5 ?0 C

  43. 2 y2 _+ r, N9 i
  44. /*定时器TIM2初始化*/; z3 R7 {8 s4 g2 v; h3 O. y' m' E
  45. TIM_DeInit(TIM2);
    % X3 d$ C8 v2 z, ?! n
  46. TIM_TimeBaseInitStructer.TIM_Period=999;//定时周期为1000' Y2 _- {5 d; F8 n% H( P
  47. TIM_TimeBaseInitStructer.TIM_Prescaler=71; //分频系数72, r+ M% G% O8 ]! V# X. m' y" W5 }
  48. TIM_TimeBaseInitStructer.TIM_ClockDivision=TIM_CKD_DIV1;//不分频
    " g* g6 E+ V+ f0 T
  49. TIM_TimeBaseInitStructer.TIM_CounterMode=TIM_CounterMode_Up;
    . X7 _  f1 i1 n! l. D# O$ j
  50. TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructer);
    2 Y# ?" T* n3 J
  51. - ?2 t! a: {1 ^
  52. TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//开启更新中断4 j+ m! l. ]8 u
  53. NVIC_Config();
    , ]. b& I+ _8 B. x4 G$ A8 r  x" n
  54. TIM_Cmd(TIM2,DISABLE);//关闭定时器使能
    * Y$ U" n( n# w# H' J* o

  55. 1 ^  k6 I1 W, h1 X. A; J: q
  56. }
    + v4 c2 m8 c. B) o+ l) p  O/ [
  57. 2 ~2 Z; A0 ^0 I3 e& Z9 H
  58. float Senor_Using(void)
    & M: p2 A8 }: }0 o, P) E
  59. {
    - M5 w+ n; I) ?( f3 L9 O$ [; ?
  60. float length=0,sum=0;! x2 p  V5 Z$ U4 ^* r9 [) S' T/ l! U
  61. u16 tim;
    * t3 B. P2 r0 |1 {
  62. uint i=0;6 ?% G" U& y& k4 {0 _( n( h
  63. /*测5次数据计算一次平均值*/# r. g' g/ {. s6 q' w
  64. while(i!=5)- c* s" ~! g! ~: r$ F" z
  65. {
    1 ~  ?4 \8 ^: k" W; [9 r& o
  66. PBout(8)=1; //拉高信号,作为触发信号
    . O, y' N- }6 \- `7 P" K$ W$ l
  67. delay_us(20); //高电平信号超过10us( {  m! J4 A0 l2 H4 o* [
  68. PBout(8)=0;. Z, f  s9 t+ n- ~: O: P7 a
  69. /*等待回响信号*/
    ; }( |& R' @- i4 e( Q
  70. while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_9)==RESET);( c& l* `) J0 {! z+ i+ D
  71. TIM_Cmd(TIM2,ENABLE);//回响信号到来,开启定时器计数3 N. Z. j- l4 ]$ [6 E

  72. " V; S# z8 `/ J6 W% n  Y
  73. i+=1; //每收到一次回响信号+1,收到5次就计算均值
    7 j/ L  ~" T8 \7 `- |1 f
  74. while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_9)==SET);//回响信号消失; ]  O' |' ^$ ^
  75. TIM_Cmd(TIM2,DISABLE);//关闭定时器
    " _! r7 j4 S2 O

  76. & C) Y& ^; g, b
  77. tim=TIM_GetCounter(TIM2);//获取计TIM2数寄存器中的计数值,一边计算回响信号时间+ m  C2 a: `; ^! \# K

  78. , z* a1 s6 F" N- Q2 z0 i! n0 G
  79. length=(tim+overcount*1000)/58.0;//通过回响信号计算距离
    9 F* C- g; W3 i3 q
  80. 6 B! G5 b: l+ y: w8 s
  81. sum=length+sum;
    1 H: Z$ s9 _$ \' \9 R7 n' a( M
  82. TIM2->CNT=0; //将TIM2计数寄存器的计数值清零
    % x8 X( f) C& V/ `3 e* i8 s
  83. overcount=0; //中断溢出次数清零
    5 D% T, m! i& U) h7 H6 F
  84. delay_ms(100);
      T& U; o5 `( k7 J* |) m( E
  85. }9 L4 u5 h% e' b* l
  86. length=sum/5;. a% S( r7 l. c
  87. return length;//距离作为函数返回值
    ! f) s4 R1 R( J% n2 `
  88. }
    5 M  c2 i& u9 T" a8 e7 y1 Y
  89. 6 u& ?! }0 `0 c8 z
  90. void TIM2_IRQHandler(void) //中断,当回响信号很长是,计数值溢出后重复计数,用中断来保存溢出次数. M% Q, A) D/ x6 c% U
  91. {, @8 X6 ]- i7 e( u' `9 s" @$ f% x: T  C
  92. if(TIM_GetITStatus(TIM2,TIM_IT_Update)!=RESET)& n9 h) A2 a7 i: ~
  93.   {
    . K9 ^8 c2 l5 z5 L) M
  94. TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//清除中断标志6 B8 d7 h4 _/ A3 W: e  u) j2 |
  95. overcount++;4 |2 F( H2 f. o" l2 ~$ x2 g. I
  96.   }) j0 a6 ?. X; K4 S  `4 K
  97. }4 k; Z% b; X9 K* Z) I; n
  98. </font>
复制代码

) t% A" ?7 _( A. Y4 m9 D上面的代码是超声波测距的代码,cs.h是头文件,内容如下:3 j, |8 L  H/ V( s3 U
  1. #ifndef _CS_H
    ' T2 j6 ^2 B* p8 T' W' S: |
  2. #define _CS_H) Q4 Z0 r5 J2 Q+ T& |3 l7 q

  3. . O$ t1 H. P+ Q# Z% f
  4. #include "sys.h"
    6 L/ J& S: J& m, [
  5. #define uint unsigned int" N4 {4 m: t% l9 v5 j- H4 [8 ?
  6. #define TRIG_Send  PBout(8)
    , b0 k. q: U, h9 H* ~
  7. #define ECHO_Reci  PBin(9)  j1 G# T! w. n6 L* j7 w

  8. ' ?# K. [' N: Q; v- ]3 A& h
  9. void CH_SR04_Init(void);
    & L' F; k# y& Q" ?
  10. float Senor_Using(void);1 g" ?  I, Z+ E  W6 L4 x% Q
  11. void NVIC_Config(void);
    " Y. x& i: M7 s3 i0 C: f, p
  12. #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
赞 收藏 评论2 发布时间:2020-9-14 11:08

举报

2个回答
goyhuan 回答时间:2020-9-14 13:33:39
长知识
w014017 回答时间:2020-9-15 09:29:39
学习
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版