ควบคุม DC Motor ด้วย L298N
มอเตอร์ไฟฟ้ากระแสตรง (DC motor) เป็นอุปกรณ์ที่ทำหน้าที่เปลี่ยนพลังงานไฟฟ้าเป็นพลังงานกล โดยเมื่อจ่ายไฟให้แก่มอเตอร์ จะทำให้แกนของมอเตอร์หมุน จึงสามารถนำการหมุนของแกนมอเตอร์ไปใช้ในการขับเคลื่อนวัตถุให้เกิดการเคลื่อนที่
มอเตอร์ไฟฟ้ากระแสตรงมีขนาดและพิกัดแรงดันให้เลือกใช้มากมาย ในบทความนี้จะเน้นไปที่มอเตอร์ขนาดเล็กที่ใช้แรงดันในย่าน +1.5 ถึง +12V ซึ่งมีการใช้งานในหุ่นยนต์หรือสิ่งประดิษฐ์ที่มีกลไกเคลื่อนไหว
บทความนี้จะสอนใช้งาน ATmega328P ควบคุมความเร็วมอเตอร์ไฟฟ้ากระแสตรง (DC motor) ด้วยการเขียนโปรแกรมภาษาซี (C) มาตรฐาน โดยใช้โมดูลขับมอเตอร์ L298N ที่มีขาที่ใช้งานสำหรับควบคุมความเร็วมอเตอร์ คือขา ENA และ ENB โดย ENA จะควบคุมมอเตอร์ A ที่ต่อกับ IN1 และ IN2 ส่วน ENB จะควบคุมมอเตอร์ B ที่ต่อกับ IN3 และ IN4
การต่อใช้งาน
Out 1: ช่องต่อขั้วไฟของมอเตอร์ A
Out 2: ช่องต่อขั้วไฟของมอเตอร์ A
Out 3: ช่องต่อขั้วไฟของมอเตอร์ B
Out 4: ช่องต่อขั้วไฟของมอเตอร์ B
12V: ช่องจ่ายไฟเลี้ยงมอเตอร์ 12V (ต่อได้ตั้งแต่ 5V ถึง 35V)
GND: ช่องต่อไฟลบ (Ground)
5V: ช่องจ่ายไฟเลี้ยงมอเตอร์ 5V (หากมีการต่อไฟเลี้ยงที่ช่อง 12V แล้ว
ช่องนี้จะทำหน้าที่จ่ายไฟออก เป็น 5V Output
สามารถต่อไฟจากช่องนี้ไปเลี้ยงบอร์ด ATmega328P ได้
ENA: ช่องต่อสัญญาณ PWM สำหรับมอเตอร์ A
IN1: ช่องต่อสัญญาณลอจิคเพื่อควบคุมทิศทางของมอเตอร์ A
IN2: ช่องต่อสัญญาณลอจิคเพื่อควบคุมทิศทางของมอเตอร์ A
IN3: ช่องต่อสัญญาณลอจิคเพื่อควบคุมทิศทางของมอเตอร์ B
IN4: ช่องต่อสัญญาณลอจิคเพื่อควบคุมทิศทางของมอเตอร์ B
ENB: ช่องต่อสัญญาณ PWM สำหรับมอเตอร์ B
หลักการทำงาน
วงจร H-Bridge ของ L298N จะขับกระแสเข้ามอเตอร์ ตามขั้วที่กำหนดด้วยลอจิกเพื่อควบคุมทิศทาง ส่วนความเร็วของมอเตอร์นั้นจะถูกควบคุมด้วย สัญญาณ (PWM Pulse Width Modulation)
PWM หมายถึง การควบคุมช่วงจังหวะการทำงานของอิเล็กตรอน ลองจินตนาการถึงแปรงขดลวดในมอเตอร์เป็นระหัดวิดน้ำและอิเล็กตรอนเป็นน้ำที่ตกลงมาจากระหัดวิดน้ำ ค่าแรงดันไฟฟ้าก็คล้ายกับกระแสน้ำที่ไหลผ่านระหัดวิดน้ำด้วยความเร็วคงที่ ยิ่งกระแสน้ำไหลเร็วเท่าไรก็จะหมายความว่าแรงดันไฟฟ้ายิ่งสูงขึ้น แต่มอเตอร์มีอัตราความเร็วคงที่และสามารถเสียหายได้หากมีแรงดันไฟฟ้าสูงไหลผ่านหรือหยุดทันทีเพื่อที่จะหยุดมอเตอร์ ดังนั้น PWM คล้ายกับการควบคุมระหัดวิดน้ำให้ตักน้ำในจังหวะคงที่ที่กระแสน้ำคงที่ ยิ่งระหัดวิดน้ำหมุนเร็วเท่าไรช่วงของ pulse ก็จะยาวขึ้น ในทางกลับกันถ้าระหัดวิดน้ำหมุนช้าช่วงของ pulse จะสั้นลง ดังนั้นเพื่อยืดอายุการใช้งานของมอเตอร์จึงควรที่จะควบคุมมอเตอร์ด้วย PWM
รายการอุปกรณ์
- 1. ชุดคิทต่อวงจร Minimum ATmega328P Circuit
- 2. Breadboard 700 Points SYB-120
- 3. Jumper (M2M) cable 10cm Male to Male
- 4. FT232RL FTDI USB To TTL Serial Converter Module
- 5. USB Male to Mini USB B 5pin Data Cable
- 6. Push Button Switch สวิตช์กดติดปล่อยดับ 2 ขา จำนวน 3 ตัว
- 7. Motor Driver Module L298N
- 8. เกียร์มอเตอร์และล้อรถ
- 9. รางถ่าน AA 8 ก้อน 12 โวลต์
- 10. Jumper (F2M) cable wire 20cm Female to Male
ขั้นตอนการทํางาน
1 : ทดสอบโปรแกรมแรก กับ ATmega328P
โปรแกรมแรกของ การใช้งานไมโครคอนโทรลเลอร์มักจะเป็น Blink ไฟกะพริบ ซึ่งเป็นหนึ่งในโปรแกรมที่ง่ายที่สุดเท่าที่จะเป็นไปได้ในการเขียนภาษาโปรแกรมต่างๆ เพราะฉะนั้นโดยธรรมเนียมปฏิบัติแล้ว มักจะใช้ในการตรวจสอบว่าเขียนภาษาโปรแกรมได้ถูกต้องหรือระบบมีการประมวลผลที่ถูกต้อง และมักถูกใช้เป็นตัวอย่างที่ง่ายที่สุดในการแสดงผลลัพธ์ของการเขียนโปรแกรม โดยทำตามขั้นตอนลิงค์ด้านล่าง
2: เชื่อมต่อมอเตอร์ เข้ากับ วงจร ATmega328P
เชื่อมต่อ สวิตช์กดติดปล่อยดับ 2 ขา เข้ากับ ขา PC1 , PC2 และ PC3 ของ ATmega328P ตามรูปด้านล่าง
ถ้าต้องการใช้งานขา ENB ให้ ให้ถอดจัมเปอร์ออก
เชื่อมต่อ L298N เข้ากับ ขา PB1 , PB2 และ PB3 ของ ATmega328P ตามรูปด้านล่าง
3: เขียนโค้ด ควบคุมมอเตอร์ DC Motor
ตัวอย่างโค้ด เขียนโค้ดแบบ ใช้ระบบเลขฐานสอง เป้าหมายคือ ถ้าสวิตช์ ตัวที่ 1 ถูก กด ให้มอเตอร์ หมุนตามเข็มนาฬิกา หรือ เดินหน้า , ถ้า สวิตช์ ตัวที่ 3 ถูก กด ให้มอเตอร์ หมุนทวนเข็มนาฬิกา หรือ ถอยหลัง และ ถ้า สวิตช์ ตัวที่ 2 ถูก กด ให้มอเตอร์หยุด
#include <avr/io.h>
#define F_CPU 16000000UL
#include "util/delay.h"
//Test1 the PINC1
#define forward (PINC & 0b00000010)
//Test2 the PINC2
#define stop (PINC & 0b00000100)
//Test3 the PINC3
#define backward (PINC & 0b00001000)
//OUTPUT DATA FOR MOTOR
#define run_forward 0b00000100
#define run_backward 0b00001000
#define stop_running 0b00000000
int main(void)
{
DDRD |= (1 << DDD6); // Configuring PD6 as Output
PWM
OCR0A = 191; // set PWM for 75% duty cycle
TCCR0A |= (1 << COM0A1); // set none-inverting mode
TCCR0A |= (1 << WGM01) | (1 << WGM00); // set fast PWM Mode
TCCR0B |= (1 << CS01); // set prescaler to 8 and starts PWM
DDRC |=
0b11110001; // Configuring PC3,PC2,PC1 as Input
PORTC |=
0b00001110; // Enabling Internal Pull-Up
to PC3,PC2,PC1
DDRB |=
0b00001100; // Configuring PB3,PB2 as Output
PORTB |=
0b11110011; // Writing LOW to PB3,PB2
while (1)
{
if (forward == 0)
{
PORTB = stop_running;
_delay_ms(250);
PORTB = run_forward;
}
else if (stop == 0)
{
PORTB = stop_running;
_delay_ms(250);
PORTB = stop_running;
}
else if (backward == 0)
{
PORTB = stop_running;
_delay_ms(250);
PORTB = run_backward;
}
}
}
อธิบายโค้ด
#include คือการเรียกใช้ไฟล์ภาษาซี จากไลบรารี ซึ่งอยู่ในโฟลเดอร์ avr และ ชื่อไฟล์ io.h สำหรับใช้งานเกี่ยวกับ ฟังก์ชั่น ควบคุมอินพุท/เอาท์พุท (เช่น PORTB, DDRB)
#include <avr/io.h>
#define คือ ค่าคงที่ และ ให้ชื่อว่า F_CPU กำหนดค่าให้เป็น 16000000 คือการกำหนดให้นำค่า 16MHz ไปไปคำนวณร่วมกับฟังก์ชั่น delay.h ในการหน่วงเวลาเพราะ วงจร Minimum ATmega328P Circuit ที่เราเชื่อมต่อนั้น ใช้คริสตัล 16Mhz เป็นแหล่งสัญญาณนาฬิกา
#define F_CPU 16000000UL
#include คือการเรียกใช้ไฟล์ภาษาซี จากไลบรารี ซึ่งอยู่ในโฟลเดอร์ util และ ชื่อไฟล์ delay.h สำหรับใช้งานเกี่ยวกับ ฟังก์ชั่น การหน่วงเวลา
#include "util/delay.h"
#define คือ ค่าคงที่ กำหนดให้ขา PC1 มีชื่อว่า forward สำหรับรับค่าจากสวิตช์ ตัวที่ 1
#define forward (PINC&0b00000010)
#define คือ ค่าคงที่ กำหนดให้ขา PC2 มีชื่อว่า stop สำหรับรับค่าจากสวิตช์ ตัวที่ 2
#define stop (PINC&0b00000100)
#define คือ ค่าคงที่ กำหนดให้ขา PC3 มีชื่อว่า backward สำหรับรับค่าจากสวิตช์ ตัวที่ 3
#define backward (PINC&0b00001000)
#define คือ ค่าคงที่ มีชื่อว่า run_forward คำสั่งให้มอเตอร์ หมุนตามเข็มนาฬิกา (ขึ้นอยู่กับการต่อสายด้วย) โดย ให้ขา PB2 เอาต์พุตเป็น HIGH และ ขา PB3 เอาต์พุตเป็น LOW
#define run_forward 0b00000100
#define คือ ค่าคงที่ มีชื่อว่า run_backward คำสั่งให้มอเตอร์ หมุนทวนเข็มนาฬิกา (ขึ้นอยู่กับการต่อสายด้วย) โดย ให้ขา PB2 เอาต์พุตเป็น LOW และ ขา PB3 เอาต์พุตเป็น HIGH
#define run_backward 0b00001000
#define คือ ค่าคงที่ มีชื่อว่า stop_running คำสั่งให้มอเตอร์ หยุดการทํางาน โดย ให้ขา PB2 เอาต์พุตเป็น LOW และ ขา PB3 เอาต์พุตเป็น LOW
#define stop_running 0b00000000
กำหนดให้เป็นขา PฺฺD6 ทำงานแบบเอาท์พุท PWM
DDRD |= (1 << DDD6);
กำหนดค่า PWM ค่า 0 ถึง 255 เป็นค่าความเร็ว ค่ายิงน้อยลงจะมอเตอร์หมุนช้าลง ในโค้ดคือ 191 คือ มีความเร็ว 75%
OCR0A = 191;
เป็นโค้ดต่อเนื่องในการกำหนดค่า PWM
TCCR0A |= (1 << COM0A1); // set none-inverting mode
TCCR0A |= (1 << WGM01) | (1 << WGM00); // set fast PWM Mode
TCCR0B |= (1 << CS01); // set prescaler to 8 and starts PWM
กำหนดให้เป็นขา PC3,PC2,PC1 ทำงานแบบอินพุท
DDRC |= 0b11110001;
เปิดการทำงาน Internal Pull-Up ให้กับขา PC3,PC2,PC1
PORTC |= 0b00001110;
กำหนดให้เป็นขา PฺฺB3 และ PB2 ทำงานแบบเอาท์พุท
DDRB |= 0b00001100;
กำหนดให้เป็นขา PฺฺB3 และ PB2 ส่งค่าเอาท์พุท LOW ออกไป
PORTB |= 0b11110011;
ถ้า สวิตช์ ตัวที่ 1 (forward) ถูก กด
if (forward == 0)
เรียกคำสั่ง (ทีประกาศไว้ด้านบน บรรทัด 15 และ 17) ให้มอเตอร์ หมุนตามเข็มนาฬิกา หรือ เดินหน้า โดยเรียก stop_running; คือให้มอเตอร์หยุดทำงานก่อน 250 มิลลิวินาที แล้วจึงเรียกใช้งานคำสั่ง run_forward ; เพื่อให้มอเตอร์ หมุนตามเข็มนาฬิกา หรือ เดินหน้า
PORTB = stop_running;
_delay_ms(250);
PORTB = run_forward;
ถ้า สวิตช์ ตัวที่ 2 (stop) ถูก กด
else if (stop == 0)
เรียกคำสั่ง (ทีประกาศไว้ด้านบน บรรทัด 17) ให้มอเตอร์หยุด
PORTB = stop_running;
_delay_ms(250);
PORTB = stop_running;
ถ้า สวิตช์ ตัวที่ 3 (backward) ถูก กด
else if (backward == 0)
เรียกคำสั่ง (ทีประกาศไว้ด้านบน บรรทัด 16 และ 17) ให้มอเตอร์ หมุนทวนเข็มนาฬิกา หรือ ถอยหลัง โดยเรียก stop_running; คือให้มอเตอร์หยุดทำงานก่อน 250 มิลลิวินาที แล้วจึงเรียกใช้งานคำสั่ง run_backward ; เพื่อให้มอเตอร์ หมุนทวนเข็มนาฬิกา หรือ ถอยหลัง
PORTB = stop_running;
_delay_ms(250);
PORTB = run_backward;
4: ทดสอบการทํางาน
เมื่อกดสวิตช์ตัวที่ 1 ในตัวอย่าง มอเตอร์จะหมุน ตามเข็มนาฬิกา เมื่อกดสวิตช์ตัวที่ 3 จะหมุนตรงข้ามคือ ทวนเข็มนาฬิกา และ กดสวิตช์ตัวที่ 2 มอเตอร์จะหยุดหมุน
<<< C6: การใช้งาน PWM บทความก่อนหน้า | บทความต่อไป C8: ควบคุม Servo Motor >>>