Forum: Mikrocontroller und Digitale Elektronik ADC ISR mehrere Kanäle


von Rafi D. (alexanderw)


Lesenswert?

HAllo,

ich habe vor mehrere ADC kanäle einzulesen, diese messen jeweils 
verschiedene spannungen. Damit der Prozessor nicht ständig arbeiten muss 
verwende ich gerne die ISR und würde gerne die ADC Werte über einen 
Timer jede Minute einlesen.

Ich lese dabei im Single Conversion Modus ein.

Jetzt versteh ich nicht ganz genau wie ich in der ISR die kanäle 
wechseln soll.
Wechsel ich die Kanäle in den jeweiligen Timerblöcken? Oder setzte ich 
in der Timer_ISR ein Flag und werte diesen in der ADC_ISR aus?

von Oliver (Gast)


Lesenswert?

Bei einem Messwert pro Minute kannst du das machen, wie immer dir das 
gefällt. Solange du kein delay_ms(60000) hinschreibst, ist alles erlaubt 
und richtig.

Oliver

von Rafi D. (alexanderw)


Lesenswert?

um gottes willen...

_delay_ms kommt erst gar nicht in die software... man müsste einen code 
schreiben bei dem sobald eine delay funktion geschrieben wird... ein 
Totenkopf auf dem bildschirm auftauchen und teuflisch lachen...

zumindest für mich :)

von Rafi D. (alexanderw)


Lesenswert?

Die Syntax fehlt mir...
Oder besser gesagt der Ablauf und welche Bits ich setzen muss oder 
abfragen bevor ich einen Kanalwechsel durchführe...
und wie diese Prozedur speziell dann mit einer ISR aussieht...
Im Tutorial hab ich auch schon gelesen wie man den ADC sequentiell wie 
auvch interruptgesteuert durchführt... hat auch alles wunderbar geklappt 
auf meinem Board...

nur kriege ich diesen Wechsel der Kanäle nicht hin...

von Wilhelm F. (Gast)


Lesenswert?

Rafi Dafi schrieb:

> Jetzt versteh ich nicht ganz genau wie ich in der ISR die kanäle
> wechseln soll.

Die Kanäle wechselt man in der ADC-ISR nach der Werteinlesung. Man legt 
da eine Volatile-Variable an, die man im Interrupt immer um 1 weiter 
schaltet, zum nächsten Kanal.

von Rafi D. (alexanderw)


Lesenswert?

Wilhelm Ferkes schrieb:
> Man legt
> da eine Volatile-Variable an, die man im Interrupt immer um 1 weiter
> schaltet, zum nächsten Kanal.

vorrausgesetzt die genutzten ADC Kanäle folgen aufeinander.

Das heißt dann das die Kanäle ständig gelesen werden?
Geht das nicht per Abfrage des ADIF, oder ähnliches?
Das wäre nämlich sinnfrei wenn ich jede minute einen Wert einlesen 
möchte der Prozessor aber jedoch ständig ackert...
Ich habe das mal über Flags in der Timer ISR versucht nur leider klappt 
es nicht...
Nach Ablauf eines Timerblocks setze ich das 1. ADC Flag in der 
Timer_ISR... Die ADC_ISR wertet dieses Flag aus und setzt 
dementsprächend den Kanal und liest danach den ADC Wert ein...

Beim ersten funktioniert es wunderbar, wenn ich jedoch in den zweiten 
Timerblock für die 2. ADC Messung wechsel und dort das 2. ADC Flag setze 
und dieses dann in der ADC_ISR auswerte...

erhalte ich den Wert der ersten Messung...

ISR(ADC_vect)
{
  if (Timer1Flag == 1)
  {
    ADMUX = (ADMUX&~(0x1F)) | (ADC_Kanal_2 & 0x1F);
    ADCwert = ADC;
    Timer1Flag = 0;
    ADCSRA |= (1<<ADSC);
  }

  if (Timer2Flag == 1)
  {
    ADMUX = (ADMUX&~(0x1F)) | (ADC_Kanal_4 & 0x1F);
    ADCwert = ADC;
    Timer2Flag = 0;
    ADCSRA |= (1<<ADSC);
  }
}

