ساخت ساعت دیجیتال اینترنتی با ESP32 و نمایشگر TM1637

تصور کنید دیگر هیچوقت لازم نباشد بعد از قطع برق یا تغییر ساعت تابستانی، ساعت خود را دستی تنظیم کنید. در این پروژه یک ساعت دیجیتال خودکار میسازیم که با استفاده از یک برد ESP32 و نمایشگر 4 رقمی 7-segment مبتنی بر TM1637 به سرورهای زمان اینترنتی (NTP) متصل میشود و زمان محلی را تا ثانیه همگام میکند.
موارد مورد نیاز
برای اجرای این پروژه به اقلام زیر نیاز دارید:
- برد توسعه ESP32
- ماژول نمایشگر TM1637 4 رقمی
- سیمهای جامپر
- کابل USB سازگار با برد ESP32
- کامپیوتری برای آپلود برنامه
- برد بورد (اختیاری، برای تست و سیمکشی آسانتر)
نمای کلی پروژه
روال کار به این صورت است که ابتدا ESP32 به شبکه وایفای شما متصل میشود. پس از اتصال، با استفاده از پروتکل UDP و پورت 123 یک درخواست به سرور NTP ارسال میکند تا زمان دقیق را دریافت کند. سرور پاسخ را با یک timestamp بازمیگرداند و ESP32 آن را خوانده و با اعمال تنظیمات منطقه زمانی و قوانین تغییر ساعت تابستانی (daylight saving) تبدیل به زمان محلی میکند.

پس از دریافت زمان محلی، ESP32 این مقدار را ذخیره کرده و با استفاده از تایمر داخلی خود زمان را دنبال میکند؛ به عبارت دیگر پس از همگامسازی اولیه، به صورت مداوم از سرور NTP درخواست زمان نمیدهد. در نهایت هر ثانیه نمایشگر TM1637 بروزرسانی شده و دو نقطه میانی (colon) چشمک میزنند تا نشان دهند ساعت در حال کار است.
سیمکشی ماژول TM1637 به ESP32
حالا وقت این است که ماژول TM1637 را به ESP32 متصل کنیم.
پین VCC ماژول را به VIN برد ESP32 متصل کنید. پین GND ماژول به یک پین GND روی ESP32 متصل شود. سپس پین CLK ماژول را به GPIO 26 و پین DIO را به GPIO 25 وصل کنید.
جدول مرجع اتصالات به صورت زیر است:
| ماژول TM1637 | ESP32 | |
| VCC | VIN | |
| GND | GND | |
| DIO | 25 | |
| CLK | 26 |
در زیر دیاگرامی وجود دارد که ترتیب اتصالها را نشان میدهد:

راهاندازی Arduino IDE
برای برنامهریزی ESP32 از Arduino IDE استفاده میکنیم. قبل از ادامه مطمئن شوید افزونه برد ESP32 در Arduino IDE نصب شده باشد.
نصب کتابخانه
برای ارتباط با آیسی TM1637 از یک کتابخانه استفاده میکنیم. یک گزینه مناسب کتابخانه TM1637Display است که توسط Avishay Orpaz نوشته شده و توابع ضروری برای کنترل نمایشگر را فراهم میکند.
مراحل نصب:
- Arduino IDE را باز کنید و به Library Manager بروید.
- در کادر جستجو عبارت “tm1637” را وارد کنید.
- کتابخانه TM1637 توسط Avishay Orpaz را پیدا کنید.
- دکمه Install را بزنید تا کتابخانه به IDE اضافه شود.

