Forum: Mikrocontroller und Digitale Elektronik ATMEGA8 - 2 analoge Signale einlesen (2-Ch AD-Wandler)


von Thomas (Gast)


Lesenswert?

Hallo zusammen,
ich möchte gerne zwei analoge Signale mit dem ATMEGA8 einlesen. Bei den 
einzelnen Kanälen klappt dies auch, aber eben leider nicht bei beiden 
gleichzeitig. Was gibt es da alles besonderes zu beachten. Anbei noch 
mein C-Code. Achja, die beiden Funktionen werden im Hauptprogramm 
nacheinander aufgerufen.
Vielen Dank.
Gruß Thomas

unsigned char U_poti_Eingang()
{
  DDRC &= 0b11111110;
  unsigned char U_poti=0;
  ADMUX |= 0b01100000;    // Einlesen des Kanals 0 usw.
  ADCSRA|= 0b11000000;
  while (ADCSRA &0b01100000)  // Überprüfung: Abschluss der Wandlung
  {}
  U_poti=ADCH;
  return U_poti;        // Wertebereich: 0-255
}


unsigned char U_LED_Eingang()
{
  DDRC &= 0b11111101;
  unsigned char U_LED=0;
  ADMUX |= 0b01100001;    // Einlesen des Kanals 1 usw.
  ADCSRA|= 0b11000000;
  while (ADCSRA &0b01100000)  // Überprüfung: Abschluss der Wandlung
  {}
  U_LED=ADCH;
  return U_LED;        // Wertebereich: 0-255
}

: Verschoben durch Admin
von Krapao (Gast)


Lesenswert?

>   ADMUX |= 0b01100000;    // Einlesen des Kanals 0 usw.

Hier habe ich beim Lesen kapituliert.

von Thomas (Gast)


Lesenswert?

Krapao schrieb:
>>   ADMUX |= 0b01100000;    // Einlesen des Kanals 0 usw.
>
> Hier habe ich beim Lesen kapituliert.

Ja, sorry für die schlechte Beschreibung. Ja die letzten vier Bits 
beziehen sich auf den Anschluss zum Poti. Also MUX0-MUX3. Und da alle 
vier Bits Null sind ist es ja der Anschluß ADC0 des µC. War für mich ne 
Bezeichnung wo ich das Kabel anzuschließen habe.

von Krapao (Gast)


Lesenswert?

Durch die absoluten Bitmasken ist es sau schwer direkt zu sehen, ob dein 
Code richtig ist.

Mit den symbolischen Bitnamen aus den Includefiles ist es wesentlich 
einfacher zu sehen, ob der Code dem bekannten Code z.B. im 
AVR-GCC-Tutorial entspricht.

Deinen Code kann man nur mit intensivem Lesen des Atmega8 Datenblatts 
überprüfen.

Bei der Stelle

>  while (ADCSRA &0b01100000)  // Überprüfung: Abschluss der Wandlung
>  {}

ist was faul. Ich erwarte da eine Bitmaske mit einem gesetzten Bit, 
nicht zwei wie in deinem Code.

Ich würde auch die bewährte Auftrennung in die einmalige 
ADC-Initialisierung und ggf. regelmäßige ADC-Kanalumschaltung/Auslesen 
beibehalten, so wie sie im Tutorial verwendet wird.

von Hubert G. (hubertg)


Lesenswert?

Wenn du ADMUX|=(1<<REFS0)|(1<<ADLAR); schreibst dann muss sich der Leser 
nicht das Datenblatt heraussuchen um zu verstehen was du meinst.
Warum aktivierst du das immer wieder, es genügt doch einmal im main.

von Karl H. (kbuchegg)


Lesenswert?

Deine SChreibweise wurde ja schon zur Genüge angesprochen.

Zu noch einem Fehler (neben der Abfrage ob er fertig ist)
1
  ADMUX |= 0b01100001;    // Einlesen des Kanals 1 usw.

