雷竞技注册
项目

如何在Arduino和LCD上使用RTC

2015年9月21日经过Jens Christoffersen

本文将向您展示一种使用实时时钟IC DS1307制作精确时钟的方法。时间将在液晶显示器上显示。

如何使用实时时钟IC DS1307制作精确时钟。时间将在液晶显示器上显示。

需求

  • 计算机运行Arduino 1.6.5
  • arduino.
  • 跳线
  • 电路试验板
  • 零件列表的零件

您可以使用Atmel将Arduino用另一个IC替换,但确保它具有足够数量的输入和输出引脚以及I2C功能。我正在使用Atmega168a-pu。如果您这样做,您需要一个程序员。我有AVR MKII ISP程序员。

建议读者熟悉面包板,在Arduino环境下编程,并有一定的C语言编程知识。下面的两个程序不需要额外的解释。

介绍

微控制器如何记录时间和日期?常规的微控制器有一个定时器功能,从0(零)电源应用,然后开始计数。在Arduino世界中,我们可以使用millis()函数来重置自电源应用以来经过的毫秒数。当你断开并重新连接电源时,一切又会重新开始。当涉及到时钟和日期时,这就不太方便了。

这就是实时时钟(Real Time Clock)芯片派上用场的地方。这个集成电路,带有一个3v硬币电池或另一个3v电源,可以跟踪时间和日期。时钟/日历提供秒、分、小时、日、日、月和年信息。IC对有30/31天和闰年的月份进行修正。沟通是通过I完成的2C总线。我的2C巴士不会在这里讨论。

如果主电路的VCC低于VBAT,则RTC自动切换到低功耗电池备份模式。备用电池通常是连接到引脚3和GND的3V硬币电池电池。这样,IC仍在跟踪时间和日期,并且当电源应用于主电路时,微控制器获取当前时间和日期。

在这个项目中,我们正在使用DS1307。在该IC上,引脚7是SQW / OUT引脚。您可以使用此引脚闪烁LED,或者将微控制器调整。我们会做两者。来自数据表的以下图像有助于我们了解SQW / OUT。

此表可帮助您使用频率:

弗里克 Bit7&Bit6&Bit5 Bit4. Bit3&Bit2. Bit1. Bit0.
1Hz. 0. 1 0. 0. 0.
4.096Hz. 0. 1 0. 0. 1
8.192赫兹 0. 1 0. 1 0.
32.768赫兹 0. 1 0. 1 1

如果您将一个LED和一个电阻连接到pin7,并希望它以1Hz的频率闪烁,您可以向控制寄存器内存地址写入0b00010000。如果你想要4.096 Hz,你可以写0b000100001。现在你需要一个示波器来观察脉冲,因为LED闪烁得如此之快,看起来就像一直亮着一样。我们使用1Hz。

硬件

这是我们想要的框图。

我们希望:

  • ISP (In System Programming)对单片机进行编程
  • 按按钮设置时间和日期
  • 微控制器通过i通过我与RTC通信2C
  • 显示LCD上的时间和日期

原理图:

点击图片为全尺寸。

Partlist

这是鹰的屏幕截图:

软件

在本教程中,我们将使用两种不同的草图:一种是将时间和日期写入RTC,另一种是从RTC读取时间和日期。我是这样做的,所以你会对发生的事情有一个更好的概述。我们将使用相同的电路为上述两个程序。

首先,我们将把时间和日期写入RTC,这就像在手表上设置时间。

我们正在使用两个交换机。一个是增加一小时,分钟,日期,月,年份和一天,另一个是在他们之间进行选择。应用程序不读取来自任何关键传感器的值,因此我们正在使用中断检查开关是否被按下并处理开关反弹。有关开关弹跳的更多信息读这个

以下代码将设置值并将其写入RTC:

// includer文件#include&ltwire.h> #include&ltliqueccrystal.h> //液晶引脚定义#define rs 9 #define e 10 #define d4 8 #define d5 7 #define d6 6 #define d7 5液晶液晶显示屏(Rs,e,d4,d5,d6,d7);//中断0是硬件引脚4(数字引脚2)int btnset = 0;//中断1是硬件引脚5(数字引脚3)int btnsel = 1;//中断状态int togbtnset = false;int togbtnsel = false;//时间和日期变量int tmphour = 0;int tmpminute = 0;int tmpdate = 0;int tmpmonth = 0;int tmpyear = 0; int tmpDay = 0; int tmpSecond = 0; int counterVal = 0; // Variable to keep track of where we are in the "menu" int myMenu[6]; // 0=Hour, 1=Minutes, 2=date, 3=MOnth, 4=Year, 5=DOW int menuCounter = 0; // A array of the weekday char* days[] = { "NA", "Mon", "Tue", "Wed", "Thu", "Fre", "Sat", "Sun" }; void setup() { // Interrupt declaration, execute increaseValue/nextItem function // when btnXXX is RISING attachInterrupt(btnSet, increaseValue, RISING); attachInterrupt(btnSel, nextItem, RISING); Wire.begin(); lcd.begin(16,2); showWelcome(); } // Interrupt function void increaseValue() { // Variables static unsigned long lastInterruptTime = 0; // Making a timestamp unsigned long interruptTime = millis(); // If timestamp - lastInterruptTime is greater than 200 if (interruptTime - lastInterruptTime > 200) { // Toggle the variable togBtnSet = !togBtnSet; // Increase the counterVal by 1 counterVal++; } // Setting lastInterruptTime equal to the timestamp // so we know we moved on lastInterruptTime = interruptTime; } // Next menuItem Interrupt function void nextItem() { static unsigned long lastInterruptTime = 0; unsigned long interruptTime = millis(); if (interruptTime - lastInterruptTime > 200) { togBtnSel = !togBtnSel; // Increase the menu counter so we move to next item menuCounter++; // Placing the counterVal in the menucounters array position myMenu[menuCounter] = counterVal; // Reset counterVal, now we start at 0 on the next menuItem counterVal = 0; } lastInterruptTime = interruptTime; } // Function that convert decimal numbers to binary byte decToBCD(byte val) { return ((val/10*16) + (val)); } // Short welcome message, now we know everything is OK void showWelcome() { lcd.setCursor(2,0); lcd.print("Hello world."); lcd.setCursor(3,1); lcd.print("I'm alive."); delay(500); lcd.clear(); } // Funcion to set the hour void setHour() { lcd.setCursor(0,0); lcd.print("Set hour. "); // Checks if interrupt has occured = button pressed if (togBtnSet) { // Update array value with counterVal myMenu[menuCounter] = counterVal; lcd.setCursor(7,1); // Print the new value lcd.print(myMenu[menuCounter]); lcd.print(" "); } else { // Update array value with counterVal myMenu[menuCounter] = counterVal; lcd.setCursor(7,1); // Print the new value lcd.print(myMenu[menuCounter]); lcd.print(" "); } } // Function to set minutes void setMinute() { lcd.setCursor(0,0); lcd.print("Set minute. "); if (togBtnSet) { myMenu[menuCounter] = counterVal; lcd.setCursor(7,1); lcd.print(myMenu[menuCounter]); lcd.print(" "); } else { myMenu[menuCounter] = counterVal; lcd.setCursor(7,1); lcd.print(myMenu[menuCounter]); lcd.print(" "); } } // Function to set date void setDate() { lcd.setCursor(0,0); lcd.print("Set date. "); if (togBtnSet) { myMenu[menuCounter] = counterVal; lcd.setCursor(7,1); lcd.print(myMenu[menuCounter]); lcd.print(" "); } else { myMenu[menuCounter] = counterVal; lcd.setCursor(7,1); lcd.print(myMenu[menuCounter]); lcd.print(" "); } } // Function to set month void setMonth() { lcd.setCursor(0,0); lcd.print("Set month. "); if (togBtnSet) { myMenu[menuCounter] = counterVal; lcd.setCursor(7,1); lcd.print(myMenu[menuCounter]); lcd.print(" "); } else { myMenu[menuCounter] = counterVal; lcd.setCursor(7,1); lcd.print(myMenu[menuCounter]); lcd.print(" "); } } // Function to set year void setYear() { lcd.setCursor(0,0); lcd.print("Set year. "); if (togBtnSet) { myMenu[menuCounter] = counterVal; lcd.setCursor(7,1); lcd.print(myMenu[menuCounter]); lcd.print(" "); } else { myMenu[menuCounter] = counterVal; lcd.setCursor(7,1); lcd.print(myMenu[menuCounter]); lcd.print(" "); } } // Function to set the day of week void setDOW() { lcd.setCursor(0,0); lcd.print("Set day (1=mon)."); if (togBtnSet) { myMenu[menuCounter] = counterVal; lcd.setCursor(7,1); lcd.print(myMenu[menuCounter]); lcd.print(" "); } else { myMenu[menuCounter] = counterVal; lcd.setCursor(7,1); lcd.print(myMenu[menuCounter]); lcd.print(" "); } } // Write the data to the RTC void writeRTC() { Wire.beginTransmission(0x68); Wire.write(0); // Start address Wire.write(0x00); // seconds Wire.write(decToBCD(myMenu[1])); // convert tmpMinutes to BCD and write them Wire.write(decToBCD(myMenu[0])); // convert tmpHour to BCD and write them Wire.write(decToBCD(myMenu[5])); // convert tmpDay to BCD and write them Wire.write(decToBCD(myMenu[2])); // convert tmpDate to BCD and write them Wire.write(decToBCD(myMenu[3])); // convert tmpMonth to BCD and write them Wire.write(decToBCD(myMenu[4])); // convert tmpYear to BCD and write them Wire.write(0b00010000); // enable 1Hz Square wave on PIN7 Wire.endTransmission(); // close the transmission } // Show the time // You need to use the other program to see the RTC is working void showTime() { lcd.setCursor(0,0); lcd.print(" "); lcd.print(myMenu[0]); lcd.print(":"); // hour lcd.print(myMenu[1]); lcd.print(":"); lcd.print("00 "); // minute lcd.setCursor(3,1); lcd.print(days[myMenu[5]]); lcd.print(" "); // DOW lcd.print(myMenu[2]); lcd.print("."); // date lcd.print(myMenu[3]); lcd.print("."); // month lcd.print(myMenu[4]); lcd.print(" "); // year // Call the writeRTC function writeRTC(); } void loop() { if (menuCounter == 0) { setHour(); } if (menuCounter == 1) { setMinute(); } if (menuCounter == 2) { setDate(); } if (menuCounter == 3) { setMonth(); } if (menuCounter == 4) { setYear(); } if (menuCounter == 5) { setDOW(); } if (menuCounter == 6) { showTime(); } }

