
آموزش راهاندازی DS1307 با آردوینو
چه در حال ساخت یک ساعت دیجیتال باشید، چه در حال ثبت دادههای حسگر همراه با زمان، یا اینکه بخواهید یک فرایند را بر اساس زمان روز خودکار کنید، همیشه به یک روش مطمئن برای نگهداری و پیگیری زمان نیاز دارید. اینجاست که ماژول ساعت واقعی DS1307 وارد میشود. DS1307 به خاطر قابلاعتماد بودن و قیمت مناسبش شناخته میشود و وقتی پروژه شما نباید حتی یک ثانیه از زمان را از دست بدهد، یکی از بهترین انتخابهاست.
در این آموزش، تمامی موارد لازم برای شروع کار با ماژول DS1307 را مرحلهبهمرحله توضیح میدهیم. متوجه میشوید این ماژول چگونه کار میکند، چطور آن را به آردوینو متصل کنید، و چگونه تاریخ و زمان را تنظیم و خوانده کنید. همچنین با نحوه استفاده از حافظه EEPROM داخلی برای ذخیرهسازی دادههای اضافه آشنا میشوید.
بیایید شروع کنیم و به آردوینوی شما توانایی نگهداری دقیق زمان را اضافه کنیم!
بررسی سختافزار
تراشهی RTC DS1307
در قلب این ماژول، تراشهی DS1307 قرار دارد—یک ساعت واقعی (RTC) مبتنی بر I2C که دقت خوب و قیمت پایینی دارد و توسط Maxim Integrated تولید شده است.

DS1307 قادر است ثانیه، دقیقه، ساعت، روز هفته، تاریخ، ماه و سال را نگهداری کند. این تراشه تعداد روزهای هر ماه را تشخیص میدهد و حتی برای ماههای کمتر از ۳۱ روز بهصورت خودکار تنظیم میشود. همچنین سالهای کبیسه را هم پشتیبانی میکند—البته فقط تا سال ۲۱۰۰.
شما میتوانید زمان را در قالب ۱۲ ساعته (با AM/PM) یا ۲۴ ساعته تنظیم کنید.دیک پایهی مخصوص به نام SQW نیز روی این تراشه وجود دارد که خروجی موج مربعی با فرکانسهای 1Hz، 4kHz، 8kHz یا 32kHz تولید میکند—قابلیتی کاربردی برای پروژههایی که به سیگنال زمانی ثابت نیاز دارند.
DS1307 از یک کریستال خارجی 32kHz برای زمانسنجی استفاده میکند. این کریستال وظیفه دارد هر ثانیه را دقیقاً اندازه بگیرد. با این حال، یک نکته وجود دارد: فرکانس کریستال با تغییر دما کمی جابهجا میشود.
این تغییر بسیار کوچک است، اما با گذشت زمان باعث خطای تجمعی میشود—بهطور معمول حدود ۵ دقیقه در ماه.
این میزان خطا ممکن است زیاد به نظر برسد، اما برای بیشتر پروژههای ساده، مشکلی ایجاد نمیکند. DS1307 همچنان یک انتخاب رایج و مطمئن برای کاربردهایی است که دقت فوقالعاده بالا نیاز ندارند.
باتری پشتیبان
تراشه DS1307 دارای قابلیت پشتیبانی باتری است تا حتی زمانی که تغذیه اصلی قطع شود، ساعت همچنان به کار خود ادامه دهد.
در پشت ماژول، یک محفظه باتری قرار دارد که برای یک باتری لیتیومی سکهای ۳ ولتی با قطر ۲۰ میلیمتر طراحی شده است.

داخل تراشه، یک مدار هوشمند تشخیص توان قرار دارد که بهصورت دائمی بررسی میکند آیا منبع تغذیه اصلی وصل است یا نه. اگر این مدار تشخیص دهد که تغذیه اصلی قطع شده است، بهطور خودکار ماژول را به باتری پشتیبان سوئیچ میکند.
EEPROM داخلی 24C32 روی برد
علاوه بر تراشهی DS1307، این ماژول یک حافظه EEPROM مدل 24C32 نیز دارد. EEPROM مخفف Electrically Erasable Programmable Read-Only Memory است. این تراشه وظیفه نگهداری زمان را ندارد، اما برای ذخیرهکردن داده—مانند لاگها، مقادیر حسگرها یا تنظیماتی که باید بعد از قطع برق باقی بمانند—بسیار مناسب است.
حافظه EEPROM 24C32 روی ماژول میتواند تا ۳۲ کیلوبیت داده ذخیره کند. این تراشه برای حدود ۱٬۰۰۰٬۰۰۰ چرخهی نوشتن طراحی شده است، یعنی میتوانید تعداد بسیار زیادی بار داده داخل آن ذخیره کنید قبل از اینکه دچار استهلاک شود.

