集成了红外通信,超声波停车,寻迹,斑马线,迷宫的51单片机智能小车
小车可以通过红外实现小车最基本的前进、倒车、左右转向以及调速
、进入寻迹、迷宫、斑马线、超声波模式
如果接线或者调试方面有问题请联系作者
#include"reg51.h"
#include "intrins.h"
typedef unsigned int u16;
typedef unsigned char u8;
typedef unsigned long u32;
sbit QIN1=P1^0;// P1.0输出pwm
sbit QIN2=P1^1;// P1.1输出pwm
sbit QIN3=P1^2;// P1.2输出pwm
sbit QIN4=P1^3;// P1.3输出pwm
sbit HIN1=P1^4;// P1.4输出pwm
sbit HIN2=P1^5;// P1.5输出pwm
sbit HIN3=P1^6;// P1.6输出pwm
sbit HIN4=P1^7;// P1.7输出pwm
sbit IRIN=P3^2; // 红外口为3.2 中断0
sbit k1=P2^0; //寻迹模块k1位
sbit k2=P2^1; //寻迹模块k2位
sbit k3=P2^2; //寻迹模块k3位
sbit k4=P2^4; //寻迹模块k4位
sbit k5=P2^5; //寻迹模块k5位
sbit Echo = P3^0; //超声波发射端
sbit Trig = P3^1; //超声波接受端
u8 i; // 定义占空比的变量
u16 count,count2,count3,count4; //pwm占空比(速度大小)
u16 read1,read2;
u8 Time;
u8 IrValue[6]; //红外接收数组
u8 m=0,n=2,z=0,x=0;
u8 d=0,b=0,c=0;
u16 tme = 0; //超声波时间变量
u16 s = 0; //超声波测距后的距离
u16 flg = 0;
void StartModule();
void t0();
void Conut();
/********基本延时函数*******/
void delay(int u)
{
while(u--);
}
/****小车转向需要的一些延时函数****/
void delayk2(int i)
{
while(i){
i--;
if((k2==0)||(k3==0)||(k4==0))
i=0; }
}
void delayk3(int p)
{
while(p){
p--;
if(k3==0)
p=0; }
}
void delayk4(int o)
{
while(o){
o--;
if((k4==0)||(k3==0)||(k2==0))
o=0; }
}
void delayk5(int j)
{
while(j){
j--;
if(k3==0||k4==0)
j=0; }
}
void delayk6(int l)
{
while(l){
l--;
if(k3==0||k2==0)
l=0; }
}
void delayk7(int y)
{
while(y){
y--;
if(k1==0||k4==0||k3==0||k5==0||k2==0)
y=0; }
}
/********小车运行状态*******/
void fast_run() //直行
{
count=30;
count2=30;
count3=0;
count4=0;
}
void run() //高速直行
{
count=70;
count2=70;
count3=0;
count4=0;
}
void srun() //中速直行
{
count=50;
count2=50;
count3=0;
count4=0;
}
/****调试后需要的一些特殊转向状态****/
void bit_left()
{
count=30;
count2=0;
count3=0;
count4=45;
}
void bit_right()
{
count=0;
count2=30;
count3=45;
count4=0;
}
void middle_left()
{
count=35;
count2=0;
count3=0;
count4=45;
}
void middle_right()
{
count=0;
count2=35;
count3=45;
count4=0;
}
void left()
{
count=50;
count2=0;
count3=0;
count4=40;
}
void right()
{
count=0;
count2=50;
count3=40;
count4=0;
}
void behind_left()
{
count=40;
count2=0;
count3=0;
count4=50;
}
void behind_right()
{
count=0;
count2=40;
count3=50;
count4=0;
}
void back() //倒退
{
count=0;
count2=0;
count3=30;
count4=30;
}
void zdt() //从左面掉头
{
count=50;
count2=0;
count3=0;
count4=50;
}
void dt() //从右面掉头
{
count=0;
count2=50;
count3=50;
count4=0;
}
void stop() //停车
{
count=0;
count2=0;
count3=0;
count4=0;
}
/******走寻迹的函数****/
void xunji()
{ u8 flag;
if((k1==1)&&(k2==1)&&(k3==1)&&(k4==1)&&(k5==1)) //没检测到,先直行再判断,flag=9时back;
{ z++;
if(z>=80)
{ if(x==1)
{flag=13;
x=0;}
if(x==2)
{ flag=14;
x=0; }
if(x==0);
flag=8;
}
else
flag=0;
}
if((k1==1)&&(k2==1)&&(k3==0)&&(k4==1)&&(k5==1)) //中间感应到,直行
{ flag=0; z=0; }
if((k1==1)&&(k2==0)&&(k3==1)&&(k4==1)&&(k5==1)) //直行发生偏转,微调
{flag=1; z=0;}
if((k1==1)&&(k2==1)&&(k3==1)&&(k4==0)&&(k5==1)) //直行发生偏转,微调
{ flag=2; z=0;}
if((k1==0)&&(k2==1)&&(k3==1)&&(k4==1)&&(k5==1)) //大幅度左转
{flag=9; z=0; }
if ((k1==1)&&(k2==1)&&(k3==1)&&(k4==1)&&(k5==0)) //大幅度右转
{flag=10; z=0;}
if(((k1==1)&&(k2==0)&&(k3==0)&&(k4==0)&&(k5==1))||((k1==1)&&(k2==0)&&(k3==1)&&(k4==0)&&(k5==1))|| ((k1==0)&&(k2==1)&&(k3==1)&&(k4==1)&&(k5==0))|| ((k1==0)&&(k2==1)&&(k3==1)&&(k4==0)&&(k5==1))|| ((k1==1)&&(k2==0)&&(k3==1)&&(k4==1)&&(k5==0))|| ((k1==1)&&(k2==0)&&(k3==0)&&(k4==1)&&(k5==1))|| ((k1==1)&&(k2==1)&&(k3==0)&&(k4==0)&&(k5==1))) //意外情况,往前一点
flag=5;
if((k1==0)&&(k2==0)&&(k3==1)&&(k4==1)&&(k5==1)) //behind左转
flag=6;
if((k1==1)&&(k2==1)&&(k3==1)&&(k4==0)&&(k5==0)) //behind右转
flag=7;
if((k1==0)&&(k3==0)&&(k4==1)&&(k5==1)) //直角转向,左转
{if(k2==0)
flag=3;
else
flag=11; x=1;}
if((k1==1)&&(k2==1)&&(k3==0)&&(k5==0)) //直角转向,右转
{ if(k4==0)
flag=4;
else
flag=12;x=2; }
switch(flag)
{
case(0):{fast_run();break;}
case(1):{bit_left();delayk3(500);break;}
case(2):{bit_right();delayk3(500);break;}
case(3):{delay(350);middle_left();delay(4);delayk2(3000);stop();delay(5);break;}
case(4):{delay(350);middle_right();delay(400);delayk4(3000);stop();delay(5);break;}
case(5):{fast_run();break; }
case(6):{middle_left();delayk3(500);break;}
case(7):{middle_right();delayk3(500);break;}
case(8):{back(); delayk3(3000);delay(100);break;}
case(9):{middle_left();delayk5(500);break;}
case(10):{middle_right();delayk6(500);break;}
case(11):{delay(500);while(!k3);behind_left();delayk6(2000);break;}
case(12):{delay(500);while(!k3);behind_right();delayk5(2000);break;}
case(13):{back();delayk3(300);delay(100);zdt();delayk6();stop();delay(5);}
case(14):{back();delayk3(300);delay(100);dt();delayk5();stop();delay(5);}
default:{run();delay(50);stop();delay(50);break;}
}
}
/*****斑马线函数*****/
void xuxian()
{ u8 flag;
if((k1==1)&&(k2==1)&&(k3==1)&&(k4==1)&&(k5==1)) //没检测到,先直行再判断,flag=9时back;
{ z++;
if(z>=80)
flag=8;
else
flag=0;
}
if((k1==1)&&(k2==1)&&(k3==0)&&(k4==1)&&(k5==1)) //中间感应到,直行
{ flag=0; z=0; }
if((k1==1)&&(k2==0)&&(k3==1)&&(k4==1)&&(k5==1)) //直行发生偏转,微调
{flag=1; z=0;}
if((k1==1)&&(k2==1)&&(k3==1)&&(k4==0)&&(k5==1)) //直行发生偏转,微调
{ flag=2; z=0;}
if((k1==0)&&(k2==1)&&(k3==1)&&(k4==1)&&(k5==1)) //大幅度左转
{flag=9; z=0; }
if ((k1==1)&&(k2==1)&&(k3==1)&&(k4==1)&&(k5==0)) //大幅度右转
{flag=10; z=0;}
if(((k1==1)&&(k2==0)&&(k3==0)&&(k4==0)&&(k5==1))||((k1==1)&&(k2==0)&&(k3==1)&&(k4==0)&&(k5==1))|| ((k1==0)&&(k2==1)&&(k3==1)&&(k4==1)&&(k5==0))|| ((k1==0)&&(k2==1)&&(k3==1)&&(k4==0)&&(k5==1))|| ((k1==1)&&(k2==0)&&(k3==1)&&(k4==1)&&(k5==0))|| ((k1==1)&&(k2==0)&&(k3==0)&&(k4==1)&&(k5==1))|| ((k1==1)&&(k2==1)&&(k3==0)&&(k4==0)&&(k5==1))) //意外情况,往前一点
flag=5;
if((k1==0)&&(k2==0)&&(k3==1)&&(k4==1)&&(k5==1)) //behind左转
flag=6;
if((k1==1)&&(k2==1)&&(k3==1)&&(k4==0)&&(k5==0)) //behind右转
flag=7;
if((k1==0)&&(k3==0)&&(k4==1)&&(k5==1)) //直角转向,左转
{if(k2==0)
flag=3;
else
flag=11; }
if((k1==1)&&(k2==1)&&(k3==0)&&(k5==0)) //直角转向,右转
{ if(k4==0)
flag=4;
else
flag=12; }
switch(flag)
{
case(0):{run();break;}
case(1):{bit_left();delayk5(500);break;}
case(2):{bit_right();delayk6(500);break;}
case(3):{delay(150);left();delay(200);delayk2(3000);stop();delay(5);break;}
case(4):{delay(150);right();delay(200);delayk4(3000);stop();delay(5);break;}
case(5):{fast_run();break; }
case(6):{middle_left();delayk3(500);break;}
case(7):{middle_right();delayk3(500);break;}
case(8):{back(); delayk7(3000);delay(100);break;}
case(9):{middle_left();delayk5(1000);break;}
case(10):{middle_right();delayk6(1000);break;}
case(11):{delay(200);left();delay(200);delayk2(3000);stop();delay(5);break;}
case(12):{delay(200);right();delay(200);delayk4(3000);stop();delay(5);break;}
default:{run();delay(50);stop();delay(50);break;}
}
}
/******迷宫函数****/
void migong()
{ u8 cun,s=0;
if((k1==1)&&(k2==1)&&(k3==0)&&(k4==1)&&(k5==1))
{ cun=0; z=0; }
if((k1==1)&&(k2==0)&&(k3==1)&&(k4==1)&&(k5==1))
{ cun=8; z=0; }
if((k1==1)&&(k2==1)&&(k3==1)&&(k4==0)&&(k5==1))
{ cun=9; z=0; }
if((k1==1)&&(k2==1)&&(k3==1)&&(k4==1)&&(k5==1)) //没检测到,先直行再判断,flag=9时back;
{ z++;
if(z>=30)
cun=10;
else
cun=0;
}
if((k1==0)&&(k2==0)&&(k3==0)&&(k4==0)&&(k5==0))
{
while(!((k1==1)&&(k2==1)&&(k3==0)&&(k4==1)&&(k5==1)))
{s++;}
if((k1==1)&&(k2==1)&&(k3==0)&&(k4==1)&&(k5==1))
cun=2;
else if((d==1)&&(b==0))
{cun=2; d=0; b=0; }
else if((d==0)&&(b==1))
{cun=3; d=0; b=0; }
else
cun=2;
}
if((k1==0)&&(k2==0)&&(k3==0)&&(k4==1)&&(k5==1))
{
delay(200);
if((k1==1)&&(k2==1)&&(k3==0)&&(k4==1)&&(k5==1))
{ cun=4; d++;}
else { cun=5; d=0; b=0; }
}
if((k1==1)&&(k2==1)&&(k3==0)&&(k4==0)&&(k5==0))
{
delay(200);
if((k1==1)&&(k2==1)&&(k3==0)&&(k4==1)&&(k5==1))
{ cun=6; b++;}
else { cun=7; d=0; b=0; }
}
switch(cun)
{
case(0):{fast_run();break;}
case(1):{middle_right();delay(400);delayk5(2000);stop();delay(5);break;}
case(2):{middle_left();delay(600);delayk2(2000);stop();delay(5);break;}
case(3):{middle_right();delay(600);delayk2(2000);stop();delay(5);break;}
case(4):{delay(50);middle_left();delay(500);delayk6(2000);stop();delay(5);break;}
case(5):{delay(150);middle_left();delay(400);delayk2(2000);stop();delay(5);break;}
case(6):{delay(50);middle_right();delay(500);delayk5(2000);stop();delay(5);break;}
case(7):{delay(150);middle_right();delay(400);delayk2(2000);stop();delay(5);break;}
case(8):{bit_left();delayk3(500);break;}
case(9):{bit_right();delayk3(500);break;}
case(10):{dt();break;}
default:{run();delay(50);stop();delay(50);break;}
}
}
/*******************
* 功能:打开需要用到的中断
* 用到的中断:定时器0、1 工作方式1 16位定时器模式
* 外部终端0
*********************/
void timer()
{
TMOD=0x11;//定时器0工作方式1
TH0=0xff;//(65536-10)/256;//赋初值定时
TL0=0xf7;//(65536-10)%256;//0.01ms
TH1=0;
TL1=0;
EA=1;//开总中断
ET0=1;//开定时器0中断
ET1=1;
TR0=1;//启动定时器0
IT0=1;
EX0=1;
IRIN=1;
}
/*********************************
*功能:接收红外信号并改为小车的运行状态
*输入:外部中断0
*********************************/
void readjs()
{if(IrValue[2]!=0)
{read1=(IrValue[2]/16);
read2=(IrValue[2]%16);
if((read1==4)&&(read2==0))
{ count+=10; count2+=10;n=2; count3=0;count4=0;
if(count>=100)
count=100;
if(count2>=100)
count2=100;
}
if((read1==1)&&(read2==9))
{ if(count==0||count2==0)
{n=2;
}
else{
count -= 10;count2 -= 10;n = 1; count3 = 0;count4 = 0;n = 2;
if(count<=9)
count=0;
if(count2<=9)
count2=0;
}}
if((read1==0)&&(read2==9))
{count3=40;count=0;count4=0;count2=40;n=2;
}
if((read1==0)&&(read2==7))
{count=40;count4=40;count2=0;count3=0;n=2;
}
if((read1==1)&&(read2==12))
{count=100;count2=100;count3=0;count4=0;n=2;
}
if((read1==1)&&(read2==8))
{
m=0;n=2; count=40;count2=40;count3=0;count4=0;
}
if((read1==5)&&(read2==2))
{
m=1;n=2;count3=50;count4=50;count=0;count2=0;
}
if((read1==1)&&(read2==5))
{count=0;count2=0;count3=0;count4=0; n=2;}
if((read1==4)&&(read2==4))
{
n=0;
}
if((read1==4)&&(read2==7))
{
n=1;
}
if((read1==4)&&(read2==3))
{
n=3;count=30;count2=30;count3=0;count4=0;
}
if((read1==4)&&(read2==2))
{
n=4;
}
IrValue[2]=0;
}
}
/*******主函数****/
void main()
{
timer(); //调用中断打开函数
while(1)
{
readjs(); /调用红外函数,注:要放在循环中不然无法使用
switch(n)
{
case(0):{xunji();break;}
case(1):{migong();break;}
case(3):{StartModule();
while(!Echo); //当RX为零时等待
TR1=1; //开启
while(Echo); //当RX为定时并等待
TR1=0; //关闭
Conut();
break;} //计算
case(4):{xuxian();break;}
default:{break;}
}
}
}
/****定时器0溢出利用pwm调4个电机的速度***/
void tim0() interrupt 1
{
//TR0=0;//赋初值时,关闭定时器
TH0=0xff;//(65536-10)/256;//赋初值定时
TL0=0xf7;//(65536-10)%256;//0.01ms,因为一个周期1us
//TR0=1;//打开定时器
i++;
if(i>=100) //1khz
i=0;
if(i<=count) //占空比%30,可改
{QIN2=0;
HIN4=0;
}
else {
QIN2=1;
HIN4=1;
}
if(i<=count2) //占空比%30,可改
{
QIN4=0;
HIN2=0;
}
else {
QIN4=1;
HIN2=1;
}
if(i<=count3) //占空比%30,可改
{QIN1=0;
HIN3=0;
}
else {
QIN1=1;
HIN3=1;
}
if(i<=count4) //占空比%30,可改
{
QIN3=0;
HIN1=0;
}
else {
QIN3=1;
HIN1=1;
}
}
/******超声波启动(发射超声波)*****/
void StartModule() //启动模块
{
Trig=1; //启动一次模块
_nop_(); _nop_(); _nop_(); _nop_();
_nop_(); _nop_(); _nop_(); _nop_();
_nop_(); _nop_(); _nop_(); _nop_();
_nop_(); _nop_(); _nop_(); _nop_();
_nop_(); _nop_(); _nop_(); _nop_();
_nop_(); _nop_(); _nop_(); _nop_();
Trig=0;
}
void t0() interrupt 3 //T0中断用来计数器溢出,超过测距范围
{
flg=1; //中断溢出标志
}
/*****计算小车前端到障碍物的距离*****/
void Conut()
{
tme=TH1*0x100+TL1;
TH1=0;
TL1=0;
s=(tme/58.0/100.0)*1000;
if((s>=4000)||flg==1) //超出测量范围显示“-”
{
flg=0;
}
else if(s<=1000)
{
count=0;
count2=0;
count3=0;
count4=0;
}
}
/***红外接收函数***/
void ReadIr() interrupt 0
{
u8 j,k;
u16 err;
Time=0;
delay(700); //7ms
if(IRIN==0) //确认是否真的接收到正确的信号
{
err=1000; //1000*10us=10ms,超过说明接收到错误的信号
/*当两个条件都为真是循环,如果有一个条件为假的时候跳出循环,免得程序出错的时
侯,程序死在这里*/
while((IRIN==0)&&(err>0)) //等待前面9ms的低电平过去
{
delay(1);
err--;
}
if(IRIN==1) //如果正确等到9ms低电平
{
err=500;
while((IRIN==1)&&(err>0)) //等待4.5ms的起始高电平过去
{
delay(1);
err--;
}
for(k=0;k<4;k++) //共有4组数据
{
for(j=0;j<8;j++) //接收一组数据
{
err=60;
while((IRIN==0)&&(err>0))//等待信号前面的560us低电平过去
{
delay(1);
err--;
}
err=500;
while((IRIN==1)&&(err>0)) //计算高电平的时间长度。
{
delay(10); //0.1ms
Time++;
err--;
if(Time>30)
{
return;
}
}
IrValue[k]>>=1; //k表示第几组数据
if(Time>=8) //如果高电平出现大于565us,那么是1
{
IrValue[k]|=0x80;
}
Time=0; //用完时间要重新赋值
}
}
}
if(IrValue[2]!=~IrValue[3])
{
return;
}
}
}