Hallo zusammen,
meine Frage bezieht sich auf die von mir erstellen Pläne (siehe Anhang).
Ich möchte für mein selbstgebauten Arduino UNO ein Shield bauen und
möchte die 6 analogen I/O´s für die Taster verwenden, genauer: die
Taster sollen über ISR (Interrupt) eingelesen werden -da es sonst blöd
wäre die Taster so lange gedrückt zu haltern bis der uC an der richtigen
Stelle angekommen ist- und dadurch Variablen im Programm verändern. Ich
kann das am Board nicht testen, da ich das UNO und sein Shield
gleichzeitig ätzen möchte und somit beides noch nicht fertig habe -es
wäre sehr ärgerlich wenn das Shield um sonst wäre! Kann man das mit den
analogen Pins machen oder laufe ich da in die verkehrte Richtung? Die
digitalen Pins benötige ich für andere Zwecke, deswegen der Umstand mit
den Analogen!
Danke im Voraus und frohes neues Jahr 2014
Beste Grüße
Max
PS: die oben angezeigten Schaltungen sind nicht fertig bsw. die
Kondensatoren sind kurzgeschlossen -> Tau = 0 & Kondensatorlebensdauer
sinkt stark!
Danke Hubert. Unterstuetzt der auch die Interrupts auf allen analogen
Pins?, denn da bin ich mir unsicher. d.h. wenn die Taste gedrueckt wird,
dann soll er das in einer ISR verwerken und Z.B. eine Variable aendern.
Hatte i.wo gelesen, dass die Interrubts (ISR) nur auf Port B (digital)
funktionieren???
Wenn du einen Mega328 hast, dann gilt das laut Datenblatt für alle I/O.
Die "analogen Pin" sind nur dann analog wenn du den jeweiligen ADC für
diesen Pin aktivierst. Ansonst sind es normale digitale I/O.
Super, denn ich hatte irrtuemlicherweise i.wo gelesen gehab dass man
ueber den Port C (analog) keine Interrupts ausloesen kann -natuerlich
erst nach dem ich mein Layout fertig hatte. Sehr gut. Hast mir viel
geholfen. Habe ich das richtig verstanden, dass man theoretisch mit
jedem Pin der Ports B, C oder D ein Interrupt ausloesen kann?
Sehr gut, dann hast du ein guten Bäcker. Aber evtl. kennst du noch die
Antwort auf meine Frage, oder du fragst deinen Bäcker? Mal was
sinnvolles sagen "Ich"!
Und sind wir doch mal ehrlich, sowas versteht jeder :)
Hi
>Die Taster sind mit Pull-Up-Widerständen, entprellt (22nF)
Meine Pull-Up-Widerstände haben als Einheit irgendwas mit Ohm. 22nF ist
etwas mit Farad. Scheint also irgendwie in die Kategorie Kondensator zu
gehören.
Ein Schaltplan wäre übrigens sinnvoller gewesen. Aber so wie es aussieht
schließt du den Kondensator bei jedem Tastendruck kurz. Sehr sinnvolle
Maßnahme zur Verkürzung der Lebensdauer der Taster.
Die Idee mit Tastern an Interrupts kommt von Anfängern hier öfters. Die
Lösung ist allerdings hier
http://www.mikrocontroller.net/articles/Entprellung
zu finden.
MfG Spess
Danke für die Erklärung, leider nichts mit meiner Frage zutun. Aber ich
weiß genau was du damit meinst (Kondensator) -diese werden entweder gar
nicht eingebaut da ich per Software das machen werde oder ich werde nach
was anderem umsehen müssen, aber danke. Dieser ist auch nicht der
momentane Stand, aber für das Verständnis reicht es!
Danke
Max Neu schrieb:> da es sonst blöd> wäre die Taster so lange gedrückt zu halten bis der uC an der richtigen> Stelle angekommen ist-
Du hast möglicherweise noch eine falsche Vorstellung von der
Arbeitsgeschwindigkeit des Prozessors.
Tastendrücke sind Ereignisse, die - auf menschliche Zeitdimensionen
übertragen - Monate bis Jahre dauern. Allein das Prellen des Kontakts
dauert "gefühlte Tage". Das kann man bequem durch "zweimal am Tag
nachsehen" erledigen.
spess53 schrieb:> Die Idee mit Tastern an Interrupts kommt von Anfängern hier öfters. Die> Lösung ist allerdings hier> http://www.mikrocontroller.net/articles/Entprellung> zu finden.
Dem ist nichts hinzuzufügen.
Grüße
Stefan
Danke Stefan für die schnelle Aufklärung!
Dein schneller Prozessor interessiert mich genauer!
Meine Aufgabe: Es soll eine Frage Wort für Wort auf dem LCD-Display
ausgegeben werden. Wird die Taste gedrückt (egal zu welchen Zeitpunkt)
so wird die Ausgabe unterbrochen und man muss die Frage beantworten. Es
darf keiner bevorzugt werden (auch nicht durch den Programmaufbau!).
Wird ein kleines Trinkspiel, was auch für mich ein Lerneffekt sein soll
-> wird da wahrscheinlich nur ein mal gespielt :). Wie machst du das mit
deinem schnellen Prozessor ohne Interrupts o.ä?
Edit: Möchte diesen mit C und/oder Assembler programmieren
Liebe Grüße
Max
Hallo Max,
du hast vermutlich bislang versucht, das Problem sequentiell (eine
Aufgabe nach der anderen) zu lösen.
Versuche doch mal, das Ganze gedanklich anders anzugehen:
1. Dein Prozessor ist so schnell, dass du seine Arbeitszeit problemlos
auf mehrere Aufgaben verteilen kannst und er trotzdem innerhalb deiner
Zeitvorgaben bleibt.
2. Daher kannst du ihn von Teilaufgabe zu Teilaufgabe "immer im Kreis
herum" scheuchen, ohne dass er durcheinander kommt. Er muss sich nur
merken, was er bei jeder Aufgabe jeweils zuletzt gemacht hat.
Schon bist du beim typischen Aufbau eines Mikrocontroller-Programms:
1
Reset:
2
Initialisierung Hardware
3
Initialisierung Variablen Teilaufgabe 1
4
Initialisierung Variablen Teilaufgabe 2
5
...
6
7
Start:
8
Aufgabe 1 was zu tun?
9
Ja: Alles machen, was kein Warten bedingt,
10
neuen Zustand merken
11
12
Aufgabe 2 was zu tun?
13
Ja: Alles machen, was kein Warten bedingt,
14
neuen Zustand merken
15
16
...
17
18
Gehe zu Start
Das ist eine einfache Form von kooperativem Multitasking:
http://www.mikrocontroller.net/articles/Multitasking
Das Merken des Zustands der einzelnen Teilaufgabe hat auch einen Namen,
das ist nämlich ein "Zustandsautomat" (state machine).
http://www.mikrocontroller.net/articles/Statemachine
Und wie gesagt: Der im Arduino verbaute ATMega 328p erledigt (pi *
Daumen) etwa 14 Mio (Assembler-)Befehle je Sekunde. Der könnte bei der
beschriebenen Aufgabe nebenher noch einiges anderes erledigen. Du musst
ihn nur lassen...
Ist es schon einigermaßen klar geworden, wie es gehen kann?
Grüße
Stefan
Erstmal, Danke an Stefan.
Natürlich, hatte ich das in Betracht gezogen, aber warum soll ich die
ISR´s nicht ausnützen? Was ist falsch daran, wenn die Architektur das
zulässt!
Das macht doch einiges einfacher?!?!
Evtl. übersehe ich noch eine Kleinigkeit?
Beste Grüße
Max
Stefan Wagner schrieb:> Dein Prozessor ist so schnell, dass du seine Arbeitszeit problemlos> auf mehrere Aufgaben verteilen kannst
Damit es noch etwas klarer wird:
"Teilaufgaben" könnten z.B. sein:
- Tastatur abfragen
- Zeichen aufs Display ausgeben
- serielle Schnittstelle bedienen (wenn du sie benutzen willst)
- eine LED an- und ausschalten (blinken lassen)
und natürlich
- Ergebnisse anderer Teilaufgaben nehmen und darauf aufbauend die Logik
des Hauptprogramms abarbeiten
Ich nehme mal die LED als Beispiel für den detaillierten Aufbau einer
solchen Teilaufgabe.
Soll die LED nur gleichlang an- und aus sein, hat die Teilaufgabe die
Zustände "LED an" und "LED aus". Diesen Zustand merken wir uns in einer
Variable led_state. Dann brauchen wir noch eine Information, wie lange
die LED schon in dem jeweiligen Zustand ist (wir wollen ja einen
bestimmten Blinktakt). Ich unterstelle jetzt noch, dass wir irgendwo
eine Quelle für eine "Systemzeit" mit z.B. 10 ms Auflösung haben (wie
das geht kommt später) die wir immer wieder abfragen können.
Das nachfolgende Beispiel enthält nur die absolute Grundfunktion.
1
// Die Systemzeit
2
externuint16_tsysticks(void);
3
4
// LED ein- und ausschalten
5
// on==0 ist LED aus
6
externvoidled_switch(uint8_ton);
7
8
// LED-Zustände
9
#define LED_AUS 0
10
#define LED_AN 1
11
12
#define LED_TAKT 100
13
14
// modulglobale Variable
15
// "static" wird später erklärt
16
staticuint8_tled_state;
17
staticuint16_tled_time;
18
19
voidled_init(void)
20
{
21
led_state=LED_AUS;
22
led_switch(LED_AUS);
23
}
24
25
voidled_task(void)
26
{
27
switch(led_state)
28
{
29
caseLED_AUS:
30
if(systicks()==led_time)
31
{
32
led_switch(LED_AN);
33
led_time=systicks()+LED_TAKT
34
}
35
break;
36
37
caseLED_AN:
38
if(systicks()==led_time)
39
{
40
led_switch(LED_AUS);
41
led_time=systicks()+LED_TAKT
42
}
43
break;
44
}
45
}
46
47
voidset_led(uint8_tnewstate)
48
{
49
led_state=newstate;
50
led_time=systicks()+LED_TAKT
51
led_switch(newstate);
52
}
So könnte das (in etwa) aussehen. Die Technik der Zeitabfrage ist sehr
vereinfacht dargestellt, tatsächlich würde man das etwas anders machen.
(Aber das ist eine andere Geschichte.)
Wichtig ist hier nur, dass das Warten auf den nächsten Zustandswechsel
nicht in Form einer Warteschleife abläuft, sondern ein oft wiederholtes
kurzes Nachsehen ist. Und dazwischen kann eine Menge anderer Dinge
erledigt werden.
Grüße
Stefan
Max Neu schrieb:> aber warum soll ich die ISR´s nicht ausnützen?> Was ist falsch daran, wenn die Architektur das> zulässt?
Man sollte sie sinnvoll nutzen. Sie haben nämlich neben Vorteilen auch
gewisse "Fallstricke".
Ob man für eine bestimmte Aufgabe einen Interrupt nutzt, hängt in der
Regel von der Art der Aufgabe ab.
Als Faustregel kann man sagen, dass Interrupts dann notwendig werden,
wenn man auf ein Ereignis schneller reagieren muss, als der Prozessor
für einen "Programmrundlauf" benötigt.
Typische Kandidaten sind Timer oder serielle Schnittstellen (UART, SPI,
I2C).
Bei einem Timer muss man sehr zeitnah auf den Überlauf reagieren, weil
sonst das Zeitraster "aus den Fugen geht".
Bei einer seriellen Schnittstelle gehen bei verspäteter Reaktion u.U.
Zeichen verloren (Bufferoverflow).
Die Eingänge für externe Interrupts braucht man schon etwas seltener.
Typisch ist hier z.B. die Information, dass ein per SPI angeschlossener
externer Baustein Daten hat, die abzuholen sind.
Generell gesagt: Typisch für die Nutzung von Interrupts ist, dass die
notwendige Aktion vergleichsweise kurz ist, aber schnell nach dem
Ereignis erfolgen muss.
Um auf deine ursprüngliche Frage zurück zu kommen: Die Abfrage eines
mechanischen Kontakts (Tasters) hat ganz andere Bedingungen.
Ein mechanischer Taster ist langsam. Die Setzzeit (Zeit bis der
Kontakt sauber geschlossen ist) liegt im Bereich etlicher Millisekunden.
Bis dahin erzeugt der Kontakt ein ganzes Bündel an Übergängen. Die
minimale Haltezeit bei menschlicher Betätigung ist im Bereich mehrerer
hundert Millisekunden.
Daraus folgt, dass man sowieso mehrfach abfragen muss, um sicher
zwischen Prellen und "wirklich gedrückt" bzw. "wirklich losgelassen"
unterscheiden zu können.
Da der Kontakt "schnarchlangsam" ist, kann man das nicht nur problemlos
"zu Fuß" machen, man muss in der Regel sogar warten, bis man sinnvoll
erneut abfragen kann. Innerhalb einer ISR ist das nicht sinnvoll
machbar.
Zudem würde bei Nutzung eines externen Interrupts das Kontaktprellen
zumindest zeitweise eine wahre "Interruptflut" erzeugen und so massiv
Rechenzeit "fressen".
Beides spricht für die zyklische Abfrage im Rahmen des normalen
Programms und gegen die Nutzung eines externen Interrupts*.
Grüße
Stefan
*Wichtig: Es gibt eine Ausnahme davon. Die liegt vor, wenn man den
Controller per Tastendruck aus einem Sleep-Modus holen will. Aber sobald
er wieder wach ist, sollte man die weitere Abfrage der Tasten besser
wieder im Vordergrund machen.
Okay, ursprünglich hatte ich eine andere Frage gestellt.
Hier sind diese kurz nochmal:
Kann ich die analogen Pins genauso wie die digitalen nutzen?
Antwort: JA siehe Antwort von Hubert (Danke)
Unterstützen alle analogen Pins die Interrupts (bei ATMEGA328/-P)?
Antwort: NEIN (keiner von denen) siehe dazu diese Seite von meinem Prof:
http://www.netzmafia.de/skripten/hardware/Arduino/programmierung.html
->habe ich das richtig Verstanden?
Bei den Diskussionen haben sich neue Fragen aufgestellt:
Betreff: Tastenabfrage ohne ISR?!? Siehe Kommentar von Stefan Wagner
(Danke)
Damit mein Problem sichtbar für alle wird hier ein Programmbeispiel mit
einer LED :D
Ein Counter soll die Tastendrücke zählen und die LED, so oft wie die
Taste gedrückt worden ist, blinken lassen.
_Programm (C):
1
#define LED_PIN 3 //z.B.
2
#define ISR_PIN 2
3
4
//globale Variable
5
intcounter=0;
6
7
//hier die ISR
8
voidtastenAbfrage(void)
9
{
10
counter++;
11
}
12
13
14
voidinit(void)//so heißt es meine ich beim UNO?
15
{
16
pinMode(LED_PIN,OUT);
17
//hier wird der Interrupt freigegeben
18
interruptFreigabe(ISR_PIN,RISING_EDGE,&tastenAbfrage);//Wie die Funktion genauer heißt müsste ich nachschauen
19
}
20
21
voidschleife(void)//so heißt es meine ich beim UNO?
22
{
23
while(conter>0)
24
{
25
digitalWrite(LED_PIN,1);
26
delay(500);
27
digitalWrite(LED_PIN,0);
28
conter--;
29
}
30
}
Es geht hierbei ums Verständnis!!!
wie würdet ihr das machen ohne ISR? Es soll keine Tastendruck
ausgelassen werden
Internet sagt zu ISR:
Interrupts sind sinnvoll um Vorgänge in Mikrocontrollerprogrammen
automatisch ablaufen zu lassen. Sie können ebenfalls dabei helfen
Zeitprobleme zu lösen. Typische Aufgaben für ein Interrupt sind z.B.
Drehwinkelgeber und Überwachung von Benutzereingaben
Max Neu schrieb:> Unterstützen alle analogen Pins die Interrupts (bei ATMEGA328/-P)?> Antwort: NEIN (keiner von denen) siehe dazu diese Seite von meinem Prof:> http://www.netzmafia.de/skripten/hardware/Arduino/programmierung.html> ->habe ich das richtig Verstanden?
Nein, nicht richtig verstanden. In dem Link habe ich die Antwort auf die
schnelle nicht gefunden.
Es sind grundsätzlich alle Pin digital, das analoge ist eine
Zusatzfunktion und muss erst aktiviert werden. Solange der Pin digital
ist, funktioniert auch der Pin-Change-Interrupt.
Eine Ausnahme gibt es nur bei der TQPF und MLF32 Version, da ist PC6 und
PC7 ausschließlich analog.
Eine Tastenabfrage über ISR ist insofern kritisch da durch das
Tastenprellen sofort ein zweiter Interrupt ausgelöst wird, der nach
beenden des ersten sofort aufgerufen wird. Bei starkem Tastenprellen
kann das mehrfach passieren.
Daher ist das Pollen der Tasten und unterdrücken des Tastenprellen
mittels einer Debounce-Funktion besser.
In der Hauptschleife darf dabei natürlich kein delay vorhanden sein.
Okay, danke Hubert.
Dann muss ich mich wohl mehr mit Assembler befassen, wollt eigentlich
mehr mit "fertigen" C-Funktionen arbeiten wie
1
...
2
attachInterrupt(14,myfunction,CHANGE);//Interrupt am analogen Pin
3
...
oder so ähnlichen Zeug, ohne Erfolg, da muss ich mich stärker
einarbeiten -leider fehlt mir die Zeit hierfür -> aus Erfahrung mit
68HC11. Aber Leiterplattenherstellung war erfolgreich :D
Danke nochmal an die Community
Auch wenn es sicherlich auf Dauer nicht verkehrt ist, den Assembler der
AVR-Controllerfamilie kennen zu lernen: Nur um Interrupts zu nutzen,
brauchst du das nicht.
Du kannst den ATMega328 auch in nativem C programmieren. avr-gcc und
avrlib unterstützen Interrupt-Serviceroutinen.
Du bist also nicht auf das Arduino-Framework festgelegt.
Grüße
Stefan
PS: Die Bibliotheken des Arduino-Framework liegen als C-Quellcode vor.
Du kannst sie also auch ansehen und auf eigene Projekte portieren.
Danke an alle Helfer!
Um es hier abzuschließen:
Hier ein kurzes Programm für alle die es interessiert wie man
Pin-Change-Interrupt auf analogen Pin 18 und 19 auslöst.
Im Beispiel werden die Tastendrücke über den Pin 19 gezählt und durch
das drücken der Taste an Pin 18 blinkt die LED an Pin 3 so oft wie man
die Taste an Pin 19 zuvor gedrückt hatte (einfach testen :D )!
1
#include<avr/interrupt.h>
2
#include<avr/io.h>
3
4
5
intcounter=0;
6
booleanlos=false;
7
8
9
ISR(PCINT1_vect)
10
{
11
if(digitalRead(19)==0)
12
counter++;
13
if(digitalRead(18)==0)
14
los=!los;
15
}
16
17
voidsetup()
18
{
19
pinMode(3,OUTPUT);
20
//Freigabe der Interrupts an analogen Pins
21
PCICR|=(1<<PCIE1);
22
//analogen Pins 12 und 13 für Interrupts freigeben
23
PCMSK1|=(1<<PCINT12);
24
PCMSK1|=(1<<PCINT13);
25
//Interrupts aktivieren -> keine Ahnung ob man das wirklich braucht :)