前言
上一节我们已经研究了超声波接收模块并自己设计了一个超声波接收模块,在此基础上又尝试用单片机加反相器构成生成40KHz的超声波发射电路,可是发现采用这种设计的发射电路存在严重的发射功率太低问题,对齐的情况下最多只有10CM。本节主要介绍并制造一种大功率超声波发射装置~
目录
一、浪里淘金,寻找最简超声波功率提高方案
1.1、优化波形发生程序
1.2、尝试各种其他超声模块方案
1.3、用三极管放大信号
1.4、MAX232放大信号方案
二、步步为营,打造高效准确超声测距算法
2.1、接收MCU区分接收头信号并统计时差算法初试
2.2、折衷——单MCU上集成收发模块实现测距
2.3、命中注定——分手的时候到了
三、阶段小结
四、相关链接
一、浪里淘金,寻找最简超声波功率提高方案
1.1、优化波形发生程序
>_<" 上节讲到的利用反相器加单片机生成40KHz的超声波发射装置存在严重的功率问题,然后在上次之后的研究中我发现通过调节定时器的定时,功率会有稍微的提高,但还是比较弱~(因为条件限制,根本买不起示波器这种神器,所有只有酷比的调试代码啦!)下面的代码即改进后的51单片机代码,这次定时器采用的是定时器2,16位重装模式~
/*-----------------------------------------------
名称:定时器2
------------------------------------------------*/
#include<reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义 sbit P10=P1^;
sbit P11=P1^;
/*------------------------------------------------
定时器初始化子程序
------------------------------------------------*/
void TIM2Inital(void)
{
RCAP2H = (-)/;//晶振11.0592M 12us 16bit 自动重载(最好是用12M但是要实现时间同步,那边需要串口,所以这里就勉强采用11.0952)
RCAP2L = (-)%;
ET2=; //打开定时器中断
EA=; //打开总中断
TR2=; //打开定时器开关
}
/*------------------------------------------------
主程序
------------------------------------------------*/
main()
{
P10=;
P11=;
TIM2Inital();
while(){}
}
/*------------------------------------------------
定时器中断子程序
------------------------------------------------*/
void TIM2(void) interrupt using //定时器2中断
{
TF2=;
P10=~P10;
P11=~P11;
}
1.2、尝试各种其他超声模块方案
>_<" 发现上面的方法不能大幅度改变发射功率,于是还是继续网上找资料,于是看上一节最后留下的第二个链接中的文章,找个简单的实验了下。结果在protues中仿真发现怎么也不是想要的效果,另一方面考虑到要提供9V的电压,于是就放弃了在面包板上连接实物实验。然后又在protues里实验了用555做超声波发送模块的方案,结果不知道为什么,protues里似乎不能给555加9V电压(一直报错)。最后大致浏览下这个文档中的方案,发现基本上都需要9V电压,而且模电较多(我这里电子元件不是太多,最坑的是没有示波器!)
1.3、用三极管放大信号
>_<" 一个偶然的发现某同学的毕业设计中的方案:他介绍在脉冲发生电路和脉冲发射电路中加一个三极管来放大信号,觉得这个简单易行,我在面包板上简单的用一个2N3904三极管,照着模拟电路书本上简单放大电路连接好,将上述产生40KHz的单片机脉冲发生电路的引脚和三极管的基极相连,集电极加载一个12V的电压,测试结果发现可以很有效地提高发射功率,但是只成功了一小会,然后再怎么实验都无法再收到超声波了(我怀疑是把三极管弄坏了),所以该方案又失败了~
1.4、MAX232放大信号方案
>_<" 通过上面的各种尝试,我发现上面发射部分设计方案有一个共同的特点:都需要较高的驱动电压。但是我购买的HC-SR04超过声波测距模块却只需要用5V就能发射功率很强的成声波,这点引起了我的思考。于是直接找来HC-SR04的设计图:
通过研究发现:其发射部分采用STC系列单片机作为40KHz的脉冲发生器,然后把13、14两路(他一定是让这两路提供反向电平作为输出)链接到 MAX232的两个输入端!一看到MAX232瞬间就明白了:MAX232是经常用在串口通信中用于将串口信号放大来传播更远距离的芯片,他这里采用 MAX232这个特点用于将信号放大,然后在输出端直接驱动发射头!非常机智!于是我利用手头上的串口转TTL模块做一个简单的实验,结果令人振奋,果然能够对信号进行很强的放大:
于是一鼓作气,重新设计一个信号更强劲的方案,并把电路焊接成发射模块:这次采用MAX232的2个输入和输出通道,将两个方波同时放大,将产生更加强劲的效果!
二、步步为营,打造高效准确超声测距算法
>_<" 到上面为止我们已经完美地把超声波发射与接收模块都做好了,那么现在就要研究下如何利用他们进行测距了~(PS:嘻嘻这里俺可不是简单的用一个发送模块一个接收模块进行直线空间上的测距,这种东西早都比较成熟了,网上一搜一把,而且非常便宜!我要做的是利用2个接收模块及一个接收模块在二维平面上对物体进行定位!)
2.1、接收MCU区分接收头信号并统计时差算法初试
>_<" 还记得我们上节用到的最最简单的信号检测算法吗?该程序是放到接收部分MCU中运行的,因为超声波接收部分一旦接收到超声波就会产生一个1-0-1信号,所以我们上一节只是简单的将接收模块输出链接到单片机的一个引脚,在单片机程序中对该引脚电平进行轮询输出。但是这里我们用了2个接收头,如果处理不当,会很难分辨是哪一个接收头产生的信号,如果采用顺序输出又不满足两个信号到达的先后顺序不同且会变的事实,综上,这里先初步用一个ok作为标记:为0表示没收到一个信号;为1表示只收到1好接收模块的信号;为2表示只收到2号接收模块的信号;为3表示两个都收到了,具体如下:[图中连续ab之间的+号的个数表示两个信号之间的时间差]
/*-------------------------------------------
简单的串口通信{接收}
-------------------------------------------*/
#include<reg51.h> #define uint unsigned int
#define uchar unsigned char sbit IN1 = P1^;
sbit IN2 = P1^;
/*--------------------------------------------
USAR初始函数
---------------------------------------------*/
void USRT_init()
{
TMOD=0x20; //设置T1定时器工作方式2
TH1=0xfd; //T1定时器装初值
TL1=0xfd;
TR1=; //启动T1定时器
SM0=; //设定串口工作方式
SM1=;
EA=; //开总中断
}
/*--------------------------------------------
主函数
---------------------------------------------*/
void main()
{
int i=,ok=;
USRT_init();
while()
{
SBUF='+';
if(IN1== && ok!= && ok!=){
SBUF='a';
if(ok==)ok=;
else ok=;
}
if(IN2== && ok!= && ok!=){
SBUF='b';
if(ok==)ok=;
else ok=;
}
if(ok==){
i++;
if(i==){
ok=;
i=;
}
}
while(!TI); //每次等待发送完毕,再执行下一条
TI=; //手动清0
}
}
code
2.2、折衷——单MCU上集成收发模块实现测距
>_<" 为了体现咱们是步步为营的,所以俺刚开始并没有直接去挑战发送和接收模块分开或者直接两个接收模块去测距,而是先尝试一下在一个MCU上连接一个发射模块和一个接收模块,自制一个简单的超声波测距仪(市场上卖的那种直线型的)。这个程序不难理解,但是麻雀虽小,五脏俱全,这里用到了51单片机的几乎所有中断:1)负责接收模块监听的外部中断2)负责计时的T0计数器3)负责串口的T1定时器4)负责产生方波的T2定时器~然后测距的思路很简单:首先发送模块在短时间内发送100周期的40KHz超声波,然后计时器开始计数,等到接收模块输出引脚产生1-0-1下降沿触发外部中断时停止计数,然后根据转换公式将超声波传播计数转换为距离并把数据通过串口发送给上位机。
/*-----------------------------------------------
名称:定时器2
------------------------------------------------*/
#include<reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#include<intrins.h> sbit P10=P1^;
sbit P11=P1^; unsigned char times;//一次发射方波数
char bwei,shwei,gwei;//数据 /*------------------------------------------------
定时器初始化子程序[定时器2,16位自动装值,用于产生40KHz方波]
------------------------------------------------*/
void TIM2Inital(void)
{
RCAP2H = (-)/;//晶振11.0592M 12us 16bit 自动重载(最好是用12M但是要实现时间同步,那边需要串口,所以这里就勉强采用11.0952)
RCAP2L = (-)%;
ET2=; //打开定时器中断
EA=; //打开总中断
TR2=; //打开定时器开关
}
/*--------------------------------------------
USAR初始函数及发送一个字符
---------------------------------------------*/
void USRT_init()
{
TMOD|=0x20; //设置T1定时器工作方式2
TH1=0xfd; //T1定时器装初值
TL1=0xfd;
TR1=; //启动T1定时器
SM0=; //设定串口工作方式
SM1=;
EA=; //开总中断
}
void send(char a)
{
SBUF=a;
while(!TI); //每次等待发送完毕,再执行下一条
TI=; //手动清0
}
/*------------------------------------------------
定时器初始化子程序[用于计算超声波发送到收到的时间间隔]
外部中断P32用于接收超声波接收低电平
------------------------------------------------*/
void InterruptInit(void)
{
TMOD|=0x01;//T0计数,方式1
TH0=;//计数初值
TL0=;
IT0=;//INT0负脉冲触发
EA=;//开总中断
EX0=;//开外部中断INT0
}
/*------------------------------------------------
主程序
------------------------------------------------*/
main()
{
USRT_init();//初始化串口
InterruptInit();//初始化
while()
{
P10=P11=;
TR0=;//T0开始计数
times=;
TIM2Inital();
while(times<);
ET2=;//关闭定时器中断
}
}
/*------------------------------------------------
INTO中断服务程序
------------------------------------------------*/
void intersvro(void) interrupt using
{
unsigned long COUNT;
unsigned long num;
TR0=; //停止计数
COUNT=TH0*+TL0;
num=(*COUNT)/;
if(num==)goto A;
bwei=(char)(''+num%/);//取百位
shwei=(char)(''+num%/);//取十位
gwei=(char)(''+num%);//取个位
send(bwei);
send(shwei);
send(gwei);
send(0x0d);
send(0x0a);
A: TH0=;
TL0=;
times=;
}
/*------------------------------------------------
定时器中断子程序
------------------------------------------------*/
void TIM2(void) interrupt using //定时器2中断
{
TF2=;
P10=~P10;
P11=~P11;
times++;
}
上面的代码将数据发送给上位机的过程放大中断中去处理不是太好,于是就将串口数据发送改到main函数中了,优化后的代码如下:
/*-----------------------------------------------
名称:定时器2
------------------------------------------------*/
#include<reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#include<intrins.h> sbit P10=P1^;
sbit P11=P1^; unsigned char times,flag;//一次发射方波数
char bwei,shwei,gwei;//数据
unsigned long num1,num2; /*------------------------------------------------
定时器初始化子程序[定时器2,16位自动装值,用于产生40KHz方波]
------------------------------------------------*/
void TIM2Inital(void)
{
RCAP2H = (-)/;//晶振11.0592M 12us 16bit 自动重载(最好是用12M但是要实现时间同步,那边需要串口,所以这里就勉强采用11.0952)
RCAP2L = (-)%;
ET2=; //打开定时器中断
EA=; //打开总中断
TR2=; //打开定时器开关
}
/*--------------------------------------------
USAR初始函数及发送一个字符
---------------------------------------------*/
void USRT_init()
{
TMOD|=0x20; //设置T1定时器工作方式2
TH1=0xfd; //T1定时器装初值
TL1=0xfd;
TR1=; //启动T1定时器
SM0=; //设定串口工作方式
SM1=;
EA=; //开总中断
}
void send(char a)
{
SBUF=a;
while(!TI); //每次等待发送完毕,再执行下一条
TI=; //手动清0
}
/*------------------------------------------------
定时器初始化子程序[用于计算超声波发送到收到的时间间隔]
外部中断P32用于接收超声波接收低电平
------------------------------------------------*/
void InterruptInit(void)
{
TMOD|=0x01;//T0计数,方式1
TH0=;//计数初值
TL0=;
IT0=;//INT0负脉冲触发
EA=;//开总中断
EX0=;//开外部中断INT0
}
/*------------------------------------------------
主程序
------------------------------------------------*/
main()
{
USRT_init();//初始化串口
InterruptInit();//初始化
while()
{
P10=P11=;
flag=;
TR0=;//T0开始计数
times=;
TIM2Inital();
while(times<);
ET2=;//关闭定时器中断
if(flag){
bwei=(char)(''+num1%/);//取百位
shwei=(char)(''+num1%/);//取十位
gwei=(char)(''+num1%);//取个位
send(bwei);
send(shwei);
send(gwei);
send(0x0d);
send(0x0a);
}
EX0=;
}
}
/*------------------------------------------------
INTO中断服务程序
------------------------------------------------*/
void intersvro(void) interrupt using
{
unsigned long COUNT;
TR0=; //停止计数
COUNT=TH0*+TL0;
num1=(*COUNT)/;
if(num1==)return;
flag=;
TH0=;
TL0=;
times=;
EX0=;
}
/*------------------------------------------------
定时器中断子程序
------------------------------------------------*/
void TIM2(void) interrupt using //定时器2中断
{
TF2=;
P10=~P10;
P11=~P11;
times++;
}
但是仅仅有一个接收模块肯定不是我们的最终目标,于是再向前迈一步,这次加入一个接收模块,于是把单片机剩下的那个外部中断也给用上了,程序大致和上面的很像~但是这里出现个问题:因为定时器就一个,如果用这一个定时器去计算两个接收模块接收时间的话,看似可以(你可能会想到用一个秒表给多人计时),但是超声波不是人!一方面,当其中一个接收模块触发中断时并进行相应的处理会影响计时器;另一方面,如果强制想实现这个计时过程要添加很多标志和判断处理,这样很不明智!下面是初步尝试时的程序,他只能测出首先接受到超声波信号的接收头的数据,另一个会被自动放弃掉~
/*-----------------------------------------------
名称:定时器2
------------------------------------------------*/
#include<reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#include<intrins.h> sbit P10=P1^;
sbit P11=P1^; unsigned char times,flag;//一次发射方波数
char bwei,shwei,gwei;//数据
unsigned long num1,num2; /*------------------------------------------------
定时器初始化子程序[定时器2,16位自动装值,用于产生40KHz方波]
------------------------------------------------*/
void TIM2Inital(void)
{
RCAP2H = (-)/;//晶振11.0592M 12us 16bit 自动重载(最好是用12M但是要实现时间同步,那边需要串口,所以这里就勉强采用11.0952)
RCAP2L = (-)%;
ET2=; //打开定时器中断
EA=; //打开总中断
TR2=; //打开定时器开关
}
/*--------------------------------------------
USAR初始函数及发送一个字符
---------------------------------------------*/
void USRT_init()
{
TMOD|=0x20; //设置T1定时器工作方式2
TH1=0xfd; //T1定时器装初值
TL1=0xfd;
TR1=; //启动T1定时器
SM0=; //设定串口工作方式
SM1=;
EA=; //开总中断
}
void send(char a)
{
SBUF=a;
while(!TI); //每次等待发送完毕,再执行下一条
TI=; //手动清0
}
/*------------------------------------------------
定时器初始化子程序[用于计算超声波发送到收到的时间间隔]
外部中断P32用于接收超声波接收低电平
------------------------------------------------*/
void InterruptInit(void)
{
TMOD|=0x01;//T0计数,方式1
TH0=;//计数初值
TL0=;
IT0=;//INT0负脉冲触发
IT1=;
EA=;//开总中断
EX0=;//开外部中断INT0
EX1=;
}
/*------------------------------------------------
主程序
------------------------------------------------*/
main()
{
USRT_init();//初始化串口
InterruptInit();//初始化
while()
{
P10=P11=;
flag=;
TR0=;//T0开始计数
times=;
TIM2Inital();
while(times<);
ET2=;//关闭定时器中断
if(flag==){
num1-=;//发现所测结果比真实大5左右
bwei=(char)(''+num1%/);//取百位
shwei=(char)(''+num1%/);//取十位
gwei=(char)(''+num1%);//取个位
send('x');
send(':');
send(bwei);
send(shwei);
send(gwei);
send(0x0d);
send(0x0a);
}else if(flag==){
num2-=;//发现所测结果比真实大5左右
bwei=(char)(''+num2%/);//取百位
shwei=(char)(''+num2%/);//取十位
gwei=(char)(''+num2%);//取个位
send('y');
send(':');
send(bwei);
send(shwei);
send(gwei);
send(0x0d);
send(0x0a);
}
EX0=;
EX1=;
}
}
/*------------------------------------------------
INTO中断服务程序
------------------------------------------------*/
void intersvro0(void) interrupt
{
unsigned long COUNT;
TR0=; //停止计数
COUNT=TH0*+TL0;
num1=(*COUNT)/;
if(num1==)return;
flag=;
TH0=;
TL0=;
times=;
EX0=;
}
/*------------------------------------------------
INT1中断服务程序
------------------------------------------------*/
void intersvro1(void) interrupt
{
unsigned long COUNT;
TR0=; //停止计数
COUNT=TH0*+TL0;
num2=(*COUNT)/;
if(num2==)return;
flag=;
TH0=;
TL0=;
times=;
EX1=;
}
/*------------------------------------------------
定时器中断子程序
------------------------------------------------*/
void TIM2(void) interrupt using //定时器2中断
{
TF2=;
P10=~P10;
P11=~P11;
times++;
}
本来我以为那种掐表模式的多接收模块计时模型肯定能实现,于是浪费了很长时间,把代码改的很乱,最后还是不能完美的完成目标~就在我吃饭的路上突然受分时操作系统的影响产生了一个新的灵感:由于测量频率很快,我可以把一个测量周期分为两部分,一部分用于只用接收模块1进行测距,另一部分只用接收模块2进行测量,这样一个测量周期就能完美的测量出两个接收模块的测距数据!代码如下:
/*-----------------------------------------------
超声波接收一个接P32一个接P33中断INT0和INT1
------------------------------------------------*/
#include<reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#include<intrins.h> sbit P10=P1^;
sbit P11=P1^; unsigned char times,flag;//一次发射方波数
char bwei,shwei,gwei;//数据
unsigned long num1,num2; /*------------------------------------------------
定时器初始化子程序[定时器2,16位自动装值,用于产生40KHz方波]
------------------------------------------------*/
void TIM2Inital(void)
{
RCAP2H = (-)/;//晶振11.0592M 12us 16bit 自动重载(最好是用12M但是要实现时间同步,那边需要串口,所以这里就勉强采用11.0952)
RCAP2L = (-)%;
ET2=; //打开定时器中断
EA=; //打开总中断
TR2=; //打开定时器开关
}
/*--------------------------------------------
USAR初始函数及发送一个字符
---------------------------------------------*/
void USRT_init()
{
TMOD|=0x20; //设置T1定时器工作方式2
TH1=0xfd; //T1定时器装初值
TL1=0xfd;
TR1=; //启动T1定时器
SM0=; //设定串口工作方式
SM1=;
EA=; //开总中断
}
void send(char a)
{
SBUF=a;
while(!TI); //每次等待发送完毕,再执行下一条
TI=; //手动清0
}
/*------------------------------------------------
定时器初始化子程序[用于计算超声波发送到收到的时间间隔]
外部中断P32用于接收超声波接收低电平
------------------------------------------------*/
void InterruptInit(void)
{
TMOD|=0x01;//T0计数,方式1
TH0=;//计数初值
TL0=;
IT0=;//INT0负脉冲触发
IT1=;
EA=;//开总中断
// EX0=1;//开外部中断INT0
// EX1=1;
}
/*------------------------------------------------
主程序
------------------------------------------------*/
main()
{
bit ok=;
USRT_init();//初始化串口
InterruptInit();//初始化
while()
{
if(ok==){
EX0=; P10=P11=;
flag=;
TR0=;//T0开始计数
times=;
TIM2Inital();
while(times<);
ET2=;//关闭定时器中断 if(flag==){
num1-=;//发现所测结果比真实大5左右
bwei=(char)(''+num1%/);//取百位
shwei=(char)(''+num1%/);//取十位
gwei=(char)(''+num1%);//取个位
send('x');
send(':');
send(bwei);
send(shwei);
send(gwei);
send(0x0d);
send(0x0a);
ok=;
}
}else{
EX1=; P10=P11=;
flag=;
TR0=;//T0开始计数
times=;
TIM2Inital();
while(times<);
ET2=;//关闭定时器中断 if(flag==){
num2-=;//发现所测结果比真实大5左右
bwei=(char)(''+num2%/);//取百位
shwei=(char)(''+num2%/);//取十位
gwei=(char)(''+num2%);//取个位
send('y');
send(':');
send(bwei);
send(shwei);
send(gwei);
send(0x0d);
send(0x0a);
ok=;
}
}
}
}
/*------------------------------------------------
INTO中断服务程序
------------------------------------------------*/
void intersvro0(void) interrupt
{
unsigned long COUNT;
TR0=; //停止计数
COUNT=TH0*+TL0;
num1=(*COUNT)/;
if(num1==)return;
flag=;
TH0=;
TL0=;
times=;
EX0=;
}
/*------------------------------------------------
INT1中断服务程序
------------------------------------------------*/
void intersvro1(void) interrupt
{
unsigned long COUNT;
TR0=; //停止计数
COUNT=TH0*+TL0;
num2=(*COUNT)/;
if(num2==)return;
flag=;
TH0=;
TL0=;
times=;
EX1=;
}
/*------------------------------------------------
定时器中断子程序
------------------------------------------------*/
void TIM2(void) interrupt using //定时器2中断
{
TF2=;
P10=~P10;
P11=~P11;
times++;
}
2.3、命中注定——分手的时候到了
>_<" 上面我们已经实现了在一个MCU上实现了一个发射模块两个接收模块分别测距,但是将发射和接收放在同一个模块上是很不理想的一种折衷,那么现在是时候来一个高超的手术了!
>_<" 通过分析上面集成在一个MCU上的代码可以知道:发送部分仅占用40KHz发送函数用于适时的发送一段连续的超声波;接收部分负责计时、等待接收模块的1-0-1中断、计算距离、将数据发送给上位机等功能。其中有一个核心而隐蔽的问题,即:时间同步问题!当在一个MCU上时,我们只要简单的启动计时器同时启动超声波发送,而在两个MCU上实现这个并不是件容易的事!最终我想到了用一根线来同步时间,即:当接收模块准备好时,把该线上的电平置1-0产生下降沿(P20引脚),然后把该线的另一端连接将发送模块的外部中断0的引脚(P32引脚),采用中断方式监听起跑命令。当发送模块收到起跑命令时便发送一串超声波,同时接收模块开始计数,剩下的部分就和在同一个MCU上的原理很相似了~具体请参考代码(注意接收部分在发送起跑命令后的延时技巧!这是一种可以被中断剪短的延时,用来等待超声波接收模块接收有效的数据)
/*----------------------------------------------- ------------------------------------------------*/
#include<reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#include<intrins.h> sbit P10=P1^;
sbit P11=P1^; unsigned char times,flag;//一次发射方波数 /*------------------------------------------------
定时器初始化子程序[定时器2,16位自动装值,用于产生40KHz方波]
------------------------------------------------*/
void TIM2Inital(void)
{
RCAP2H = (-)/;//晶振11.0592M 12us 16bit 自动重载(最好是用12M但是要实现时间同步,那边需要串口,所以这里就勉强采用11.0952)
RCAP2L = (-)%;
ET2=; //打开定时器中断
EA=; //打开总中断
TR2=; //打开定时器开关
}
/*------------------------------------------------
用于接收接收端发送过来的发送超声波的命令
------------------------------------------------*/
void InterruptInit(void)
{
TMOD|=0x01;//T0计数,方式1
TH0=;//计数初值
TL0=;
IT0=;//INT0负脉冲触发
EA=;//开总中断
EX0=;//开外部中断INT0
}
/*------------------------------------------------
主程序
------------------------------------------------*/
main()
{
InterruptInit();//初始化
while()
{
flag=;
while(!flag);
EX0=;//关闭中断
times=;
TIM2Inital();
while(times<);
ET2=;//关闭定时器中断
EX0=;//开中断
}
}
/*------------------------------------------------
INTO中断服务程序
------------------------------------------------*/
void intersvro0(void) interrupt
{
flag=;
}
/*------------------------------------------------
定时器中断子程序
------------------------------------------------*/
void TIM2(void) interrupt using //定时器2中断
{
TF2=;
P10=~P10;
P11=~P11;
times++;
}
发送代码
/*-----------------------------------------------
超声波接收一个接P32一个接P33中断INT0和INT1
------------------------------------------------*/
#include<reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#include<intrins.h> sbit P20=P2^;//通知发送的发送超声波(由高电平变低电平)
unsigned char flag;
char bwei,shwei,gwei;//数据
unsigned long num1,num2,times; /*--------------------------------------------
延时函数
---------------------------------------------*/
void delays()
{
times=;
while(times<)times++;
} /*--------------------------------------------
USAR初始函数及发送一个字符
---------------------------------------------*/
void USRT_init()
{
TMOD|=0x20; //设置T1定时器工作方式2
TH1=0xfd; //T1定时器装初值
TL1=0xfd;
TR1=; //启动T1定时器
SM0=; //设定串口工作方式
SM1=;
EA=; //开总中断
}
void send(char a)
{
SBUF=a;
while(!TI); //每次等待发送完毕,再执行下一条
TI=; //手动清0
}
/*------------------------------------------------
定时器初始化子程序[用于计算超声波发送到收到的时间间隔]
外部中断P32用于接收超声波接收低电平
------------------------------------------------*/
void InterruptInit(void)
{
TMOD|=0x01;//T0计数,方式1
TH0=;//计数初值
TL0=;
IT0=;//INT0负脉冲触发
IT1=;
EA=;//开总中断
// EX0=1;//开外部中断INT0
// EX1=1;
}
/*------------------------------------------------
主程序
------------------------------------------------*/
main()
{
bit ok=;
USRT_init();//初始化串口
InterruptInit();//初始化
while()
{
P20=;
if(ok==){
EX0=;//开外部INT0中断
flag=;
P20=;//P20由高变低产生一个下降沿来触发发送模块进行发送超声波
TR0=;//T0开始计数
delays();
if(flag==){
num1-=;//发现所测结果比真实大5左右
bwei=(char)(''+num1%/);//取百位
shwei=(char)(''+num1%/);//取十位
gwei=(char)(''+num1%);//取个位
send('x');
send(':');
send(bwei);
send(shwei);
send(gwei);
send(0x0d);
send(0x0a);
ok=;
}
}else{
EX1=;//开外部中断INT1
flag=;
P20=;//P20由高变低产生一个下降沿来触发发送模块进行发送超声波
TR0=;//T0开始计数
delays();
if(flag==){
num2-=;//发现所测结果比真实大5左右
bwei=(char)(''+num2%/);//取百位
shwei=(char)(''+num2%/);//取十位
gwei=(char)(''+num2%);//取个位
send('y');
send(':');
send(bwei);
send(shwei);
send(gwei);
send(0x0d);
send(0x0a);
ok=;
}
}
}
}
/*------------------------------------------------
INTO中断服务程序
------------------------------------------------*/
void intersvro0(void) interrupt
{
unsigned long COUNT;
TR0=; //停止计数
COUNT=TH0*+TL0;
num1=(*COUNT)/;
if(num1==)return;
flag=;
TH0=;
TL0=;
times=;
EX0=;
}
/*------------------------------------------------
INT1中断服务程序
------------------------------------------------*/
void intersvro1(void) interrupt
{
unsigned long COUNT;
TR0=; //停止计数
COUNT=TH0*+TL0;
num2=(*COUNT)/;
if(num2==)return;
flag=;
TH0=;
TL0=;
times=;
EX1=;
}
接收代码
三、阶段小结
>_<" 经过这三个阶段,我们已经从分析需求->调研市场->研究资料->购买原料->动手实践->模数结合->软硬兼修->调试修改->优化....最终完成了我们的超声波测距的硬件模块(鼓掌)!然后下一阶段将进入PC上基于C#的测距客户端软件的开发,更多有趣小制作敬请关注~
相关链接
博主主页(希望在其他地方看到该文的朋友点击这里):http://www.cnblogs.com/zjutlitao/
[自娱自乐] 1、超声波测距模块DIY笔记(一)链接:http://www.cnblogs.com/zjutlitao/p/4014855.html
[自娱自乐] 2、超声波测距模块DIY笔记(二)链接:http://www.cnblogs.com/zjutlitao/p/4029937.html
超声波发射接收电路(1.2中提到的资料):文库连接 下载好的文档链接
用三极管放大信号的方案(1.3中提到的资料):http://wenku.baidu.com/view/1637c60676c66137ee0619c8.html
[自娱自乐] 3、超声波测距模块DIY笔记(三)的更多相关文章
-
[自娱自乐] 4、超声波测距模块DIY笔记(四)——终结篇&#183;基于C#上位机软件开发
前言 上一节我们已经基本上把超声波硬件的发射和接收模块全部做好了,接下来我们着手开发一个软硬结合的基于C#的平面定位软件! 目录 一.整体思路 二.效果提前展示 2-1.软件部分展示 2-2.硬件部分 ...
-
[自娱自乐] 2、超声波测距模块DIY笔记(二)
前言 上一节我们已经大致浏览下目前销售的超声波测距模块同时设计了自己的分析电路,这次由于我买的电子元件都到了,所以就动手实验了下!至写该笔记时已经设计出超声波接收模块和超声波发射模块,同时存在超声波发 ...
-
STM32—驱动HC-SR04超声波测距模块
文章目录 超声波测距原理 HC-SR04工作原理 STM32实现驱动 1.引脚的配置 2.时序控制 3.时间差测量 4.如何将距离测出来 超声波测距原理 利用HC-SR04超声波测距模块可以实现比较精 ...
-
loto示波器实践——超声波测距模块
我们这里用到的超声波测距模块,一般是用于arduino智能小车自动避障的.经常见到的应用是使用单片机或者stm32和这种模块结合进行开发的. 我们使用LOTO示波器可以更直观和快速的看到超声波测量距离 ...
-
张高兴的 Windows 10 IoT 开发笔记:HC-SR04 超声波测距模块
HC-SR04 采用 IO 触发测距.下面介绍一下其在 Windows 10 IoT Core 环境下的用法. 项目运行在 Raspberry Pi 2/3 上,使用 C# 进行编码. 1. 准备 H ...
-
基于STM32F103ZET6 HC_SR04超声波测距模块
这是最后的实验现象,改变不同的角度即可测得距离 板子 PZ6806L 超声波模块 HC_SR04 HC_SR04模块讲解 通过该超声波模块说明书,可明白供电需VCC 5V 还需GND ECHO(回 ...
-
树莓派 HC-SRO4超声波测距模块的使用
先上个图 这个模块的针脚跟之前玩的那三个有所区别,除了VCC和GND两个针脚,还多了两个Trig和Echo针脚,分别是输出和输入,Trig我接的是20针脚,Echo是21 该模块的工作原理为,先向TR ...
-
Arduino 控制超声波测距模块
一.实物图 二.例子代码 用到数字2 和3 引脚,还有两个就是vcc GND两个阴脚,用模块连线比较简单
-
KS103超声波测距模块
max232:电平转换芯片,将电脑的RS-232标准串口(高+12V,低-12V)转换为(高+5V,低0V). 电脑串口(RS -232) => 单片机串口(TTL串口) SIPEX SP323 ...
随机推荐
-
丙申年把真假美猴王*在容器中跑 ASP.NET Core 1.0
var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i= ...
-
转:Delphi各种Socket组件的模式和模型
Delphi的大多数书籍里面都没有提到delphi的各种socket通信组件的模式和模型,有的书只讲解了windows的socket模式和模型,并没有归纳各种组件采用的模型,所以我们的程序员并不知道如 ...
-
poj 1947 树形dp
思路:dp[i][j]表示,以i节点为根,删去j个节点最少要断几条边. 那么dp[u][j]=min(dp[u][j],dp[v][k]+dp[u][j-k]);//选取最优状态 dp[u][j]=m ...
-
ASP.NET中App_Code,App_Data等文件夹的作用
http://www.cnblogs.com/shiyu007/archive/2007/12/04/982264.html 1. Bin文件夹 Bin文件夹包含应用程序所需的,用于控件.组件或者需 ...
-
CDOJ 1251 谕神的密码 贪心
谕神的密码 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.uestc.edu.cn/#/problem/show/1251 Descr ...
-
(转载)php curl_init函数用法
(转载)http://blog.sina.com.cn/s/blog_640738130100tsig.html 使用PHP的cURL库可以简单和有效地去抓网页.你只需要运行一个脚本,然后分析一下你所 ...
-
Jedis Client的使用以及序列化
JedisPool pool = new JedisPool(poolConfig, IP, PORT, timeout); public String set(String key,String v ...
-
527D.Clique Problem
题解: 水题 两种做法: 1.我的 我们假设$xi>xj$ 那么拆开绝对值 $$xi-w[i]>x[j]+w[j]$$ 由于$w[i]>0$,所以$x[i]+w[i]>x[j] ...
-
WebService服务介绍与调用
一: WebService简介 WebService是一个平*立的,低耦合的,自包含的.基于可编程的web的应用程序,可使用开放的XML(标准通用标记语言的下的一个子集)标准来描述.发布.发现.协调 ...
-
Tomcat SSL配置及Tomcat CA证书安装
Tomcat既可以作为独立的Servlet容器,也可以作为其他HTTP服务器附加的Servlet容器.如果Tomcat在非独立模式下工作, 通常不必配置SSL,由它从属的HTTP服务器来实现和客户的S ...