MicroPython: Funções, temporizadores e interrupções relacionadas ao tempo no ESP8266 e ESP32

MicroPython: funciones relacionadas con el tiempo, temporizadores e interrupciones en ESP8266 y ESP32

Los temporizadores son una de las características de hardware comunes en todos los microcontroladores. Los temporizadores y las interrupciones del temporizador son de gran utilidad en aplicaciones de microcontroladores. Las interrupciones del temporizador se utilizan a menudo cuando se requiere una sincronización precisa sin una fracción de error. Todos los puertos MicroPython tienen uno o más temporizadores. Algunos de estos temporizadores se pueden reservar para funciones específicas, como redes o Wi-Fi, mientras que el resto de los temporizadores se pueden utilizar en la aplicación del usuario. Este artículo explorará los temporizadores y la implementación de interrupciones del temporizador en MicroPython. A continuación, veremos los temporizadores disponibles en ESP8266 y ESP32. Finalmente, usaremos los conceptos mencionados anteriormente para diseñar un ticker ESP8266.

Funciones relacionadas con el tiempo de MicroPython
MicroPython proporciona un módulo de temporización para retrasos, intervalos y mantenimiento de fecha y hora. Este módulo es una reimplementación de un módulo CPython del mismo nombre. Las funciones relacionadas con el tiempo de MicroPython admiten puertos integrados, que utilizan la época de 2000-01-01 00:00:00 UTC en lugar de la época de los sistemas POSIX de 1970-01-01 00:00:00 UTC. Es importante tener en cuenta que la configuración y el mantenimiento de la hora del calendario dependen del sistema operativo o RTOS instalado en el puerto compatible, como en Raspberry Pico. Un RTC integrado puede gestionar esto en el caso de puertos de microcontrolador. Las funciones relacionadas con el tiempo de MicroPython consultan el sistema operativo/RTOS o RTC para mantener o configurar la fecha y la hora. La configuración de la hora se puede realizar manualmente mediante un protocolo de red o una batería de respaldo.

El módulo de hora proporciona las siguientes funciones relacionadas con la hora, la fecha y el retraso.

time.sleep(segundos) : este método de bloqueo proporciona un retraso en segundos. Algunos puertos le permiten especificar el tiempo de retraso como un número de punto flotante. Una vez que se llama al método, el controlador deja de ejecutar el programa de usuario durante el número de segundos definido.

tempo.sleep_ms(ms) : este es otro método de bloqueo que proporciona un retraso en milisegundos. Comparado con time.sleep, este método es más preciso. Se puede pasar un número positivo o cero como argumento a este método. Si se utiliza para una interrupción del temporizador, el retraso puede extenderse hasta que se complete la ejecución de la rutina del servicio de interrupción. Si se pasa 0 como argumento, el retraso es igual al tiempo dedicado a ejecutar la rutina del servicio de interrupción.

time.sleep_us(nodes) : este es otro método de bloqueo que proporciona un retraso en microsegundos. Se puede pasar un número positivo o cero como argumento. Si se utiliza para una interrupción del temporizador, el retraso puede extenderse hasta que se complete la ejecución de la rutina del servicio de interrupción. Si se pasa 0 como argumento, el retraso es igual al tiempo dedicado a ejecutar la rutina del servicio de interrupción.

time.ticks_ms : este método devuelve el número de milisegundos pasados ​​en una referencia arbitraria. Es algo similar a la función Arduino millis. Aunque la función millis en Arduino devuelve un intervalo de tiempo en milisegundos desde la inicialización de la placa Arduino, time.ticks_ms toma un punto de tiempo arbitrario como referencia. El valor de la envolvente utilizado como rango máximo siempre está en la potencia de 2, por lo que permanece igual durante toda la implementación de MicroPython, independientemente del puerto. Se llama TICKS_PERIOD, que es igual a uno más que TICKS_MAX. Por lo tanto, una llamada a esta función siempre devuelve un valor no negativo que oscila entre 0 y TICKS_MAX inclusive, que es indicativo de los milisegundos en el rango mencionado pasados ​​en un momento arbitrario. Es importante tener en cuenta que, a diferencia de Arduino, no se permiten operadores matemáticos estándar u operadores relacionales, directamente o como argumentos de los métodos ticks_diff o ticks_add en los valores devueltos por este método o marcado según los métodos mencionados anteriormente. Estas operaciones pueden provocar un error de sintaxis (según el IDE) o resultados erróneos.

