基于单片机的车辆防碰撞及自动刹车系统(STC89C52RC芯片+超声波传感器HC-SR04+液晶屏1602+继电器+蜂鸣器)

本系统的目的是设计一个基于单片机的车辆防碰撞及自动刹车系统,系统通过对汽车行进过程中前后车距离的实时检测与过近声光报警功能有效的解决当前汽车行驶过程中由于驾驶员反应不及时导致跟车距离过近引发汽车追尾的问题;系统的基本任务如下:

(1)通过系统的设计与实现,能够解决汽车行进过程中由于驾驶员分心导致汽车碰撞的问题;

(2)构建型号为STC89C52RC的单片机最小工作电路,作为系统的中心处理单元,负责对超声传感器测得的距离值的接收,对液晶屏显示内容的控制,对声光报警电路及继电器电路的控制等;

(3)设置超声波传感器HC-SR04实现对在汽车行进过程中前后车之间的距离的实时采集;

(4)当采集的距离值小于设定的最小报警距离值时,声光报警电路工作,进行报警和提示;

(5)应用液晶屏1602实现对实时距离和设定的最小报警距离值的显示,对当前汽车继续行进的状态即安全与危险进行指示;

(6)系统设置独立按键电路,实现对系统设定的最小报警距离值进行设置,对系统的模式正常工作模式及休眠模式进行切换;

(7)构建1路继电器电路,通过继电器的吸合来实现对刹车装置自动开启动作的模拟;

(8)构建电源供电电路,满足系统的供电需求。

因为这次课设是直接给板子,并没有用protues画仿真图仿真。不过用AT89C51可以代替,自己可以尝试用protues仿真一下。

image
image
image
image
image
image
image

其中的引脚解法在代码里有,可以自行找一下,所以下面上代码

main.c

#include<reg51.h>
#include<intrins.h>    
#include"lcd.h"


sbit Trig = P2^1;
sbit Echo = P2^0;


sbit led_0 = P1^0;
sbit led_1 = P1^1;


sbit beep = P1^3;
sbit jdq = P1^4;


///////////按键模块//////////////////////
sbit k1=P3^2;       //加法按键
sbit k2=P3^3;       //减法按键
sbit k3=P3^1;       //休眠按键
sbit k4=P3^0;      //复位按键

/////////////////////////////////////////


unsigned char PuZh[]="CM shi juli";


unsigned char code ASCII[15] =    {'0','1','2','3','4','5','6','7','8','9','.','-','M'};

static unsigned char DisNum = 0; //显示用指针                  
       unsigned int  time=0;
       unsigned long S=0;
       bit      flag =0;
       unsigned char disbuff[4]       ={ 0,0,0,0,};
/*******************************************************************************
* 函 数 名         : main
* 函数功能           : 主函数
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void Conut(unsigned char q)
    {
     unsigned int anquanjuli = q;
     time=TH0*256+TL0;
     TH0=0;
     TL0=0;    
     S=(time*1.7)/100;     //算出来是CM
     if((S>=700)||flag==1) //超出测量范围显示“-”
     {     
      flag=0;
     
      DisplayOneChar(0, 1, ASCII[11]);
      DisplayOneChar(1, 1, ASCII[10]);    //显示点
      DisplayOneChar(2, 1, ASCII[11]);
      DisplayOneChar(3, 1, ASCII[11]);
      DisplayOneChar(4, 1, ASCII[12]);    //显示M
     }
     else
     {
      disbuff[0]=S%1000/100;
      disbuff[1]=S%1000%100/10;
      disbuff[2]=S%1000%10 %10;
      DisplayOneChar(0, 1, ASCII[disbuff[0]]);
      DisplayOneChar(1, 1, ASCII[10]);    //显示点
      DisplayOneChar(2, 1, ASCII[disbuff[1]]);
      DisplayOneChar(3, 1, ASCII[disbuff[2]]);
      DisplayOneChar(4, 1, ASCII[12]);    //显示M
     }
    if(S<=anquanjuli)  //小于安全距离就亮红灯且蜂鸣器响继电器工作
    {
         led_0=0;
         led_1=1;
         beep=0;
          jdq=0;
    }
    else if(S>anquanjuli&&S<=700) //处于安全范围内就亮绿灯蜂鸣器不响
    {
           led_0=1;
        led_1=0;
        beep=1;
        jdq=1;    
    }


    }



void Conut2(unsigned char q)
{
     unsigned int anquanjuli = q;
     time=TH0*256+TL0;
     TH0=0;
     TL0=0;
    
     S=(time*1.7)/100;     //算出来是CM
     if((S>=700)||flag==1) //超出测量范围显示“-”
     {     
      flag=0;
     
      DisplayOneChar(0, 1, ASCII[11]);
      DisplayOneChar(1, 1, ASCII[10]);    //显示点
      DisplayOneChar(2, 1, ASCII[11]);
      DisplayOneChar(3, 1, ASCII[11]);
      DisplayOneChar(4, 1, ASCII[12]);    //显示M
     }
     else
     {
      disbuff[0]=S%1000/100;
      disbuff[1]=S%1000%100/10;
      disbuff[2]=S%1000%10 %10;
      DisplayOneChar(0, 1, ASCII[disbuff[0]]);
      DisplayOneChar(1, 1, ASCII[10]);    //显示点
      DisplayOneChar(2, 1, ASCII[disbuff[1]]);
      DisplayOneChar(3, 1, ASCII[disbuff[2]]);
      DisplayOneChar(4, 1, ASCII[12]);    //显示M
     }

}

void zd0() interrupt 1          //T0中断用来计数器溢出,超过测距范围
  {
    flag=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_();
      Trig=0;
  }



void delayms(unsigned int ms)
{
    unsigned char i=100,j;
    for(;ms;ms--)
    {
        while(--i)
        {
            j=10;
            while(--j);
        }
    }
}


///////////////////////////////////////////////////////////////////////////////////////////////////


/*

字符串转十进制整形
*/

