Hướng dẫn ESP32 53/55 - Xây dựng đồng hồ Internet LCD | Bộ học IoT ESP32 của SunFounder
Trong hướng dẫn này, chúng ta sẽ xây dựng một đồng hồ LCD kết nối Internet sử dụng vi điều khiển ESP32 từ SunFounder. Đồng hồ này sẽ tự động đồng bộ thời gian hiện tại qua Internet, hiển thị thời gian ở định dạng 12 giờ hoặc 24 giờ, cùng với thứ trong tuần, ngày và tháng. Việc sử dụng Giao thức Thời gian Mạng (NTP) đảm bảo đồng hồ luôn chính xác mà không cần điều chỉnh thủ công.
Dự án này tận dụng khả năng Wi-Fi tích hợp của ESP32 để lấy thời gian hiện tại từ máy chủ NTP. Chúng ta sẽ sử dụng Màn hình Tinh thể Lỏng (LCD) để hiển thị thời gian, có thể được định dạng theo sở thích của người dùng. Để làm rõ hơn bất kỳ bước nào, vui lòng tham khảo video tại (trong video ở 00:30).
Phần cứng được giải thích
Các thành phần chính cho dự án này bao gồm vi điều khiển ESP32, màn hình LCD 20x4 và nguồn điện. ESP32 là một vi điều khiển mạnh mẽ với Wi-Fi và Bluetooth tích hợp, phù hợp cho các dự án IoT. LCD được sử dụng để hiển thị thời gian và ngày tháng, và có thể được cấu hình cho các kích thước màn hình khác nhau.
LCD hoạt động thông qua giao thức I2C, cho phép giao tiếp qua hai dây (SDA và SCL). Điều này đơn giản hóa việc nối dây và giảm số chân cần thiết trên ESP32. Kết nối đến máy chủ NTP được thực hiện bằng khả năng Wi-Fi của ESP32, cho phép cập nhật theo thời gian thực.
- Đảm bảo điện áp nguồn cung cấp chính xác (5 V).
- Sử dụng tụ điện tách rời gần các chân nguồn để ổn định.
- Thận trọng với các kết nối I2C để tránh xung đột bus.
- Xác minh địa chỉ I2C của LCD (0x27 hoặc 0x3F).
- Kiểm tra thông tin đăng nhập Wi-Fi để kết nối chính xác.
- Xử lý điều chỉnh giờ mùa hè trong mã của bạn.
- Sử dụng máy chủ NTP chính xác cho vị trí địa lý của bạn.
- Luôn xóa LCD trước khi cập nhật màn hình.
Hướng dẫn nối dây

