【STC15单片机】 超声波模块的使用

简介: 【STC15单片机】 超声波模块的使用

1 基于STC15F2K60S2的超声波测距代码

单片机型号说明:IAP15F2K61S2

新建工程时单片机型号选择STC15F2K60S2


超声波测距模块的工作原理及应用

使用定时器产生超声波发射频率

1.1 基本注意事项

1.1.1 跳线帽接法

蓝桥杯单片机开发板 J13跳线帽 选择I/O模式

超声波和数码管之间的两个跳线帽接法:横着接(1-3)(2-4),J2两个跳线帽接到左边是超声波,接到右边是红外通信模块

598ebbc474f7a803f769d56ae993b55d_d7a861a01d95445cae40b304a2dc41f5.png

本开发板用到的芯片是   CX20106A芯片

1.1.2 晶振设置

说明STC15单片机默认晶振频率是11.0592MHz

历年赛题 一般要求选择12MHz

d39421e4a2e1afd610c17fd1d9e481a9_c75020aadcb0494e95000600a3da89ff.png

我们只需要在STC-ISP里设置一下即可

adb09a42b6c6fccd7630225bd301c649_547ef28b385d417081f24177e354fd55.png


1.2 板载超声波工作原理

14c267439132da432881c56602ffeeba_a034964d715a4b729824a41303633c81.png

fd5c015ef6485e5ac4742e940aefc94c_2d805c84d38946ee945984ed7da6c800.png

1.2.1 原理总结

       只需要在Trig管脚(TX管脚)发送8个40KHz的超声波脉冲(方波信号),驱动超声波发送探头工作,然后检测回波信号。当检测到回波信号后,通过Echo管脚(RX管脚)输出

       根据Echo管脚输出高电平的持续时间可以继续距离值

       即距离值为:(高电平时间*340m/s)/2

1.2.2 超声波代码思路

  1. 发送8个40KHz的超声波信号
  2. 检测接收管脚高电平时间
  3. 根据时间计算距离值

23143308ed30a63c7dbe8eaf8f220b7d_a7998b5b72a7492f89aaa4f3a4fda204.jpeg


1.3 STC15单片机代码部分

1.3.1 定时器0&定时器1初始化

定时器0用作基准定时

定时器1用作超声波距离检测定时器1不需要中断

1. void Timer0_Init(void)   //1毫秒 @12.000MHz @16位自动重载模式
2. {
3.  AUXR |= 0x80;   //定时器时钟1T模式
4.  TMOD &= 0xF0;   //设置定时器模式
5.  TL0 = 0x20;   //设置定时初始值
6.  TH0 = 0xD1;   //设置定时初始值
7.  TF0 = 0;    //清除TF0标志
8.  TR0 = 1;    //定时器0开始计时
9.  ET0 = 1;
10.   EA = 1; 
11. }
12. 
13. void Timer1_Init(void)
14. {
15.   AUXR |= 0x40;   //定时器时钟1T模式
16.   TMOD &= 0x0F;   //设置定时器模式
17. }

1.3.2 超声波ultrasonic.c  ultrasonic.h文件配置

这里先粘贴超声波模块的代码,具体计算过程放在1.3.3距离计算讲解

