基于单片机的车辆防碰撞及自动刹车系统(STC89C52RC芯片+超声波传感器HC-SR04+液晶屏1602+继电器+蜂鸣器)
本系统的目的是设计一个基于单片机的车辆防碰撞及自动刹车系统,系统通过对汽车行进过程中前后车距离的实时检测与过近声光报警功能有效的解决当前汽车行驶过程中由于驾驶员反应不及时导致跟车距离过近引发汽车追尾的问题;系统的基本任务如下:
(1)通过系统的设计与实现,能够解决汽车行进过程中由于驾驶员分心导致汽车碰撞的问题;
(2)构建型号为STC89C52RC的单片机最小工作电路,作为系统的中心处理单元,负责对超声传感器测得的距离值的接收,对液晶屏显示内容的控制,对声光报警电路及继电器电路的控制等;
(3)设置超声波传感器HC-SR04实现对在汽车行进过程中前后车之间的距离的实时采集;
(4)当采集的距离值小于设定的最小报警距离值时,声光报警电路工作,进行报警和提示;
(5)应用液晶屏1602实现对实时距离和设定的最小报警距离值的显示,对当前汽车继续行进的状态即安全与危险进行指示;
(6)系统设置独立按键电路,实现对系统设定的最小报警距离值进行设置,对系统的模式正常工作模式及休眠模式进行切换;
(7)构建1路继电器电路,通过继电器的吸合来实现对刹车装置自动开启动作的模拟;
(8)构建电源供电电路,满足系统的供电需求。
因为这次课设是直接给板子,并没有用protues画仿真图仿真。不过用AT89C51可以代替,自己可以尝试用protues仿真一下。
其中的引脚解法在代码里有,可以自行找一下,所以下面上代码
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。有疑问欢迎底下评论交流。