int atoi(char s[]) 
{ 
    int i; 
    int n = 0; 
    for (i = 0; s[i] >= '0' && s[i] <= '9'; ++i) 
    { 
        n = 10 * n + (s[i] - '0'); 
    } 
    return n; 
} 

///////////////////////////////////////////////////////////////////



void main(void)
{
     
     
     unsigned char safe[]={"10"};
//     unsigned char safe3[1]=0;
//     unsigned char safe4[1]=0;
//     unsigned char safe5[2]    = 0;
     unsigned char safe6[3]    = 0;
//
//     unsigned char safe2[]={'C','M'};
      unsigned int getdata= atoi(safe);
    unsigned int    a=0; ///个位
    unsigned int    b=0; ////十位
    unsigned int    c=0; ///百位


//     unsigned char  *p=PuZh;
//   unsigned char *q=&safe[0];
//     unsigned char  *t=safe2;
    

     TMOD=0x01;           //设T0为方式1,GATE=1;
     TH0=0;
     TL0=0;          
     ET0=1;      //允许T0中断
     EA=1;               //开启总中断    

       InitLcd1602();

       /////////第一次显示//////////////////
                        a=getdata;
                      c=a/100;
                      b=a/10%10;
                      a=a%10;
                      safe6[0]=c+0x30;
                      safe6[1]=    b+0x30;
                      safe6[2]=a+0x30;
                      DisplayOneChar(0,0,safe6[0]);
                      DisplayOneChar(1,0,safe6[1]);
                      DisplayOneChar(2,0,safe6[2]);
                      LcdShowStr(4,0,PuZh);
//         safe4[0]=getdata+0x30;
//         DisplayOneChar(0,0,safe4[0]);


    while(1)
    {
        
        
         StartModule();
         while(!Echo);        //当RX为零时等待
         TR0=1;                //开启计数
         while(Echo);            //当RX为1计数并等待
         TR0=0;                //关闭计数
         Conut(getdata);            //计算 安全距离,需要传入参数
         delayms(80);
        while(1)
      {
            
        if(!k1||!k2||!k3||!k4)//判断有无键按下
        {
            delayms(10);//消抖动
            if(!k1)
            {
                while(!k1);//按键1按下
                getdata=getdata+3;
            }
            else if(!k2)//按键2按下
            {
                while(!k2);
                getdata=getdata-3;
            }
            else if(!k3)//按键3按下
            {
                while(!k3);
                getdata=0;
                 c=getdata/100;
                      b=getdata/10%10;
                      a=getdata%10;
                      safe6[0]=c+0x30;
                      safe6[1]=    b+0x30;
                       safe6[2]=a+0x30;
                      DisplayOneChar(0,0,safe6[0]);
                      DisplayOneChar(1,0,safe6[1]);
                      DisplayOneChar(2,0,safe6[2]);
                LcdShowStr(4,0,PuZh);
                 StartModule();
         while(!Echo);        //当RX为零时等待
         TR0=1;                //开启计数
         while(Echo);            //当RX为1计数并等待
         TR0=0;                //关闭计数
         Conut2(getdata);            //计算 安全距离,需要传入参数
         delayms(80);
            }

            else if(!k4)//按键2按下
            {
                while(!k4);
                getdata=10;
            }
                if(getdata>9&&getdata<100)
                {
                      c=getdata/100;
                      b=getdata/10%10;
                      a=getdata%10;
                      safe6[0]=c+0x30;
                      safe6[1]=    b+0x30;
                       safe6[2]=a+0x30;
                      DisplayOneChar(0,0,safe6[0]);
                      DisplayOneChar(1,0,safe6[1]);
                      DisplayOneChar(2,0,safe6[2]);
                       LcdShowStr(4,0,PuZh);
                }
                else if(getdata>0&&getdata<10)
                {
                        safe6[0]=0+0x30;
                        safe6[1]=0+0x30;
                        safe6[2]=getdata+0x30;
                       
                        DisplayOneChar(0,0,safe6[0]);
                        DisplayOneChar(1,0,safe6[1]);
                        DisplayOneChar(2,0,safe6[2]);
                        LcdShowStr(4,0,PuZh);
                }
                else if(getdata>=100&&getdata<1000)
                {
                        safe6[0]=getdata/100+0x30;
                        safe6[1]=getdata/10%10+0x30;
                        safe6[2]=getdata%10+0x30;
                       
                        DisplayOneChar(0,0,safe6[0]);
                        DisplayOneChar(1,0,safe6[1]);
                        DisplayOneChar(2,0,safe6[2]);
                        LcdShowStr(4,0,PuZh);
                }
            break ;
    }
        
      
        
         StartModule();
         while(!Echo);        //当RX为零时等待
         TR0=1;                //开启计数
         while(Echo);            //当RX为1计数并等待
         TR0=0;                //关闭计数
         Conut(getdata);            //计算 安全距离,需要传入参数
         delayms(80);
    }
            
}
}
lcd.c

