基于52单片机的超声波测距模块(hc-sr04超声波测距模块+1602液晶显示器)

二年级课设做了超声波测障仪,用的是hc-sr04超声波测距模块+1602液晶显示器和52单片机。

由于自己之前的学习很是不牢固,在课设的时候没少走弯路,最后在第二个周的星期五做了出来,浪费了很多的时间,所以就想着把这个东西写出来,一则加强自己的理解,二则或许能帮助帮助别人。


HC-SR04超声波模块工作原理

 1).采用IO口触发测距,给至少10us高电平脉冲;

 2).模块自动发送八个40khz方波,并自主检测是否有电波返回;

  3)当有信号返回时,通过IO口输出一个高电平,高电平的持续时间就是超声波从发送到返回的时间;

  4)测距公式:距离=(高电平时间*声速)/2;

  5)超声波模块时序图如图6所示:


6:超声波模块时序图

(模块的原理很重要,只有把原理弄懂了才能很好地做出来你想要的东西)

程序的核心在于中断,即单片机内部的计数器中断。

具体的程序分为两个部分:1602显示部分和主程序(见下)

1602程序,基本上都是一些简单的时序问题。

首先对1602进行初始化,定义1602对应接口的接线方式。然后进行写命令,写数据操作,最后将得到的距离数(3位数,以cm为单位)按照个十百分为三个单独的数字输出到液晶显示器上,最后输出单位cm。

#include "lcd.h"

/*******************************************************************************
* 函 数 名         : Lcd1602_Delay1ms
* 函数功能    : 延时函数,延时1ms
* 输    入         : c
* 输    出         : 无
* 说    名         : 该函数是在12MHZ晶振下,12分频单片机的延时。
*******************************************************************************/


void Lcd1602_Delay1ms(uint c)   //误差 0ms
{
    uchar a,b;
for (; c>0; c--)
{
for (b=199;b>0;b--)
{
  for(a=1;a>0;a--);
}      
}
   
}


/*******************************************************************************
* 函 数 名         : LcdWriteCom
* 函数功能    : 向LCD写入一个字节的命令
* 输    入         : com
* 输    出         : 无
*******************************************************************************/
#ifndef LCD1602_4PINS //当没有定义这个LCD1602_4PINS时
void LcdWriteCom(uchar com)   //写入命令
{
LCD1602_E = 0;     //使能
LCD1602_RS = 0;    //选择发送命令
LCD1602_RW = 0;    //选择写入

LCD1602_DATAPINS = com;     //放入命令
Lcd1602_Delay1ms(1); //等待数据稳定


LCD1602_E = 1;           //写入时序
Lcd1602_Delay1ms(5);   //保持时间
LCD1602_E = 0;
}
#else 
void LcdWriteCom(uchar com)   //写入命令
{
LCD1602_E = 0; //使能清零
LCD1602_RS = 0; //选择写入命令
LCD1602_RW = 0; //选择写入


LCD1602_DATAPINS = com; //由于4位的接线是接到P0口的高四位,所以传送高四位不用改
Lcd1602_Delay1ms(1);


LCD1602_E = 1; //写入时序
Lcd1602_Delay1ms(5);
LCD1602_E = 0;


LCD1602_DATAPINS = com << 4; //发送低四位
Lcd1602_Delay1ms(1);


LCD1602_E = 1; //写入时序
Lcd1602_Delay1ms(5);
LCD1602_E = 0;
}
#endif
/*******************************************************************************
* 函 数 名         : LcdWriteData
* 函数功能    : 向LCD写入一个字节的数据
* 输    入         : dat
* 输    出         : 无
*******************************************************************************/    
#ifndef LCD1602_4PINS    
void LcdWriteData(uchar dat) //写入数据
{
LCD1602_E = 0; //使能清零
LCD1602_RS = 1; //选择输入数据
LCD1602_RW = 0; //选择写入


LCD1602_DATAPINS = dat; //写入数据
Lcd1602_Delay1ms(1);


LCD1602_E = 1;   //写入时序
Lcd1602_Delay1ms(5);   //保持时间
LCD1602_E = 0;
}
#else
void LcdWriteData(uchar dat) //写入数据
{
LCD1602_E = 0;   //使能清零
LCD1602_RS = 1;   //选择写入数据
LCD1602_RW = 0;   //选择写入


LCD1602_DATAPINS = dat; //由于4位的接线是接到P0口的高四位,所以传送高四位不用改
Lcd1602_Delay1ms(1);


LCD1602_E = 1;   //写入时序
Lcd1602_Delay1ms(5);
LCD1602_E = 0;


LCD1602_DATAPINS = dat << 4; //写入低四位
Lcd1602_Delay1ms(1);


LCD1602_E = 1;   //写入时序
Lcd1602_Delay1ms(5);
LCD1602_E = 0;
}
#endif
/*******************************************************************************
* 函 数 名       : LcdInit()
* 函数功能 : 初始化LCD屏
* 输    入       : 无
* 输    出       : 无
*******************************************************************************/    
#ifndef LCD1602_4PINS
void LcdInit()   //LCD初始化子程序
{
  LcdWriteCom(0x38);  //开显示
LcdWriteCom(0x0c);  //开显示不显示光标
LcdWriteCom(0x06);  //写一个指针加1
LcdWriteCom(0x01);  //清屏
LcdWriteCom(0x80);  //设置数据指针起点
}
#else
void LcdInit()   //LCD初始化子程序
{
LcdWriteCom(0x32); //将8位总线转为4位总线
LcdWriteCom(0x28); //在四位线下的初始化
LcdWriteCom(0x0c);  //开显示不显示光标
LcdWriteCom(0x06);  //写一个指针加1
LcdWriteCom(0x01);  //清屏
LcdWriteCom(0x80);  //设置数据指针起点
}

