Raspberry Pi Pico als analoge Uhr

Como la Raspberry Pi Pico todavía es bastante nueva para mí y necesito refrescar mis conocimientos sobre Python, siempre uso "pequeños proyectos estándar" que me permitan familiarizarme con un nuevo hardware o software. Ya lo ha visto en mi último blog Estación meteorológica con Raspberry Pi Pico y pantalla OLED y me gustaría continuar aquí construyendo un Reloj Analógico utilizando un RealTimeClock y una pantalla OLED.

Dividiré el blog en dos partes:

  1. Un RealTimeClock tipo DS3231 con puesta en marcha en la Pico.
  2. Mostrar la hora del RealTimeClock en la pantalla OLED.

El reloj debe ser capaz de distinguir entre el horario de verano y el de invierno al mismo tiempo. Se requiere un componente RTC, ya que la Raspberry Pi Pico tiene un RTC instalado internamente.

Hardware y Software requeridos

El hardware para este esquema experimental es sencillo, véase la Tabla 1.

Cantidad Hardware Anotación
1 Raspberry Pi Pico
1 0,96 pulgadas OLED SSD1306 Display 128x64 I2C
1 Placa de pruebas y Cables de Puente (Jumper Wire)
1 Reloj en Tiempo Real RTC DS3231 I2C

Alternativamente: DS1302 Reloj en Tiempo Real

Tabla 1: Piezas de hardware para el Reloj Analógico

Para el software, ya que será un programa con Micropython, utilice Thonny Python IDE, que ya está disponible con la imagen de Raspbian y se puede instalar para todos los sistemas operativos comunes.

Además, una vez instalado el Thonny Python IDE y conectada la Pico, necesitará las bibliotecas urtc y micropython-oled, que se transferirán a la Pico. También puede encontrar cómo instalar las bibliotecas en la publicación Estación meteorológica con Raspberry Pi Pico y pantalla OLED.

Puesta en marcha del RTC DS3231

En el momento en que obtiene un nuevo RTC DS3231 de nuestra tienda, o si la batería del RTC se ha agotado, entonces el RTC DS3231 debe ser reiniciado. De esto se trató en la primera parte de este blog. Para este propósito, primero se debe conectar la Raspberry Pi Pico con el RCT DS3231, véase la Figura 1.

Figura 1: Cableado RTC DS3231 con Pico

Figura 1: Cableado RTC DS3231 con Pico

