ไอเดียและแรงบันดาลใจ
วันหนึ่งตอนที่ฟังวิทยุคลื่นยาว (longwave) ผ่าน SDR อยู่นะ ไปเจอสัญญาณแปลกๆ ที่ความถี่ 77KHz เข้าให้เลย ไม่รู้เหมือนกันว่ามันคืออะไร แต่ฟังไปซักพักก็เริ่มรู้สึกคุ้นๆ เหมือนเป็นสัญญาณบอกเวลา เปิดกูเกิลเช็คอีกทีก็ชัวร์เลย มันคือสัญญาณ DCF77 ที่ส่งมาจากแถบแฟรงก์เฟิร์ต เยอรมนี รับกันง่ายๆ ในยุโรปตะวันตก
ด้วยความเป็นเด็กช่าง/เด็ก Arduino อย่างเรา ก็เลยสงสัยขึ้นมาว่า มีโมดูลไหนที่รับสัญญาณนี้ได้มั้ย จะได้สร้างนาฬิกาที่ตั้งเวลาเองได้ตลอด แม่นยำระดับอะตอมคล็อก (atomic clock) ไปเลย :-) และแน่นอนว่า... มีสิวะ!
พูดจริงๆ นาฬิกาธรรมดาๆ มันก็ไม่ค่อยตื่นเต้นหรอก เพราะรอบตัวเราก็มีแต่ของบอกเวลาเต็มไปหมด แต่อย่างหนึ่งที่คิดว่าน่าจะมีประโยชน์มากๆ โดยเฉพาะช่วงโควิดที่ต้อง Work From Home แบบนี้ คือเราทำงานในวงการ IT ต้องคุยกับเพื่อนร่วมงานที่กระจายอยู่ทั่วโลก ทั้งอเมริกา ยุโรป และเอเชียแปซิฟิก การได้มองขึ้นมาจากจอคอมแล้วเห็นเวลาของแต่ละโซนทันที มันช่วยได้เยอะเลย แม้ว่าจะเช็คในเน็ตหรือตั้งเวลาเพิ่มใน Windows ได้ก็ตาม แต่การมีอุปกรณ์เฉพาะที่แสดงผลพร้อมกันหลายโซน มันสะดวกและเท่กว่ามาก แถมครอบครัวเราก็กระจายตัวอยู่ต่างประเทศด้วย เลยคิดว่าน่าจะมีประโยชน์ไปอีก
นี่คือวิดีโอตัวอย่าง (ยังไม่มีเสียงนะ เดี๋ยวรุ่นพี่กำลังทำเอฟเฟกต์เสียงอยู่ อัพเดทเร็วๆ นี้)
ฟีเจอร์เด็ดๆ
แทนที่จะทำแค่นาฬิกาที่แสดงเวลาต่างโซนแบบแห้งๆ เราว่ามันน่าเบื่อ เลยเพิ่มอนิเมชันและฟังก์เจอร์สนุกๆ เข้าไปให้มันท้าทายขึ้น ตามนี้เลยวัยรุ่น:
- ตอนเปิดเครื่องจะมีอนิเมชัน "ทดสอบหลอด" (bulb test) ก่อน จากนั้นจะมีสัญญาณแปลกๆ ปรากฏและหายไปแบบสุ่ม ดูเหมือนอุปกรณ์กำลัง "คิด" อยู่ตอนที่รอรับสัญญาณเวลา DCF77 (ใช้เวลาประมาณ 2 นาที)
- หมุน Rotary Encoder เพื่อปรับความสว่างของหลอด LED 7-Segment ได้ 7 ระดับ จัดไป!
- กดปุ่มบน Rotary Encoder เพื่อแสดงวันที่และเวลาท้องถิ่น (รูปแบบ YYYY.MM.DD) มันจะหายไปเองหลังจาก 10 วินาที หรือกดปุ่มอีกทีเพื่อปิดทันทีก็ได้
- หลังจากแสดงวันที่/เวลาท้องถิ่นแล้ว เวลาของแต่ละโซนจะปรากฏกลับมาด้วยอนิเมชันสไตล์ต่างๆ ถึง 7 แบบ! เช่น ปรากฏทีละ Segment จากกลางออกด้านข้าง, จากซ้ายไปขวา, หรือสุ่ม Segment ขึ้นมาจนครบ ดูวิดีโอด้านล่างเลยจะเห็นภาพ
- ในช่วงเวลางานวันธรรมดา (จันทร์-ศุกร์) นาฬิกาจะมีอนิเมชันไฟกระพริบแบบสุ่ม 5 แบบ ตอนเริ่มชั่วโมงใหม่ (top of the hour) และตอนครึ่งชั่วโมง (30 minutes into the hour) เป็นการเตือนเราเพราะประชุมส่วนใหญ่จะเริ่มตรงเวลาพวกนี้พอดี สู้งานนะน้อง!
ไฮไลต์โค้ดและประเด็นอื่นๆ
เราเขียนโค้ดให้ปรับแต่งง่ายๆ ใครอยากทำนาฬิกาแบบนี้ด้วยจำนวนโซนเวลามากหรือน้อยกว่านี้ก็ทำได้สบาย ฟังก์ชันที่ใช้แสดงเวลาและทำอนิเมชันต่างๆ ไม่ต้องแก้อะไรให้วุ่นวาย เพราะมันอ้างอิงจากค่าคงที่ (global constants) ที่กำหนดไว้ตอนต้นโค้ดทั้งหมด
เพื่อให้เขียนอนิเมชันหรือการเปลี่ยนภาพ (transition) ได้ง่ายขึ้น เราใช้ Array 2 ชุด: ชุดแรกเก็บสถานะปัจจุบันของแต่ละหลักที่แสดงอยู่ (เหมือน "Display Memory") อีกชุดเก็บสถานะที่เราอยากให้แสดง อนิเมชันส่วนใหญ่จะทำงานโดยดูจาก Array สองตัวนี้ เพื่อเปลี่ยนการแสดงผลจากสถานะปัจจุบันไปสู่สถานะใหม่ที่ต้องการ ห้ามช็อตนะตัวนี้!
ในงานของพี่นะ พี่ตั้งให้จอตรงกลางแสดงเวลาตามโซนเวลาของพี่ (ตัวแปร localTimezone บอกว่าจอไหนคือเวลาท้องถิ่น) แต่แน่นอนว่าเราจะเลือกจอไหนก็ได้ตามสะดวก พี่แนะนำให้ใช้จอเป็นจำนวนคี่ (เช่น 3, 5, 7 แบบของพี่ หรือ 9 ขึ้นไปก็จัดไป)
พี่เลือกใช้ Arduino Mega 2560 ตั้งใจเลยนะ เพราะมันมีขา Digital เยอะมาก ถ้าอยากใช้แค่ 3 หรือ 5 จอ Arduino Uno ก็พอไหว แต่สำหรับโปรเจกต์ 7 โซนเวลาแบบพี่ มันมีขาไม่พอแน่นอน
ระวังเรื่องไฟเลี้ยงด้วยนะ! การใช้ไฟ 5V จาก Arduino เลี้ยงไฟให้จอ 7-Segment สองสามตัวอาจพอไหว แต่ห้ามลองกับจำนวนจอที่มากขึ้นเด็ดขาด เพราะมันจะกินกระแสเกินกว่าที่ Arduino จะจ่ายไหว แล้วเจ้า Arduino ของน้องอาจพังได้! ในกรณีของพี่ พี่เลือกที่จะใช้แหล่งจ่ายไฟแยกสำหรับจอ 7-Segment ทั้งหมด ส่วนการต่อสาย Clock และ Data ของจอหลายๆ ตัวเข้ากับ Arduino ไม่มีปัญหาหรอก เพราะ Arduino จะส่งคำสั่งไปทีละตัว การใช้ขาทั้งหมดที่มีเพื่อต่อจอเพิ่มจึงไม่น่ามีความเสี่ยง
อีกเรื่องคือไฟเลี้ยง LED สำหรับป้ายชื่อโซนเวลานี่แหละ มันรวมกันเร็วมาก (ของพี่ใช้ 7 ดวง) เพราะ LED พวกนี้กินไฟจากขา Digital ของ Arduino โดยตรง น้องอาจใช้ไฟถึงขีดจำกัดของ Arduino ได้ง่ายๆ ของพี่ 7 ดวงยังไม่มีปัญหา แต่ถ้ามากกว่านี้อาจเกินลิมิต ต้องคิดไว้ด้วยนะ
โครงสร้าง NTP สากล: นาฬิกา Multi-Time Zone
โปรเจกต์นาฬิกา Arduino ส่วนใหญ่พึ่งพาโมดูล RTC แบบ DS3231 ราคา $2 โมดูลนั้นก็ใช้ได้นะ แต่มันจะค่อยๆ เผลอไปประมาณ 2 นาทีใน 3 ปี โปรเจกต์นี้ใช้ตัวรับสัญญาณ DCF77 เพื่อความแม่นยำระดับนาฬิกาอะตอมในยุโรปตะวันตก แต่ถ้าอยากได้วิธีแบบสากลที่ใช้อินเทอร์เน็ต น้องอาจใช้ ESP8266 เพื่อทิ้งคริสตัลออสซิลเลเตอร์แบบฟิสิคัลไปเลย มันจะไปคุยทางคณิตศาสตร์กับนาฬิกาอะตอมของ NIST (สถาบันมาตรฐานและเทคโนโลยีแห่งชาติสหรัฐฯ) ที่ลอยอยู่ในอวกาศ ผ่านทางอินเทอร์เน็ตด้วยการแลกเปลี่ยนแพ็กเก็ต NTP UDP
โปรโตคอลการทำงานลึกๆ ของ NTP UDP
โซลูชันแบบใช้อินเทอร์เน็ตจะต้องพึ่งพาวิศวกรรมซ็อกเก็ตเครือข่าย
- ESP8266 (WiFiManager) จะล็อกอินเข้าเราเตอร์ที่บ้าน
- มันจะส่งอาร์เรย์ไบต์
UDP (User Datagram Protocol)ข้ามโลกไปยังpool.ntp.orgพอดีที่พอร์ต 123 - เซิร์ฟเวอร์จะตอบกลับด้วยแพ็กเก็ต 48 ไบต์ ที่มีค่า UNIX Epoch time แม่นยำ (วินาทีที่ผ่านมาตั้งแต่วันที่ 1 มกราคม 1970)
- คณิตศาสตร์ของ Epoch: Arduino จะดึงค่าวินาทีออกมา!
timeClient.update(); unsigned long epochTime = timeClient.getEpochTime(); int currentHour = (epochTime % 86400L) / 3600;
การคำนวณออฟเซ็ตโซนเวลาสากล (Arrays)
นาฬิกาจะไร้ประโยชน์ถ้ามันแสดงแค่ UTC เวลาลอนดอนดิบๆ ให้ผู้ใช้
- โปรเจกต์ควรจะรันจอแสดงผลที่แบ่งออกเป็นส่วนๆ ตามภูมิศาสตร์ (นิวยอร์ก, โตเกียว, ซิดนีย์ ฯลฯ)
- โปรแกรมเมอร์ต้องสร้างอาร์เรย์ออฟเซ็ต!
int zoneOffsets[7] = { -5, +9, +10 ... }; // ชั่วโมงที่ต่างจาก UTC! - กับดักการทำงาน: น้องบวกชั่วโมงธรรมดาๆ ไม่ได้นะ! ถ้า UTC เป็น
22:00แล้วน้องบวกเวลาโตเกียว+9ชั่วโมง โค้ดจะคำนวณได้31:00ซึ่งจะทำให้การแสดงผลพังทันที! - น้องต้องใช้การหารแบบ Modulo อย่างเคร่งครัด:
int tokyoHour = (currentHour + zoneOffsets[1]) % 24; if (tokyoHour < 0) { tokyoHour += 24; } // คณิตศาสตร์สำหรับแก้ไขชั่วโมงติดลบที่ย้อนกลับ! - จากนั้นไมโครคอนโทรลเลอร์ก็จะส่งสตริงเวลาอะตอมที่จัดรูปแบบสมบูรณ์แบบทั้งหมดไปยังเมทริกซ์จอแสดงผลพร้อมกัน!
โครงร่างระบบย่อยอะตอม (แบบออกแบบทางเลือก)
สำหรับเวอร์ชันที่ใช้อินเทอร์เน็ต:
- ESP8266 NodeMCU หรือ ESP32 (Uno ธรรมดาเข้า Wi-Fi ไม่ได้)
- OLED ขนาดใหญ่ I2C 128x64 (SSD1306) หรือ จอ TFT แบบ SPI เพื่อจัดระเบียบโซนเวลาทางภูมิศาสตร์ทั้งหมดบนหน้าจอ
<NTPClient.h> และไลบรารี่ <WiFiUdp.h>
แผนผังวงจร (Schematic)
รุ่นพี่หาตัวโมดูลรับสัญญาณ DCF77 ในคลังชิ้นส่วนของ Fritzing ไม่เจอ แถมยังขี้เกียจจะนั่งสร้างชิ้นส่วนใหม่ด้วย แต่ว่าโมดูลนี้ต่อกับ Arduino ง่ายมากๆ เลยนะตัวนี้ จ่ายไฟตรงจากเอาต์พุต 5VDC ของตัวแปลง 12VDC ไป 5VDC ได้เลย พินที่สามคือพินสัญญาณ (เขียนว่า "SIG") เอาไปต่อกับดิจิตอลพิน 2 ของ Arduino ไป
อีกอย่าง รูปมุมมองบนเบรดบอร์ดที่พี่ใส่ไว้มันอาจจะดูไม่ค่อยมีประโยชน์เท่าไหร่ เพราะว่ามันดูรกไปหมดด้วยสายต่อต่างๆ และพี่ก็ยังไม่ได้จัดเวลาไปนั่งวาดแผนผังวงจรที่สะอาดตาสักเท่าไหร่ แต่ว่าการต่อสายมันตรงไปตรงมาเองอยู่แล้วน้อง ลองดูจากโค้ดที่พี่คอมเมนต์ไว้ดีๆ ก็หายห่วง
ทางเลือกอื่นๆ (Alternatives)
สำหรับคนที่อยู่โซนนอกพื้นที่รับสัญญาณ DCF77 (ยุโรปตะวันตก) นะ น้องอาจจะต้องหาตัวรับสัญญาณเวลาชนิดอื่นที่เหมาะสมมาใช้แทน หรือไม่ก็ใช้โมดูลนาฬิกาจริง (Real-Time Clock Module) ภายนอก ซึ่งมีตัวเลือกถูกๆ ให้เลือกเพียบเลย อย่างที่บอกไปข้างบน อีกทางที่มั่นคงมากๆ คือใช้โมดูล ESP8266/ESP32 ไปซิงค์เวลาผ่านอินเทอร์เน็ตด้วยโปรโตคอล NTP ไปเลย ง่ายดี
เครื่องมือ เทคนิค และทริคเล็กๆ น้อยๆ
พี่ใช้ Google SketchUp (ฟรี) ในการออกแบบกล่องไม้ จัดวางชิ้นส่วน และสร้างแบบตัด (cut-sheets) เพื่อที่จะได้เจาะรูสำหรับติดตั้งจอแสดงผล 7 หลักได้พอดีเป๊ะ
พี่ไม่รู้วิธีพิมพ์แบบตัดจาก SketchUp ให้ได้ขนาดจริงบนกระดาษสักที เลยใช้วิธีแคปหน้าจอเทมเพลตที่ออกแบบไว้ใน SketchUp ไปวางใน Adobe Photoshop Elements (ไม่ฟรี แต่มีตัวฟรีอื่นๆ นะ) แล้วค่อยปรับขนาดภาพให้ได้มิลลิเมตรเป๊ะๆ
แต่การพิมพ์จาก Photoshop Elements มันยุ่งยากสำหรับพี่มาก พิมพ์ทีไรได้ขนาดไม่ตรงกับที่ตั้งใจสักที มีทริคเก่าแก่ที่พี่ใช้คือ บันทึกไฟล์เป็น PDF แล้วใช้ฟีเจอร์พิมพ์โปสเตอร์ใน Adobe Acrobat Reader (ฟรี) โดยเลือก "ขนาดจริง" และ "เครื่องหมายตัด" มันจะพิมพ์ออกมาได้ขนาดแม่นยำมาก ถ้าขนาดจริงใหญ่เกินหน้ากระดาษเดียว มันก็จะแบ่งพิมพ์หลายแผ่นให้เอง จากนั้นก็ตัดตามเส้น แล้วใช้เทปต่อให้เป็นเทมเพลตใหญ่ๆ ไปวางบนวัสดุที่ต้องการตัดได้พอดีเป๊ะ พี่ใช้ทริคนี้พิมพ์ภาพพาโนรามาสวยๆ บนกระดาษอัดรูปแล้วเอามาต่อกันเป็นโปสเตอร์ใหญ่ๆ ด้วย – อลังการงานสร้าง!
มีอีกทางนึงที่พี่เจอหลังจากทำโปรเจกต์นี้เสร็จแล้ว คือใช้ Affinity Designer แทน Photoshop Elements นี่เป็นโปรแกรมวาดภาพเวกเตอร์ (และแรสเตอร์) ราคาไม่แพง ที่พี่ว่าดีมากๆ โมเดิร์นและใช้ง่ายกว่า Photoshop Elements เยอะ ซึ่งสำหรับพี่มันดูล้าสมัยไปแล้ว ว่าแต่ พี่ลองใช้โปรแกรมฟรีชื่อดังหลายตัวมาก่อนจะซื้อ Affinity Designer นะ แต่ใช้ได้แป๊บเดียวก็เลิกแล้ว ส่วนใหญ่ฟังก์ชันจำกัด มีบั๊ก หรืออินเทอร์เฟซใช้งานยากน่ะ
พี่ใช้ Blackmagic Design's DaVinci Resolve (ฟรี) ทำวิดีโอ และ Ableton Live 9 Intro (ไม่ฟรี) ทำเสียงเอฟเฟกต์ ถ้าน้องยังไม่เคยใช้ DaVinci Resolve เลย พี่บอกเลยว่าต้องลอง! เครื่องพี่ต้องแรงหน่อยถึงจะรันไหว แต่มันทรงพลังมากกก และขอย้ำอีกที... ฟรีสำหรับพวกเราชาวฮ็อบบี! ส่วน Ableton Live ก็สนุกดีนะ แต่ถ้าเพิ่งเริ่มใช้ซอฟต์แวร์แบบนี้ (เหมือนพี่ตอนแรก) มันต้องใช้เวลาเรียนรู้สักพักว่าจะใช้ซินธิไซเซอร์ ออดิโอเอฟเฟกต์ ยังไงให้ได้เสียงตามที่ต้องการ พอเข้าใจแล้วมันสุดยอดมาก!
จอแสดงผล 7 หลักที่พี่ซื้อมามีหน้าจอสีดำแต่ข้างๆ เป็นสีขาว พี่เลยใช้ปากกามาร์กเกอร์สีดำทาลงไปให้ข้างๆ ดำด้วย บางทีก็ทาสีขาวทับข้อความบนแผ่น PCB ที่จอติดอยู่ให้ดูสตีลท์ขึ้นอีกนิด งานเข้าละน้อง!
ข้อตกลงก่อนเริ่มเล่น
พี่ไม่ได้รับค่าจ้างหรือผลประโยชน์ใดๆ จากผู้ผลิตเครื่องมือที่พี่แนะนำเลยนะ (ส่วนใหญ่ก็ฟรีอยู่แล้วสำหรับงานอดิเรก) จริงๆ ก็ไม่จำเป็นต้องเอ่ยชื่อพวกนี้ด้วยซ้ำ แต่ที่เอามาเล่าเพราะพี่ใช้เวลาตรวจสอบและลองใช้เครื่องมือคล้ายๆ กันมาอย่างโชกโชน แล้วตัวพี่เองก็ปลื้มปริ่มกับตัวที่เลือกมาแนะนำสุดๆ
พี่รับประกันไม่ได้ว่างานของน้องจะรันเป๊ะเวอร์ถ้าลองทำตามที่พี่เขียนไว้ที่นี่ทุกประการ แต่ว่าพี่พยายามสุดตัวแล้วที่จะให้ข้อมูลถูกต้องและละเอียดที่สุด ดังนั้นมันก็น่าจะเวิร์ค (ของพี่เองรันมาได้อย่างเสถียรตลอด 2 ปีที่ผ่านมาล่ะ!) อีกอย่าง นี่เป็นงานอดิเรกที่พี่ก็มีเวลาให้ไม่มากนัก ถ้าน้องเจอปัญหาอะไรขึ้นมา น้องต้องลุยแกะเอง แก้เองนะจ๊ะ แต่พี่ว่า นั่นแหละคือส่วนหนึ่งของความมันส์ในโปรเจกต์แบบนี้เลย แถมเวลามีปัญหาเนี่ยแหละ ที่เรามักจะได้เรียนรู้เยอะที่สุด
ขอให้สนุกกับการเดินทางนะน้อง! สู้งาน!