กลับไปหน้ารวมไฟล์
astronomical-clock-with-rtc-ds3231-e63235.md

หลายปีก่อนพี่สั่ง 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 บนจอจะแสดงเป็น d
  • 25 บนจอจะแสดงเป็น P
  • 143 บนจอจะแสดงเป็น L
  • 195 บนจอจะแสดงเป็น j
  • 15 บนจอจะแสดงเป็น t
  • 199 บนจอจะแสดงเป็น u

เข้าใจไหมน้อง? สู้งานนะน้อง!

95 คือ r, 18 คือ H, งั้นก็ทำตัวหนังสือได้เหมือนกันนะน้อง

ข้อมูล Frontmatter ดั้งเดิม

apps:
  - "1x Arduino IDE"
author: "nankie"
category: "Screens & Displays"
components:
  - "1x Grove - Barometer Sensor (BMP280)"
  - "4x Toggle Switch, Toggle"
  - "1x Rotary Encoder with Push-Button"
  - "3x Shift Register- Parallel to Serial"
  - "1x DS3231MPMB1 Peripheral Module"
  - "8x Resistor 220 ohm"
  - "1x Arduino UNO"
  - "2x Transistor driver UDN2981"
  - "1x Soldering iron (generic)"
description: "นาฬิกาเทพๆ ที่ทำได้ตั้ง 16 ฟังก์ชัน แต่งานง่ายแต่หล่อ เพราะใช้แค่ Shift Register สามตัวเท่านั้น!"
difficulty: "Intermediate"
documentationLinks: []
downloadableFiles:
  - "https://projects.arduinocontent.cc/6e5b2dfc-ee06-4715-bd95-6a55e2ae6436.ino"
encryptedPayload: "U2FsdGVkX18cIWYCKPoHFx5o8HEmGLOpwG2qyQ13h16PkYI37ILe0GMFhG0pcnVeouVMMytpwdExzMNtoIxoWfC9qaDHTP5XRR/jemGOa1s="
heroImage: "https://cdn.jsdelivr.net/gh/bigboxthailand/arduino-assets@main/images/projects/astronomical-clock-with-rtc-ds3231-e63235_cover.jpg"
lang: "en"
likes: 0
passwordHash: "66d522dfb35d54f860836cbf382d7d79a3329df45b9b1569a6f59c21ef037fcd"
price: 2450
seoDescription: "Build an Astronomical Clock with RTC ds3231. Features 16 functions using only 3 shift registers. Precise Arduino timekeeping project."
tags:
  - "astronomical"
  - "clocks"
  - "sun rise"
title: "นาฬิกาดาราศาสตร์สุดตึง! ควบคุมด้วย RTC ds3231"
tools: []
videoLinks:
  - "https://www.youtube.com/embed/g9Y7L_Na1V8"
views: 2341