本篇有兩個主題:一是使用不同的驅動方式控制步進馬達轉動的方向,另一個是控制其轉動的角度。過去曾使用樹梅派做過類似的控制,有些原理可以參考:
Raspberry Pi 筆記(12):控制步進馬達。本篇將使用一個按鍵來切換 28BYJ-48 步進馬達驅動的方式,並可讓馬達轉動 180 度。28BYJ-48 是一個常見的步進馬達,幾乎所有學習開發板的人,都會認識這個型號,而型號命名是有意義的:
線圈的接線如下圖:
28BYJ-48 步進馬達有 4 相(表示 4 組線圈) 5 根線,紅色是公共端,接 5V 電源,4橙(A),3黃(B),2粉(C),1藍(D)。半步的減速比為 64:1 表示內部馬達轉動 64 圈,外部的軸才轉動 1 圈,可以算出內部馬達轉動一圈,外部軸心轉動角度為 360º / 64 = 5.625º。
若將 5.625º 乘以減速比得到輸出的解析度為:每步旋轉 5.625 x 1/64 = 0.087890625 度。由此算出若要讓外軸轉動一圈,內部馬達需要行走 360 / 0.087890625 = 4096 步。
這是在行走半步的模式,若為全步,則外軸轉動一圈,內部點機需轉動 64 / 2 = 32 步。這表示內部馬達必須移動 32×64 = 2048 步,外部的軸才能轉一圈。每一步將轉動 360º/ 2048 = 0.18º 。
旋轉步進馬達通常稱為驅動,可以是波浪驅動、全步驅動、半步驅動驅動三種之一:
1.全步波浪驅動(Wave Drive)時序為:D->C->B->A ,轉一圈需要四步,一次僅驅動一個線圈工作,較少的消耗。
2.全步驅動(Full-Step Drive)時序為:AB->BC ->CD ->DA ,轉一圈需要四步,一次激勵兩個線圈,在最大扭矩下,更高的電流換來的是更高的扭矩。
3.半步驅動(Half-Step Drive)時序為:A->AB->B ->BC ->C ->CD ->D ->DA ,轉一圈需要八步,可使用半步驅動以獲得更精確的運動。
- 28:步進馬達的有效最大外徑是 28 毫米
- B:表示是步進馬達
- Y:表示是永磁式
- J:表示是減速型(減速比1:64)
- 48:表示四相八拍
[28BYJ-48規格]
28BYJ-48 步進馬達的規格如下:- 單極兩種規格:DC 5V 及 12V
- 直徑:28mm
- 齒輪減速比(變速箱):1/64
- 定子極數:上(8+8)、下(8+8)
- 轉子極數:16
- 步距角度:360 / 64 x 1/64 = 0.087890625(半步模式)
- 中心抽頭(紅線)與輸入引腳之間的直流電阻:21Ω
- 輸出軸步數/轉 = (8x4x2) x 64 = 4096(半步模式)
- 最大速度 = 15~20 rpm
線圈的接線如下圖:
28BYJ-48 步進馬達有 4 相(表示 4 組線圈) 5 根線,紅色是公共端,接 5V 電源,4橙(A),3黃(B),2粉(C),1藍(D)。半步的減速比為 64:1 表示內部馬達轉動 64 圈,外部的軸才轉動 1 圈,可以算出內部馬達轉動一圈,外部軸心轉動角度為 360º / 64 = 5.625º。
若將 5.625º 乘以減速比得到輸出的解析度為:每步旋轉 5.625 x 1/64 = 0.087890625 度。由此算出若要讓外軸轉動一圈,內部馬達需要行走 360 / 0.087890625 = 4096 步。
這是在行走半步的模式,若為全步,則外軸轉動一圈,內部點機需轉動 64 / 2 = 32 步。這表示內部馬達必須移動 32×64 = 2048 步,外部的軸才能轉一圈。每一步將轉動 360º/ 2048 = 0.18º 。
[ULN2003驅動板]
ULN2003 是高壓大電流達林頓晶體管陣列系列產品,具有電流增益高、工作電壓高、溫度範圍寬、帶負載能力強等特點,適合各類要求高速大功率驅動的系統。在實際使用中,只需要使用 STM32 的 I/O 接 ULN2003 驅動板的 IN1 ~ IN4 即可,單片機和此驅動板需要共接地線。旋轉步進馬達通常稱為驅動,可以是波浪驅動、全步驅動、半步驅動驅動三種之一:
1.全步波浪驅動(Wave Drive)時序為:D->C->B->A ,轉一圈需要四步,一次僅驅動一個線圈工作,較少的消耗。
| 時序 | 橙 | 黃 | 粉 | 藍 |
|---|---|---|---|---|
| A | 0 | 1 | 1 | 1 |
| B | 1 | 0 | 1 | 1 |
| C | 1 | 1 | 0 | 1 |
| D | 1 | 1 | 1 | 0 |
2.全步驅動(Full-Step Drive)時序為:AB->BC ->CD ->DA ,轉一圈需要四步,一次激勵兩個線圈,在最大扭矩下,更高的電流換來的是更高的扭矩。
| 時序 | 橙 | 黃 | 粉 | 藍 |
|---|---|---|---|---|
| A | 0 | 0 | 1 | 1 |
| B | 1 | 0 | 0 | 1 |
| C | 1 | 1 | 0 | 0 |
| D | 0 | 1 | 1 | 0 |
3.半步驅動(Half-Step Drive)時序為:A->AB->B ->BC ->C ->CD ->D ->DA ,轉一圈需要八步,可使用半步驅動以獲得更精確的運動。
| 時序 | 橙 | 黃 | 粉 | 藍 |
|---|---|---|---|---|
| A | 0 | 1 | 1 | 1 |
| AB | 0 | 0 | 1 | 1 |
| B | 1 | 0 | 1 | 1 |
| BC | 1 | 0 | 0 | 1 |
| C | 1 | 1 | 0 | 1 |
| CD | 1 | 1 | 0 | 0 |
| D | 1 | 1 | 1 | 0 |
| DA | 0 | 1 | 1 | 0 |
[材料]
- STM32F103C8T6 主板 x 1
- STLINK V2 模擬下載器 x 1
- UNL2003 控制版 x 1
- 28BYJ-48 步進馬達 x 1
- 按鍵 x 1
- 麵包板 x 1
- 連接線 x N 條
[接線與電路圖]
UNL2003模組的正負分別接 3.3v 及 GND,IN1~IN4 接腳分別接在 STM32F103x 的 PA1 ~ PA4,按鍵的一腳接 PB14,另一端接地,連接的方式如下:| STM32F103x | UNL2003 |
|---|---|
| 5v | + |
| GND | - |
| PA1 | IN1 |
| PA2 | IN2 |
| PA3 | IN3 |
| PA4 | IN4 |
[程式]
按鍵控制四種驅動方式:按一下使用波浪驅動方式轉動,按兩下使用全步驅動方式轉動,按三下使用半步驅動方式轉動,按四下轉動 180度後暫停,在繼續轉動180,持續進行到下一個按鍵按下。為了跟前一個動作有明顯的不同,每次變換動作,旋轉的方向就相反。主程式 main.c 如下:#include "delay.h"
#include "sys.h"
#include "motor.h"
#include "button.h"
int main(void)
{
uint16_t btn_count;
delay_init(); //延時函數初始化
Button_Init(); //按鍵初始化
Step_Motor_GPIO_Init(); //步進馬達初始化
while (1)
{
btn_count = Button_Get();
if (btn_count%5 == 1){
Motor_Start(1, 4, 1); // 順時鐘轉, 延時需大於4ms, 使用波浪驅動
}
if (btn_count%5 == 2){
Motor_Start(0, 4, 2); // 逆時鐘轉, 延時需大於4ms, 使用全步驅動
}
if (btn_count%5 == 3){
Motor_Start(1, 2, 3); // 順時鐘轉, 延時2ms, 使用半步驅動
}
if (btn_count%5 == 4){
Motor_Start_Angle(0, 4, 1, 180); // 轉動 180度
delay_ms(50000); // 暫停再繼續
}
}
}
Motor.c 的程式如下:#include "delay.h"
#include "motor.h"
//引腳初始化
void Step_Motor_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = IN1|IN2|IN3|IN4;
GPIO_Init(MOTOR_PORT, &GPIO_InitStructure);
}
// 波浪驅動
void Phase4_Single(u8 step, u8 delay)
{
switch(step){
case 1:
IN1_HIGH; IN2_LOW; IN3_LOW; IN4_LOW;
break;
case 2:
IN1_LOW; IN2_HIGH; IN3_LOW; IN4_LOW;
break;
case 3:
IN1_LOW; IN2_LOW; IN3_HIGH; IN4_LOW;
break;
case 4:
IN1_LOW; IN2_LOW; IN3_LOW; IN4_HIGH;
break;
}
delay_ms(delay);
}
// 全步驅動
void Phase4_Double(u8 step, u8 delay)
{
switch(step){
case 1:
IN1_LOW; IN2_HIGH; IN3_HIGH; IN4_LOW;
break;
case 2:
IN1_LOW; IN2_LOW; IN3_HIGH; IN4_HIGH;
break;
case 3:
IN1_HIGH; IN2_LOW; IN3_LOW; IN4_HIGH;
break;
case 4:
IN1_HIGH; IN2_HIGH; IN3_LOW; IN4_LOW;
break;
}
delay_ms(delay);
}
// 半步驅動
void Phase8_Single(u8 step, u8 delay)
{
switch(step){
case 1:
IN1_LOW; IN2_HIGH; IN3_HIGH; IN4_HIGH;
break;
case 2:
IN1_LOW; IN2_LOW; IN3_HIGH; IN4_HIGH;
break;
case 3:
IN1_HIGH; IN2_LOW; IN3_HIGH; IN4_HIGH;
break;
case 4:
IN1_HIGH; IN2_LOW; IN3_LOW; IN4_HIGH;
break;
case 5:
IN1_HIGH; IN2_HIGH; IN3_LOW; IN4_HIGH;
break;
case 6:
IN1_HIGH; IN2_HIGH; IN3_LOW; IN4_LOW;
break;
case 7:
IN1_HIGH; IN2_HIGH; IN3_HIGH; IN4_LOW;
break;
case 8:
IN1_LOW; IN2_HIGH; IN3_HIGH; IN4_LOW;
break;
}
delay_ms(delay);
}
//馬達停止
void Motor_Stop(void)
{
IN1_LOW; IN2_LOW; IN3_LOW; IN4_LOW;
}
/*
功能:轉動1/64圈
direction: 轉動方向 1:正轉 非1:反轉
delay: 延時時長,需 >= 2
phase: 1:四相單步, 2:四相雙步, 3:八相單步
*/
void Motor_Start(u8 direction, u8 delay, u8 phase)
{
if (direction){ // 順時針轉
switch(phase){
case 1:
for(u8 i=1;i<5;i++){
Phase4_Single(i, delay); }
break;
case 2:
for(u8 i=1;i<5;i++){
Phase4_Double(i, delay); }
break;
case 3:
for(u8 i=1;i<9;i++){
Phase8_Single(i, delay); }
break;
default:
break;
}
} else // 逆時針轉
{
switch(phase){
case 1:
for(u8 i=4;i>0;i--){
Phase4_Single(i, delay); }
break;
case 2:
for(u8 i=4;i>0;i--){
Phase4_Double(i, delay); }
break;
case 3:
for(u8 i=8;i>0;i--){
Phase8_Single(i, delay); }
break;
default:
break;
}
}
}
/*
功能:旋轉至特定角度
direction: 轉動方向 1:正轉 非1:反轉
delay: 延時時長,需 >= 2
phase: 1:四相單步, 2:四相雙步, 3:八相單步
angle: 轉動角度
*/
void Motor_Start_Angle(u8 direction, u8 delay, u8 phase, u16 angle)
{
for(u16 j=0;j<(64*angle/45);j++){
Motor_Start(direction, delay, phase);
}
}
Motor.h 程式如下:#ifndef __MOTOR_H__ #define __MOTOR_H__ #define MOTOR_PORT GPIOA #define IN1 GPIO_Pin_1 #define IN2 GPIO_Pin_2 #define IN3 GPIO_Pin_3 #define IN4 GPIO_Pin_4 #define IN1_HIGH GPIO_SetBits(MOTOR_PORT,IN1); #define IN1_LOW GPIO_ResetBits(MOTOR_PORT,IN1); #define IN2_HIGH GPIO_SetBits(MOTOR_PORT,IN2); #define IN2_LOW GPIO_ResetBits(MOTOR_PORT,IN2); #define IN3_HIGH GPIO_SetBits(MOTOR_PORT,IN3); #define IN3_LOW GPIO_ResetBits(MOTOR_PORT,IN3); #define IN4_HIGH GPIO_SetBits(MOTOR_PORT,IN4); #define IN4_LOW GPIO_ResetBits(MOTOR_PORT,IN4); void Step_Motor_GPIO_Init(void); void motor_circle(int n, int direction, int delay); void Phase4_Single(u8 step, u8 delay); void Phase8_Single(u8 step, u8 delay); void Phase4_Double(u8 step, u8 delay); void Motor_Start(u8 direction, u8 freq, u8 phase); void Motor_Start_Angle(u8 direction, u8 freq, u8 phase, u16 angle); void Motor_Stop(void); #endif完整的程式請參考 Github:12.ULN2003 Control 28BYJ-48 Stepper Motor
[結果]
按下三次按鍵使用半步驅動時,發現有時會停頓不會轉動,原因可能是我使用 STM32 開發板上的 5V 電源,加上這個驅動強調精度,扭力不足,如果改用外接電源,應該可以改變這個狀況。[參考資料]
- STM32F103 Reference manual
- STM32F10xxx參考手冊
- STM32F103控制28BYJ-48步進電機正轉或者反轉一定的角度
- 28BYJ-48–5V Stepper Motor


張貼留言