und wie erwartest du, dass das ganz rechte 1 Bit (für Kanal 1) jemals 
wieder gelöscht wird?
1
  ADMUX |= 0b01100000;    // Einlesen des Kanals 0 usw.
kann das nicht leisten. Mit einem Oder (|) kann man BIts nur auf 1 
zwingen, nicht jedoch auf 0 zurücksetzen.

Schau dir die ADC Routinen im AVR-GCC-Tutorial an, die 
berücksichtigen das. Und wenn du schon dabei bist könntest du auch ganz 
einfach die Routinen von dort verwenden. Die sind sauber geschrieben und 
berücksichtigen deine Kanalumschaltung. Im Prinzip weißt du ja wie's 
geht, daher spricht nichts dagegen, wenn du fix&fertige Funktionen dafür 
einsetzt, die dann auch noch die letzten Feinheiten berücksichtigt 
haben. Kein Grund das Rad neu zu erfinden und in 3 Anweisungen 4 
vermeidbare Fehler zu machen.

von Ingo L. (Gast)


Lesenswert?

Hi, das wird nicht funktionieren:
> while (ADCSRA &0b01100000)

Du meinst sicherlich:
1
while (ADCSRA &(1<<ADSC));


Grüße,
Ingo

von Thomas (Gast)


Lesenswert?

Hubert G. schrieb:
> Wenn du ADMUX|=(1<<REFS0)|(1<<ADLAR); schreibst dann muss sich der Leser
> nicht das Datenblatt heraussuchen um zu verstehen was du meinst.
> Warum aktivierst du das immer wieder, es genügt doch einmal im main.

Ah okay, wird diese Art der Schreibweise "(1<<REFS0)|(1<<ADLAR)" als 
"symbolische Bitnamen" benannt? Hab davor gedacht die absolute 
Schreibweise ist eindeutiger. Ich wollte damit nur ausschließen, dass 
mir durch das Kompilieren oder durch andere Programme die Register 
verändert werden.

Danke für die vielen Hinweise. Werde mich dann jetzt erst nochmals mit 
der Kanalumschaltung ausführlich befassen.

von Falk B. (falk)


Lesenswert?

@  Thomas (Gast)

>Ah okay, wird diese Art der Schreibweise "(1<<REFS0)|(1<<ADLAR)" als
>"symbolische Bitnamen" benannt?

Ja.

> Hab davor gedacht die absolute
>Schreibweise ist eindeutiger.

Nein.

von Jens (Gast)


Lesenswert?

Hallo Freunde,

ich möchte gerne mit einem Atmega16 zwei verschiedene Analogsignale an 
den Pins PA0 und PA1 abtasten.
Leider bin ich noch Anfänger und muss noch viel herum probieren und 
lesen dazu. Aber jetzt komme ich wirklich nicht mehr weiter.
Vielleicht kann mir ja mal einer einen Tip geben und sagen, was an dem 
unten aufgeführten Code nicht richtig ist. Wenn ich nur über den ADC PA0 
einlese funktioniert es, was ich dann über das PWM TImer1 auch sauber 
angezeigt bekomme. Möchte ich jedoch beide Pins abtasten, reagiert er 
wieder nur auf PA0 und lässt PA1 scheinbar außer acht.

Danke im Voraus.
Jens






#include <avr/io.h>
#ifndef F_CPU
#define F_CPU 4000000UL
#define ADATE 5
#endif
#include <util/delay.h>