Para toda la construcción, se necesitan básicamente cuatro cables y los dos componentes que se mencionaron previamente. Después, si ya ha instalado Thonny Python IDE, conecte la Raspberry Pi Pico al PC o a la Raspberry Pi y descargue las bibliotecas necesarias. En este punto, supongo que el firmware está disponible en la Pico. A continuación, cargue el código 1 en la Pico. Puede leer cómo instalar el firmware en esta guía de inicio rápido.


 """
 // leer / escribir un DS3231-RTC a través de I2C
 // y la salida al terminal de escritura
 // Autor: Joern Camino
 // Licencia: GNU GPL 3.0
 // Creado: 03. Nov 2021
 // actualización: 11 Nov 2021
 """
 
 de máquina importar Código PIN,I2C
 de uti importar dormir
 importar URTC #Lib de RTC
 
 Se necesita #init interfaz I2C
 I2c_port = 0
 I2C_SDA = Código PIN(0)
 I2C_SCL = Código PIN(1)
 I2C = I2C(I2c_port, SDA=I2C_SDA, SCL=I2C_SCL, frec=40000)
 
 #Write en direcciones encontradas Terminal
 I2cscan = I2C.escanear()
 Encimera = 0
 impresión('-----------------')
 impresión(Encontrado I2C-Dispositivos ')
 por I en I2cscan:
     impresión("Dirección I2C" + F '{Contador: 03d}' + " : "+maleficio(I).superior())
     Encimera+=1
 #Sleep (5) #make como comentario, si la fecha / hora debe ser conjunto
 #Init RTC-DS3231
 RTC = URTC.DS3231(I2C)
 Arrayday = ["Domingo","Lunes","Martes","Miércoles","Jueves","Viernes","Sábado"];
 
 "" Tiempo #Establecer de RTC
 #UNCOMMENT SÓLO PARA Establecer hora para RTC
 #Create tupla con Nueva Fecha POR EJEMPLO Miércoles 03 de noviembre 2021 07:30:00 en
 DateTime = URTC.DATETIME_TUPLE (Año = 2021, Mes = 11, día = 3,
  Día de la semana = 5, hora = 10, minuto = 34,
  Segundo = 0, Millisegundo = 0)
 RTC.DATETIMIENTE (DATETIMIENTO) #WRITE Nueva Fecha / Hora a RTC
 """#End tiempo de espera
 
 Ultimo segundo = -1
 muecero Cierto: #Infinit bucle para leer la fecha / hora
     t = Rtc.fecha y hora() # Fecha / hora de RTC
     SI Ultimo segundo != En t(t[6]): #Upado solo si las segundas cambiaron
         impresión('-----------------')
         #Print (LastSecond) #show Último segundo
         #Print (rtc.datetime ()) #show tuple con información de fecha-hora
         # Fecha y hora actuales de salida de RTC a Terminal
         impresión('Fecha:' + F '{t [2]: 02d}' + '/' + F '{t [1]: 02d}' + '/' + F '{t [0]: 02d}')
         impresión('Día:' + Arroyday[t[3]-1])
         impresión('Tiempo:' + F '{t [4]: ​​02d}'+':'+F '{t [5]: 02d}'+':'+F '{t [6]: 02d}')
         Ultimo segundo = En t(t[6])

Código 1: Configuración del RTC DS3231

Para asegurarse de que el RTC DS3231 también está ajustado, debe borrar la línea precedente ""#SET TIME FROM RTC y ""# END SET TIME"  e ingresar una nueva fecha y hora. El Día de la semana es un poco confuso en este punto porque aquí se utiliza el formato horario americano y la semana comienza con el día domingo. Por lo tanto, el domingo es 1 y el miércoles es 4 en el ejemplo. Cuando se ejecuta el script, el RTC DS3231 se reinicia. Inmediatamente después, verá la hora y la fecha actuales del RTC cada segundo en la línea de comandos, véase la Figura 2.

Figura 2: Fecha y hora actual y la hora de RTC DS3231

Figura 2: Fecha y hora actuales de RTC DS3231

Inicie la Pico nuevamente, entonces en el caso actual el tiempo se restablecerá, por lo que debe insertar el “““ de nuevo en los lugares apropiados y dejar que el código se cargue.

Mientras la batería de botón esté insertada en el RTC DS 3231 y no esté vacía, el reloj seguirá funcionando.

Reloj analógico con OLED y RTC DS3231

Ahora viene el verdadero proyecto, el reloj analógico en la pantalla OLED con el resto de la información horaria. El cableado, dado que básicamente sólo se ha agregado un componente más, no se ha complicado mucho, véase la Figura 3.

Figura 3: Visualización de cableado OLED y RTC DS3231 con Pico

Figura 3: Cableado de la pantalla OLED y el RTC DS3231 con Pico

Dado que el RTC DS3231 y la pantalla OLED se comunican con i2c, pero tienen direcciones diferentes, se pueden colocar en una línea de bus. Una vez realizado el trabajo de cableado, puede transferir el código 2 a la Pico.


 """
 // leer un DS3231-RTC a través de I2C y
 // Escribir salida al terminal y OLED
 // Autor: Joern Way
 // Licencia: GNU GPL 3.0
 // creado: 04. nov 2021
 // Actualización: 05. Nov 2021
 """
 
 de máquina importar Código PIN,I2C
 importar uti
 de Oled importar SSD1306_I2C,Gfx,Escribiendo
 de Oled.fuente importar ubuntu_mo_12, ubuntu_mo_15
 importar Urtc #Lib para rtc
 importar Matemáticas # Todo el mundo ama las matemáticas;)
 
 bprintdiag = Falso #Bool para mostrar diag de la terminal. ADVERTENCIA CONJUNTO PARA EL RENDIMIENTO DE COSTO VERDADERA
 #Init necesitado interfaz I2C
 I2c_port = 0
 I2c_sda = Código PIN(0)
 I2c_scl = Código PIN(1)
 I2C = I2C(I2c_port, Sda=I2c_sda, Scl=I2c_scl, freq=40000)
 
 #WRITE EN LA TERMINAL DIRECTORES ENCONTRADAS
 SI bprintdiag:
     I2cscan = I2C.escanear()
     Encimera = 0
     impresión('-----------------')
     impresión('Encontrado i2c-dispositivos')
     por I en I2cscan:
         impresión("Dirección I2C" + F '{Counter: 03D}' + " : "+maleficio(I).superior())
         Encimera+=1
 
 #Init rtc-ds3231
 Rtc = Urtc.DS3231(I2C)
 Arroyday = ["Domingo","Lunes","Martes","Miércoles","Jueves","Viernes","Sábado"];
 
 #DEFINICIONES Y INIT PARA PANTALLA OLED
 Ancho = 128
 Hight = 64
 Oled = SSD1306_I2C(Ancho, Hight, I2C)
 gráficos = Gfx.Gfx(Ancho,Hight,Oled.píxel)
 
 #Definiciones para el reloj
 Xcenter = 32
 Yecenter = 32
 radio = 30
 
 #Definición para la fuente
 fuente = Escribiendo(Oled,ubuntu_mo_12)
 Intro = Escribiendo(Oled,ubuntu_mo_15)
 
 "" #Set hora de RTC
 #Comentario solo para poner tiempo a RTC
 #Create tupla con fecha nueva por ejemplo. Miércoles 03 nov. 2021 07:30:00 en
 DateTime = urTC.DataTime_Tuple (Año = 2021, Mes = 11, Día = 3,
  Día de la semana = 4, hora = 7, minuto = 30,
  Segundo = 0, Millisegundo = 0)
 RTC.DATETIMIENTE (DATETIMIENTO) #WRITE Nueva Fecha / Hora a RTC
 """#End tiempo de sincronización de RTC
 
 """
 Función: calc_summer_winter_time
 Descripción: Calcular la diferencia horaria.
 Para el verano o el invierno.
 En hora: hora actual
 En minuto: minuto actual
 En segundo: Curent Second
 En el día: día actual
 En mes: mes actual
 En el año: año en curso
 """
 def Calc_summer_winter_time(hora,minuto,segundo,día,mes,año):
     Hhmarch = utime.mktime((año,3 ,(14-(En t(5*año/4+1))%7),1,0,0,0,0,0)) # Tiempo de marzo cambia a DST
     Hhnovember = utime.mktime((año,10,(7-(En t(5*año/4+1))%7),1,0,0,0,0,0)) # Tiempo de noviembre CAMBIAR A EST
     #Print (HHNovember)
     ahora=utime.mktime((año,mes,día,hora,minuto,segundo,0,0))
     
     si ahora < Hhmarch :
         dst=0
     elif ahora < Hhnovember : # Estamos antes del último domingo de octubre.
         dst=1
     demás: # estamos después del domingo pasado de octubre
         dst=0
     
     regreso(dst)
 
 """
 Función: DRAW_CLOCK
 Descripción: Dibuja el reloj analógico OLED
 En hora: hora actual
 En minuto: minuto actual
 """
 def DRAW_CLOCK(hora,minuto):
     gráficos.circulo(xcenter,eCenter,radio,1)
     gráficos.Fill_circle(xcenter,eCenter,2,1)
     oled.texto('12',25,6)
     oled.texto('3',52,30)
     oled.texto('6',29,50)
     oled.texto('9',5,28)
     Minuga = 180 - minuto * 6
     Incifre = 5 * En t(minuto/10)
     #Impresión (minuto)
     si hora>=0 y hora<=12:
         Bodega = 180 - hora * 30
     demás:
         Bodega = 180 - (hora-12) * 30
     Bodega-=Incifre
     #Print (aroma)
     #Obtain coordenadas para un mango de minuto
     Shift_min_x = 0.8 * radio * Matemáticas.pecado(Matemáticas.radianes(Minuga))
     Shift_min_y = 0.8 * radio * Matemáticas.cos(Matemáticas.radianes(Minuga))
     gráficos.línea(xcenter,eCenter,ronda(xcenter+Shift_min_x),ronda(eCenter+Shift_min_y),1)
     #Obtain coordenadas durante la manija de la hora
     Shift_hour_x = 0.6 * radio * Matemáticas.pecado(Matemáticas.radianes(Bodega))
     Shift_hour_y = 0.6 * radio * Matemáticas.cos(Matemáticas.radianes(Bodega))
     gráficos.línea(xcenter,eCenter,ronda(xcenter + Shift_hour_x),ronda(eCenter + Shift_hour_y),1)
 
 """
 Función: calc_summer_winter_time
 Descripción: Calcular la diferencia horaria.
 Para el verano o el invierno.
 En hora: hora actual
 En minuto: minuto actual
 En segundo: Curent Second
 En May: Nombre escrito
 En el día: día actual
 En mes: mes actual
 En el año: año en curso
 """
 def Print_date_time(hora,minuto,segundo,nombramiento,día,mes,año):
     ypos = 1
     yshift = 13
     XPOS = xcenter+radio+6
     fuente.texto('---Fecha---', XPOS, ypos)
     ypos+=yshift
     fuente.texto(f '{day: 02d}' + '/' + F '{mes: 02d}' + '/' + F '{Año: 02D}', XPOS, ypos)
     ypos+=yshift
     fuente.texto(F '{dayname: ^ 10}', XPOS, ypos) #Dayname en el centro
     ypos+=yshift
     fuente.texto('---Tiempo---', XPOS, ypos)
     ypos+=yshift
     fuente.texto(' ' + f '{hora: 02d}' + ':' + F '{Minuto: 02D}' + ':' + f '{segundo: 02d}', XPOS, ypos)
     
     
 ultimo segundo = -1 # Actualizar texto en OLED
 último minuto = -1 #Apdate reloj analógico
 ultima hora = -1 # Para revisar el sombrero y el invierno
 Cambio de hora = 0 # Para el verano y el invierno
 #Show una introducción en OLED durante 5 segundos
 oled.llenar(0)
 gráficos.Fill_RECT(0, 5, 128, 15, 1)
 Intro.texto("Reloj analogo", 20, 5, bgcolor=1, color=0)
 Intro.texto("(C) Joern Weise", 10, 25)
 Intro.texto("Para AZ-Entrega", 10, 45)
 oled.show()
 
 #Print intro corto en terminal
 impresión('----------------')
 impresión(f '{"reloj analógico": ^ 16}')
 impresión(F '{"(c) Joern Weise": ^ 16}')
 impresión(F '{"para AZ-Entrega": ^ 16}')
 impresión('----------------')
 
 utime.dormir(5)
 
 tiempo Cierto: #Infinit bucle para leer la fecha / hora
     t = Rtc.fecha y hora() # Fecha / hora de RTC
     si ultimo segundo != En t(t[6]): #Upado solo si los segundos cambiaron
         si ultima hora != t[4]: #Compruebe el verano o el invierno
             Cambio de hora = Calc_summer_winter_time(t[4],t[5],t[6],t[2],t[1],t[0])
             #Print ('Nuevo tiempo de tiempo:' + STR (Timeshift))
             ultima hora = t[4]
         correcto = t[4] + Cambio de hora
         # Fecha y hora actuales de salida de RTC a Terminal
         si bprintdiag:
             impresión('-----------------')
             impresión('Fecha: ' + F '{t [2]: 02d}' + '/' + F '{t [1]: 02d}' + '/' + F '{t [0]: 02d}')
             impresión('Día:' + Arroyday[t[3]-1])
             impresión('Tiempo:' + F '{Correcthour: 02d}'+':'+F '{t [5]: 02d}'+':'+F '{t [6]: 02d}')
         SI último minuto != t[5]:
             Oled.llenar(0)
             Draw_clock(Correcthour,t[5])
             último minuto = t[5]
         Print_date_time(Correcthour,t[5],t[6],Arroyday[t[3]-1],t[2],t[1],t[0])
         Oled.show()
         Ultimo segundo = En t(t[6])

Código 2: Reloj analógico con pantalla OLED y el RTC DS3231

Me gustaría explicar brevemente este código fuente en algunos puntos. En primer lugar, añadí una bandera Diag a mi código fuente bPrintDiag. Como la hora completa se imprime cada segundo en el terminal, la Pico funciona un poco lento con él. Como las salidas Diag son sólo necesarias para la depuración, las he hecho conmutables en encendido y apagado. A continuación, sigue la definición de la función Calc_Summer_Winter_Time, que comprueba si es invierno o verano. Esto devuelve el desplazamiento de la hora, que se utiliza en el bucle while como corrección de la hora del RTC DS3231. Además, para mantener el código más claro, he externalizado el dibujo del reloj analógico y la escritura del texto en la pantalla OLED a las funciones Draw_Clock y Print_Date_Time. La primera función sólo se llama cuando ha habido un cambio en los minutos, la segunda cuando ha habido un cambio en los segundos.

Draw_Clock contiene las matemáticas para dibujar las manecillas y la esfera del reloj. Como soy un fanático de que todo funcione exactamente como con un reloj analógico real, el comportamiento de la aguja de las horas también se reproduce correctamente. En el código fuente inicial, la aguja horaria era rígida en la hora actual. Esto no ocurre con un reloj analógico real, sino que se pasa a la hora siguiente poco a poco. Me di cuenta de ello calculando el ángulo de la aguja de las horas con el minuto actual. Dado que faltan algunas funciones de dibujo en la biblioteca estándar para el OLED, utilizo la biblioteca GFX para dibujar. Esto siempre llama a la función del píxel del objeto OLED para dibujar. La definición se puede encontrar al principio del código fuente, véase detrás del comentario #Definitions y init para la pantalla OLED.

Print_Date_Time escribe entonces la hora como la fecha en la parte derecha de la pantalla OLED. Como ya se ha mencionado, esto se hace cada segundo. Sin embargo, todavía hay un pequeño truco. La fuente por defecto del OLED es bastante grande, por lo que existe la fuente objeto, que se crea al principio del código fuente. Esto carga la fuente ubuntu_mono_12, que se suministra en la biblioteca micropython-oled.

El bucle while al final del código fuente hace el resto. Se encarga de los controles correspondientes. Puede ver el resultado en la Figura 4.

Figura 4: La fecha actual y la hora actual con el Pico

Figura 4: La fecha y la hora actuales con la Pico

Resumen

La Pico es todavía bastante nueva en nuestra gama de productos, por lo que muchos proyectos "antiguos" se pueden reconstruir. Especialmente en términos de microcontroladores por poco dinero, la Pico es una alternativa real a un Nano V3.0 o a la placa de microcontroladores ATmega328. La diferencia es de "sólo" 2 euros, pero en términos de principio, la Raspberry Pi Pico no es en absoluto inferior a la original.

En lo personal, cada vez estoy más entusiasmado con la Pico, especialmente por el lenguaje de scripting MicroPython. Aunque las bibliotecas para la Pico aun no son tan extensas como en el caso del Arduino IDE, hay que tener en cuenta que la Raspberry Pi Pico no se presentó hasta el 21 de enero de 2021 y que la distribución mundial del hardware también ha llevado su tiempo. La Nano V3.0 o la placa microcontrolador ATMega328 llevan mucho más tiempo en el mercado y, por lo tanto, ya se ha avanzado más en el ámbito del desarrollo de bibliotecas.

Para personalizar aun más el proyecto, podría añadir un segundero en la esfera del reloj, por ejemplo, pero éste también tendría que rediseñarse cada segundo. También puede modificar los punteros con un poco de matemáticas, como usted prefiera.

Nota: si utiliza el Módulo Reloj en Tiempo Real RTC DS3231 I2C en lugar del Módulo Reloj en tiempo real RTC DS1302 Serial, puede probar esta biblioteca de programas.

Puede encontrar más proyectos míos para AZ-Delivery en https://github.com/M3taKn1ght/Blog-Repo.

DisplaysProjekte für anfängerRaspberry pi

6 comentarios

Konrad

Konrad

Hallo,
wo kann ich die urtc Lib gerunterladen?

Mit sonnigen Grüßen,
Konrad

Gerhard Uhlhorn

Gerhard Uhlhorn

Viel interessanter wäre doch einen Zeitserver abzufragen, damit sich die Uhr selbst stellt. Das scheint aber mangels Netzwerk nicht so einfach zu sein (ich suche gerade nach so einer Möglichkeit).

Alternativ könnte man beim starten des Picos vom Rechner oder bei der Scriptübergabe vielleicht die Rechnerzeit übergeben oder bei bestehender USB-Verbindung zum Rechner die Uhrzeit des Rechners auslesen. Dann bräuchte man ihn nur 2x im Jahr kurz mal in den Rechner einstecken und er stellt sich automatisch.

Hmm, ich glaube es wird wohl doch ein Arduino mit Ethernet oder WLAN.

Slyfox

Slyfox

Hallo,
hier ein Codevorschlag für Sommer Winterzeit-berechnung für MEZ/MESZ

Function: Calculates for a given date time if it is summer or winter time (MEZ/MESZ) Methode Find the last Sunday in March and October and substract the number of Days from the end of the month until that last Sunday Input Date & Time (hour,minute,second,day,month,year) Output 0 = Wintertime 1 = Summertime
def Calc_Summer_Winter_Time(hour,minute,second,day,month,year):
HHMarch = utime.mktime((year,3,31,1,0,0,0,0,0)) # int time in sec since
HHMarch2 = utime.localtime(HHMarch) # generate tuple of time
ds = (HHMarch26 + 1)%7 # take the Day of the week 6 (int) of localtime Monday = 0, add one to make Monday the first day of the week ==> Sunday becomes 7 and with modulus 7 Sunday becomes 0
HHMarch = utime.mktime((year,3,31 – ds,1,0,0,0,0,0)) # Substract day of the week from 31 and generate time in sec since for start of summertime HHNovember = utime.mktime((year,10,31,1,0,0,0,0,0)) HHNovember2 = utime.localtime(HHNovember) dw = (HHNovember26 + 1) % 7 HHNovember = utime.mktime((year,10,31-dw,1,0,0,0,0,0)) now=utime.mktime((year,month,day,hour,minute,second,0,0)) if now < HHMarch : dst = 0 elif now < HHNovember : # we are before last sunday of october dst = 1 else: dst = 0 return(dst)
Andreas Wolter

Andreas Wolter

@Slyfox: wir schauen uns das an

@Manfred sen.: dieser Beitrag war gedacht dafür zu zeigen, wie der Pico mit den Komponenten programmiert werden kann.
Es gibt bereits ein ähnliches Projekt mit ESP32 und dem AZ-Touch Mod:
https://www.az-delivery.de/blogs/azdelivery-blog-fur-arduino-und-raspberry-pi/az-touch-mod-als-analoge-uhr-mit-anzeige-fur-sonnenauf-und-untergang

Das zeigt, wie es in der Arduino IDE programmiert werden kann.

Grüße,
Andreas Wolter

Manfred sen.

Manfred sen.

Hallo
Scheint ja ein tolles Projekt zu sein, aber leider muss man wieder eine neue Hardware kaufen und eine neue Programmiersprache lernen.
Gibt es die Möglichkeit das Projekt auch für einen Uno oä. zu schreiben?
Das wäre richtig toll.
Gruß an den Programmierer

Slyfox

Slyfox

Hallo,

nettes Projekt.
Die Sommer/Winterzeit Umschaltung ist hier aber in DST und die Formeln ergeben die amerikanischen Daten welches für die Sommerzeitumstellung der zweite Sonntag im März ist und nicht wie in Europa der letzte Sonntag im März.
USA 14.3.2021 – 7.11.2021 (1. Sonntag im November) Deutschland 28.3 – 31.10 letzter Sonntag im Oktober. Auf die Schnelle keine einfache Umstellung der Formel gefunden die für D passen würde denn der spätestens beim Übergang 2023 23.3. auf 2024 31.3 passt das nicht. Vielleicht habe ich aber auch nur den Wald vor lauter Bäumen nicht gesehen.

Deja un comentario

Todos los comentarios son moderados antes de ser publicados

Publicaciones de blog recomendadas

  1. Wir bauen eine Smart Home Zentrale mit ArduiTouch
  2. Schrittmotor Steuerung für Antennen Rotor
  3. Arbeiten mit dem Cayenne Dashboard - einfacher Sensor (Teil 1)
  4. Mit dem ESP8266 8 Lampen steuern