پس از نصب کتابخانه آماده برنامهریزی هستید.
آپلود کد
کد زیر را در Arduino IDE کپی کنید. قبل از آپلود چند تغییر مهم لازم است تا برنامه با شبکه و منطقه زمانی شما سازگار شود.
- ابتدا دو متغیر مربوط به شبکه را با نام و رمز شبکه خود جایگزین کنید تا برد بتواند به وایفای متصل شود:
// Replace with your network credentials const char* ssid = "YOUR_SSID"; const char* password = "YOUR_PASS";
- بعد رشته منطقه زمانی (timezone string) را متناسب با منطقه خود تغییر دهید. فهرست رشتههای منطقه زمانی در منابعی مانند posix_tz_db قابل مشاهده است.
// Time zone string // Example below is for US Eastern Time with automatic daylight saving // Change this for your region const char* tzInfo = "EST5EDT,M3.2.0,M11.1.0";
بعد از اعمال این تغییرات، کد را آپلود کنید.
#include <WiFi.h>
#include <time.h>
#include <TM1637Display.h>
// Replace with your network credentials
const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASS";
// NTP servers used to get the current time from the internet
const char* ntpServer1 = "pool.ntp.org";
const char* ntpServer2 = "time.nist.gov";
// Time zone string
// Example below is for US Eastern Time with automatic daylight saving
// Change this for your region
// See list of timezone strings https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
const char* tzInfo = "EST5EDT,M3.2.0,M11.1.0";
// ESP32 pins connected to the TM1637 module
#define CLK 26
#define DIO 25
// Create the display object
TM1637Display display(CLK, DIO);
void connectWiFi() {
// Put Wi-Fi in station mode so ESP32 connects to a router
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
// Wait until Wi-Fi connection is established
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
}
void syncTime() {
// Start NTP using the two servers above
configTime(0, 0, ntpServer1, ntpServer2);
// Set the timezone for your region
setenv("TZ", tzInfo, 1);
tzset();
// Wait until a valid time is received from the NTP server
// 1577836800 is the Unix time for Jan 1, 2020
time_t now = 0;
while (time(&now) < 1577836800) {
delay(500);
}
}
void displayTime() {
static bool colonOn = false; // Keeps track of colon state between calls
colonOn = !colonOn; // Toggle colon each second for blinking effect
struct tm timeinfo;
if (!getLocalTime(&timeinfo, 2000)) {
display.clear(); // Clear display if time is not available
return;
}
int hours = timeinfo.tm_hour; // Current hour (0 to 23)
int minutes = timeinfo.tm_min; // Current minute (0 to 59)
// Combine hours and minutes into a 4-digit number: HHMM
// Example: 9:05 becomes 905, and leading zeros will show it as 0905
int value = hours * 100 + minutes;
// Bit mask to control the center colon on the TM1637 display
uint8_t colonMask = colonOn ? 0b01000000 : 0;
display.showNumberDecEx(
value,
colonMask, // Show or hide colon
true // Keep leading zeros, so 06:04 displays correctly
);
}
void setup() {
// Set display brightness from 0 to 7
display.setBrightness(5);
display.clear();
// Connect to Wi-Fi and get the current time
connectWiFi();
syncTime();
}
void loop() {
// Update the clock display every second
displayTime();
delay(1000);
} اجرای آزمایشی
پس از آپلود اسکچ، دکمه EN (ریست) روی ESP32 را فشار دهید. اگر همه چیز درست تنظیم شده باشد، باید زمان جاری روی نمایشگر TM1637 هر ثانیه بروزرسانی شود.

برای بررسی میتوانید زمان نمایش داده شده را با زمان EST در جستجوی گوگل مقایسه کنید. در تصویر نمونه، زمان روی نمایشگر با زمان آنلاین مطابقت دارد که نشان میدهد ESP32 با سرور NTP همگام شده و زمان محلی را حفظ میکند.