1. #include "ultrasonic.h"
2. 
3. unsigned char Ultrasonic_Time_Flag;  //200ms置1
4. 
5. /*
6.  TX引脚发送40KHz方波信号驱动超声波发送探头
7.  1/40KHz = 0.000025s = 0.025ms = 25us
8.  使用软件延时注意RC振荡器频率
9. */
10. void Ultrasonic_Delay25us()   //@12.000MHz 超声波专用的延时函数
11. {
12.   unsigned char i;
13. 
14.   _nop_();
15.   _nop_();
16.   i = 72;
17.   while (--i);
18. }
19. void Send_wave(void)  //发送40KHz的方波信号函数
20. {
21.   unsigned char i;
22.   for (i = 0; i < 8; i ++ )
23.   {
24.     TX = 1; Ultrasonic_Delay25us();
25. //    somenop;somenop;somenop;somenop;somenop;somenop;somenop;somenop;somenop;somenop;
26.     TX = 0; Ultrasonic_Delay25us();
27. //    somenop;somenop;somenop;somenop;somenop;somenop;somenop;somenop;somenop;somenop;
28.   }
29. }
30. 
31. //超声波测距函数
32. float Ultrasonic_Ranging(void)
33. {
34.   unsigned int Ranging_Time;  //测距的时间
35.   float Distance;
36. 
37.   if (1 == Ultrasonic_Time_Flag)  //200ms接受一次数据
38.   {
39.     Ultrasonic_Time_Flag = 0; //200ms时间标志位置0
40.     Send_wave();  //发送方波信号
41.     TR1 = 1;    //启动计时
42.     while ((1 == RX) && (0 == TF1));  //等待收到脉冲
43.     TR1 = 0;    //关闭计时
44. 
45.     if (1 == TF1) //发生溢出
46.     {
47.       TF1 = 0;
48.       Distance = 99;  //报错误数据
49.     }
50.     else
51.     {
52.       //Ranging_Time = (TH1<<8) | TL1;
53.       Ranging_Time = TH1*256 + TL1; 
54.       Distance = Ranging_Time*0.017;    //0.017 @12MHz 和 0.18446 @11.0592MHz
55.       Distance /= 12.0; //STC15单片机运行速度是51单片机的12倍,这里要除以12.0
56.             if (Distance >= 99) Distance = 99;  //限幅
57.     }
58.     TH1 = 0;    //复位清零
59.     TL1 = 0;    
60.   }
61.   return Distance;
62. }
63. 
64. //定时器0中断服务函数
65. void Timer0_Rountine(void) interrupt 1
66. {
67.   static unsigned int T0Count0;
68. 
69.   T0Count0++;
70.   if(T0Count0 >= 200) //200ms
71.   {
72.     //执行操作
73.     Ultrasonic_Time_Flag = 1;
74.     T0Count0 = 0; //软件复位
75.   }
76. }
1. //ultrasonic.h 文件
2. 
3. #ifndef __ULTRASONIC_H__
4. #define __ULTRASONIC_H__
5. 
6. #include <STC15F2K60S2.H>
7. #include "intrins.h"
8. 
9. #define somenop {_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_(); _nop_();}
10. 
11. sbit TX = P1^0;  //发射引脚
12. sbit RX = P1^1;  //接收引脚
13. 
14. float Ultrasonic_Ranging(void);
15. 
16. #endif

关于ultrasonic.c文件的一些解释说明

  1. Ultrasonic_Delay25us函数是Send_wave的内部调用函数,就是生成一个40KHz方波信号的函数
  2. 超声波测距函数,带float类型返回值,直接调用Ultrasonic_Ranging函数返回float类型的距离
  3. 注意Distance /= 12.0; 不能写Distance /= 12; 因为Distance是float类型!!!
  4. 定时器0中断服务函数放在本文件中,因为方便使用200ms的标志位Ultrasonic_Time_Flag

1.3.3 距离计算

计算公式:s = v*t  

  1. s:距离
  2. v:声音的传播速度
  3. t:传播时间!

对于51单片机@12.000MHz晶振而言,1个时钟周期 = 1 /(时钟源频率) = 1/12,000,000

1个机器周期 = 12个时钟周期

所以一个机器周期的时间就是 1 / 12,000,000 * 12 s=12/12,000,000= 1/1,000,000s

一个机器周期定时器计数加一

这里讲清楚了定时器计数加一的时间, 所以我们只需要获得定时器1的计数次数就能计算出超声波模块的传播时间,进而求的距离

高电平计数次数:TH1 * 256 + TL1

超声波模块计时时间 t  =(TH1 * 256 + TL1)* 12 / 12000000

由于这个计数时间是双程距离(一个来回的距离),所以时间应该除以2

t  = (TH1 * 256 + TL1)* 12 / 12000000 / 2

声速 = 340m/s,s = v*t 单位是米(m),最后乘以100,将单位换算成厘米(cm)

t  = (TH1 * 256 + TL1)* 12 / 12000000 / 2

∴ 距离  = (TH1 * 256 + TL1)* 12 / 12000000 / 2 * 340 * 100(cm)

∴距离  =  (TH1 * 256 + TL1)*0.017 (cm)

上述式子 用橙色标记的数据是一个机器周期

注意:

如果STC15单片机没用使用AUXR寄存器,使用12T模式,那么蓝桥杯单片机开发板运行速度和51单片机一致,到这里距离计算就ok了,可以直接拿到数码管上显示。

!!!

但是我们配置的定时器0使用AUXR寄存器,配置为1T模式,所以蓝桥杯单片机开发板运行速度是51单片机的12倍,所以最后要修正一下距离数据,最后将距离数据除以12.0,就得到真正的距离了

对于@11.0592MHz的晶振而言

一个机器周期时间就是12/11.0592MHz = 12/11059200s,一个机器周期定时器计数加一
所以用超声波模块计时时间 t = (TH1*256+TL1)*12/11.0595/1000/1000
由于这个计数时间是双程距离(来回),所以时间要/2  

