sweet11 发表于 2011-5-4 19:38:47

基于STC89C51的超声波模块测距出现问题,请求帮助,急急!

本人刚刚接触单片机,不得不从基础学起,由于要完成一个任务,小车避障,所以我就买了一个超声波模块直接用来测距
测距原理:
超声波模块工作原理:

(1)采用IO触发测距,给至少10us的高电平信号;

(2)模块自动发送8个40khz的方波,自动检测是否有信号返回;

(3)有信号返回,通过IO输出一高电平,高电平持续的时间就是超声波从发射到返回的时间. 测试距离=(高电平时间*声速(340M/S))/2;


然后我就用单片机的P1.3与模块的发射端Trig相连,P3.3作为外部中断1检测回波信号下降沿产生中断测距,P3.3与Echo相连。测距后由四位一体的数码管显示并将测得距离(用厘米表示)发送给PC机。
本来一切进行的很顺利,但是出现了一个问题,想了几天还是不知道怎么回事,希望大家帮忙解决一下,我将不胜感激。
当测距距离显示65cm后,大于65后数码管就重新从0开始显示,比如实际距离为80CM时,它就显示15CM,不知道问题所在。急死我了。。。

单片机晶振11.0592Mhz。

程序代码:
#include <reg51.h>
#include <intrins.h>
#include <math.h>
#define LED P0
#define        uint unsigned int
#define        uchar unsigned char
//#define v 340
sbit No1 = P1^4;//动态显示控制位
sbit No2 = P1^5;       
sbit No3 = P1^6;       
sbit No4 = P1^7;
sbit trig=P1^3;//超声波发射端
sbit echo=P3^3;   //超声波接收端       

/*********宏定义,定义数码管显示第几位***********/
#define         DIS_NO1         No1=0; No2=1; No3=1; No4=1       
#define         DIS_NO2         No1=1; No2=0; No3=1; No4=1                      
#define         DIS_NO3         No1=1; No2=1; No3=0; No4=1       
#define         DIS_NO4         No1=1; No2=1; No3=1; No4=0

uint t,distance;
uchar i,j,flag;


void delay(uint time);
void display(uint num);
void initial(void);
void send_signal(void);
void send(uint m);

code uchar table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0xbf,0x7f,0xff};

/************************************************************************************/
/*TRIG端口发一个10US高电平,当TRIG变成0时,超声波模块开始发射超声波,主控制 */
/*板就可以在ECHO等待0输出.从TRIG=1到ECHO=0的时间就为此次测距的时间,可算出距离        */
/************************************************************************************/

void main(void)
{
delay(50);   //去抖动
initial();          //初始化
trig=0;
delay(50);
while(1)
{
send_signal();

while(!flag);       //等待外部中断或定时器0溢出中断
if(flag==1)                        //外部中断,测距
{
display(distance);           //显示距离
send(distance);                   //发送数据给PC机
//send(0);

}
else                                   //定时器0溢出中断
{
display(0);
send(0);
//send(1);
}
delay(10);                           //延时
TL0=0x00;                           //定时器0重新设置值
TH0=0x00;
flag=0;                                   //测试标志位置0
}
}


//*延时程序
void delay(uint time)
{
   while(time--);
}

//初始化
void initial(void)
{
    TMOD = 0x21;   //定时器1工作方式2,定时器0工作方式1
        SCON = 0x50;       // uart 模式1 (8 bit), REN=1;
        TL1 = 0xfd;      //波特率9600                                    
        TH1 = 0xfd;      
        TL0 = 0x00;      //初始值;                                    
        TH0 = 0x00;   
        TR1=1;   
        EA=1;
}
/**************************************************************/
/*产生超声波并计时等待中断*************************************/
/**************************************************************/
void send_signal(void)
{
trig=1;
for(i=0;i<10;i++) _nop_();
trig=0;
for(j=0;j<65;j++) _nop_();        //避免发射波对回波产生干扰,延时
TR0=1;                                  //启动定时器1计时
ET0=1;                                  //定时器1允许中断
EA=1;                                  //开总中断
EX1=1;                                  //外部中断1开中断
IT1=1;                                  //下降沿触发
}

/************************************************************/
/********定时器0溢出中断*************************************/
/**************************************************************/
void timer0(void) interrupt 1
{
TR0=0;
EX1=0;
ET0=0;
flag=2;
}

/**************************************************************/
/*******外部中断1中断测距**************************************/
void test(void) interrupt 2
{
TR0=0;                       //停止计数
ET0=0;                        //关定时器0中断
EX1=0;                        //关外部中断
EA=0;                  //关总中断
flag=1;                   //测距成功标志
t=TH0;                        //读取测试时间
t<<=8;
t+=TL0;
distance=17*t/1000;          //声速340m/s,结果用cm表示
}

/**************************************************************/
/*************************显示***********************************/
/**************************************************************/
void display(uint num)
{
       
//        DIS_NO1;         //选中第一只灯
//        LED=table;    //指针指向下一位数据
//        delay(50);                               


        DIS_NO2;          //选中第二只灯
        LED=table;
        delay(100);                                       


        DIS_NO3;       //选中第三只灯       
        LED=table[(num%100)/10];
        delay(100);                       

           DIS_NO4;                 //选中第四只灯
        LED=table;
        delay(100);                               
}


/**************************************************************/
/***********************单片机向PC机发送数据*******************/
/**************************************************************/
void send(uint m)
{
SBUF=m;
while(TI==0);
TI=0;
}

yuan2000 发表于 2011-5-5 14:29:19

下载下来看看.

sweet11 发表于 2011-5-6 13:01:51

回复【1楼】yuan2000
-----------------------------------------------------------------------
希望你发现问题了,可以告诉我一下,谢谢了。

