目录
一.简介
在蓝桥杯“单片机设计与开发”比赛中,超声波测距是一直以来都是国赛中重要的考点,几乎每届必考。虽然省赛还没有考过,但也不能排除以后不考,它和其他的外设模块不同,没有底层驱动代码提供,得自己来写实现代码
在蓝桥杯单片机的竞赛综合平台CT107D中,超声波模块的TX引脚接到单片机的P1.0端口,RX引脚接到单片机的P1.1端口。设计程序,进行超声波测距,最大测量范围约140cm
基本原理:想必大家在高中物理做过超声波测距的题
超声波发射模块向某一方向发射超声波,在发射时刻的同时开始计时,超声波在空气中传播,途中碰到障碍物就立即返回来,超声波接收器收到反射波就立即停止计时
二、超声波实现
1.计算公式
距离=声速*总时间/2
最大测量范围约140cm
2.实现原理
1.产生8个或10个频率为40KHZ,占空比为50%的方波信号,通过TX引脚发送出去(1/40 000 = 25us,25/2=12.5us,所以TX电平翻转时间为12us即可)
2.启动定时器,直到RX引脚接收到方波信号或者计时器计数溢出后关闭定时器
3.判断导致定时器停止的原因
若是因为定时器溢出而导致的停止计数,就说明超出了测量距离,可以就按变量最大的值255(我们定义的是u8),也可以通过其他方式表示
若是因为RX=0(接收到方波时RX=0)而停止的,就进行距离测量
dis = v*t/2,v=340m/s = 34000cm/s = 0.034cm/us
t 的单位是us,所以dis = t*v/2 = t*0.0174.测量完一次就清零计数值
代码实现:
sbit TX = P1^0;
sbit RX = P1^1;
void Delay12us() //@11.0592MHz
{
unsigned char i;
_nop_();
_nop_();
_nop_();
i = 30;
while (--i);
}
u8 Sonic_Measure()
{
u8 i,dis;
for(i=0;i<10;i++)//产生8个或10个方波信号
{
TX = 1;
Delay12us();
TX = 0;
Delay12us();
}
TR0 = 1;//开启定时器
while(RX == 1 && TF0 == 0);//接收到时RX = 0
TR0 = 0;//关闭定时器
if(TF0 == 1)//定时器溢出
{
TF0 = 0;
dis = 255;
}
else //定时器未溢出,就收到了
{
dis = (TH0*256+TL0)*0.017;
}
TH0 = 0;
TL0 = 0;
return dis;
}
上面的延时是用Delay实现的,难免有些误差,我们也可以直接使用定时器进行计时
void Sonic_Timer1Init(void) //12微秒@11.0592MHz,16位
{
AUXR &= 0xBF; //定时器时钟12T模式----->每过1us计数器+1
TMOD &= 0x0F; //设置定时器模式
TMOD |= 0x10; //设置定时器模式
TL1 = 0xF5; //设置定时初值
TH1 = 0xFF; //设置定时初值
TF1 = 0; //清除TF1标志
TR1 = 0; //定时器1停止计时
}
u8 Sonic_Measure()
{
u8 i,dis;
Sonic_Timer1Init();
TX = 0; //先拉低,其实先拉高也行
for(i=0;i<10;i++) //产生40KHZ的方波信号,1/40KHZ = 0.025s = 25us
{ //所以要产生占空比为50%的就是12.5us翻转一次
TR1 = 1; //要发送十个
while(!TF1); //计数器溢出 TF0 = 1,退出循环,溢出时是12us
TF1 = 0;
TX ^= 1; //TX翻转一次,TX = 0,TX ^1 = 1, TX = 1,TX ^ 1 = 0;
Sonic_Timer1Init();//初始化,重装定时器值为12us
}
//开始测距
TF1 = 0; //清除TF1标志
TR1 = 0; //定时器1停止计时
TL1 = 0; //设置定时初值
TH1 = 0; //设置定时初值
TR1 = 1; //定时器开始计时
while(RX && !TF1);//当接收到返回的超声波时RX = 0,退出循环,当定时器计数溢出TF1 = 1时退出循环
TR1 = 0;//暂停计时
if(TF1)//若定时器溢出了,即超声波还没有返回到接收头,那就给最大距离255
{
TF1 = 0;
dis = 255;
}
else//接收到了,定时器未溢出,就计算距离
{
dis = (TH1*256+TL1)*0.017;//TH1为高八位,则真实际数值为TH1<<8即TH1*256
//dis = v*t/2,v=340m/s = 34000cm/s = 0.034cm/us
//t 的单位是us,所以dis = t*v/2 = t*0.017
}
//因为每次执行此函数,开头都有初始化定时器,所以这里不用再为下一次测距做准备了
return dis;
}
三、实际使用
#include <STC15F2K60S2.H>
#include "intrins.h"
#include "csb.h"
#include "seg.h"
#define wan(x) x/10000
#define qian(x) x/1000%10
#define bai(x) x/100%10
#define shi(x) x/10%10
#define ge(x) x%10
u8 csb_mea;
void main()
{
All_Init();
Timer0Init();
Sonic_Init();
while(1)
{
if(csb_f)
{
csb_f=0;
csb_mea = Sonic_Mea();
if(csb_mea<10)
seg_set(21,16,16,16,16,16,16,ge(csb_mea));
else if(csb_mea<100)
seg_set(21,16,16,16,16,16,shi(csb_mea),ge(csb_mea));
else
seg_set(21,16,16,16,16,bai(csb_mea),shi(csb_mea),ge(csb_mea));
}
}
}
void Timer0_ISR() interrupt 1
{
seg_loop();
count++;
if(count % 300 == 0)csb_f = 1;
count%=1000;
}