[TH] Arduino: Serial Class

บทความนี้อธิบายการใช้งานคลาส Serial ในเฟรมเวิร์กของ Arduino เพื่อใช้เป็นคำสั่งสำหรับรายงานผลจากบอร์ดไมโครคอนโทรลเลอร์กลับมายังโปรแกรม Arduino IDE ทำให้สะดวกต่อการตรวจสอบการทำงานและการเรียนรู้พื้นฐานภาษา C++

Class Serial

คลาส Serial ของ Arduino เป็นการใช้พอร์ตสื่อสารอนุกรมของบอร์ดไมโครคอนโทรลเลอร์ที่ใช้สื่อสารกับอุปกรณ์ภายนอก โดยการทำงานของพอร์ตสื่อสารอนุกรมจะมีบัฟเฟอร์สำหรับเก็บข้อมูลเพื่อนำออกและที่รับเข้า ซึ่งการใช้งานคำสั่งหรือเมธอด (method) ต่าง ๆ เป็นดังนี้

เริ่มต้นสื่อสาร

คำสั่ง begin ของคลาส Serial ใช้วำหรับกำหนดความเร็วในการสื่อสาร หรือการรับ/ส่งระหว่างอุปกรณ์ภายนอกกับบอร์ดไมโครคอนโทรลเลอร์ โดย ค่าความเร็วในการสื่อสารได้แก่ 300 1200 2400 4800 9600 19200 38400 57600 และ 115200 bps

หน่วยความเร็วในการสื่อสารเรียกว่า bps (bits per second) ซึ่งเป็นสัดส่วนของการส่งข้อมูล n บิตในเวลา 1 วินาที ด้วยเหตุนี้ 9600bps จึงหมายถึงใน 1 วินาทีมีการส่งหรือรับข้อมูล 9600 บิต แต่ถ้าฝั่งส่งใช้ 9600bps ฝั่งรับใช้ความเร็ว 19200bps จะเกิดปัญหาคือ เมื่อส่งข้อมูลไป 1 วินาที ทางฝั่งรับจะมองว่าข้อมูลที่ส่งมานั้นมีจำนวน 19200 ข้อมูล ขณะที่ผู้ส่งส่งไปเพียง 9600 ข้อมูลเท่านั้น ด้วยเหตุนี้ ในการสื่อสารความเร็วในการสื่อสารทั้งฝั่งบอร์ดไมโครคอนโทรลเลอร์และอุปกรณ์ภายนอกจะต้องมีความเร็วที่เท่ากัน

Serial.begin( ความเร็วในการสื่อสาร );

ค่าการทำงานโดยปกติของ begin() คือ SERIAL_8N1 ซึ่งหมายถึง การสื่อสารผ่านพอร์ตอนุกรมจะมีข้อมูลจำนวน 8 บิต ไม่มีพาริตีบิต (non-parity bit) และมีบิตกำกับการหยุด 1 บิต (1-stop bit) ซึ่งตั้งค่าตรงกับกับอุปกรณ์ภายนอกที่เชื่อมต่อสื่อสารกับบอร์ดไมโครคอนโทรลเลอร์

Serial Monitor

การตั้งค่าความเร็วในการสื่อสารของ Terminal ในโปรแกรม Arduino IDE สามารถกระทำโดยไปที่เมนู Tool แล้วเลือกรายการ Serial Monitor หรือกดแป้นลัด

เมื่อเลือกโปรแกรม Serial Monitor เพื่อเป็น Terminal ในการสื่อสารผ่านพอร์ตสื่อสารอนุกรม จะพบหน้าต่างของโปรแกรมด้านล่างของโปรแกรม Arduino IDE ดังนี้

ผู้ใช้งานสามารถปรับเปลี่ยนอัตราการสื่อสารกับบอร์ด Arduino ได้ด้วยการเลือกอัตราการสื่อสารดังภาพต่อไปนี้

ปิดการสื่อสาร

คำสั่งสำหรับยกเลิกการทำงานของพอร์ตสื่อสารอนุกรมมีรูปแบบการใช้งานดังนี้

Serial.end();

การตรวจสอบพอร์ตสื่อสาร

