您希望在30秒內偵測到移動時不重置計時器,而是繼續累積計時。我會將邏輯修改為,當30秒內偵測到移動時,計時器會繼續累積時間,而不是重置。
建議:在訊號輸出端可以並連一顆LED串上330歐姆電阻,就可以觀測到訊號輸出端的變化,有助於在程式開發時比對功能是否正常。
根據您的描述,問題出在偵測到移動後,倒數計時還在持續進行,而當偵測到移動時,倒數計時應該立即停止,並重置相關計時器,而不應繼續倒數。
當在30秒倒數過程中再次偵測到移動時,倒數計時器(no_motion_start_time)應該被重置,而不是繼續倒數,這樣才能避免不必要的計時停止邏輯被觸發。
當偵測到移動時,應立即重置 no_motion_start_time,讓倒數計時停止。
只有當沒有偵測到移動時,才會啟動或繼續倒數計時。
在偵測到移動時,不會再顯示倒數中的訊息,避免計時錯誤。
以下是修正後的程式碼:
python
複製程式碼
# 2024/09/30-02:50
import RPi.GPIO as GPIO
import time
from datetime import datetime
# 設定 GPIO 模式為 BCM
GPIO.setmode(GPIO.BCM)
# 定義 HC-SR501 的輸出腳位
PIR_PIN = 16
# 設定 GPIO 腳位為輸入模式
GPIO.setup(PIR_PIN, GPIO.IN)
# 設定相關變數
detect_flag = False # 是否偵測到物體
start_time = 0 # 計時開始時間
timeout = 30 # 偵測間隔為30秒
interval = 3 # 偵測間隔時間,單位:秒
no_motion_start_time = None # 用於記錄無移動時的開始時間
# 設定程式結束時的清理函數
def cleanup():
GPIO.cleanup()
try:
print("PIR 模組初始化中...")
time.sleep(2) # 等待模組穩定
print("準備偵測中(按 Ctrl+C 結束)")
while True:
# 讀取當前的 PIR 狀態
current_state = GPIO.input(PIR_PIN)
if current_state:
if not detect_flag:
# 偵測到移動,開始計時
detect_flag = True
start_time = time.time()
no_motion_start_time = None # 重置無移動計時器
print("\n偵測到物體移動! 開始計時...", end="\r")
else:
# 偵測到物體移動且計時已開始,更新計時器顯示
elapsed_time = time.time() - start_time
print(f"持續偵測到物體移動! 計時... {elapsed_time:.2f} 秒", end="\r")
# 在偵測到移動時,重置無移動的計時器
no_motion_start_time = None
else:
if detect_flag and no_motion_start_time is None:
# 如果沒有偵測到移動,開始計算無移動的時間
no_motion_start_time = time.time()
print("\n未偵測到移動,開始計算30秒倒數...", end="\r")
elif no_motion_start_time is not None:
# 計算無移動的持續時間
no_motion_elapsed_time = time.time() - no_motion_start_time
if no_motion_elapsed_time >= timeout:
# 假如超過30秒未偵測到移動,則停止計時
elapsed_time = time.time() - start_time
stop_time = datetime.now().strftime('%H:%M:%S')
print(f"\n30秒內未偵測到移動。持續計時時間為:{elapsed_time:.2f} 秒,停止計時... 停止時間:{stop_time}")
detect_flag = False
no_motion_start_time = None
start_time = 0
else:
# 只有在無移動且未達到30秒時才繼續倒數
print(f"\n30秒倒數中,還剩:{timeout - no_motion_elapsed_time:.2f} 秒", end="\r")
# 每隔3秒檢查一次狀態,更新時間顯示
time.sleep(interval)
except KeyboardInterrupt:
print("\n程式結束")
finally:
cleanup()
靜態時間戳:在程式的第一行,加入一個手動更新的時間戳,例如 # 2024/09/30-02:50。您可以根據每次更新的時間手動修改這個時間戳。
格式:這個格式可以根據您習慣的方式設定,例如 # YYYY/MM/DD-HH:MM,以表示程式上一次更新的日期和時間。
位置:這行註解始終放在程式的第一行,方便日後查看和區分版本。
停止倒數計時的條件:
在倒數過程中,如果偵測到移動(current_state 為 True),no_motion_start_time 會被立即重置為 None,從而停止倒數。
倒數過程只會在 PIR 感測器偵測不到移動的情況下啟動。
顯示邏輯更新:
在倒數計時過程中,只有當 PIR 感測器未偵測到移動時才會顯示倒數提示。
當倒數結束(30秒內無移動)時,會顯示計時結束的訊息並停止計時。
如果在倒數過程中再次偵測到移動,會立即停止倒數,並繼續顯示持續偵測到物體移動的訊息。
無移動時的倒數與重置:
倒數計時開始時,會顯示剩餘秒數。
如果在倒數結束之前偵測到移動,會重置 no_motion_start_time 並停止倒數,這樣就不會發生您描述的錯誤訊息。
這樣修改後,當 PIR 偵測到移動時,倒數會停止,並且計時會繼續累積,直到再次無偵測到移動且超過30秒為止。