[TH] Arduino: ใช้ SoftwareSerial กับ STM32F030F4

จากบทความแนะนำการใช้บอร์ด 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.
ภาพที่ 1 บอร์ด STM32F030F4P6 กับโมดูล CH340E
ภาพที่ 2 การตั้งค่าสำหรับ Arduino IDE

อุปกรณ์

  1. บอร์ด STM32F030F4P6
  2. โมดูล RS232 ในที่นี้เลือกใช้ CH340E ที่ใช้ชิพ CH340 สำหรับแปลงสัญญาณ USB TO TTL
  3. สายไฟเชื่อมต่อจำนวน 4 เส้น

การเชื่อมต่อระหว่างบอร์ดไมโครคอนโทรลเลอร์กับโมดูล CH340E เป็นดังนี้

  1. ขา 3V3 ของบอร์ดต่อเข้ากับ 3V3 ของโมดูล CH340E หรือ ขา 5V ของบอร์ดเข้ากับขา 5v ของโมดูล CH340E
  2. ขา GND ของทั้ง 2 บอร์ดต่อเชื่อมหากัน
  3. ขา PA9 ของไมโครคอนโทรลเลอร์ต่อเข้ากับขา RX ของ CH340E
  4. ขา PA10 ของ ST32F030F4P6 ต่อเข้ากับขา TX บนบอร์ด CH340E

หรือ เชื่อมต่อกับขาในส่วนของ RS232 ของบอร์ดไมโครคอนโทรลเลอร์

  1. ขา 3V3 ของบอร์ดเข้ากับขา 3V3 ของโมดูล RS232
  2. ขา GND ของบอร์ดเข้ากับขา GND ของ CH340E
  3. ขา TX ของบอร์ดเข้ากับขา RX ของโมดูลแปลง RS232
  4. ขา 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 ส่วน คือ

  1. ส่ง Hi ออกไปที่วัตถุ mySerial
  2. กระพริบหลอดแอลอีดีที่เชื่อมต่อกับขา PA4 ซี่งมากับบอร์ดไมโครคอนโทรลเลอร์อยู่แล้ว โดยส่ง HIGH แล้วรอ 500 มิลลิวินาที ตามด้วย LOW และรออีก 500 มิลลิวินาที

ตัวอย่างถัดไปเป็นการแปลงโค้ดการหาจำนวนเฉพาะเพื่อมใช้กับ SoftwareSerial พบว่าถ้าคอมไพล์เป็นแบบ -Os เพื่อประหยัดพื้นที่ ROM แต่ความเร็วช้าที่สุด กับ -O1, -O2 และ O3 เพื่อให้ความเร็วในการทำงานสูงสุดแต่ขนาดไฟล์จะใหญ่กว่าแบบแรก ให้ผลเป็นดังนี้

  1. แบบ -Os ทำให้ ROM และ RAM ถูกใช้งานไป 13560 และ 888 ไบต์ ส่วนผลการทำงานอยู่ที่ 432 มิลลิวินาที
  2. แบบ -O1 ใช้ ROM และ RAM ไป 15708 และ 888 ไบต์ โดยใช้เวลาในการหาจำนวนเฉพาะไป 412 มิลลิวินาที
  3. แบบ -O2 ใช้พื้นที่ของ ROM และ RAM เป็น 15192 และ 888 ไบต์ ใช้เวลาไป 402 มิลลิวินาที
  4. ส่วน -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