این تراشه EEPROM از همان پروتکل ارتباطی I2C استفاده میکند؛ درست مانند DS1307. این دو تراشه، باس I2C مشترک دارند.
رابط I2C
ماژول DS1307 برای ارتباط با میکروکنترلرهایی مثل آردوینو یا رزبریپای از پروتکل I2C استفاده میکند. زمانی که این ماژول را به پروژه متصل میکنید، از دو آدرس I2C متفاوت استفاده میشود:
- تراشهی RTC مدل DS1307 آدرس ثابت 0x68 دارد.
- تراشهی EEPROM آدرس ثابت 0x50 دارد.
اتصالهای I2C—یعنی پایههای SDA (داده) و SCL (کلاک)—بههمراه تغذیه (VCC) و زمین (GND) در هر دو طرف برد آورده شدهاند. این طراحی باعث میشود اتصال ماژول به پروژه ساده باشد، یا حتی بتوانید آن را در زنجیرهی I2C همراه با دستگاههای دیگر قرار دهید.

پینآوت ماژول DS1307 RTC ماژول DS1307 RTC در مجموع ۷ پین دارد. در ادامه میبینیم هر پین چه کاری انجام میدهد:

پینآوت ماژول DS1307 RTC ماژول DS1307 RTC در مجموع ۷ پین دارد. در ادامه میبینیم هر پین چه کاری انجام میدهد:
پینآوت ماژول DS1307 RTC SQW پین خروجی موج مربعی است. این پین میتواند طوری تنظیم شود که یک سیگنال موج مربعی با فرکانسهای انتخابی مختلف تولید کند، مثل 1Hz، 4kHz، 8kHz یا 32kHz. این سیگنال میتواند در پروژههایی که نیاز به یک پالس زمانی پایدار دارند مفید باشد.
DS یک پین اختیاری است. اگر یک سنسور دمای DS18B20 در محل سه سوراخ نصب در گوشه بالا-راست ماژول (با برچسب U1) نصب شود، این پین مقدار دما را ارائه میدهد.
SCL پین کلاک سریال برای ارتباط I2C است.
SDA پین داده سریال برای ارتباط I2C است.
VCC پین تغذیه است و باید به خروجی 5V آردوینو وصل شود.
GND پین زمین است.
BAT برای اتصال یک باتری پشتیبان ۳ ولت (معمولاً باتری سکهای CR2032) استفاده میشود. این باتری زمانی که تغذیه اصلی (VCC) قطع یا در دسترس نباشد، DS1307 را تغذیه میکند.
اتصال ماژول DS1307 RTC به آردوینو
بیایید ماژول DS1307 را به آردوینو وصل کنیم! فرآیند اتصال ساده است و فقط چند مرحله نیاز دارد. ابتدا، پین VCC روی ماژول را به خروجی 5V آردوینو وصل کنید و پین GND را به زمین آردوینو وصل کنید. در مرحله بعد، باید پینهایی را که برای ارتباط I2C استفاده میشوند وصل کنیم. مهم است بدانید که بردهای مختلف آردوینو پینهای متفاوتی برای I2C دارند و باید درست متصل شوند. روی بردهای آردوینو با طرح R3، پینهای SDA و SCL همچنین روی هدرهایی نزدیک پین AREF وجود دارند، اما در اصل همان پینهای A4 (SDA) و A5 (SCL) هستند.
در ادامه یک جدول مرجع سریع برای اتصالات مشاهده میکنید:

لطفاً به تصویر زیر مراجعه کنید تا سیمکشی صحیح را مشاهده کنید.

نصب کتابخانه برای استفاده از ماژول DS1307
در پروژه، از یک کتابخانه مخصوص به نام uRTCLib استفاده میکنیم. این کتابخانه خواندن دادههای زمانی از RTC را بسیار ساده میکند.
با وجود اینکه uRTCLib ساده است، بسیار قدرتمند نیز هست. برخلاف بسیاری از کتابخانههای RTC دیگر، از آلارمهای زمان روز پشتیبانی میکند و اجازه میدهد خروجی موج مربعی (SQW) را کنترل کنید.
برای نصب کتابخانه:
- ابتدا برنامه Arduino IDE را باز کنید. سپس روی آیکون Library Manager در نوار کناری سمت چپ کلیک کنید.
- عبارت “urtclib” را در کادر جستجو وارد کنید.
- کتابخانه uRTCLib نوشته Naguissa را پیدا کنید.
- روی دکمه Install کلیک کنید تا به IDE اضافه شود.

در ادامه آموزش، نحوه خواندن و نوشتن روی چیپ EEPROM داخلی 24C32 را نیز توضیح میدهیم. اگر قصد دارید آن بخش را نیز امتحان کنید، باید کتابخانه uEEPROMLib را نصب کنید.

