from machine import Pin import micropython import time micropython.alloc_emergency_exception_buf(100) # emergency exception buffer BIT_TIME = 140 # this value should be between 100 and 200, it decides between 0 and 1 MINUTE_UP = 1400 # the minute is up VALUES = [1, 2, 4, 8, 10, 20, 40, 80] WEEKDAYS = ["--", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"] CEST = ["CET", "CEST"] ledPIN = Pin(6, Pin.OUT) # onboard LED dcfPIN = Pin(26, Pin.IN) # DCF77 signal input ticks = 0 # global variables cest = 0 minute = 0 hour = 0 day = 0 weekday = 0 month = 0 year = 0 position = 0 parity = 0 # even parity in the time signal def print_dcf(arg): # Interrupts do not like serial communication, so a schedule for print(arg) # outputs is created in the interrupt and processed here, all outputs # in the interrupt are added to the schedule def callback_dcf77(channel): # this function responds to high and low changes in the input global ticks, cest, minute, hour, day, weekday, month, year, position, parity global VALUES, WEEKDAYS, CEST, BIT_TIME, MINUTE_UP ledPIN.value(dcfPIN.value()) # live update for the onboard LED _ticks = time.ticks_ms() # increasing millisecond counter len = time.ticks_diff(_ticks, ticks) # calculates the pulse length ticks = _ticks # remember the value if dcfPIN.value() == 0: # this means that the signal was high and is now low # micropython.schedule(print_dcf, len) # enable this line to see the bit length if len > BIT_TIME: # zero or one ? parity += 1 # one ! if 21 <= position <= 27: # minute minute += VALUES[position - 21] elif 29 <= position <= 34: # hour hour += VALUES[position - 29] elif 36 <= position <= 41: # day day += VALUES[position - 36] elif 42 <= position <= 44: # weekday weekday += VALUES[position - 42] elif 45 <= position <= 49: # month month += VALUES[position - 45] elif 50 <= position <= 57: # year year += VALUES[position - 50] # only the year, not the century if position == 17: cest = 1 # Central European Summertime elif position == 18: if cest == 1: # Central European Time position = 0 # Error: sets the position to 0, making the time information invalid elif position == 20: # start of encoded time, always 1 parity = 0 # reset parity for the following bits elif position == 28 or position == 35 or position == 58: if (parity % 2) != 0: # even parity ? position = 0 # Error: sets the position to 0, making the time information invalid parity = 0 # reset parity for the following bits else: # zero if position == 28 or position == 35 or position == 58: if (parity % 2) != 0: # even parity ? position = 0 # Error: sets the position to 0, making the time information invalid parity = 0 # reset parity for the following bits micropython.schedule(print_dcf, 'Bit: %d' % position) # optional # micropython.schedule(print_dcf, "Timestamp: %d-%02d-%02d %02d:%02d %s %s" % # ((year + 2000), month, day, hour, minute, # WEEKDAYS[weekday], CEST[cest])) # enable the lines above to see how the date and time evolve position += 1 # increment the bit counter else: if len > MINUTE_UP: # the minute is up, the parity bit does not allow error correction, # so some additional checks are performed if position == 59 and (0 <= minute <= 59 or 0 <= hour <= 23 or 1 <= day <= 31 or 1 <= weekday <= 7 or 1 <= month <= 12 or year >= 25): micropython.schedule(print_dcf, "Timestamp: %d-%02d-%02d %02d:%02d %s %s" % ((year + 2000), month, day, hour, minute, WEEKDAYS[weekday], CEST[cest])) else: micropython.schedule(print_dcf, "No valid timestamp") position = 0 # reset everything, preparing for the next minute cest = 0 minute = 0 hour = 0 day = 0 weekday = 0 month = 0 year = 0 parity = 0 # end of 'callback_dcf77' # the program starts here print("Start...DCF77") # 'Hello world' # define callback function and trigger dcfPIN.irq(trigger=Pin.IRQ_RISING | Pin.IRQ_FALLING, handler=callback_dcf77) while True: # endless loop time.sleep(0.2)