Arduino A4950 驅動直流電機 超詳細版
Arduino A4950 驅動直流電機
對於自己做車的大部份同學來說,我和大家一樣,用的最多的就是L298N驅動器,這次在家想試著自己研究一個驅動能力更好的更加方便的電機驅動,而網上使用Arduino L298N 驅動小車的例子非常的多 A4950 的一篇也沒有,那好吧,希望這篇文章能給L298N用膩了的同學提供一個更好更新的選項
1.實驗準備
1.Arduino 系列微控制器
2.直流電機
3.A4950驅動器
2.A4950晶片簡介
一個A4950驅動器可驅動兩個直流電機
驅動板工作電壓範圍:7.6V~30V
A4950引腳 | 對應引腳 |
---|---|
VCC | 微控制器5V |
GND | 微控制器GND |
VM | 驅動電源7.6~30V |
AIN1 | 控制A電機的1號PWM引腳 |
AIN2 | 控制A電機的2號PWM引腳 |
AOUT1 | 電機A正極 |
ATOU2 | 電機A負極 |
BN1 | 控制A電機的1號PWM引腳 |
BIN2 | 控制A電機的2號PWM引腳 |
BOUT1 | 電機B正極 |
BTOU2 | 電機B負極 |
一個模組上有兩組 VCC GND VM 至少接一組
微控制器 A4950 驅動電源 記得共地
A4950 驅動是通過比較兩個控制引腳輸出PWM的大小關係來確定電機方向的
兩個控制引腳輸出PWM的差值決定電機的轉速
3.程式設計
我們接下來的程式碼都已驅動一個電機為例,剩下一個如法炮製就可以了
3.1簡易驅動板
unsigned int Motor_AIN1=2; //控制A電機的PWM引腳 一定改成自己用的
unsigned int Motor_AIN2=3;
char Motor_Order; //定義一個字元型變數儲存串列埠輸入命令
void setup()
{
Serial.begin(9600); //開啟串列埠
Serial.println("/*****開始驅動*****/");
pinMode(Motor_AIN1,OUTPUT); //設定兩個驅動引腳為輸出模式
pinMode(Motor_AIN2,OUTPUT);
}
void loop()
{
while(Serial.available()>0) //檢測串列埠是否有命令
{
Motor_Order=Serial.read(); //將命令儲存在變數中
switch(Motor_Order)
{
//傳送字元1電機正轉
case '1' : analogWrite(Motor_AIN1,250); analogWrite(Motor_AIN2,0);Serial.println("/*****電機正傳*****/");break;
//傳送字元2電機反轉
case '2' : analogWrite(Motor_AIN1,0); analogWrite(Motor_AIN2,250);Serial.println("/*****電機反轉*****/");break;
//傳送其他字元電機停轉
default : analogWrite(Motor_AIN1,0); analogWrite(Motor_AIN2,0);Serial.println("/*****停轉****/");break;
}
}
}
燒錄之後開啟串列埠分別輸入指令就可以了
3.2串列埠輸入調速版接上位機版(高階版)
好吧這個對萌新來說看起來好像有一點複雜
簡單說功能就是在串列埠按照輸入協議:
控制A電機的1號引腳PWM值.控制A電機的2號引腳PWM值
注:控制A電機的1號引腳PWM值(一個英文的點)控制A電機的2號引腳PWM值
例: 在串列埠輸入 10.255
功能:控制A電機的1號PWM引腳輸出0,控制A電機的1號PWM引腳輸出255
實現:電機反轉,控制速度的PWM差值為 255-10=245
先把完整的程式碼貼上,我會逐個部分講解
先講一下邏輯實現的步驟
1.從串列埠接收一個包含被一個點分開的兩個數字的字串
2.從一個完整字串中擷取出兩個數字字串
3.將數字字串轉換成整形
4.通過PWM引腳將轉換好的數值輸出
第二步詳細實現:1.獲取分割符號(既:點的位置)2.根據點的位置前後擷取
unsigned int Motor_AIN1=2;
unsigned int Motor_AIN2=3;
String Motor_Order,String_Motor_AIN1_Value,String_Motor_AIN2_Value;
unsigned int Motor_AIN1_Value,Motor_AIN2_Value,Point_desepote;
void setup()
{
// put your setup code here, to run once:
Serial.begin(9600);
Serial.println("/*****開始測試*****/");
pinMode(Motor_AIN1,OUTPUT);
pinMode(Motor_AIN2,OUTPUT);
}
/*****************獲取截止位****************/
unsigned int Motor_Point_desepote(String Motor_Order)
{
unsigned int desepote,point_desepote;
for(desepote=0;desepote<Motor_Order.length();desepote++)
if (Motor_Order[desepote]=='.')
{
point_desepote=desepote+1;
Serial.print("點的位置為:");
Serial.println(point_desepote);
break;
}
return point_desepote;
}
/****************擷取字串函式***************/
String String_fragment(String Complete_information,unsigned int Intitial_Position,unsigned int Final_Position)
{
String Fragment;
unsigned int location;
for(location=Intitial_Position-1;location<Final_Position;location++)
Fragment+=Complete_information[location];
return Fragment;
}
/******************電機驅動函式**************/
void Drive_Motor(unsigned int Motor_AIN1_Value,unsigned int Motor_AIN2_Value)
{
analogWrite(Motor_AIN1,Motor_AIN1_Value);
analogWrite(Motor_AIN2,Motor_AIN2_Value);
Serial.println("/*****驅動電機*****/");
}
void loop()
{
// put your main code here, to run repeatedly:
while(Serial.available()>0)
{
Motor_Order=Serial.readString();
Point_desepote=Motor_Point_desepote(Motor_Order);
String_Motor_AIN1_Value=String_fragment(Motor_Order,1,Point_desepote-1);
String_Motor_AIN2_Value=String_fragment(Motor_Order,Point_desepote+1,Motor_Order.length());
// Serial.print("String_Motor_AIN1_Value:");
// Serial.println(String_Motor_AIN1_Value);
// Serial.print("String_Motor_AIN2_Value:");
// Serial.println(String_Motor_AIN2_Value);
Motor_AIN1_Value=constrain(String_Motor_AIN1_Value.toInt(),0,255);
Motor_AIN2_Value=constrain(String_Motor_AIN2_Value.toInt(),0,255);
Serial.print("Motor_AIN1_Value:");
Serial.println(Motor_AIN1_Value);
Serial.print("Motor_AIN2_Value:");
Serial.println(Motor_AIN2_Value);
if(Motor_AIN1_Value==Motor_AIN2_Value)
{
Drive_Motor(Motor_AIN1_Value,Motor_AIN2_Value);
Serial.println("電機停轉");
}
else if(Motor_AIN1_Value>Motor_AIN2_Value)
{
Drive_Motor(Motor_AIN1_Value,Motor_AIN2_Value);
Serial.println("電機正轉");
}
else if(Motor_AIN1_Value<Motor_AIN2_Value)
{
Drive_Motor(Motor_AIN1_Value,Motor_AIN2_Value);
Serial.println("電機反轉");
}
}
}
3.2.1 定義部分
unsigned int Motor_AIN1=2;
unsigned int Motor_AIN2=3;
String Motor_Order,String_Motor_AIN1_Value,String_Motor_AIN2_Value;
unsigned int Motor_AIN1_Value,Motor_AIN2_Value,Point_desepote;
變數名稱 | 功能 |
---|---|
Motor_AIN1 | 控制A電機的1號PWM引腳號 |
Motor_AIN2 | 控制A電機的2號PWM引腳 |
Motor_Order | 用來儲存串列埠處的完整指令 |
String_Motor_AIN1_Value | 儲存控制A電機的1號PWM值字串變數 |
String_Motor_AIN2_Value | 儲存控制A電機的2號PWM值字串變數 |
Motor_AIN1_Value | 儲存控制A電機的1號PWM值整形變數 |
Motor_AIN2_Value | 儲存控制A電機的2號PWM值整形變數 |
Point_desepote | 儲存初始命令點的位置 |
3.2.2獲取點的位置
/*****************獲取截止位****************/
unsigned int Motor_Point_desepote(String Motor_Order)
{
unsigned int desepote,point_desepote;
for(desepote=0;desepote<Motor_Order.length();desepote++)
if (Motor_Order[desepote]=='.')
{
point_desepote=desepote+1;
Serial.print("點的位置為:");
Serial.println(point_desepote);
break;
}
return point_desepote;
}
功能:檢索字串中點的位置並返回
注: 字串長度表示方式 : 字串名.length()
例: Motor_Order.length()
3.2.3字串擷取函式
/****************擷取字串函式***************/
String String_fragment(String Complete_information,unsigned int Intitial_Position,unsigned int Final_Position)
{
String Fragment;
unsigned int location;
for(location=Intitial_Position-1;location<Final_Position;location++)
Fragment+=Complete_information[location];
return Fragment;
}
功能:從指定字串中截從第(Intitial_Position)位擷取到第(Final_Position)位
並作為字串變數返回
注:使用方法 : String_fragment(要擷取字串變數名,擷取的初始位,擷取的終止位)
3.2.4電機驅動函式
void Drive_Motor(unsigned int Motor_AIN1_Value,unsigned int Motor_AIN2_Value)
{
analogWrite(Motor_AIN1,Motor_AIN1_Value);
analogWrite(Motor_AIN2,Motor_AIN2_Value);
Serial.println("/*****驅動電機*****/");
}
這個不多說了只要分別輸入數值就可以了
3.2.5初始化設定函式
void setup()
{
// put your setup code here, to run once:
Serial.begin(9600); //開啟串列埠
Serial.println("/*****開始測試*****/");
pinMode(Motor_AIN1,OUTPUT); //設定兩控制引腳為輸出模式
pinMode(Motor_AIN2,OUTPUT);
}
3.2.6主函式實現
void loop()
{
// put your main code here, to run repeatedly:
while(Serial.available()>0) //判斷串列埠是否接收到資料
{
Motor_Order=Serial.readString(); //將串列埠的字串存到Motor_Order中
Point_desepote=Motor_Point_desepote(Motor_Order);//獲取Motor_Order字串中點的位置
String_Motor_AIN1_Value=String_fragment(Motor_Order,1,Point_desepote-1);//擷取儲存控制A電機的1號PWM值字串變數(從第一位擷取到點的前一位)
String_Motor_AIN2_Value=String_fragment(Motor_Order,Point_desepote+1,Motor_Order.length());//擷取儲存控制A電機的2號PWM值字串變數(從點的後一位擷取到最後一位)
// Serial.print("String_Motor_AIN1_Value:");
// Serial.println(String_Motor_AIN1_Value);
// Serial.print("String_Motor_AIN2_Value:");
// Serial.println(String_Motor_AIN2_Value);
Motor_AIN1_Value=constrain(String_Motor_AIN1_Value.toInt(),0,255);//將擷取儲存控制A電機的1號PWM值字串變數轉換成整形,並設定值約束其在0~255範圍內
Motor_AIN2_Value=constrain(String_Motor_AIN2_Value.toInt(),0,255);
//將擷取儲存控制A電機的2號PWM值字串變數轉換成整形,並設定值約束其在0~255範圍內
Serial.print("Motor_AIN1_Value:"); //將數值列印以便觀察
Serial.println(Motor_AIN1_Value);
Serial.print("Motor_AIN2_Value:");
Serial.println(Motor_AIN2_Value);
//驅動控制部分
if(Motor_AIN1_Value==Motor_AIN2_Value) //如果Motor_AIN1_Value=Motor_AIN2_Value Motor_AIN1_Value,Motor_AIN2_Value 兩PWM差值為0 電機停轉
{
Drive_Motor(Motor_AIN1_Value,Motor_AIN2_Value);
Serial.println("電機停轉");
}
else if(Motor_AIN1_Value>Motor_AIN2_Value)//如果Motor_AIN1_Value>Motor_AIN2_Value , Motor_AIN1_Value-Motor_AIN2_Value 兩PWM差值為為正 電機正轉
{
Drive_Motor(Motor_AIN1_Value,Motor_AIN2_Value);
Serial.println("電機正轉");
}
else if(Motor_AIN1_Value<Motor_AIN2_Value)//如果Motor_AIN1_Value>Motor_AIN2_Value , Motor_AIN1_Value-Motor_AIN2_Value 兩PWM差值為為負 電機反轉
{
Drive_Motor(Motor_AIN1_Value,Motor_AIN2_Value);
Serial.println("電機反轉");
}
}
}
開啟串列埠輸入命令效果如圖
到這裡就全部結束了,還有一個要說的
我為什麼一定要轉換成字串型之後再轉換成整形,而不是在一個函式裡直接解決,因為arduino官方庫沒找到類似指定位置的字串擷取函式,單獨列出來方便理解,方便類似功能移植
4. 後言
本文章是通過Arduino系列微控制器程式碼實現功能,同樣的如果看懂原理,用其他微控制器當然也可以實現,A4950的模組詳細資料好多我就不貼了,希望有幫到大家
相關文章
- 樹莓派 - L298N模組 驅動直流電機樹莓派
- win10印表機驅動在電腦哪裡找 怎麼檢視電腦印表機驅動詳細教程Win10
- Cobbler 自動部署裝機(超詳細)
- 基於STM32F1系列,驅動L298N電機驅動板實現直流電機的啟動、停止、調速功能
- cc2530控制直流電機
- Arduino 驅動火焰感測器模組UI
- Arduino 驅動煙霧感測器模組UI
- STM32F103驅動LCD1602 (4線) 函式超級詳細函式
- 超詳細的node垃圾回收機制
- :SpringBoot專案接入ELK超級版(超詳細圖文教程)Spring Boot
- 步進電機Linux驅動Linux
- 電腦印表機驅動在哪個位置?window電腦印表機驅動位置介紹
- 電腦怎麼安裝印表機驅動程式 電腦印表機安裝驅動教程
- Arduino 驅動模擬溫度感測器模組UI
- JWT 超詳細分析JWT
- 直流穩壓電源
- 顯示卡驅動有必要更新嗎 顯示卡驅動怎麼更新詳細教程
- Win7電腦驅動器怎麼加密?Win7系統給驅動器加密的方法和詳細步驟Win7加密
- Arduino+ESP32 之 驅動GC9A01圓形LCD(一),基於Arduino_GFX庫UIGC
- web259(超詳細)Web
- Maven筆記---超詳細Maven筆記
- java運算子(超詳細!!!)Java
- MyBatis Generator 超詳細配置MyBatis
- Vue 指令大全(超詳細)Vue
- 超詳細的IIS部署
- python使用xpath(超詳細)Python
- Vue 超詳細手記Vue
- win10ahci驅動怎麼安裝_win10安裝ahci驅動詳細教程Win10
- 超詳細!如何準備機器學習競賽?機器學習
- 超詳細!如何搭建國際版我的世界伺服器伺服器
- Spring AOP全面詳解(超級詳細)Spring
- 暴力風扇無刷電機驅動方案
- PYB——PWM控制驅動器+步進電機
- GPIO口工作原理的超詳細解釋(附電路圖)
- 8.JVM記憶體分配機制超詳細解析JVM記憶體
- 超詳細Dkhadoop虛擬機器圖文安裝步驟Hadoop虛擬機
- SpringBoot整合Mybatis超詳細流程Spring BootMyBatis
- Redis安裝教程(超詳細)Redis