找回密码
 立即注册

QQ登录

只需一步,快速开始

帖子
查看: 8850|回复: 2
打印 上一主题 下一主题
收起左侧

基于C51单片机和LCD1602显示的超声波测距仪C语言程序

[复制链接]
跳转到指定楼层
#
ID:51090 发表于 2014-10-12 21:32 | 只看该作者 回帖奖励 |正序浏览 |阅读模式
#include"reg52.h"
#include"intrins.h"


#define uchar unsigned char    //无符号8位
#define uint unsigned int    //无符号16位
#define ulong unsigned long    //无符号32位


sbit K1=P1^0;   //按下K1后,开始测距
sbit LEDRed=P1^1; //测距指示灯,亮表示正在测距,灭表示测距完成
//sbit BEEP=P1^2;  //报警测量超出范围

sbit Trig=P2^5;  //HC-SR04触发信号输入
sbit Echo=P2^6;  //HC-SR04回响信号输出

float xdata DistanceValue=0.0; //测量的距离值
float xdata SPEEDSOUND;    //声速
float xdata XTALTIME;    //单片机计数周期
uchar xdata stringBuf[6];   //数值转字符串缓冲

//LCD1602提示信息
uchar code Prompts[][16]=
{
{"Measure Distance"}, //测量距离
{"- Out of Range -"}, //超出测量范围
{"MAX range 400cm "}, //测距最大值400cm
{"MIN range 2cm   "}, //测距最小值2cm
{"                "}, //清屏
{" Press K1 Start "} //按键开始测量
};
uchar xdata DistanceText[]="Range:          ";   //测量结果字符串
uchar xdata TemperatureText[]="Temperature:    ";//测量温度值


extern void LCD_Initialize();                       //LCD初始化
extern void LCD_Display_String(uchar *, uchar);     //字符串显示
extern void ReadTemperatureFromDS18B20();           //从DS18B20读取温度值
extern int xdata CurTempInteger;


//毫秒延时函数
void DelayMS(uint ms);
//20微秒延时函数
void Delay20us();
//HCSR04初始化
void HCSR04_Initialize();
//测量距离
float MeasuringDistance();
//测距的数值排序求平均
float DistanceStatistics();
//输出距离值到LCD1602上
void DisplayDistanceValue(float dat);
//将无符号的整数转成字符串,返回字符串长度,不包括'\0'结束符
uchar UnsigedIntToString(uint value);
//蜂鸣器
//void Beep(uchar time);
//显示温度值
void DisplayTemperatureValue();


void main()
{
LCD_Initialize();//LCD1602初始化
LCD_Display_String(Prompts[0],0x00);
LCD_Display_String(Prompts[5],0x40);
ReadTemperatureFromDS18B20();    //测温度
HCSR04_Initialize();             //HC-SR04初始化
while(1)
{
  if(K1==0)
  {
   DelayMS(5);
   if(K1==0)
   {
    //Beep(1);
    while(K1==0);
    LEDRed=0;
    ReadTemperatureFromDS18B20();//测温度
    DisplayTemperatureValue();
    if(CurTempInteger<14)
     CurTempInteger=14;
    else if(CurTempInteger>26)
     CurTempInteger=26;
    SPEEDSOUND=334.1+CurTempInteger*0.61;//计算声速
    DistanceValue=DistanceStatistics();  //测距并返回距离值
    DisplayDistanceValue(DistanceValue); //显示距离值
    LEDRed=1;
   }
  }
}
}

//测距的数值排序求平均
float DistanceStatistics()
{
uchar i,j;
float disData[7],t;
//连续测距
for(i=0;i<7;i++)
{
  disData=MeasuringDistance();
  DelayMS(80);
}
//排序
for(j=0;j<=6;j++)
{
  for(i=0;i<7-j;i++)
  {
   if(disData>disData[i+1])
   {
    t=disData;
    disData=disData[i+1];
    disData[i+1]=t;
   }
   }
}
return (disData[2]+disData[3]+disData[4])/3;
}

//测量距离
float MeasuringDistance()
{
//最大定时时间约65ms
TH0=0;
TL0=0;

//生成20us的脉冲宽度的触发信号
Trig=1;   
Delay20us();
Trig=0;

//等待回响信号变高电平
while(!Echo);
TR0=1;  //启动定时器0

//等待回响信号变低电平
while(Echo);  
TR0=0;  //关闭定时器0

//返回距离值(mm)
return (SPEEDSOUND*XTALTIME*((float)TH0*256+(float)TL0))/2000;
}

