Forum: Mikrocontroller und Digitale Elektronik Tasks sharen - mit Interrupts?


von Fabian M. (elmetzo)


Angehängte Dateien:

Lesenswert?

Erstmal ein hallo an alle! :-)

Ich besitze ein AT90USBKey und möchte folgendes Programm entwickeln:

2 Incrementalgeber ("Drehpotis" mit Gray-Code) sollen je eine Variable 
auf und runterzählen. Nebenbei muss der Prozessor verschiedene Tasks 
abarbeiten (SPI Schnittstelle, Temperatur auslesen usw.). Im Moment habe 
ich die Incrementalgeber ausgelesen und auf die LED's dargstellt. Ich 
habe das Signal mit einem Delay von 3ms (mit delay.h) entprellt. Dies 
funktioniert alles einwandfrei, jedoch möchte ich nun dass der Prozessor 
erst bei einer Veränderung des "Potis" dies abarbeitet und auch dass 
während der Entprellungszeit von 3ms andere "tasks" abgearbeitet werden 
können.

Nun zu meiner Frage: Wie soll ich an das Programm rangehen, gibt es 
sowas wie eine Betriebssystemstruktur (bei C# könnte man ja thread.sleep 
machen und somit hätten andere Thread's vorrang). Wenn man es mit Timer 
lösen kann, hat mir einer ein Beispiel in C?

Ich habe mal das C. File angehängt, falls ich mein aktuelles Programm 
ein bisschen ungenau beschrieben habe ;-)

Besten Dank für eure wertvollen Tipps!

von Falk B. (falk)


Lesenswert?

@ Fabian Metz (elmetzo)

>2 Incrementalgeber ("Drehpotis" mit Gray-Code) sollen je eine Variable
>auf und runterzählen. Nebenbei muss der Prozessor verschiedene Tasks
>abarbeiten (SPI Schnittstelle, Temperatur auslesen usw.).

Keine grosse Sache.

>ich die Incrementalgeber ausgelesen und auf die LED's dargstellt. Ich
>habe das Signal mit einem Delay von 3ms (mit delay.h) entprellt. Dies

AUA!!! Delays sind böse. Nutze Timer. Hab leider kein Beispiel direkt 
für dich. Aber die Tutorials.

Drehgeber
AVR-Tutorial: Timer
AVR-GCC-Tutorial

>Nun zu meiner Frage: Wie soll ich an das Programm rangehen, gibt es
>sowas wie eine Betriebssystemstruktur (bei C# könnte man ja thread.sleep

Nein, eine einfach Endloschleife im Main, i der zyklisch dine 
Aufgabenbearbeitet werden.

MFG
Falk

von Ulrich P. (uprinz)


Lesenswert?

Hi!

Muss Falk zustimmen. Auf keinen Fall Threads oder Tasks in die Luft 
hängen.
Gerade Hardware-nahe Schnittstellen, deren Zeitverhalten nicht 
vorhersehbar sind, sollte man nicht in die Abhängikeit eines Tasks 
stellen, sondern umgekehrt.

Daher hast Du zwei Möglichkeiten:
1) Die Gray-Encoder hängen an IRQ-Fähigen Pinnen
2) Setzte einen Timer auf, der wegen der Entprellung auch ruhig im 10ms 
Bereich laufen kann, oder sogar noch etwas langsamer.

Ich mache das grundsätzlich mit Timer, weil dadurch das Entprellen weg 
fällt, bzw sehr einfach wird:

1) Timer fragt Eingang ab und vergleicht mit vorhergehendem Wert
1a) Vorhergehender Wert ist gleich, nix passiert -> Exit
1b) Vorangegangener Wert ist unterschiedlich also neuen Stand speichern 
und ein Flag setzen, dass etwas passiert ist.

In 1b) kannst Du schon das Gray-Decoding machen, und damit entweder ein 
Flag für Links oder Rechts setzen, oder aber einen Zähler verändern und 
das mit einem Flag dem Rest des Systems signalisieren. ( Ich glaube 
dieses Flag nennen C++/# Entwickler Semaphore, oder?)

Gruß, Ulrich

von Fabian M. (elmetzo)


Lesenswert?

Hi Ulrich
>1) Die Gray-Encoder hängen an IRQ-Fähigen Pinnen

