|
#include<reg52.h>
#include <intrins.h>
typedef unsigned char uchar;
typedef unsigned int uint;
#define L_go IN1=0;IN2=1 //左輪前進(jìn)
#define L_back IN1=1;IN2=0 //左輪后退
#define L_stop IN1=0;IN2=0 //左輪停止
#define R_go IN3=0;IN4=1 //右輪前進(jìn)
#define R_back IN3=1;IN4=0 //右輪后退
#define R_stop IN3=0;IN4=0 //右輪停止
sbit Echo=P3^2;//超聲波模塊的回響信號輸出,P3^2也是51單片機(jī)外部中斷0的輸入端,利用下降沿來觸發(fā)中斷
sbit Trig=P3^3;//觸發(fā)信號腳
sbit IN1 =P3^4;
sbit IN2 =P3^5;
sbit IN3 =P3^6;
sbit IN4 =P3^7;
sbit lcdrs=P1^0;//數(shù)據(jù)命令選擇端,為0時寫指令,為1時寫數(shù)據(jù)
sbit lcdrw=P1^1;//讀、寫命令選擇端,為0時寫數(shù)據(jù),為1時讀數(shù)據(jù),讀狀態(tài)時置1,其他時間都是0;
sbit lcden=P2^5;//使能端
sbit dula=P2^6;//在這段程序里沒有用處
sbit wela=P2^7;
sbit STA7=P0^7;//D0~D7數(shù)據(jù)口對應(yīng)P0^0~P0^7,當(dāng)讀液晶的數(shù)據(jù)時,STA7對應(yīng)P0^7,STA7為1時表示液晶忙,無法接收數(shù)據(jù)
float dis;//距離的緩存
uchar flag;//中斷標(biāo)志位
char code table[]="distance:";//在規(guī)定位置顯示字符
char code table1[]="cm";
void delayms(uchar x)
{
uint i,j;
for(i=0;i<x;i++)
{
for(j=0;j<110;j++);
}
}
void nops()//延時10.9us,每個機(jī)器周期約1.09us,在晶振為11.0592MHz時
{
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
}
void distance()//計算距離的函數(shù)
{
Trig=0;//首先將觸發(fā)拉低
nops();
Trig=1;//給至少10us的高電平,啟動模塊
nops();
nops();
Trig=0;//此時已經(jīng)觸發(fā)了模塊,接下來立刻開啟定時器計數(shù)
TR0=1;//打開定時器0
EX0=1;//打開外部中斷,外部中斷輸入為P3^2,下降沿有效,觸發(fā)中斷
delayms(1);//等待一下,一個機(jī)器周期約為1.09us,如果不等待,可能就錯過計算dis,陷入死循環(huán),永遠(yuǎn)無法得出值
if(flag==1)//如果標(biāo)志位置1,表示Echo輸出下降沿,即接收結(jié)束
{
flag=0;
}
}
void wait()//等待液晶空閑
{
P0=0xff;
do
{
lcdrs=0;//循環(huán)里的這些語句是讀狀態(tài)時的操作時序
lcdrw=1;
lcden=0;
lcden=1;
}while(STA7==1);//等液晶空閑的時候再出循環(huán)
lcden=0;//使使能為0
}
void write_com(uchar com)//寫命令程序
{
wait();
lcdrs=0;//使RS為0,發(fā)出的數(shù)據(jù)會被液晶當(dāng)做命令而不是現(xiàn)實數(shù)據(jù),這也是與寫數(shù)據(jù)程序的唯一不同
P0=com;
lcdrw=0;//總是寫的,故為0
delayms(5);//使數(shù)據(jù)平穩(wěn),讓液晶有時間讀取
lcden=1;//根據(jù)操作時序,使能要輸出高脈沖,這句與后面那句共同構(gòu)成一個高脈沖
delayms(5);
lcden=0;
}
void write_date(uchar date)//寫數(shù)據(jù)程序
{
wait();
lcdrs=1;//注意這是寫數(shù)據(jù)
P0=date;
lcdrw=0;
delayms(5);
lcden=1;
delayms(5);
lcden=0;
}
/*初始化函數(shù)*/
void init()
{
wait();
dula=0;//沒用
wela=0;
lcden=0;
write_com(0x38);//設(shè)置16*2顯示,5*7點陣,8位數(shù)據(jù)口。這句是不變的
write_com(0x0c);//根據(jù)操作時序設(shè)置的狀態(tài)字。下面一樣
write_com(0x06);
TMOD=0x21;//16位計數(shù)器,這里不用開啟定時器中斷,因為定時器中斷無事可做,只要定時器里的值就行,因此無需將TF0置1
TH0=0;//全部設(shè)為0
TL0=0;
IT0=1;//設(shè)置外部中斷下降沿有效
EA=1;//開總中斷
}
/*顯示函數(shù)*/
void display(float dis)
{
uint bai,shi,ge,p1,p2;//分別是百位一次向下,到小數(shù)點后兩位
bai=dis/100;
shi=(dis-bai*100)/10;
ge=dis-bai*100-shi*10;
p1=(dis*10)-bai*1000-shi*100-ge*10;
p2=(dis*100)-bai*10000-shi*1000-ge*100-p1*10;
write_date(0x30+bai);//將數(shù)字轉(zhuǎn)換為字符,必須+0x30,另外,1602液晶只能接收字符型的數(shù)據(jù)
write_date(0x30+shi);
write_date(0x30+ge);
write_date('.');
write_date(0x30+p1);
write_date(0x30+p2);
}
void csbbz()
{
uchar i=0;
init();
write_com(0x80);//設(shè)置地址,在第一行第一列顯示distance:,0x80是第一行的起始地址
while(table[ i]!='\0')[ i]
{
write_date(table[ i]);[ i]
i++;
delayms(5);
}
i=0;
write_com(0x80+0x40+6);//設(shè)置地址,在第二行第7位顯示cm,0x80+0x40是第二行的起始地址
while(table1[ i]!='\0')[ i]
{
write_date(table1[ i]);[ i]
i++;
delayms(5);
}
while(1)
{
distance();
write_com(0x80+0x40);//設(shè)置數(shù)據(jù)的顯示地址,為第二行的起始位,之后在進(jìn)行循環(huán)時不斷刷新在這個地方顯示
display(dis);
delayms(60);
}
}
void ex() interrupt 0//外部中斷的中斷函數(shù)
{
TR0=0;//一旦受到下降沿,立馬停止定時器計數(shù)
dis=(TH0*256+TL0)*1.09/58;//先取出定時器里的時間值,之后再將定時器置0
flag=1;//將標(biāo)志位置0
TH0=0;
TL0=0;
}
void UsartConfiguration();
void Delay_1ms(uint i);
/********************************************************************
* 名稱 : Com_Int()
* 功能 : 串口中斷子函數(shù)
* 輸入 : 無 * 輸出 : 無
***********************************************************************/
void Com_Int(void) interrupt 4
{
uchar i;
uchar receive_data;
EA = 0;
if(RI == 1) //當(dāng)硬件接收到一個數(shù)據(jù)時,RI會置位
{
RI = 0;
receive_data = SBUF;//接收到的數(shù)據(jù)
if(receive_data == 'A')
{
L_go;
R_go;
}
if(receive_data == 'B')
{
R_back;
L_back;
}
if(receive_data == 'C')
{
L_stop;
R_stop;
}
if(receive_data == 'D')
{
L_back;
R_go;
}
if(receive_data == 'E')
{
L_go;
R_back;
}
}
for(i=0; i<36; i++)
{
SBUF = '1'; //將要發(fā)送的數(shù)據(jù)放入到發(fā)送寄存器
while(!TI); //等待發(fā)送數(shù)據(jù)完成
TI=0; //清除發(fā)送完成標(biāo)志位
Delay_1ms(1);
}
EA = 1;
}
/*******************************************************************************
* 函 數(shù) 名 : main
* 函數(shù)功能 : 主函數(shù)
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
void main()
{
PS=1;
PX0=0;
UsartConfiguration();
csbbz();
while(1);
}
void UsartConfiguration()
{
SCON=0X50; //設(shè)置為工作方式1,8位數(shù)據(jù),可變波特率
TMOD=0X21; //設(shè)置計數(shù)器工作方式2
PCON=0X00; //波特率不加倍
TH1=0XFd; //計數(shù)器初始值設(shè)置,9600@11.0592MHz
TL1=0XFd;
TR1=1; //打開計數(shù)器
ES = 1; //開串口中斷
EA = 1; //開總中斷
}
void Delay_1ms(uint i)//1ms延時
{
uchar x,j;
for(j=0;j<i;j++)
for(x=0;x<=148;x++);
}
|
|