หลายปีก่อนพี่สั่ง 7-segment display มา 12 ตัว อยากทำนาฬิกาที่แสดงเวลาและวันที่ แต่ตอนนั้นดูเหมือนว่าจะต้องใช้ IC ดิจิตอลเยอะเกินไป ยุคนี้มี Arduino แล้ว งานนี้เลยง่ายขึ้นเยอะ
นาฬิกาเรือนนี้สามารถแสดงได้ทั้งเวลาและวันที่, อายุจันทร์ (เป็นวัน), เวลาพระอาทิตย์ขึ้นและตก, ระดับสูงสุดของดวงอาทิตย์, ระดับจริงของดวงอาทิตย์, มุมเอียงของโลก, ระยะเวลาระหว่างพระอาทิตย์ขึ้น-ตก, ความกดอากาศ (mBar), อุณหภูมิ (เซลเซียส), โหมดปรับตั้งเวลาและวันที่, และตั้งค่า aging register ของ RTC
นาฬิกาเรือนนี้ใช้สัญญาณ 1 Hz SQW จาก RTC เป็น interrupt พี่เขียน routine สำหรับ RTC (DS3231) เอง เลยไม่ต้องโหลด library ของ RTC
เพราะพี่ใช้วิธี multiplexing สิ่งแรกที่ทำคือเชื่อมต่อ segment a ของทั้ง 12 ตัวเข้าด้วยกัน แล้วก็ segment b, c, d, e, f, g และจุดทศนิยมด้วย ดูรูปบอร์ดแสดงผลได้เลย







จากนั้นพี่ก็ทำบอร์ดเล็กๆ สำหรับ shift register (SN74595) สามตัว
พี่ใช้ตัวต้านทาน (Resistor) 220 โอห์ม เพราะกระแสสูงสุดของแต่ละ segment คือ 20 mA
กระแสที่ได้คือ (5-1.8)/220 = 14.5 mA เพราะพี่ไม่แน่ใจว่ากระแสจะเท่าไหร่จริง เลยใส่ทรานซิสเตอร์ขับ (UDN2981) สองตัวที่ขา CA (Common Anode) ของแต่ละ display กระแสสูงสุดที่ shift register จ่ายได้คือ 35 mA ทฤษฎีคือถ้า segment ทั้งหมดติดพร้อมกัน กระแสควรจะเป็น 8*14.5 = 116 mA
เยอะเกินไปสำหรับ shift register มาก แต่ในความเป็นจริงมันจะน้อยกว่านี้ เพราะเราใช้ multiplexing อยู่


บอร์ด2 - CN1 ต่อกับ CN1 ของบอร์ดแสดงผล ขาซ้ายของคอนเนคเตอร์คือ display บนตัวแรก ขาที่สองคือ display ตัวที่สอง ไปเรื่อยๆ
บอร์ด2 - CN2 ต่อกับ CN2 ของบอร์ดแสดงผล ขาซ้ายของคอนเนคเตอร์คือ display ล่างตัวแรก ขาที่สองคือ display ตัวที่สอง ไปเรื่อยๆ
บอร์ด2 - CN3 ต่อกับ CN3 ของบอร์ดแสดงผล ขาซ้ายของคอนเนคเตอร์คือ segment a, ขาที่สองคือ segment b ไล่ไปจนถึง segment e
บอร์ด2 - CN4 ต่อกับ CN4 ของบอร์ดแสดงผล ขาซ้ายของคอนเนคเตอร์คือ segment f, ขาที่สองคือ segment g, ขาขวาสุดคือจุดทศนิยม
โปรแกรม จะตรวจสอบสถานะของสวิตช์ทั้งสี่ตัว (ใน void loop)
ใน loop เวลาจะถูกอัปเดตทุกวินาที และทุกๆ 3 วินาทีจะอ่านค่าจากเซ็นเซอร์วัดความกดอากาศ
วิดีโอต่อไปจะแสดงการเริ่มต้นทำงานของนาฬิกา และแสดงเวลาและวันที่
ด้วยสวิตช์ 4 ตัว เราจะได้ฟังก์ชันทั้งหมด 16 แบบ
16 ฟังก์ชันมีดังนี้
Switch position 0000
จอด้านบน: เวลา
จอด้านล่าง: วันที่ (วัน, เดือน, ปี)

Switch position 0001
จอด้านบน: dn = (จำนวนวันที่ผ่านมาตั้งแต่วันที่ 1 มกราคม)
จอด้านล่าง: n = อายุของดวงจันทร์ (เป็นวัน)