time.ticks_us : este método es similar a time.ticks_ms excepto que devuelve el tiempo transcurrido en microsegundos desde un punto arbitrario en el tiempo.

time.ticks_cpu : este método es similar a time.ticks_ms y time.ticks_us excepto que devuelve los ciclos de reloj de la CPU anteriores desde un punto arbitrario en el tiempo. Proporciona la mayor resolución posible. En lugar de ciclos de reloj, en algunos puertos se puede devolver otra unidad de mayor resolución proporcionada por un temporizador integrado. Cabe señalar que este método no está disponible para todos los puertos MicroPython. Por lo tanto, se debe consultar la documentación específica del puerto antes de utilizar este método en un script MicroPython.

time.ticks_add(ticks, delta) : este método calcula los plazos para eventos y tareas del microcontrolador. Dependiendo del tiempo, devuelve una fecha límite en milisegundos, microsegundos o ciclo de CPU , ticks_ms , time.ticks_us o time.ticks_cpu se utilizan como parámetro de ticks respectivamente. El argumento delta puede ser un argumento entero o numérico. Es igual al número de ticks, donde los ticks pueden ser milisegundos, microsegundos o ciclos de CPU definidos como fecha límite. Por ejemplo, la siguiente declaración devuelve una fecha límite de 200 milisegundos.
fecha límite = ticks_add(time.ticks_ms, 200)

La siguiente declaración devuelve una fecha límite de 100 microsegundos.
fecha límite = ticks_add(time.ticks_us, 100)

La siguiente declaración devuelve una fecha límite de 20 ciclos de CPU.
fecha límite = ticks_add(time.ticks_cpu, 20)

time.ticks_diff(ticks1, ticks2) : este método devuelve la diferencia entre dos ticks. La diferencia de ticks puede ser en milisegundos, microsegundos o ciclos de CPU, según el valor devuelto por las funciones time.ticks_ms , time.ticks_us o time.ticks_cpu se utilizan como ticks respectivamente. El valor devuelto es ticks1-ticks2, que puede variar desde -TICKS_PERIOD/2 hasta TICKS_PERIOD/2 – 1. Time.ticks_diff es útil para buscar un tiempo de espera, programar una tarea integrada o calcular una fecha límite.

time.hour : este método devuelve el número de segundos transcurridos desde la época siempre que se establezca y mantenga el RTC de un puerto determinado. La época admite la incrustación y el tiempo devuelto es el número de segundos desde el 01/01/2000 a las 00:00:00 UTC. La época puede ser una referencia específica del puerto, como el tiempo desde el inicio o el reinicio en algunos puertos.

hour.time_ns : este método devuelve el número de microsegundos desde la época. Es muy útil para determinar el tiempo absoluto. El valor devuelto por este método es un número entero.

time.mktime : este método devuelve una cantidad de segundos transcurridos entre la época (es decir, 2000-01-01 00:00:00 UTC) y una hora local pasada como argumento. El método considera una tupla completa de 8 como hora local, donde la tupla está en el siguiente formato – (año, mes, día, hora, minuto, segundo, día de la semana, día del año) donde los valores de la tupla debe estar en el siguiente intervalo.

Año año en DC
mes 1~12
hoy 1~31
hora 0~23
minuto 0~59
segundo 0~59
dia de la semana 0~6 para lunes~domingo
dia del año 1~366

