|
利用STC89C52单片机、超声波模块(HC-RS04)、DS18B20数字温度传感器和LCD1602液晶显示模块制作一个超声波测距仪,液晶屏第一行显示温度和超声波速度“T:30°C V:349m/s”,第二行显示测量距离“S=X.XXXm”。
所设计的测距仪测量单位为米,精确到小数点后面3位(毫米),测量范围:0.05m~5m。
(一)基本部分
1、液晶显示功能
(1)开机时,液晶屏第一行显示温度和超声波速度,例如“T:30°C V:349m/s”,第二行显示测量距离“S=0.000m”
(2)操作对应的功能按键时,液晶屏第一行显示温度和超声波速度,例如“T:30°C V:349m/s”,第二行显示测量距离“S=X.XXXm”。
(3)本超声波测距仪使用4个独立按键。第1个按键为复位清零功能;第2个按键为单次测量功能;第3个按键为瞬时连续测量功能;第4个按键为平均连续测量功能。
(4)第1个按键为复位清零功能。无论什么时候按下该键,液晶屏第二行均显示测量距离“S=0.000m”
(5)第2个按键为单次测量功能。每按一次该键,就发射一次超声波,液晶屏第二行对应显示一次测量距离“S=X.XXXm”
(6)第3个按键为瞬时连续测量功能。按下该键,连续发射超声波,液晶屏第二行对应显示瞬时测量距离“S=X.XXXm”,再按一次该键,数字保持,以便读数
(7)第4个按键为平均连续测量功能。按下该键,连续发射超声波,液晶屏第二行对应显示平均测量距离“S=X.XXXm”,再按一次该键,数字保持,以便读数
(8)第5个按键为自动/手动温度设置按键,转换到手动设置温度值,这时可以利用加键和减键使温度在0度至50度范围内调节,再按一次该键,重新回到自动温控状态,如此循环。
(9)第6个按键为温度加按键,当处于手动温度控制状态时,按下本按键可以加温度,最高可以加到50摄氏度。
(10)第7个按键为温度减按键,当处于手动温度控制状态时,按下本按键可以减温度,最低可以减0摄氏度。
程序代码如下:
- /**************************************/
- /* 超声波测距(自动/手动温度校正) */
- /* (超声波模块+18B20+1602液晶) */
- /**************************************/
- #include <reg52.h>
- #include <intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
- #define LcdData P0 //1602数据端口
- sbit LCD_RS=P2^6; //1602 RS端口
- sbit LCD_RW=P2^5; //1602 RW端口
- sbit LCD_EN=P2^7; //1602 EN端口
- sbit Echo=P2^4; //HC-SR04 接收端口
- sbit Trig=P2^3; //HC-SR04 发射端口
- sbit Resets_Key=P1^0; //复位清零按键
- sbit Single_Key=P1^1; //单次测量按键 误差较大
- sbit Contin_Key=P1^2; //连续测量按键 误差小
- sbit Averag_Key=P1^3; //连续(平均测量)按键 误差较小
- sbit Setting_Key=P1^4; //温度修正按键
- sbit Add_Key=P1^5; //温度加1按键
- sbit Sub_Key=P1^6; //温度减1按键
- sbit DQ=P3^7; //DS18B20单总线接口
- bit Temp_Flag; //正负温度标志:温度为正Temp_Flag=0,否则为1
- uint temp=25; //温度值
- bit flag_flow=0,flag_one=0,flag_clear=0,flag_con1=0,flag_con2=0,flag_temp=0;
- uchar i=0,m,j,k;
- uint time=0,S=0,S1=0,totle=0;
- float V=346.0;
- uint Sav[11]; //连续测量时10次平均值数组
- uchar Line1[16]={"T: C V:346m/s"}; //1602第一行初始字符显示数组
- uchar Line2[16]={"S= m "}; //1602第二行初始字符显示数组
- void Delayms(uchar xms); //延时xms函数
- void WriteLcd(uchar Dat,bit x); //1602写函数
- void InitLcd(void); //1602初始化函数
- void DisplayLcd(); //1602显示函数
- void init(); //初始化函数
- void keyscan(); //键扫描函数
- void StartModule(); //启动模块函数
- void Conut(void); //测量计算函数
- void Delayus(uchar xus); //us级延时函数
- bit Init_DS18B20(void); //初始化DS18B20函数
- uchar Read_DS18B20(void); //读DS18B20函数
- void Write_DS18B20(uchar Dat); //写DS18B20函数
- void GetTemp(); //取温度函数
- void CalcTestTemp(); //温度处理函数
- void main(void) //主函数
- {
- init();
- InitLcd();
- while(1)
- {
- keyscan(); //键扫描函数
- DisplayLcd();
- if(flag_temp==0)
- {
- GetTemp();
- CalcTestTemp();
- }
- if(flag_one==1||flag_con1==1||flag_con2==1)
- {
- StartModule(); //开始发射超声波
- while(!Echo); //当RX为零时等待
- TR0=1; //开启计数
- while(Echo); //当RX为1计数并等待
- TR0=0; //关闭计数
- Conut(); //计算
- Delayus(200);
- flag_one=0;
- }
- }
- }
- void Delayms(uchar xms) //延时ms函数
- {
- uchar i,j;
- for(i=xms;i>0;i--)
- for(j=110;j>0;j--);
- }
- void WriteLcd(uchar Dat,bit x) //1602写函数(写指令时x=0,写数据时x=1)
- {
- LCD_EN=0;
- LcdData=Dat;
- LCD_RS=x;
- LCD_RW=0;
- LCD_EN=1;
- Delayms(1);
- LCD_EN=0;
- }
- void InitLcd(void) //1602初始化函数
- {
- WriteLcd(0x38,0); //功能设定(38H),8位数据,2行显示,5*7点阵
- WriteLcd(0x0C,0); //显示开、关设定(0CH),开显示,不显示光标,光标不闪烁
- WriteLcd(0x06,0); //输入模式设定(06H),读写一个字符后,地址指针加1,且光标加1
- WriteLcd(0x01,0); //清除显示(01H),清除数据RAM中的数据
- }
- void DisplayLcd() //液晶屏显示函数
- {
- uchar y;
- V=(331.4+temp*0.607);
- Line1[2]=temp/10+0x30;
- Line1[3]=temp%10+0x30;
- Line1[4]=0xDF; //显示℃中C前面的小圆
- Line1[10]=(uint)V/100+0x30;
- Line1[11]=(uint)V%100/10+0x30;
- Line1[12]=(uint)V%10+0x30;
- if(flag_clear==1)
- S1=0;
- if((S1>=7000)||flag_flow==1) //超出测量范围显示“-”
- {
- flag_flow=0;
- Line2[2]='-';
- Line2[3]='.';
- Line2[4]='-';
- Line2[5]='-';
- Line2[6]='-';
- }
- else
- {
- Line2[2]=S1/1000+0x30;
- Line2[3]='.';
- Line2[4]=S1%1000/100+0x30;
- Line2[5]=S1%100/10+0x30;
- Line2[6]=S1%10+0x30;
- }
- WriteLcd(0x80,0); //设定第一行地址
- for(y=0; y<16; y++)
- WriteLcd(Line1[y],1);
- WriteLcd(0xc0,0); //设定第二行地址
- for(y=0; y<16; y++)
- WriteLcd(Line2[y],1);
- }
- void init() //初始化函数
- {
- TMOD=0x01; //设T0为方式1,GATE=1;
- TH0=0;
- TL0=0;
- ET0=1; //允许T0中断
- EA=1; //开启总中断
- }
- void keyscan() //键扫描函数
- {
- if(Resets_Key==0) //复位清零键
- {
- Delayms(5);
- if(Resets_Key==0)
- {
- while(Resets_Key==0);
- flag_clear=1;
- }
- }
- if(Single_Key==0) //单次测量键
- {
- Delayms(5);
- if(Single_Key==0)
- {
- while(Single_Key==0);
- flag_one=1;
- flag_con1=0;
- flag_con2=0;
- flag_clear=0;
- }
- }
- if(Contin_Key==0) //连续瞬时测量键
- {
- Delayms(5);
- if(Contin_Key==0)
- {
- while(Contin_Key==0);
- flag_con1=~flag_con1;
- if(flag_con1==1)
- {
- flag_one=0;
- flag_con2=0;
- flag_clear=0;
- }
- }
- }
- if(Averag_Key==0) //连续平均测量键
- {
- Delayms(5);
- if(Averag_Key==0)
- {
- while(Averag_Key==0);
- flag_con2=~flag_con2;
- if(flag_con2==1)
- {
- flag_one=0;
- flag_con1=0;
- flag_clear=0;
- }
- }
- }
- if(Setting_Key==0) //自动和手动转换键
- {
- Delayms(5);
- if(Setting_Key==0)
- {
- while(Setting_Key==0);
- flag_temp=~flag_temp;
- }
- }
- if(Add_Key==0) //温度减键
- {
- Delayms(5);
- if(Add_Key==0)
- {
- while(Add_Key==0);
- if(flag_temp==1)
- {
- temp++;
- if(temp>=50)
- temp=50;
- }
- }
- }
- if(Sub_Key==0) //温度加键
- {
- Delayms(5);
- if(Sub_Key==0)
- {
- while(Sub_Key==0);
- if(flag_temp==1)
- {
- if(temp>0)
- temp--;
- if(temp<=0)
- temp=0;
- }
- }
- }
- }
- void StartModule() //启动模块函数(触发一次,提供大于10us的高电平)
- {
- Trig=1; //启动一次模块
- Delayus(15); //延时2i+5=35us
- Trig=0;
- }
- void Conut(void) //测量计算函数
- {
- time=TH0*256+TL0;
- TH0=0;
- TL0=0;
- V=(331.4+temp*0.607); //由温度计算速度值,单位是m/s
- S=(uint)(time*V/2000); //算出来是mm
- if(flag_con2==1) //如果是连续测量,则取10次的平均值
- {
- if(k<=10)
- k++;
- if(k>=11)
- k=1;
- Sav[k]=S;
- j++;
- if(j<10)
- S1=S;
- if(j>=10)
- {
- j=10;
- for(m=1;m<=10;m++)
- totle=totle+Sav[m];
- S1=(uint)(totle/10); //取10次的平均值
- totle=0;
- }
- }
- if(flag_one==1||flag_con1==1) //如果是单次测量或连续瞬时测量,则取1次的值
- {
- S1=S;
- }
- }
- void Delayus(uchar xus) //晶振为12MHz,延时时间为2i+5 us
- {
- while(--xus);
- }
- bit Init_DS18B20(void)
- {
- bit x;
- DQ=1;
- DQ=0;
- Delayus(250);
- DQ=1;
- Delayus(20);
- if(!DQ) x=0;
- else x=1;
- Delayus(250);
- DQ=1;
- return x;
- }
- //读DS18B20函数
- uchar Read_DS18B20(void)
- {
- uchar i=0,Dat=0;
- for(i=0;i<8;i++)
- {
- DQ=1;
- DQ=0;
- Dat>>=1;
- DQ=1;
- if(DQ) Dat |= 0x80;
- DQ=1;
- Delayus(30);
- }
- return Dat;
- }
- //写DS18B20函数
- void Write_DS18B20(uchar Dat)
- {
- uchar i=0;
- for(i=0;i<8;i++)//循环8次,写入一个字节
- {
- DQ=1;//未发送前的状态
- Dat >>= 1;//将要传送的最低位放入CY
- DQ=0;//将总线拉低,产生写时序
- DQ=CY;//将要传送的位状态送到总线上
- Delayus(30);//延时50us,即保持总线状态,待DS18B20采样
- DQ=1;//恢复期,总线置1
- }
- }
- void GetTemp(void) //获取温度函数
- {
- uchar a=0,b=0;
- Init_DS18B20();
- Write_DS18B20(0xcc); //跳过ROM
- Write_DS18B20(0x44); //开启温度转换
- Init_DS18B20();
- Write_DS18B20(0xcc); //跳过ROM
- Write_DS18B20(0xbe); //读暂存器
- a=Read_DS18B20(); //读取高速暂存字节0,温度低8位
- b=Read_DS18B20(); //读取高速暂存字节1,温度高8位
- temp=b;
- temp<<=8;
- temp=temp|a; //将高、低位温度编码合在一起
- if(b>=8) //判断温度值是否为负,如果温度高字节大于等于8说明温度值为负
- {
- temp=~temp+1; //将补码转换成原码
- Temp_Flag=1; //温度标志为1,表示温度为负
- }
- else
- {
- Temp_Flag=0; //温度标志为0,表示温度为正
- }
- temp=temp*0.0625+0.5;//将温度编码转换成温度值,加0.5是为了四舍五入
- }
- void CalcTestTemp() //温度处理函数
- {
- if(temp<100) Line1[2]=' '; //如果温度值小于10,十位显示空白(不显示0)
- else Line1[2]=temp%100/10+0x30; //取温度十位并转换成ASCII码
- Line1[3]=temp%10+0x30; //取温度个位并转换成ASCII码
- }
复制代码
|
评分
-
查看全部评分
|