Apprenez à interfacer le module d’horloge DS3231 en temps réel avec les cartes ESP32 et ESP8266 programmées avec Micropython. Le module RTC DS3231 est un excellent module pour le chronomètre précis, il vous permet également de régler des alarmes, de sortir des ondes carrées avec différentes fréquences et d’obtenir des lectures de température. Dans ce tutoriel, vous apprendrez à définir et à obtenir le temps, à définir des alarmes et à obtenir une lecture de température.

Table des matières
Dans ce tutoriel, nous couvrirons les sujets suivants:
Nouveau sur Micropython? Consultez notre ebook: Micropython Programming avec ESP32 et ESP8266 Ebook (2e édition)
Condition préalable
Pour suivre ce didacticiel, vous avez besoin d’un micrologiciel micropython installé dans vos cartes ESP32 ou ESP8266. Vous avez également besoin d’un IDE pour écrire et télécharger le code sur votre carte. Nous suggérons d’utiliser Thonny IDE ou UpyCraft IDE:
- Thonny Ide:
- upycraft ide:
Présentation des modules d’horloge en temps réel (RTC)
Les modules RTC, tels que les DS3231 et DS1307, ont leur propre petite horloge à l’intérieur pour garder le temps par eux-mêmes. Habituellement, ils sont livrés avec un support de batterie pour connecter une batterie afin qu’ils continuent de fonctionner même si l’ESP32 / ESP8266 réinitialise ou perd de l’énergie.

Le DS3231 et le DS1307 sont quelques-uns des choix les plus populaires à utiliser avec les microcontrôleurs. Les deux sont compatibles avec ESP32 et ESP8266 et communiquent via le protocole de communication I2C. Le DS3231 est plus précis car il donne des résultats compensés par la température. De plus, il est également possible de définir des alarmes externes avec le DS3231, ce qui peut être extrêmement utile.
Présentation du module DS3231 RTC
L’image suivante montre le module RTC DS3231. Il utilise un oscillateur en cristal compensé à 32 kHz (TCXO) pour garder une trace du temps de manière précise (elle résiste aux changements de température). Pour cette raison, il vous permet également d’obtenir des données de température.

En plus de garder une trace de la date et de l’heure précisément, il a également une mémoire intégrée pour stocker jusqu’à deux alarmes et peut produire des ondes carrées à différentes fréquences: 1Hz, 4KHz, 8KHz et 32KHz.
Vous communiquez avec le module RTC à l’aide du protocole de communication I2C. Habituellement, c’est sur l’adresse 0x68.
Ce module est également livré avec un EEPROM de 32 octets 24c32 que vous pouvez utiliser pour stocker toutes les données non volatiles que vous souhaitez. Vous pouvez communiquer avec cette mémoire EEPROM via I2C en adressant la bonne adresse (0x57).
Porte-batterie DS3231
Le DS3231 est livré avec un support de batterie pour connecter une batterie pour maintenir un chronomètre précis. En cas de panne de courant, il peut toujours garder une trace du temps avec précision et garder toutes les alarmes.
Vous devez utiliser une batterie LIR2032, qui est rechargeable. N’utilisez pas un CR2032 (pas rechargeable).


Si vous souhaitez utiliser une batterie CR2032, qui n’est pas record, vous devez déconnecter le circuit de charge de la batterie en décollant et en supprimant la résistance (étiquetée R4 dans mon module) à côté de la diode.

Alarmes DS3231
Le DS3231 peut stocker jusqu’à deux alarmes: alarme 1 et alarme 2. Ces alarmes peuvent être configurées pour déclencher en fonction d’une heure et / ou d’une date spécifiques. Lorsqu’une alarme est déclenchée, la broche SQW du module sortira un signal faible.
Vous pouvez détecter ce signal avec l’ESP32 / ESP8266 et déclencher des interruptions, ou même pour le réveiller du sommeil profond. Ainsi, cette fonctionnalité est extrêmement utile pour définir un réveil périodique de sommeil profond et d’autres tâches périodiques, une automatisation temporelle et également des alertes uniques (car vous pouvez effacer une alarme après son déclenchement).
Adresse du module I2C du module RTC DS3231
Par défaut, l’adresse du DS3231 RTC est 0x68 et l’EEPROM connecté au module est 0x57. Vous pouvez exécuter un croquis du scanner I2C pour revérifier les adresses
DS3231 RTC Module Pinout
Le tableau suivant décrit rapidement la broche du module RTC DS3231.
| 32k | Sortie de l’oscillateur de 32 kHz – peut être utilisée comme référence d’horloge |
| SQW | Sortie d’onde carrée / interruption |
| SCL | Pin SCL pour I2C |
| SDA | PIN SDA pour I2C |
| VCC | Fournit de la puissance au module (3,3 V ou 5V) |
| GND | GND |

Voici une liste des pièces requises pour ce tutoriel:
Vous pouvez utiliser les liens précédents ou aller directement à makeradvisor.com/tools pour trouver toutes les pièces de vos projets au meilleur prix!

