考慮到大部分學校,會發放簡易小車來作為智能車初期培訓和篩選的工具,
于是,我寫一個簡單的教程,能夠實現簡單小車的電磁循跡。
通過這個教程,能夠通過簡化的步驟搭建尋跡小車,進而了解整個智能車是如何實現的,快速上手,為后續參與智能車競賽做準備。
這里我不會講解原理,直接手把手帶著使用,需要看原理的時候就看我相關博客。
目錄
一、準備
C語言
單片機
二、器件
三、安裝編程環境軟件KEIL
1.安裝KEIL
?2.激活License
?3.安裝pack包
四、下載逐飛開源庫
五、測試器件
電機轉
屏幕
ADC
六、裝車
七、循跡
電機
循跡
一、準備
C語言
智能車入門——編程語言(c)的學習
?智能車入門補充篇——模塊化編程
首先要有一定的C語言基礎。
想要學好嵌入式,C語言必須學會!
這里一定不要為了進度圖快,打好基礎很重要。當時帶我們的學長,給了我們一周的時間讓我們復習C語言。
推薦平臺:
菜鳥教程 - 學的不僅是技術,更是夢想!
?郝斌C語言
下面必須要掌握:
初學階段要學會掌握基本的概念、函數、數組、語法關鍵詞if,for,while的使用即可,指針與結構體部分可以在后期再進行補充學習。
這雖然就兩行字,但是一定要扎實,好好打好基礎,數據類型、運算符號都要會,別到時候用除法打了個"\"還不知道哪里錯了。uint=unsigned int這種小知識別漏了。
單片機
需要簡單了解一下什么是單片機,起碼知道什么是IO口。
智能車入門——I/O、PWM
推薦學習平臺:
51單片機普中科技視頻完整版0基礎入門學習_嗶哩嗶哩_bilibili
51單片機入門教程-2020版 程序全程純手打 從零開始入門_嗶哩嗶哩_bilibili
?最低的要求是跟著教程,能夠點亮LED燈。
二、器件
一個舵機將近100塊,一個攝像頭得兩三百,大部分學校選拔應該會選用這種廉價的小車,靠電機實現前進和轉向。
那么我就拿這種最簡單的小車舉例,介紹循跡最起碼有的器件:
單片機(一般是STC)
電源(電池),
電機驅動(一般練手用的是L298N),
電機(小馬達)、轱轆,
還有傳感器,光電循跡用光電傳感器,電磁循跡用電容電感對+運放
如果硬件給力點,還會有主板將前面的接口合并到一個板子上
為了方便看參數,還會有屏幕。
三、安裝編程環境軟件KEIL
Keil?C51是美國Keil軟件公司(現已被ARM公司收購)出品的支持8051系列單片機架構的一款?IDE
?【精選】智能車入門——IDE安裝以及庫函數選用
STC8系列 MDK FOR C51 IDE軟件
鏈接:https://pan.baidu.com/s/10eqOQOFn7JapLJ_1Wc_DTQ? ?提取碼:aom2
STC16專用 MDK FOR C251 IDE軟件:鏈接:https://pan.baidu.com/s/1euVGEsRCV_novTHqnhQD7Q? ?提取碼:krw6
?需要這三個文件,MDK532是keil的安裝文件,keygen是破解軟件,C51V960a是C51的pack包
1.安裝KEIL
首先點擊運行mdk532.exe文件
然后一路Next
路徑自己選,name隨便填
?2.激活License
(1)右擊圖標,用管理員身份運行!
(2)把ID復制下來
(3)把電腦靜音
(4)右擊keygen_new2032,用管理員身份運行
?把ID粘貼進去,
Target這里,STC8選C51,STC32選C251
不知道自己手里的該裝哪個,你就百度或者問賣板子的客服
下面的選prof....PLUS
點擊Generate,生成激活碼
?(5)打開KEIL復制生成的激活碼,粘貼在New License ID Code處,點擊Add LIC,即可成功激活mdk,顯示mdk的使用期限2032年
?3.安裝pack包
雙擊c51v960a.exe,一路next。
這里pack包需要與自己的單片機相匹配,沒有pack包的話,向賣板子的客服要就行了。
四、下載逐飛開源庫
?智能車入門——庫函數選用
找到自己的型號下載?
SeekFree (seekfree) - Gitee.com
?復制Seekfree_XXXXXXX_Opensource_Library文件夾,在此基礎上增添代碼,最后放到中文路徑。
Seekfree_STC8A8K64S4_Opensource_Library\Project\MDK
雙擊該路徑下的SEEKFREE.uvproj文件,即可打開工程
五、測試器件
首先寫代碼,看自己能不能調用那些器件。
【逐飛科技】STC8G2K 核心板與智能車常用模塊搭配使用視頻教程_嗶哩嗶哩_bilibili
【精選】智能車入門——簡單驅動常用模塊
電機轉
電機驅動有兩種
一種是兩路PWM,另一種是一路PWM,一路 GPIO。
兩路PWM,就是根據兩個pwm信號 差值的正負決定電機轉動方向,差值大小決定電機轉速,
?一路PWM,一路 GPIO,就是pwm控制轉速,GPIO控制方向。
想知道你手上的驅動屬于哪一種,你就淘寶掃一掃識圖,看哪家店賣的一模一樣,然后看商品介紹。
以一路PWM,一路 GPIO舉例:
#include "headfile.h"uint16 duty = 7000;void main()
{DisableGlobalIRQ(); //1?±?×ü?D??board_init(); pwm_init(PWM5_P25, 10000, 9500); EnableGlobalIRQ(); //?a??×ü?D??while(1){pwm_duty(PWM5_P25,duty);gpio_pull_set(P2_6, 0);}
}
這就實現了讓一個電機固定轉速轉。
接下來測試整個驅動好不好使
#include "My.h"void pwm_duty_init()
{pwm_init(PWM3_P63,17000,0);pwm_init(PWM4_P64,17000,0);}
/****************************************************************
電機驅動測試
12假設2路pwm的正反轉
34假設64口控制方向的正反轉(1個PWM,1控制方向)
56假設63口控制方向的正反轉(1個PWM,1控制方向)
****************************************************************/
void mitor_duty(char mode)
{
if(mode==1)
{pwm_duty(PWM3_P63,0);pwm_duty(PWM4_P64,800);
}
if(mode==2)
{pwm_duty(PWM3_P63,800);pwm_duty(PWM4_P64,0);
}
if(mode==3)
{pwm_duty(PWM3_P63,800);pwm_duty(PWM4_P64,0);
}
if(mode==4)
{pwm_duty(PWM3_P63,800);pwm_duty(PWM4_P64,1000);
}
if(mode==5)
{pwm_duty(PWM3_P63,0);pwm_duty(PWM4_P64,800);
}
if(mode==6)
{pwm_duty(PWM3_P63,1000);pwm_duty(PWM4_P64,800);
}}
#ifndef __MY_H_
#define __MY_H_
#include "headfile.h"void pwm_duty_init();void mitor_duty(char mode);#endif
屏幕
下面是常見三款屏幕,同樣的,不知道什么型號就淘寶搜,不會接線就問客服。
我以1.8TFT舉例:
首先去淘寶搜到這個型號屏幕,在商品詳情頁可以看到引腳名稱
在?seekfree_peripheral文件夾下找到屏幕對應的文件
?首先打開18TFT.h文件找到接線定義:
?
?? ??? ??? ??? ??? ?接線定義:
?? ??? ??? ??? ??? ?------------------------------------?
?? ??? ??? ??? ??? ??? ?模塊管腳 ? ? ? ? ? ?單片機管腳
?? ??? ??? ??? ??? ??? ?SCL ? ? ? ? ? ? ? ? 查看TFT_SCL_PIN?? ??? ?宏定義的引腳 ? ? 硬件SPI引腳不可隨意切換
?? ??? ??? ??? ??? ??? ?SDA ? ? ? ? ? ? ? ? 查看TFT_SDA_PIN?? ??? ?宏定義的引腳 ? ? 硬件SPI引腳不可隨意切換
?? ??? ??? ??? ??? ??? ?RES ? ? ? ? ? ? ? ? 查看REST_PIN?? ??? ?宏定義的引腳 ? ?
?? ??? ??? ??? ??? ??? ?DC ? ? ? ? ? ? ? ? ?查看DC_PIN_PIN?? ??? ?宏定義的引腳 ?
?? ??? ??? ??? ??? ??? ?CS ? ? ? ? ? ? ? ? ?查看TFT_CS_PIN?? ??? ?宏定義的引腳 ? ? ?
?? ??? ??? ??? ??? ??? ?
?? ??? ??? ??? ??? ??? ?電源引腳
?? ??? ??? ??? ??? ??? ?BL ?3.3V電源(背光控制引腳,也可以接PWM來控制亮度)
?? ??? ??? ??? ??? ??? ?VCC 3.3V電源
?? ??? ??? ??? ??? ??? ?GND 電源地
?? ??? ??? ??? ??? ??? ?最大分辨率128*160
?? ??? ??? ??? ??? ?------------------------------------?
//--------------------軟件SPI--------------------
#define?? ?TFT_SCL_SIMSPI_PIN ?? ??? ?P25?? ??? ??? ??? ?//定義SPI_SCK引腳
#define?? ?TFT_SDA_SIMSPI_PIN?? ??? ?P23 ? ?? ??? ??? ?//定義SPI_MOSI引腳
#define TFT_REST_SIMSPI_PIN ??? ?P20?? ??? ??? ??? ?//定義復位引腳
#define TFT_DC_SIMSPI_PIN?? ? ??? ?P21?? ??? ??? ??? ?//液晶命令位引腳定義
#define TFT_CS_SIMSPI_PIN?? ? ??? ?P22?? ??? ??? ??? ?//定義SPI_CS引腳
#define TFT_BL_SIMSPI_PIN?? ? ??? ?P24?? ??? ??? ??? ?//液晶背光引腳定義 ?//--------------------硬件SPI--------------------
#define TFT_SPIN SPI_2?? ??? ??? ??? ? ?? ?//定義使用的SPI號
#define?? ?TFT_SCL_PIN ?? ?SPI2_SCLK_P25?? ?//定義SPI_SCK引腳
#define?? ?TFT_SDA_PIN?? ??? ?SPI2_MOSI_P23 ? //定義SPI_MOSI引腳
#define?? ?TFT_SDA_IN_PIN?? ?SPI2_MISO_P24 ? //定義SPI_MISO引腳 ?TFT屏幕沒有MISO引腳,但是這里任然需要定義,在spi的初始化時需要使用#define TFT_REST_PIN ??? ?P20
#define TFT_DC_PIN?? ? ??? ?P21
#define TFT_CS_PIN?? ? ??? ?P22?? ??? ??? ?//定義SPI_CS引腳
#define TFT_BL_PIN?? ? ??? ?P24
?根據接線定義去接線,硬件SPI、軟件SPI根據喜好去選就行了。
函數有這些:
//--------------------ó2?tSPI--------------------
void lcd_init(void);
void lcd_clear(int color);
void lcd_drawpoint(uint16 x,uint16 y,uint16 color);
void lcd_showchar(uint16 x,uint16 y,uint8 dat);
void lcd_showstr(uint16 x,uint16 y,uint8 dat[]);
void lcd_showint8(uint16 x,uint16 y,int8 dat);
void lcd_showuint8(uint16 x,uint16 y,uint8 dat);
void lcd_showint16(uint16 x,uint16 y,int16 dat);
void lcd_showuint16(uint16 x,uint16 y,uint16 dat);
void lcd_showint32(uint16 x,uint16 y,int32 dat,uint8 num);
void lcd_showfloat(uint16 x,uint16 y,double dat,uint8 num,uint8 pointnum);
void showimage(const unsigned char *p);
然后初始化、調用代碼就行了
/********************************************************************************************************************** COPYRIGHT NOTICE* Copyright (c) 2020,逐飛科技* All rights reserved.* 技術討論QQ群:一群:179029047(已滿) 二群:244861897(已滿) 三群:824575535** 以下所有內容版權均屬逐飛科技所有,未經允許不得用于商業用途,* 歡迎各位使用并傳播本程序,修改內容時必須保留逐飛科技的版權聲明。** @file main* @company 成都逐飛科技有限公司* @author 逐飛科技(QQ790875685)* @version 查看doc內version文件 版本說明* @Software MDK FOR C51 V9.60* @Target core STC8A8K64S4* @Taobao https://seekfree.taobao.com/* @date 2020-5-13********************************************************************************************************************/#include "headfile.h"board.h文件中FOSC的值設置為0,則程序自動識別系統頻率///*board.h文件中FOSC的值設置不為0,則系統頻率為FOSC的值,
//在使用stc-isp工具下載程序的時候需要將IRC頻率設置為FOSC的值*/void main()
{DisableGlobalIRQ(); //關閉總中斷board_init(); //初始化內部寄存器,勿刪除此句代碼。lcd_init();//此處編寫用戶代碼(例如:外設初始化代碼等)EnableGlobalIRQ(); //開啟總中斷while(1){//此處編寫需要循環執行的代碼
// lcd_showstr(0,0,"lucky");
// pca_delay_ms(1000);lcd_showchar(0,0,'x');//坐標0,0寫一個字符x}
}
ADC
同樣的運放,哪里弄得,從哪里獲取資料
最簡單的循跡只需要2個電感電容對,按照下面的接線就行
?將采集到的電感值顯示到屏幕上
/********************************************************************************************************************** COPYRIGHT NOTICE* Copyright (c) 2020,逐飛科技* All rights reserved.* 技術討論QQ群:一群:179029047(已滿) 二群:244861897(已滿) 三群:824575535** 以下所有內容版權均屬逐飛科技所有,未經允許不得用于商業用途,* 歡迎各位使用并傳播本程序,修改內容時必須保留逐飛科技的版權聲明。** @file main* @company 成都逐飛科技有限公司* @author 逐飛科技(QQ790875685)* @version 查看doc內version文件 版本說明* @Software MDK FOR C51 V9.60* @Target core STC8A8K64S4* @Taobao https://seekfree.taobao.com/* @date 2020-5-13********************************************************************************************************************/#include "headfile.h"board.h文件中FOSC的值設置為0,則程序自動識別系統頻率///*board.h文件中FOSC的值設置不為0,則系統頻率為FOSC的值,
//在使用stc-isp工具下載程序的時候需要將IRC頻率設置為FOSC的值*/void main()
{DisableGlobalIRQ(); //關閉總中斷board_init(); //初始化內部寄存器,勿刪除此句代碼。lcd_init();adc_init(ADC_P01,ADC_SYSclk_DIV_2); //adc_init(ADC_P02,ADC_SYSclk_DIV_2); ////此處編寫用戶代碼(例如:外設初始化代碼等)EnableGlobalIRQ(); //開啟總中斷while(1){//此處編寫需要循環執行的代碼lcd_showuint16(2,2,adc_once(ADC_P01, ADC_10BIT) );lcd_showuint16(3,3,adc_once(ADC_P02, ADC_10BIT) );}
}
六、裝車
七、循跡
智能車入門——跑車前的零碎知識
?智能車入門補充篇——電感值處理、轉向控制與巡線
?智能車入門——電磁循跡原理與實現
電機
#include "dianji.h"// 電機初始化
void dianji_init()
{pwm_init(PWM3_P63,17000,0); //IN1 右pwm_init(PWM4_P64,17000,0); //IN2 右 +前pwm_init(PWM5_P65,17000,0); //IN3 左 +前pwm_init(PWM6_P66,17000,0); //IN4 左
}//驅動電機
void dianji_Control(int32 LDuty, int32 RDuty)
{ if(LDuty > 0) //左正{pwm_duty(PWM5_P65, LDuty);pwm_duty(PWM6_P66, 0);}if(LDuty < 0) //左反{pwm_duty(PWM5_P65, 0);pwm_duty(PWM6_P66, LDuty);}if(RDuty > 0) //右正{pwm_duty(PWM3_P63, 0);pwm_duty(PWM4_P64, RDuty);}if(RDuty < 0) //右反{pwm_duty(PWM3_P63, RDuty);pwm_duty(PWM4_P64, 0);}if(LDuty == 0){pwm_duty(PWM3_P63, 0);pwm_duty(PWM4_P64, 0);}if(RDuty == 0){pwm_duty(PWM5_P65, 0);pwm_duty(PWM6_P66, 0);}}//限幅保護
int32 range_protect(int32 duty, int32 min, int32 max)
{if (duty >= max){return max;}if (duty <= min){return min;}else{return duty;}
}
#ifndef __dianji_H__
#define __dianji_H__
#include "headfile.h" int32 range_protect(int32 duty, int32 min, int32 max);//限幅保護
void dianji_init();
void dianji_Control(int32 LDuty, int32 RDuty);#endif
循跡
我找的小車,循跡只能靠電機的差速,由于這種小車速度很慢,因此,只需要偏差乘一個比例系數就能簡單循跡,相當于PID中只給P系數,I、D的值為0.
首先初始化各個器件
void all_init()
{adc_init(ADC_P01,ADC_SYSclk_DIV_2); //3?ê??ˉP1.0?aADC1|?ü,ADCê±?ó?μ?ê£oSYSclk/2adc_init(ADC_P02,ADC_SYSclk_DIV_2); //3?ê??ˉP1.0?aADC1|?ü,ADCê±?ó?μ?ê£oSYSclk/2dianji_init(); //μ??ú3?ê??ˉlcd_init(); //?á??3?ê??ˉpd_init();
}
獲取ADC
void adc_collect()
{
adc1=adc_once(ADC_P01, ADC_10BIT);
adc4=adc_once(ADC_P02, ADC_10BIT);
}
?差速循跡
float kp=1.2;
now_error = adc1-adc4;
output=kp*now_errorLeftDuty =600-output;
RightDuty=600+output;LeftDuty = range_protect( LeftDuty,-200, 1000);
RightDuty= range_protect(RightDuty,-200, 1000);
dianji_Control(LeftDuty,RightDuty);
我會貼上完整代碼,用來參考。
舉一反三,如果要用到按鍵、舵機、陀螺儀等也是同樣的步驟。