一、基本原理
超声波发射模块向某一方向发射超声波
,在发射时刻的同时开始计时
,超声波在空气中传播,途中碰到障碍物就立即返回来,超声波接收器收到反射波就立即停止计时
。
二、计算公式
距离 = 声速 × 发出超声波到接收返回的时间/2
因为超声波在空气中的传播速度受温度影响。声波在空气中的传播速度与温度的关系是:
在20摄氏度时,声速V = 332 + 0.607t (m/s)
利用超声波进行距离测量,要求精度一般都不高,取20摄氏度时候的声速344M/S
进行计算,再进行适当的补偿就可以。所以,其计算公式为:距离L = 344M/S * T / 2 = 172M/S * T 。
三、实现步骤
- 产生
8个40KHz
的超声波信号,通过TX引脚
发射出去 启动定时器
,计算计数脉冲。- 等待超声波信号返回,如果接收到反射回来的信号,
RX引脚变为低电平
。 停止定时器
,读取脉冲个数,即获得时间T。- 根据公式,
L = V * T /2m
进行距离的计算。
四、参考程序
注:超声波测距是一直以来都是国赛中重要的考点,几乎每届必考。虽然省赛还没有考过,但也不能排除以后不考
在蓝桥杯单片机的竞赛综合平台CT107D中,超声波模块的TX引脚接到单片机的
P1.0端口
,RX引脚接到单片机的P1.1端口
。设计程序,进行超声波测距,最大测量范围约140cm。测量结果用cm作为显示单位,显示在数码管的最左边三位。如果测量距离超出范围,则以“F”作为标志,显示在数码管的最右边一位。
sonic.c
#include "sys.h"
#define sonic_nop {_nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_();};
void Send_Sonic(void) //发送8个40khz脉冲信号
{
unsigned char i = 8;
while(i --)
{
TX = 1;
sonic_nop; sonic_nop; sonic_nop; sonic_nop; sonic_nop;
sonic_nop; sonic_nop; sonic_nop; sonic_nop; sonic_nop;
TX = 0;
sonic_nop; sonic_nop; sonic_nop; sonic_nop; sonic_nop;
sonic_nop; sonic_nop; sonic_nop; sonic_nop; sonic_nop;
}
}
unsigned int Mea_Distance()
{
u16 distance = 0;
u16 time = 0;
Send_Sonic(); //发送超声波信号
TR1 = 1; //启动定时器1
while((RX == 1)&&(TF1 == 0));//等待超声波信号返回,或者等到测量超出范围
TR1 = 0; //停止定时器1
if(TF1 == 0) //正常测量范围
{
time = TH1;
time = (time << 8)|TL1;
distance = time*0.0175;
}else //超出测量范围
{
TF1 = 0;
distance = 999;
}
TH1 = 0;
TL1 = 0;
return distance;
}
main.c
#include "sys.h"
bit MEA_SONIC_FLAG;
void main()
{
u16 distance = 0;
ALL_Init();
Timer0Init();
Timer1Init();
while(1)
{
if(MEA_SONIC_FLAG) //每125ms测量一次
{
MEA_SONIC_FLAG = 0;
distance = Mea_Distance();
}
Nixie_Drive(distance);
}
}
sys.h
#ifndef __SYS_H__
#define __SYS_H__
//头文件包含
#include <STC15F2K60S2.H>
#include <intrins.h>
//管脚声明
sbit TX = P1^0;//超声波发送
sbit RX = P1^1;//超声波接收
//变量类型声明
typedef unsigned int uint;
typedef unsigned int u16;
typedef unsigned char uchar;
typedef unsigned char u8;
//外部变量声明
//函数声明
void ALL_Init();
void Operate_Delay(unsigned int ms);
void HC138_Set(u8 channel);
void Timer0Init();
void Timer1Init(void);
//nixie.c
void Nixie_Scan();
void Nixie_Show();
void Nixie_Drive(u16 dat);
//sonic.c
void Send_Sonic();
unsigned int Mea_Distance();
#endif
nixie.c
#include "sys.h"
// 0 1 2 3 4 5 6 7
uchar code nixie[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
// 8 9 a b c d e f u
0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0xc1,0xff}; //共阳数码管码字
uchar NixieBuff[] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
uchar smg1,smg2,smg3,smg4,smg5,smg6,smg7,smg8;
uchar code Symbol[] = {0xff,0xbf}; //全灭,-
void Nixie_Scan()
{
static u8 index;
HC138_Set(7);
P0 = 0XFF;
HC138_Set(6);
P0 = 0x01<<index;
HC138_Set(7);
P0 = NixieBuff[index];
HC138_Set(0);
index++;
index &= 0x07;
}
void Nixie_Show()
{
NixieBuff[0] = nixie[smg1];
NixieBuff[1] = nixie[smg2];
NixieBuff[2] = nixie[smg3];
NixieBuff[3] = Symbol[smg4];
NixieBuff[4] = Symbol[smg5];
NixieBuff[5] = Symbol[smg6];
NixieBuff[6] = Symbol[smg7];
NixieBuff[7] = nixie[smg8];
}
void Nixie_Drive(u16 dat)
{
if(dat == 999)
{
smg1 = smg2 = smg3 = 17;
smg4 = smg5 = smg6 = smg7 = 0;
smg8 = 15;
}else
{
smg1 = dat/100;
smg2 = dat%100/10;
smg3 = dat%10;
smg4 = smg5 = smg6 = smg7 = 0;
smg8 = 17;
}
}
sys.c
#include "sys.h"
extern bit MEA_SONIC_FLAG;
/**
*@brief 外设初始化
*@param[in] none
*@return none
**/
void ALL_Init()
{
P2 = (P2&0x1f)|0xa0; //打开Y5C
P0 = 0x00; //关闭蜂鸣器&继电器
P2 = (P2&0x1f)|0xe0; //打开Y7C
P0 = 0xff; //关闭数码管
P2 = (P2&0x1f)|0x80; //打开Y4C
P0 = 0xff; //关闭LED
P2 = P2&0x1f; //关闭所用使能
}
/**
*@brief 延时函数
*@param[in] 延时多少ms(0~65535)
*@return none
**/
void Operate_Delay(u16 ms)
{
u16 i;
for(ms;ms>0;ms--)
for(i=921;i>0;i--);
}
/**
*@brief 74HC138译码器通道选择
*@param[in] channel (通道)
*@return none
**/
void HC138_Set(u8 channel)
{
switch(channel)
{
case 0: P2 = P2 & 0x1f; break; //关闭所有通道
case 4: P2 = (P2&0x1f)|0x80; break; //选择Y4对应的模块 (LED), 运算结果为P2高三位 100
case 5: P2 = (P2&0x1f)|0xa0; break; //选择Y5对应的模块 (蜂鸣器), 运算结果为P2高三位 101
case 6: P2 = (P2&0x1f)|0xc0; break; //选择Y6对应的模块 (数码管位选), 运算结果为P2高三位 110
case 7: P2 = (P2&0x1f)|0xe0; break; //选择Y7对应的模块 (数码管段选), 运算结果为P2高三位 111
}
}
void Timer0Init(void) //1毫秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xCD; //设置定时初值
TH0 = 0xD4; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1;
EA = 1;
}
void Timer1Init(void) //0微秒@11.0592MHz
{
AUXR &= 0xBF; //定时器时钟12T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0; //设置定时初值
TH1 = 0; //设置定时初值
TF1 = 0; //清除TF1标志
TR1 = 0;
}
void Timer0() interrupt 1
{
static unsigned char i;
i++;
if(i == 125)
{
i = 0;
MEA_SONIC_FLAG = 1;
}
Nixie_Show();
Nixie_Scan();
}