von Wilhelm F. (Gast)


Lesenswert?

Rafi Dafi schrieb:

> vorrausgesetzt die genutzten ADC Kanäle folgen aufeinander.

Wenn sie nicht gerade aufeinander folgen, z.B. man verwendet nur Kanal 
0, 1 und 4, dann zählt man die Variable 0, 1 und 2, dann wieder 0, und 
macht eine if-Abfrage, oder switch case, und schaltet dort den richtigen 
Kanal ein.

Deinen µC kenne ich nicht, zu den Registern kann ich nichts sagen, aber 
das Prinzip ist oft ähnlich.

von Oliver (Gast)


Lesenswert?


von Bernd S. (bernds1)


Lesenswert?

Rafi Dafi schrieb:
> Timerblock für die 2. ADC Messung wechsel und dort das 2. ADC Flag setze

Anderer Vorschlag:
Schreib dir keine "Timerblöcke" in die ISR. Schreib dir eine einzige 
Funktion (außerhalb der ISR), z.B.
1
uint16_t GETADC(uint8_t channel)

Und in der ISR zählst du nur eine static-8bit-volatile-Variable hoch, 
wenn sie die Nummer des höchsten Kanals erreicht hat, setz sie auf Null.
Und mit dieser Variablen rufst du in der Routine die Funktion GETADC 
auf.
Bei jedem Aufruf einen Kanal höher.

Dann hast du nur eine Funktion und eine Zähl-Variable und der Prozessor 
kann wieder eine Weile schlafen.

Oder du zählst nur die Kanäle in der ISR hoch und setze ein Flag, daß 
eine
Wandlung stattfinden darf. Außerhalb (in der main) schaust du nur das 
Flag an und wenn es gesetzt ist, rufst du GETADC(channel) auf.
Hier kann der Prozessor nicht schlafen, weil er ja nach dem Flag gucken 
muß.

Das wären zwei Varianten, die mir jetzt so einfallen.

von Spess53 (Gast)


Lesenswert?

Hi

>Nach Ablauf eines Timerblocks setze ich das 1. ADC Flag in der
>Timer_ISR... Die ADC_ISR wertet dieses Flag aus und setzt
>dementsprächend den Kanal und liest danach den ADC Wert ein...

Wozu? bei den neueren AVRs kann der ADC auch direkt von verschiedenen 
Timerereignissen getriggert werden. Welchen hast du denn?

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?

> ISR(ADC_vect)

Würde ich gar nicht machen.

Starte den ADC für einen Kanal. Warte auf das Andlungsergebnis.
Danach: starte den ADC für den nächsten Kanal - warte auf das Ergebnis
Danach: starte den ADC für den nächsten Kanal - warte auf das Ergebnis
etc. etc.
bis alle Kanäle durch sind. Und danach legt sich der µC wieder schlafen, 
bis er vom Timer nach 1 Minute erneut aufgeweckt wird und wieder reihum 
alle ADC-Kanäle abfragt und auswertet.

KISS   -  Keep it simple, stupid.

Im Tutorial gibt es eine schöne Funktion, die man aufruft und der man 
den zu wandelnden Kanal mitgibt. Dann steh halt in der main-Schleife
1
....
2
3
int main()
4
{
5
  ....
6
7
  while( 1 ) {
8
9
    value0 = ADC_Read( 0 );
10
    value1 = ADC_Read( 1 );
11
    value2 = ADC_Read( 5 );
12
13
    .... mach was mit den Werten
14
15
    ... und wieder schlafen legen
16
    sleep();
17
  }
18
}

und der Timer holt den µC regelmässig aus dem Sleep wieder raus.

von Vuvuzelatus (Gast)


Lesenswert?

>Das wäre nämlich sinnfrei wenn ich jede minute einen Wert einlesen
>möchte der Prozessor aber jedoch ständig ackert...

Schwierig wird's erst wenn Du den Betriebsmodi "idle" noch zu "ackern" 
zählst (über die Modi "active" und "power down" dürfte diesbezüglich 
Einigkeit herrschen).

