基于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;
} 下载下来看看. 回复【1楼】yuan2000
-----------------------------------------------------------------------
希望你发现问题了,可以告诉我一下,谢谢了。 问题解决了,将uint t,distance;改为unsigned long t,distance;即可,其他的就再优化一下。
继续改进。。。 加油,成功了一起分享 #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机了,不足的是精度不是很高,随着测距的增大误差也会增大,所以接下来要考虑温度补偿。
↖(^ω^)↗ ↖(^ω^)↗
论坛有类似 超声波避障小车 代码的
页:
[1]