避障小車程序實現功能:
1.藍牙控制,重力感應,通過串口通訊實現手機和藍牙之間的連接控制用到hc-06模塊
2.循跡壁障,遇見障礙能夠及時躲避,通過舵機帶動hc-sr04超聲波模塊的左右轉動來測量前左右的障礙
3.跟蹤,可以追蹤一個物體,物進車進,物退車退
4.走黑線,不同顏色的物體對光的反射不同
4.pwm速度快慢調速,通過pwm調節l298n產生脈寬調制
5.開燈,通過手機控制單片機的io口輸出高低電頻實現
6.喇叭,高低電頻產生震蕩
********************************************************************************/
/********************************************************************************
避障小車出現的問題:
1.主要是定時器優先級別問題,解決辦法調節定時器優先級別,第一次掌握了定時器二的用法,這是52特有的
2.切記,定時器0不能和定時器1互換,因為定時器1優先級沒有0高,互換會導致超聲波測距模塊接受不到數據
3.出現模塊從諜,的問題,解決辦法用標記把可能出問題模塊一個一個標記;最后發現原來是延時函數名字相同
4.字符串不能直接比較需要用if(strcmp(字符串,字符串2)==0)如果一樣就返回一個0,如果一比二大就返回
一個正數否則返回負數記住需要包含#include<string.h>頭文件
5.舵機不能兩個地方同時出現歸中,剛開始以為是定時器優先級別的問題,打開定時器1串口通訊就會制動打開
所以我在串口函數里設了點亮led燈來測試串口中斷是否自己打開,然后我先是注釋ET1發現程序正常,
后面又注釋掉中斷3發現程序正常,說明不是定時器設置問題, 注釋掉中斷三里的內容發現也正常說明不是中斷引起的
然后注釋掉舵機pwm調速,發現也正常說明不是小車檔位pwm的問題最后注釋掉小車快慢pwm調速,發現舵機函數有問題
然后注釋掉舵機pwm調速里的eles發現不正常,之后嘗試了改pwm輸出口的名字以及io口發現都沒用,最后拔掉舵機信號線
發現有用,說明舵機初始化有問題,最后把初始化里的歸中14,該成0,發現能正常運作,最后把初始化該成14,注釋掉
超聲波次主函數的歸中發現能正常運作,說明兩個歸中只能要一個。
結論;一點要細致認真,勤于思考,碰到問題要迎難而上因為編程本來就是個改錯的過程別碰到問題就想著
問別人,因為自己的程序只有自己最了解,寫代碼一定要規范,免得到時后亂起來連自己都看不懂。
11月13日,吳才成
下面是制作的避障小車的實物圖:
psb.jpg (29.33 KB, 下載次數: 137)
下載附件
2017-12-5 10:27 上傳
psb (6).jpg (25.11 KB, 下載次數: 131)
下載附件
2017-12-5 10:27 上傳
psb (5).jpg (20.49 KB, 下載次數: 137)
下載附件
2017-12-5 10:27 上傳
psb (4).jpg (24.35 KB, 下載次數: 120)
下載附件
2017-12-5 10:27 上傳
psb (3).jpg (18.53 KB, 下載次數: 121)
下載附件
2017-12-5 10:27 上傳
psb (2).jpg (26.39 KB, 下載次數: 130)
下載附件
2017-12-5 10:27 上傳
psb (1).jpg (25.35 KB, 下載次數: 106)
下載附件
2017-12-5 10:27 上傳
51單片機避障小車源程序如下:
- #include<AT89X52.H>
- #include<string.h> //字符串比較頭文件
- #include <intrins.h> //nop的頭文件
- #define Left_moto_go {P3_1=1,P3_2=0,P3_3=1,P3_4=0;} //左邊兩個電機向前走
- #define Left_moto_back {P3_1=0,P3_2=1,P3_3=0,P3_4=1;} //左邊兩個電機向后轉
- #define Left_moto_Stop {P3_1=0,P3_2=0,P3_3=0,P3_4=0;} //左邊兩個電機停轉
- #define Right_moto_go {P1_4=1,P1_5=0,P1_6=1,P1_7=0 ;} //右邊兩個電機向前走
- #define Right_moto_back {P1_4=0,P1_5=1,P1_6=0,P1_7=1;} //右邊兩個電機向前走
- #define Right_moto_Stop {P1_4=0,P1_5=0,P1_6=0,P1_7=0;} //右邊兩個電機停轉 */
- /***************************************************************/
- //藍牙的設置
- /*****************************************************************/
- void zxddc (); //轉向燈 后退 剎車指示燈
- void zxdzz (); //轉向燈左轉
- void zxdyz (); //轉向燈右轉
- void zxdgd (); //轉向燈關燈
- sbit LEDHZ = P3^5; //轉向燈左邊
- sbit LEDHY = P3^6; //轉向燈右邊
- sbit LED1 = P1^0 ; //左方向燈
- sbit LED2 = P1^1 ; //右方向燈
- sbit fmq = P1^2 ; //喇叭,蜂鳴器
- int pwmjishu = 0 ; //pwm調速
- int pushjishu = 0 ; //pwm調速
- sbit ena1 = P2^7;
- sbit enb1 = P2^6; //l298npwm調速引腳
- sbit ena2 = P2^5;
- sbit enb2 = P2^4;
- unsigned char data table[4]={ 0,0,0,};//用來裝串口發送過來的字符串,不包括0
- /***************************************************************/
- //超聲波的設置
- /*********************************************************/
- #define CSBPWM P2_2 //接舵機信號端輸入PWM信號調節速度
- #define ECHO P2_0 //超聲波接口定義
- #define TRIG P2_1 //超聲波接口定義
- unsigned char disdat[4]={ 0,0,0,0,};
- unsigned char pwm_val_left = 0;//變量定義
- unsigned char push_val_left =0;//14;//舵機歸中,產生約,1.5MS 信號
- unsigned long S=0;
- unsigned long S1=0;
- unsigned long S2=0;
- unsigned long S3=0;
- unsigned long S4=0;
- unsigned int time=0; //時間變量
- unsigned int timer=0; //延時基準變量
- unsigned char timer1=0; //掃描時間變量
- void qianj(void) //前進
- {
- Left_moto_go ; //左電機往前走
- Right_moto_go ; //右電機往前走
- }
- /************************************************************************/
- //全速后退
- void hout(void) //后退
- {
- Left_moto_back ; //左電機往前走
- Right_moto_back ; //右電機往前走
- zxddc (); //后退指示燈
- }
- /********************* ***************************************************/
- //左轉 //左轉
- void zuoz(void)
- {
- Left_moto_back ; //左電機往前走
- Right_moto_go ; //右電機往前走
- zxdzz (); //左轉指示燈
- }
- /************************************************************************/
- //右轉
- void youz(void) //右轉
- {
- Left_moto_go ; //左電機往前走
- Right_moto_back ; //右電機往前走
- zxdyz (); //右轉指示燈
- }
- /************************************************************************/
- //STOP
- void tingz(void) //停止
- {
- Left_moto_Stop ; //左電機停走
- Right_moto_Stop ; //右電機停走
- zxdgd (); //車子停止指示燈關閉
- }
- /************************************************************************/
- /************************************************************************/
- void delay1(unsigned int k) //延時函數
- {
- unsigned int x,y;
- for(x=0;x<k;x++)
- for(y=0;y<2000;y++);
- }
- /******************************//*******************************************/
- void delay_50us(unsigned int z) //延時函數
- {
- unsigned int x,y;
-
- for(x=z;x>0;x--)
- for(y=110;y>0;y--);
-
- }
- /*************************************************/
- void StartModule() //啟動測距信號
- {
- TRIG=1; //給10us以上的高電頻
- _nop_(); //_nop_()一個機器周期,1us
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- TRIG=0;
- }
- /***************************************************/
- /**************************************************/
- void Conut(void) //計算距離
- {
- while(!ECHO); //當RX為零時等待
- TR0=1; //開啟計數
- while(ECHO); //當RX為1計數并等待
- TR0=0; //關閉計數
- time=TH0*256+TL0; //讀取脈寬長度
- TH0=0;
- TL0=0;
- S=(time*1.7)/100; //算出來是CM
- }
- void COMM( void ) //方向計算
- {
- push_val_left=5; //舵機向左轉90度
- timer=0;
- while(timer<=4000); //延時400MS讓舵機轉到其位置
- StartModule(); //啟動超聲波測距
- Conut(); //計算距離
- S2=S;
-
- push_val_left=23; //舵機向右轉90度
- timer=0;
- while(timer<=4000); //延時400MS讓舵機轉到其位置
- StartModule(); //啟動超聲波測距
- Conut(); //計算距離
- S4=S;
- push_val_left=14; //舵機歸中
- timer=0;
- while(timer<=4000); //延時400MS讓舵機轉到其位置
- StartModule(); //啟動超聲波測距
- Conut(); //計算距離
- S1=S;
- if((S2<20)||(S4<20)) //只要左右各有距離小于20CM小車后退
- {
- hout(); //后退
- timer=0;
- while(timer<=4000);
- }
- if(S2>S4)
- {
- youz(); //車的左邊比車的右邊距離小 右轉
- timer=0;
- while(timer<=4000);
- }
- else
- {
- zuoz(); //車的左邊比車的右邊距離大 左轉
- timer=0;
- while(timer<=4000);
- }
- }
- /**********************************************************************************
- 舵機pwm調速,和小車換擋調速共用一個定時器
- ***********************************************************************************/
- void pwm_Servomoto()
- {
-
- if(pwm_val_left<=push_val_left)
- CSBPWM=1;
- else
- CSBPWM=0;
- if(pwm_val_left>=200)
- pwm_val_left=0;
- }
- /************************************************************/
- void Delay(unsigned int i)
- {
- char j;
- for(i; i > 0; i--)
- for(j = 200; j > 0; j--);
- }
- /*****************************************************************/
- void fangx() //方向函數
- {
- if(strcmp(table,"ONA")==0) qianj();//前進
- else if(strcmp(table,"ONB")==0) hout();//后退
- else if(strcmp(table,"ONC")==0) zuoz();//左轉
-
- else if(strcmp(table,"OND")==0) youz ();//右轉
- else tingz();//停止
-
- // if((a[0]=='O')&&(a[1]='N')&&(a[2]=='A')&&(a[3]==0)) qianj();
- /*if(a=="ONA")qianj();//前進 總結字符串不能用==比較需要調用內部庫函數
- else if(a=="ONB") hout();//后退
- else if(a=="ONC") zuoz();//左轉
-
- else if(a=="OND") youz();//右轉
-
- else tingz();//停止 */
- }
- /*****************************************************************************/
- void dangwei() //檔位函數
- {
- if (strcmp(table,"ON1") ==0 )
- pushjishu=0;
- if (strcmp(table,"ON2") ==0 ) //判斷是否按下按鍵
- {
- //pushjishu=pushjishu+10;
- pushjishu+=10; //x+=y;相當與x=x+y;這樣使程序更精煉
- while (strcmp(table,"ON2") ==0 ); //當按鍵按下的時候進入while循環執行分號空語句,
- //當按鍵是釋放跳出while循環,很好的使按鍵按下一次執行一次,不會跑飛
- }
- if (strcmp(table,"ON3") ==0 )
- {
- //pushjishu=pushjishu-10;
- pushjishu-=10;
- while (strcmp(table,"ON3") ==0 );
- }
- /* if (strcmp(table,"ON4") ==0 )
- pushjishu=105;
- /*if(strcmp(table,"ON5")==0)
- pushjishu=160;
- if(strcmp(table,"ON6")==0)
- pushjishu=200; */
- }
- /**************************************************************************/
- void zxddc () //轉向燈 后退 剎車指示燈 。函數需要在前面聲明,因為電機函數定義在此函數前面,在電機函數調用此函數會出現錯誤
- {
- LEDHZ = 0;
- LEDHY = 0;
- }
- void zxdzz () //轉向燈左轉
- {
- LEDHZ = 0;
- LEDHY = 1;
- }
- void zxdyz () //轉向燈右轉
- {
- LEDHZ = 1;
- LEDHY = 0;
- }
- void zxdgd () //轉向燈關燈
- {
- LEDHZ = 1;
- LEDHY = 1;
- }
- /***************************************************************************/
- void kaideng() //開前大燈燈函數
- {
- if ( strcmp(table,"ON7") == 0 ) //開燈
- {
- LED1=0;
- LED2=0;
- }
- if ( strcmp(table,"ON8") == 0 )//關燈
- {
- LED1=1;
- LED2=1;
- }
- }
- /*************************************************************************/
- void laba()
- {
- if(strcmp(table,"ON9")==0)
- {
- fmq = 1; //給高電平
- Delay(5); //延時
- fmq = 0; //給低電平
- Delay(5);
- }
- }
- /**********************************************************/
- void pwm(void)//小車快慢pwm調速,是通過l298n完成的
- {
- if(pwmjishu<=pushjishu)
- {
- ena1 = 0;
- enb1 = 0;
- ena2 = 0;
- enb2 = 0; //l298n,實現pwm調速,當給高電頻的時候io引腳有效,給低電平時無效
- }
- else
- {
- ena1 = 1 ;
- enb1 = 1 ;
- ena2 = 1 ;
- enb2 = 1 ;
- }
- if(pwmjishu >= 200)
- pwmjishu = 0;
- }
- /*******************************************************************************
- 超聲波魔術手程序
- *******************************************************************************/
- void moss ()
- {
- Delay (100);
- push_val_left=14; //舵機歸中
- while(1) /*無限循環*/
- {
- dangwei();//檔位
- if(strcmp(table,"ON6")==0) //判斷按鍵 是否按下如果按下就退出csbmian函數,return結束函數
- return;
- if(timer>=1000) //100MS檢測啟動檢測一次
- {
- timer=0;
- StartModule(); //啟動檢測
- Conut(); //計算距離
- if(S<10) //距離小于20CM
- hout(); //小車停止
- if(20>S&&S>10) //距離小于20CM
- tingz();
- if(30>S&&S>20) //距離大于,30CM往前走
- qianj();
- else
- if(S>35)
- tingz();
- }
- }
- }
- /****************************************
- 超聲波壁障主函數
- /***************************************************************/
- /* delay_50us(500);
- TMOD=0X11;
- TH1=(65536-100)/256; //100US定時
- TL1=(65536-100)%256;
- TH0=0;
- TL0=0;
- TR1= 1;
- ET1= 1;
- ET0= 1;
- EA = 1; */
- void csbmian ()
- {
- timer=0;
- push_val_left=14; /*舵機歸中,在初始化的時候歸要不在這歸中,如果兩個地方貴在程序就會出現毛病 兩個地方
- 同時歸中串口中斷無緣無辜的會打開,導致車子不能串口通訊, */
- delay1(50);
- while(1) //無限循環//
- {
- dangwei();//檔位
- kaideng(); //開燈函數
- laba(); //鳴笛函數
-
- if(strcmp(table,"ON6")==0) //判斷按鍵 是否按下如果按下就退出csbmian函數,return結束函數
- return;
-
- if(timer>=1000) //100MS檢測啟動檢測一次
- {
- timer=0;
- StartModule(); //啟動檢測
- Conut(); //計算距離
- if(S<45) //距離小于20CM
- {
- hout();
- hout(); //剎車
- hout();
- tingz(); //小車停止
- COMM(); //方向函數
- }
- else
- if(S>45) //距離大于,30CM往前走
- qianj();
- }
- }
- }
-
- /**********************************************************/
- void main()
- {
- T2CON=0x30; //設置定時器二為串口波特率模式
- SCON=0x50; //設置串口方式為1
- RCAP2H=0xff;
- RCAP2L=0xdc; //定時器二自動裝初值16位
- TH2=0xff;
- TL2=0xdc; //定時器二
- TR2=1; //啟動定時器2
- ES=1; //打開串口中斷
- PS=1; //串口優先級設置為最高
- TMOD=0X11; //打開定時器0和定時器1,工作做方式一
- TH1=(65536-100)/256; //100US定時
- TL1=(65536-100)%256;
- ET1=1 ; //打開定時器一中斷
- TR1=1 ; //啟動定時器一
- TH0=0; //定時器0初始化
- TL0=0; //切記定時器0不能和定時器一互換,因為定時器0優先級比1高,如果換了以后就不能接收超聲波了
- ET0=1; //打開定時器0中斷
- EA=1; //打開總中斷
-
-
-
- /* T2CON=0x30;
- SCON=0x50; //設置串口方式為1
- RCAP2H=0xff;
- RCAP2L=0xdc;
- TH2=0xff;
- TL2=0xdc;
- TMOD=0X11; //打開定時器0和定時器1,工作做方式一
- TH1=(65536-100)/256; //100US定時
- TL1=(65536-100)%256;
- TH0=0; //定時器0初始化
- TL0=0;
- ET1=1 ;
- ET0= 1; //打開定時器0中斷
- TR2=1;
- ES=1;
- PS=1;
- EA=1;
- /*******************************************/
- /* TMOD=0X11;
- TH1=(65536-100)/256; //100US定時
- TL1=(65536-100)%256;
- TH0=0;
- TL0=0;
- TR1= 1;
- ET1= 1;
- ET0= 1;
- EA=1; //總開關
- /******************************************/
- //單獨藍牙的串口設置
- /******************************************/
- /*TMOD=0x21;//定時器1工作方式2,8位自動重裝
- TH0=(65536-100)/256; //100US定時
- TL0=(65536-100)%256;
- TH1=0xFd; //11.0592M晶振,9600波特率
- TL1=0xFd;
- PS=1;
- ET0=1 ;
- TR0=1 ;
- TR1=1 ;//打開定時器1
- SM0=0 ;//串口方式1 SM0 SM1 01 允許接收
- SM1=1 ;//SMOD=0 16分頻
- REN=1 ;
- ES=1 ;//打開串口中斷
- EA=1;//開總中斷 */
- //以上跟串口通信初始化有關
- while(1)
- {
- dangwei();//檔位
- fangx(); //方向函數
- kaideng(); //開燈函數
- laba(); //鳴笛函數
- if(strcmp(table,"ON5")==0)//判斷是否按下第五個按鍵,按下則啟動超聲波模式
- csbmian (); //超聲波模塊的主函數
- if(strcmp(table,"ON4")==0)//判斷是否按下第四個按鍵,按下則啟動超聲波魔術手
- moss (); //超聲波魔術手模塊的主函數
- }
- }
- /***************************************************/
- ///*TIMER1中斷服務子函數產生PWM信號*/
- void pwmdins()interrupt 3 //定時器一,優先級別最低
- {
- TH1=(65536-100)/256; //100US定時
- TL1=(65536-100)%256;
- pwmjishu++; // 小車快慢的pwm調速
- pwm(); //小車快慢的pwm函數
- timer++; //超聲波的基準 定時器100US為準。在這個基礎上延時
- pwm_val_left++; //舵機的pwm調速基準時間
- pwm_Servomoto(); //舵機pwm調速函數
- }
- /***************************************************/
- ///*TIMER0中斷服務子函數產生PWM信號*/
- void timer0()interrupt 1 //因為串口優先級別變最高所以定時器0位第二高
- {
- }
- /***************************************************/
- void serial() interrupt 4 //中斷子函數 //ps=1;使之優先級最高
- {
- int i;
- ES=0; //關閉串口中斷,其實不關也沒影響
- table[i++]=SBUF; //數組下標加一,把字符串變成字符字單個取出存入數組,使之成為一元素
- if(i==3) //字符串有三個字符,不包括標志位0
- i=0; //使之清零以便下次從收
- RI=0; //串口標志位硬件制一,手動清零
- ES=1; //打開串口
- …………
- …………
- …………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼
原理圖: 無
仿真: 無
代碼:
寶馬自動駕駛.zip
(53.9 KB, 下載次數: 509)
2017-12-5 10:29 上傳
點擊文件名下載附件
程序帶詳細注解 下載積分: 黑幣 -5
|