เนื่องจาก LCD พิมพ์ค่าเริ่มต้นจากตำแหน่ง cursor ที่เซ็ตไว้ ยาวไปจนถึงตัวอักษรตัวสุดท้าย ปัญหานี้เกิดจากการไม่ได้จองพื้นที่แสดงข้อความอย่างถูกต้อง
ตัวอย่างการส่งพิมพ์ข้อความตัวอักษร abcd ที่ตำแหน่งแถว 0 หลัก 0 (แถวแรกหลักแรก) แล้วแก้เป็นตัวเลข 123
lcd.setCursor(0,0); // ตั้งเคอร์เซอร์ที่ตำแหน่งแถวแรกหลักแรก
lcd.print("abcd"); // หน้าจอจะเริ่มแสดง abcd จากนั้นเคอร์เซอร์ตอนนี้จะอยู่ที่ 4,0
lcd.setCursor(0,1); // ตั้งเคอร์เซอร์ที่ตำแหน่งแถวสองหลักแรก
lcd.print("efgh"); // หน้าจอจะเริ่มแสดง efgh จากนั้นเคอร์เซอร์ตอนนี้จะอยู่ที่ 4,1
delay(3000); // หยุดเวลาเพื่อแสดงผลไว้ 3 วินาที
lcd.setCursor(0,0); // ตั้งเคอร์เซอร์กลับมาที่ตำแหน่งแถวแรกหลักแรก
lcd.print("123"); // จะเห็นหน้าจอแสดง 123d ซึ่งตัว d ยังไม่หายไปจากการพิมพ์ครั้งแรก
delay(3000); // หยุดเวลาเพื่อแสดงผลไว้ 3 วินาที
วิธีแก้ด้วยการ clear ก่อนแล้วค่อย print ใหม่ กรณีสามารถล้างหน้าจอทั้งหน้าได้
lcd.setCursor(0,0); // ตั้งเคอร์เซอร์ที่ตำแหน่งแถวแรกหลักแรก
lcd.print("abcd"); // หน้าจอจะเริ่มแสดง abcd จากนั้นเคอร์เซอร์ตอนนี้จะอยู่ที่ 4,0
lcd.setCursor(0,1); // ตั้งเคอร์เซอร์ที่ตำแหน่งแถวสองหลักแรก
lcd.print("efgh"); // หน้าจอจะเริ่มแสดง efgh จากนั้นเคอร์เซอร์ตอนนี้จะอยู่ที่ 4,1
delay(3000); // หยุดเวลาเพื่อแสดงผลไว้ 3 วินาที
lcd.clear(); // ล้างหน้าจอ
lcd.setCursor(0,0); // ตั้งเคอร์เซอร์กลับมาที่ตำแหน่งแถวแรกหลักแรก
lcd.print("123"); // จะเห็นหน้าจอแสดง 123 ถูกต้องแต่ตัวอักษร efgh จะหายไปด้วย
lcd.setCursor(0,1); // ตั้งเคอร์เซอร์ที่ตำแหน่งแถวสองหลักแรก
lcd.print("efgh"); // หน้าจอจะเริ่มแสดง efgh จากนั้นเคอร์เซอร์ตอนนี้จะอยู่ที่ 4,1
delay(3000); // หยุดเวลาเพื่อแสดงผลไว้ 3 วินาที
วิธีแก้ด้วยการเพิ่มตัวอักษรว่างให้มันเพื่อกลบตัวอักษรเก่าทิ้ง
lcd.setCursor(0,0); // ตั้งเคอร์เซอร์ที่ตำแหน่งแถวแรกหลักแรก
lcd.print("abcd"); // หน้าจอจะเริ่มแสดง abcd จากนั้นเคอร์เซอร์ตอนนี้จะอยู่ที่ 4,0
lcd.setCursor(0,1); // ตั้งเคอร์เซอร์ที่ตำแหน่งแถวสองหลักแรก
lcd.print("efgh"); // หน้าจอจะเริ่มแสดง efgh จากนั้นเคอร์เซอร์ตอนนี้จะอยู่ที่ 4,1
delay(3000); // หยุดเวลาเพื่อแสดงผลไว้ 3 วินาที
lcd.setCursor(0,0); // ตั้งเคอร์เซอร์กลับมาที่ตำแหน่งแถวแรกหลักแรก
lcd.print("123 "); // จะเห็นหน้าจอแสดง 123 ถูกต้องโดยยังมี efgh ที่แถวที่ 2 อยู่ปกติด้วยการถมด้วยที่ว่าง
delay(3000); // หยุดเวลาเพื่อแสดงผลไว้ 3 วินาที
ตัวอย่างแรกเราทราบในใจอยู่แล้วว่าข้อความที่จะนำมาแทนข้อความที่แล้ว มีขนาดจำนวนอย่างไร จึงแทนที่ด้วยที่ว่าง หรือเคลียร์ทั้งหน้าจอได้ไม่ยาก แต่ในตัวอย่างนี้จะซับซ้อนขึ้นหน่อย เพราะเราต้องการให้จอแสดงค่าจากตัวแปรอะไรบางอย่าง เช่น แสดงค่าอุณหภูมิ 0-200องศา อาจจะแสดงไปพร้อม ๆ กับค่าความชื้น 0.00-100.00% ซึ่งเราไม่ทราบจำนวนตัวอักษรที่แน่นอนเพื่อแทนด้วยที่ว่างได้อย่างชัดเจนดังเช่นตัวอย่างแรก
เช่น อุณหภูมิ 135องศา ความชื้น 40.50%
ต้องการให้แสดงทางหน้าจอดังนี้
TEMP : 135 C
HUMID : 40.50%
โดยเมื่อเวลาผ่านไปกำหนดให้เซนเซอร์อ่านค่าเปลี่ยนไปป็น
อุณหภูมิ 99องศา ความชื้น 0.30%
ค่าบนหน้าจอที่เราต้องการควรแสดงเป็น
TEMP : 99 C
HUMID : 0.30%
เราจะสังเกตว่าตัวแปรที่จะเอามาแสดงมักมีหลักจำนวนที่คาดเดาไม่ได้เช่น 40.50 มีตัวอักษร 5ตัว 0.30 มีตัวอักษร 4 ตัว เป็นต้น
วิธีที่ 1 ใช้การเคลียร์หน้าจอ และพิมพ์ข้อความใหม่ทั้งดุ้น
วิธีนี้เป็นวิธีตรงไปตรงมา คือเน้นการ refresh ทั้งหน้าจอ เพื่อแสดงสถานะหน้าจอทั้งหน้าจอใหม่ที่มีค่าตัวแปรที่เปลี่ยนไป
int temp = 135;
float humid = 40.5;
lcd.setCursor(0,0); // ตั้งเคอร์เซอร์ที่ตำแหน่งแถวแรกหลักแรก
lcd.print("TEMP : "); // หน้าจอจะเริ่มแสดง TEMP : ตอนนี้เคอร์เซอร์ควรอยู่ที่ 7,0
lcd.print(temp);
lcd.setCursor(0,1);
lcd.print("HUMID : ");
lcd.print(String(humid,2));
delay(3000); // หยุดเวลาเพื่อแสดงผลไว้ 3 วินาที
lcd.clear(); // ล้างหน้าจอ
temp = 99;
humid = 0.3;
lcd.setCursor(0,0); // ตั้งเคอร์เซอร์ที่ตำแหน่งแถวแรกหลักแรก
lcd.print("TEMP : "); // หน้าจอจะเริ่มแสดง TEMP : ตอนนี้เคอร์เซอร์ควรอยู่ที่ 7,0
lcd.print(temp);
lcd.setCursor(0,1);
lcd.print("HUMID : ");
lcd.print(String(humid,2)); //แปลงตัวเลข(float)เป็นสายอักขระ(String)โดยใช้ทศนิยม2ตำแหน่ง
วิธีที่ 2 ใช้ sprintf (แนะนำ)
วิธีนี้เป็นวิธีที่ผมใช้เป็นประจำ คือใช้ฟังก์ชัน sprintf ฟังก์ชันนี้ทำงานคล้าย ๆ การ printf ที่พิมพ์ข้อความออกมาทาง console แต่สำหรับคนที่พึ่งเข้ามาเล่น Arduino ใหม่ ๆ เลย อาจยังไม่คุ้นชินนัก
การใช้ sprintf เป็นการแปลงตัวเลข ตัวอักษร ผสมกับอักขระต่าง ๆ ให้อยู่ในฟอร์มที่เราต้องการ เช่น
เราต้องการแสดงวัน/เดือน/ปี ให้อยู่ในข้อความเดียวกัน โดยวันเดือนปีเป็นตัวแปรเช่น
int day = 2;
int month = 5;
int year = 1992;
char buff[11]; //จองพื้นที่ 10+1 ตัวอักษรนับจากตัวอักษรที่เราจะใช้กรณีนี้เป็น 02/05/1992 รวม 10 อักษร
sprintf(buff, "%02d/%02d/%d", day, month, year); //แพ็คตัวแปร day month year ให้อยู่ในฟอร์ม
//ที่กำหนดแล้วเก็บไว้ใน buff
%d หมายถึงการแทนที่ด้วยตัวแปรตัวเลข integer
%02d หมายถึงการแทนที่ด้วยตัวแปรเลข integer โดยหากมีเลขไม่ครบ 2 หลักจะเติมเลข 0 ไว้ข้างหน้าเช่น day=3 ผ่านฟอร์ม %02d จะได้เป็น 03 เป็นต้น
สำหรับตัวแปรประเภทอื่น ๆ เช่น float จะใช้เป็น %f อักขระจะใช้เป็น %c สายอักขระ string จะใช้เป็น %sเป็นต้น ทีนี้ลองเอามาใช้กับตัวอย่างที่แล้วกัน
//ตรงส่วนนี้สามารถปริ้นแค่ครั้งเดียวได้เลย
lcd.setCursor(0,0); // ตั้งเคอร์เซอร์ที่ตำแหน่งแถวแรกหลักแรก
lcd.print("TEMP : "); // หน้าจอจะเริ่มแสดง TEMP : ตอนนี้เคอร์เซอร์ควรอยู่ที่ 7,0 <--จำไว้
lcd.setCursor(0,1);
lcd.print("HUMID : "); // หน้าจอจะเริ่มแสดง TEMP : ตอนนี้เคอร์เซอร์ควรอยู่ที่ 8,1 <--จำไว้
//หลังจากส่วนนี้เป็นสามารถทำเป็นฟังก์ชันเรียกเพื่ออัพเดทแต่ละช่วงเวลาได้
int temp = 135;
float humid = 40.5;
updateValue(temp, humid);
delay(3000); // หยุดเวลาเพื่อแสดงผลไว้ 3 วินาที
temp = 99;
humid = 0.3;
updateValue(temp, humid);
จะเห็นว่าด้านบนมีโค้ดสองส่วน คือ ส่วนที่เป็นการปริ้นตัวอักษรที่ไม่เปลี่ยนตามเวลาเช่นพวกหัวข้อ และส่วนที่เป็นตัวเลขจากเซนเซอร์ วันที่ เวลา ที่เปลี่ยนตามเวลา เราจะใช้ชื่อฟังก์ชัน updateValue โดยกำหนดใส้ในของมันเป็นดังนี้
//ฟังก์ชันสำหรับอัพเดทเฉพาะค่า temp และ humid
void updateValue(temp, humid) {
char buff[10]; //จองพื้นที่ไว้สัก 10 ตัวอักษรน่าจะเหลือเฟือ
sprintf(buff, "%3d", temp);//สังเกตว่า %3d ที่ไม่มี 0 เหมือนกับ %03d ตรงนี้ถ้ามี 0 ระบบจะเติม 0 ให้กรณีที่ตัวเลขไม่ครบ 3 ตัว แต่ถ้าไม่มี 0 ระบบจะเว้นที่ว่างให้ครบ 3 อักษร ลองที่ http://cpp.sh/8ndum
lcd.setCursor(7, 0);
lcd.print(buff);
sprintf(buff, "%6.2f", humid);//%6.2f หมายถึงจองพื้นที่ไว้ 6 ตัวอักษร โดยที่.2หมายถึงทศนิยม 2 ตำแหน่ง (อันนี้ต้องนับทั้งหมดนะเช่น 100.02 นับได้ 6 ตัวอักษรรวมจุด และทศนิยม 2 ตำแหน่ง)
lcd.setCursor(8, 1);
lcd.print(buff);
}
ข้อดีของวิธีนี้ที่ชัดเจนคือ เราใช้ฟอร์มกำหนดได้ว่าเราจะให้ตัวอักษรมีความยาวเท่าไร ทศนิยมกี่ตัแหน่ง ทำให้จัดสรรตำแหน่งหน้าจอได้สะดวกมาก นอกจากนั้นเราสามารถกำหนดให้เราอัพเดทค่าเฉพาะส่วนได้ ไม่จำเป็นต้องอัพเดททั้งหน้าจอ เนื่องจากทุก ๆ ตัวอักษรที่ต้องส่งไป จะทำให้controllerเราเอาเวลามาประมวลผล ซึ่งเวลาเหล่านั้นอาจเป็นเวลาที่ควรนำไปอ่านค่าเซนเซอร์ให้มีความละเอียดมากขึ้น
หวังว่าบทความนี้จะเป็นประโยชน์กับนักพัฒนาและมือใหม่ทุก ๆ ท่านครับ