課題的技術要求:本次課題最終要求小車能在無人操作的條件下實現自動避障,避障基于超聲波測距的原理實現的,當超聲波檢測到小車與障礙物的距離大于設定值時,小車按照原先設定的速度正常行駛;當超聲波檢測到小車和障礙物的距離小于設定值時,單片機控制蜂鳴器發聲同時控制小車停止。因為本次設計的小車時兩輪驅動的小車,也沒有安裝舵機,所以小車的轉彎通過控制兩個車輪間的轉速差實現。
課題研究的主要內容:本次設計以超聲波避障為研究對象,以自動避障為核心控制功能。要研究內容包括:以STC89C52為控制核心的智能系統的平臺搭建、各個模塊的選型、多傳感器的組合應用、PWM控制電機驅動的相應動作、外置儲存器的選型、測距系統的選擇與搭建、報警與顯示系統的選擇與搭建等。
系統總體流程圖
STC89C52單片機接通電源后開始運行,首先對LCD1602的寄存器發送數據進行初始化,完成最基本的屏幕顯示配置,然后在界面上顯示主界面的框架,接下來在While循環中不斷采集超聲波發送的數據,進行轉換后變為整數字節型顯示在LCD1602屏幕上,若采集的數值大于設定值即報警。
鍵盤程序流程圖
在鍵盤處理函數中,分別判斷按下的為哪個按鍵,若按下設定值增加按鍵,則設定值的數值增加10;若按下設定值減少按鍵,設定值的數字減少10,并在變動后均存入外部儲存器。
#include "reg51.h"
#include
#define uchar unsigned char
#define uint unsigned int
#define LCD1602_DATAPINS P0
sbit LCD1602_E=P2^7;
sbit LCD1602_RW=P2^6;
sbit LCD1602_RS=P2^5;
sbit Trig = P1^1;
sbit Echo = P1^0;
sbit BEEP = P2^4;
sbit MotorA_1 = P2^0;
sbit MotorA_2 = P2^1;
sbit MotorB_1 = P2^2;
sbit MotorB_2 = P2^3;
sbit I2C_SDA = P1^2;
sbit I2C_SCL = P1^3;
unsigned char Set_dis = 80;
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,};
unsigned int DIstance;
void D_10()
{
uchar a, b;
for(b=1; b>0; b--)
{
for(a=2; a>0; a--);
}
}
void IIC_S()
{
I2C_SDA = 1;
D_10();
I2C_SCL = 1;
D_10();
I2C_SDA = 0;
D_10();
I2C_SCL = 0;
D_10();
}
void IIC_ST()
{
I2C_SDA = 0;
D_10();
I2C_SCL = 1;
D_10();
I2C_SDA = 1;
D_10();
}
uchar WD_SB(uchar dat, uchar ack)
{
uchar a = 0,b = 0;
for(a=0; a8; a++)
{
I2C_SDA = dat >> 7;
dat = dat < 1;
D_10();
I2C_SCL = 1;
D_10();
I2C_SCL = 0;
D_10();
}
I2C_SDA = 1;
D_10();
I2C_SCL = 1;
while(I2C_SDA && (ack == 1))
{
b++;
if(b > 200)
{
I2C_SCL = 0;
D_10();
return 0;
}
}
I2C_SCL = 0;
D_10();
return 1;
}
uchar WD_RB()
{
uchar a = 0,dat = 0;
I2C_SDA = 1;
D_10();
for(a=0; a8; a++)
{
I2C_SCL = 1;
D_10();
dat <= 1;
dat |= I2C_SDA;
D_10();
I2C_SCL = 0;
D_10();
}
return dat;
}
void CC_WR(uchar addr,uchar dat)
{
IIC_S();
WD_SB(0xa0, 1);
WD_SB(addr, 1);
WD_SB(dat, 0);
IIC_ST();
}
uchar CC_RD(uchar addr)
{
uchar num;
IIC_S();
WD_SB(0xa0, 1);
WD_SB(addr, 1);
IIC_S();
WD_SB(0xa1, 1);
num=WD_RB();
IIC_ST();
return num;
}
void RUN_UP()
{
MotorA_1 = 1;
MotorA_2 = 0;
MotorB_1 = 1;
MotorB_2 = 0;
}
void RUN_DOWN()
{
MotorA_1 = 0;
MotorA_2 = 0;
MotorB_1 = 0;
MotorB_2 = 0;
}
void RUN_RIGHT()
{
MotorA_1 = 1;
MotorA_2 = 0;
MotorB_1 = 0;
MotorB_2 = 1;
}
/*******************************************************************************
* 函 數 名 : Lcd1602_Delay1ms
* 函數功能 : 延時函數,延時1ms
* 輸 入 : c
* 輸 出 : 無
* 說 名 : 該函數是在12MHZ晶振下,12分頻單片機的延時。
*******************************************************************************/
void Lcd1602_Delay1ms(uint c) //誤差 0us
{
uchar a,b;
for (; c?>0; c--)
{
for (b=199;b>0;b--)
{
for(a=1;a>0;a--);
}
}
}
/*******************************************************************************
* 函 數 名 : LcdWriteCom
* 函數功能 : 向LCD寫入一個字節的命令
* 輸 入 : com
* 輸 出 : 無
*******************************************************************************/
void LcdWriteCom(uchar com) //寫入命令
{
LCD1602_E = 0; //使能
LCD1602_RS = 0; //選擇發送命令
LCD1602_RW = 0; //選擇寫入
LCD1602_DATAPINS = com; //放入命令
Lcd1602_Delay1ms(1); //等待數據穩定
LCD1602_E = 1; //寫入時序
Lcd1602_Delay1ms(5); //保持時間
LCD1602_E = 0;
}
/*******************************************************************************
* 函 數 名 : LcdWriteData
* 函數功能 : 向LCD寫入一個字節的數據
* 輸 入 : dat
* 輸 出 : 無
*******************************************************************************/
void LcdWriteData(uchar dat) //寫入數據
{
LCD1602_E = 0; //使能清零
LCD1602_RS = 1; //選擇輸入數據
LCD1602_RW = 0; //選擇寫入
LCD1602_DATAPINS = dat; //寫入數據
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //寫入時序
Lcd1602_Delay1ms(5); //保持時間
LCD1602_E = 0;
}
/*******************************************************************************
* 函 數 名 : LcdInit()
* 函數功能 : 初始化LCD屏
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
void LcdInit() //LCD初始化子程序
{
LcdWriteCom(0x38); //開顯示
LcdWriteCom(0x0c); //開顯示不顯示光標
LcdWriteCom(0x06); //寫一個指針加1
LcdWriteCom(0x01); //清屏
LcdWriteCom(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; // 算出指令碼
LcdWriteCom(X); //這里不檢測忙信號,發送地址碼
LcdWriteData(DData);
}
//按指定位置顯示一串字符
void DisplayListChar(unsigned char X, unsigned char Y, unsigned char code *DData)
{
unsigned char ListLength;
ListLength = 0;
Y &= 0x1;
X &= 0xF; //限制X不能大于15,Y不能大于1
while (DData[ListLength]>=0x20) //若到達字串尾則退出
{
if (X <= 0xF) //X坐標應小于0xF
{
DisplayOneChar(X, Y, DData[ListLength]); //顯示單個字符
ListLength++;
X++;
}
}
}
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;
}
/*******************************************************************************
* 函 數 名 : main
* 函數功能 : 主函數
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
void Conut(void)
{
time=TH0*256+TL0;
TH0=0;
TL0=0;
S=(time*1.7)/100; //算出來是CM
DIstance = S;
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 main()
{
TMOD=0x01; //設T0為方式1,GATE=1;
TH0=0;
TL0=0;
ET0=1; //允許T0中斷
EX0=1; //外部中斷0開() EX1 為外部中斷1 (P3^3)
IT0=1; //低電平觸發 IT1為中斷1
EX1=1; //外部中斷0開() EX1 為外部中斷1 (P3^3)
IT1=1; //低電平觸發 IT1為中斷1
EA=1; //開啟總中斷
Set_dis = CC_RD(0x01);
LcdInit();
DisplayListChar(4,0,"Car system");
while(1)
{
StartModule();
while(!Echo); //當RX為零時等待
TR0=1; //開啟計數
while(Echo); //當RX為1計數并等待
TR0=0; //關閉計數
Conut(); //計算
DisplayOneChar(8,1,(char)(Set_dis/100)+'0');
DisplayOneChar(9,1,(char)(Set_dis/10%10)+'0');
DisplayOneChar(10,1,(char)(Set_dis%10)+'0');
if(DIstance>Set_dis)
{
BEEP = 0;
RUN_RIGHT();
}else
{
BEEP = 1;
RUN_UP();
}
}
}
void Key1_INT( ) interrupt 0 // 這里0對應下表
{
Set_dis = Set_dis+10;
CC_WR(0x01,Set_dis);
}
void Key2_INT( ) interrupt 2 // 這里0對應下表
{
Set_dis =Set_dis-10;
CC_WR(0x01,Set_dis);
}
審核編輯:湯梓紅
-
單片機
+關注
關注
6035文章
44554瀏覽量
634633 -
仿真
+關注
關注
50文章
4070瀏覽量
133552 -
蜂鳴器
+關注
關注
12文章
891瀏覽量
45917 -
避障小車
+關注
關注
1文章
24瀏覽量
19028
發布評論請先 登錄
相關推薦
評論