本文将对两者实现超声波测距进行对比
原材料:Arduino,51单片机,杜邦线,HC-SR04(市面常见)
HC-SR04工作原理:网络上相关的介绍很多,这里我将以我的理解来进行阐述:它有四个引脚,一个接VCC,一个接GND。另外两个分别是Trig以及Echo。其中,Trig的作用是启动该模块;而Echo引脚的作用是接受返回的声波。
启动模块的步骤:Trig置为高电平,持续时间大于10us即可,之后将其置为低电平。
之所以我们通过这个模块来测距,是因为我们可以通过计算Echo引脚高电平持续时间进而求出对应的距离。所以核心在于计算高电平的持续时间。
- Arduino
Arduino中,有一个特别的函数可以简单直接求出高电平的持续时间–pulseIn(引脚,高/低电平);它的输出就是时间。完全不需要像单片机使用定时计数器那样麻烦。
const int TrigPin = 2; //触发控制信号输入
const int EchoPin = 3; //回响信号输出
float cm;
void setup() {
Serial.begin(9600);
pinMode(TrigPin,OUTPUT);
pinMode(EchoPin,INPUT);
}
void loop() {
digitalWrite(TrigPin,LOW);
delayMicroseconds(2); //delayMicroseconds也是延时函数,单位是微秒
digitalWrite(TrigPin,HIGH);
delayMicroseconds(10);
digitalWrite(TrigPin,LOW);
cm = pulseIn(EchoPin,HIGH)/58; //pulseIn用于检测引脚输出的高低电平的脉冲宽度。58用于将回波时间换算成cm
cm = (int(cm*100))/100; //保留两位小数
Serial.print(cm);
Serial.print("cm");
Serial.println();
delay(1000);
}
- 51单片机
#include"reg51.h"
#include <intrins.h>
sbit RX=P2^0;
sbit TX=P2^1;
unsigned int time=0;
unsigned int timer=0;
unsigned char posit=0;
unsigned long S=0;
bit flag =0;
//--定义使用的IO--//
#define GPIO_DIG P0
sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;
//--定义全局变量--//
unsigned char code DIG_CODE[17]={
0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
//0、1、2、3、4、5、6、7、8、9、A、b、C、d、E、F的显示码
unsigned char disbuff[4] ={ 0,0,0,0,};
void DigDisplay()
{
unsigned char i;
unsigned int j;
for(i=0;i<8;i++)
{
switch(i) //位选,选择点亮的数码管,
{
case(0):
LSA=1;LSB=1;LSC=1; break;//显示第7位
case(1):
LSA=0;LSB=1;LSC=1; break;//显示第6位
case(2):
LSA=1;LSB=0;LSC=1; break;//显示第5位
case(3):
LSA=0;LSB=0;LSC=1; break;//显示第4位
}
GPIO_DIG=disbuff[i];//发送段码
j=10; //扫描间隔时间设定
while(j--);
GPIO_DIG=0x00;//消隐
}
}
void Conut(void)
{
time=TH0*256+TL0;
TH0=0;
TL0=0;
S= (long)(time*0.17); //算出来是CM
if((S>=4000)||flag==1) //超出测量范围显示“ERR0”
{
flag=0;
disbuff[0]=0x3f; //“-”
disbuff[1]=0x50; //“-”
disbuff[2]=0x50; //“-”
disbuff[3]=0x79; //“-”
}
else
{
disbuff[0]=DIG_CODE[S%10000/1000];
disbuff[1]=DIG_CODE[S%1000/100];
disbuff[2]=DIG_CODE[S%100/10];
disbuff[3]=DIG_CODE[S%10/1];
}
}
void zd0() interrupt 1 //T0中断用来计数器溢出,超过测距范围
{
flag=1; //中断溢出标志
}
void zd3() interrupt 3 //T1中断用来扫描数码管和计800MS启动模块
{
TH1=0xf8;
TL1=0x30;
DigDisplay();
timer++;
if(timer>=100)
{
timer=0;
TX=1; //800MS 启动一次模块
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
TX=0;
}
}
void main( void )
{
TMOD=0x11; //设T0为方式1,GATE=1;gate位置1,相当于测量脉宽。
TH0=0;
TL0=0;
TH1=0xf8; //2MS定时
TL1=0x30;
ET0=1; //允许T0中断
ET1=1; //允许T1中断
TR1=1; //开启定时器
EA=1; //开启总中断
while(1)
{
while(!RX); //当RX为零时等待
TR0=1; //开启计数
while(RX); //当RX为1计数并等待
TR0=0; //关闭计数
Conut(); //计算
}
}
当然了,为了直观显示测距后的结果,我这里用到了数码管,这个模块用起来十分的方便,如果有不懂的话,可以在评论区留言。
- 总结
从代码的行数来看,显然是Arduino实现起来方便,仅一句pulseIn就完成了51单片机定时计数器的任务。当然了,像我这种初学者最开始接触的就是51了,用它来实现也可以帮助我们深入理解定时计数器。为以后学习stm32打下基础。
PS:作为一名通信专业的毕业生,目前仍然在学习51以及Arduino,处于找工作的路上,Fighting!