t = (TH1*256+TL1)*12/11.0595/1000/1000/2
声速340m/s ,s = v*t 单位是m,最后乘以100 单位化成cm
将后面计算简化得0.01844618

   (TH1*256+TL1)*12/11.0595/1000/1000/2*340*100  (cm)
  =(TH1*256+TL1)*1.085/58
  =(TH1*256+TL1)*0.01844618

1.3.4 数码管

由于本人懒得一批,直接copy之前写过的数码管代码

06a7a386895bc23daf54cd0e73cd0d94_f558bfcfe7b343b8bc3c1750d85d99de.jpeg

1. #include "smg.h"
2. 
3. //关闭 蜂鸣器继电器LED数码管
4. void All_Init(void)
5. {
6.  P2 = 0xA0;  // 1010 0000
7.  P0 = 0x00;  //off蜂鸣器继电器
8. 
9.  P2 = 0x80;  // 1000 0000
10.   P0 = 0xFF;  //offLED
11. 
12.   P2 = 0xC0;  //使能锁存器U8 1100 0000
13.   P0 = 0xFF;  //选择所有数码管
14.   P2 = 0xFF;  //使能锁存器U7 1111 1111
15.   P0 = 0xFF;  //关闭所有数码管
16. }
17. 
18. //15单片机延时函数 @11.0592MHz
19. void Delay_ms(int xms)
20. {
21.   unsigned char i, j;   
22.   while(xms--){
23.     _nop_(); _nop_(); _nop_();
24.     i = 11; j = 190;
25.     do{
26.       while (--j);
27.     } while (--i);
28.   } 
29. }
30. 
31. /*共阳极码表 ABCDEF都是大写*/
32.                //0     1     2     3     4     5     6     7     8     9     A     B     C     D     E     F     -    灭
33. unsigned char NixieTable[] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90, 0x88, 0x80, 0xC6, 0xC0, 0x86, 0x8E, 0xBF, 0xFF, \
34.   0xC0 & 0x7F,  \
35.   0xF9 & 0x7F,  \
36.   0xA4 & 0x7F,  \
37.   0xB0 & 0x7F,  \
38.   0x99 & 0x7F,  \
39.   0x92 & 0x7F,  \
40.   0x82 & 0x7F,  \
41.   0xF8 & 0x7F,  \
42.   0x80 & 0x7F,  \
43.   0x90 & 0x7F,  \
44.   0xC1    //U
45. };
46. 
47. //如果想显示小数点,就 &0x7F 
48. 
49. void Nixie(unsigned char location, unsigned char number)
50. {
51.   P2 = 0xC0;  //Y6=0;Y6C=1; 使能锁存器U8     P27 = 1; P26 = 1; P25 = 0;
52.   switch(location)//选中LED位置,位选
53.   {
54.     case 1:P0 = 0x01;break;
55.     case 2:P0 = 0x02;break;
56.     case 3:P0 = 0x04;break;
57.     case 4:P0 = 0x08;break;
58.     case 5:P0 = 0x10;break;
59.     case 6:P0 = 0x20;break;
60.     case 7:P0 = 0x40;break;
61.     case 8:P0 = 0x80;break;
62.   }
63.   P2 = 0xFF;  //Y7=0;Y7C=1; 使能锁存器U7     P27 = 1; P26 = 1; P25 = 1;
64.   P0=NixieTable[number];//数字
65.   Delay_ms(1);
66.   P0=0xFF;//消影清零
67. }
68. 
69. /*数码管显示浮点数,支持0-1000以内的浮点数*/
70. void SMG_ShowFloatNum(float num)
71. {
72. 
73.   unsigned char Sep_Num[8]; //一次存放 千百十个...
74.   long temp;
75. 
76.   if (num >= 0) //正数
77.     temp = (long)(num*1000);    
78.   else  
79.     temp = (long)(-num*1000);
80. 
81. 
82.   Sep_Num[0] = temp / 1000000 % 10; //千位
83.   Sep_Num[1] = temp / 100000  % 10; //百位
84.   Sep_Num[2] = temp / 10000   % 10; //十位
85.   Sep_Num[3] = temp / 1000    % 10; //个位
86.   Sep_Num[4] = temp / 100     % 10; //小数点后第一位
87.   Sep_Num[5] = temp / 10      % 10; //小数点后第二位
88.   Sep_Num[6] = temp           % 10; //小数点后第三位 
89. 
90. 
91.   Nixie(4, Sep_Num[3] + 18);  //下标+18代表显示小数点
92.   Nixie(5, Sep_Num[4]);
93.   Nixie(6, Sep_Num[5]);
94.   Nixie(7, Sep_Num[6]);
95. 
96.   if    (num >=10     && num < 100  ) {Nixie(3, Sep_Num[2]);} //显示十位
97.   else if (num >=100    && num < 1000 ) {Nixie(3, Sep_Num[2]); Nixie(2, Sep_Num[1]);} //显示十位百位
98.   else if (num >=1000   && num <= 9999) {Nixie(3, Sep_Num[2]); Nixie(2, Sep_Num[1]); Nixie(1, Sep_Num[0]);} //显示十位百位千位
99.   else if (num > -100   && num <= -10 ) {Nixie(3, Sep_Num[2]); Nixie(2,16);}  //显示十位,并且显示负号
100.  else if (num > -1000  && num <= -100) {Nixie(3, Sep_Num[2]); Nixie(2, Sep_Num[1]); Nixie(1,16);}  //显示十位百位,并且显示负号
101.  else if (num >= -9999 && num <=-1000) {Nixie(3, Sep_Num[2]); Nixie(2, Sep_Num[1]); Nixie(1, Sep_Num[0]);} //显示十位百位千位,但是数码管不够了后续想显示出来,就把数码管显示的内容整体往后挪动一个位置即可
102.  else if (num > -10    && num < 0    ) {Nixie(3,16);}  //大于-10小于0的负数
103. }
1. #ifndef __SMG_H__
2. #define __SMG_H__
3. 
4. #include <STC15F2K60S2.H>
5. #include "intrins.h"
6. 
7. #define OFF_CODE 17  //数码管熄灭码
8. 
9. void All_Init(void); //关闭 蜂鸣器继电器LED数码管
10. void Delay_ms(int xms); //15单片机延时函数 @11.0592MHz
11. 
12. extern unsigned char NixieTable[];
13. void Nixie(unsigned char location, unsigned char number);
14. void SMG_ShowFloatNum(float num);
15. 
16. #endif

