#include <reg51.h>#include <intrins.h> #define Delay4us(){_nop_();_nop_();_nop_();_nop_();}/*
宏定义*/#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^5; //
报警测量超出范围sbit Trig=P1^7; //HC-SR04
触发信号输入sbit Echo=P1^6; //HC-SR04
回响信号输出 float xdata DistanceValue=0.0; //
测量的距离值float xdata SPEEDSOUND; //
声速float xdata XTAL
tiME; //
单片机计数周期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();extern void LCD_Display_String(uchar *, uchar);extern void ReadTemperatureFromDS18B20();extern int xdata CurTempInteger; //
毫秒延时函数void DelayMS(uint ms);//20
微秒延时函数void Delay20us();//HCSR04
初始化void HCSR04_Initialize();//
测量距离float MeasuringDistance();//
测距的数值排序求平均float DistanceStatistics();//
输出距离值到LCD1602上void DisplayDistanceValue(float dat);//
将无符号的整数转成字符串,返回字符串长度,不包括' '结束符uchar UnsigedIntToString(uint value);//
蜂鸣器void Beep(uchar time);//
显示温度值void DisplayTemperatureValue(); //
测量距离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
!=' ') { 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%10+'0'; TemperatureText[15]='C'; LCD_Display_String(TemperatureText,0x00); } //将无符号的整数转成字符串,返回字符串长度uchar UnsigedIntToString(uint value){ uchar i=0,t,length; //从个位开始转换 do { stringBuf='0'+value%10; 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]=' '; return length;} //蜂鸣器void Beep(uchar time){ uchar i; for(i=0;i<100;i++) { BEEP=!BEEP; DelayMS(time); } BEEP=0; DelayMS(100);} //延时函数 毫秒 @12.000MHzvoid DelayMS(uint ms){ uchar i, j; while(ms--) { _nop_(); i = 2; j = 239; do { while (--j); }while (--i); }} //延时函数 20微秒 @12.000MHzvoid Delay20us(){ uchar i; _nop_(); i = 7; while (--i);} //定时器0中断void Timer0() interrupt 1{ } //DS18B20代码:/*----------------------------------------------* 程序功能: DS18B20温度检测程序* 单片机型号:STC89C52 12MHz* 晶振: 12Mhz------------------------------------------------*/ /*包含头文件*/#include <reg51.h>#include <intrins.h> /*宏定义*/#define uchar unsigned char //无符号8位#define uint unsigned int //无符号16位 //定义DS18B20端口DS18B20_DQsbit DS18B20_DQ = P3^7; //当前采集的温度值整数部分int xdata CurTempInteger; //当前采集的温度值小数部分int xdata CurTempDecimal; /*----------------------------------------------------------------* 功能:延时函数 STC89C52 @12MHz 12T模式* 参数:无* 返回:无----------------------------------------------------------------*/void Delayus(uint count) { while (--count);} /*----------------------------------------------------------------* 功能:DS18B20复位及状态检测* 参数:无* 返回:0或1,1表示未准备好,0表示准备好----------------------------------------------------------------*/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;} /*----------------------------------------------------------------* 功能:写一字节到DS18B20中* 参数:dat=数据* 返回:无----------------------------------------------------------------*/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; //准备下一位数据 }} /*----------------------------------------------------------------* 功能:从DS18B20中读一字节* 参数:无* 返回:读取的数据----------------------------------------------------------------*/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程序代码:/*----------------------------------------------* 程序功能:1602液晶显示程序* 单片机型号:STC90C160 12MHz------------------------------------------------*/ /*1602液晶显示器控制端口分配,数据使用P0端口*/sbit LCD_RS=P2^6;sbit LCD_RW=P2^5;sbit LCD_EN=P2^7; /*--------------------------------------------* 功能:毫秒级延时函数* 参数:ms=毫秒数值* 返回:无--------------------------------------------*/void LCDDelay(uint ms){ uchar i, j; while(ms--) { _nop_(); i = 2; j = 239; do { while (--j); }while (--i); } } /*--------------------------------------------* 功能:1602液晶忙状态检测* 参数:无* 返回:0或1,1表示状态忙,0表示状态闲--------------------------------------------*/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;} /*--------------------------------------------* 功能:1602液晶写指令* 参数:cmd=1602LCD指令* 返回:无--------------------------------------------*/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;} /*--------------------------------------------* 功能:1602液晶写数据* 参数:dat=一个字节数据* 返回:无--------------------------------------------*/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;} /*--------------------------------------------* 功能:设置1602液晶显示位置* 参数:pos=位置地址值* 返回:无--------------------------------------------*/void LCD_Set_POS(uchar pos){ Write_LCD_Command(pos|0x80);} /*--------------------------------------------* 功能:1602液晶初始化* 参数:无* 返回:无--------------------------------------------*/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);} /*--------------------------------------------* 功能:在1602液晶指定的行上显示字符串 (共两行,一行16个字符)* 参数:*str=字符串指针, LineNo=行首地址(第一行0x00,第二行0x40)* 返回:无--------------------------------------------*/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]); } } /*--------------------------------------------* 功能:在1602液晶指定位置显示一个字符 (共两行,一行16个字符)* 参数:Dat=一个字符, X=列位置(0-15) Y=行位置(0,1)* 返回:无--------------------------------------------*/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);} /*主函数*/void main(){ LCD_Initialize();//1602初始化 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;}
一周热门 更多>