Forum: Mikrocontroller und Digitale Elektronik Arduino UNO: analoge Eingänge (Eigenbau)


von Max N. (max_89)


Angehängte Dateien:

Lesenswert?

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!

: Bearbeitet durch User
von Hubert G. (hubertg)


Lesenswert?

Wer sagt das du die analogen Eingänge nicht auch digital verwenden 
kannst?
Der Mega328 hat Pinchange-Interrupt.

von Max N. (max_89)


Lesenswert?

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???

von Hubert G. (hubertg)


Lesenswert?

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.

von Max N. (max_89)


Lesenswert?

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?

von Hubert G. (hubertg)


Lesenswert?

Ja, schau einfach ins Datenblatt, du wirst die Register ohnehin zum 
programmieren brauchen.

von Ich (Gast)


Lesenswert?

> Edit: Die Taster sind mit Pull-Up-Widerständen, entprellt (22nF)

Das hätte mein Bäcker nicht besser ausdrücken können

von Max N. (max_89)


Lesenswert?

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 :)

von spess53 (Gast)


Lesenswert?

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

von Max N. (max_89)


Lesenswert?

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

: Bearbeitet durch User
von Stefan W. (dl6dx)


Lesenswert?

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

: Bearbeitet durch User
von Max N. (max_89)


Lesenswert?

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

: Bearbeitet durch User
von Stefan W. (dl6dx)


Lesenswert?

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

von Max N. (max_89)


Lesenswert?

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

von Stefan W. (dl6dx)


Lesenswert?

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
extern uint16_t systicks(void);
3
4
// LED ein- und ausschalten
5
// on==0 ist LED aus
6
extern void led_switch(uint8_t on);
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
static uint8_t  led_state;
17
static uint16_t led_time;
18
19
void led_init(void)
20
  {
21
  led_state = LED_AUS;
22
  led_switch(LED_AUS);
23
  }
24
25
void led_task(void)
26
  {
27
  switch(led_state)
28
    {
29
    case LED_AUS:
30
      if(systicks() == led_time)
31
        {
32
        led_switch(LED_AN);
33
        led_time = systicks() + LED_TAKT
34
        }
35
      break;
36
37
    case LED_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
void set_led(uint8_t newstate)
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

von Stefan W. (dl6dx)


Lesenswert?

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.

von Max N. (max_89)


Lesenswert?

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
int counter = 0;
6
7
//hier die ISR
8
void tastenAbfrage(void)
9
{
10
   counter++;
11
}
12
13
14
void init(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
void schleife(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

: Bearbeitet durch User
von Hubert G. (hubertg)


Lesenswert?

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.

von Max N. (max_89)


Lesenswert?

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

von Stefan W. (dl6dx)


Lesenswert?

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.

von Max N. (max_89)


Lesenswert?

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
int counter=0;
6
boolean los = 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
void setup() 
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 :)
26
      interrupts();  
27
}
28
29
void loop() {
30
 
31
    while((counter>0)&&los)
32
    {
33
        digitalWrite(3,HIGH);
34
        delay(500);
35
        digitalWrite(3,LOW);
36
        delay(500);
37
        counter--;
38
    }
39
40
}
Ist bestimmt nicht die schönste Lösung, aber für den Anfang funktioniert 
es! Es soll ja nur grob zeigen wie es funktioniert!!!

PS: Es funktionier auf fast allen I/O-Pins des ATMEGA328, denke ich...
Ach ja hier findet man weitere hilfen: 
http://www.kriwanek.de/arduino/grundlagen/182-pin-change-interrupts-grundlagen.html

: Bearbeitet durch User
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.