Saltar al contenido

Interrupción por Timer

Hola controleros y controleras, en esta entrada aprenderemos a programar los Timer con MicroPython y para eso usaremos la poderosa Raspberry Pi Pico o también el NodeMCU8266.

Antes de comenzar, te hago la invitación que aprendas a programar microcontroladores con nuestro Curso Gratuito de MicroPython.

MicroPython

Y que te suscríbas al canal si te interesa la programación de microcontroladores o la teoría del control.

Timer con Micropython

Si viste nuestra entrada anterior sobre el uso de las interrupciones con MicroPython, esta entrada te será muy familiar.

Para el uso del Timer en MicroPython se debe importar el módulo machine , que nos dará acceso a las funciones necesarias para configurar y manejar las interrupciones del temporizador o Timer del microcontrolador empleado.

import machine

o de forma selectiva

from machine import Timer

Si va a utilizar alguna variable compartida entre la función de manejo de la interrupción por timer y el código principal debe utilizar una variable global para dicho fin.

Recuerde que toda interrupción debe ejecutarse lo más rápido posible y, por lo tanto, no debemos llamar a funciones como imprimir, o retardos dentro de ella.

A continuación se crea un objeto de clase Timer , que está disponible en el módulo machine. Con este objeto se configuran las interrupciones del temporizador o Timer en el microcontrolador Raspberry Pi Pico o en el NodeMCU ESP8266.

El constructor de esta clase recibe como entrada un valor numérico de 0 a 3, que indica el temporizador de hardware que se utilizará (La Raspberry Pi Pico y el ESP32 tiene 4 temporizadores de hardware). El ESP8266 posee 2 timers. Para este ejemplo, usaremos el temporizador 0.

tim = Timer()

Ahora necesitamos declarar nuestra función de manejo de la interrupción con el nombre que nosotros queramos. 

Esta función recibe un argumento de entrada al que se le pasará un objeto de la clase Timer cuando se dispare la interrupción.

def temporizador(timer):
    #Variables globales compartidas con el main
    global contador, sentido
    #Lógica de la interrupción
    if sentido:
        contador += 1
    else:
        contador -= 1

Ahora que hemos terminado la declaración de la función de manejo, se inicia el temporizador con una llamada al método init del objeto Timer creado previamente.

Las entradas de esta función son el período en el que ocurrirá la interrupción (especificado en milisegundos), el modo del temporizador (de un disparo o periódico) y la función de llamada que manejará la interrupción.

tim.init(period= 1000, mode=Timer.PERIODIC, callback=temporizador)

Argumentos clave:

  • mode puede ser uno de:
    • Timer.ONE_SHOT – El temporizador funciona una vez hasta que expira el período configurado del canal.
    • Timer.PERIODIC – El temporizador funciona periódicamente a la frecuencia configurada del canal.
    • period – configura el periodo de la interrupción.

Cuando se modifican variables compartidas en el programa principal con la función de interrupción, se recomienda deshabilitar la interrupción, modificar la variable y posteriormente habilitar de nuevo la interrupción.

Entonces, deshabilitamos las interrupciones con una llamada a la  función disable_irq del módulo machine. Esta función devolverá el estado de IRQ anterior, que almacenaremos en una variable. 

Para volver a habilitar las interrupciones, simplemente llamamos a la  función enable_irq , también desde el módulo machine, y pasamos como entrada el estado previamente almacenado. Entre estas dos llamadas, accedemos a la variable compartida y la modificamos.

state = machine.disable_irq()
#modifica las variables globales
machine.enable_irq(state)

Ejemplo con Timer

Convertir en temporizador, el proyecto de contador que vimos en el video pasado de los displays de 7 segmentos. El temporizador debe contabilizar exactamente los números de 0-9999 cada segundo.

main.py

