本篇有兩個主題:一是使用不同的驅動方式控制步進馬達轉動的方向,另一個是控制其轉動的角度。過去曾使用樹梅派做過類似的控制,有些原理可以參考:
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
張貼留言