项目

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时蜂鸣器发出警报声