二年级课设做了超声波测障仪,用的是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;
}
硬件仿真图如下:
希望对你有些帮助。。。