#endif


主程序:主程序的核心在于中断

首先对于单片机的IO口进行初始化,1602液晶显示器的初始化,超声波模块的初始化。初始化的同时打开了定时器,同时内部中断打开并开始计数操作,待超声波的输入端接收到返回波之后关闭内部中断,停止计数,接下来通过记到的时间计算被测物的距离(s=time*340/2m)。

/**************************************************************************************
*               LCD1602液晶显示超声波测试的距离   *
实现现象:下载程序后插上LCD1602液晶在开发板上,即可显示
  
***************************************************************************************/


#include "reg52.h" //此文件中定义了单片机的一些特殊功能寄存器
#include "lcd.h"
#include "intrins.h"


typedef unsigned int u16;   //对数据类型进行声明定义
typedef unsigned char u8;


sbit Trig = P2^1;
sbit Echo = P2^0; 


sbit key =P1^1; 
sbit key1 = P3^2;
sbit led = P1^0;


u16 time = 0,S = 0; 


/*******************************************************************************
* 函 数 名         : main
* 函数功能    : 主函数
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/


void Time_Init()
{
TMOD=0x01;    //设T0为方式1,GATE=1;
TH0=0;
TL0=0;  
EA=1;
TR0 = 0;        
}  

void Conut(void)
{
  Trig=1;                      //启动一次模块
  _nop_(); 
  _nop_(); 
  _nop_(); 
  _nop_(); 
  _nop_(); 
  _nop_(); 
  _nop_(); 
  _nop_(); 
  _nop_(); 
  _nop_(); 
  _nop_(); 
  _nop_(); 
  _nop_(); 
  _nop_(); 
  _nop_(); 
  _nop_();
  Trig=0;
  while(!Echo);
      TR0=1;    
  while(Echo);
    TR0=0; 
time=TH0*256+TL0;
TH0=0;
TL0=0;
S=(time*1.7)/100;     //算出来是CM
}


void delayms(u16 xms)
{
u8 i,j;
for(i=0;i<110;i++)
   for(j=0;j<xms;j++);  
}


void main(void)
{
  Time_Init();
  LcdInit();
  while(1)
  {
     Conut();
LcdWriteData((S/100)+0x30);
LcdWriteData((S/10)%10+0x30);
      LcdWriteData((S%10)+0x30);
LcdWriteData('C');
LcdWriteData('M');
delayms(20);
LcdWriteCom(0x80);  //设置数据指针起点
}
}


 void Time0() interrupt 1
 {
    Echo = 1;

 }

硬件仿真图如下:



希望对你有些帮助。。。

猜你喜欢

转载自blog.csdn.net/weixin_40647352/article/details/80791927