#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++);
}
|