برای نصب آن هم: مانند قبل در Library Manager عبارت “uEEPROMLib” را جستجو کرده و Install را بزنید.
کد آردوینو – خواندن تاریخ و زمان
در این مثال، از یک اسکچ ساده آردوینو برای تنظیم و خواندن تاریخ، زمان و دما از ماژول DS1307 RTC استفاده میکنیم.
(کد دقیق، بدون تغییر:)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
#include "Arduino.h" #include "uRTCLib.h" // uRTCLib rtc; uRTCLib rtc(0x68); char daysOfTheWeek[7][12] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; void setup() { Serial.begin(9600); URTCLIB_WIRE.begin(); // Comment out below line once you set the date & time. // Following line sets the RTC with an explicit date & time // for example to set April 14 2025 at 12:56 you would call: rtc.set(0, 56, 12, 2, 14, 4, 25); // rtc.set(second, minute, hour, dayOfWeek, dayOfMonth, month, year) // set day of week (1=Sunday, 7=Saturday) } void loop() { rtc.refresh(); Serial.print("Current Date & Time: "); Serial.print(rtc.year()); Serial.print('/'); Serial.print(rtc.month()); Serial.print('/'); Serial.print(rtc.day()); Serial.print(" ("); Serial.print(daysOfTheWeek[rtc.dayOfWeek() - 1]); Serial.print(") "); Serial.print(rtc.hour()); Serial.print(':'); Serial.print(rtc.minute()); Serial.print(':'); Serial.println(rtc.second()); delay(1000); } |
وقتی کد را روی آردوینو آپلود کنید، سریال مانیتور را باز کرده و نرخ باد را روی 9600 تنظیم کنید. تاریخ و زمان جاری را مشاهده خواهید کرد.

توضیح کد:
(تمام متن انگلیسی خطبهخط ترجمه شده است:) در آغاز با include کردن دو کتابخانه Arduino.h و uRTCLib.h شروع میکنیم. این کتابخانهها به آردوینو کمک میکنند با چیپ DS1307 ارتباط برقرار کند.
در مرحله بعد، یک شیء RTC با استفاده از کتابخانه uRTCLib میسازیم و یک آرایه با نام daysOfTheWeek تعریف میکنیم که نام روزهای هفته از Sunday تا Saturday را نگه میدارد.
در تابع setup، سریال مانیتور را باز میکنیم تا بتوانیم تاریخ، زمان و مقادیر دما را مشاهده کنیم. سپس با URTCLIB_WIRE.begin ارتباط I2C را فعال میکنیم.
سپس تاریخ و زمان را بهصورت دستی با rtc.set تنظیم میکنیم. فقط یک بار لازم است این خط را اجرا کنید. بعد از تنظیم درست، باید آن را کامنت کنید تا هر بار کد آپلود میشود زمان دوباره ریست نشود.
در تابع loop، تابع rtc.refresh زمان فعلی را از RTC بهروزرسانی میکند و سپس تاریخ، ماه، روز و نام روز هفته چاپ میشود. سپس ساعت، دقیقه و ثانیه چاپ میشود. در آخر، یک تأخیر یکثانیهای قرار داده میشود تا خروجی هر ثانیه یک بار آپدیت شود.
کد آردوینو – خواندن و نوشتن روی EEPROM 24C32
در ادامه نمونهکد کامل بدون تغییر آمده است:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
#include "Arduino.h" #include "Wire.h" #include "uEEPROMLib.h" // uEEPROMLib eeprom; uEEPROMLib eeprom(0x50); void setup() { Serial.begin(9600); Wire.begin(); int inttmp = 32123; float floattmp = 3.1416; char chartmp = 'A'; char c_string[] = "lastminuteengineers.com"; // 23 Characters int string_length = strlen(c_string); Serial.println("Writing into memory..."); // Write an int if (!eeprom.eeprom_write(0, inttmp)) { Serial.println("Failed to store int."); } else { Serial.println("int was stored correctly."); } // write a float if (!eeprom.eeprom_write(4, floattmp)) { Serial.println("Failed to store float."); } else { Serial.println("float was stored correctly."); } // Write single char at address if (!eeprom.eeprom_write(8, chartmp)) { Serial.println("Failed to store char."); } else { Serial.println("char was stored correctly."); } // Write a long string of chars FROM position 33 which isn't aligned to the 32 byte pages of the EEPROM if (!eeprom.eeprom_write(33, (byte *)c_string, strlen(c_string))) { Serial.println("Failed to store string."); } else { Serial.println("string was stored correctly."); } Serial.println(""); Serial.println("Reading memory..."); Serial.print("int: "); eeprom.eeprom_read(0, &inttmp); Serial.println(inttmp); Serial.print("float: "); eeprom.eeprom_read(4, &floattmp); Serial.println((float)floattmp); Serial.print("char: "); eeprom.eeprom_read(8, &chartmp); Serial.println(chartmp); Serial.print("string: "); eeprom.eeprom_read(33, (byte *)c_string, string_length); Serial.println(c_string); Serial.println(); } void loop() { } |
سریال مانیتور خروجی مقادیر ذخیرهشده را نمایش میدهد و ثابت میکند که EEPROM دادهها را بهدرستی نگه داشته است.

