实现机器人避障,测温。
并显示障碍物距离和温度。
超温停止机器人,障碍物距离过小则避障。
Proteus仿真图如下:
物料清单:
Keil代码如下:
#include <reg52.h>
#include <stdio.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
// I/o声明及位、变量定义
sbit L293D_IN1=P0^0;
sbit L293D_IN2=P0^1;
sbit L293D_IN3=P0^2;
sbit L293D_IN4=P0^3;
sbit L293D_EN1=P0^4;
sbit L293D_EN2=P0^5;
sbit key= P3^3;
sbit RX = P1^2;
sbit TX = P1^3;
sbit DQ=P1^5;
sbit led=P1^0;
sbit led1=P3^4;
sbit rs=P3^0;
sbit rw=P3^1;
sbit e=P3^2;
sbit beep=P0^7;
bit flag =0;//量程溢出标志位
int temp=0,temp1=0;//temp为温度的整数部分,temp1为温度的小数部分
uint time=0;//用于存放定时器的时间值
unsigned long S=0;//用于存放距离的值
//函数声明
void delay(uint t);
uchar init_ds18b20();
void write_byte(uchar dat);
uchar read_byte(void);
char read_tem(void);
void write_com(uchar com);
void write_dat(uchar dat);
void lcdinit();
void Count(void);//距离计算函数
void Delay1ms(uint i);
void Delay10us(uchar i);
void Forward();//前进
void Stop(void);//刹车
void Turn_Retreat();//后
void Turn_left();//左转
void Turn_right();//右转
void Timer_Count(void);
void StartModule();//启动模块
//主函数
void main(void)
{
uint a,bflag=0;
uchar n;
lcdinit();//屏幕初始化
TMOD=0x01;//定时器初始化
TX=0;
EA=1;
TH0=0;
TL0=0;
ET0=1;
n=init_ds18b20(); //18b20初始化
if(n)
led=0;
temp=read_tem();
while(temp==85)
{
temp=read_tem();
}
temp=0;
while(1)
{
if(key==0)
{
led=1;
led1=1;
RX=1;
StartModule();
for(a=951;a>0;a--)
{
if(RX==1)
{
Timer_Count();
}
}
temp=read_tem(); //温度值的整数部分,显示温度
if(temp>=0) //正温度+0
{
write_com(0x80+8);
write_dat(0xdf); //显示温度符号
write_dat(0x43); //显示温度符号
Delay1ms(5);
write_com(0x80+3);
write_dat(' ');
write_dat(0x30+temp/10); //显示温度的十位
write_dat(0x30+temp%10); //显示温度的个位
write_com(0x80+6);
write_dat('.');
write_dat(0x30+temp1); //显示小数部分
}
else //负温度
{
write_com(0x80+8);
write_dat(0xdf); //显示温度符号
write_dat(0x43); //显示温度符号
Delay1ms(5);
write_com(0x80+3);
write_dat('-');
write_dat(0x30+(-1*temp)/10); //显示温度的十位
write_dat(0x30+(-1*temp)%10); //显示温度的个位
write_com(0x80+6);
write_dat('.');
write_dat(0x30+temp1); //显示小数部分
}
//距离显示
write_com(0x40+0x80+8); //显示超声波距离
write_dat(0x43); //显示距离符号
write_dat(0x4D); //显示距离符号
Delay1ms(5);
write_com(0x40+0x80+4);
write_dat(0x30+S/100); //显示距离的百位
write_dat(0x30+S/10%10); //显示距离的十位
write_dat(0x30+S%10); //显示距离的个位
if(temp<50 && temp>-10)
{
Forward(); //前进条件
if(S<=20) //设定超声波采集模块距离范围
{
beep=0;
Stop();
Delay1ms(2000); //停
Turn_Retreat();
Delay1ms(2000); //退
Stop();
Delay1ms(1500); //停
Turn_left();
Delay1ms(2000); //转 避障
beep=1;
}
}
if(temp>=50||temp<=-10) //判断采集到的温度是否达到上限或下限
{
bflag=1;
if(bflag> 0)
{
beep=0;
Delay1ms(500);
beep=1;
bflag=0;
}
Stop();
}
}
else
{
stop();
led=0;
led1=0;
write_com(0x01);//设置位置
}
}
}
void Delay1ms(uint i) //延时ms
{
uchar j,k;
do{
j = 10;
do{
k = 50;
do{
_nop_();
}while(--k);
}while(--j);
}while(--i);
}
void Delay10us(uchar i) //延时10us
{
uchar j;
do{
j = 10;
do{
_nop_();
}while(--j);
}while(--i);
}
void delay(uint t)//延时
{
while(t--);
}
void Forward()//前进
{
L293D_IN1=1;
L293D_IN2=0;
L293D_IN3=1;
L293D_IN4=0;
}
void Stop()//刹车
{
L293D_IN1=0;
L293D_IN2=0;
L293D_IN3=0;
L293D_IN4=0;
}
void Turn_Retreat()//后退
{
L293D_IN1=0;
L293D_IN2=1;
L293D_IN3=0;
L293D_IN4=1;
}
void Turn_left()//左转
{
L293D_IN1=0;
L293D_IN2=1;
L293D_IN3=1;
L293D_IN4=0;
}
/*
void Turn_right()//右转
{
L293D_IN1=1;
L293D_IN2=0;
L293D_IN3=0;
L293D_IN4=1;
}
*/
void Conut(void)//计算距离
{
time=TH0*256+TL0;
TH0=0;
TL0=0;
S=time*1.7/100+1;
}
void zd0() interrupt 1//T0中断用来计数器溢出,超过测距范围
{
flag=1;
RX=0;
}
void Timer_Count(void)
{
TR0=1; //开启计数
while(RX); //当RX为1计数并等待
TR0=0; //关闭计数
Conut(); //计算
}
void StartModule()//启动模块
{
TX=1;//启动一次模块
Delay10us(2);
TX=0;
}
uchar init_ds18b20()//ds18b20复位初始化
{
uchar n=0;
DQ=1;//DQ复位
delay(8);//稍做延时
DQ=0;//单片机将DQ拉低
delay(80);//600us 精确延时,大于480us
DQ=1;//拉高总线
delay(8);//15us~60us
n=DQ;//初始化成功n=0,失败n=1
delay(4);
return 0;
}
void write_byte(uchar dat)//写字节
{
uchar i;
for(i=0;i<8;i++)
{
DQ=0;//给脉冲信号
DQ=dat&0x01;
delay(4);
DQ=1;
dat=dat>>1;
}
delay(4);
}
uchar read_byte(void)//读字节
{
uchar i,value;
for(i=0;i<8;i++)
{
DQ=0;
value>>=1;
DQ=1; //
if(DQ)
value|=0x80;
delay(4);
}
return value;
}
char read_tem(void)//读取ds18b20当前温度
{
uchar a=0,b=0,temp0=0;
init_ds18b20();
write_byte(0xcc);//跳过读序号列号的操作
write_byte(0x44);//启动温度转换
delay(500);
init_ds18b20();
write_byte(0xcc);
write_byte(0xbe);//读取温度寄存器等(共可读9个寄存器) 前两个寄存器是温度
a=read_byte();//读取温度值低位
b=read_byte();//读取温度值高值
b<<=4;
temp1=(a&0x0f);
temp1=temp1*0.625+0.5;
a>>=4;
temp0=b|a;
return temp0;
}
void write_com(uchar com) //LCD的写指令
{
rs=0;
rw=0;
P2=com;
e=1;
Delay1ms(5);
e=0;
}
void write_dat(uchar dat) //LCD的写数据
{
rs=1;
rw=0;
P2=dat;
e=1;
Delay1ms(5);
e=0;
}
void lcdinit() //1602初始化最大化最小化调整界面
{
Delay1ms(15);
write_com(0x38);//屏幕初始化
Delay1ms(6);
write_com(0x38);
Delay1ms(6);
write_com(0x38);
write_com(0x38);
write_com(0x0c);
write_com(0x06);//当读或写一个字符是指针后一位
write_com(0x01);//设置位置
}