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