ในบางครั้งบอร์ดไมโครคอนโทรลเลอร์อาจจะไม่มีพอร์ตสื่อสารอนุกรม ดังนั้น ถ้าเขียนโปรแกรมโดยเพื่อให้ทำการสื่อสารผ่านพอร์ตทำให้เกิดความผิดพลาด ซึ่งปัญหาใหญ่ของการเขียนโปรแกรมบนระบบไมโครคอนโทรลเลอร์ คือ ไม่สามารถมองเห็นความผิดพลาดของการทำงานได้ เนื่องจากไม่มีระบบปฏิบัติการรายงานความผิดพลาดให้ทราบ ด้วยเหตุนี้เมื่อผู้เขียนโปรแกรมต้องการใช้งานการสื่อสารผ่านทางพอร์ตอนุกรมจึงต้องทำการตรวจสอบพอร์ตก่อนเสมอเพื่อไม่ให้เกิดความผิดพลาดในการทำงาน เช่น ในโปรแกรมมีการตรวจสอบเพื่อรอการเชื่อมต่อสื่อสารอนุกรม ซึ่งในการเขียนโปรแกรมกับ Arduino IDE การทำงานนี้จะสามารถทำงานได้เนื่องจากการพัฒนาโปรแกรมต้องเชื่อมต่อสายสื่อสารเข้ากับคอมพิวเตอร์ แต่เมื่อนำบอร์ดไปใช้งานจริงกลับไม่สามารถทำงานได้ ทั้งนี้เกิดจากโปรแกรมวนรอบรอการสื่อสาร แต่ไม่พบการเชื่อมต่อจึงวนรอบรอไม่รู้จบ

คำสั่งสำหรับตรวจสอบพอร์ตหรือการเชื่อมต่อสื่อสารพอร์ตอนุกรมมีรูปแบบให้ใช้งานดังนี้

if (Serial) {
    // สิ่งที่ทำเมื่อมีพอร์ตสื่อสารอนุกรม
}

หรือ

if (!Serial) {
    // สิ่งที่ทำเมื่อไม่มีพอร์ตสื่อสารอนุกรม
}

หรือ

while (Serial) {
    // สิ่งที่ทำเมื่อมีพอร์ตสื่อสารอนุกรม
}

หรือ

while (!Serial) {
    // สิ่งที่ทำเมื่อไม่มีพอร์ตสื่อสารอนุกรม
}

การส่งข้อมูลออก

คำสั่งสำหรับนำออกข้อมูลมีรูปแบบการใช้งานดังนี้

Serial.write(val);
Serial.write(str);
Serial.write(buf, len);

ซึ่งความแตกต่างของคำสั่งทั้ง 3 คือ แบบแรกส่งไบต์ของข้อมูลที่มีค่า val ออกไป แบบที่ 2 ทำการส่งสตริงหรือสายอักขระออกไป และแบบที่ 3 เป็นการส่งงข้อมูลจากตัวแปรแถวลำดับจำนวน len ไบต์

กรณีที่ต้องการนำออกข้อมูลในลักษณะของสตริง (กลุ่มของข้อมูลไบต์ที่เรียงกัน) โดยข้อมูลที่นำเข้าคำสั่งจะถูกแปลงเป็นสตริงเพื่อส่งออกไปยังพอร์ตอนุกรม สามารถใช้คำสั่งในรูปแบบต่อไปนี้

Serial.print( ข้อมูล );
Serial.println( ข้อมูล );
Serial.print( ข้อมูล, ฐาน );
Serial.println( ข้อมูล, ฐาน );
Serial.print( ตัวเลขทศนิยม, จำนวนหลักหลังจุดทศนิยม );
Serial.println( ตัวเลขทศนิยม, จำนวนหลักหลังจุดทศนิยม );

คำสั่ง print และ println ใช้สำหรับนำข้อมูลส่งออกไปที่พอร์ตสื่อสารอนุกรมด้วยอัตราความเร็วที่กำหนดจากคำสั่ง begin() โดยคำสั่ง print เมื่อนำข้อมูลส่งออกจะถือว่าเป็นการจบการทำงาน แต่ println จะส่งรหัสขึ้นบรรทัดใหม่หลังจากส่งข้อมูลออกทางพอร์ตสื่อสารอนุกรมไปแล้ว

โดย ฐาน คือ ค่าประเภทของเลขฐานของข้อมูลที่ต้องการแสดง ซึ่งมีค่าเป็น DEC OCT หรือ HEX สำหรับเลขฐาน 10 ฐาน 8 และฐาน 16

กรณีแสดงข้อมูลเลขทศนิยมสามารถกำหนดจำนวนหลักของตัวเลขหลังจุดทศนิยมได้ เช่น

Serial.println( 1.1234, 0 );
Serial.println( 1.1234, 1 );
Serial.println( 1.1234, 2 );
Serial.println( 1.1234, 3 );

การอ่านข้อมูล

ข้อมูล = Serial.read();

คำสั่ง read() ใช้สำหรับสั่งให้นำข้อมูลจากบัฟเฟอร์ของพอร์ตสื่อสารอนุกรม

Serial.readBytes( ตัวแปร, จำนวนข้อมูล );

คำสั่งนี้ทำการอ่านข้อมูลจำนวน n ชุดตามที่กำหนดมาเก็บในตัวแปร ใช้กับกรณีของการสตรีม

Serial.readBytesUntil( character, ตัวแปรแถวลำดับ, จำนวนข้อมูล );

ทำการอ่านจากสตรีมจำนวน n ไบต์ หรือจนกว่าจะพบ character ไปเก็บในตัวแปรแถวลำดับ

ตัวแปร = Serial.readString();