Tirez le DS3231 à la carte ESP32 ou ESP8266. Vous pouvez utiliser le tableau suivant comme référence ou jeter un œil aux diagrammes schématiques.
| Module DS3231 RTC | ESP32 | ESP8266 NODEMCU |
| SQW | GPIO 4 (ou toute autre broche numérique) | GPIO 14 (D5) (ou toute autre broche numérique) |
| SCL | GPIO 22 | GPIO 5 (D1) |
| SDA | GPIO 21 | GPIO 4 (D2) |
| VCC | 3V3 | 3V3 |
| GND | GND | GND |
ESP32

Vous pouvez également aimer: Guide pour la communication I2C avec l’ESP32
ESP8266 NODEMCU

Vous aimerez peut-être aussi: ESP8266 Référence de broche: quelles broches GPIO devriez-vous utiliser?
Travailler avec le RTC
L’utilisation d’un module RTC dans vos projets nécessite toujours deux étapes importantes.
- Définition de l’heure actuelle: vous pouvez le faire manuellement en insérant l’heure actuelle (ou un temps souhaité différent) sur le code; l’heure locale du système; ou obtenez le temps d’un serveur NTP.
- Conserver le temps: pour s’assurer que le RTC conserve le bon temps, même s’il perd l’énergie, il doit être connecté à une batterie. Les modules RTC sont livrés avec un support de batterie, généralement pour une cellule de pièces.
Module DS3231 RTC Micropython
Il existe différentes bibliothèques avec différentes fonctionnalités qui facilitent la communication avec le module RTC DS3231. Nous utiliserons une version légèrement modifiée du module urtc.py développé par AdaFruit.
Suivez les étapes suivantes pour installer le module requis.
Télécharger et télécharger l’urtc.py
- Cliquez ici pour télécharger le code urtc.py;
- Copiez le code dans un fichier sur Thonny IDE;
- Allez dans Fichier> Enregistrer sous… et sélectionnez le périphérique MicropyThon;
- Enregistrez le fichier avec le nom urtc.py (ne modifiez pas le nom).
# Forked and adapted from https://github.com/adafruit/Adafruit-uRTC/tree/master
import collections
import time
DateTimeTuple = collections.namedtuple("DateTimeTuple", ["year", "month",
"day", "weekday", "hour", "minute", "second", "millisecond"])
def datetime_tuple(year=None, month=None, day=None, weekday=None, hour=None,
minute=None, second=None, millisecond=None):
return DateTimeTuple(year, month, day, weekday, hour, minute,
second, millisecond)
def _bcd2bin(value):
return (value or 0) - 6 * ((value or 0) >> 4)
def _bin2bcd(value):
return (value or 0) + 6 * ((value or 0) // 10)
def tuple2seconds(datetime):
return time.mktime((datetime.year, datetime.month, datetime.day,
datetime.hour, datetime.minute, datetime.second, datetime.weekday, 0))
def seconds2tuple(seconds):
(year, month, day, hour, minute,
second, weekday, _yday) = time.localtime(seconds)
return DateTimeTuple(year, month, day, weekday, hour, minute, second, 0)
class _BaseRTC:
_SWAP_DAY_WEEKDAY = False
def __init__(self, i2c, address=0x68):
self.i2c = i2c
self.address = address
def _register(self, register, buffer=None):
if buffer is None:
return self.i2c.readfrom_mem(self.address, register, 1)[0]
self.i2c.writeto_mem(self.address, register, buffer)
def _flag(self, register, mask, value=None):
data = self._register(register)
if value is None:
return bool(data & mask)
if value:
data |= mask
else:
data &= ~mask
self._register(register, bytearray((data,)))
def datetime(self, datetime=None):
if datetime is None:
buffer = self.i2c.readfrom_mem(self.address,
self._DATETIME_REGISTER, 7)
if self._SWAP_DAY_WEEKDAY:
day = buffer[3]
weekday = buffer[4]
else:
day = buffer[4]
weekday = buffer[3]
return datetime_tuple(
year=_bcd2bin(buffer[6]) + 2000,
month=_bcd2bin(buffer[5]),
day=_bcd2bin(day),
weekday=_bcd2bin(weekday),
hour=_bcd2bin(buffer[2]),
minute=_bcd2bin(buffer[1]),
second=_bcd2bin(buffer[0]),
)
datetime = datetime_tuple(*datetime)
buffer = bytearray(7)
buffer[0] = _bin2bcd(datetime.second)
buffer[1] = _bin2bcd(datetime.minute)
buffer[2] = _bin2bcd(datetime.hour)
if self._SWAP_DAY_WEEKDAY:
buffer[4] = _bin2bcd(datetime.weekday)
buffer[3] = _bin2bcd(datetime.day)
else:
buffer[3] = _bin2bcd(datetime.weekday)
buffer[4] = _bin2bcd(datetime.day)
buffer[5] = _bin2bcd(datetime.month)
buffer[6] = _bin2bcd(datetime.year - 2000)
self._register(self._DATETIME_REGISTER, buffer)
class DS1307(_BaseRTC):
_NVRAM_REGISTER = 0x08
_DATETIME_REGISTER = 0x00
_SQUARE_WAVE_REGISTER = 0x07
def stop(self, value=None):
return self._flag(0x00, 0b10000000, value)
def memory(self, address, buffer=None):
if buffer is not None and address + len(buffer) > 56:
raise ValueError("address out of range")
return self._register(self._NVRAM_REGISTER + address, buffer)
class DS3231(_BaseRTC):
_CONTROL_REGISTER = 0x0e
_STATUS_REGISTER = 0x0f
_DATETIME_REGISTER = 0x00
_TEMPERATURE_MSB_REGISTER = 0x11
_TEMPERATURE_LSB_REGISTER = 0x12
_ALARM_REGISTERS = (0x08, 0x0b)
_SQUARE_WAVE_REGISTER = 0x0e
def lost_power(self):
return self._flag(self._STATUS_REGISTER, 0b10000000)
def alarm(self, value=None, alarm=0):
return self._flag(self._STATUS_REGISTER,
0b00000011 & (1 << alarm), value)
def interrupt(self, alarm=0):
return self._flag(self._CONTROL_REGISTER,
0b00000100 | (1 << alarm), 1)
def no_interrupt(self):
return self._flag(self._CONTROL_REGISTER, 0b00000011, 0)
def stop(self, value=None):
return self._flag(self._CONTROL_REGISTER, 0b10000000, value)
def datetime(self, datetime=None):
if datetime is not None:
status = self._register(self._STATUS_REGISTER) & 0b01111111
self._register(self._STATUS_REGISTER, bytearray((status,)))
return super().datetime(datetime)
def alarm_time(self, datetime=None, alarm=0):
if datetime is None:
buffer = self.i2c.readfrom_mem(self.address,
self._ALARM_REGISTERS[alarm], 3)
day = None
weekday = None
second = None
if buffer[2] & 0b10000000:
pass
elif buffer[2] & 0b01000000:
day = _bcd2bin(buffer[2] & 0x3f)
else:
weekday = _bcd2bin(buffer[2] & 0x3f)
minute = (_bcd2bin(buffer[0] & 0x7f)
if not buffer[0] & 0x80 else None)
hour = (_bcd2bin(buffer[1] & 0x7f)
if not buffer[1] & 0x80 else None)
if alarm == 0:
# handle seconds
buffer = self.i2c.readfrom_mem(
self.address, self._ALARM_REGISTERS[alarm] - 1, 1)
second = (_bcd2bin(buffer[0] & 0x7f)
if not buffer[0] & 0x80 else None)
return datetime_tuple(
day=day,
weekday=weekday,
hour=hour,
minute=minute,
second=second,
)
datetime = datetime_tuple(*datetime)
buffer = bytearray(3)
buffer[0] = (_bin2bcd(datetime.minute)
if datetime.minute is not None else 0x80)
buffer[1] = (_bin2bcd(datetime.hour)
if datetime.hour is not None else 0x80)
if datetime.day is not None:
if datetime.weekday is not None:
raise ValueError("can't specify both day and weekday")
buffer[2] = _bin2bcd(datetime.day)
elif datetime.weekday is not None:
buffer[2] = _bin2bcd(datetime.weekday) | 0b01000000
else:
buffer[2] = 0x80
self._register(self._ALARM_REGISTERS[alarm], buffer)
if alarm == 0:
# handle seconds
buffer = bytearray([_bin2bcd(datetime.second)
if datetime.second is not None else 0x80])
self._register(self._ALARM_REGISTERS[alarm] - 1, buffer)
def get_temperature(self):
"""
Reads the temperature from the DS3231's temperature registers.
Returns the temperature as a float in Celsius.
"""
msb = self._register(self._TEMPERATURE_MSB_REGISTER) # 0x11
lsb = self._register(self._TEMPERATURE_LSB_REGISTER) # 0x12
if msb is None or lsb is None:
print("Error: Register read returned None")
return None
temp = msb + ((lsb >> 6) * 0.25)
if msb & 0x80:
temp -= 256
return temp
class PCF8523(_BaseRTC):
_CONTROL1_REGISTER = 0x00
_CONTROL2_REGISTER = 0x01
_CONTROL3_REGISTER = 0x02
_DATETIME_REGISTER = 0x03
_ALARM_REGISTER = 0x0a
_SQUARE_WAVE_REGISTER = 0x0f
_SWAP_DAY_WEEKDAY = True
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.init()
def init(self):
# Enable battery switchover and low-battery detection.
self._flag(self._CONTROL3_REGISTER, 0b11100000, False)
def reset(self):
self._flag(self._CONTROL1_REGISTER, 0x58, True)
self.init()
def lost_power(self, value=None):
return self._flag(self._CONTROL3_REGISTER, 0b00010000, value)
def stop(self, value=None):
return self._flag(self._CONTROL1_REGISTER, 0b00010000, value)
def battery_low(self):
return self._flag(self._CONTROL3_REGISTER, 0b00000100)
def alarm(self, value=None):
return self._flag(self._CONTROL2_REGISTER, 0b00001000, value)
def datetime(self, datetime=None):
if datetime is not None:
self.lost_power(False) # clear the battery switchover flag
return super().datetime(datetime)
def alarm_time(self, datetime=None):
if datetime is None:
buffer = self.i2c.readfrom_mem(self.address,
self._ALARM_REGISTER, 4)
return datetime_tuple(
weekday=_bcd2bin(buffer[3] &
0x7f) if not buffer[3] & 0x80 else None,
day=_bcd2bin(buffer[2] &
0x7f) if not buffer[2] & 0x80 else None,
hour=_bcd2bin(buffer[1] &
0x7f) if not buffer[1] & 0x80 else None,
minute=_bcd2bin(buffer[0] &
0x7f) if not buffer[0] & 0x80 else None,
)
datetime = datetime_tuple(*datetime)
buffer = bytearray(4)
buffer[0] = (_bin2bcd(datetime.minute)
if datetime.minute is not None else 0x80)
buffer[1] = (_bin2bcd(datetime.hour)
if datetime.hour is not None else 0x80)
buffer[2] = (_bin2bcd(datetime.day)
if datetime.day is not None else 0x80)
buffer[3] = (_bin2bcd(datetime.weekday) | 0b01000000
if datetime.weekday is not None else 0x80)
self._register(self._ALARM_REGISTER, buffer)
Afficher le code brut
Avec le module chargé sur la carte, vous pouvez désormais utiliser les fonctionnalités de la bibliothèque dans votre code pour interfacer avec le module RTC DS3231.
DS3231 RTC: réglez et obtenez le temps avec Micropython
Le code suivant synchronise l’heure RTC avec l’heure du système et obtient la date, l’heure et la température actuelles chaque seconde.
# Rui Santos & Sara Santos - Raspberryme.com
# Complete project details at https://Raspberryme.com/micropython-esp32-esp8266-ds3231/
# Code to synchronize the RTC with the local time
import time
import urtc
from machine import I2C, Pin
days_of_week = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
# Initialize RTC (connected to I2C) - ESP32
i2c = I2C(0, scl=Pin(22), sda=Pin(21))
# Initialize RTC (connected to I2C) - uncomment for ESP8266
#i2c = I2C(scl=Pin(5), sda=Pin(4))
rtc = urtc.DS3231(i2c)
# Set the current time using a specified time tuple
# Time tuple: (year, month, day, day of week, hour, minute, seconds, milliseconds)
#initial_time = (2025, 1, 30, 1, 12, 30, 0, 0)
# Or get the local time from the system
initial_time_tuple = time.localtime() # tuple (microPython)
initial_time_seconds = time.mktime(initial_time_tuple) # local time in seconds
# Convert to tuple compatible with the library
initial_time = urtc.seconds2tuple(initial_time_seconds)
# Sync the RTC
rtc.datetime(initial_time)
while True:
current_datetime = rtc.datetime()
temperature = rtc.get_temperature()
# Display time details
print('Current date and time:')
print('Year:', current_datetime.year)
print('Month:', current_datetime.month)
print('Day:', current_datetime.day)
print('Hour:', current_datetime.hour)
print('Minute:', current_datetime.minute)
print('Second:', current_datetime.second)
print('Day of the Week:', days_of_week[current_datetime.weekday])
print(f"Current temperature: {temperature}°C")
# Format the date and time
formatted_datetime = (
f"{days_of_week[current_datetime.weekday]}, "
f"{current_datetime.year:04d}-{current_datetime.month:02d}-{current_datetime.day:02d} "
f"{current_datetime.hour:02d}:{current_datetime.minute:02d}:{current_datetime.second:02d} "
)
print(f"Current date and time: {formatted_datetime}")
print(" \n");
time.sleep(1)
Afficher le code brut
Comment fonctionne le code
Jetons un coup d’œil aux parties pertinentes de ce code.
Bibliothèques d’importation
Tout d’abord, vous devez importer le module URTC que vous avez téléchargé précédemment qui contient les fonctions pour interagir avec le RTC. Vous devez également importer les classes PIN et I2C pour établir une communication I2C avec le module.
import time
import urtc
from machine import I2C, Pin
Initialiser le module RTC
Ensuite, initialisez la communication I2C et créez un objet appelé RTC pour faire référence à notre module RTC DS3231. Nous utilisons les broches I2C par défaut ESP32 et ESP8266.
# Initialize RTC (connected to I2C) - ESP32
i2c = I2C(0, scl=Pin(22), sda=Pin(21))
# Initialize RTC (connected to I2C) - uncomment for ESP8266
#i2c = I2C(scl=Pin(5), sda=Pin(4))
rtc = urtc.DS3231(i2c)
Si vous utilisez l’ESP32, créez l’objet I2C comme suit:
i2c = I2C(0, scl=Pin(22), sda=Pin(21))
Si vous utilisez un ESP8266, vous créez un objet I2C comme suit:
i2c = I2C(scl=Pin(5), sda=Pin(4))
Synchroniser l’heure
Pour synchroniser le temps RTC, vous devez utiliser la méthode DateTime () sur l’objet RTC et passer comme argument un tuple de temps avec le format suivant:
(year, month, day, day of week, hour, minute, seconds, milliseconds)
Remarque: Ce tuple est différent de celui utilisé par le module temporel micropopython.
Nous pouvons définir l’heure manuellement sur une date et une heure définies comme suit:
#initial_time = (2025, 1, 30, 1, 12, 30, 0, 0)
Ou, nous pouvons synchroniser le RTC avec l’heure locale du système. Nous synchroniserons l’heure avec l’heure locale du système.
Tout d’abord, nous obtenons l’heure du tuple de l’heure locale en utilisant Time.Localtime ().
initial_time_tuple = time.localtime() # tuple (microPython)
Le tuple retourné est différent de celui utilisé par le module URTC.
Donc, d’abord, nous le convertissons en secondes en utilisant Time.mktime ().
initial_time_seconds = time.mktime(initial_time_tuple) # local time in seconds
Et enfin, nous le convertissons en tuple compatible avec la bibliothèque en utilisant la fonction seconds2Tuple () de la bibliothèque URTC qui accepte comme argument le nombre de secondes depuis l’époque pour l’heure locale.
initial_time = urtc.seconds2tuple(initial_time_seconds)
Enfin, nous pouvons transmettre notre variable initial_time qui contient le temps local dans un tuple compatible avec le module URTC à la fonction DateTime () comme suit.
# Convert to tuple compatible with the library
initial_time = urtc.seconds2tuple(initial_time_seconds)
# Sync the RTC
rtc.datetime(initial_time)
Remarque: Après avoir réglé l’heure pour la première fois, nous n’avons besoin de redémarrer l’heure que si le RTC perd l’énergie (vous devriez avoir une batterie connectée pour éviter cela). Vous pouvez utiliser la fonction Lost_power () sur l’objet RTC pour vérifier s’il a perdu de l’énergie. Cette fonction renvoie vrai ou faux en conséquence.
Obtenir le temps
Après ces lignes de code, le module RTC est synchronisé avec votre heure locale et vous pouvez simplement appeler RTC.DateTime () pour obtenir l’heure actuelle du RTC. Cela renvoie un objet avec tous les éléments de temps.
Pour obtenir et imprimer à chaque élément, nous pouvons faire comme suit:
current_datetime = rtc.datetime()
print('Current date and time:')
print('Year:', current_datetime.year)
print('Month:', current_datetime.month)
print('Day:', current_datetime.day)
print('Hour:', current_datetime.hour)
print('Minute:', current_datetime.minute)
print('Second:', current_datetime.second)
print('Day of the Week:', days_of_week[current_datetime.weekday])
Nous pouvons également obtenir la température actuelle du module en appelant la méthode get_Temperature () sur l’objet RTC.
temperature = rtc.get_temperature()
Les données de température sont disponibles en degrés Celsius.
print(f"Current temperature: {temperature}°C")
Nous imprimons le temps et la température du courant chaque seconde.
time.sleep(1)
Exécuter le code
Exécutez ce code précédent pour synchroniser le temps RTC avec l’heure locale et obtenir l’heure et la température actuelles.

À partir de maintenant, si le RTC a une batterie attachée, il gardera le temps synchronisé avec votre heure locale. Ainsi, vous n’avez plus besoin de le synchroniser, et vous pouvez simplement appeler rtc.DateTime () pour obtenir l’heure actuelle.

DS3231 avec ESP32 / ESP8266 – Réglage des alarmes
Le module RTC DS3231 vous permet de configurer jusqu’à deux alarmes: alarme 1 et alarme 2. Nous pouvons vérifier le changement sur cette broche et effectuer une certaine tâche lorsque l’alarme tire.

Notes importantes sur les alarmes:
- Le RTC vous permet d’économiser jusqu’à deux alarmes;
- Vous ne pouvez avoir qu’une seule alarme active à la fois;
- Une fois qu’une alarme est déclenchée, vous devez effacer son drapeau pour éviter de déclencher et de planter l’ESP32 / ESP8266;
- Vous devez désactiver une alarme avant d’activer l’autre.
DS3231 – Configuration des alarmes
L’exemple suivant montre comment configurer deux alarmes. Il bascule la LED embarquée lorsque l’alarme tire.
# Rui Santos & Sara Santos - Raspberryme.com
# Complete project details at https://Raspberryme.com/micropython-esp32-esp8266-ds3231/
import time
import urtc
from machine import Pin, I2C
# Pin setup for SQW pin and LED
CLOCK_INTERRUPT_PIN = 4 # Adjust to your specific GPIO pin for SQW (ESP32)
#CLOCK_INTERRUPT_PIN = 14 # Adjust to your specific GPIO pin for SQW (ESP8266)
LED_PIN = 2 # Adjust to your specific GPIO pin for the LED
# Initialize RTC (connected to I2C) - ESP32
i2c = I2C(0, scl=Pin(22), sda=Pin(21))
# Initialize RTC (connected to I2C) - uncomment for ESP8266
#i2c = I2C(scl=Pin(5), sda=Pin(4))
rtc = urtc.DS3231(i2c)
# Setup GPIO for SQW and LED
sqw_pin = Pin(CLOCK_INTERRUPT_PIN, Pin.IN, Pin.PULL_UP)
led_pin = Pin(LED_PIN, Pin.OUT)
led_pin.off()
# Alarm times (year, month, day, weekday, hour, minute, second, millisecond)
alarm1_time = urtc.datetime_tuple(2025, 01, 02, None, 14, 58, 00, 0) # Alarm 1 uses full datetime
alarm2_time = urtc.datetime_tuple(2025, 01, 02, None, 14, 59, 00, 0) # Alarm 2 uses day, hour, minute, weekday
# Print the current time from the RTC
def print_current_time():
now = rtc.datetime()
formatted_time = f"{now.year}-{now.month:02}-{now.day:02} {now.hour:02}:{now.minute:02}:{now.second:02}"
print(f"Current time: {formatted_time}")
#Callback for handling alarm interrupt.
def on_alarm(pin):
print("Interrupt detected.")
if rtc.alarm(alarm=0): # Check if Alarm 1 triggered
print("Alarm 1 triggered.")
rtc.alarm(False, alarm=0) # Clear Alarm 1 flag
led_pin.value(not led_pin.value()) # Toggle LED for Alarm 1
if rtc.alarm(alarm=1): # Check if Alarm 2 triggered
print("Alarm 2 triggered.")
rtc.alarm(False, alarm=1) # Clear Alarm 2 flag
led_pin.value(not led_pin.value()) # Toggle LED for Alarm 2
# Setup alarms on the DS3231
def setup_alarms():
# Clear any existing alarms
rtc.alarm(False, 0)
rtc.alarm(False, 1)
rtc.no_interrupt()
# Set the desired alarm times
rtc.alarm_time(alarm1_time, 0) # Alarm 1
rtc.alarm_time(alarm2_time, 1) # Alarm 2
# Enable interrupts for the alarms
rtc.interrupt(0)
rtc.interrupt(1)
print("Alarms set successfully.")
# Attach the interrupt callback
sqw_pin.irq(trigger=Pin.IRQ_FALLING, handler=on_alarm)
try:
# Sync time to compile time if RTC lost power
if rtc.lost_power():
initial_time_tuple = time.localtime() # tuple (MicroPython)
initial_time_seconds = time.mktime(initial_time_tuple) # local time in seconds
initial_time = urtc.seconds2tuple(initial_time_seconds) # Convert to tuple compatible with the library
rtc.datetime(initial_time) # Sync the RTC
print("RTC initialized. Setting alarms...")
setup_alarms()
while True:
print_current_time()
time.sleep(5)
except KeyboardInterrupt:
print("Exiting program.")
Afficher le code brut
Comment fonctionne le code?
Jetons un coup d’œil aux parties pertinentes du code pour configurer les alarmes.
Définir les broches
Tout d’abord, vous devez définir le GPIO qui est connecté à la broche SQW. Il s’agit de la broche qui changera d’état lorsque les alarmes se déclencheront. Si vous utilisez un ESP32, nous définissons GPIO 4. Pour l’ESP8266, nous définissons GPIO 14. Vous pouvez choisir toutes les autres broches tant que les connexions de circuit correspondent.
CLOCK_INTERRUPT_PIN = 4 # Adjust to your specific GPIO pin for SQW (ESP32)
#CLOCK_INTERRUPT_PIN = 14 # Adjust to your specific GPIO pin for SQW (ESP8266)
Nous définissons la broche SQW comme une entrée avec une résistance de traction interne (car il s’agit d’une broche à bassesse active).
sqw_pin = Pin(CLOCK_INTERRUPT_PIN, Pin.IN, Pin.PULL_UP)
Temps d’alarme
Ensuite, nous créons deux variables de type datetime_tuple pour enregistrer les temps d’alarme dans les variables comme suit:
# Alarm times (year, month, day, weekday, hour, minute, second, millisecond)
alarm1_time = urtc.datetime_tuple(2025, 01, 02, None, 14, 44, 00, 0) # Alarm 1 uses full datetime
alarm2_time = urtc.datetime_tuple(2025, 01, 02, None, 14, 46, 00, 0) # Alarm 2 uses day, hour, minute, weekday
Ajustez les alarmes à votre temps souhaité.
Définition de la broche SQW comme interruption
Ensuite, nous définissons la broche SQW en tant qu’interruption en appelant la méthode irq ().
sqw_pin.irq(trigger=Pin.IRQ_FALLING, handler=on_alarm)
La méthode irq () accepte les arguments suivants:
- Handler: Il s’agit d’une fonction qui sera appelée lorsqu’une interruption sera détectée, dans ce cas, la fonction on_alarm ().
- Trigger: cela définit le mode de déclenchement. Il y a 3 conditions différentes. Dans notre cas, nous utiliserons IRQ_FALLING pour déclencher l’interruption chaque fois que la broche passe de haut à bas.
Pour en savoir plus sur la définition des interruptions avec l’ESP32 / ESP8266 à l’aide de Micropython, vérifiez le tutoriel suivant: Micropython: Interruptions avec ESP32 et ESP8266
Fonction ON_ALARM
La fonction ON_ALARM vérifie quelle alarme a été déclenchée et désactive cette alarme pour effacer son drapeau. Cette fonction sera appelée lorsqu’une alarme tirera.
def on_alarm(pin):
La ligne suivante vérifie si Alarm1 a été déclenché. Cela nous permet de désactiver juste après son déclenchement et d’exécuter également une tâche spécifique à un moment déterminé.
if rtc.alarm(alarm=0): # Check if Alarm 1 triggered
print("Alarm 1 triggered.")
rtc.alarm(False, alarm=0) # Clear Alarm 1 flag
led_pin.value(not led_pin.value()) # Toggle LED for Alarm 1
Cette ligne efface l’indicateur Alarm1 (pour le réinitialiser à son état initial).
rtc.alarm(False, alarm=0) # Clear Alarm 1 flag
Ensuite, nous basculons l’état de la LED.
led_pin.value(not led_pin.value()) # Toggle LED for Alarm 1
Nous agissons de la même manière pour l’alarme2.
if rtc.alarm(alarm=1): # Check if Alarm 2 triggered
print("Alarm 2 triggered.")
rtc.alarm(False, alarm=1) # Clear Alarm 2 flag
led_pin.value(not led_pin.value()) # Toggle LED for Alarm 2
Configuration des alarmes
Nous créons une fonction appelée setup_alarms () pour configurer les alarmes.
Pour configurer les alarmes, nous devons d’abord effacer toutes les alarmes existantes précédentes comme suit.
def setup_alarms():
# Clear any existing alarms
rtc.alarm(False, 0)
rtc.alarm(False, 1)
rtc.no_interrupt()
Ensuite, nous pouvons définir les temps d’alarme en appelant la méthode alarm_time () sur l’objet RTC. Passez en arguments le temps d’alarme (une variable de type DateTime_Tuple) et le numéro d’alarme (0 = Alarm1; 1 = Alarm2).
# Set the desired alarm times
rtc.alarm_time(alarm1_time, 0) # Alarm 1
rtc.alarm_time(alarm2_time, 1) # Alarm 2
Nous activons l’interruption pour les alarmes, de sorte que la broche SQW est déclenchée lorsqu’une alarme se déclenche.
rtc.interrupt(0)
rtc.interrupt(1)
Ensuite, nous avons une déclaration d’essai qui ajustera l’heure du RTC si nécessaire (s’il a perdu de l’énergie) et configurera les alarmes.
try:
# Sync time to compile time if RTC lost power
if rtc.lost_power():
initial_time_tuple = time.localtime() # tuple (MicroPython)
initial_time_seconds = time.mktime(initial_time_tuple) # local time in seconds
initial_time = urtc.seconds2tuple(initial_time_seconds) # Convert to tuple compatible with the library
rtc.datetime(initial_time) # Sync the RTC
print("RTC initialized. Setting alarms...")
setup_alarms()
Ensuite, nous imprimerons constamment l’heure actuelle toutes les cinq secondes.
while True:
print_current_time()
time.sleep(5)
La détection des alarmes se fait en arrière-plan car nous avons configuré une interruption sur la broche SQW.
Tester les alarmes
Réglez les alarmes sur un gros plan afin que vous puissiez les voir en action. Ensuite, exécutez le code.

L’heure actuelle sera imprimée dans la coquille toutes les cinq secondes. Lorsque l’alarme tirera, vous obtiendrez un message sur la coque et la LED embarquée de l’ESP32 ou ESP8266 basculera.

DS3231 – Configuration des alarmes périodiques
Pour configurer des alarmes périodiques, nous pouvons ajuster le temps d’alarme chaque fois qu’une alarme est déclenchée. Par exemple, imaginez que vous souhaitez déclencher une alarme toutes les 10 minutes. Pour ce faire:
- Lisez l’heure actuelle lorsque l’alarme est déclenchée;
- Configurez une nouvelle alarme en ajoutant 600 secondes (10 minutes) à l’heure actuelle;
- Après 10 minutes, l’alarme sera déclenchée;
- Répétez les étapes précédentes.
C’est exactement ce que nous implémenterons dans l’exemple suivant.
# Rui Santos & Sara Santos - Raspberryme.com
# Complete project details at https://Raspberryme.com/micropython-esp32-esp8266-ds3231/
from machine import Pin, I2C
import time
import urtc
# Pin setup for SQW pin and LED
CLOCK_INTERRUPT_PIN = 4 # Adjust to your specific GPIO pin for SQW (ESP32)
#CLOCK_INTERRUPT_PIN = 14 # Adjust to your specific GPIO pin for SQW (ESP8266)
LED_PIN = 2 # Adjust to your specific GPIO pin for the LED
# Initialize RTC (connected to I2C) - ESP32
i2c = I2C(0, scl=Pin(22), sda=Pin(21))
# Initialize RTC (connected to I2C) - uncomment for ESP8266
#i2c = I2C(scl=Pin(5), sda=Pin(4))
rtc = urtc.DS3231(i2c)
# Setup GPIO for SQW and LED
sqw_pin = Pin(CLOCK_INTERRUPT_PIN, Pin.IN, Pin.PULL_UP)
led_pin = Pin(LED_PIN, Pin.OUT)
led_pin.off()
# Add minutes to a datetime tuple and return a new datetime tuple
def add_minutes_to_time(dt, minutes):
timestamp = time.mktime((dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, 0, 0))
new_timestamp = timestamp + (minutes * 60)
new_time = time.localtime(new_timestamp)
return urtc.datetime_tuple(new_time[0], new_time[1], new_time[2], None, new_time[3], new_time[4], new_time[5], 0)
# Print the current time from the RTC
def print_current_time():
now = rtc.datetime()
formatted_time = f"{now.year}-{now.month:02}-{now.day:02} {now.hour:02}:{now.minute:02}:{now.second:02}"
print(f"Current time: {formatted_time}")
# Callback for handling alarm interrupt
def on_alarm(pin):
print("Alarm triggered! Toggling the LED.")
led_pin.value(not led_pin.value()) # Toggle the LED
# Clear the alarm flag and schedule the next alarm
if rtc.alarm(alarm=0): # Check if Alarm 0 triggered
print("Clearing Alarm 0 flag.")
rtc.alarm(False, alarm=0) # Clear alarm flag
# Schedule the alarm to repeat 10 minutes from now
now = rtc.datetime()
next_alarm_time = add_minutes_to_time(now, 10) # Add 10 minutes
rtc.alarm_time(next_alarm_time, alarm=0) # Set new alarm
rtc.interrupt(0) # Ensure Alarm 0 interrupt is enabled
print(f"Next alarm set for: {next_alarm_time}")
def setup_alarm():
# Clear any existing alarms
rtc.alarm(False, 0)
rtc.no_interrupt()
# Get the current time and set the first alarm 1 minute from now
now = rtc.datetime()
first_alarm_time = add_minutes_to_time(now, 1) # Set first alarm for 1 minute from now
rtc.alarm_time(first_alarm_time, alarm=0) # Alarm 0
# Enable the interrupt for Alarm 0
rtc.interrupt(0)
print(f"Alarm set for: {first_alarm_time}")
# Attach the interrupt callback
sqw_pin.irq(trigger=Pin.IRQ_FALLING, handler=on_alarm)
try:
# Sync time to compile time if RTC lost power
if rtc.lost_power():
initial_time_tuple = time.localtime() # tuple (MicroPython)
initial_time_seconds = time.mktime(initial_time_tuple) # local time in seconds
initial_time = urtc.seconds2tuple(initial_time_seconds) # Convert to tuple compatible with the library
rtc.datetime(initial_time) # Sync the RTC
print("RTC initialized. Setting up the periodic alarm...")
setup_alarm()
while True:
print_current_time()
time.sleep(5)
except KeyboardInterrupt:
print("Exiting program.")
Afficher le code brut
Dans cet exemple, nous créons une fonction appelée add_minutes_to_time () qui ajoutera des minutes à l’heure actuelle.
# Add minutes to a datetime tuple and return a new datetime tuple
def add_minutes_to_time(dt, minutes):
timestamp = time.mktime((dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, 0, 0))
new_timestamp = timestamp + (minutes * 60)
new_time = time.localtime(new_timestamp)
return urtc.datetime_tuple(new_time[0], new_time[1], new_time[2], None, new_time[3], new_time[4], new_time[5], 0)
Cette fonction accepte comme arguments un tupple DateTime (comme l’heure actuelle) et les minutes que vous souhaitez ajouter à l’heure actuelle pour configurer une nouvelle alarme à l’avenir. Cette fonction renvoie un nouveau tuple DateTime avec le nouveau temps d’alarme.
Lorsqu’une alarme est déclenchée, la fonction on_alarm () s’exécutera. Il basculera d’abord l’état de la LED embarquée.
# Callback for handling alarm interrupt
def on_alarm(pin):
print("Alarm triggered! Toggling the LED.")
led_pin.value(not led_pin.value()) # Toggle the LED
Ensuite, il désactivera (effacer l’indicateur pour Alarm1).
if rtc.alarm(alarm=0): # Check if Alarm 0 triggered
print("Clearing Alarm 0 flag.")
rtc.alarm(False, alarm=0) # Clear alarm flag
Après cela, il mettra en place un nouveau temps d’alarme en ajoutant un nombre prédéfini de minutes à l’heure actuelle. Dans cet exemple, nous configurons une alarme toutes les 10 minutes
# Schedule the alarm to repeat 10 minutes from now
now = rtc.datetime()
next_alarm_time = add_minutes_to_time(now, 10) # Add 10 minutes
rtc.alarm_time(next_alarm_time, alarm=0) # Set new alarm
rtc.interrupt(0) # Ensure Alarm 0 interrupt is enabled
print(f"Next alarm set for: {next_alarm_time}")
Vous pouvez facilement changer cela en vous ajustant au temps souhaité sur la ligne suivante.
next_alarm_time = add_minutes_to_time(now, 10) # Add 10 minutes
Test des alarmes périodiques
Réglez les alarmes sur un gros plan afin que vous puissiez les voir en action. Ensuite, exécutez le code.

La première alarme se déclenche après une minute. Les alarmes suivantes se déclencheront toutes les 10 minutes. Lorsqu’une alarme est déclenchée, nous basculons également l’état de la LED embarquée.

Emballage
Dans ce tutoriel, vous avez appris à interfacer le module RTC DS3231 avec les cartes ESP32 et ESP8266 programmées avec Micropython pour obtenir la date et l’heure actuelles et configurer des alarmes. Ce module peut être très utile dans les projets de journalisation des données, l’automatisation, les tâches périodiques et plus encore.
Nous espérons que vous avez trouvé ce guide rapide utile. Nous avons des guides pour d’autres capteurs et modules que vous pouvez trouver utiles:
Pour en savoir plus sur Micropython, consultez nos ressources:
Merci d’avoir lu.
Plongez dans l’histoire de Raspberry Pi avec cette vidéo :

-
3X Real Time Clock, Modules d'Horloge Temps Réel Haute Précision, Compatibles avec Montre en Temps Réel I2C RTC DS3231, Module Precision Real Time Clock Module Compatible avec Arduino et Raspberry Pi
-
TECNOIOT 2xpcs DS3231 AT24C32 IIC Module Precision Clock for Arduino | 2xpcs I2C Module Minuscule DS3231 AT24C32 Précision Module Horloge Temps Réel pour Arduino