تشریح کد
کد با وارد کردن سه کتابخانه آغاز میشود: WiFi.h برای اتصال برد به شبکه وایفای، time.h برای برقراری ارتباط با سرور NTP و قالببندی زمان، و TM1637Display.h برای کنترل نمایشگر TM1637.
#include <WiFi.h> #include <time.h> #include <TM1637Display.h>
سپس دو متغیر برای اطلاعات شبکه تعریف میشوند: ssid و password. این مقادیر باید با نام و رمز واقعی شبکه شما جایگزین شوند تا ESP32 بتواند به اینترنت دسترسی پیدا کند و با سرور NTP ارتباط برقرار کند.
// Replace with your network credentials const char* ssid = "YOUR_SSID"; const char* password = "YOUR_PASS";
دو سرور NTP به نامهای pool.ntp.org و time.nist.gov تعریف شدهاند. pool.ntp.org در واقع یک خوشه جهانی از سرورهای زمان است و time.nist.gov به عنوان پشتیبان قابل اعتماد اضافه شده است تا اگر یکی از سرورها در دسترس نبود، برنامه بتواند از سرور دیگر استفاده کند.
// NTP servers used to get the current time from the internet const char* ntpServer1 = "pool.ntp.org"; const char* ntpServer2 = "time.nist.gov";
برای تبدیل زمان جهانی به زمان محلی، از یک رشته اطلاعات منطقه زمانی در متغیر tzInfo استفاده شده است. در مثال پیشفرض، رشته برای منطقه زمانی US Eastern با پشتیبانی خودکار از تغییر ساعت تابستانی تنظیم شده است. میتوانید این رشته را مطابق منطقه خود تغییر دهید؛ فهرست رشتهها در منابعی مانند posix_tz_db قابل مشاهده است.
// Time zone string // Example below is for US Eastern Time with automatic daylight saving // Change this for your region const char* tzInfo = "EST5EDT,M3.2.0,M11.1.0";
پینهای مورد استفاده برای اتصال به نمایشگر تعریف شدهاند: CLK روی GPIO 26 و DIO روی GPIO 25.
// ESP32 pins connected to the TM1637 module #define CLK 26 #define DIO 25
یک شیء به نام display از کلاس TM1637Display ساخته میشود که فرمانهای لازم برای نمایش عدد و کنترل روشنایی را ارسال میکند.
// Create the display object TM1637Display display(CLK, DIO);
تابع connectWiFi() وظیفه اتصال ESP32 به شبکه را بر عهده دارد. برد ابتدا در حالت station قرار میگیرد (WiFi.mode(WIFI_STA)) تا به یک روتر موجود متصل شود، سپس اتصال را با WiFi.begin آغاز میکند و تا زمان اتصال موفق در یک حلقه با تاخیر 500 میلیثانیه وضعیت را بررسی میکند.
void connectWiFi() {
// Put Wi-Fi in station mode so ESP32 connects to a router
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
// Wait until Wi-Fi connection is established
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
} تابع syncTime() هماهنگسازی با سرور NTP را انجام میدهد. ابتدا با فراخوانی configTime(0, 0, ntpServer1, ntpServer2) سرویس NTP را راهاندازی میکنیم. دو صفر به این معناست که آفست ثابتی برای UTC اعمال نمیکنیم زیرا تبدیل منطقه زمانی بهصورت جداگانه با tzInfo انجام میشود. سپس متغیر محیطی TZ با setenv("TZ", tzInfo, 1) تنظیم شده و با tzset() اعمال میشود.
برای اطمینان از اینکه زمان معتبر دریافت شده، مقدار زمان کنونی داخلی با یک timestamp مشخص (در این مثال 1577836800 که متناظر با 1 ژانویه 2020 است) مقایسه میشود. اگر زمان داخلی کوچکتر از این مقدار باشد یعنی همگامسازی هنوز کامل نشده و حلقه تا دریافت زمان جدید به انتظار ادامه میدهد.
void syncTime() {
// Start NTP using the two servers above
configTime(0, 0, ntpServer1, ntpServer2);
// Set the timezone for your region
setenv("TZ", tzInfo, 1);
tzset();
// Wait until a valid time is received from the NTP server
// 1577836800 is the Unix time for Jan 1, 2020
time_t now = 0;
while (time(&now) < 1577836800) {
delay(500);
}
} منطق اصلی نمایش زمان در تابع displayTime() قرار دارد. یک متغیر ثابت محلی بولی به نام colonOn برای نگه داشتن وضعیت دو نقطه میانی تعریف شده که در هر بار اجرا معکوس میشود تا اثر چشمکزدن ایجاد شود.
سپس با فراخوانی getLocalTime() ساختار زمان محلی پر میشود. در صورت شکست، نمایشگر پاک شده و تابع بازمیگردد. در صورت موفقیت، ساعت و دقیقه از ساختار استخراج میشوند و با ضرب ساعت در 100 و جمع با دقیقه، عدد چهاررقمی HHMM ساخته میشود؛ برای مثال 9:05 به 905 تبدیل میشود و با فعال بودن نگهداشتن صفرهای پیشرو به صورت 0905 نمایش داده میشود.
برای کنترل روشن یا خاموش بودن کلون (colon) از یک ماسک بیت استفاده میشود و سپس مقدار و ماسک به متد showNumberDecEx ارسال میگردد.
void displayTime() {
static bool colonOn = false; // Keeps track of colon state between calls
colonOn = !colonOn; // Toggle colon each second for blinking effect
struct tm timeinfo;
if (!getLocalTime(&timeinfo, 2000)) {
display.clear(); // Clear display if time is not available
return;
}
int hours = timeinfo.tm_hour; // Current hour (0 to 23)
int minutes = timeinfo.tm_min; // Current minute (0 to 59)
// Combine hours and minutes into a 4-digit number: HHMM
// Example: 9:05 becomes 905, and leading zeros will show it as 0905
int value = hours * 100 + minutes;
// Bit mask to control the center colon on the TM1637 display
uint8_t colonMask = colonOn ? 0b01000000 : 0;
display.showNumberDecEx(
value,
colonMask, // Show or hide colon
true // Keep leading zeros, so 06:04 displays correctly
);
} در setup() مقدار روشنایی نمایشگر با setBrightness() روی 5 قرار داده میشود (محدوده 0 تا 7). سپس نمایشگر پاک شده، اتصال وایفای برقرار و همگامسازی زمان انجام میشود.
void setup() {
// Set display brightness from 0 to 7
display.setBrightness(5);
display.clear();
// Connect to Wi-Fi and get the current time
connectWiFi();
syncTime();
} در حلقه اصلی (loop()) هر ثانیه تابع نمایش زمان فراخوانی میشود تا نمایشگر بروزرسانی شود.
void loop() {
// Update the clock display every second
displayTime();
delay(1000);
} سوالات متداول
چه پینهایی باید ماژول TM1637 را به ESP32 وصل کنم؟
طبق جدول اتصال: VCC ماژول به VIN برد ESP32، GND به GND، پین DIO به GPIO 25 و پین CLK به GPIO 26 متصل میشود.
چگونه رشته منطقه زمانی (tzInfo) را تنظیم کنم؟
در کد متغیر tzInfo با یک رشته POSIX مشخص شده است؛ مثال پیشفرض “EST5EDT,M3.2.0,M11.1.0” برای US Eastern است. این رشته را باید مطابق منطقه خود تغییر دهید و فهرست رشتهها در منابعی مثل posix_tz_db قابل مشاهده است.
از چه سرورهای NTP استفاده میشود و چرا دو سرور تعریف شدهاند؟
در کد دو سرور تعریف شدهاند: pool.ntp.org به عنوان خوشه سرورهای NTP و time.nist.gov به عنوان یک پشتیبان قابل اعتماد. داشتن دو سرور کمک میکند اگر یک سرور در دسترس نباشد، سرور دوم بتواند جایگزین شود.











