本系統(tǒng)的目的是設(shè)計一個基于單片機的車輛防碰撞及自動剎車系統(tǒng),系統(tǒng)通過對汽車行進過程中前后車距離的實時檢測與過近聲光報警功能有效的解決當前汽車行駛過程中由于駕駛員反應不及時導致跟車距離過近引發(fā)汽車追尾的問題;系統(tǒng)的基本任務(wù)如下:
(1)通過系統(tǒng)的設(shè)計與實現(xiàn),能夠解決汽車行進過程中由于駕駛員分心導致汽車碰撞的問題;
(2)構(gòu)建型號為STC89C52RC的單片機最小工作電路,作為系統(tǒng)的中心處理單元,負責對超聲傳感器測得的距離值的接收,對液晶屏顯示內(nèi)容的控制,對聲光報警電路及繼電器電路的控制等;
(3)設(shè)置超聲波傳感器HC-SR04實現(xiàn)對在汽車行進過程中前后車之間的距離的實時采集;
(4)當采集的距離值小于設(shè)定的最小報警距離值時,聲光報警電路工作,進行報警和提示;
(5)應用液晶屏1602實現(xiàn)對實時距離和設(shè)定的最小報警距離值的顯示,對當前汽車繼續(xù)行進的狀態(tài)即安全與危險進行指示;
(6)系統(tǒng)設(shè)置獨立按鍵電路,實現(xiàn)對系統(tǒng)設(shè)定的最小報警距離值進行設(shè)置,對系統(tǒng)的模式正常工作模式及休眠模式進行切換;
(7)構(gòu)建1路繼電器電路,通過繼電器的吸合來實現(xiàn)對剎車裝置自動開啟動作的模擬;
(8)構(gòu)建電源供電電路,滿足系統(tǒng)的供電需求。
因為這次課設(shè)是直接給板子,并沒有用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,};
/*******************************************************************************
* 函 數(shù) 名 : main
* 函數(shù)功能 : 主函數(shù)
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
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) //處于安全范圍內(nèi)就亮綠燈蜂鳴器不響
{
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中斷用來計數(shù)器溢出,超過測距范圍
{
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);
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
/*
字符串轉(zhuǎn)十進制整形
*/
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; //設(shè)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; //開啟計數(shù)
while(Echo); //當RX為1計數(shù)并等待
TR0=0; //關(guān)閉計數(shù)
Conut(getdata); //計算 安全距離,需要傳入?yún)?shù)
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; //開啟計數(shù)
while(Echo); //當RX為1計數(shù)并等待
TR0=0; //關(guān)閉計數(shù)
Conut2(getdata); //計算 安全距離,需要傳入?yún)?shù)
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; //開啟計數(shù)
while(Echo); //當RX為1計數(shù)并等待
TR0=0; //關(guān)閉計數(shù)
Conut(getdata); //計算 安全距離,需要傳入?yún)?shù)
delayms(80);
}
}
}
lcd.c
#include"lcd.h"
void Read_Busy() //忙檢測函數(shù),判斷bit7是0,允許執(zhí)行;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) //寫數(shù)據(jù)
{
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); //發(fā)命令字
Lcd1602_Write_Data(DData); //發(fā)數(shù)據(jù)
}
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位數(shù)據(jù)
Lcd1602_Write_Cmd(0x0c);
Lcd1602_Write_Cmd(0x06);
Lcd1602_Write_Cmd(0x01); //清屏
}
lcd.h
#ifndef __LCD_H_
#define __LCD_H_
/**********************************
當使用的是4位數(shù)據(jù)傳輸?shù)臅r候定義,
使用8位取消這個定義
**********************************/
//#define LCD1602_4PINS
/**********************************
包含頭文件
**********************************/
#include<reg51.h>
//---重定義關(guān)鍵詞---//
#ifndef uchar
#define uchar unsigned char
#endif
#ifndef uint
#define uint unsigned int
#endif
/**********************************
PIN口定義
**********************************/
#define LCD1602_DB P0 //data bus 數(shù)據(jù)總線
sbit LCD1602_RS = P3^5; //寄存器選擇,高電平數(shù)據(jù)寄存器,低電平指令寄存器
sbit LCD1602_RW = P3^6; //讀寫信號線,1為讀,0寫
sbit LCD1602_EN = P3^4; //使能端,1讀取信息,
/**********************************
函數(shù)聲明
**********************************/
/*在51單片機12MHZ時鐘下的延時函數(shù)*/
void Lcd1602_Delay1ms(uint c); //誤差 0us
void Read_Busy(); //忙檢測函數(shù),判斷bit7是0,允許執(zhí)行;1禁止
void Lcd1602_Write_Cmd(unsigned char cmd); //寫命令
void Lcd1602_Write_Data(unsigned char dat); //寫數(shù)據(jù)
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。有疑問歡迎底下評論交流。