//HCSR04初始化
void HCSR04_Initialize()
{
//计算单片机计数周期  晶振=11.953M 单位us
XTALTIME=12/11.953;
//温度25度时声速的值
SPEEDSOUND=334.1+25*0.61;   
Trig=0;
Echo=0;
TMOD=0x01;
}

//输出距离值到LCD1602上
void DisplayDistanceValue(float dat)
{
uchar i=0,j=0,len;
uint value;
value=(uint)dat;
//范围检查大于4000mm和小于20mm都为超出测量范围
if(value>4000)
{
  LCD_Display_String(Prompts[1],0x00);
  LCD_Display_String(Prompts[2],0x40);
  //Beep(2);
}
else if(value<20)
{
  LCD_Display_String(Prompts[1],0x00);
  LCD_Display_String(Prompts[3],0x40);
  //Beep(2);
}
else
{
  //将数值转换成字符串
  len=UnsigedIntToString(value);
  //保留1位小数
  while(stringBuf!='\0')
  {
   if(len-j==1)
   {
    DistanceText[6+j]='.';
    j++;
   }else
   {
    DistanceText[6+j]=stringBuf;
    i++;
    j++;
   }
  }
  DistanceText[6+j]='c';
  j++;
  DistanceText[6+j]='m';
  i=7+j;
  //剩余位置补空格
  while(i<16)
  {
   DistanceText=' ';
   i++;
  }
  //LCD_Display_String(Prompts[0],0x00);
  LCD_Display_String(DistanceText,0x40);
}
}

//显示温度值
void DisplayTemperatureValue()
{
TemperatureText[13]=CurTempInteger/10+'0';
TemperatureText[14]=CurTempInteger+'0';
TemperatureText[15]='C';
LCD_Display_String(TemperatureText,0x00);  
}

//将无符号的整数转成字符串,返回字符串长度
uchar UnsigedIntToString(uint value)
{
uchar i=0,t,length;
//从个位开始转换
do
{
  stringBuf='0'+value;
  value=value/10;
  i++;
}while(value!=0);
length=i;
//将字符串颠倒顺序
for(i=0;i<(length/2);i++)
{
  t=stringBuf;
  stringBuf=stringBuf[length-i-1];
  stringBuf[length-i-1]=t;
}
stringBuf[length]='\0';
return length;
}

//蜂鸣器

//延时函数 毫秒 @12.000MHz
void DelayMS(uint ms)
{
uchar i, j;
while(ms--)
{
  _nop_();
  i = 2;
  j = 239;
  do
  {
   while (--j);
  }while (--i);
}
}

//延时函数 20微秒 @12.000MHz
void Delay20us()
{
uchar i;
_nop_();
i = 7;
while (--i);
}

//定时器0中断
void Timer0() interrupt 1
{

}

//DS18B20代码:


#include
#include


#define uchar unsigned char  //无符号8位
#define uint unsigned int   //无符号16位

//定义DS18B20端口DS18B20_DQ
sbit DS18B20_DQ = P2^7;

//当前采集的温度值整数部分
int xdata CurTempInteger;
//当前采集的温度值小数部分
int xdata CurTempDecimal;


void Delayus(uint count)  
{
while (--count);
}


uchar Reset_DS18B20()
{
uchar status;
DS18B20_DQ=1;
Delayus(1);
//开始复位过程
DS18B20_DQ=0;  //数据线拉低
Delayus(100);  //延时480us-960us
DS18B20_DQ=1;  //数据线拉高
Delayus(10);  //延时15us-60us
status=DS18B20_DQ; //读取数据线上的状态
Delayus(120);
return status;
}


void  WriteByteToDS18B20(uchar dat)
{
uchar i;
for(i=0;i<8;i++)
{
  DS18B20_DQ=0;
  DS18B20_DQ=dat&0x01;   //发送1位数据
  Delayus(15);      //延时60us以上
  DS18B20_DQ=1;      //释放总线,等待总线恢复
  dat>>=1;       //准备下一位数据
}
}


uchar ReadByteFromDS18B20()
{
uchar i,dat=0;
for(i=0;i<8;i++)
{

  DS18B20_DQ=0;      //拉低总线,产生读信号
  dat>>=1;
  DS18B20_DQ=1;     //释放总线,准备读1位数据   
Delayus(2);     //延时4us
  if(DS18B20_DQ) dat|=0x80; //合并每位数据
  Delayus(15);     //延时60us
  DS18B20_DQ=1;     //拉高总线,准备读下1位数据
}
return dat;
}


