Xây dựng Đồng hồ thời gian thực bằng Arduino và Mô-đun RTC DS1307 Ghi chú về Mô-đun RTC DS1307
Trong bài viết này, chúng ta sẽ xây dựng Đồng hồ thời gian thực Arduino sử dụng Mô-đun RTC DS1307 và mô-đun LCD 16 × 2 để hiển thị. Trước hết, chúng ta hãy xem cách giao diện Module RTC với Arduino. Có nhiều loại mô-đun RTC khác nhau có sẵn trên thị trường. Chúng tôi đang sử dụng mô-đun RTC phổ biến nhất có tên là IC DS1307, một mô-đun LCD và Arduino Uno cho hướng dẫn này. Giao tiếp một mô-đun RTC với Arduino khá đơn giản. Bạn chỉ cần thực hiện 2 kết nối giữa mô-đun RTC và Arduino. Vì vậy, chúng ta hãy bắt đầu kinh doanh!
Mô-đun Đồng hồ thời gian thực về cơ bản là một thiết bị theo dõi thời gian cung cấp ngày và giờ hiện tại. Mô-đun RTC đi kèm với IC DS3231 có chức năng đặt báo động.
Ở đây chúng tôi đang sử dụng một mô-đun RTC với chip đồng hồ DS1307 dựa trên giao thức I2C (Two Wire Protocol). Mô-đun cung cấp thông tin chi tiết như giây, phút, giờ, ngày trong tuần, ngày trong tháng, tháng và năm bao gồm cả hiệu chỉnh cho năm nhuận. Nó có thể hoạt động ở định dạng 12 giờ hoặc 24 giờ. Mức tiêu thụ hiện tại của mô-đun này là dải nano ampe. Ngay cả pin 3V cũng có thể cung cấp năng lượng cho nó trong 10 năm để duy trì đồng hồ chính xác mà không cần bất kỳ nguồn điện bên ngoài nào. DS1307 có vùng nhớ 64 byte, trong đó 8 byte đầu tiên được dành riêng làm vùng thanh ghi RTC và 56 byte còn lại được phân bổ làm RAM cho mục đích chung. Các chi tiết về ngày và giờ hiện tại được lưu trữ trong khu vực đăng ký của nó dưới dạng Số thập phân được mã hóa nhị phân. Mô-đun giao tiếp với vi điều khiển bằng giao thức truyền thông nối tiếp được gọi là I2C.Bus I2C về mặt vật lý bao gồm 2 dây hoạt động. Các dây, được gọi là SDA và SCL, đều là hai chiều. SDA là dòng Dữ liệu nối tiếp và SCL là dòng Serial CLock. Mọi thiết bị kết nối với bus đều có địa chỉ thiết bị duy nhất của nó, bất kể đó là MCU hay mô-đun RTC. Mỗi chip này có thể hoạt động như một bộ thu hoặc phát, tùy thuộc vào chức năng.
DS1307 sẽ hoạt động như nô lệ trong mạng truyền thông và bộ điều khiển chỉ có thể truy cập phụ kiện bằng cách khởi tạo điều kiện khởi động cùng với địa chỉ thiết bị. Sau đó, chúng ta cần gửi số đăng ký để truy cập giá trị bên trong. Giao diện với Arduino là I2C đơn giản với các chân SDA và SCL được kết nối với các chân I2C tương ứng của arduino. Ở phía phần mềm, chúng tôi đang sử dụng một thư viện arduino có tên là “Wire” để giao tiếp I2C. Thư viện này cho phép bạn giao tiếp với các thiết bị I2C / TWI.
Tôi hy vọng bạn đã hiểu cho đến nay! Hãy đến với sơ đồ mạch! Vì vậy, dưới đây là sơ đồ mạch để kết nối mô-đun RTC với Arduino.
#include
#include
#define DS1307_ADDRESS 0x68
LiquidCrystal lcd(13,12,11,10,9,8);
boolean MODE = false;
byte Dec_To_BCD(byte dec){
return( (dec/10*16) + (dec%10) );
}
byte BCD_To_Dec(byte BCD){
return( (BCD/16*10) + (BCD%16) );
}
void Mode12(){
MODE=true;
}
void Mode24(){
MODE=false;
}
void setTime(byte SEC, byte MIN, byte HOUR, byte DOW, byte DOM, byte MONTH, byte YEAR)
{
Wire.beginTransmission(DS1307_ADDRESS);
Wire.write(0);
Wire.write(Dec_To_BCD(SEC));
Wire.write(Dec_To_BCD(MIN));
Wire.write(Dec_To_BCD(HOUR));
Wire.write(Dec_To_BCD(DOW));
Wire.write(Dec_To_BCD(DOM));
Wire.write(Dec_To_BCD(MONTH));
Wire.write(Dec_To_BCD(YEAR));
Wire.endTransmission();
}
void getTime(byte *SEC, byte *MIN, byte *HOUR)
{
Wire.beginTransmission(DS1307_ADDRESS);
Wire.write(0);
Wire.endTransmission();
Wire.requestFrom(DS1307_ADDRESS, 7);
*SEC = BCD_To_Dec(Wire.read()&0x7f);
*MIN = BCD_To_Dec(Wire.read());
*HOUR = BCD_To_Dec(Wire.read()&0x3f);
}
void getDate(byte *DOM, byte *MONTH, byte *YEAR)
{
Wire.beginTransmission(DS1307_ADDRESS);
Wire.write(4);
Wire.endTransmission();
Wire.requestFrom(DS1307_ADDRESS, 7);
*DOM = BCD_To_Dec(Wire.read());
*MONTH = BCD_To_Dec(Wire.read());
*YEAR = BCD_To_Dec(Wire.read());
}
byte getWeek()
{
Wire.beginTransmission(DS1307_ADDRESS);
Wire.write(3);
Wire.endTransmission();
Wire.requestFrom(DS1307_ADDRESS, 7);
return(BCD_To_Dec(Wire.read()));
}
String getTimeStr()
{
String ALL;
byte SEC, MIN, HOUR,AM_PM;
getTime(&SEC, &MIN, &HOUR);
if(!MODE)
{
if (HOUR<10)
ALL=String('0')+String(HOUR, DEC)+String(':');
else
ALL=String(HOUR, DEC)+String(':');
if (MIN<10)
ALL+=String('0');ALL+=String(MIN, DEC);
ALL+=String(':');
if (SEC<10)
ALL+=String('0');ALL+=String(SEC, DEC);
}
else
{
AM_PM=HOUR;
if(HOUR>12)
HOUR-=12;
if (HOUR<10)
ALL=String('0')+String(HOUR, DEC)+String(':');
else
ALL=String(HOUR, DEC)+String(':');
if (MIN<10)
ALL+=String('0');ALL+=String(MIN, DEC);
ALL+=String(':');
if (SEC<10)
ALL+=String('0');ALL+=String(SEC, DEC);
ALL+=String(' ');
if(AM_PM>12)ALL+=String("PM");
else ALL+=String("AM");
}
return(ALL);
}
String getDateStr()
{
String ALL;
byte DOM, MONTH, YEAR;
getDate(&DOM, &MONTH,&YEAR);
if (DOM<10)
ALL+=String('0');ALL+=String(DOM, DEC);
ALL+=String('/');
if (MONTH<10)
ALL+=String('0');ALL+=String(MONTH, DEC);
ALL+=String('/');ALL+=String(YEAR, DEC);
ALL+=String(' ');
return(ALL);
}
String getWeekStr()
{
String ALL;
switch(getWeek())
{
case 1:ALL+=String("Sunday");break;
case 2:ALL+=String("Monday");break;
case 3:ALL+=String("Tuesday");break;
case 4:ALL+=String("Wednesday");break;
case 5:ALL+=String("Thursday");break;
case 6:ALL+=String("Friday");break;
case 7:ALL+=String("Saturday");break;
}
return(ALL);
}
void setup()
{
lcd.begin(16,2);
Wire.begin();
setTime(10,33,13,12,11,10,17);
}
void loop()
{
///// 24hr MODE /////
lcd.clear();
lcd.setCursor(0,0);
Mode24();
lcd.print(getTimeStr());lcd.print(' ');
lcd.setCursor(0,1);
lcd.print(getDateStr());lcd.print(' ');
lcd.print(getWeekStr());
delay(5000);
///// 12hr MODE /////
lcd.clear();
lcd.setCursor(0,0);
Mode12();
lcd.print(getTimeStr());lcd.print(' ');
lcd.setCursor(0,1);
lcd.print(getDateStr());lcd.print(' ');
lcd.print(getWeekStr());
delay(5000);
}
Chúng tôi bắt đầu đưa thư viện LiquidCrystal vào chương trình. Trong dòng tiếp theo, chúng tôi tạo một phương thức khởi tạo của Liduidcrysal với tên lcd và chúng tôi chuyển các số pin kỹ thuật số làm tham số. Định dạng thực tế giống như SoftwareSerial lcd (RS, EN, D4, D5, D6, D7); Bạn sẽ biết thêm chi tiết về giao diện LCD trong bài viết “Giao diện LCD với Arduino”.
Ở đây chúng tôi đang tập trung chủ yếu vào giao diện mô-đun RTC. Như đã đề cập trước đó, một thư viện có tên "Wire" được sử dụng ở đây cho giao tiếp I2C. Hàm Wire.begin () sẽ khởi tạo thư viện dây. Vì nó được sử dụng để khởi tạo thư viện, nó chỉ cần được gọi khi bắt đầu. Wire.beginTransmission () là hàm được sử dụng để gửi địa chỉ thiết bị. Sau đó với Wire.write (), chúng ta sẽ gửi số thanh ghi có giá trị mà chúng ta cần truy cập.
Hàm Wire.endTransmission () sẽ kết thúc quá trình truyền. Hàm Wire.requestFrom () được sử dụng bởi master để yêu cầu byte từ mô-đun. Wire.read () sẽ đọc một byte được truyền từ thiết bị phụ đến Arduino sau một cuộc gọi tới requestFrom ().
Trong DS1307, các byte được lưu trữ dưới dạng số thập phân được mã hóa nhị phân. Vì vậy, trước khi ghi các giá trị vào các thanh ghi, chúng ta cần chuyển nó thành BCD (Số thập phân được mã hóa nhị phân). Giống như khôn ngoan, sau khi đọc các giá trị từ vùng đăng ký, nó nên được chuyển đổi thành số thập phân. Dec_To_BCD () và BCD_To_Dec () là các hàm được sử dụng cho việc này.
Trước khi đọc các giá trị từ mô-đun RTC, chúng ta phải đặt ngày và giờ cùng một lúc. Hàm được sử dụng cho việc này là hàm setTime (). Chúng ta nên chuyển các chi tiết thời gian thực tế làm thông số. Định dạng thực tế giống như setTime (giây, phút, giờ, xuống, dom, tháng, năm); .
Ở đây chúng tôi đang sử dụng DS1307 ở chế độ 24 giờ. Và sau đó chuyển nó thành chế độ 12 giờ ở phía phần mềm. Vì vậy, chi tiết thời gian phải ở chế độ 24 giờ trong khi truyền các đối số cho hàm setTime (). Sau khi tải lên chương trình cùng một lúc, bạn nên tải lại mã bằng cách nhận xét hàm setTime (). Nếu không, hàm setTime () sẽ làm hỏng thời gian hiện tại trong khi bạn đặt lại Arduino.
getTime (), getDate (), getWeek () là các hàm được sử dụng để truy cập bảy thanh ghi dữ liệu trong DS1307. Hàm getTime () sẽ cung cấp chi tiết giờ phút và giây. getDate () cho biết ngày, tháng và năm. Và getWeek () sẽ trả về ngày trong tuần. Chúng cung cấp dữ liệu dưới dạng số thập phân. Vì vậy, chúng ta nên chuyển đổi nó sang định dạng thời gian và dưới dạng chuỗi có thể sử dụng. getTimeStr () là hàm sẽ trả về thời gian hiện tại dưới dạng một chuỗi đơn. Giống như khôn ngoan, getDateStr () sẽ trả về ngày hiện tại và getWeekStr () sẽ trả về ngày trong tuần dưới dạng chuỗi.
Bạn có thể hiển thị thời gian hiện tại trên màn hình LCD bằng cách chỉ cần gọi hàm getTimeStr () bên trong lcd.print (). Ví dụ: lcd.print (getTimeStr ()); .
Mode12 () và Mode24 () là các chức năng chuyển đổi chế độ hiển thị thời gian. Nếu bạn muốn hiển thị thời gian hiện tại ở chế độ 12 giờ, bạn nên gọi hàm Mode12 () trước khi sử dụng getTimeStr (). Nếu bạn có bất kỳ nghi ngờ nào, vui lòng hỏi trong phần bình luận.
Hotline: 0979 466 469