1.3.5 主函数

1. /* 
2.     实验名称:超声波测距实验
3.  开发平台:STC15F2K60S2 @12.000MHz
4. */
5. 
6. #include <STC15F2K60S2.H>
7. #include "smg.h"
8. #include "ultrasonic.h"
9. #include "Timer0.h"
10. #include "Timer1.h"
11. 
12. float distance;
13. 
14. void main()
15. {
16.   All_Init();
17.   Timer0_Init();  //基准定时1ms @12.000MHz @16位自动重载模式 
18.   Timer1_Init();  //仅初始化定时器1,不需要 计时、中断
19. 
20.   while(1)
21.   {
22.     distance = Ultrasonic_Ranging();
23.     SMG_ShowFloatNum(distance);
24.   }
25. }

2 缺陷

2.1 传播速度

声音在空气中传播的影响因素有许多

  1. 声音的传播速度跟介质的反抗平衡力有关,反抗平衡力就是当物质的某个分子偏离其平衡位置时,其周围的分子就要把它挤回到平衡位置上,而反抗平衡力越大,声音就传播的越快。水的反抗平衡力要比空气的大,而铁的反抗平衡力又比水的大。
  2. 声音在空气中的传播速度还与压强有关。
  3. 声音在空气中的速度随温度的变化而变化,温度每上升/下降5℃,声音的速度上升/下降3m/s。声音在空气中的传播速度是:空气(15℃)340m/s ,空气(25℃)346m/s 。
  4. 声音的传播速度随物质的坚韧性的增大而增加,物质的密度减小而减少。一般情况下,同温度下,固体传声最快,液体次之,气体最慢;而在同种介质中,温度越低声速越慢。
  5. 声音的传播与阻力有关。声音会因外界物质的阻挡而发生折射,例如人面对群山呼喊,就可以听得到自己的回声。

声音在空气中的传播速度=340m/s,受这么多因素影响,声音的传播速度不一定是标准的340m/s,但是代码中用的就是340这个数据,所以测量距离并不是非常准确

2.2 代码

所测的距离经常超出范围,原因是直接输出所测的距离,解决方案:优化输出距离的数据,用简单的滤波即可

数码管不稳定,能看到闪烁,可以使用定时器刷新数码管,或者采集数据时间更长一点(大概500ms采集一次?)这里留个疑问

fe38c3874f69587ffb4adae33aaead41_b5c257733ca841edb161482e3269d5bc.jpeg


3 超声波距离报警器

