در این پست قصد دارم تا روش استفاده از DS1307 را در آردوینو، آموزش دهم. در مرحلهی اول ببینیم این ماژول DS1307 چی هست؟ و به چه کاری میآید؟
معرفی DS1307 :
DS1307 یک ماژول ساعت است که از آی سی ای به همین نام استفاده می کند. کارش حساب کردن دقیق زمان می باشد. در این ماژول یک باطری پشتیبانی هم کار گذاشته شده تا مواقعی که منبع تغذیه قطع میشود، زمان از دست نرود. ارتباط با این ماژول از طریق پروتکل I2C امکان پذیر است. برای مطالعهی I2C به این مطلب مراجعه کنید. در پروژه هایی که ما با زمان کار داریم. و دانستن زمان دقیق برای ما اهمیت دارد، میتوانیم از این ماژول استفاده کنیم. از مزایای دیگر این ماژول این است که بار محاسبه زمان را از روی دوش میکروکنترلر ما بر می دارد. و هر وقت که به دانستن زمان احتیاج داشتیم به این ماژول فرمانی میفرستیم. و این ماژول جواب مارا با اعلام دقیق زمان میدهد.
ارتباط با این ماژول به صورتBCD (Binary Decimal Coded) میباشد. در جلوتر کاملا با این BCD آشنا میشویم. خب فکر کنم تا اینجا با این ماژول آشنا شدیم. برای اطلاعات بیشتر به دیتاشیت این ماژول مراجعه کنید.
اتصال DS1307 به آردوینو :
اتصال DS1307 کار راحتی است و پیچیدگی خاصی نداره. دوتا پین برای تغذیه دارد که به گراند و 5 ولت وصل میکنیم. و دوتا پین هم برای اتصال به SCL و SDL آردوینو دارد. که همین دو پین آردوینو متصل میکنیم. البته اگر از ارتباط I2C نرم افزاری استفاده میکنیم باید به دو پینی که در نظر داریم متصل کنیم.
نکته اینکه در هنگام اتصال به ESP8266 به این ماژول 3.3 ولت وصل کردم و باز هم کار کرد. و لازم نیست دو ولتاژ مختلف داشته باشید.
بررسی دیتاشیت DS1307 :
برای DS1307 کتابخانه هایی هم موجود است ولی من خودم از کتابخانه استفاده نمی کنم. و قرار هم هست که در اینجا ارتباط ارتباط بدون کتابخانه را توضیح بدهم. از این طریق بیشتر هم با این ماژول و ارتباط I2C آشنا می شویم.
برای شروع به مطالعهی قسمتی از دیتاشیت این ماژول میپردازیم که کمی با طرز کار آن آشنا شویم.
چیزی که در این قسمت از دیتاشیت برای ما اهمیت دارد، اول ترتیب آدرسها میباشد. چون اطلاعات را به همین ترتیب باید ارسال و دریافت کنیم. و دیگری هم روش ارسال است. که همان BCD می باشد که قبلا گفته بودم. همانطور که میبینید مثلا دقیقه در 8 بیت فرستاده میشود که چهار بیت کم ارزش آن رقم یکان دقیقه میباشد و چهار بیت با ارزش آن رقم دهگان است.
نکته اینجاست که مثلا ساعت 15 به باینری می شود 00001111 ولی در روش BCD چهار بیت کم ارزش می شود 5 و چهار بیت باارزش میشود 1 . پس ما خواهیم داشت 00010101 . دقیقا تفاوت در همینجاست. چگونگی تبدیل عدد از دهتایی به BCD را در خود برنامه توضیح میدهم.
قسمت بعدیای که باید به آن توجه داشت نحوهی خواندن و نوشتن بر روی این ماژول است. البته زیاد هم لازم نیست خودمان را درگیر این قضیه کنیم چون از کتابخانهی wire که برای ارتباط سریال است استفاده می کنیم. ولی نکتهی قایل توجه آدرس ماژول است که ما برای ارتباط سریال به آن نیاز داریم. این آدرس بصورت باینری در اولین خانه سمت چپ نوشته شده. 1101000 که به عدد می شود 104 و به هگز که ما از این استفاده میکنیم، میشود 0x68 .
بررسی نرم افزار ارتباط با DS1307 :
#include <ESP8266WiFi.h> #include <Wire.h> const int DS1307 = 0x68; // Address of DS1307 see data sheets const char* days[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; const char* months[] = {"January", "February", "March", "April", "May", "June", "July", "August","September", "October", "November", "December"}; // Initializes all values: byte second = 0; byte minute = 0; byte hour = 0; byte weekday = 0; byte monthday = 0; byte month = 0; byte year = 0;
خب اول برنامه کتابخانه های لازم را فراخوانی می کنیم. من چون از ESP8266 استفاده کردم، کتابخانهی آن را هم فراخوانی کردهام. و در خطهای بعدی آدرس ماژول و متغیر هایی را که لازم داریم تعریف میکنیم.
void setup() { Wire.pins(0, 2);// yes, see text Wire.begin(0, 2); // 0=sda, 2=scl Serial.begin(115200); delay(2000); // This delay allows the MCU to read the current date and time. Serial.print("The current date and time is: "); printTime(); Serial.println("Please change to newline ending the settings on the lower right of the Serial Monitor"); Serial.println("Would you like to set the date and time now? Y/N"); while (!Serial.available()) delay(10); if (Serial.read() == 'y' || Serial.read() == 'Y') // This set of functions allows the user to change the date and time { Serial.read(); setTime(); Serial.print("The current date and time is now: "); printTime(); } Serial.println("Thank you."); }
در فانکشن setup پینهایی که قرار است برای ارتباط سریال استفاده شود را با متد pins معرفی می کنیم. چون ESP8266 پین I2C ندارد بصورت نرم افزاری از این امکان استفاده میکنیم. با متد begin ارتباط سریال را شروع می کنیم.
در ادامه کدهایی برای تنظیم ساعت نوشته شده است. که شما میتوانید ساعت و تقویم ماژول را تنظیم کنید.
byte decToBcd(byte val) { return ((val/10*16) + (val%10)); } byte bcdToDec(byte val) { return ((val/16*10) + (val%16)); }
این قسمت همان تبدیل دسیمال به BCD و بالعکس می باشد. برای تبدیل، عدد را بر 10 تقسیم میکند، چیزی که می ماند دهگان عدد است. که در 16 ضرب میکنیم. این ضرب باعث می شود که دهگان عدد ما 4 بیت به سمت چپ شیفت پیدا کند. اگر عدد ما 35 باشد. دهگان آن 3 میباشد. که باینری آن می شود 00000011 که وقتی در 16 ضرب شود، می شود 48 که باینری آن می شود 00110000 . در ادامه باقیماندهی تقسیم عدد ما بر 10 میشود 5 که باینری آن هم میشود 00000101.
از جمع این دو عدد به همان BCD خواهیم رسید. جمع 48 و 5 می شود 53 که باینری آن می شود 00110101.
برای برگرداندن عدد خود هم همین کار را بالعکس انجام میدهیم.
نوشتن و خواندن DS1307 :
برای نوشتن و خواندن از DS1307 باید ارتباط را با آدرس ماژول بر قرار کنیم و یک بیت خالی ارسال کنیم. موقع نوشتن بیتهای ثانیه و دقیقه و ساعت و تقویم را به همان ترتیبی که در دیتاشیت بود برای ماژول ارسال می کنیم. که البته قبل از ارسال آنرا به BCD تبدیل کرده ایم. و در آخر دوباره یک بایت خالی می فرستیم و ارتباط را قطع میکنیم.
برای در خواست فقط یک بایت خالی میفرستیم و ارتباط را قطع میکنیم و با دستور Wire.requestFrom بایت های دریافتی را می خوانیم. این دستور دو پارامتر میگیرید. اولی آدرس ماژول و دومی تعداد بایت هایی است که قرار است دریافت کند. که در اینجا ما 7 بایت را لازم داریم و همان 7 را قرار میدهیم.
در ادامه برنامه را به صورت کامل قرار میدهم:
#include <ESP8266WiFi.h> #include <Wire.h> const int DS1307 = 0x68; // Address of DS1307 see data sheets const char* days[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; const char* months[] = {"January", "February", "March", "April", "May", "June", "July", "August","September", "October", "November", "December"}; // Initializes all values: byte second = 0; byte minute = 0; byte hour = 0; byte weekday = 0; byte monthday = 0; byte month = 0; byte year = 0; void setup() { Wire.pins(0, 2);// yes, see text Wire.begin(0, 2); // 0=sda, 2=scl Serial.begin(115200); delay(2000); // This delay allows the MCU to read the current date and time. Serial.print("The current date and time is: "); printTime(); Serial.println("Please change to newline ending the settings on the lower right of the Serial Monitor"); Serial.println("Would you like to set the date and time now? Y/N"); while (!Serial.available()) delay(10); if (Serial.read() == 'y' || Serial.read() == 'Y') // This set of functions allows the user to change the date and time { Serial.read(); setTime(); Serial.print("The current date and time is now: "); printTime(); } Serial.println("Thank you."); } // Continuous function for converting bytes to decimals and vice versa void loop() { } byte decToBcd(byte val) { return ((val/10*16) + (val%10)); } byte bcdToDec(byte val) { return ((val/16*10) + (val%16)); } // This set of codes is allows input of data void setTime() { Serial.print("Please enter the current year, 00-99. - "); year = readByte(); Serial.println(year); Serial.print("Please enter the current month, 1-12. - "); month = readByte(); Serial.println(months[month-1]); Serial.print("Please enter the current day of the month, 1-31. - "); monthday = readByte(); Serial.println(monthday); Serial.println("Please enter the current day of the week, 1-7."); Serial.print("1 Sun | 2 Mon | 3 Tues | 4 Weds | 5 Thu | 6 Fri | 7 Sat - "); weekday = readByte(); Serial.println(days[weekday-1]); Serial.print("Please enter the current hour in 24hr format, 0-23. - "); hour = readByte(); Serial.println(hour); Serial.print("Please enter the current minute, 0-59. - "); minute = readByte(); Serial.println(minute); second = 0; Serial.println("The data has been entered."); // The following codes transmits the data to the RTC Wire.beginTransmission(DS1307); Wire.write(byte(0)); Wire.write(decToBcd(second)); Wire.write(decToBcd(minute)); Wire.write(decToBcd(hour)); Wire.write(decToBcd(weekday)); Wire.write(decToBcd(monthday)); Wire.write(decToBcd(month)); Wire.write(decToBcd(year)); Wire.write(byte(0)); Wire.endTransmission(); // Ends transmission of data } byte readByte() { while (!Serial.available()) delay(10); byte reading = 0; byte incomingByte = Serial.read(); while (incomingByte != '\n') { if (incomingByte >= '0' && incomingByte <= '9') reading = reading * 10 + (incomingByte - '0'); else; incomingByte = Serial.read(); } Serial.flush(); return reading; } void printTime() { char buffer[3]; const char* AMPM = 0; readTime(); Serial.print(days[weekday-1]); Serial.print(" "); Serial.print(months[month-1]); Serial.print(" "); Serial.print(monthday); Serial.print(", 20"); Serial.print(year); Serial.print(" "); if (hour > 12) { hour -= 12; AMPM = " PM"; } else AMPM = " AM"; Serial.print(hour); Serial.print(":"); sprintf(buffer, "%02d", minute); Serial.print(buffer); Serial.println(AMPM); } void readTime() { Wire.beginTransmission(DS1307); Wire.write(byte(0)); Wire.endTransmission(); Wire.requestFrom(DS1307, 7); second = bcdToDec(Wire.read()); minute = bcdToDec(Wire.read()); hour = bcdToDec(Wire.read()); weekday = bcdToDec(Wire.read()); monthday = bcdToDec(Wire.read()); month = bcdToDec(Wire.read()); year = bcdToDec(Wire.read()); }
دیدگاه ها :