從本文開始,在之後的一段時間裏,我會通過本系列文章,詳細介紹如何從零開始用51單片機去實現智能小車的控制,本文作爲本系列的第一篇文章,主要介紹如何讓小車動起來。
本系列文章鏈接:
-----------------------------------------------------------------------------
詳細介紹如何從零開始製作51單片機控制的智能小車(一)———讓小車動起來
詳細介紹如何從零開始製作51單片機控制的智能小車(二)———超聲波模塊、漫反射光電管、4路紅外傳感器的介紹和使用
詳細介紹如何從零開始製作51單片機控制的智能小車(三)———用超聲波模塊和漫反射光電傳感器實現小車的自動避障
詳細介紹如何從零開始製作51單片機控制的智能小車(四)———通過藍牙模塊實現數據傳輸以及通過手機藍牙實現對小車運動狀態的控制
詳細介紹如何從零開始製作51單片機控制的智能小車(五)———對本系列第四篇文章介紹的手機藍牙遙控加減速異常的錯誤的介紹及糾正
-----------------------------------------------------------------------------
一、硬件的選擇
1、底盤和電機
底盤的形狀呢,大家可以按照自己的需要自主選取,至於電機關注一下工作電壓,轉速,電機類型就差不多,對於新手,可以嘗試以下樣式(4WD智能小車底盤,附帶4個直流減速電機,電機接線需要自己焊接),也就是本文例子採用的底盤和電機,組裝簡單,使用方便,特別適合新手。
2、電機驅動模塊
L298N電機驅動模塊,絕對是新手的首選,但是此係列也包含了很多類型,本文采用的是L298N雙H橋驅動 紅色版 ,除了性能外,我選擇它是因爲它具備了5v的輸出接口,可以用來給單片機供電。大家可以用兩個這種驅動,也可以用一個,另一個用個便宜點的。
由於家中有一個如下式樣的L298N驅動,所以爲了不讓資源浪費,另一個,我就用如下型號的L298N驅動。
3、單片機最小系統
關於最小系統,大家只要選用自己熟悉的就行了,沒什麼特別的講究,我採用的樣式如下(芯片採用的是STC89C52)
4、電源
這一部分大家根據需要自己選擇即可,選的時候注意一下電壓和容量就行,我選用的是常見的 9v 650mAh(容量不是很大,但是這種電池比較常見,充一次電跑2~3小時應該不是問題),我選的是USB充電款,充電很方便,電池盒我選用的是如下的這種拆卸方便的款式,缺點就是不附帶電源開關。
5、杜邦線
這是必備的輔件,就不多說了,公對公,母對母,公對母(這一種一般用的多一些)都要買一些,家裏常備物品。
二、硬件的連接
本文涉及到的硬件連接爲單片機、電源、 電機、 兩個電機驅動L298N之間的連接,在這裏我介紹一種參考的連接方式,大家可以自己設計連接方案
如上圖所示,四個電機的正負極分別接兩個L298N的綠色電機接口,至於到底哪個接正極,哪個接負極,根據你電機安裝的方式而定,建議先把電機的兩根線焊上,然後把底盤安裝起來,這樣電機的安裝方式就確定了,先隨便把兩個L298N的4個綠色電機接口跟電機相接,等到把其他信號線接好後,再判斷對錯並調節,調節方法如下:在程序中讓小車往前跑,觀察車輪的轉向,往前轉的車輪的線不用變,把往後轉的電機對應的L298N綠色接口的兩根線換一下就行了。
如上圖所示,L298N的左邊數第一個藍色端口 是5V輸出,把其中一個L298N的該接口接到單片機的5v接口上,另一L298N該接口可以空着,左邊數第二個藍色端口是GND需要同時與單片機的GND與電源的負極相接,左邊數第三個藍色端口是L298N的電源輸入端口,與電源的正極相接,我採用的是9v的電源。
剩下的就是L298N的信號線與單片機的連接了,介紹如上圖所示,在這裏我採用的是雙驅的接法,也就是左邊兩個點擊用同一個信號控制,右邊兩個電機用同一個信號控制,單片機的I/O口自行選擇,與程序配合起來就行,我選用的是 ENA接P16 ENB 接P17 IN1接P34 IN2接P35 IN3接P36 IN4接P37 若改爲4驅所需的I/O將擴大一倍。
實物圖片如下:
三、程序的編寫
1、工程的建立
編譯環境根據自己習慣和需要選擇,本文以KEIL C51爲例,由於本次設計的小車控制並不複雜,所以我把工程中用到的所有頭文件、函數的定義、sbit定義的位變量都放到了一個頭文件中,取名爲car.h(名字大家隨意取即可),C文件呢我建議大家把各個部分別寫在不同的文件中,比如我把與電機驅動有關的函數放到了motor_control.c(名字任意取)文件中,控制方案和延時函數,中斷函數放到了主函數main.c(名字任意取)文件中,後續隨着功能增加還會增設其他的C文件,只要所有的C文件均包含以上共同的頭文件car.h,也就互相建立了聯繫。
2、根據L298N與單片機的接線,編寫電機控制函數
雖然說本文選用的車型四個電機可以獨立控制,但是爲了簡單化,方便化,我們讓左邊的兩個電機採用共同的信號控制,右邊的兩個電機採用共同的信號控制,大家若需要可以自主改爲4路獨立的信號控制,根據本文第二部分——硬件的連接部分的介紹,我們選用了單片機的P34 P35 I/O口作爲左電機的方向控制信號,單片機的P36 P37 I/O口作爲右電機的方向控制信號,單片機的P16 I/O口作爲左電機的PWM輸出控制信號,單片機的P17 I/O口作爲右電機的PWM輸出控制信號。
以上6個I/O口的位定義如下(爲方便各文件調用,我們把它放到統一的h文件car.h中)
sbit Left_moto_pwm=P1^6 ;
sbit Right_moto_pwm=P1^7;
sbit p34=P3^4;
sbit p35=P3^5;
sbit p36=P3^6;
sbit p37=P3^7;
左右電機的狀態控制函數如下:
void Left_moto_go() //左電機正轉
{p34=0;p35=1;}
void Left_moto_back() //左電機反轉
{p34=1;p35=0;}
void Left_moto_stp() //左電機停轉
{p34=1;p35=1;}
void Right_moto_go() //右電機正轉
{p36=0;p37=1;}
void Right_moto_back() //右電機反轉
{p36=1;p37=0;}
void Right_moto_stp() //右電機停轉
{p36=1;p37=1;}
4、PWM調速輸出函數的編寫:
對於新手來說,如果理解不了以下兩個函數,那隻需要知道如何使用就行了,即通過修改push_val_left的值就可以調節左電機的轉速,通過修改push_val _right的值就可以調節右電機的轉速,push_val_left和push_val_right的值均位於1到10之間,值越大電機轉速越快
bit Left_moto_stop =1;
bit Right_moto_stop =1;
unsigned char pwm_val_left =0;
unsigned char push_val_left =0;
unsigned char pwm_val_right =0;
unsigned char push_val_right=0;
void pwm_out_left_moto(void) //左電機調速
{
if(Left_moto_stop)
{
if(pwm_val_left<=push_val_left)
Left_moto_pwm=1;
else
Left_moto_pwm=0;
if(pwm_val_left>=10)
pwm_val_left=0;
}
else
Left_moto_pwm=0;
}
void pwm_out_right_moto(void) //右電機調速
{
if(Right_moto_stop)
{
if(pwm_val_right<=push_val_right)
Right_moto_pwm=1;
else
Right_moto_pwm=0;
if(pwm_val_right>=10)
pwm_val_right=0;
}
else
Right_moto_pwm=0;
}
5、小車姿態控制函數的編寫:
理解了 左右電機的狀態控制函數,編寫小車姿態控制函數就很簡單了,大家稍微想一下小車左右輪的狀態,小車會怎麼運行,就理解了,比如 左右電機都正轉,那小車運行狀態肯定是前行。每個函數的前兩行是左右電機轉速的設置。
unsigned char Left_Speed_Ratio; //左電機轉速的設定值
unsigned char Right_Speed_Ratio; //右電機轉速的設定值
void run(void) //小車前行
{
push_val_left =Left_Speed_Ratio;
push_val_right =Right_Speed_Ratio;
Left_moto_go();
Right_moto_go();
}
void back(void) //小車後退
{
push_val_left =Left_Speed_Ratio;
push_val_right =Right_Speed_Ratio;
Left_moto_back();
Right_moto_back();
}
void left(void) //小車左轉
{
push_val_left =Left_Speed_Ratio;
push_val_right =Right_Speed_Ratio;
Right_moto_go();
Left_moto_stp();
}
void right(void) //小車右轉
{
push_val_left =Left_Speed_Ratio;
push_val_right =Right_Speed_Ratio;
Right_moto_stp();
Left_moto_go();
}
void stop(void) //小車停止
{
push_val_left =Left_Speed_Ratio;
push_val_right =Right_Speed_Ratio;
Left_moto_stp();
Right_moto_stp();
}
void rotate(void) //小車原地轉圈
{
push_val_left =Left_Speed_Ratio;
push_val_right =Right_Speed_Ratio;
Left_moto_back();
Right_moto_go();
}
6、與定時器中斷有關函數的編寫
void Timer0Init() //定時器初始化函數
{
TMOD|=0X01;//選擇爲定時器0模式,工作方式1,僅用TR0打開啓動。
TH0=0XFC; //給定時器賦初值,定時1ms
TL0=0X18;
ET0=1;//打開定時器0中斷允許
EA=1;//打開總中斷
TR0=1;//打開定時器
}
void timer0()interrupt 1 using 2 //定時器中斷函數,此處配置爲1ms產生一次中斷,對PWM的輸出進行控制
{
TH0=0XFC; //給定時器賦初值,定時1ms
TL0=0X18;
time++;
pwm_val_left++;
pwm_val_right++;
pwm_out_left_moto();
pwm_out_right_moto();
}
7、延時函數的編寫
關於延時函數,大家只要會用就行,可以用單片機小精靈等輔助軟件生成,以下爲延時1秒的函數
void delay1s(void)
{
unsigned char a,b,c;
for(c=167;c>0;c--)
for(b=171;b>0;b--)
for(a=16;a>0;a--);
_nop_();
}
8、主函數內容的編寫
關於主函數的內容,首先要調用定時器中斷初始化函數,其次要設置左右電機的速度參數,本文的主要內容是讓車動起來,所以主函數內要調用本部分第5步中編寫的小車姿態控制函數,對其進行檢驗,爲了便於觀察兩個狀態之間加了5秒的延時,代碼如下:
void main()
{
Timer0Init();
Left_Speed_Ratio=5; //設置左電機車速爲最大車速的50%
Right_Speed_Ratio=5; ////設置右電機車速爲最大車速的50%
while(1)
{
run();
delay1s(); delay1s(); delay1s(); delay1s(); delay1s();
back();
delay1s(); delay1s(); delay1s(); delay1s(); delay1s();
left();
delay1s(); delay1s(); delay1s(); delay1s(); delay1s();
right();
delay1s(); delay1s(); delay1s(); delay1s(); delay1s();
stop();
delay1s(); delay1s(); delay1s(); delay1s(); delay1s();
rotate();
delay1s(); delay1s(); delay1s(); delay1s(); delay1s();
}
}
四、本文例子完整的C文件和H文件代碼
1、motor_control.c文件完整代碼如下:
#include <car.h>
unsigned char pwm_val_left =0;
unsigned char push_val_left =0;
unsigned char pwm_val_right =0;
unsigned char push_val_right=0;
unsigned char Left_Speed_Ratio;
unsigned char Right_Speed_Ratio;
bit Left_moto_stop =1;
bit Right_moto_stop =1;
void Left_moto_go() //左電機正轉
{p34=0;p35=1;}
void Left_moto_back() //左電機反轉
{p34=1;p35=0;}
void Left_moto_stp() //左電機停轉
{p34=1;p35=1;}
void Right_moto_go() //右電機正轉
{p36=0;p37=1;}
void Right_moto_back() //右電機反轉
{p36=1;p37=0;}
void Right_moto_stp() //右電機停轉
{p36=1;p37=1;}
void pwm_out_left_moto(void) //左電機PWM
{
if(Left_moto_stop)
{
if(pwm_val_left<=push_val_left)
Left_moto_pwm=1;
else
Left_moto_pwm=0;
if(pwm_val_left>=10)
pwm_val_left=0;
}
else
Left_moto_pwm=0;
}
void pwm_out_right_moto(void) //右電機PWM
{
if(Right_moto_stop)
{
if(pwm_val_right<=push_val_right)
Right_moto_pwm=1;
else
Right_moto_pwm=0;
if(pwm_val_right>=10)
pwm_val_right=0;
}
else
Right_moto_pwm=0;
}
void run(void) //小車前行
{
push_val_left =Left_Speed_Ratio;
push_val_right =Right_Speed_Ratio;
Left_moto_go();
Right_moto_go();
}
void back(void) //小車後退
{
push_val_left =Left_Speed_Ratio;
push_val_right =Right_Speed_Ratio;
Left_moto_back();
Right_moto_back();
}
void left(void) //小車左轉
{
push_val_left =Left_Speed_Ratio;
push_val_right =Right_Speed_Ratio;
Right_moto_go();
Left_moto_stp();
}
void right(void) //小車右轉
{
push_val_left =Left_Speed_Ratio;
push_val_right =Right_Speed_Ratio;
Right_moto_stp();
Left_moto_go();
}
void stop(void) //小車停止
{
push_val_left =Left_Speed_Ratio;
push_val_right =Right_Speed_Ratio;
Left_moto_stp();
Right_moto_stp();
}
void rotate(void) //小車原地轉圈
{
push_val_left =Left_Speed_Ratio;
push_val_right =Right_Speed_Ratio;
Left_moto_back();
Right_moto_go();
}
2、main.c文件完整代碼如下:
#include <car.h>
extern unsigned char Left_Speed_Ratio;
extern unsigned char Right_Speed_Ratio;
unsigned int time=0;
extern unsigned char pwm_val_left;
extern unsigned char pwm_val_right;
void delay1s(void)
{
unsigned char a,b,c;
for(c=167;c>0;c--)
for(b=171;b>0;b--)
for(a=16;a>0;a--);
_nop_();
}
void Timer0Init()
{
TMOD|=0X01;//選擇爲定時器0模式,工作方式1,僅用TR0打開啓動。
TH0=0XFC; //給定時器賦初值,定時1ms
TL0=0X18;
ET0=1;//打開定時器0中斷允許
EA=1;//打開總中斷
TR0=1;//打開定時器
}
void timer0()interrupt 1 using 2
{
TH0=0XFC; //給定時器賦初值,定時1ms
TL0=0X18;
time++;
pwm_val_left++;
pwm_val_right++;
pwm_out_left_moto();
pwm_out_right_moto();
}
void main()
{
Timer0Init();
Left_Speed_Ratio=5; //設置左電機車速爲最大車速的50%
Right_Speed_Ratio=5; ////設置右電機車速爲最大車速的50%
while(1)
{
run();
delay1s(); delay1s(); delay1s(); delay1s(); delay1s();
back();
delay1s(); delay1s(); delay1s(); delay1s(); delay1s();
left();
delay1s(); delay1s(); delay1s(); delay1s(); delay1s();
right();
delay1s(); delay1s(); delay1s(); delay1s(); delay1s();
stop();
delay1s(); delay1s(); delay1s(); delay1s(); delay1s();
rotate();
delay1s(); delay1s(); delay1s(); delay1s(); delay1s();
}
}
3、car.h文件完整代碼如下:
#ifndef __car_H
#define __car_H
#include <reg52.h>
#include <intrins.h>
sbit Left_moto_pwm=P1^6 ;
sbit Right_moto_pwm=P1^7;
sbit p34=P3^4;
sbit p35=P3^5;
sbit p36=P3^6;
sbit p37=P3^7;
void Left_moto_go() ;
void Left_moto_back() ;
void Left_moto_stp() ;
void Right_moto_go();
void Right_moto_back();
void Right_moto_stp();
void delay(unsigned int k) ;
void delay1s(void) ;
void pwm_out_left_moto(void) ;
void pwm_out_right_moto(void);
void run(void);
void back(void);
void left(void);
void right(void);
void stop(void);
void rotate(void);
五、本文例子實物視頻演示
實物視頻演示視頻鏈接
點擊上面的鏈接即可查看本文介紹內容的視頻演示,內容依次爲(即主函數中程序的內容):前進5秒 、後退5秒、左轉5秒、右轉5秒、停轉5秒、轉圈5秒。附視頻網址:
https://www.bilibili.com/video/bv1N5411x7zL
本文到這裏就結束了,本文完整的工程文件我會放在附件裏,需要者自取,我放的時候都是免費的,但是過段時間它會自己漲…需要的在評論區留言我可以直接發給你,歡迎大家繼續閱讀本系列的後續文章“詳細介紹如何從零開始製作51單片機控制的智能小車(二)———超聲波模塊、漫反射光電管、4路紅外傳感器的介紹和使用”
歡迎大家積極交流,本文未經允許謝絕轉載