Blog der Heimetli Software AG

Python-Programm für einen Zähler

Gefragt war ein Impulszähler mit einer graphischen Oberfläche. Wenn der Zähler einen Grenzwert erreicht, soll ein Ausgang geschaltet werden.

Weil tkinter in meiner Code-Sammlung noch fehlte, habe ich mich dahinter geklemmt:

Screenshot des laufenden Scripts

tkinter ist etwas gewöhnungsbedürftig, aber nicht unüberwindbar.

Das Script

Nutzt die "Interrupts" von RPi.GPIO, um auch recht kurze Impulse zu erfassen. Weil es auf Flanken reagiert, ist es auf saubere Impulse angewiesen. Jegliches Prellen würde gnadenlos mitgezählt so lange die "Interrupts" schnell genug sind.

Wegen der Kohäsion sollte der Code für die GPIOs sollte eigentlich nicht in MainWindow stehen, aber der Einfachheit halber ist er trotzdem dort eingebaut. Bei einer Erweiterung müsste das refactored werden.

Die verwendeten GPIO-Pins und das Update-Intervall werden bei der Instanzierung der Klasse übergeben.

Das Limit wird im Konstruktor gesetzt. Das ist wahrscheinlich nicht passend für eine praktische Anwendung, kann aber einfach geändert werden.

from tkinter import Tk, Label, Button, E, X
import RPi.GPIO as GPIO

class MainWindow:
    """The GUI for this system

    It implements all the functions which are necessary for the application.
    """
    def __init__( self, inputpin, outputpin, interval ):
        """Sets up the GPIOs and constructs the Window.

        Parameters
        ----------
        inputpin:  integer
                   the GPIO pin used as input
        outputpin: integer
                   the GPIO pin used as output
        interval:  integer
                   the interval between updates (ms)
        """
        # Initialize the member variables
        self.limit     = 10000
        self.counter   = 0
        self.interval  = interval
        self.outputpin = outputpin

        # Sets up the GPIOs
        GPIO.setmode( GPIO.BCM )
        GPIO.setup( inputpin,  GPIO.IN )
        GPIO.setup( outputpin, GPIO.OUT )

        GPIO.add_event_detect( inputpin, GPIO.RISING, callback=self.count )
        GPIO.output( outputpin, GPIO.LOW )

        # Constructs the Window
        self.root  = Tk()
        self.root.title( "Found at http://blog.heimetli.ch" )
        lbl = Label( self.root, text="Counter", font=("Helvetica",40,"bold") )
        lbl.pack( fill=X )
        self.label = Label( self.root, text=str(self.counter), anchor=E, width=7, font=("Helvetica",120,"bold") )
        self.label.pack()
        lbl = Label( self.root, text="Limit", font=("Helvetica",40,"bold") )
        lbl.pack( fill=X )
        lbl = Label( self.root, text=str(self.limit), anchor=E, width=7, font=("Helvetica",120,"bold") )
        lbl.pack()

        btn = Button( self.root, text="Reset", command=self.reset, font=("Helvetica",40,"bold") )
        btn.pack()

        # Starts the update mechanism
        self.root.after( self.interval, self.update )

        # Shows the window and runs the application
        self.root.mainloop()

    def update( self ):
        """Displays the current counter value and schedules a call to itself."""
        self.label["text"] = str(self.counter)
        self.root.after( self.interval, self.update )
 
    def count( self, channel ):
        """Counts the pulses."""
        self.counter = self.counter + 1

        # Turn off the machine if the limit is reached
        if self.counter >= self.limit:
            GPIO.output( self.outputpin, GPIO.HIGH )

    def reset( self ):
        """Resets the counter."""
        self.counter = 0

# Starts the application
#
# The GPIO used as input  is GPIO4
# The GPIO used as output is GPIO18
# The window is updated every 100ms
app = MainWindow( 4, 18, 100 )

Update 25.03.2020

Variablen umbenannt und die globalen Variablen zu Attributen der Klasse gemacht.