使用超声波模块测距,数码管显示距离,蜂鸣器根据距离长短发出不同频率鸣叫

距离越远鸣叫时间越长(频率越小),距离越近鸣叫时间越短(频率越大)

代码有一些小修改

main.c里的float distance;变量拿到ultrasonic.c中定义,然后在.h文件中externa外部声明出去,这样方便数据调用

在ultrasonic.c里声明两个变量

1. unsigned int  Buzzer_Time_Flag = 1000;    //蜂鸣器报警时间长短标志位
2. unsigned char Buzzer_Alarm_Flag;          //蜂鸣器报警标志位

定时器0中断服务函数有修改

1. //定时器0中断服务函数
2. void Timer0_Rountine(void) interrupt 1
3. {
4.  static unsigned int T0Count0, Buzzer_Count;
5. 
6.  T0Count0++;
7.  if(T0Count0 >= 200) //200ms
8.  {
9.    //执行操作
10.     Ultrasonic_Time_Flag = 1;
11.     T0Count0 = 0; //软件复位
12.   }
13. 
14.   Buzzer_Count++;
15.   if(Buzzer_Count >= Buzzer_Time_Flag)    //大于等于时间标志位(大概是**ms)
16.   {
17.     Buzzer_Alarm_Flag = !Buzzer_Alarm_Flag;    //鸣叫标志位状态反转,根据这个状态判断是否鸣叫
18.     Buzzer_Count = 0;
19.   }
20. }

编写蜂鸣器函数

1. //蜂鸣器 开启P06 =1,关闭P06 = 0;
2. void Buzzer_Alarm(void)
3. {
4.    //将main.c的distance变量拿到本文件中,然后外部声明出去,方便这里和主函数的数据调用
5.  if (distance) { Buzzer_Time_Flag = distance*10; } //鸣叫时间 = 距离*10,实现了距离越近,鸣叫时间越短
6. 
7.  P2 = 0xA0;  // 1010 0000 选中
8.  if (1 == Buzzer_Alarm_Flag) //鸣叫
9.  {
10. //    P06 = 1;
11.     P0 = 0x40;  //0100 0000   
12.   }
13.   else if((0 == Buzzer_Alarm_Flag)) //不鸣叫
14.   {
15. //    P06 = 0;
16.     P0 = 0x00;
17.   }   
18. }

控制蜂鸣器最好控制整个P0口,但是P06也能控制

如果没有障碍物,数据就溢出,数码管默认显示99.000,蜂鸣器默认以0.5Hz的频率鸣叫

声明void Buzzer_Alarm(void)函数,在while(1)里调用即可实现功能


4 超声波模块(HC-SR04)代码(51单片机)

更新中...

01e671dc1844eb741f9b2fd7df98df2e_f2462133dd0545208ef72800a78bc106.jpeg


相关文章
|
6月前
|
C++
【51单片机】添加模块代码的常见问题(图示&代码演示)
【51单片机】添加模块代码的常见问题(图示&代码演示)
|
存储 开发框架 前端开发
单片机与HC-05蓝牙模块通信
单片机与HC-05蓝牙模块通信
160 0
|
编解码 芯片
单片机外围模块漫谈之二,如何提高ADC转换精度
单片机外围模块漫谈之二,如何提高ADC转换精度
单片机外围模块漫谈之二,如何提高ADC转换精度
单片机外围模块漫谈之五,USB开发,这个错误你犯了吗?
单片机外围模块漫谈之五,USB开发,这个错误你犯了吗?
|
存储 Go 芯片
单片机外围模块漫谈之四,USB总线基本概念。
单片机外围模块漫谈之四,USB总线基本概念。
|
监控 芯片
单片机外围模块漫谈之三,CAN总线
单片机外围模块漫谈之三,CAN总线
|
编解码 资源调度 内存技术
单片机外围模块漫谈之一,图解说明什么是Flash, SAR, Sigma-Delta型ADC
单片机外围模块漫谈之一,图解说明什么是Flash, SAR, Sigma-Delta型ADC
51单片机学习-HC-05蓝牙模块-LCD12864显示
51单片机学习-HC-05蓝牙模块-LCD12864显示
158 0
51单片机学习-HC-05蓝牙模块-LCD12864显示
【单片机期中测试】13.串口通信的应用(2)—— 超声波通过串口返回数据
【单片机期中测试】13.串口通信的应用(2)—— 超声波通过串口返回数据
103 0
51单片机学习--LCD模块使用
51单片机学习--LCD模块使用
138 0
下一篇
无影云桌面