sweet11 发表于 2011-5-9 15:22:34

问题解决了,将uint t,distance;改为unsigned long t,distance;即可,其他的就再优化一下。

继续改进。。。

me18923 发表于 2011-5-9 18:32:18

加油,成功了一起分享

sweet11 发表于 2011-5-9 21:34:29

#include <reg51.h>
#include <intrins.h>
#include <math.h>
#define LED P0
#define        uint unsigned int
#define        ulong unsigned long
#define        uchar unsigned char
sbit No1 = P1^4;
sbit No2 = P1^5;       
sbit No3 = P1^6;       
sbit No4 = P1^7;
sbit trig=P1^3;
sbit echo=P3^3;       

/*********宏定义,定义数码管显示第几位***********/
#define         DIS_NO1         No1=0; No2=1; No3=1; No4=1       
#define         DIS_NO2         No1=1; No2=0; No3=1; No4=1                      
#define         DIS_NO3         No1=1; No2=1; No3=0; No4=1       
#define         DIS_NO4         No1=1; No2=1; No3=1; No4=0
ulong t;
float distance;//很重要,防止溢出,距离计算出错
uchar i,j,flag;
const uint v=340;

void delay(uint time);
void display(uint num);
void initial(void);
void send_signal(void);
void send(float m);

code uchar table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0xbf,0x7f,0xff};

/************************************************************************************/
/*TRIG端口发一个10US高电平,当TRIG变成0时,超声波模块开始发射超声波,主控制 */
/*板就可以在ECHO等待0输出.从TRIG=1到ECHO=0的时间就为此次测距的时间,可算出距离        */
/************************************************************************************/

void main(void)
{
delay(50);   //去抖动
initial();          //初始化
trig=0;
delay(50);
while(1)
{
send_signal();

while(!flag);       //等待外部中断或定时器0溢出中断
if(flag==1)                        //外部中断,测距
{
display(distance);           //显示距离
send(distance);
//if(distance<=1000&&distance>=400)       send(0);
//else send(1);                   //发送指令给PC机
}
else                                   //定时器0溢出中断
{
display(0);
send(0);

}
TL0=0x00;                           //定时器0重新设置值
TH0=0x00;
delay(50);                           //延时
flag=0;                                   //测试标志位置0
}
}


//*延时程序
void delay(uint time)
{
   while(time--)
{_nop_();}
}

//初始化
void initial(void)
{
    TMOD = 0x21;   //定时器1工作方式2,定时器0工作方式1
        SCON = 0x50;       // uart 模式1 (8 bit), REN=1;
        TL1 = 0xfd;      //波特率9600                                    
        TH1 = 0xfd;      
        TL0 = 0x00;      //初始值;                                    
        TH0 = 0x00;   
        TR1=1;   
        EA=1;
}
/**************************************************************/
/*产生超声波并计时等待中断*************************************/
/**************************************************************/
void send_signal(void)
{
trig=1;
//for(i=0;i<10;i++) _nop_();
delay(10);
trig=0;
while(echo==0); //等待Echo回波引脚变高电平
//for(j=0;j<50;j++) _nop_();        //避免发射波对回波产生干扰,延时
delay(30);
flag=0;               //清测量成功标志
TR0=1;                                  //启动定时器0计时
ET0=1;                                  //定时器0允许中断
EA=1;                                  //开总中断
EX1=1;                                  //外部中断1开中断
IT1=1;                                  //下降沿触发
}

/************************************************************/
/********定时器0溢出中断*************************************/
/**************************************************************/
void timer0(void) interrupt 1
{
TR0=0;
EX1=0;
ET0=0;
flag=2;
}

/**************************************************************/
/*******外部中断1中断测距**************************************/
void test(void) interrupt 2
{
delay(50);        //不能太长时间,有可能是2次中断
if(echo==0)
{
TR0=0;                       //停止计数
ET0=0;                        //关定时器0中断
EX1=0;                        //关外部中断
EA=0;                  //关总中断
flag=1;                   //测距成功标志
t=TH0;                        //读取测试时间
t<<=8;
t+=TL0;
distance=v*t/2000.0;          //声速340m/s,结果用mm表示
}
}

/**************************************************************/
/*************************显示***********************************/
/**************************************************************/
void display(uint num)
{
       
        DIS_NO1;         //选中第一只灯
        LED=table;    //指针指向下一位数据
        delay(50);                               


        DIS_NO2;          //选中第二只灯
        LED=table;
        delay(50);                                       


        DIS_NO3;       //选中第三只灯       
        LED=table[(num%100)/10];
        delay(50);                       

           DIS_NO4;                 //选中第四只灯
        LED=table;
        delay(50);                               
}


/**************************************************************/
/***********************单片机向PC机发送数据*******************/
/**************************************************************/
void send(float m)
{
uchar *pf=(uchar*)&m;
uchar array;
for(i=4;i>0;i--)
{
array=pf;
}
for(j=4;j>0;j--)
{
SBUF=array;
while(TI==0);
TI=0;
}
}

   在师兄的帮助下终于将一些不易发觉的错误挖掘出来了,自己总是犯一些低级的错误,希望能够好好的改掉坏毛病。纠结了这么多天的问题今天全部解决了,虽然还有很多问题还要考虑,但是这次的体会很多,也借此勉励自己继续加油!


   这个程序已经可以实现将测得的浮点型数据发送给PC机了,不足的是精度不是很高,随着测距的增大误差也会增大,所以接下来要考虑温度补偿。
      ↖(^ω^)↗

wkman 发表于 2011-5-10 18:18:07

↖(^ω^)↗

论坛有类似 超声波避障小车 代码的
页: [1]
查看完整版本: 基于STC89C51的超声波模块测距出现问题,请求帮助,急急!