找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 11171|回复: 0
打印 上一主题 下一主题
收起左侧

51单片机超声波避障小车程序与原理图

[复制链接]
跳转到指定楼层
楼主
制作出来的实物图如下:


电路原理图如下:


单片机源程序如下:
#include <REGX51.H>
#include "lcd1602.h"
#include "ds18b20.h"
#include "eeprom52.h"
#include "car_pwm.h"
#include<intrins.h>
#define uint unsigned int
#define uchar unsigned char

sbit trig=P2^1; //超声波测距模块Trig
sbit echo=P3^2; //超声波测距模块Echo

sbit key1=P2^0;
sbit key2=P2^2;
sbit key3=P2^3;
sbit key4=P2^4;           //按键IO口定义

bit key1_flag=1;
bit key2_flag=1;
bit key3_flag=1;
bit key4_flag=1;        //按键标志位
bit start_flag=0;        //开始测量标志位

bit start_flag1=0;        //开始测量标志位



sbit key5=P1^6;//红外遥控
sbit key6=P2^5;

sbit key7=P3^3;
sbit key8=P3^4;



sbit LeftIRBZ=P2^6;//左循迹传感器
sbit RightIRBZ=P2^7;//右循迹传感器


bit beep1;           //蜂鸣器标志位
int temp;           //温度变量
uchar count; //中断累加变量
long int distance; //测量所得距离
uint distance_h=50;          //阈值
uchar system_ms,ms,t1ms1,ms1;        //累加时间
bit read_flag=1;        //读数据标志位
bit memory_flag=0;        //存储标志位
uint C;



void delay_nus(unsigned int i)  //延时:i>=12 ,i的最小延时单12 us
{
  i=i/10;
  while(--i);
}

void delay_nms(unsigned int n)  //延时n ms
{
  n=n+1;
  while(--n)  
  delay_nus(900);         //延时 1ms,同时进行补偿

}







//对于掉电存储,实际就是用的单片机自带的EEPROM,对于这个EEPROM,使用起来要知道如下几点
//“  EEPROM存储区域分了好几个扇区”
//“  存储数据时,先擦除要存储的扇区,然后写入数据”
//“  读数据的时候,直接读取相应的扇区   
void memory()           //存储子函数
{
        SectorErase(0x2000);
        byte_write(0x2000,distance_h/256);
        byte_write(0x2001,distance_h%256);
}

void read_memory() //读存储子函数
{
        distance_h=byte_read(0x2000)*256+byte_read(0x2001);
        if(distance_h>450) distance_h=50;
}

void delayt(uint x)        //延时x ms函数
{
        uchar j;
        while(x-- > 0)
        {
                for(j = 0;j < 125;j++)
                {
                        ;
                }
        }
}
/*
    对于显示函数,本次设计用到的是LCD1602液晶,程序里用到的显示函数主要有两个,                LCD1602_write            LCD1602_writebyte
两个都是有参函数,其中  LCD1602_write  ,要填写两个元素,第一个只能填写0  1,当填写0,就说明你第二个元素是命令,当填写1,就
说明第二个元素是数据,例如          LCD1602_write(0,0x80);    ,说明0x80这个数据对于LCD1602来说是命令,其功能是 在第一行第0个位置
进行显示。
LCD1602_writebyte  这个函数是显示一串字符串

    液晶是字符屏,我们要显示的也只能是字符,  temp_h/10%10         得到的是数据,是不能直接显示的,而0x30是字符0,0x31是字符1,所以我们
直接用 数据加上0x30就得到对应的字符数据;


*/
void dis_play()         //显示函数
{
        LCD1602_write(0,0x80);        //0是发命令,0x80是液晶第一行第一个位置
        LCD1602_writebyte(" ");
        LCD1602_write(1,'0'+temp/100%10);        
        LCD1602_write(1,'0'+temp/10%10);
        LCD1602_writebyte(".");
        LCD1602_write(1,'0'+temp%10);           //1是发送数据,显示温度数据,液晶只能显示字符,所以在显示的时候加一个‘0’,将数字转换成字符进行显示
        LCD1602_write(1,0xdf);
        LCD1602_writebyte(" D: ");
        LCD1602_write(1,'0'+distance/100%10);        
        LCD1602_write(1,'0'+distance/10%10);
        LCD1602_write(1,'0'+distance%10);
        LCD1602_writebyte("cm  ");
        LCD1602_write(0,0xc0);
        LCD1602_writebyte(" Alarm_Di:");
        LCD1602_write(1,'0'+distance_h/100%10);        
        LCD1602_write(1,'0'+distance_h/10%10);
        LCD1602_write(1,'0'+distance_h%10);
        LCD1602_writebyte("cm  ");
}



