找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1202|回复: 6
收起左侧

超声波测距程序就是不能显示测出的距离,单片机程序没错误,求大佬们教我如何解决

[复制链接]
ID:1005855 发表于 2022-4-6 17:22 | 显示全部楼层 |阅读模式
程序没有错误
/*
计算公式
我们知道声速是340m/s
根据x=vt
因为超声波发送出去和回来是测量距离的两倍,所以假设距离是L
2L=344xt
t我们用定时器测出来
一般都是us
所以就是tx172x10的-6次方=L,L单位为cm
最终的出 L= t(us) * 0.0172(cm/us)
0.0172=1/58
所以 L= t(us)/58(cm)


对于51单片机,12mhz的周期时间为1us
所以11.059200mzh的计算公式为
L = 计数 x(12/11.0592) x (1/58)
= 计数 x 0.0187
= (计数 x 1.87)/100(cm)
*/
#include "reg52.h"                        
#include "lcd.h"
#include "intrins.h"
#include "delay.h"


typedef unsigned int u16;         
typedef unsigned char u8;
typedef unsigned long u32;


sbit Echo = P2^0;//回响信号输出
sbit Trig = P2^1;//触发信号输入


u8 di[]="Distance";//液晶显示:Distance(距离)
u8 code ASCII[13] = {'0','1','2','3','4','5','6','7','8','9','.','-','M'};
                                 
u16 time = 0;
u16 s = 0;
u8 disbuff[4] = {0,0,0,0,};//提供4个数据位
u16 i = 0;


//对使用到函数进行声明定义
void StartModule();
void Timer0Init(void);
void Conut(void);




/******************************************
* 函 数 名         : main
* 函数功能                   : 主函数
* 输    入         : 无
* 输    出         : 无
*******************************************/
void main(void)
{        
        Timer0Init();
        LCD_Init();              //液晶初始化
        LCD_Write_String(4,0,di);//液晶第一行显示字符“Distance”
        
        while(1)//获取一次超声波测距模块的距离
        {
               
                 StartModule();
             while(!Echo);                //当Echo为零时等待
             TR0=1;                            //开启
             while(Echo);                //当Echo为1计数并等待
             TR0=0;                                //关闭
         Conut();                        //计算
         DelayMs(10);
        }
}


/*-------------启动超声波模块------------*/
void StartModule()         
{
          Trig=1;//启动一次模块
   
          _nop_(); _nop_(); _nop_(); _nop_();
          _nop_(); _nop_(); _nop_(); _nop_();
          _nop_(); _nop_(); _nop_(); _nop_();
          _nop_(); _nop_(); _nop_(); _nop_();
          _nop_(); _nop_(); _nop_(); _nop_();
          _nop_(); _nop_(); _nop_(); _nop_();/*可以生成10us脉冲,此处可以使用Delay10us_51();代替*/


          Trig=0;
}
      /*
      51延时10us程序
      void Delay10us_51(void)
      {
          u8 i=15;
          _nop_();
          while(--i);
      }
      */


void Timer0Init(void)        
{
        TMOD &= 0xF0;
        TMOD |= 0x01;                //设T0为方式1
        TH0 = 0;
        TL0 = 0;
    TF0 = 0;                   //清除TF0标志        
        ET0 = 1;           //允许T0中断
        EA = 1;                           //开启总中断
    TR0 = 1;               //开启定时器0
}




/*--------------距离计算模块------------*/
void Conut(void)
{
         time=TH0*0x100+TL0;    //获取时间 0x100=256  TH0*0x100+TL0=256
     /*也可以写成
     1、time=TH0*256+TL0;
     2、time=TH0<<8|TL0;
    */
         //重置初值
         TH0=0;
         TL0=0;
        
         //s=(time/58.0/100.0)*1000;  与下面的一样意思
     s=((u16)(time/58.0));       //获取距离——计数出来的是M
         if( s>= 400 )//超出测量范围显示“-”
         {         
         
          LCD_Write_Char(4, 1, ASCII[11]);//液晶第二行第4个点阵显示ASCII[]第11个数据'-',一下以此类推!!!
          LCD_Write_Char(5, 1, ASCII[10]);//显示点
          LCD_Write_Char(6, 1, ASCII[11]);
          LCD_Write_Char(7, 1, ASCII[11]);
          LCD_Write_Char(8, 1, ASCII[11]);
          LCD_Write_Char(9, 1, ASCII[12]);//显示M
         }
         else
         {
          disbuff[0]=s/1000%10;
          disbuff[1]=s/100%10;
          disbuff[2]=s/10%10;
          disbuff[3]=s/1%10;
          LCD_Write_Char(4, 1, ASCII[disbuff[0]]);//显示千位
          LCD_Write_Char(5, 1, ASCII[10]);//显示点
          LCD_Write_Char(6, 1, ASCII[disbuff[1]]);//显示百位
          LCD_Write_Char(7, 1, ASCII[disbuff[2]]);//显示十位
          LCD_Write_Char(8, 1, ASCII[disbuff[3]]);//显示个位
          LCD_Write_Char(9, 1, ASCII[12]);//显示M
         }
}
回复

使用道具 举报

ID:1005855 发表于 2022-4-6 17:23 | 显示全部楼层
仿真不能出数据,怎么解决
51hei图片20220406172057.png
回复

