⏰ ماژول ساعت DS3231 با آردوینو: ساعت و تاریخی که با قطع برق هم گم نمی‌شود

✍️ تیم ووکوی فارسی ·

آردوینو خودش ساعت ندارد. می‌تواند بشمارد از وقتی روشن شده چند میلی‌ثانیه گذشته، ولی نمی‌داند امروز چندم است و ساعت چند. با قطع برق هم همه‌چیز صفر می‌شود. ماژول ساعت DS3231 این مشکل را حل می‌کند: یک ساعت دقیق کوچک با باتری سکه‌ای که حتی وقتی آردوینو خاموش است، جلو می‌رود. در این آموزش DS3231 با آردوینو را با کتابخانه‌ی RTClib راه می‌اندازیم، تاریخ و ساعت و دما را می‌خوانیم و یک ساعت زنگ‌دار می‌سازیم.

RTC چیست و DS3231 چرا دقیق است؟

RTC یعنی Real-Time Clock، «ساعت زمان واقعی». داخل DS3231 یک کریستال کوارتز هست که مثل آونگ ساعت‌های قدیمی با فرکانس ثابت می‌لرزد و تراشه این لرزش‌ها را می‌شمارد. کریستال‌ها با گرما و سرما کمی تند و کند می‌شوند؛ DS3231 یک دماسنج داخلی دارد و این خطا را خودش جبران می‌کند. نتیجه دقتی حدود یک دقیقه در سال است، خیلی بهتر از DS1307 قدیمی. یک باتری سکه‌ای CR2032 هم پشت ماژول است که سال‌ها ساعت را زنده نگه می‌دارد.

ارتباط با آردوینو از راه I2C است: فقط دو سیم SDA و SCL، و آدرس ماژول 0x68. یعنی می‌توانی LCD I2C را هم روی همان دو سیم بگذاری. اگر می‌خواهی بدانی چرا نمی‌شود فقط با millis ساعت ساخت، جواب در همان پاراگراف اول است: millis حافظه ندارد.

پایه‌های ماژول

پایهکار
VCCتغذیه‌ی ۳٫۳ تا ۵ ولت
GNDزمین
SDAداده‌ی I2C
SCLساعت I2C
SQWخروجی موج مربعی یا وقفه‌ی آلارم (فعلاً لازم نیست)
32Kخروجی ۳۲ کیلوهرتز (فعلاً لازم نیست)

قطعه‌ها و سیم‌کشی

پایه‌ی DS3231آردوینو Uno
VCC5V
GNDGND
SDAA4
SCLA5

در آردوینو Uno، پایه‌های I2C ثابت‌اند: A4 داده و A5 ساعت. روی بردهای جدیدتر Uno دو پایه‌ی SDA و SCL کنار AREF هم هست که در واقع همان A4 و A5 است.

کد کامل

کتابخانه‌ی RTClib (از Adafruit) را از Library Manager نصب کن. این برنامه هر ثانیه روز هفته، تاریخ، ساعت و دمای داخل ماژول را در سریال مانیتور (۹۶۰۰) چاپ می‌کند.

// DS3231 real-time clock: weekday, date, time and temperature.
#include <Wire.h>
#include <RTClib.h>