ใช้สำหรับอ่านข้อมูลมาเก็บในตัวแปรสตริง โดยข้อมูลที่อ่านมาจะสิ้นสุดด้วยรหัส ‘\0’

สำหรับการอ่านสตริงหรือจนกว่าจะพบอักขระที่กำหนด (terminator) สามารถใช้คำสั่งตามรูปแบบต่อไปนี้ ซึ่งตัวข้อมูลที่เป็น terminator นั้นจะถูกนำออกจากบัฟเฟอร์ โดยไม่ปรากฎในสตริง

Serial.readStringUntil( terminator) ;

ตั้งค่า Time-out

Serial.setTimeout( จำนวนมิลลิวินาที );

ตั้งค่าการรอการสื่อสารของพอร์ตสื่อสารอนุกรม โดยปกติตั้งค่าไว้ 1000 มิลลิวินาที ซึ่งค่าช่วงเวลานี้มีผลกับคำสั่ง find() findUntil() parseInt() parseFloat() readBytes() readBytesUntil() readString() และ readStringUntil()

การตรวจสอบข้อมูลที่เก็บในบัฟเฟอร์ของพอร์ตสื่อสาร

กรณีที่ต้องการทราบจำนวนข้อมูลที่ถูกเก็บอยู่ในบัฟเฟอร์ของพอร์ตสื่อสารอนุกรมสามารถใช้คำสั่งดังต่อไปนี้

จำนวนข้อมูล = Serial.available();

โดย คำสั่ง available() จะทำการตรวจสอบบัฟเฟอร์ของพอร์ตสื่อสารอนุกรม และรายงานจำนวนไบต์ของข้อมูลที่ถูกจัดเก็บกลับมา

กรณีที่ต้องตรวจสอบจำนวนข้อมูลที่เก็บในบัฟเฟอร์ที่เตรียมนำออกจากพอร์ตสื่อสารอนุกรมต้องใช้คำสั่งดังรูปแบบต่อไปนี้

จำนวนข้อมูล = Serial.availableForWrite();

การค้นหาข้อมูลในบัฟเฟอร์

การค้นหาข้อมูลในบัฟเฟอร์ของพอร์ตสื่อสารอนุกรมมีรูปแบบการใช้งานดังนี้

ผลลัพธ์ = Serial.find( target );

ผลลัพธ์ของการทำงานเป็น True เมื่อพบ target ในบัฟเฟอร์ และเป้น False เมื่อไม่พบ target ในบัฟเฟอร์

การค้นหาแบบสตรีม

สำหรับกรณีที่ต้องการค้นหา target จากพอร์ตอนุกรมแบบสตรีมจนกว่าจะพบ terminal มีรูปแบบของการใช้งานดังนี้

ผลลัพธ์ = Serial.findUntil( target, terminal );

เป็น True เมื่อพบ target และ False เมื่อเกิด time-out

การสั่งให้นำออกข้อมูลจากบัฟเฟอร์

คำสั่งสำหรับสั่งให้นำข้อมูลออกจากบัฟเฟอร์ให้หมดโดยไม่รอการรับข้อมูลเข้า มีรูปแบบดังนี้

Serial.flush();

การแปลงข้อมูลที่ได้จากพอร์ตสื่อสารอนุกรม

คำสั่งสำหรับแปลงข้อมูลที่อ่านจากบัฟเฟอร์และแปลงประเภทของข้อมูลให้เป็นตัวเลขจำนวนเต็มและทศนิยมมีรูปแบบดังนี้

ข้อมูล = Serial.parseInt();
ข้อมูล = Serial.parseFloat();

การอ่านข้อมูลถัดไป

กรณีที่ต้องการอ่านข้อมูลไบต์ถัดไปของบัฟเฟอร์โดยไม่ต้องนำข้อมูลออก มีรูปแบบของการใช้งานดังนี้

ข้อมูลถัดไป = Serial.peek();

สรุป

จากบทความนี้จะพบว่าคลาส Serial ของไลบรารี Arduino รองรับการนำเข้าและนำออกข้อมูลจากพอร์ตสื่อสารอนุกรมได้หลากหลายรูปแบบ ซึ่งในบทความด้าน Arduino สำหรับเรียนรู้ภาษา C++ เราจะใช้เป็นกลุ่มคำสั่งสำหรับแสดงผลลัพธ์ และนำเข้าข้อมูลระหว่าง Serial Monitor ของ Arduino IDE กับบอร์ดไมโครคอนโทรลเลอร์

สุดท้ายนี้ทีมงานหวังว่าบทความนี้คงมีประโยชน์บ้างไม่มากก็น้อย และขอให้สนุกกับการเขียนโปรแกรมครับ

อ้างอิง

https://www.arduino.cc/reference/en/language/functions/communication/serial/

(C) 2020-2021, โดย อ.ดนัย เจษฎาฐิติกุล/อ.จารุต บุศราทิจ
ปรับปรุงเมื่อ 2021-05-22, 2021-06-07, 2021-09-14