time.gmtime((secs)) : este método devuelve la fecha y la hora en UTC a partir de los segundos especificados como argumento. La hora devuelta es una tupla en el formato (año, mes, día, hora, minuto, segundo, día de la semana, día del año).

time.localtime((secs)) : este método devuelve la fecha y la hora en hora local, ya que los segundos se especifican como argumento. La hora devuelta es una tupla en el formato (año, mes, día, hora, minuto, segundo, día de la semana, día del año). La hora local se puede configurar según OS/RTOS o RTC.

Usando funciones de ticking
Las funciones de marcado son útiles cuando se requiere una sincronización precisa en un programa de usuario de MicroPython. Las funciones de cronometraje pueden calcular el tiempo dedicado a realizar una tarea integrada, establecer una fecha límite para una tarea integrada, establecer tiempos de espera y programar tareas integradas.

A continuación se muestra un ejemplo válido de cómo calcular el tiempo dedicado a ejecutar una parte del script MicroPython.
tiempo de importación
inicio = hora.ticks_us
… Declaraciones #MicroPython para pruebas de tiempo
print(time.ticks_diff(time.ticks_us, inicio))

El siguiente es un ejemplo válido de cómo encontrar TICKS_MAX para un puerto determinado.
imprimir(ticks_add(0, -1))

El siguiente es un ejemplo válido de cómo establecer una fecha límite para una tarea integrada.
fecha límite = ticks_add(time.ticks_ms, 200)
mientras ticks_diff(fecha límite, time.ticks_ms) > 0:
hacer_un_poco_de_algo

El siguiente es un ejemplo válido de búsqueda de un evento cronometrado.
inicio = hora.ticks_us
mientras pin.valor == 0:

si time.ticks_diff(time.ticks_us, inicio) > 500:
generar error de tiempo de espera

A continuación se muestra un ejemplo válido de programación de tareas integradas utilizando funciones de tictac.
ahora = tiempo.ticks_ms
tiempo_programado = tarea.tiempo_programado
si ticks_diff(hora_programada, ahora) == 0:
print(“¡Es hora de ejecutar la tarea!”)
tarea.ejecutar

Problema con funciones relacionadas con el tiempo.
Las funciones de tictac son bastante precisas. Las funciones de marcado son útiles para calcular intervalos de tiempo, establecer tiempos de espera para eventos e incluso programar tareas. Aunque no son de bloqueo, estas funciones no se utilizan a menudo para proporcionar retrasos o programar tareas. La razón principal detrás de esto es la dependencia del módulo de sincronización de OS/RTOS o RTC. En segundo lugar, estos métodos pueden verse interrumpidos por otros eventos del microcontrolador de mayor prioridad.

Por otro lado, las funciones relacionadas con el retraso del módulo de tiempo, como time.sleep, time.sleep_ms y time.sleep_us, tienen dos problemas que vale la pena señalar. Primero, estos métodos son de naturaleza bloqueante y detienen el script cuando se los llama. En segundo lugar, estos métodos no proporcionan un retraso preciso. Por ejemplo, un retraso de unos segundos en el método time.sleep puede dar un error de unos pocos milisegundos. Estos errores pueden llegar al 1 o 2 por ciento.

En estas situaciones, los cronómetros llegan al resort. Los temporizadores tienen interrupciones de mayor prioridad que a menudo no se pueden anular excepto mediante un reinicio. Sus interrupciones utilizan hardware subyacente, es decir, los registros del temporizador que no dejan lugar a ningún error. Para establecer tiempos de espera o programar tareas integradas en las que el tiempo es crítico, las interrupciones del temporizador son las mejores opciones. Al mismo tiempo, las funciones de tick se pueden utilizar para establecer plazos o calcular el tiempo dedicado a ejecutar partes críticas del script MicroPython.