"""
USO DEL TIMER EN RASPBERRY PI PICO
Display 7 Segmentos usando MicroPython
Importación de nuestro propio módulo display7seg

by: Sergio Andres Castaño Giraldo
Referencia: https://controlautomaticoeducacion.com/
"""

from machine import Pin, Timer
import utime
import display7seg


def temporizador(timer):
    #Variables globales compartidas con el main
    global contador, sentido
    #Lógica de la interrupción
    if sentido:
        contador += 1
    else:
        contador -= 1
        

def main():
    global contador, sentido
    #Raspberry Pi PICO (4 digitos)
    display_pins = (16, 18, 13, 14, 15, 17, 12) #(a, b, c, d, e, f, g)
    transistor_pins = (22, 21, 20, 19)
    
    #NodeMCU 8266v3 (2 Digitos)
    #display_pins = (16, 5, 4, 0, 2, 14, 12)
    #transistor_pins = (13, 15)
    
    display7 = display7seg.Display(display_pins,transistor_pins = transistor_pins )
    
    #Inicia las variables
    contador = 0
    sentido = True
    
    tim = Timer()
    tim.init(period= 500, mode=Timer.PERIODIC, callback=temporizador)
    
    while True:
        #Muestra el valor del contador en el display
        #temporizacion(display7, contador)
        display7.show(contador)      #Llamar la rutina MOSTRAR
        
                
        #Si contador es nueve coloque el sentido del contador a decrementar
        if contador == 9999:
            sentido = False
        
        #Si contador es cero coloque el sentido del contador a incrementar
        if contador == 0:
            sentido = True
                 
    

#Entry Point
if __name__ == '__main__':
    main()

display7seg.py

"""
Clase de Display 7 Segmentos usando MicroPython
by: Sergio Andres Castaño Giraldo
Referencia: https://controlautomaticoeducacion.com/
"""

from machine import Pin
import utime

class Display:
    
    
    def __init__(self, Pins, kind = 'C', transistor_pins = 1):
        self.kind = kind
        self.number_digit = len(transistor_pins)
        
        #Configura los pines del display como salida
        display = list()
        for i in range(7):
            display.append( Pin(Pins[i], Pin.OUT) )
        
        #Configura los pines de los transistores como salida
        transistors = list()
        for i in range(self.number_digit):
            transistors.append( Pin(transistor_pins[i], Pin.OUT) )
        
        #Tupla con las posiciones del display
        self.display = display
        
        #Tupla con las posiciones de los transistores
        self.transistors = transistors
        
    def show(self, digits):
        #Realiza la multiplexación
        for i in range( self.number_digit ):
            number = int((digits % 10 ** (i+1)) / 10 ** i)
            self._show_one_display(number)
            self.transistors[i].on()
            utime.sleep_ms(1)
            self.transistors[i].off()
            
    
    #Metodo provado para mostrar número en un solo display
    def _show_one_display(self, digit):
        bit = 1;
        
        #Display Cátodo Común
        if self.kind.upper() == 'C':
            numbers = (int('3f',16),int('06',16),int('5b',16),int('4f',16),int('66',16),int('6d',16),int('7d',16),int('07',16),int('7f',16),int('67',16))
        #Display Ánodo Común
        elif self.kind.upper() == 'A':
            numbers = (int('40',16),int('79',16),int('24',16),int('30',16),int('19',16),int('12',16),int('02',16),int('78',16),int('00',16),int('18',16))
        else:
            return
        
        for i in range(7):
            if (numbers[digit]  & bit) == 0:
                self.display[i].off()
            else:
                self.display[i].on()
            bit = bit << 1
            

    

Eso es todo por la entrada del dia de hoy, espero les haya gustado y hayan aprendido algo nuevo. Si te ha servido el contenido de esta entrada, de los videos y los códigos de implementación y deseas apoyar mi trabajo invitandome a un café super barato, puedes hacerlo en el siguiente link:

👉 Invitar a Sergio a un Café ☕️

Que esten muy bien, nos vemos en la siguiente entrada.