توضیح کد: ما با اضافه کردن کتابخانههای Arduino.h، Wire.h و uEEPROMLib.h شروع میکنیم. این کتابخانهها به آردوینو اجازه میدهند تا از طریق I2C با ایئیپروم ارتباط برقرار کند.
سپس یک شیء EEPROM با آدرس پیشفرض I2C برابر 0x50 ایجاد میکنیم.
در داخل تابع setup()، مانیتور سریال را راهاندازی میکنیم تا نتایج را مشاهده کنیم و با استفاده از Wire.begin() اتصال I2C را شروع میکنیم.
سپس چهار متغیر تعریف میکنیم: یکی برای عدد صحیح، یکی برای عدد اعشاری، یکی برای یک کاراکتر و یکی رشتهای به سبک C (که فقط یک آرایه از کاراکترها است). همچنین طول رشته را محاسبه میکنیم تا بدانیم چند کاراکتر ذخیره میکنیم.
|
1 2 3 4 5 6 |
int inttmp = 32123; float floattmp = 3.1416; char chartmp = 'A'; char c_string[] = "lastminuteengineers.com"; // 23 کاراکتر int string_length = strlen(c_string); |
برای نوشتن داده در ایئیپروم، از تابع eeprom_write() استفاده میکنیم. به آن آدرس حافظه و مقداری که میخواهیم ذخیره کنیم میدهیم. هر بار که مینویسیم، بررسی میکنیم که عملیات موفق بوده یا نه و پیام تأیید چاپ میکنیم.
عدد صحیح را در آدرس 0، عدد اعشاری را در آدرس 4، کاراکتر را در آدرس 8 و رشته را از آدرس 33 ذخیره میکنیم. دلیل شروع رشته از آدرس بالاتر جلوگیری از همپوشانی با دادههای موجود در حافظه پایینتر است.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
// نوشتن عدد صحیح if (!eeprom.eeprom_write(0, inttmp)) { Serial.println("ذخیره عدد صحیح ناموفق بود."); } else { Serial.println("عدد صحیح با موفقیت ذخیره شد."); } // نوشتن عدد اعشاری if (!eeprom.eeprom_write(4, floattmp)) { Serial.println("ذخیره عدد اعشاری ناموفق بود."); } else { Serial.println("عدد اعشاری با موفقیت ذخیره شد."); } // نوشتن یک کاراکتر در آدرس if (!eeprom.eeprom_write(8, chartmp)) { Serial.println("ذخیره کاراکتر ناموفق بود."); } else { Serial.println("کاراکتر با موفقیت ذخیره شد."); } // نوشتن رشته از موقعیت 33 که با صفحات 32 بایتی EEPROM همتراز نیست if (!eeprom.eeprom_write(33, (byte *)c_string, strlen(c_string))) { Serial.println("ذخیره رشته ناموفق بود."); } else { Serial.println("رشته با موفقیت ذخیره شد."); } |
پس از نوشتن، دادهها را با استفاده از تابع eeprom_read() میخوانیم و مقادیر را یکییکی چاپ میکنیم تا مطمئن شویم همه چیز درست ذخیره شده است.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
Serial.print("عدد صحیح: "); eeprom.eeprom_read(0, &inttmp); Serial.println(inttmp); Serial.print("عدد اعشاری: "); eeprom.eeprom_read(4, &floattmp); Serial.println((float)floattmp); Serial.print("کاراکتر: "); eeprom.eeprom_read(8, &chartmp); Serial.println(chartmp); Serial.print("رشته: "); eeprom.eeprom_read(33, (byte *)c_string, string_length); Serial.println(c_string); |
نکته: هنگام نوشتن در eprom ، مهم است که بدانید انواع مختلف داده چه میزان فضا اشغال میکنند.
به این معنی است که باید مراقب باشید هر نوع داده را در کجا ذخیره میکنید. برای مثال، اگر یک عدد صحیح را در آدرس 0 ذخیره کنید، نباید چیزی در آدرس 1 ذخیره کنید چون عدد صحیح از دو بایت استفاده میکند. در عوض، مقدار بعدی را در آدرس 2 یا بالاتر ذخیره میکنید. برای ذخیره چند عدد صحیح، میتوانید از آدرسهای حافظه مانند 0، 2، 4، 6 و … استفاده کنید.
این روش به جلوگیری از همپوشانی دادهها یا خراب شدن آنها کمک میکند.