¿Qué es un cronómetro?
Cada microcontrolador tiene algunas características de hardware integradas. El temporizador/contador es uno de los periféricos integrados importantes casi presentes en todos los microcontroladores. Un temporizador/contador se utiliza para medir eventos de tiempo o funcionar como contador. Un temporizador está vinculado al reloj del sistema del microcontrolador, lo que le permite realizar un seguimiento del tiempo con alta precisión y exactitud. Puede haber varios temporizadores en un microcontrolador. Cada temporizador se configura, rastrea y controla mediante un conjunto de registros internos.

¿Qué es una interrupción del temporizador?
Una de las funciones importantes de los temporizadores es cronometrar eventos. Esto se hace con la ayuda de interrupciones del temporizador. Un evento no es más que la ejecución de un bloque de código específico en un microcontrolador. Este bloque de código está incluido dentro de la Función de Rutina de Servicio de Interrupción (ISR) . Un ISR se ejecuta cuando se genera una interrupción.

Normalmente, el microcontrolador ejecuta instrucciones de forma secuencial. Cuando se genera una interrupción, el microcontrolador omite la ejecución del código actual y ejecuta el ISR primero. Una vez que se completa el ISR, reanuda la ejecución normal del código.

Las interrupciones del temporizador se activan cuando el temporizador alcanza un conteo establecido. Un registro actualiza el recuento del temporizador, a menudo denominado registro de temporizador. Existe otro registro donde el usuario define el conteo de referencia. A esto se le suele denominar registro de comparación y coincidencia. Puede haber uno o más registros asociados con la configuración del temporizador. Existe un registro que mantiene valores de varias máscaras de interrupción. Cada vez que se activa una interrupción del temporizador, su bit de máscara correspondiente se alterna en el registro de máscara de interrupción. Al rastrear el bit de máscara de interrupción, se detecta una interrupción del temporizador. Esto puede proporcionar un retraso, establecer un tiempo de espera o programar tareas en una rutina de servicio de interrupción.

Clase de temporizador MicroPython
MicroPython proporciona una clase de temporizador para manejar temporizadores e interrupciones de temporizador de puertos admitidos. La clase de temporizador es parte del módulo de la máquina. Se importa a un script MicroPython mediante la siguiente declaración.
Importación de la máquina del temporizador

Si el puerto es WiPy, se debe utilizar la siguiente instrucción.
desde la importación de la máquina TimerWiPy

Es importante tener en cuenta que si se generan errores en la ejecución de una rutina de servicio de interrupción, MicroPython no produce un informe de error a menos que se cree un búfer especial para ello. Por lo tanto, se debe crear un búfer para la depuración cuando se utilizan interrupciones del temporizador u otras interrupciones en un script de MicroPython. El búfer se puede crear siguiendo las siguientes instrucciones.
importar micropython
micropython.alloc_emergency_exception_buf(100)

Es importante tener en cuenta que el búfer solo almacena aquí el seguimiento de la pila de excepciones más reciente. Si se produce una segunda excepción mientras el montón está bloqueado, el seguimiento de la pila de la segunda excepción sobrescribe el seguimiento original.

Después de importar la clase de temporizador, se debe crear un objeto de temporizador. Esto se hace llamando al método constructor. El método constructor tiene el siguiente prototipo.
máquina de clase. Temporizador (id, /,…)

El método constructor toma la identificación del temporizador como argumento. Puede ser un número positivo 0, 1, 2, etc., para un temporizador de hardware o -1 para un temporizador virtual, siempre que el puerto lo admita. Los otros parámetros de configuración también se pueden definir al llamar al método constructor. De lo contrario, el objeto del temporizador se puede configurar explícitamente utilizando el método timer.init . El método timer.init tiene el siguiente prototipo.
Timer.init(*, modo=Timer.PERIODIC, período=- 1, devolución de llamada=Ninguno)