Hmm, aber wenn ich die an einem IRQ-Pin habe dann würde ich ja gleich 
mehrere Interrupts auslösen wenn die kontakte "prellen", oder eben halt 
nach dem interrupt wieder warten...

Ich probiers mal mit dem Timer zu lösen, jedoch ist das ja nicht 
ereignisgesteuert sondern einfach eine zyklische abfrage (polling). Aber 
viel Zeit nimmt das ja nicht in anspruch...

Gruss Fabian

von Falk B. (falk)


Lesenswert?

@ Fabian Metz (elmetzo)

>Hi Ulrich
>>1) Die Gray-Encoder hängen an IRQ-Fähigen Pinnen

>Hmm, aber wenn ich die an einem IRQ-Pin habe dann würde ich ja gleich
>mehrere Interrupts auslösen wenn die kontakte "prellen", oder eben halt
>nach dem interrupt wieder warten...

Eben, das macht man nicht so. Steht alles fein säuberlich im Artikel 
Drehgeber.

MFG
Falk

von Ulrich P. (uprinz)


Lesenswert?

Ich habe ja auch nicht geschrieben, dass man das über IRQ machen soll, 
sondern es als nicht näher erklärte Option angeboten ( weil es eben 
Prell-Anfällig ist).
Der Timer ist bei mechanischen Eingabegeräten immer vorzuziehen, weil er 
das Entprellen gleich mit erledigt. Durch Veränderung der 
Timer-Zeitbasis kann man dann sehr einfach den Punkt finden, an dem sich 
das System durch Prellen nicht zu sehr verwirren lässt, es aber auch ein 
schnelles Drehen nicht zum Stolpern bringt.

Ich habe das zuletzt für eine Tastatur im PKW gemacht, wo neben dem 
Kontaktprellen noch andere Störeinflüsse hinzu kommen könnten. Dort habe 
ich eine zweite Stufe eingebaut in der Software. Bezogen auf den 
Gray-Encoder ( und mein Gott prellen die Dinger, wenn die älter werden!) 
sollte man das gleich vorsehen:

1. Interrupt-> Prüfe mit vorhergehendem Signalstand?
  Unterschied! Zwischen-speichern.
2. Interrupt-> Prüfe mit gemerktem Signalstand von 1.?
  Gleich-> Neuen Wert als Gray-Wert nehmen und mit vorhergehendem 
Gray-Wert die Drehrichtung ermitteln.
  Unterschied! -> Zwischen-speichern.

Man überschreibt so lange den 1. Zwischenspeicher, bis man dort einen 
stabilen Zustand erreicht hat und vergleicht dann, ob sich dieser 
stabile Zustand vom letzten stabilen unterscheidet. Tut er das, dann 
wird der Zähler behandelt und / oder das/die Flag(s) gesetzt, um eine 
Drehung anzuzeigen.

Um die Systemlast nicht zu sprengen und nicht auf jeden Drehimpuls 
direkt reagieren zu müssen ( was bei Systemen sinn macht, die 
gelegentlich schwer an einzelnen Tasks zu arbeiten haben), kann man auch 
einen Differenz-Zählerstand einbauen. D.h. der Timerinterrupt kumuliert 
die Drehereignisse in einem Zähler. Kommt die Software dann zur 
Auswertung, addiert sie diesen Zählerstand zu ihrem eigenen hinzu.
Beispiel:
Software ist mit Malen von Menügrafiken beschäftigt. Um das nicht zu 
sehr zu verlangsamen, oder den Menücode einfacher zu halten, nimmt sie 
dabei keine Eingaben entgegen. Ich kann jetzt trotzdem 5x nach recht 
drehen und 3x nach links. Wenn mein Menü gemalt ist, und der Balken 
stand auf Punkt 1, dann flitzt er jetzt auf Punkt 3.
Natürlich sollte man diesen Differenzzähler als Signed ausführen :)

So, sind nur ein paar Anregungen. Muss ja nicht alles auf einmal 
implementiert werden.

Gruß, Ulrich

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.