void ReadTemperatureFromDS18B20()
{
uchar flag=0;//正负符号标志
//存储当前采集的温度值
uchar TempValue[]={0,0};
if(Reset_DS18B20())
{
  CurTempInteger=255;
  CurTempDecimal=0;
}
else
{
  WriteByteToDS18B20(0xCC);//跳过ROM命令
  WriteByteToDS18B20(0x44);//温度转换命令
  Reset_DS18B20();//复位
  WriteByteToDS18B20(0xCC);//跳过ROM命令
  WriteByteToDS18B20(0xBE);//读取温度暂存器命令
  TempValue[0]=ReadByteFromDS18B20();//先读低字节温度值
  TempValue[1]=ReadByteFromDS18B20();//后读高字节温度值
  Reset_DS18B20();//复位

  //计算温度值
  //先进行正温度与负温度判断,高5位全为1(0xF8)则为负数
  if((TempValue[1]&0xF8)==0xF8)
  {
   //负温度计算:取反加1,低字节为0时,高字节取反加1,否则不需要。
   TempValue[1]=~TempValue[1];
   TempValue[0]=~TempValue[0]+1;
   if(TempValue[0]==0x00) TempValue[1]++;
   flag=1;//负数标志
  }
  //将温度值分为整数和小数两部分存储(默认为12位精度)
  CurTempInteger=((TempValue[1]&0x07)<<4)|((TempValue[0]&0xF0)>>4);   if(flag) CurTempInteger=-CurTempInteger;
  CurTempDecimal=(TempValue[0]&0x0F)*625;
}
}

//LCD1602程序代码:

#include
#include


#define uchar unsigned char
#define uint  unsigned int
#define Delay4us(){_nop_();_nop_();_nop_();_nop_();}


sbit LCD_RS=P2^0;
sbit LCD_RW=P2^1;
sbit LCD_EN=P2^2;


void LCDDelay(uint ms)
{
uchar i, j;
while(ms--)
{
  _nop_();
  i = 2;
  j = 239;
  do
  {
   while (--j);
  }while (--i);
}  
}


bit LCD_Busy_Check()
{
bit result;
LCD_RS=0; LCD_RW=1; LCD_EN=1;
Delay4us();
result=(bit)(P0&0x80);
LCD_EN=0;
return result;
}


void Write_LCD_Command(uchar cmd)
{
while(LCD_Busy_Check());
LCD_RS=0; LCD_RW=0;  LCD_EN=0; _nop_(); _nop_();
P0=cmd; Delay4us();
LCD_EN=1; Delay4us(); LCD_EN=0;
}


void Write_LCD_Data(uchar dat)
{
while(LCD_Busy_Check());
LCD_RS=1;LCD_RW=0;LCD_EN=0;
P0=dat;Delay4us();
LCD_EN=1;Delay4us();LCD_EN=0;
}


void LCD_Set_POS(uchar pos)
{
Write_LCD_Command(pos|0x80);
}


void LCD_Initialize()
{
Write_LCD_Command(0x01); LCDDelay(5);
Write_LCD_Command(0x38); LCDDelay(5);
Write_LCD_Command(0x0C); LCDDelay(5);
Write_LCD_Command(0x06); LCDDelay(5);
}


void LCD_Display_String(uchar *str, uchar LineNo)
{
uchar k;
LCD_Set_POS(LineNo);
for(k=0;k<16;k++)
{
  Write_LCD_Data(str[k]);
}
}



void LCD_Display_OneChar(uchar Dat, uchar X, uchar Y)
{
Y &= 0x01; //限制Y不能大于1(2行,0-1)
X &= 0x0F;  //限制X不能大于15(16个字符,0-15)
if(Y) {X |= 0x40;} //当要在第二行显示时地址码+0x40;
X |= 0x80; //算出指令码
Write_LCD_Command(X);
Write_LCD_Data(Dat);
}

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

举报

沙发
ID:98657 发表于 2016-3-3 17:31 | 只看该作者
你好,请问你有用过霍尔传感器测距的吗,能否发份代码给我看看,谢谢
回复

举报

楼主
ID:81768 发表于 2015-6-1 20:49 | 只看该作者
谢谢你,这对我帮助很大。可是我有一个问题:为什么把蜂鸣器报警的给删了?有仿真图吗?
回复

举报

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

本版积分规则

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

Powered by 单片机教程网

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