Để nối dây ESP32 với LCD, bắt đầu bằng cách kết nối các chân nguồn. Kết nối VCC của LCD với chân 5V trên ESP32 và chân GND của LCD với chân GND trên ESP32. Đối với giao tiếp I2C, kết nối chân SDA của LCD với GPIO 21 trên ESP32 và chân SCL với GPIO 22. Đảm bảo các kết nối chắc chắn để tránh các vấn đề giao tiếp.
Khi thiết lập nối dây, sử dụng dây jumper đực-cái để kết nối dễ dàng. Nếu LCD của bạn có địa chỉ I2C hoặc cấu hình chân khác, hãy điều chỉnh mã cho phù hợp. Tham khảo video tại (trong video ở 05:30) để có các tùy chọn nối dây thay thế nếu cần.
Ví dụ mã & hướng dẫn chi tiết
Mã khởi tạo LCD và thiết lập kết nối Wi-Fi để lấy dữ liệu thời gian từ máy chủ NTP. Các định danh chính như ssid và password được sử dụng để kết nối với mạng Wi-Fi, trong khi ntpServer1 và ntpServer2 chỉ định các máy chủ NTP cần sử dụng.
const char* ssid = "dars";
const char* password = "llllllllllllll";
const char* ntpServer1 = "pool.ntp.org";
const char* ntpServer2 = "time.nist.gov";
Đoạn mã này hiển thị thông tin đăng nhập mạng và địa chỉ máy chủ. Đảm bảo bạn nhập SSID và mật khẩu Wi-Fi của mình một cách chính xác, vì bất kỳ sai sót nào sẽ ngăn ESP32 kết nối với Internet.
Trong hàm printLocalTime(), thời gian hiện tại được định dạng để hiển thị. Cấu trúc tm được sử dụng để lưu trữ thông tin thời gian, trong khi strftime giúp định dạng thời gian thành một chuỗi có thể đọc được.
void printLocalTime() {
struct tm timeinfo;
if(!getLocalTime(&timeinfo)) {
Serial.println("No time available (yet)");
return;
}
char timeHour[5];
strftime(timeHour, 5, "%H", &timeinfo);
Mã này kiểm tra xem thời gian cục bộ có khả dụng không và lấy giờ. Giờ được định dạng sau đó được sử dụng để hiển thị thời gian hiện tại trên LCD. Nếu thời gian chưa khả dụng, nó sẽ in một thông báo ra Serial Monitor.
Cuối cùng, hàm setup() khởi tạo LCD và kết nối với Wi-Fi. Nó cũng cấu hình cài đặt máy chủ NTP và đặt một hàm gọi lại để đồng bộ thời gian.
void setup() {
Serial.begin(115200);
lcd.init(); // initialize the lcd
lcd.backlight(); // Turns on the LCD backlight.
Serial.printf("Connecting to %s ", ssid);
WiFi.begin(ssid, password);
Đoạn trích này khởi tạo Serial Monitor để gỡ lỗi, thiết lập LCD và cố gắng kết nối với mạng Wi-Fi đã chỉ định. Trạng thái kết nối sẽ được in ra Serial Monitor, cho phép bạn xác minh kết nối.
Trình diễn / Điều gì sẽ xảy ra
Sau khi thiết lập thành công, LCD sẽ hiển thị thời gian hiện tại, thứ trong tuần và ngày tháng. Bạn có thể mong đợi thời gian cập nhật mỗi 5 giây, nhờ vào hàm loop(). Nếu kết nối đến máy chủ NTP thất bại, một thông báo sẽ xuất hiện trên Serial Monitor cho biết thời gian chưa khả dụng (trong video ở 12:00).
Các lỗi thường gặp bao gồm nối dây không đúng, địa chỉ I2C sai và thông tin đăng nhập Wi-Fi không chính xác. Đảm bảo tất cả các kết nối chắc chắn và máy chủ NTP có thể truy cập được từ mạng của bạn.
Mốc thời gian video
- 00:00 Bắt đầu
- 2:10 Giới thiệu
- 5:15 Giải thích nối dây
- 7:32 Giải thích mã Arduino
- 18:43 Chọn bo mạch ESP32 và cổng COM trong Arduino IDE
- 20:27 Trình diễn Đồng hồ Internet
/*
Internet Clock using SunFounder's IoT ESP32 Learning kit
Full video instruction https://youtu.be/0KnuNqfiVug
📚⬇️ Download and resource page https://robojax.com/RJT686
Internet Clock for ESP32
Written by Ahamd Shasmhiri on Dec 31, 2023 at 19:29
www.Robojax.com
*/
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
//SDA->21,SCL->22
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display
const bool showSeconds = true;//set to "true" to show seconds and "false" to hide
const bool showShortMonth = false;//December = false, Dec=true
const bool show24Hours = true;//true to have 18:30 or false to have 6:30
#include <WiFi.h>
#include "time.h"
#include "sntp.h"
#include "TZ.h"
//TZ.h is taken from https://github.com/esp8266/Arduino/blob/master/cores/esp8266/TZ.h
const char* ssid = "dars";
const char* password = "llllllllllllll";
const char* ntpServer1 = "pool.ntp.org";
const char* ntpServer2 = "time.nist.gov";
const long gmtOffset_sec = -5 * 3600;
const int daylightOffset_sec = 3600;
const String months[][2] ={
"January","Jan",
"February","Feb",
"March","Mar",
"April","Apr",
"May","May",
"June","Jun",
"July","Jul",
"August","Aug",
"September","Sep",
"October","Oct",
"November","Nov",
"December","Dec"
};
void printLocalTime()
{
struct tm timeinfo;
if(!getLocalTime(&timeinfo)){
Serial.println("No time available (yet)");
return;
}
//Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S 12Hours: %I:%M:%S");
// get time format HH:MM
char timeHour[5];
strftime(timeHour,5, "%H", &timeinfo);
String hourString = String(timeHour);//convert timeHour to string
char timeMinute[3];
strftime(timeMinute,3, "%M", &timeinfo);
String minuteString = String(timeMinute);
//Serial.println(hourString);
if(!show24Hours)
{
if(hourString.toInt() >= 12)
{
minuteString = minuteString + "PM";
}else{
minuteString = minuteString + "AM";
}
}
char timeSeconds[3];
strftime(timeSeconds,3, "%S", &timeinfo);
char timeDayofWeek[10];
strftime(timeDayofWeek, 10 , "%A", &timeinfo);
char timeMonth[10];
strftime(timeMonth, 10 , "%B", &timeinfo);
String Month = String(timeMonth);
if(showShortMonth)
{
for(int m=0; m <12; m++)
{
if(Month == months[m][0] )
{
Month = months[m][1];
//Serial.println(months[m][1]);
}
}
}
char timeDayofMonth[3];
strftime(timeDayofMonth,3 , "%d", &timeinfo);
char timeYear[5];
strftime(timeYear, 5 , "%Y", &timeinfo);
String time = String(timeHour) + ":" + minuteString ;
if(showSeconds) time = time +":" + String(timeSeconds);//add seconds if showSeconds=true
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(time);
lcd.print(" ");
lcd.print(String(timeDayofWeek));
//
lcd.setCursor(0, 1);
lcd.print(timeDayofMonth);
lcd.print(" ");
lcd.print(Month);
lcd.print(" ");
lcd.print(timeYear);
}
// Callback function (get's called when time adjusts via NTP)
void timeavailable(struct timeval *t)
{
Serial.println("Got time adjustment from NTP!");
printLocalTime();
}
void setup()
{
Serial.begin(115200);
lcd.init();// initialize the lcd
lcd.backlight(); // Turns on the LCD backlight.
lcd.print("Internet Clock");
delay(3000);//waif 3 seconds
// set notification call-back function
sntp_set_time_sync_notification_cb( timeavailable );
/**
* NTP server address could be aquired via DHCP,
*
* NOTE: This call should be made BEFORE esp32 aquires IP address via DHCP,
* otherwise SNTP option 42 would be rejected by default.
* NOTE: configTime() function call if made AFTER DHCP-client run
* will OVERRIDE aquired NTP server address
*/
sntp_servermode_dhcp(1); // (optional)
/**
* This will set configured ntp servers and constant TimeZone/daylightOffset
* should be OK if your time zone does not need to adjust daylightOffset twice a year,
* in such a case time adjustment won't be handled automagicaly.
*/
// configTime(gmtOffset_sec, daylightOffset_sec, ntpServer1, ntpServer2);
/**
* A more convenient approach to handle TimeZones with daylightOffset
* would be to specify a environmnet variable with TimeZone definition including daylight adjustmnet rules.
* A list of rules for your zone could be obtained from https://github.com/esp8266/Arduino/blob/master/cores/esp8266/TZ.h
*/
//configTzTime(TZ_America_Toronto, ntpServer1, ntpServer2);
configTzTime(TZ_America_Toronto, ntpServer1, ntpServer2);
//connect to WiFi
Serial.printf("Connecting to %s ", ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println(" CONNECTED");
}
void loop()
{
delay(5000);
printLocalTime(); // it will take some time to sync time :)
}
Common Course Links
Common Course Files
Nghĩ bạn có thể cần
-
AmazonBuy LCD1602-I2C from Amazonamzn.to
-
eBayPurchase LCD1602-I2C from eBayebay.us
-
BanggoodPurchase LCD1602 display from Banggoodbanggood.com
Tài nguyên & tài liệu tham khảo
-
Bên ngoàiPurchase LCD1602 display from Banggoodbanggood.com
Tập tin📁
Tệp Yêu Cầu (.h)
-
TZ.h
TZ.h0.02 MB