int main(void)
{

uint16_t wert1;
uint16_t wert2;


  DDRB |= (1 << DDB3);      // Setup PB0 as output

  while(1)
  {

//erstes Abtasten

  ADMUX |= (1<<REFS0);
  ADCSRA |= (1<<ADEN)|(1<<ADATE)|(1<<ADPS2)|(1<<ADSC);

  while(!(ADCSRA&(1<<ADSC))); // Wait until a conversion is finished

  wert1 = ADC;

//zweites Abtasten

  ADMUX |= (1<<REFS1);
        ADCSRA |= (1<<ADEN)|(1<<ADATE)|(1<<ADPS2)|(1<<ADSC);

  while(!(ADCSRA&(1<<ADSC))); // Wait until a conversion is finished

  wert2 = ADC;

//über PWM Timer1 ausgeben


  DDRD |= (1 << DDB4);
  DDRD |= (1 << DDB5);


  TCCR1A = (1<<WGM10)|(1<<WGM11)|(1<<COM1A1)|(1<<COM1B1);

  TCCR1B = (1<<WGM12)|(1<<CS11)|(1<<CS10);

  OCR1A = wert1;
  OCR1B = wert2;


  }

  return 0;

}

von Max H. (hartl192)


Lesenswert?

Was war an diesem Hienweis nicht verständlich?
>>>  Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
>>>  Bitte hier nur auf die ursprüngliche Frage antworten,
>>>  für neue Fragen einen neuen Beitrag erstellen.

von spess53 (Gast)


Lesenswert?

Hi

>//erstes Abtasten
>  ADMUX |= (1<<REFS0);

>//erstes Abtasten
>  ADMUX |= (1<<REFS0);

Damit schaltest du die Referenzspannungsquelle aber nicht die Kanäle um. 
Außerdem konfiguriert man den ADC nicht ständig in der while-Schleife. 
das macht man einmal davor. In der Schleife brauchst du nur die 
ADMUX-Bits und ADSC anfassen.

MfG spess

von Achim K. (aks)


Lesenswert?

1
  ADMUX |= 0b01100000;  
2
...
3
  ADMUX |= 0b01100001;

Das mit dem "|=" ist keine gute Idee! Damit wird irgendwann mal der 
Kanal auf 1 gestellt und "|= 0" macht das nicht rückgängig! Du mußt 
entweder Deinen Code auf "=" umstellen oder vor dem "|=" mit "&= ..." 
die Kanalbits löschen.

von Return of Schnulli (Gast)


Lesenswert?

Max fragte:
>Was war an diesem Hienweis nicht verständlich?

Wo ist Deine Hilfe? Ich sehe sie nicht.
Bist Du einer der Typen, die den TO, wenn er wirklich einen neuen 
Beitrag
verfasst hätte, auch nur auf die Suchfunktion hinweisen und nicht helfen
wollen oder können?

Ist es Deiner Meinung nach sinnvoll, 10 gleichartige Threads mit nicht
Einer Lösung des Problemes zu haben?

Das mußte mal raus....

von Jens (Gast)


Lesenswert?

Sorry, ich hatte das verteilt. Ja ich werd dazu was komplett neues 
erstellen.

von Jens (Gast)


Lesenswert?

Verpeilt meinte ich.

von Max H. (hartl192)


Lesenswert?

Return of Schnulli schrieb:
> Wo ist Deine Hilfe? Ich sehe sie nicht.
Deine ist auch nicht vorhanden.

Return of Schnulli schrieb:
> Bist Du einer der Typen, die den TO, wenn er wirklich einen neuen
> Beitrag verfasst hätte, auch nur auf die Suchfunktion hinweisen
Wenn ich nicht richtig erinnere, habe ich das noch nie gemacht oder 
mindestens nicht in nennenswerter Menge.

von Franz (Gast)


Lesenswert?

@ Max H. (hartl192)
was lässt du dich als registrierter User hier von so einem Blockwart 
denunzieren? setz den auf die Ignoliste und gut ist,
oder suche seine Beiträge hier, der kann nur Rummosern - fachl. 
Tiefflieger

von Ein (Gast)


Lesenswert?

Jens schrieb:
> Sorry, ich hatte das verteilt. Ja ich werd dazu was komplett neues
> erstellen.

Dann schreib doch gleich den Link - wer soll sich da sonst noch zurecht 
finden.

Oder ein Mod erbarmt sich und löscht hier den ganzen, an den alten 
Thread rangeklatschten Mist.

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.