Frage für Experten: Was hat es für Folgen für Deinen µC, wenn Du ihn 
jede Sekunde z. B. zwanzigtausend mal in den idle-Modus schickst und 
wieder daraus zurückholst? Oder wenn Du den ADC hundertmal pro Sekunde 
einschaltest, eine AD-Wandlung durchführen lässt und ihn danach wieder 
ausschaltest? Beides ununterbrochen über Jahre.

von Karl H. (kbuchegg)


Lesenswert?

Vuvuzelatus schrieb:

> Frage für Experten: Was hat es für Folgen für Deinen µC, wenn Du ihn
> jede Sekunde z. B. zwanzigtausend mal in den idle-Modus schickst und
> wieder daraus zurückholst?

Lässt du auch 50 mal in der Sekunde über einen Zeitraum von knapp 2.5 
Jahren zu?
Wenn ja: der Stromverbrauch sinkt.
         Und sonst?
         Nichts.

von Vuvuzelatus (Gast)


Lesenswert?

>Nichts.

Richtig. Was ich damit sagen wollte: Der bisweilen geäußerte Wunsch nach 
langen Sleep-Phasen a la "mein µC soll nur jede Minute aufwachen, aber 
nur jede Stunde wäre noch besser. Leider lassen sich solch lange 
Intervalle mit einem Timer nicht erreichen. Was soll ich blos tun?" hat 
selten eine rationale Grundlage. Dahinter steht oft der (Irr-)glaube, zu 
häufiges Wechseln in den Sleep und das Wieder-Daraus-Aufwachen würde dem 
µC irgendwie schaden.

Die Stromersparnis ist nur beim Betrieb mit Knopfzellen machen ernsthaft 
relevant. Bei AA-Zellen ist es überhaupt kein Problem, einen µC z. B. 
fortlaufend alle 10 bis 20 ms aus dem Sleep aufzuwecken, ein paar Taster 
zu pollen (dann kann das Device jederzeit sofort reagieren) oder eine 
AD-Wandlung zu triggern inklusive Warten auf das Ergebnis, und ihn 
danach wieder in den Idle zu schicken. Man kann den Stromverbrauch 
anhand des Datenblatts sogar einfach ausrechnen, und wird einen Wert 
herausbekommen, der der Selbstentladung von Batterien entspricht 
(Hausnummer: 30 µA).

von Paul Baumann (Gast)


Lesenswert?

Vuvuzelatus schrob:
> Dahinter steht oft der (Irr-)glaube, zu
>häufiges Wechseln in den Sleep und das Wieder-Daraus-Aufwachen würde dem
>µC irgendwie schaden.

Vielleicht ist der TO im 3-Schicht System beschäftigt und hat mit dieser
Verfahrensweise am eigenen Leib schlechte Erfahrungen gemacht. Dann wäre
es verständlich, wenn er dem Kontroller diese Erfahrung ersparen möchte.

;-)
MfG Paul

von Rafi D. (alexanderw)


Lesenswert?

Paul Baumann schrieb:
> Vielleicht ist der TO im 3-Schicht System beschäftigt und hat mit dieser
> Verfahrensweise am eigenen Leib schlechte Erfahrungen gemacht. Dann wäre
> es verständlich, wenn er dem Kontroller diese Erfahrung ersparen möchte.

Vielleicht aber auch nicht... ;)
Und was bringt eigentlich so ein Post zur Problemlösung... naja ist ja 
deine zeit...

Zurück zum Thema...
Vom sleep_mode war von meiner Seite her keine Rede... naja Ackern ist 
auch eine Definitionssache... sorry wenn es falsch verstanden wurde
Denn neben der minütlichen ADC Wandlung, sollen ständig LED's läuchten 
um die gemessenen Spannungen zu signalisieren...
Bleiben im idlemode die von mir vorher gesetzten Pin's für die LED`s 
oder werden diese gelöscht?
Das wäre natürlich super praktisch wenn er denn aktuellen Status 
beibehällt... und wie ich gelesen habe kann die ISR für den UART in dem 
mode auch daten empfangen/senden... bzw. weckt den µC wieder aus dem 
idle_mode, wenn Daten empfangen werden oder eben vom µC gesendet werden