Switch position 0010
จอด้านบน: จำนวนวินาทีที่ผ่านมาตั้งแต่เที่ยงคืน (สูงสุด = 86400)
จอด้านล่าง: จำนวนนาทีที่ผ่านมาตั้งแต่วันที่ 1 มกราคม

Switch position 0011
จอด้านบน: p = เวลาพระอาทิตย์ขึ้น (ขึ้นอยู่กับละติจูดและลองจิจูดของพื้นที่)
จอด้านล่าง: n = เวลาพระอาทิตย์ตก

Switch position 0100
จอด้านบน: H = ความสูงสูงสุดของดวงอาทิตย์ตอนเที่ยง (หน่วยเป็นองศา)
จอด้านล่าง: n = ความสูงจริงของดวงอาทิตย์ในขณะนั้น (จะเป็นศูนย์ที่เวลาขึ้นหรือตก)

Switch position 0101
จอด้านบน: มุมเอียงของโลก (หน่วยเป็นองศา) (ศูนย์ที่เริ่มฤดูใบไม้ผลิและใบไม้ร่วง, +23.5 ที่เริ่มฤดูร้อน, -23.5 ที่เริ่มฤดูหนาว)
จอด้านล่าง: dL = ระยะเวลาระหว่างพระอาทิตย์ขึ้นถึงตก = กลางวัน

Switch position 0110
จอด้านบน: L = ความกดอากาศ (หน่วย mBar)
จอด้านล่าง: t = อุณหภูมิ (หน่วยเซลเซียส)

Switch position 0111
จอด้านบน: AdjUst (โหมดตั้งค่า)
จอด้านล่าง: ว่าง
ในโหมดนี้เราสามารถตั้งค่าเวลา, วันที่, ค่า aging register ของ RTC รวมถึงตั้งค่าละติจูดและลองจิจูดได้เลย อย่าลืมเซฟให้เรียบร้อยนะ

Switch position 1000
จอด้านบน: เวลา (แบบปกติ)
จอด้านล่าง: เวลาในรูปแบบเลขฐานสอง (ยกเว้นเลข 8 กับ 9)

Switch position 1001
จอด้านบน: dow 6, หมายเลขวันในสัปดาห์ (1 = วันอาทิตย์, 2 = วันจันทร์, ไปเรื่อยๆ)
จอด้านล่าง: unr 45, หมายเลขสัปดาห์ของปี

Switch position 1010
จอด้านบน : u = มุมอะซิมัทของโลก (หน่วยเป็นองศา)
จอด้านล่าง : n = มุมอะซิมัทของดวงจันทร์ (หน่วยเป็นองศา)
ตำแหน่งบนขอบฟ้า: 0 = ทิศเหนือ, 90 = ทิศตะวันออก, 180 = ทิศใต้, 270 = ทิศตะวันตก

Switch position 1011
จอด้านบน : t = สมการของเวลา (Equation of time)
จอด้านล่าง : H = มุมระหว่างโลกกับดวงจันทร์
มุม: 0 = ดวงจันทร์ดับ, 90 = ขึ้น 1 ค่ำ, 180 = ดวงจันทร์เต็มดวง, 270 = แรม 1 ค่ำ

Switch position 1100
จอด้านบน: u = ตำแหน่งดวงอาทิตย์ขึ้นบนขอบฟ้า (90 = ทิศตะวันออก, เริ่มฤดูใบไม้ผลิหรือใบไม้ร่วง)
จอด้านล่าง: n = ตำแหน่งดวงอาทิตย์ตกบนขอบฟ้า (270 = ทิศตะวันตก, เริ่มฤดูใบไม้ผลิหรือใบไม้ร่วง)

Switch position 1101
จอด้านบน: b = ละติจูด (Latitude)
จอด้านล่าง: L = ลองจิจูด (Longitude)

Switch position 1110
จอด้านบน: u = เวลาที่ดวงอาทิตย์อยู่ทางทิศใต้
จอด้านล่าง: เปอร์เซ็นต์ความสว่างของดวงจันทร์

Switch position 1111
โหมดกลางคืน: ถ้าเวลาอยู่ระหว่าง 00:00 - 08:00 น. จอจะว่างเปล่า นอกเหนือจากนั้น: จะแสดง:
- จอด้านบน: เวลา
- จอด้านล่าง: วันที่ (วัน, เดือน, ปี)