DS1307_WRITE_LCD_v1.ino.zip

该程序以简短的欢迎消息开始。此消息告诉您应用的电源,LCD正在工作,程序已开始运行。

要从RTC读取并显示时间和日期,你必须用下面的程序编程你的微控制器。该程序从RTC读取时间和日期值,并在LCD上显示它们。

// includer文件#include&ltwire.h> #include&ltliqueccrystal.h> //液晶引脚定义#define rs 9 #define e 10 #define d4 8 #define d5 7 #define d6 6 #define d7 5液晶液晶显示屏(Rs,e,d4,d5,d6,d7);// PIN将从RTC INT CLOWPIN = 0接收时钟脉冲;//时间和日期变量字节秒;字节分钟;字节小时;字节日;字节日期;字节月份;字节年份;//平日的数组char * days [] = {“na”,“mon”,“tue”,“周三”,“星期四”,“fre”,“sat”,“sun”}; // Function run once void setup() { pinMode(clockPin, INPUT); pinMode(clockPin, LOW); Wire.begin(); lcd.begin(16,2); showWelcome(); } // Nice welcome message, then we know LCD is OK void showWelcome() { lcd.setCursor(2,0); lcd.print("Hello world."); lcd.setCursor(3,1); lcd.print("I'm alive."); delay(500); lcd.clear(); } // Doing this forever void loop() { // While clockPin is high while (digitalRead(clockPin)) { // start the I2C transmission, at address 0x68 Wire.beginTransmission(0x68); // Start at address 0 Wire.write(0); // Close transmission Wire.endTransmission(); // Start to read the 7 binary data from 0x68 Wire.requestFrom(0x68, 7); second = Wire.read(); minute = Wire.read(); hour = Wire.read(); day = Wire.read(); date = Wire.read(); month = Wire.read(); year = Wire.read(); // Formatting and displaying time lcd.setCursor(4,0); if (hour < 10) lcd.print("0"); lcd.print(hour, HEX); lcd.print(":"); if (minute < 10) lcd.print("0"); lcd.print(minute, HEX); lcd.print(":"); if (second < 10) lcd.print("0"); lcd.print(second, HEX); lcd.setCursor(2,1); // Formatting and displaying date lcd.print(days[day]); lcd.print(" "); if (date < 10) lcd.print("0"); lcd.print(date, HEX); lcd.print("."); if (month < 10) lcd.print("0"); lcd.print(month, HEX); lcd.print("."); lcd.print(year, HEX); } // end while }

jc_DS1307_READ_LCD_v0.ino.zip

结论

在本文中,我们已经从Maxim集成了一张小型DS1307 RTC IC。我们制作了一个程序,该计划设置时间和日期,我们备份了另一个程序来阅读时间和日期。要检查是否按下了开关,我们使用中断。中断也照顾开关弹跳。

图片和视频

点击图片为全尺寸。

点击图片为全尺寸。

设定时间

阅读时间

自己试试这个项目吧!得到bom。

8评论
  • P.
    菲尔斯 2015年12月04日

    你好
    只是快速看,非常好,也可能只是我想做的事情。
    我承认我没有时间好好学习Arduino的用法,但我确实喜欢让有用的东西工作。
    我正在进行的一个项目是更新RTC(我已经尝试了大多数,但还没有找到一个保持正确的第二个月的准确性)。
    我的方法是为了破解无线电控制的数字时钟(在我的情况下MSF),并使用警报输出来发送无线同步脉冲,例如午夜。
    大多数RTC芯片只会在最坏的情况下丢失或增益秒,因此想法是使用SYNC脉冲来设置秒,可能会返回或转发到00:00。
    快速浏览一下你的文章,你就会知道如何使用SET函数来实现这一点。
    长期目的是摆脱众多可编程计时器等。在房子里,这一点都没有一个保持良好的时光并根据准确的时间来源做好自己。
    你觉得呢?
    刚刚加入了该网站,乍一看似乎非常有用,有用和文明。

    喜欢的。 回复
    • j
      Jens Christoffersen 2015年12月22日
      你好谢谢。这可能是一个有趣的项目。让房子里的所有时钟在午夜同步。如何添加GPS模块以获得准确的时间?
      喜欢的。 回复
  • 约翰加伦特 2016年1月07日

    嗨,请告诉我,如果我上传这两个代码到一个328没有连接到电路,然后添加控制器,我怎么能让它工作,我要设置所有,但不能开始运行时钟。如果我们想要建造一些时钟,那么必须组装所有的组件,然后加载草图,这真的没有好处。

    喜欢的。 回复