ich hab jetzt die sachen so programmiert das ich nicht über die ISR_ADC 
arbeite... sondern über get_ADC() und dann eben der warteschleife in 
dieser, die mir den Abschluss der Konvertierung signalisiert.
Es funktioniert...

Danke für alle hilfreichen Posts... :) und die weniger hilfreichen waren 
auch amüsant... **Paul-schiel**

von Karl H. (kbuchegg)


Lesenswert?

Rafi Dafi schrieb:

> Bleiben im idlemode die von mir vorher gesetzten Pin's für die LED`s
> oder werden diese gelöscht?

In dem Fall kannst du dir den ganzen Aufwand aber auch sparen.
Denn deine leuchtenden Leds (wenn es ein paar sind) brauchen um einiges 
mehr Strom als der µC für sich braucht.
Und dann kannst du dir auch den ganzen Aufwand mit minütlicher Wandlung 
sparen.  Denn dem µC ist es egal ob er Däumchen dreht oder mal wieder 
eine AD Wandlung macht.

von Paul Baumann (Gast)


Lesenswert?

O.T.
Rafidafi schrub:
>naja ist ja deine zeit...

Ja, man muß auch mal trotz aller Probleme, die zu lösen sind, 
zwischendurch
einmal grinsen können. Die halbe Minute reißt es dann auch nicht mehr 
raus.

>und die weniger hilfreichen waren auch amüsant... **Paul-schiel**

Naja, so sollte das sein.

MfG Paul

von Vuvuzelatus (Gast)


Lesenswert?

>Vom sleep_mode war von meiner Seite her keine Rede...

Nur zur Klarstellung der Begrifflichkeiten: Mit Sleep meint man 
gemeinhin alle Modi außer "active", d. h. sleep fasst die Modi "idle" 
und "power-down" zusammen (von denen es wiederum die ein oder andere 
Variante gibt).

>Denn neben der minütlichen ADC Wandlung, sollen ständig LED's läuchten
>um die gemessenen Spannungen zu signalisieren...

OK, damit fällt Stromsparen als Hintergrund Deiner Frage flach.

>Bleiben im idlemode die von mir vorher gesetzten Pin's für die LED`s
>oder werden diese gelöscht?

Die Pinzustände bleiben erhalten, sogar im Modus power-down.

>[...] kann die ISR für den UART in dem mode auch daten empfangen/senden...
>bzw. weckt den µC wieder aus dem idle_mode, wenn Daten empfangen werden
>oder eben vom µC gesendet werden

Ja. Idle ist der Schlafmodus, in dem alles, was über Interrupts läuft, 
noch zur Verfügung steht.

Ich frage mich immer noch, was für Vorteile Du Dir von der minütlichen 
AD-Wandlung erhoffst. Ich sehe keinen einzigen, aber dafür einen 
Nachteil, der Dir vielleicht nicht bewusst ist: Deine LED-Anzeige wird 
auf jede Änderung erst mit durchschnittlich halbminütiger (maximal 
minütlicher) Verzögerung reagieren. Sowas kann massiv nerven, beim 
Testen während der Entwicklung, aber auch später. Ein Beispiel: Du 
klemmst irgendwann probeweise einen niederohmigen Widerstand als Last an 
Deinen Akku (?) an, um herauszufinden, wie stark die Spannung einbricht. 
Dann wird der Lastwiderstand heißer und heißer während Du ewig auf das 
Umschalten Deiner LEDs wartest - Spaßfaktor Null.

Tipp: Investiere keine Zeit in die Realisierung sehr langer, d. h. 
Sekunden oder noch länger dauernder Schlafphasen. Du würdest am Schluss 
höchstwahrscheinlich nur feststellen, dass Dich das Ergebnis nicht 
zufriedenstellt und dann war die Mühe umsonst. Lass die AD-Wandlung etwa 
4 mal pro Sekunde stattfinden. Das ist für den ADC immer noch "selten" 
(er könnte auch problemlos 4000 mal pro Sekunde), aber oft genug, damit 
sich Dein fertiges Device so verhalten wird, wie es der Benutzer 
intuitiv erwartet, nämlich (annähernd) sofort auf Änderungen reagierend.

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.