《51单片机超声波测距离(带温度补偿)(共19页).doc》由会员分享,可在线阅读,更多相关《51单片机超声波测距离(带温度补偿)(共19页).doc(19页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、精选优质文档-倾情为你奉上超声波模块原理图: 发射 接收原理图PCB:51单片机原理图:软件部分C语言程序:/*= 调试要求: 1.MCU:AT89S52芯片或AT89C52 2.晶振:12MHz 调试注意: 本程序带温度补偿,采用DS18B20测量温度 1.LCD1602液晶屏有显示后,才接入超声波模块。 2.注意超声波模块电源的极性。不清楚请参好淘宝的电路图 3.没有选用频率为12MHz晶振,用了别的频率晶振,单片机定时器的测量值与 发出的40KHz频率脉冲不对。 4.使用者经常误发出20KHZ脉冲当40KHZ脉冲。(40KHz频率脉冲,周期25us, 占空比为50% = 12.5us)
2、5.如果是用开发板调超声波模块,请检查开发板上的电路是否与超声波模块的 控制脚复用了, 若复用了,请通过跳线分开发板上的电路。 6如果使用的是万用板,请确定单片机的复位电路和晶振电路是否正常,同时 单片机的31脚(EA)记得 接高电平。=*/#include #include #define uchar unsigned char#define uint unsigned int/=LCD1602接口定义=/*- |DB0-P2.0 | DB4-P2.4 | RW-P0.1 | |DB1-P2.1 | DB5-P2.5 | RS-P0.2 | |DB2-P2.2 | DB6-P2.6 | E-
3、P0.0 | |DB3-P2.3 | DB7-P2.7 | 注意,P0.0到P0.2需要接上拉电阻 -=*/#define LCM_Data P2 /数据接口#define Busy 0x80 /用于检测LCM状态字中的Busy标识sbit LCM_RW = P01; /读写控制输入端,LCD1602的第五脚sbit LCM_RS = P02; /寄存器选择输入端,LCD1602的第四脚sbit LCM_E = P00; /使能信号输入端,LCD1602的第6脚/=超声波模块定义=sbit RemPin = P32;/ 接收端(这个不能修改,因为是外部中断(INT0)的引脚)sbit TxPi
4、n = P31;/ 发射端 /*/ds18b20数字温度传感器控制引脚定义 sbit dq_ds18b20=P33;/定义控制DS18B20/*/LCD显示模块的函数声明void WriteDataLCM(uchar WDLCM);/LCD模块写数据void WriteCommandLCM(uchar WCLCM,BuysC); /LCD模块写指令uchar ReadDataLCM(void);/LCD模块读数据uchar ReadStatusLCM(void);/读LCD模块的忙标void DisplayOneChar (uchar X,uchar Y,uchar ASCII);/在第X+1
5、行的第Y+1位置显示一个字符void DisplayListChar (uchar X,uchar Y,uchar delayms,uchar code *DData);void DisplayCursorPos (uchar X, uchar Y);void LCMInit (void);void DisplayIntData (uchar X, uchar Y,int ZhengShu,uchar Digit,uchar XiaoShu);void DisplayCharData (uchar X, uchar Y,uchar ZiFu);/*/延时函数声明void delay25us_4
6、0KHz(unsigned char us);void DelayUs(uint us);void DelayMs(uint Ms);void delay_3us();/3US的延时程序void delay_8us(unsigned int t);/8US延时基准程序void delay_50us(unsigned int t);/延时50*T微妙函数的声明/*/DS18B20测温函数定义void w_1byte_ds18b20(uchar value);/向DS18B20写一个字节 uchar r_1byte_ds18b20(void);/从DS18B20读取一个字节的数据void rest
7、_ds18b20(void);/DS18B20复位程序void readtemp_ds18b20(void);/读取温度 void display_temp(void);/温度显示程序/*/参数定义uint length = 0; / 测距的长度0.00Muchar flag = 0; / 测距的标志有信号接收=1uchar templ,temph;uint speed;/根据温度计算出来的声音速度uchar t_b,t_s,t_g,t_x;/从左到右分别存储温度百位,十位,个位,小数位uchar flag1;/温度正负性暂存,1为正数,0为负数const unsigned char tabl
8、3=0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x04,0x05,0x06,0x06,0x07,0x08,0x08,0x09,0x09; /*= 主程序=*/void main(void) uchar i; LCMInit(); /1602初始化 EX0 = 1; /允许总中断中断,使能 INT0 外部中断 ET0 = 1; TMOD=0x11; /设定T0为16位时器,设定T1为16位时器 DisplayOneChar( 0,14,m); DisplayListChar(0,0,0, Distanc: ); /显示字符串 while(1) readtemp_ds1
9、8b20(); display_temp();/显示温度 for(i=0;i20;i+) DisplayIntData(0, 13,length,5,3);/显示测量距离 TH0=0x00; TL0=0x00; TR0=1; /启动定时器0 EA = 1; /允许所有中断 delay25us_40KHz(15); /发出脉冲信号 DelayMs(200); /*/温度显示函数void display_temp() if(flag1=1)/温度为正数时的显示程序 DisplayOneChar( 1,2,+); else DisplayOneChar( 1,2,-); /显示温度信息 Displa
10、yOneChar( 1,0,T); DisplayOneChar( 1,1,:); DisplayOneChar( 1,3,t_s+0x30); DisplayOneChar( 1,4,t_g+0x30); DisplayOneChar( 1,5,.); DisplayOneChar( 1,6,t_x+0x30); /显示速度信息 DisplayOneChar( 1,8,S); DisplayOneChar( 1,9,:); DisplayOneChar( 1,10,speed/100%10+0x30); DisplayOneChar( 1,11,speed/10%10+0x30); Disp
11、layOneChar( 1,12,speed%10+0x30); DisplayOneChar( 1,13,M); DisplayOneChar( 1,14,/); DisplayOneChar( 1,15,S);/*/读取温度 void readtemp_ds18b20(void) uchar temp32; rest_ds18b20(); w_1byte_ds18b20(0xcc); /跳过读序列号的操作 w_1byte_ds18b20(0x44); /启动温度转换 delay_8us(2); rest_ds18b20(); w_1byte_ds18b20(0xcc); /跳过读序列号的操
12、作 w_1byte_ds18b20(0xbe); /读取温度寄存器等(共可读9个寄存器) 前两个就是温度 templ=r_1byte_ds18b20(); temph=r_1byte_ds18b20(); if(temph&0xf0)/判断温度的正负性 flag1=0; temph=-temph; templ=-templ; t_x=tabl3templ & 0x0f;/计算温度的小数 temp32=temph & 0x0f; temp32=4; temp32=temp32 | templ; t_b=temp32/100%10;/计算温度的百位数据 t_s=temp32/10%10;/计算温度
13、的十位数据 t_g=temp32%10;/计算温度的个位数据 speed=331.4-0.607*(temp32 | templ); else/为正数 t_x=tabl3templ & 0x0f;/计算温度的小数 temp32=temph & 0x0f; temp32=4; temp32=temp32 | templ; t_b=temp32/100%10;/计算温度的百位数据 t_s=temp32/10%10;/计算温度的十位数据 t_g=temp32%10;/计算温度的个位数据 flag1=1; speed=311.4+0.607*(temp32 | templ); /*= 功 能: 在16
14、02显示一个整数数据 说 明: 显示一个整数数据-9999-32625. 从右至左显示数据5位: =*/void DisplayIntData(uchar X, uchar Y,int ZhengShu,uchar Digit,uchar XiaoShu) uchar i=0,k=0, BCD5=0; if(Digit5) Digit=5; if(ZhengShu0) k=1;/负数示志位 ZhengShu=-ZhengShu; BCD4 = ZhengShu / 10000; /求出万位数据 ZhengShu = ZhengShu % 10000; BCD3 = ZhengShu / 100
15、0; /求出千位数据 ZhengShu = ZhengShu % 1000; BCD2 = ZhengShu / 100; /求出百位数据 ZhengShu = ZhengShu % 100; BCD1 = ZhengShu / 10; /求出十位数据 BCD0 = ZhengShu % 10; /求出个位数据 for(i=0;iDigit;i+)/输出显示的数值 if(i=XiaoShu)&(0!=XiaoShu) DisplayOneChar(X,Y-i,.);/输出小数点 Y= Y-1; DisplayOneChar(X,Y-i,BCDi+0x30); /显示一个字符 if(k=1) D
16、isplayOneChar(X,Y-1,-);/输出负符/*/读一个字节 uchar r_1byte_ds18b20(void) uchar i=0; uchar value = 0; for (i=0;i=1; dq_ds18b20=0;/ DQ_L; delay_3us(); dq_ds18b20=1; /DQ_H; delay_8us(2); if(dq_ds18b20=1) value|=0x80; delay_8us(6); /延时40us dq_ds18b20=1; return value;/*/子程序功能:向DS18B20写一字节的数据void w_1byte_ds18b20(
17、uchar value) uchar i=0; for(i=0;i=1; dq_ds18b20=1; /DQ = 1/;*/ds18b20复位子程序void rest_ds18b20(void) rest:delay_3us(); /稍做延时 delay_3us(); dq_ds18b20=1; delay_3us(); dq_ds18b20=0;/ DQ_L; delay_50us(11);/480usT190)timer_us=timer_us-180;/修正测距的距离 if(timer_us5059) timer_us+=29; if(timer_us5470) timer_us+=29
18、; if(timer_us6410) timer_us+=29; if(timer_us7410) timer_us+=29; if(timer_us8410) timer_us+=29; if(timer_us9410) timer_us+=29; if(timer_us10410) timer_us+=29; length = (unsigned long)(speed)*timer_us)/2000;/计算长度,是扩大100倍flag = 0;EA = 0; /禁止所有中断/*= 功 能:在1602显示一个字符数据 说 明:显示一个字符数据0256. 从左至右显示数据3位=*/void
19、DisplayCharData(uchar X, uchar Y,uchar ZiFu) uchar i=0; uchar ValueBCD3; ValueBCD0 = ZiFu / 100; /求出百位数据 ZiFu = ZiFu % 100; ValueBCD1 = ZiFu / 10; /求出十位数据 ValueBCD2 = ZiFu % 10; /求出个位数据 for(i=0;i3;i+)/输出显示的数值 DisplayOneChar(X,Y+i,ValueBCDi+0x30); /显示一个字符 /*= 超出测量时间=*/void timer0int (void) interrupt
20、1 TR0=0; /关闭定时器0length = 0; /超出测量时间显示示0 flag = 1; /EA = 0; /禁止所有中断 /*= LCM初始化=*/void LCMInit(void) LCM_Data = 0; WriteCommandLCM(0x38,0); /三次显示模式设置,不检测忙信号 DelayMs(5); WriteCommandLCM(0x38,0); DelayMs(5); WriteCommandLCM(0x38,0); DelayMs(5); WriteCommandLCM(0x38,1); /显示模式设置,开始要求每次检测忙信号 WriteCommandLC
21、M(0x08,1); /关闭显示 WriteCommandLCM(0x01,1); /显示清屏 WriteCommandLCM(0x06,1); / 显示光标移动设置 WriteCommandLCM(0x0C,1); / 显示开及光标设置 DelayMs(100);/*= 显示光标的位置=*/void DisplayCursorPos( unsigned char X, unsigned char Y) X &= 0x1; Y &= 0xF; /限制Y不能大于15,X不能大于1 if (X) Y |= 0x40; /当要显示第二行时地址码+0x40; Y |= 0x80; / 算出指令码 Wr
22、iteCommandLCM(Y, 1); /这里不检测忙信号,发送地址码/*= 按指定位置显示一串字符:第 X 行,第 y列 注意:字符串不能长于16个字符=*/void DisplayListChar(uchar X,uchar Y,uchar delayms, uchar code *DData) unsigned char ListLength; ListLength = 0; X &= 0x1; Y &= 0xF; /限制X不能大于15,Y不能大于1 while (DDataListLength!=0) /若到达字串尾则退出 if (Y = 0xF) /X坐标应小于0xF Displa
23、yOneChar(X, Y, DDataListLength); /显示单个字符 ListLength+; Y+; DelayMs(delayms);/延时显示字符串 else break;/跳出循环体 /*= 设定延时时间:x*1us=*/void DelayUs(uint us) while(us-); /*= 设定延时时间:x*1ms=*/void DelayMs(uint Ms) uint i,TempCyc; for(i=0;iMs;i+) TempCyc = 250; while(TempCyc-); /=LCD1602显示子程序= /*= 写数据函数: E =高脉冲 RS=1 R
24、W=0=*/void WriteDataLCM(unsigned char WDLCM) ReadStatusLCM(); /检测忙 LCM_Data = WDLCM; LCM_RS = 1; LCM_RW = 0; LCM_E = 0; /若晶振速度太高可以在这后加小的延时 LCM_E = 0; /延时 LCM_E = 1;/*= 写指令函数: E=高脉冲 RS=0 RW=0=*/void WriteCommandLCM(unsigned char WCLCM,BuysC) /BuysC为0时忽略忙检测 if (BuysC) ReadStatusLCM(); /根据需要检测忙 LCM_Dat
25、a = WCLCM; LCM_RS = 0; LCM_RW = 0; LCM_E = 0; LCM_E = 0; LCM_E = 1;/*=/读数据=*/unsigned char ReadDataLCM(void) LCM_RS = 1; LCM_RW = 1; LCM_E = 0; LCM_E = 0; LCM_E = 1; return(LCM_Data);/*= 正常读写操作之前必须检测LCD控制器状态:E=1 RS=0 RW=1; DB7: 0 LCD控制器空闲,1 LCD控制器忙。 读状态=*/unsigned char ReadStatusLCM(void) LCM_Data = 0xFF; LCM_RS = 0; LCM_RW = 1; LCM_E = 0; LCM_E = 0; LCM_E = 1; while (LCM_Data & Busy); /检测忙信号 return(LCM_Data);/*=功 能: 在1602 指定位置显示一个字符:第一行位置015,第二行1631说 明: 第 X 行,第 y 列 注意:字符串不能长于16个字符=*/void DisplayOneChar( unsigned char X, unsigned char Y, unsigned char ASCII) X &= 0x1
限制150内