二年級課設做了超音波測障儀,用的是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"
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--);
}
}
}
#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
#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
#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)。
#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;
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;
}
硬體仿真圖如下:
希望對你有些幫助。。。