จากบทความแนะนำการใช้บอร์ด STM32F030F4P6 ที่ใช้การสื่อสารพอร์ตอนุกรมด้วยการใช้ไลบรารีเพิ่มเติมซึ่งทำให้ปริมาณหน่วยความจำไม่มากพอสำหรับใช้งาน ทางเราเลยลองเปลี่ยนมาใช้ SoftwareSerial ของเฟรมเวิร์ก Arduino และใช้ขา PA10 และ PA9 ต่อเข้ากับ RX และ TX ของโมดูลแปลง USB-RS232 ดังภาพที่ 1 และทดลองใช้งานตามการตั้งค่าของ Arduino IDE ดังภาพที่ 2 พร้อมทั้งสั่ง Toggle หลอด LED ที่เชื่อมต่อกับขา PA4 พบว่า เมื่อคอมไพล์โปรแกรมตัวอย่างแล้วมีการใช้ ใช้หน่วยความจำ ROM และ RAM เป็น 80% และ 21% ตามลำดับดังการรายงานจาก Arduino IDE ดังต่อไปนี้
Sketch uses 13188 bytes (80%) of program storage space. Maximum is 16384 bytes.
Global variables use 876 bytes (21%) of dynamic memory, leaving 3220 bytes for local variables. Maximum is 4096 bytes.
อุปกรณ์
- บอร์ด STM32F030F4P6
- โมดูล RS232 ในที่นี้เลือกใช้ CH340E ที่ใช้ชิพ CH340 สำหรับแปลงสัญญาณ USB TO TTL
- สายไฟเชื่อมต่อจำนวน 4 เส้น
การเชื่อมต่อระหว่างบอร์ดไมโครคอนโทรลเลอร์กับโมดูล CH340E เป็นดังนี้
- ขา 3V3 ของบอร์ดต่อเข้ากับ 3V3 ของโมดูล CH340E หรือ ขา 5V ของบอร์ดเข้ากับขา 5v ของโมดูล CH340E
- ขา GND ของทั้ง 2 บอร์ดต่อเชื่อมหากัน
- ขา PA9 ของไมโครคอนโทรลเลอร์ต่อเข้ากับขา RX ของ CH340E
- ขา PA10 ของ ST32F030F4P6 ต่อเข้ากับขา TX บนบอร์ด CH340E
หรือ เชื่อมต่อกับขาในส่วนของ RS232 ของบอร์ดไมโครคอนโทรลเลอร์
- ขา 3V3 ของบอร์ดเข้ากับขา 3V3 ของโมดูล RS232
- ขา GND ของบอร์ดเข้ากับขา GND ของ CH340E
- ขา TX ของบอร์ดเข้ากับขา RX ของโมดูลแปลง RS232
- ขา RX จากบอร์ดเข้ากับขา TX ของโมดูล CH340E
SoftwareSerial
คลาส SoftwareSerial เป็นคลาสสำหรับทำการสื่อสารแบบอนุกรมด้วยไลบรารีที่เป็นซอฟต์แวร์ และมีการใช้หน่วยความจำจากแรมจำนวน 64 ไบต์สำหรับใช้เป็นบัฟเฟอร์ พร้อมทั้งระบุขาสำหรับทำหน้าที่เป็น TX และ RX ด้วยความเร็วสูงสุดในการสื่อสารอยู่ที่ 115200bps
การเรียกใช้ต้องนำเข้าไฟล์ส่วนหัว SoftwareSerial.h ดังรูปแบบการเขียนโค้ด ดังนี้
#include <SoftwareSerial.h>
คำสั่งสำหรับสร้างวัตถุประเภท SoftwareSerial เพื่อใช้งานต้องกำหนดค่าหน้าที่ขาสำหรับเป็นขา RX และ TX ดังนี้
SoftwareSerial ชื่อวัตถุ( ขาสำหรับทำหน้าที่RX, ขาสำหรับทำหน้าที่TX )
ส่วนการใช้งานคำสั่งอื่น ๆ สามารถอ่านได้จากบทความ Arduino: Serial Class เนื่องจากคลาส SoftwareSerial สืบทอดมาจากคลาส Serial ของเฟรมเวิร์ก Arduino อีกทีหนึ่งทำให้สามารถใช้งานเมธอดหรือคำสั่งได้เหมือนกัน
ตัวอย่างโปรแกรม
ตัวอย่างโปรแกรมสำหรับกำหนดอัตราการสื่อสาร 9600bps เพื่อส่งข้อความ Hi ทุก 1 วินาทีและสั่งกระพริบหลอดแอลอีดีบนบอร์ด STM32F030F4P6 ทุก 500 มิลลิวินาทีเขียนได้ดังนี้
#include <SoftwareSerial.h>
#define PIN_LED PA4
SoftwareSerial mySerial(PA10, PA9); // RX, TX
void setup() {
mySerial.begin(9600);
pinMode( PIN_LED, OUTPUT );
}
void loop() {
mySerial.println("hi");
digitalWrite( PIN_LED, HIGH );
delay(500);
digitalWrite( PIN_LED, LOW );
delay(500);
}
จากโค้ดโปรแกรมได้สร้างวัตถุชื่อ mySerial ที่ระยุให้ขา PA10 ทำหน้าที่เป็น RX และ PA9 เป็นขาสำหรับเป็นขารับสัญญาณหรือ TX ที่สืบทอดมาจากคลาส SoftwareSerial หลังจากนั้นใน setup() ได้ระบุความเร็วในการสื่อสารเอาไว้ที่ 9600 และที่สำคัญคือ ผู้อ่านต้องเปิดการใช้ UART แต่ไม่เลือกเป็น no seneric “serial” ตามภาพที่ 2 เพราะถ้าปิดจะส่งผลให้ไม่สามารถใช้งานคลาสเกี่ยวกับ Serial ได้ แต่ถ้าใช้ generic serial จะเป็นการเปิดให้ HW ทำงาน (แล้วมันจะไม่ทำงาน … อย่างงน่อ …)
ในส่วนของ loop() ได้แบ่งการทำงานเป็น 2 ส่วน คือ
- ส่ง Hi ออกไปที่วัตถุ mySerial
- กระพริบหลอดแอลอีดีที่เชื่อมต่อกับขา PA4 ซี่งมากับบอร์ดไมโครคอนโทรลเลอร์อยู่แล้ว โดยส่ง HIGH แล้วรอ 500 มิลลิวินาที ตามด้วย LOW และรออีก 500 มิลลิวินาที
ตัวอย่างถัดไปเป็นการแปลงโค้ดการหาจำนวนเฉพาะเพื่อมใช้กับ SoftwareSerial พบว่าถ้าคอมไพล์เป็นแบบ -Os เพื่อประหยัดพื้นที่ ROM แต่ความเร็วช้าที่สุด กับ -O1, -O2 และ O3 เพื่อให้ความเร็วในการทำงานสูงสุดแต่ขนาดไฟล์จะใหญ่กว่าแบบแรก ให้ผลเป็นดังนี้
- แบบ -Os ทำให้ ROM และ RAM ถูกใช้งานไป 13560 และ 888 ไบต์ ส่วนผลการทำงานอยู่ที่ 432 มิลลิวินาที
- แบบ -O1 ใช้ ROM และ RAM ไป 15708 และ 888 ไบต์ โดยใช้เวลาในการหาจำนวนเฉพาะไป 412 มิลลิวินาที
- แบบ -O2 ใช้พื้นที่ของ ROM และ RAM เป็น 15192 และ 888 ไบต์ ใช้เวลาไป 402 มิลลิวินาที
- ส่วน -O3 ไม่สามารถคอมไพล์ได้เนื่องจากพื้นที่ ROM ไม่เพียงพอ
#include <math.h>
#include <SoftwareSerial.h>
SoftwareSerial mySerial(PA10, PA9);
#define PIN_LED PA4
bool isPrimeNumber(uint16_t x) {
uint16_t i;
for (i = 2; i < x; i++) {
if (x % i == 0) {
return false;
}
}
if (i == x)
return true;
return false;
}
int counter = 0;
uint32_t t0, t1;
void testPrimeNumber(uint16_t maxN) {
t0 = millis();
for (uint16_t n = 2; n < maxN; n++) {
if (isPrimeNumber(n)) {
counter++;
}
}
t1 = millis();
}
void setup(void)
{
pinMode( PIN_LED, OUTPUT );
mySerial.begin(9600);
testPrimeNumber(2000);
mySerial.print("Found ");
mySerial.print(counter, DEC);
mySerial.print(" in ");
mySerial.print(int(fabs(t1 - t0)), DEC);
mySerial.println(" milliseconds.");
}
void loop(void)
{
digitalWrite( PIN_LED, HIGH );
delay(500);
digitalWrite( PIN_LED, LOW );
delay(500);
}
จากตัวอย่างที่ 2 จะพบว่า การใช้ -Os เป็นทางเลือกที่ดีที่สุด และ -O1 ทำให้เร็วขึ้นแต่จำนวน ROM ถูกใช้เยอะกว่า ซึ่งต้องดูว่ามีโค้ดทำงานอยู่เยอะหรือไม่เป็นข้อมูลประกอบการเลือกวิธีการคอมไพล์โปรแกรม
สรุป
จากบทความนี้จะพบว่า เมื่อใช้ SoftwareSerial ทำให้การใช้งาน STM32F030F4P6 สำหรับการสื่อสารอนุกรมนั้นสะดวกยิ่งขึ้น หรือทำการใช้ขาอื่น ๆ เพื่อเป็นขาสื่อสารเพิ่มเติมย่อมทำได้เช่นกัน เช่น เพิ่มการสื่อสารกับ ESP32/ESP8266 ไป 2 ขา แลอีก 2 ขาสำหรับ GPS เป็นต้น ทำให้ระบบของเราสามารถเชื่อมต่อ WiFi และใช้งาน GPS ได้พร้อมกัน สุดท้าย ขอให้สนุกกับการเขียนโปรแกรมครับ
(C) 2020-2022, โดย อ.ดนัย เจษฎาฐิติกุล/อ.จารุต บุศราทิจ
ปรับปรุงเมืี่อ 2022-01-02, 2022-02-12