#include"lcd.h"


void Read_Busy()           //忙检测函数,判断bit7是0,允许执行;1禁止
{
    unsigned char sta;      //
    LCD1602_DB = 0xff;
    LCD1602_RS = 0;
    LCD1602_RW = 1;
    do
    {
        LCD1602_EN = 1;
        sta = LCD1602_DB;
        LCD1602_EN = 0;    //使能,用完就拉低,释放总线
    }while(sta & 0x80);
}

void Lcd1602_Write_Cmd(unsigned char cmd)     //写命令
{
    Read_Busy();
    LCD1602_RS = 0;
    LCD1602_RW = 0;
    LCD1602_DB = cmd;
    LCD1602_EN = 1;
    LCD1602_EN = 0;    
}

void Lcd1602_Write_Data(unsigned char dat)   //写数据
{
      Read_Busy();
      LCD1602_RS = 1;
      LCD1602_RW = 0;
      LCD1602_DB = dat;
      LCD1602_EN = 1;
      LCD1602_EN = 0;
}

void LcdSetCursor(unsigned char x,unsigned char y)  //坐标显示
{
    unsigned char addr;
    if(y == 0)
        addr = 0x00 + x;
    else
        addr = 0x40 + x;
    
    Lcd1602_Write_Cmd(addr|0x80);
}

//按指定位置显示一个字符
void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData)
{
    Y &= 0x1;
    X &= 0xF; //限制X不能大于15,Y不能大于1
    if (Y) X |= 0x40; //当要显示第二行时地址码+0x40;
    X |= 0x80; //算出指令码
    Lcd1602_Write_Cmd(X); //发命令字
    Lcd1602_Write_Data(DData); //发数据
}


void LcdShowStr(unsigned char x,unsigned char y,unsigned char *str)     //显示字符串
{
    LcdSetCursor(x,y);      //当前字符的坐标
    while(*str != '\0')
    {
        Lcd1602_Write_Data(*str++);
    }
}

void InitLcd1602()              //1602初始化
{
    Lcd1602_Write_Cmd(0x38);    //打开,5*8,8位数据
    Lcd1602_Write_Cmd(0x0c);
    Lcd1602_Write_Cmd(0x06);
    Lcd1602_Write_Cmd(0x01);    //清屏   
}
lcd.h

#ifndef __LCD_H_
#define __LCD_H_
/**********************************
当使用的是4位数据传输的时候定义,
使用8位取消这个定义
**********************************/
//#define LCD1602_4PINS

/**********************************
包含头文件
**********************************/
#include<reg51.h>

//---重定义关键词---//
#ifndef uchar
#define uchar unsigned char
#endif

#ifndef uint 
#define uint unsigned int
#endif

/**********************************
PIN口定义
**********************************/
#define LCD1602_DB  P0      //data bus 数据总线
sbit LCD1602_RS = P3^5;         //寄存器选择,高电平数据寄存器,低电平指令寄存器
sbit LCD1602_RW = P3^6;        //读写信号线,1为读,0写
sbit LCD1602_EN = P3^4;         //使能端,1读取信息,

/**********************************
函数声明
**********************************/
/*在51单片机12MHZ时钟下的延时函数*/
void Lcd1602_Delay1ms(uint c);   //误差 0us

void Read_Busy();           //忙检测函数,判断bit7是0,允许执行;1禁止
void Lcd1602_Write_Cmd(unsigned char cmd);     //写命令
void Lcd1602_Write_Data(unsigned char dat);   //写数据
void LcdSetCursor(unsigned char x,unsigned char y);  //坐标显示
void LcdShowStr(unsigned char x,unsigned char y,unsigned char *str);     //显示字符串
void InitLcd1602();              //1602初始化
void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData);
                      

#endif

以上就是全部,第一个按键是加距离,第二个减距离,第三个是休眠,第四个是复位。当超声波测距小于安全距离时,蜂鸣器报警,亮红灯,继电器吸合模拟刹车。安全距离可以在代码中自行修改,原初始定的安全距离是10CM。有疑问欢迎底下评论交流。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容