บทความนี้อธิบายการใช้งานคลาส 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