使用道具 举报

ID:161164 发表于 2022-4-6 23:09 | 显示全部楼层
试试在while(1)之前加个DelayMs(1000);

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:1005855 发表于 2022-4-7 19:53 | 显示全部楼层
lkc8210 发表于 2022-4-6 23:09
试试在while(1)之前加个DelayMs(1000);

还是不能显示数据,还要其他的方法吗
回复

使用道具 举报

ID:161164 发表于 2022-4-7 21:14 | 显示全部楼层
lj2443454061 发表于 2022-4-7 19:53
还是不能显示数据,还要其他的方法吗

我又沒有lcd.h和delay.h
回复

使用道具 举报

ID:1005855 发表于 2022-4-8 10:17 | 显示全部楼层
lkc8210 发表于 2022-4-7 21:14
我又沒有lcd.h和delay.h

#ifndef __LCD_H_
#define __LCD_H_

/**********************************
包含头文件
**********************************/
#include <reg52.h>
#include "intrins.h"

//---重定义关键词---//
#ifndef uchar
#define uchar unsigned char
#endif

#ifndef uint
#define uint unsigned int
#endif

/**********************************
            PIN口定义
**********************************/
sbit EN = P2^7;
sbit RW = P2^5;
sbit RS = P2^6;

/**********************************
            函数声明
**********************************/
void busy();//忙检测函数

/*LCD1602写入8位命令子函数*/
void LCD_Write_Com(unsigned char cmd);

/*LCD1602写入8位数据子函数*/       
void LCD_Write_Data(unsigned char dat);

/*LCD1602初始化子程序*/               
void LCD_Init(void);

void LCD_Write_Char(unsigned char x,unsigned char y,unsigned char Data);

void LCD_Write_String(unsigned char x,unsigned char y,unsigned char *s);
                                                  

#endif



#ifndef __DELAY_H__
#define __DELAY_H__

void DelayUs2x(unsigned char t);

void DelayMs(unsigned char t);

#endif




回复

使用道具 举报

ID:1005855 发表于 2022-4-8 10:48 | 显示全部楼层
#include "lcd.h"

//---------------------------------------------------------------------
//函数:判忙函数
//功能:判断液晶是否忙碌
void busy()
{
        uchar sta;
        P0= 0xFF;                //P0初始化
        RS = 0;                        //选择指令寄存器
        RW = 1;                        //读模式
        do
        {
                EN = 1;
                _nop_();
                sta = P0;         //读取状态字
                EN = 0;                //当E端由高电平跳变成低电平时,液晶模块执行命令
               
        }
        while (sta & 0x80); //bit7 等于 1 表示液晶正忙,重复检测直到其等于 0 为止
}

//---------------------------------------------------------------------
//函数:写命令函数
//功能:向液晶写入一字节命令(8位命令), cmd-待写入命令值
void LCD_Write_Com(unsigned char cmd)
{
        busy(); //判断液晶是否忙碌
        RS = 0; //选择指令寄存器
        RW = 0; //写模式
        P0 = cmd;//把数据给P0,即写入指令和地址
        EN = 1;
    _nop_();//短暂延时1us
        _nop_();//短暂延时1us       
        EN = 0;        //当E端由高电平跳变成低电平时,液晶模块执行命令
       
}

//---------------------------------------------------------------------
//函数:写数据函数
//功能:向液晶写入一字节数据(8位数据), dat-待写入数据值
void LCD_Write_Data(unsigned char dat)
{
        busy(); //判断液晶是否忙碌
        RS = 1; //选择数据寄存器
        RW = 0; //写模式
        P0= dat;//把数据给P0
        EN = 1;
        _nop_();//短暂延时1us
        _nop_();//短暂延时1us               
        EN = 0;        //当E端由高电平跳变成低电平时,液晶模块执行命令
       
}


//---------------------------------------------------------------------
//函数:初始化液晶函数
//功能:初始化液晶,并显示启动界面
void LCD_Init()
{
        LCD_Write_Com(0x38); //16*2 显示, 5*7 点阵, 8 位数据传送
        LCD_Write_Com(0x0C); //显示器开,光标关闭
        LCD_Write_Com(0x06); //文字不动,地址自动+1
        LCD_Write_Com(0x01); //清屏
       
}


//---------------------------------------------------------------------
/*函数:写入字符函数*/
//功能:设置显示 DDRAM 起始地址,亦即光标位置, (x,y)-对应屏幕上的字符坐标
void LCD_Write_Char(unsigned char x,unsigned char y,unsigned char Data)
{     
    if (y == 0) //由输入的屏幕坐标计算显示 DDRAM 的地址
        {     
        LCD_Write_Com(0x80 + x); //第一行字符地址从 0x80 起始   
        }   
    else
        {     
        LCD_Write_Com(0xC0 + x); //第二行字符地址从 0xc0起始   
        }        
    LCD_Write_Data( Data);           //写数据-设置 DDRAM 地址
}

/*函数:写入字符串函数*/
//可参考网上的
void LCD_Write_String(unsigned char x,unsigned char y,unsigned char *s)
{            
    while (*s) //先取 s 指向的数据,然后s自加 1,指向下一个待写字符
    {     
        LCD_Write_Char(x,y,*s);     
        s++;  
        x++;   
    }
}
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表