void Robot_Traction()                     //机器人循迹子程序
{

        if(key5==1)
        {
                        run();
                         delay_nms (1000);
                stop();
}
        
        
                if(key6==1)
        {
                        leftrun();
                         delay_nms (1000);
                stop();
}
        
                if(key7==1)
        {
                        rightrun();
                         delay_nms (1000);
                stop();
}
        
                if(key8==1)
        {
                        back();
                         delay_nms (1000);
                stop();
}
else {
        
   if(LeftIRBZ  == 0 && RightIRBZ == 0)    //两个红外检测到黑线,就前进         Left_1_led           Right_1_led
   {
      run_1();                     
      delay_nms (100);
                 run_1();

         
   }

    if(LeftIRBZ  == 1 && RightIRBZ == 0)
   {

                 leftrun_1();
      delay_nms (10);
   }

    if(LeftIRBZ  == 0 &&  RightIRBZ == 1)
   {
      rightrun_1();                        
         
      delay_nms (10);
   }
         
   if(LeftIRBZ  == 1 &&  RightIRBZ == 1)
   {

          stop();                        
         
      delay_nms (10);
   }
         
        }

}

void Robot_A()                     
{

        
        if(key5==1)
        {
                        run();
                         delay_nms (1000);
                stop();
}
        
        
                if(key6==1)
        {
                        leftrun();
                         delay_nms (1000);
                stop();
}
        
                if(key7==1)
        {
                        rightrun();
                         delay_nms (1000);
                stop();
}
        
                if(key8==1)
        {
                        back();
                         delay_nms (1000);
                stop();
}

}
//按键处理函数,常规的处理方式是,判断按键按下-短延时消抖-再次判断按键按下-执行函数体-按键死循环等待
//常规的有一个弊端,就是我按键一直按下,程序就一直等待按键死循环释放,程序不往下执行。所以这里采用另一种方式
//标志位判断的方式,按键送开的时候,将一个标志位置一,然后按键按下,判断标志位只要是1,就执行函数体,同时将标志位置零
//这时候,如果我按键还是按下,由于标志位已经置零,是不能再执行函数体的,只有按键松开,才会将标志位再次置一
//这个处理方式,可以放到定时器里面,效果最好,定时器本身就是定时一段时间执行一次,放到定时器里,变相的实现了定时扫描按键的作用
//并且可以消除抖动
void key_scan()          //
{
        if(!key1)           //判断按键按下
        {
                if(key1_flag)
                {
                        key1_flag=0;
                        if(distance_h<450) distance_h++;  //阈值自加
                }
        }
        else                                    //松开按键
        {
                if(key1_flag==0)
                {
                        memory_flag=1;        //存储标志位置1一次
                        key1_flag=1;
                }
        }
        if(!key2)
        {
                if(key2_flag)
                {
                        key2_flag=0;
                        if(distance_h>0) distance_h--;          //阈值自减
                }
        }
        else
        {
                if(key2_flag==0)
                {
                        memory_flag=1;
                        key2_flag=1;
                }
        }
        if(!key3)
        {
                if(key3_flag)
                {
                        key3_flag=0;
                        start_flag=1; //开始测量
                        start_flag1=0;
                }
        }
        else key3_flag=1;
        if(!key4)
        {
                if(key4_flag)
                {
                        key4_flag=0;
                        start_flag=0; //停止测量
                start_flag1=1;
                        
                }
        }
        else key4_flag=1;
}

void Time_init()        //配置定时器
{
        TMOD=0x11;         //定时器0和1都是方式1
//        TH1=0X4C;
//        TL1=0X00;         //50ms初值
        TH1=0XFc;          //1Ms定时
    TL1=0X18;

        ET1=1;
        TR1=1;                  //打开定时器1
        TL0=0x66;
        TH0=0xfc; //1ms
        ET0=1;                 //设置定时器0
        EA=1;                 //打开总中断
}

