這是一個幾乎完整的程式,至少目前我時這麼認為,當然也有想要再改的,現在是逐一資料顯示,如果可以一次更新LCD,應該可以省下一些時間,但我覺得目前的程式易於閱讀,就不想改了。
之前的版整都是用 time.delay所以極耗資源,而且反應緩慢,後來改用 timer 如下的二行程式應該為核心程式
timer.init(period=1000, mode=Timer.PERIODIC, callback=timer_callback)
button_timer.init(period=50, mode=Timer.PERIODIC, callback=button_check)
用定時器在每一秒更新LCD螢幕上的資料,按鍵定時器隨時監測有沒有按鍵被按,在此範例中設定的按鍵有關閉LCD版光,跟時間跟網路資訊的切換。
功能說明:
1.開機時先連上網路,並進行對時。
2.第0行顯示日期、連網狀態、星期英文縮寫
3 .第1行顯示時間、溫度及溼度
4 .設定定時器為每秒顯示一次時間
5 .設定0 .1秒檢查按鈕有沒有按下,有時分辨執行GPIO14或是GPIO27內建程序
6 .主循環檢查於4:00進行時間校正,並且防止重複校正的情況發生
接腳說明:
DHT11 S訊號接 GPIO13
DHT11 +接GPIO12
GPIO14 為LCD背光按鈕
GPIO27為 顯示主機名稱及IP按鈕
1602 SDA GPIO21
1602 CSL GPIO22
附屬程式:要將lcd_api.py,i2c_lcd.py要跟主程式放在同一個目錄
#優化後ESP32_Clock_main_adam.py
import machine
import network
import ntptime
import time
from machine import Pin, SoftI2C, RTC, Timer
from lcd_api import LcdApi
from i2c_lcd import I2cLcd
import dht # DHT11 感測器模組
I2C_ADDR = 0x27
totalRows = 2
totalColumns = 16
SSID = "Bili-Net"
PASSWORD = "0932388283"
CustomHostmane = "Deimos-ESP32"#Phobos
rtc = RTC()
# 初始化網路設置
wifi = network.WLAN(network.STA_IF)
wifi.active(True)
wifi.config(dhcp_hostname=CustomHostmane)
wifi_status = False # 初始化 Wi-Fi 狀態為未連線
dht_sensor = dht.DHT11(Pin(13)) # 初始化 DHT11 感測器 (接在 GPIO13)
dht_power = Pin(12, Pin.OUT)
dht_power.value(1) # 拉高 GPIO12 提供電源
backlight_control = Pin(14, Pin.IN, Pin.PULL_UP)
gpio27 = Pin(27, Pin.IN, Pin.PULL_UP)
backlight_state = False
gpio27_state = False
debounce_time_14 = 0
debounce_time_27 = 0
pause_time_update = False
timer = Timer(0)
button_timer = Timer(1)
previous_time = None
def set_timezone():
offset = 8 * 3600 # Offset for UTC+8
now = time.time() + offset
tm = time.localtime(now)
rtc.datetime((tm[0], tm[1], tm[2], 0, tm[3], tm[4], tm[5], 0))
print('Timezone set to Taipei (UTC+8). Current RTC time:', rtc.datetime())
def connect_wifi():
global wifi_status
wifi_status = False
wifi.connect(SSID, PASSWORD)
max_attempts = 10
attempt_count = 0
while not wifi.isconnected() and attempt_count < max_attempts:
print("等待 Wi-Fi 連線... 嘗試次數:", attempt_count + 1)
time.sleep(1)
attempt_count += 1
if wifi.isconnected():
print("Wi-Fi 連線成功:", wifi.ifconfig())
wifi_status = True
#lcd.move_to(0, 0)
#lcd.putstr("WiFi Linked")
#time.sleep(0.5)
#update_display() # 在Wi-Fi連線後更新顯示
else:
print("Wi-Fi 連線失敗,已達最大嘗試次數")
def sync_time():
try:
ntptime.settime()
set_timezone()
print("時間校對完成:", time.localtime())
# update_display()
except:
print("時間校對失敗")
i2c = SoftI2C(scl=Pin(22), sda=Pin(21), freq=10000)
lcd = I2cLcd(i2c, I2C_ADDR, totalRows, totalColumns)
def debounce_control(pin, debounce_time, delay=100):
current_time = time.ticks_ms()
if pin.value() == 0 and (current_time - debounce_time > delay):
debounce_time = current_time
return True, debounce_time
return False, debounce_time
def control_backlight():
global backlight_state, debounce_time_14
triggered, debounce_time_14 = debounce_control(backlight_control, debounce_time_14)
if triggered:
backlight_state = not backlight_state
if backlight_state:
lcd.backlight_on()
else:
lcd.backlight_off()
def control_gpio27():
global gpio27_state, debounce_time_27, pause_time_update
triggered, debounce_time_27 = debounce_control(gpio27, debounce_time_27)
if triggered:
gpio27_state = not gpio27_state
pause_time_update = not pause_time_update
update_display()
def get_weekday_abbreviation(t):
weekdays = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
return weekdays[t[6]] # t[6] 是星期,其中0是星期一,6是星期日
def restore_display(date, time_str, wifi_status, temp, hum):
"""恢復顯示日期、時間、Wi-Fi 狀態以及溫溼度"""
wifi_indicator = "W" if wifi_status else "X"
weekday_abbr = get_weekday_abbreviation(time.localtime()) # 這裡用time.localtime()假定你想顯示當前星期
lcd.clear() # 只有在更新時才清除和重寫LCD
lcd.move_to(0, 0)
lcd.putstr(date + " " * (totalColumns - len(date) - 3))
lcd.move_to(totalColumns - 5, 0)
lcd.putstr(wifi_indicator)
lcd.move_to(totalColumns - 3, 0)
##### 顯示星期的縮寫######
lcd.putstr(weekday_abbr)
lcd.move_to(0, 1)
lcd.putstr(current_time) # 只顯示時間
if temp is not None and hum is not None:
lcd.putstr(time_str + " {:2d}C {:2d}%".format(temp, hum))
else:
lcd.putstr(time_str + " NaC Na%")
def update_display():
global previous_time, previous_date, previous_temp, previous_hum, previous_wifi_status
now = time.localtime()
current_date = format_date(now)
current_time = format_time(now)
weekday_abbr = get_weekday_abbreviation(now) # 獲取星期縮寫
wifi_indicator = "W" if wifi_status else "X"
if gpio27_state:
hostname, ip = get_hostname_and_ip()
lcd.clear()
lcd.move_to(0, 0)
lcd.putstr(hostname + " " * (totalColumns - len(hostname))) # 顯示 hostname
lcd.move_to(0, 1)
lcd.putstr(ip + " " * (totalColumns - len(ip)))
else:
lcd.clear()
lcd.move_to(0, 0)
lcd.putstr(current_date + " " * (totalColumns - len(current_date))) # 顯示日期
lcd.move_to(totalColumns - 5, 0)
lcd.putstr(wifi_indicator) # 顯示 Wi-Fi 狀態
lcd.move_to(totalColumns - 3, 0)
##### 顯示星期的縮寫######
#lcd.move_to(totalColumns - len(weekday_abbr) - 3, 0)
lcd.putstr(weekday_abbr)
lcd.move_to(0, 1)
lcd.putstr(current_time) # 只顯示時間
lcd.move_to(len(current_time) + 1, 1)
lcd.putstr("{:2d}C {:2d}%".format(previous_temp, previous_hum))
previous_temp = None
previous_hum = None
previous_date = None
previous_time = None
previous_wifi_status = None
previous_weekday_abbr=None
def timer_callback(timer):
global previous_time, previous_date, previous_temp, previous_hum, previous_wifi_status,previous_weekday_abbr
if not pause_time_update:
now = time.localtime()
current_time = format_time(now)
current_date = format_date(now)
temp, hum = read_dht11()
current_weekday_abbr = get_weekday_abbreviation(now)
wifi_current_status = wifi_status
# 檢查日期是否有變化並更新
if current_date != previous_date:
lcd.move_to(0, 0)
lcd.putstr(current_date + " " * (totalColumns - len(current_date)))
previous_date = current_date
# 檢查時間是否有變化並更新
if current_time != previous_time:
lcd.move_to(0, 1)
lcd.putstr(current_time)
previous_time = current_time
# 檢查Wi-Fi狀態是否有變化並更新
if wifi_current_status != previous_wifi_status:
lcd.move_to(totalColumns - 5, 0)
wifi_indicator = "W" if wifi_current_status else "W"
lcd.putstr(wifi_indicator)
previous_wifi_status = wifi_current_status
if previous_weekday_abbr != current_weekday_abbr:
lcd.move_to(totalColumns - 3, 0)
lcd.putstr(current_weekday_abbr)
previous_weekday_abbr = current_weekday_abbr
# 檢查溫濕度是否有變化並更新
if temp != previous_temp or hum != previous_hum:
lcd.move_to(len(current_time) + 1, 1)
if temp is not None and hum is not None:
lcd.putstr("{:2d}C {:2d}%".format(temp, hum))
else:
lcd.putstr("NaC Na%")
previous_temp = temp
previous_hum = hum
def button_check(timer):
control_backlight()
control_gpio27()
def format_time(t):
return "{:02}:{:02}:{:02}".format(t[3], t[4], t[5])
def format_date(t):
return "{:04}-{:02}-{:02}".format(t[0], t[1], t[2])
def get_hostname_and_ip():
if wifi.isconnected():
return wifi.config('dhcp_hostname'), wifi.ifconfig()[0]
return None, None
def read_dht11():
try:
dht_sensor.measure()
return dht_sensor.temperature(), dht_sensor.humidity()
except:
return None, None
sync_done = False
connect_wifi()
sync_time()
timer.init(period=1000, mode=Timer.PERIODIC, callback=timer_callback)
button_timer.init(period=50, mode=Timer.PERIODIC, callback=button_check)
while True:
now = time.localtime()
if now[3] == 4 and now[4] == 0 and not sync_done:
sync_time()
sync_done = True
if now[3] == 0 and now[4] == 0 and sync_done:
sync_done = False
time.sleep(0.1)
這段程式碼是一個主循環,用於在特定時間同步系統時間,並依據條件控制同步行為。這是實現定時任務的常見方法,特別是在嵌入式系統或類似應用中。以下是這段程式碼各部分的具體說明:
python
複製程式碼
while True:
now = time.localtime() # 獲取當前本地時間
# 檢查當前時間是否是早上4:00,並且是否未同步
if now[3] == 4 and now[4] == 0 and not sync_done:
sync_time() # 執行時間同步
sync_done = True # 標記已完成同步
# 檢查當前時間是否是午夜0:00,並且已經同步過
if now[3] == 0 and now[4] == 0 and sync_done:
sync_done = False # 重置同步標記以便於下一次同步
time.sleep(0.1) # 程式休眠0.1秒,以減少CPU負載
無限循環 (while True):
這是一個無限循環,使得程式能夠持續運行,不斷檢查時間並執行相應的操作。
時間獲取 (time.localtime()):
time.localtime() 函數獲取當前的本地時間,返回一個結構化時間,其中 now[3] 表示小時,now[4] 表示分鐘。
條件檢查與時間同步:
如果當前時間是早上4:00(now[3] == 4 and now[4] == 0),且之前沒有進行過同步(not sync_done),則調用 sync_time() 函數進行時間同步。同步後,設置 sync_done = True 來避免在同一分鐘內重複同步。
如果當前時間是午夜0:00(now[3] == 0 and now[4] == 0),且已經完成了之前的同步(sync_done 為 True),則重置 sync_done 為 False。這樣做是為了在下一次達到同步條件時能夠再次執行同步。
休眠 (time.sleep(0.1)):
time.sleep(0.1) 使得程式每隔0.1秒檢查一次條件,這樣可以有效減少CPU的負載,使得程式更高效地運行。
這段程式的主要目的是確保系統時間能在每天特定時間點自動同步,這對於需要保持精確時間的應用來說非常重要,特別是在可能無法手動校正時間的嵌入式系統中。