mikrocontroller.net

Forum: Compiler & IDEs Atmega2560 ADC auslesen


Autor: A. R. (redegle)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich besitze ein STK600 und versuche gerade, ein paar kleine Programme zu 
schreiben.
Mein jetziges Ziel ist es, einen analogen Pegel auszulesen.
Ich lege an den PIN PF0 eine analoge Spannung. Diese wird intern in 
einen 10Bit Wert gewandelt. Die untern 8 Bit sollen an den PORTB 
ausgegeben werden.
#include <avr/io.h>

// inernet Takt 128kHz
// Port E hat ADC  (ADC0) PF0
// Ausgänge sind negiert

   
  int main(void)

{

 
#include <avr/io.h>

// Internet Takt 128kHz
// Der ADC ist an PortF angeschlossen, ADC0 --> PF0
// Ausgänge des PortB sind negiert

   
  int main(void)

{

  ADCSRA= 0b11100000; // Free running mode mit Takt: 128/2khz
  ADCSRB= 0b00000000; // Letzen 3 Bits stehen auch für free running mode
  ADMUX = 0b11100000; // Referenz ADLAR und Eingang // ADLAR gesetzt
  char Wert = 0xff;
  DDRB = 0b11111111; // Port B ist ein Ausgang 0b11111111 = 0xff


  while(1)
  {
    Wert = ~ADCH;
    PORTB = Wert;
  }
  

return 0;
}

Dieser Code funktioniert!
Wenn ich jedoch ADLAR ausschalte (Bit --> 0), so dass die untern 8 Bits 
in dem Register ADCL stehen sollten und ich schreibe:
  while(1)
  {
    Wert = ~ADCL;
    PORTB = Wert;
  }

Dann funktioniert das Programm nicht mehr!
Aus irgendeinem Grund kann ich nur das Register ADCH und nicht das 
Register ADCL auslesen. Hat jemand hierfür eine Erklärung?

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Grund dafür ist im Datenblatt erklärt:
When ADCL is read, the ADC Data Register is not updated until ADCH is 
read

Also einfach einen Dummy-Read von ADCH hinterher machen, oder ADCW lesen 
und nur die unteren 8Bit verwenden.

Autor: Walter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tip für später:
außerdem könntest du auch noch warten bis der neue Wert gewandelt wurde
(oder einen Interrupt verwenden)

Autor: A. R. (redegle)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Der Grund dafür ist im Datenblatt erklärt:
>When ADCL is read, the ADC Data Register is not updated until ADCH is
>read

Danke!
Wenn ich danach suche, dann finde ich das auch.
Habe irgendwie nur bis zur Grafik geschaut.

>oder ADCW lesen und nur die unteren 8Bit verwenden.

Hast du einen Vorschlag, wie man das etwas einfacher machen kann?

>Tip für später:
>außerdem könntest du auch noch warten bis der neue Wert gewandelt wurde
>(oder einen Interrupt verwenden)

Danke,
das warten habe ich schon eingebaut.
In Interrupts muss ich mich beim Atmega noch einlesen.

#include <avr/io.h>

// Internet Takt 128kHz
// Der ADC ist an PortF angeschlossen, ADC0 --> PF0
// Ausgaege des PortB sind negiert

   
  int main(void)

{

  ADCSRA= 0b11100000; // Free running mode mit 128/2khz
  ADCSRB= 0b00000000; // Letzen 3 stehen auch für free running mode
  ADMUX = 0b11000000; // Referenz ADLAR und Eingang // ADLAR nicht gesetzt
  DDRB = 0b11111111; // Port B ist ein Ausgang 0b11111111 = 0xff

/* 
// Staendige Abfrage nicht notwendig
    char Wert = 0xff;
  char Dummy = 0x00;
  while(1)
  {
    Dummy = ADCH;
    Wert  = ~ADCL;
    PORTB = Wert;
  }
*/

// Interrupt-Flag abfragen

  short s_Wert = 0;
  char c_Wert= 0;
  while(1)
  {
    if((ADCSRA & 0b00010000)==0b00010000)
    {
      s_Wert= ADCW;
      c_Wert= ~(s_Wert & 0xFF); 
      PORTB = c_Wert;
    }
  }
  

return 0;
}

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. R. schrieb:

>>oder ADCW lesen und nur die unteren 8Bit verwenden.
>
> Hast du einen Vorschlag, wie man das etwas einfacher machen kann?

Frag dich ganz einfach, wozu du eigentlich in deinem Code die Variable 
s_Wert brauchst.

Autor: A. R. (redegle)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Naja die Variable brauche ich gar nicht.

Autor: Walter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. R. schrieb:
> if((ADCSRA & 0b00010000)==0b00010000)

wenn statt kryptischer Bitfolgen die bekannten Konstanten verwendest,
ist das Programm für Dich und vor allem auch andere leichter 
verständlich

du schreibst ja auch nicht anstatt ADCSRA irgendeine Zahl hin

Autor: A. R. (redegle)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Für mich wars so einfacher, weil ich genau weiß, welches Bit gemeint 
ist. Währe bei 2^5 (32) wohl auch erstichtlich gewesen.
Aber dies ist wohl eher die Preferenz des jeweiligen Programmierers.

Kann es sein, das GCC nicht mit Arrays arbeiten kann?

Folgender Code wird bei mir komplett übersprungen.
char array[100];
int i = 0;
while(i<100)
{
array[i]=0;
i++;
}

Autor: Maik M. (myco)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> if((ADCSRA & 0b00010000)==0b00010000)

kann man auch so schreiben:

if (ADCSRA & (1<<ADIF))

oder so:

if (ADCSRA & _BV(ADIF))

ist so denke mal viel leserlicher, oder ?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. R. schrieb:
> Für mich wars so einfacher, weil ich genau weiß, welches Bit gemeint
> ist. Währe bei 2^5 (32) wohl auch erstichtlich gewesen.

Davon war aber auch nicht die Rede!
Jedes Bit hat einen Namen! Der wird im Datenblatt verwendet und durch 
die Header Files ist dieser Name auch für dein C-Programm verfügbar.

Die meisten Programmierer wollen nämlich gar nicht wissen, welche 
Bitnummer abgefragt wird, der symbolische Name ist völlig ausreichend. 
Das hat dann auch den Vorteil, dass der Compiler die Anpassung vornimmt, 
wenn dieses Bit bei einem anderen Prozessor zwar an anderer Stelle aber 
noch im gleichen Register beheimatet ist. Der Programmierer muss sich 
dann nicht darum kümmern.

> Kann es sein, das GCC nicht mit Arrays arbeiten kann?

Ehe wir hier weitermachen:
In 99.999% aller Fälle, in denen Programmierer den Compiler eines 
Fehlers bezichtigen, stellt sich hinten nach raus, dass die Kentnisse 
der Programmierer lückenhaft, wenn nicht gar fehlerhaft sind.

Also: Ehe du den Compiler eines Fehlers bezichtigst, stell sicher, dasss 
nicht du der mit dem Fehler bist.

>
> Folgender Code wird bei mir komplett übersprungen.
>
>
> char array[100];
> int i = 0;
> while(i<100)
> {
> array[i]=0;
> i++;
> }
> 

Der Compiler kann ja auch rausgefunden haben, dass der Nettoeffekt darin 
besteht, dass Array komplett auf 0 zu setzen. Und der Compiler mag dafür 
bessere, schnellere Methoden haben, als das was du da hingeschrieben 
hast. Im Debugger siehst du dann keine 1 zu 1 Korrelation mehr zwischen 
den abgearbeiteten Anweisungen und dem was auf dem µC tatsächlich 
passiert. Solange das Endergebnis aber dasselbe ist, darf der Compiler 
das.

Autor: A. R. (redegle)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>>if (ADCSRA & (1<<ADIF))

>>oder so:

>>if (ADCSRA & _BV(ADIF))

>>ist so denke mal viel leserlicher, oder ?

Danke für den Hinweis.

>Die meisten Programmierer wollen nämlich gar nicht wissen, welche
>Bitnummer abgefragt wird, der symbolische Name ist völlig ausreichend.
>Das hat dann auch den Vorteil, dass der Compiler die Anpassung vornimmt,
>wenn dieses Bit bei einem anderen Prozessor zwar an anderer Stelle aber
>noch im gleichen Register beheimatet ist. Der Programmierer muss sich
>dann nicht darum kümmern.

Klingt logisch!
Also sind für die Namen wie DDB0, DDB1, ADLAR etc. die jeweiligen 
Wertigkeiten hinterlegt. Bzw. die Wertigkeit n-1. Also für ADIF (2^5) 
ist eine 4 hinterlegt.

>Also: Ehe du den Compiler eines Fehlers bezichtigst, stell sicher, dasss
>nicht du der mit dem Fehler bist.

Da hast du vollkommen recht!
Deswegen habe ich hier nachgefragt, ob GCC arrays beherrscht bzw. wo der 
Fehler sein könnte.
Ich habe nun folgendes Programm erstellt.

Es soll eine 2 Dimensionale Matrix mit der Größe 3600Bytes erstellt 
werden.
#include <avr/io.h>
  int main(void)
{
  char array[360][10];
  for(int i=0;i<360;i++)
  {
    for(int k = 0; k<10; k++)
    {
      array[i][k]= 0x7E;
    }
  }
return 0;
}

Beim offline Debugging überspringt er die komplette Schleife.
Meinst du, dass der Compiler so intelligent ist?

Autor: A. R. (redegle)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Compiler ist so intelligent!
Wenn später nicht auf das Array zugreife, so wird es erst gar nicht 
angelegt.

Wenn ich später eine Abfrage ergänze so klappt alles wie gewollt.
#include <avr/io.h>


  int main(void)
{
  char array[360][10];
  for(int i=0;i<360;i++)
  {
    for(int k = 0; k<10; k++)
    {
      array[i][k]= 0x7E;
    }
  }
  DDRB= 0xFF;
  PORTB = array[23][4];
return 0;
}


Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
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.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.