void trigger()        //启动测量
{
        trig=0;
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        trig=1;
}

void init_measuring()         //初始化超声波
{
        trig=1;
        echo=1;
        count=0;
}

void measuring()        //测量函数
{
        uchar l;
        uint h,y;
        TR0 = 1;
        while(echo==1)
        {
                ;
        }
        TR0 = 0;
        l = TL0;
        h = TH0;
        y = (h << 8) + l;
        y = y - 0xfc66;//us部分
        distance = y + 1000 * count;//计算总时间,单位是微秒
        TL0 = 0x66;
        TH0 = 0xfc;
        delayt(30);
        C=331.45+0.061*temp;
        distance = C* distance / 20000;//原始为:(0.34毫米/us)*时间/2//
}

void police()           //报警函数
{
        if(distance<distance_h)        
                {
                        back_1();
                delay_nms (1000);
                stop();
                        delay_nms (1000);
                        rightrun_1();
                        delay_nms (500);
                        stop();
                }

        else
        {
//                beep=1;                 //否则停止报警
                run();
                //beep1=0;
        }
}









void main()
{
        do
        {
                temp=Temper();
        }while(temp==850); //温度传感器上电会读一个850,这里用do{}while()语句将850过滤掉
        Time_init();  //调用定时器初始化函数
        LCD1602_cls(); //调用液晶初始化函数
        init_measuring(); //超声波相应端口初始化
        read_memory();         //上电把存储的数据读出来
        while(1)
        {
               
               
               
               
               
        //        Robot_Traction();        
               
               
               
        //Robot_A();
               
                if(memory_flag)          //如果存储标志位是1
                {
                        memory_flag=0; //清0
                        memory();          //存储一次数据
                }
               
                ms1++;
                if(distance>=3)          //如果距离大于3cm
                {
                        if(ms1>=distance)        //根据距离的远近,报警频率不同
                        {
                                ms1=0;
//                                if(beep1) beep=!beep;
        //                        else beep=1;
                        }
                }
                else        //否则小于3cm,用最快的报警频率
                {
                        if(ms1>=3)
                        {
                                ms1=0;
//                                if(beep1) beep=!beep;
        //                        else beep=1;
                        }
                }
               
                dis_play();        //液晶显示函数
                if(start_flag) police();  //如果开始测量,调用报警函数
                //if(start_flag1) Robot_Traction();        
                if(read_flag)          //如果读数据标志位是1
                {
                        read_flag=0;  //置0
                        temp=Temper();        //读温度数据
                        if(start_flag)          //如果开始测量
                        {
                                
                                trigger(); //触发超声波启动
                                while(echo==0) //等待回声
                                {
                                        ;
                                }
                                measuring(); //进行距离测量
                                init_measuring(); //超声波相应端口初始化
                        }
                        else  //否则
                        {
                                //beep1=0;        //停止报警,测量距离是0
                                stop();
                                distance=0;
                        }
                }        
        }
}
//……………………………………………中断服务函数…………………………………………………//

void T_0()interrupt 1
{
        TF0 = 0;
  TL0 = 0x66;
        TH0 = 0xfc;
        

        count++;
        
        if(count==18)
        {
                TR0 =0;
                TL0 = 0x66;
                TH0 = 0xfc;
                count = 0;
        }
        
        

}

void time1() interrupt 3
{
        t1ms1++;
        TH1=0XFc;          //1Ms定时
         TL1=0X18;
        if(t1ms1>=50)
        {
                t1ms1=0;
                key_scan();          //调用按键处理函数
                ms++;
        }
        if(ms%10==0)
        {
                read_flag=1;   //每10*50ms=500ms将读数据标志位置1一次
        }
        if(ms>=40)
        {
                ms=0;
        }

         time3++;
         pwm_val_left++;
         pwm_val_right++;
         pwm_out_left_moto();
         pwm_out_right_moto();
}

全部资料51hei下载地址:
B65037资料20210322.zip (242.92 KB, 下载次数: 63)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏3 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表