โปรเจคจัดเต็ม! ติดตามดวงอาทิตย์แบบแม่นยำขั้นสุด
โปรเจคนี้มันไม่ใช่แค่นาฬิกาธรรมดาๆ นะน้อง มันคำนวณตำแหน่งดวงอาทิตย์และวัตถุท้องฟ้าจากวันที่และตำแหน่งปัจจุบันเลย
- หัวใจหลักคือการคำนวณ Ephemeris: Arduino ใช้เวลาที่แม่นยำจาก DS3231 RTC ร่วมกับค่าละติจูด/ลองจิจูดที่เราตั้งไว้ เพื่อคำนวณเวลาดวงอาทิตย์ขึ้น-ตกในพื้นที่นั้นๆ
- ติดตามดวงอาทิตย์อัตโนมัติ (เวอร์ชันขั้นสูง): ส่งผลลัพธ์การคำนวณเป็นสัญญาณ PWM ไปควบคุมฐานติดตามแสงอาทิตย์ (solar tracker) ให้แผงโซลาร์เซลล์หันไปทางที่รับแสงได้ดีที่สุดตลอดเวลา งานนี้จัดไปวัยรุ่น!
ความแม่นยำเรื่องเวลา
- ชดเชยอุณหภูมิอัตโนมัติ: DS3231 มี TCXO (Temperature Compensated Crystal Oscillator) ในตัว ทำให้ความแม่นยำของนาฬิกาอยู่ที่ ±2 นาทีต่อปี แม้จะติดตั้งกลางแจ้งที่อุณหภูมิสุดขั้วก็ตาม งานนี้ห้ามช็อตนะตัวนี้
อธิบายโค้ดแบบรุ่นพี่
เวลา
ดูโค้ดตรงนี้เลย: void Tijd()
//---------------------------------------------------------------------------------
void Tijd() { // แสดงเวลาบน display1 และวันที่บน display2
int test;
test = a % 2;
if (test == 0) {
display1( Data1[f], Data1[e] - 1, Data1[d], Data1[c], Data1[b], Data1[a]);
} else {
display1( Data1[f], Data1[e], Data1[d], Data1[c] - 1, Data1[b], Data1[a]);
}
display2( Data1[h], Data1[g] - 1, Data1[j], Data1[i] - 1, Data1[m], Data1[k]);
// เมื่อใส่ '' - 1'' หลัง "]" จุดบนจอแสดงผลจะติด เช่นในบรรทัด display2(.....) จุดบนจอที่ 2 และ 4 จะติด
}
//---------------------------------------------------------------------------------
ตัวแปรแรก Data1[f] คือข้อมูลสำหรับจอแสดงผลซ้ายบนตัวแรก
e และ f คือตัวแปรสำหรับชั่วโมง ถ้าชั่วโมงเป็น 15
แล้ว f=1 โปรแกรมจะไปค้นหาในอาร์เรย์ Data1[f] และพบว่าที่ตำแหน่งที่สอง (ตำแหน่งแรกคือศูนย์นะ นับจากศูนย์) มีค่า 243 นี่คือข้อมูลที่จะส่งไปยัง shift register ค่า 243 คือเลข 1 สำหรับจอแสดงผลตัวแรก ข้อมูลนี้อยู่แค่ชั่ววูบเดียว จากนั้นโปรแกรมจะอ่าน Data1[e] ต่อไป และพบว่าที่ตำแหน่งที่ 6 มีค่า 37 นี่คือข้อมูลที่จะส่งไปยัง shift register ต่อ ค่า 37 คือเลข 5 สำหรับจอแสดงผลตัวที่สอง ไปเรื่อยๆ...
ดังนั้น ในบรรทัด display1(x,x,x,x,x,x); มีตัวแปร 6 ตัวสำหรับจอบน ตัวแรกคือจอซ้ายบนสุด ตัวที่สองคือจอถัดไป ฯลฯ
ในบรรทัด display2(x,x,x,x,x,x); มีตัวแปร 6 ตัวสำหรับจอล่าง ตัวแรกคือจอซ้ายล่างสุด ตัวที่สองคือจอถัดไป ฯลฯ
ถ้าเห็นเป็นแค่ตัวเลขธรรมดา นั่นคือตัวเลขที่เราตั้งค่าเอง แต่ถ้าเห็นเลขพิเศษ เช่น:
67บนจอจะแสดงเป็นd25บนจอจะแสดงเป็นP143บนจอจะแสดงเป็นL195บนจอจะแสดงเป็นj15บนจอจะแสดงเป็นt199บนจอจะแสดงเป็นu
เข้าใจไหมน้อง? สู้งานนะน้อง!
95 คือ r, 18 คือ H, งั้นก็ทำตัวหนังสือได้เหมือนกันนะน้อง