51-超声波测距+温度显示
项目
main.c
# include "reg51.h"
# include "LCD1602.h"
# include "Sonar.h"
# include "temp.h"
# include "fmq.h"
# include <stdio.h>
float GetTemperature (void)
{
float Temperature = (float)Ds18b20ReadTemp();
return (Temperature>0?Temperature:-Temperature) * 0.0625; //得到温度
}
void main(void)
{
char line1[16]="";
char line2[16]="";
float Temperature=0;
Sonar_Init(); //初始化超声波
LCDInit(); //初始化LCD
while(1)
{
Temperature = GetTemperature(); //获取温度
Sonar_Precision(Temperature,11.0952); //修正声呐(温度,晶振)
sprintf(line1,"Temp:%+07.2fC",Temperature);
sprintf(line2,"Dist:%+07.2fcm",Sonar_Distance());
LCDLineputs(1,line1);
LCDLineputs(2,line2);
}
}
temp.c(温度模块)
# include "temp.h"
void Ds18b20Sleep1ms(uint time)
{
uint temp;
for(;time>0;time--)
for(temp=110;temp>0;temp--);
}
//初始化时序
uchar Ds18b20Init()
{
uint Sleep;
Signal = 0; // (1).数据线拉到低电平“0”。
Sleep=70;
while(Sleep--);// (2).延时480微妙(该时间的时间范围可以从480到960微妙)。
Signal = 1;// (3).数据线拉到高电平“1”。
Sleep = 0;
while(Signal)
{
Ds18b20Sleep1ms(1);
Sleep++;
if(Sleep>5)
{
return 0;
}
}
return 1;// (5).若CPU读到了数据线上的低电平“0”后,还要做延时,其延时的时间从发出的高电平算起(第(3)步的时间算起)最少要480微妙
}
uchar Ds18b20ReadByte()
{
uint i=0,Sleep=0;
uchar MyData=0,temp=0;
for(i=0;i<8;i++)
{
Signal = 0;// (1).将数据线拉低“0”。
Sleep++;// (2).延时1微妙。
Signal = 1;// (3).将数据线拉高“1”,释放总线准备读数据。
Sleep++;
Sleep++;
temp = Signal;
MyData = (MyData >> 1) | (temp << 7);
Sleep = 4;
while(Sleep--);
}
return MyData;
}
void Ds18b20WriteByte(uchar MyData)
{
uint i=0,Sleep=0;
for(i=0;i<8;i++)
{
Signal = 0;// (1).数据线先置低电平“0”
Sleep++;
Signal = MyData & 0x01;// (3).按从低位到高位的顺序发送数据(一次只发送一位)。
Sleep=6;
while(Sleep--);
Signal = 1;// (5).将数据线拉到高电平。
MyData >>= 1;
}
}
void Ds18b20ChangTemp()
{
Ds18b20Init();//复位
Ds18b20Sleep1ms(1);
Ds18b20WriteByte(0xcc); //跳过搜索,直接使用
Ds18b20WriteByte(0x44); //温度转换命令
}
void Ds18b20ReadTempCom()
{
Ds18b20Init();
Ds18b20Sleep1ms(1);
Ds18b20WriteByte(0xcc); //跳过搜索,直接使用
Ds18b20WriteByte(0xbe); //发送读取温度命令
}
int Ds18b20ReadTemp()
{
int temp = 0;
uchar tmh,tml;
Ds18b20ChangTemp();
Ds18b20ReadTempCom();
tml = Ds18b20ReadByte(); //这个问题我找了一个晚上.以后一定要记得顺序这个东西!
tmh = Ds18b20ReadByte(); //因为 这个 tmh 与 tml 顺序反了!导致问题出现!!!
//合并成16位数据
temp |= (tmh << 8);
temp |= tml;
return temp;
}
temp.h
# ifndef _temp_H_
# define _temp_H_
# include "reg51.h"
# ifndef uchar
# define uchar unsigned char
# endif
# ifndef uint
# define uint unsigned int
# endif
sbit Signal=P3^7;
uchar Ds18b20Init();
uchar Ds18b20ReadByte();
void Ds18b20WriteByte(uchar MyData);
void Ds18b20ChangTemp();
void Ds18b20ReadTempCom();
int Ds18b20ReadTemp();
# endif
Sonar.c(超声波模块)
# include "Sonar.h"
# include "fmq.h"
void warning(int k);
float WEIGHT = 0.017; //权值.这里不需要改动.除非你看懂原理
void Sonar_Sleep10us(uint times)
{
unsigned char a,b;
while(times--){
for(b=1;b>0;b--)
for(a=2;a>0;a--);
}
}
void Sonar_OverFlow() interrupt 1 //INT0:0 T0:1 INT1:2 T1:3
{
TH0 = 0;
TL0 = 0;
}
void Sonar_Precision(float Temperature,float OCXO) //利用温度与晶振修正距离
{
float speed=0,Time=12/OCXO; //机器周期=晶振周期*12=(1/晶振频率)*12 单位是us
speed = (331.4 + 0.607 * Temperature); //速度与温度的关系
//距离 = (速度 * 时间) / 2 下面的 Time 是单位!不是时间!!!
//权值 = (speed*100 * (时间*Time)/1000000) / 2 统一单位为 cm/s
WEIGHT = (speed*Time)/20000;
}
void Sonar_Init(void)
{
TMOD = 0x01; //模式1的计时间
TH0 = 0;
TL0 = 0; //计时器
ET0 = 1; //响应中断
TR0 = 0; //运行控制位
EA = 1; //总中断
}
void Sonar_Trig(void)
{
TRIG = 1;
Sonar_Sleep10us(1); //10us
TRIG = 0;
}
void Sonar_Echo(void)
{
while(!ECHO); //ECHO到高电平 开始计时
TR0 = 1; //开始计时
while(ECHO); //ECHO到低电平 结束计时
TR0 = 0; //关闭计时
}
float Sonar_Distance(void)
{
int k;
uint Time = 0;
float Distance=0;
Sonar_Trig(); // 发出探测信号
Sonar_Echo(); // 检测回声时长
Time |= (TH0 << 8);
Time |= TL0; //获取时间
TH0 = 0; //清空计时器
TL0 = 0;
Sonar_Sleep10us(850); //延时85ms,这个值可以超声波垂直地面.微调直到距离为 0
Distance = Time * WEIGHT; //运算结果的单位是 cm
k=Distance;
warning(k);//距离小于10发出声音
return Distance<500?Distance:0; //距离 = 高电平时间 * 声速(340M/S) / 2
}
Sonar.h
# ifndef __SONAR_H_YAOWU__
# define __SONAR_H_YAOWU__
# ifndef uchar
# define uchar unsigned char
# endif
# ifndef uint
# define uint unsigned int
# endif
# include <reg51.h>
sbit TRIG = P2^1; //将这里调整下你就可以正常使用这个模块了
sbit ECHO = P2^0;
void Sonar_Init(void); //声呐传感器初始化
void Sonar_Trig(void);
void Sonar_Echo(void);
void Sonar_Precision(float,float); //利用温度值与晶振频率运算出声音传播速度从而修正距离
float Sonar_Distance(void); //返回与目标的距离,这里可以较为精准测量 0.5cm ~ 5m 内的距离
# endif
LCD1602.c(显示屏)
# include <string.h>
# include "LCD1602.h"
void LCD_Sleep1ms(uint c)
{
uchar a,b;
for (; c>0; c--)
{
for (b=199;b>0;b--)
{
for(a=1;a>0;a--);
}
}
}
void LCDInit()
{
SetLCDCommand(0x06); //写入新数据光标右移,屏幕不动.
SetLCDCommand(0x0C); //光标不闪烁,无光标,显示功能打开.
SetLCDCommand(0x38); //5x7\显示两行\数据总线8根
SetLCDCommand(0x01); //清屏
SetLCDCommand(0x80); //调整光标到左上角
}
void SetLCDCommand(uchar source)
{
LCD1602_RS = 0; // L 命令
LCD1602_RW = 0; // L 写
LCD1602_E = 0;
LCD1602_DATAPINS = source;
LCD_Sleep1ms(1);
LCD1602_E = 1;
LCD_Sleep1ms(5);
LCD1602_E = 0;
}
void SetLCDData(uchar source)
{
LCD1602_RS = 1; //H 数据
LCD1602_RW = 0; //L 写
LCD1602_E = 0;
LCD1602_DATAPINS = source;
LCD_Sleep1ms(1);
LCD1602_E = 1;
LCD_Sleep1ms(5);
LCD1602_E = 0;
}
void LCDLineputs(uchar line,char * source)
{
uchar j=0,length=strlen(source);
line = (line==2?1:0); //将line 转换成布尔值 0表示第一行 1 表示第二行
if(length>16)return;
SetLCDCommand(line?0xC0:0x80); //设置写入地址
for(j=0;j<length;j++)
{
SetLCDData(*(source + j));
}
}
LCD1602.h
# ifndef _LCD1602_H_YAOWU_
# define _LCD1602_H_YAOWU_
# include "reg51.h"
# ifndef uint
# define uint unsigned int
# endif
# ifndef uchar
# define uchar unsigned char
# endif
# define LCD1602_DATAPINS P0
sbit LCD1602_E=P2^7;
sbit LCD1602_RW=P2^5;
sbit LCD1602_RS=P2^6;
void LCDInit();
void SetLCDData(uchar );
void SetLCDCommand(uchar );
void LCDLineputs(uchar ,char * source);
# endif
fmq.c(蜂鸣器)
# include "fmq.h"
unsigned char H_count,L_count;
//延时函数
void delay_10us(int ten_us)
{
while(ten_us--);
}
void warning(int k)
{
unsigned int i=300;
if(k<=10)
{
while(i--)
{
BEEP=!BEEP;
delay_10us(40);
}
i=0;//赋0就不会再响了
BEEP=1;//这赋0或者1都行
k=0;
}
}
fmq.h
# ifndef _fmq_H_
# define _fmq_H_
# include "reg51.h"
# ifndef uchar
# define uchar unsigned char
# endif
# ifndef uint
# define uint unsigned int
sbit BEEP=P2^5;
void delay_10us(int ten_us);
void warning(int k);
# endif
实验现象
显示屏显示温度和距离(厘米),当测距小于10时蜂鸣器发出警报声