El modo se puede configurar en timer.ONE_SHOT o Timer.PERIODIC. Si se establece en timer.ONE_SHOT, el temporizador solo se ejecutará una vez hasta que haya transcurrido el período especificado en milisegundos. Si se establece en timer.PERIODIC, el temporizador se ejecuta periódicamente en un intervalo en milisegundos pasado como argumento de período . El argumento period es el período de tiempo en milisegundos utilizado como tiempo de espera para ejecutar la función de devolución de llamada una vez o periódicamente, según el modo establecido. La devolución de llamada es una llamada ejecutada al final del período de tiempo. Se llama a la rutina del servicio de interrupción para realizar las tareas integradas deseadas aumentando la interrupción del temporizador. El invocable puede ser una función o incluso un método que pertenece a un objeto de clase.

La clase de temporizador le permite detener el temporizador y desactivar el temporizador periférico. Esto se hace llamando al método timer.deinit. Una llamada a este método detiene inmediatamente el temporizador si se está ejecutando, desinicializa el objeto del temporizador y desactiva el periférico del temporizador. Tiene el siguiente prototipo.
Temporizador.deinit

Si se desea reactivar un temporizador desactivado, se debe volver a crear en el programa de usuario un objeto de temporizador con el mismo ID.

Manejadores de interrupciones MicroPython
La función de devolución de llamada especificada como argumento al inicializar o crear un objeto de temporizador es la rutina del servicio de interrupción que se ejecuta cuando se activa la interrupción del temporizador. Curiosamente, MicroPython no expone la programación a nivel de registro para temporizadores. En cambio, utiliza interrupciones del temporizador para proporcionar un tiempo de espera en milisegundos. Los métodos están disponibles a través de la máquina. Los temporizadores suelen aplicarse a todos los puertos admitidos.

La función de devolución de llamada o la rutina de servicio de interrupción para objetos de temporizador requiere ciertas precauciones de programación para evitar fallas en tiempo de ejecución. Ya hemos discutido una de estas precauciones: definir un objeto de búfer para almacenar el último error de excepción. Analicemos algunas recomendaciones más para escribir controladores de interrupciones en MicroPython.

El cuerpo de una rutina de servicio de interrupción debe ser lo más breve y directo posible. Las rutinas de servicio de interrupción están destinadas a realizar acciones en las que el tiempo es crítico. Estos no deben usarse indebidamente para la programación regular de tareas integradas. Si se requiere alguna programación de tareas integrada en un script de MicroPython, se debe realizar utilizando micropython.schedule . No debería haber ningún tipo de asignación de memoria dentro de una rutina de servicio de interrupción. Evite valores de punto flotante insertándolos en diccionarios o agregando elementos a listas. Sin embargo, las variables globales se pueden actualizar en las rutinas del servicio de interrupción.

La mayoría de las plataformas de microcontroladores no permiten que las rutinas de servicio de interrupción devuelvan valores. Sin embargo, MicroPython le permite interrumpir las rutinas de servicio y devolver uno o más valores. El ISR puede devolver un valor único actualizando una variable global. Si es necesario devolver varios valores, la rutina debe actualizar una matriz de bytes preasignada. Se debe actualizar un objeto de matriz preasignado si la rutina devuelve múltiples valores enteros. Sin embargo, este intercambio de variables y objetos entre el ISR y el bucle principal puede provocar una condición de carrera, donde tanto el bucle del programa principal como la carrera del ISR cambian el valor de la variable. Por lo tanto, actualizar el valor de estas variables en el bucle principal del programa requiere especial cuidado. Antes de actualizar la variable compartida/matriz de bytes/matriz en el bucle principal del programa, las interrupciones deben deshabilitarse llamando al método de comando pyb.disable_irq . Después de actualizar la variable compartida/matriz de bytes/matriz en el programa principal, las interrupciones se pueden volver a habilitar llamando al método pyb.enable_irq .

