2025-03-27 12:22:30
import time
import board
import busio
import digitalio
import TM1637
import adafruit_ds1307
import microcontroller
import struct
# Константы
SECONDS_TO_ADD_PER_WEEK = 5
DAYS_BEFORE_ADJUSTMENT = 10
I2C_SDA_PIN = board.GP15
I2C_SCL_PIN = board.GP14
TM1637_CLK_PIN = board.GP1
TM1637_DIO_PIN = board.GP0
BEEPER_PIN = board.GP6
RTC_ADDRESS = 0x68
CHECK_ADJUSTMENT_INTERVAL = 18000 # 300 минут
HOURLY_BEEP_START_HOUR = 8
HOURLY_BEEP_END_HOUR = 22
MORSE_WPM = 27
MAIN_LOOP_DELAY = 0.9
# Инициализация I2C с обработкой ошибок
def init_i2c():
try:
i2c = busio.I2C(I2C_SDA_PIN, I2C_SCL_PIN)
print(f"I2C инициализирован на пинах SCL: {I2C_SCL_PIN}, SDA: {I2C_SDA_PIN}")
return i2c
except Exception as e:
print(f"Ошибка инициализации I2C: {e}")
return None
# Проверка доступности устройства I2C
def wait_for_i2c_device(i2c, address, timeout=5):
start_time = time.monotonic()
while time.monotonic() - start_time < timeout:
try:
i2c.try_lock()
if address in i2c.scan():
i2c.unlock()
return True
i2c.unlock()
except Exception as e:
print(f"Ошибка проверки I2C: {e}")
if i2c.locked():
i2c.unlock()
time.sleep(1)
return False
# Инициализация TM1637 с обработкой ошибок
def init_tm1637():
try:
display = TM1637.TM1637(TM1637_CLK_PIN, TM1637_DIO_PIN)
display.brightness(0)
print(f"TM1637 инициализирован на пинах CLK: {TM1637_CLK_PIN}, DIO: {TM1637_DIO_PIN}")
return display
except Exception as e:
print(f"Ошибка инициализации TM1637: {e}")
return None
# Инициализация RTC с обработкой ошибок
def init_rtc(i2c):
if i2c and wait_for_i2c_device(i2c, RTC_ADDRESS):
try:
rtc = adafruit_ds1307.DS1307(i2c)
print(f"RTC (DS1307) инициализирован по адресу {RTC_ADDRESS}")
return rtc
except Exception as e:
print(f"Ошибка инициализации RTC: {e}")
else:
print("RTC не обнаружен на шине I2C")
return None
# Инициализация beeper
def init_beeper():
try:
beep = digitalio.DigitalInOut(BEEPER_PIN)
beep.direction = digitalio.Direction.OUTPUT
print(f"Beeper инициализирован на пине {BEEPER_PIN}")
return beep
except Exception as e:
print(f"Ошибка инициализации beeper: {e}")
return None
# Morse кодирование
def morse_transmitter(beep, message, wpm=MORSE_WPM):
morse_dict = {
'0': '-----', '1': '.----', '2': '..---', '3': '...--', '4': '....-',
'5': '.....', '6': '-....', '7': '--...', '8': '---..', '9': '----.',
':': '---...',
}
dot_duration = 1.2 / wpm
for char in message:
if char in morse_dict:
for symbol in morse_dict[char]:
if symbol == '.':
beep.value = True
time.sleep(dot_duration)
beep.value = False
time.sleep(dot_duration)
elif symbol == '-':
beep.value = True
time.sleep(3 * dot_duration)
beep.value = False
time.sleep(dot_duration)
time.sleep(3 * dot_duration)
# Сигнализация времени морзянкой
def signal_time_morse(beep, rtc):
if rtc and beep:
current_time = rtc.datetime
time_str = f"{current_time.tm_hour:02}:{current_time.tm_min:02}"
morse_transmitter(beep, time_str.replace(':', ' '))
# Отображение последней коррекции времени
def display_last_adjustment(display, rtc):
if rtc and display:
last_adjustment = load_last_adjustment_date()
if last_adjustment:
last_adj_str = f"{last_adjustment.tm_year:04}-{last_adjustment.tm_mon:02}-{last_adjustment.tm_mday:02}"
print(f"Последняя коррекция: {last_adj_str}")
# Сохранение даты последней корректировки в NVM
def save_last_adjustment_date(rtc):
if rtc:
current_time = rtc.datetime
date_bytes = struct.pack('>HBB', current_time.tm_year, current_time.tm_mon, current_time.tm_mday)
microcontroller.nvm[0:4] = date_bytes
# Загрузка даты последней корректировки из NVM
def load_last_adjustment_date():
try:
date_bytes = microcontroller.nvm[0:4]
unpacked_date = struct.unpack('>HBB', date_bytes)
return time.struct_time((unpacked_date[0], unpacked_date[1], unpacked_date[2], 0, 0, 0, 0, 0, -1))
except Exception as e:
print(f"Ошибка загрузки даты корректировки: {e}")
return None
# Корректировка времени
def adjust_time(rtc, seconds_to_add):
if rtc:
current_time = rtc.datetime
time_list = list(current_time)
time_list[5] += seconds_to_add
new_time = time.struct_time(tuple(time_list))
rtc.datetime = new_time
print(f"Время скорректировано на +{seconds_to_add} секунд")
save_last_adjustment_date(rtc)
# Проверка необходимости корректировки времени
def check_time_adjustment(rtc):
if rtc:
current_time = rtc.datetime
last_adjustment = load_last_adjustment_date() or time.struct_time((2000, 1, 1, 0, 0, 0, 0, 0, -1))
days_since_last_adjustment = (time.mktime(current_time) - time.mktime(last_adjustment)) // 86400
if days_since_last_adjustment >= DAYS_BEFORE_ADJUSTMENT:
weeks_passed = days_since_last_adjustment // 7
adjust_time(rtc, weeks_passed * SECONDS_TO_ADD_PER_WEEK)
# Отображение времени на дисплее
def display_time(display, rtc):
if rtc and display:
current_time = rtc.datetime
display.show("{:02}{:02}".format(current_time.tm_hour, current_time.tm_min))
# Основная инициализация
i2c = init_i2c()
display = init_tm1637()
rtc = init_rtc(i2c)
beep = init_beeper()
# Восстановление времени при запуске
if rtc:
if not rtc.datetime.tm_year: # Проверка, что время обнулилось
last_adjustment = load_last_adjustment_date()
if last_adjustment:
rtc.datetime = last_adjustment
print("Время восстановлено из NVM")
# Проверка корректировки времени при запуске
check_time_adjustment(rtc)
# Отображение последней коррекции
display_last_adjustment(display, rtc)
# Основная петля
last_adjustment_check = time.monotonic()
hourly_beep_played = False
if rtc:
current_time = rtc.datetime
signal_time_morse(beep, rtc)
while True:
if rtc:
current_time = rtc.datetime
else:
current_time = time.localtime()
display_time(display, rtc)
# Проверка ежечасного сигнала
if current_time.tm_min == 0 and not hourly_beep_played:
if HOURLY_BEEP_START_HOUR <= current_time.tm_hour < HOURLY_BEEP_END_HOUR and beep:
signal_time_morse(beep, rtc)
hourly_beep_played = True
elif current_time.tm_min != 0:
hourly_beep_played = False
# Проверка корректировки времени
if time.monotonic() - last_adjustment_check >= CHECK_ADJUSTMENT_INTERVAL:
check_time_adjustment(rtc)
last_adjustment_check = time.monotonic()
time.sleep(MAIN_LOOP_DELAY)
Back to list