RTC_DS3231 rtc;
const char* DAYS[7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
int lastSecond = -1;

void print2(int n) {              // 7 -> "07"
  if (n < 10) Serial.print("0");
  Serial.print(n);
}

void setup() {
  Serial.begin(9600);
  if (!rtc.begin()) {
    Serial.println("RTC not found! Check SDA/SCL.");
    while (true) delay(1000);
  }
  if (rtc.lostPower()) {
    // First run or empty battery: copy the computer's time at compile time.
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    Serial.println("Time was set.");
  }
}

void loop() {
  DateTime now = rtc.now();
  if (now.second() == lastSecond) return;   // print once per second
  lastSecond = now.second();

  Serial.print(DAYS[now.dayOfTheWeek()]);
  Serial.print("  ");
  Serial.print(now.year()); Serial.print("/");
  print2(now.month()); Serial.print("/");
  print2(now.day()); Serial.print("  ");
  print2(now.hour()); Serial.print(":");
  print2(now.minute()); Serial.print(":");
  print2(now.second());
  Serial.print("  temp: ");
  Serial.print(rtc.getTemperature());
  Serial.println(" C");
}

توضیح بخش‌های مهم

💡 RTC هیچ چیزی درباره‌ی منطقه‌ی زمانی نمی‌داند؛ هر ساعتی به آن بدهی همان را جلو می‌برد. پس آن را با ساعت ایران تنظیم کن. ایران از ۱۴۰۱ ساعت تابستانی ندارد، پس لازم نیست سالی دو بار جابه‌جایش کنی.

پروژه‌ی کوچک: ساعت زنگ‌دار

هر روز ساعت ۷:۳۰ بازر روی D8 بوق‌بوق می‌کند و LED روی برد چشمک می‌زند تا دکمه‌ی روی D2 را بزنی. برای تست، ساعت زنگ را یک دقیقه بعد از الان بگذار.

// Daily alarm: buzzer + LED at ALARM_HOUR:ALARM_MINUTE, button stops it.
#include <Wire.h>
#include <RTClib.h>

RTC_DS3231 rtc;
const int BUZZER = 8;
const int LED = 13;
const int BUTTON = 2;
const int ALARM_HOUR = 7;
const int ALARM_MINUTE = 30;

bool ringing = false;
int lastDayRung = -1;            // ring only once per day

void setup() {
  pinMode(BUZZER, OUTPUT);
  pinMode(LED, OUTPUT);
  pinMode(BUTTON, INPUT_PULLUP);
  Serial.begin(9600);
  if (!rtc.begin()) {
    Serial.println("RTC not found!");
    while (true) delay(1000);
  }
  if (rtc.lostPower()) rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}

void loop() {
  DateTime now = rtc.now();
  if (!ringing && now.hour() == ALARM_HOUR && now.minute() == ALARM_MINUTE
      && now.day() != lastDayRung) {
    ringing = true;
    lastDayRung = now.day();
    Serial.println("Wake up!");
  }

  if (ringing) {
    bool beat = (millis() / 250) % 2 == 0;   // beep-beep pattern
    digitalWrite(LED, beat ? HIGH : LOW);
    if (beat) tone(BUZZER, 1000);
    else noTone(BUZZER);

    if (digitalRead(BUTTON) == LOW) {        // the button stops the alarm
      ringing = false;
      noTone(BUZZER);
      digitalWrite(LED, LOW);
      Serial.println("Alarm off");
    }
  }
}

متغیر lastDayRung نمی‌گذارد بعد از خاموش کردن، در همان دقیقه دوباره زنگ بزند. اگر می‌خواهی ساعت روی نمایشگر هم دیده شود، کد را با سون‌سگمنت TM1637 یا LCD I2C ترکیب کن؛ LCD I2C و DS3231 هر دو روی همان A4 و A5 می‌نشینند.

اجرا در شبیه‌ساز

در تینکرکد فارسی هر دو مدار آماده‌اند: ساعت واقعی DS3231 و ساعت زنگ‌دار. اگر درس‌محور جلو می‌روی، درس ساعت واقعی با RTC و بعد درس ساعت زنگ‌دار را ببین. باز کردن و خواندن رایگان است؛ ماژول RTC جزو ماژول‌های حرفه‌ای است و اجرایش اشتراک Plus می‌خواهد. در شبیه‌ساز، lostPower() بار اول true است، درست مثل ماژولی که تازه باتری گرفته.

اشکال‌های رایج

برای دیدن مقدارها به شکل نمودار، سریال مانیتور و پلاتر را بخوان. همه‌ی کتابخانه‌های پشتیبانی‌شده در صفحه‌ی کتابخانه‌ها و بقیه‌ی پروژه‌ها در صفحه‌ی آردوینو هستند.

ساعت واقعی DS3231 را باز کن ⏰

سؤال‌های رایج

چرا با millis ساعت نسازم؟

millis با قطع برق صفر می‌شود و در طول روز چند ثانیه خطا جمع می‌کند. DS3231 باتری دارد، با خاموش شدن آردوینو هم جلو می‌رود و دقتش حدود یک دقیقه در سال است.

ساعت را فقط یک بار تنظیم کنم یا هر بار؟

فقط یک بار. در کد، adjust را داخل شرط lostPower بگذار تا فقط وقتی باتری خالی یا تازه گذاشته شده، ساعت دوباره تنظیم شود.

ماژول RTC در شبیه‌ساز کار می‌کند؟

بله، با همان کتابخانه‌ی RTClib. خواندن مثال‌ها و درس‌ها رایگان است؛ اجرای ماژول RTC جزو ماژول‌های حرفه‌ای است و اشتراک Plus می‌خواهد.

مقاله‌های مرتبط

⚙️

استپر موتور 28BYJ-48 با درایور ULN2003 و آردوینو: چرخش دقیق به درجه

🔌

ماژول رله با آردوینو: روشن و خاموش کردن یک مدار جدا، با نکات ایمنی

📡

کنترل آردوینو با ریموت کنترل مادون قرمز (IRremote نسخه‌ی جدید)

🐞

دیباگ قدم‌به‌قدم کد آردوینو در شبیه‌ساز آنلاین: بریک‌پوینت و دیدن متغیرها

همه‌ی آموزش‌های سنسورها و ماژول‌ها ← · همه‌ی مقاله‌ها