BeagleBone Black(BBB)上DCF77信号读取与解码方法咨询
Hey there! Let's get your DCF77 RTC setup on the BeagleBone Black (BBB) sorted out—connecting it to UART4 is a solid choice, and we’ll walk through reading and decoding the signal step by step.
First, confirm your wiring matches this (critical to avoid damaging the BBB):
- DCF77 module output pin → BBB P9.11 (UART4_RX)
- DCF77 module GND → BBB GND (any P9/P8 GND pin, like P9.1)
- DCF77 module power → BBB 3.3V (e.g., P9.3)
Note: BBB uses 3.3V logic—never feed 5V into its pins, or you’ll fry the UART port!
By default, UART4 might not be enabled. Here's how to turn it on:
Option 1: Use config-pin (temporary, resets on reboot)
Run these commands in the terminal:
# Configure P9.11 as UART receive sudo config-pin P9.11 uart # Verify the setting config-pin -q P9.11
You should see P9.11 Mode: uart as the output.
Option 2: Persist UART4 across reboots
Edit /boot/uEnv.txt with your favorite editor (e.g., sudo nano /boot/uEnv.txt), uncomment or add this line:
cape_enable=bone_capemgr.enable_partno=BB-UART4
Save the file and reboot with sudo reboot. After restarting, check if the UART4 device node exists:
ls /dev/ttyO3
You should see /dev/ttyO3 listed (this is the device file for UART4).
First, let's confirm we can receive data from the module. We'll use Python's pyserial library for this.
Install dependencies
sudo apt update && sudo apt install python3-pip sudo pip3 install pyserial
Basic raw data reader script
Create a file named dcf77_raw.py:
import serial # Initialize UART4 connection (DCF77 typically uses 75 baud, no parity, 8 data bits, 1 stop bit) ser = serial.Serial( port='/dev/ttyO3', baudrate=75, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_1, bytesize=serial.EIGHTBITS, timeout=1 ) try: print("Reading raw DCF77 data (press Ctrl+C to stop)...") while True: data = ser.read(1) if data: # Print both hex and ASCII for debugging print(f"Raw byte: 0x{data.hex()} | ASCII: {data.decode('ascii', errors='replace')}") finally: ser.close()
Run it with python3 dcf77_raw.py. You should see a steady stream of bytes—this confirms the module is sending data to UART4.
DCF77 sends a 60-bit frame every minute, packed with date/time, parity checks, and daylight saving info. Here's a script to decode it:
Create dcf77_decoder.py:
import serial import subprocess # Initialize UART connection ser = serial.Serial('/dev/ttyO3', baudrate=75, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_1, bytesize=serial.EIGHTBITS, timeout=1) def decode_dcf77(bitstring): """Decode a 60-bit DCF77 frame into a readable datetime""" if len(bitstring) != 60: print(f"Invalid frame length: {len(bitstring)} bits") return None # --- Minute decoding + parity check --- min_units = int(bitstring[1:8], 2) min_tens = int(bitstring[8:14], 2) minute = min_tens * 10 + min_units min_parity = bitstring[14] # Check odd parity (total 1s should be odd) if bin(int(bitstring[1:14], 2)).count('1') % 2 != int(min_parity): print("Minute parity check failed") return None # --- Hour decoding + parity check --- hour_units = int(bitstring[16:21], 2) hour_tens = int(bitstring[21:23], 2) hour = hour_tens * 10 + hour_units hour_parity = bitstring[23] if bin(int(bitstring[16:23], 2)).count('1') % 2 != int(hour_parity): print("Hour parity check failed") return None # --- Date/Month/Year --- day_units = int(bitstring[25:29], 2) day_tens = int(bitstring[29:32], 2) day = day_tens * 10 + day_units weekday = int(bitstring[32:35], 2) # 1=Monday, 7=Sunday month_units = int(bitstring[35:39], 2) month_tens = int(bitstring[39:40], 2) month = month_tens * 10 + month_units year_units = int(bitstring[40:44], 2) year_tens = int(bitstring[44:48], 2) year = 2000 + (year_tens * 10 + year_units) # --- Daylight Saving Time info --- dst_active = int(bitstring[49]) # 1 = DST is currently active dst_announce = int(bitstring[48]) # 1 = DST change coming next Sunday return { 'datetime': f"{year:04d}-{month:02d}-{day:02d} {hour:02d}:{minute:02d}", 'weekday': weekday, 'dst_active': dst_active, 'dst_announce': dst_announce } try: bit_buffer = [] print("Waiting for valid DCF77 frame (press Ctrl+C to stop)...") while True: data = ser.read(1) if data: # Convert byte to bit (adjust this based on your module's output) # If your module sends 0xFF for high (1) and 0x00 for low (0): bit = '1' if ord(data) > 127 else '0' bit_buffer.append(bit) # Once we have a full 60-bit frame, decode it if len(bit_buffer) == 60: frame = ''.join(bit_buffer) decoded = decode_dcf77(frame) if decoded: print("\n--- Decoded DCF77 Time ---") print(f"Datetime: {decoded['datetime']}") print(f"Weekday: {decoded['weekday']} (1=Mon, 7=Sun)") print(f"DST Active: {'Yes' if decoded['dst_active'] else 'No'}") print(f"DST Change Coming: {'Yes' if decoded['dst_announce'] else 'No'}") # Optional: Set BBB system time (requires sudo) datetime_cmd = f"{year:04d}{month:02d}{day:02d}{hour:02d}{minute:02d}.00" subprocess.run(['sudo', 'date', '-s', datetime_cmd], check=True) print("System time updated successfully!") # Reset buffer for next frame bit_buffer = [] except KeyboardInterrupt: print("\nStopping decoder...") finally: ser.close()
Important Notes:
- Adjust the
bitconversion logic if your module outputs different values (e.g., ASCII '0'/'1' instead of raw bytes). Use the raw data reader script to confirm what your module sends. - Parity checks are critical—they filter out corrupted frames caused by signal interference.
- No data received? Check your wiring, confirm UART4 is enabled with
ls /dev/ttyO3, and ensure your DCF77 module has a good antenna (DCF77 is a German longwave signal—you’ll need a clear line of sight or indoor antenna if you’re in Europe, otherwise signal might be weak). - Parity checks failing? This means the signal is corrupted—try repositioning the antenna, or add a small delay in the script to account for timing drift.
- Permission errors? Run the script with
sudoto access UART and modify system time.
内容的提问来源于stack exchange,提问作者Ben Jo