Temporizadores en ESP8266
En ESP8266, hay dos temporizadores: timer0 y timer1. Timer0 se utiliza para funciones de red. Timer1 está disponible para su uso en ESP8266, pero MicroPython proporciona acceso a los temporizadores ESP8266. En cambio, ESP8266 proporciona una API para un temporizador virtual. Este temporizador virtual basado en RTOS tiene una identificación de -1. El siguiente es un ejemplo válido de interrupción del temporizador en ESP8266.
Importación de la máquina del temporizador
tim = Temporizador(-1)
tim.init(período=500, modo=Timer.ONE_SHOT, devolución de llamada=lambda t:print(1))
tim.init(período=200, modo=Temporizador.PERIÓDICO, devolución de llamada=lambda t:print(2))

Temporizadores en ESP32
ESP32 tiene cuatro temporizadores de hardware con ID de 0 a 3. Todos los temporizadores están disponibles para el usuario. El siguiente es un ejemplo válido de interrupciones del temporizador en ESP32.
Importación de la máquina del temporizador
tim0 = Temporizador(0)
tim0.init(período=2000, modo=Timer.ONE_SHOT, devolución de llamada=lambda t:print(0))
tim1 = Temporizador(1)
tim1.init(período=1000, modo=Temporizador.PERIÓDICO, devolución de llamada=lambda t:print(1))

Usando el temporizador ESP8266 para el teletipo LED
Usemos ahora los temporizadores MicroPython para alternar el estado de un LED.

Componentes necesarios

  1. ESP8266/ESP32x1
  2. 1 LED de 5 mm.
  3. Resistencia de 330Ω x1
  4. tablero de prueba
  5. Cables de conexión/cables de puente

Conexiones de circuito
Conecte el ánodo LED con GPIO14 de ESP8266 o ESP32. Conecte una resistencia de 330 Ω al cátodo del LED y conecte a tierra el otro extremo de la resistencia.

Encendido del LED en ESP8266 usando la interrupción del temporizador MicroPython

Secuencia de comandos MicroPython

Como funciona
El LED está conectado al GPIO14 del ESP8266 de tal manera que se ilumina cuando la placa le suministra corriente, mientras que se apaga cuando hay una señal baja del pin. El script MicroPython implementa una interrupción del temporizador cada 1 segundo, donde el estado del LED se alterna y la cantidad de parpadeos se actualiza en la consola.

Conclusión
De la discusión anterior, podemos concluir que las funciones de ticking de MicroPython son útiles para calcular tiempos de espera y establecer fechas límite para ejecutar partes del script. Las interrupciones del temporizador son útiles cuando las tareas integradas en las que el tiempo es crítico deben programarse con precisión dentro del script, independientemente de si deben ejecutarse una vez o periódicamente. Las interrupciones del temporizador son mucho más eficientes a la hora de producir retrasos e intervalos exactos.

Conteúdo Relacionado

En cada vehículo hay una red de sensores integrada...
El controlador del motor es uno de los componentes...
ESP32-CAM es un módulo de cámara compacto que combina...
La evolución de los estándares USB ha sido fundamental...
SCHURTER anuncia una mejora de su popular serie SWZ...
Visual Communications Company (VCC) ha anunciado sus nuevos tubos...
A Sealevel Systems anuncia o lançamento da Interface Serial...
A STMicroelectronics introduziu Diodos retificadores Schottky de trincheira de...
Determinar uma localização precisa é necessário em várias indústrias...
O novo VIPerGaN50 da STMicroelectronics simplifica a construção de...
A Samsung Electronics, fornecedora de tecnologia de memória avançada,...
O mercado embarcado tem uma necessidade de soluções de...
Probablemente se haya encontrado con el término " resistencia...
Probablemente tenga un aislante de soporte si ha notado...
Probablemente haya visto un aislante colocado en postes de...
Probablemente hayas visto aisladores de grillete entronizados en postes...
Probablemente hayas experimentado situaciones en las que controlar un...
Regresar al blog

Deja un comentario

Ten en cuenta que los comentarios deben aprobarse antes de que se publiquen.