Forum: Compiler & IDEs Atmega2560 ADC auslesen


von A. R. (redegle)


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.
1
#include <avr/io.h>
2
3
// inernet Takt 128kHz
4
// Port E hat ADC  (ADC0) PF0
5
// Ausgänge sind negiert
6
7
   
8
  int main(void)
9
10
{
11
12
 
13
#include <avr/io.h>
14
15
// Internet Takt 128kHz
16
// Der ADC ist an PortF angeschlossen, ADC0 --> PF0
17
// Ausgänge des PortB sind negiert
18
19
   
20
  int main(void)
21
22
{
23
24
  ADCSRA= 0b11100000; // Free running mode mit Takt: 128/2khz
25
  ADCSRB= 0b00000000; // Letzen 3 Bits stehen auch für free running mode
26
  ADMUX = 0b11100000; // Referenz ADLAR und Eingang // ADLAR gesetzt
27
  char Wert = 0xff;
28
  DDRB = 0b11111111; // Port B ist ein Ausgang 0b11111111 = 0xff
29
30
31
  while(1)
32
  {
33
    Wert = ~ADCH;
34
    PORTB = Wert;
35
  }
36
  
37
38
return 0;
39
}

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:
1
  while(1)
2
  {
3
    Wert = ~ADCL;
4
    PORTB = Wert;
5
  }

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?

von Maik M. (myco)


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.

von Walter (Gast)


Lesenswert?

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

von A. R. (redegle)


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.

1
#include <avr/io.h>
2
3
// Internet Takt 128kHz
4
// Der ADC ist an PortF angeschlossen, ADC0 --> PF0
5
// Ausgaege des PortB sind negiert
6
7
   
8
  int main(void)
9
10
{
11
12
  ADCSRA= 0b11100000; // Free running mode mit 128/2khz
13
  ADCSRB= 0b00000000; // Letzen 3 stehen auch für free running mode
14
  ADMUX = 0b11000000; // Referenz ADLAR und Eingang // ADLAR nicht gesetzt
15
  DDRB = 0b11111111; // Port B ist ein Ausgang 0b11111111 = 0xff
16
17
/* 
18
// Staendige Abfrage nicht notwendig
19
    char Wert = 0xff;
20
  char Dummy = 0x00;
21
  while(1)
22
  {
23
    Dummy = ADCH;
24
    Wert  = ~ADCL;
25
    PORTB = Wert;
26
  }
27
*/
28
29
// Interrupt-Flag abfragen
30
31
  short s_Wert = 0;
32
  char c_Wert= 0;
33
  while(1)
34
  {
35
    if((ADCSRA & 0b00010000)==0b00010000)
36
    {
37
      s_Wert= ADCW;
38
      c_Wert= ~(s_Wert & 0xFF); 
39
      PORTB = c_Wert;
40
    }
41
  }
42
  
43
44
return 0;
45
}

von Karl H. (kbuchegg)


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.

von A. R. (redegle)


Lesenswert?

Naja die Variable brauche ich gar nicht.

von Walter (Gast)


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

von A. R. (redegle)


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.
1
char array[100];
2
int i = 0;
3
while(i<100)
4
{
5
array[i]=0;
6
i++;
7
}

von Maik M. (myco)


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 ?

von Karl H. (kbuchegg)


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.
>
>
1
> char array[100];
2
> int i = 0;
3
> while(i<100)
4
> {
5
> array[i]=0;
6
> i++;
7
> }
8
>

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.

von A. R. (redegle)


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.
1
#include <avr/io.h>
2
  int main(void)
3
{
4
  char array[360][10];
5
  for(int i=0;i<360;i++)
6
  {
7
    for(int k = 0; k<10; k++)
8
    {
9
      array[i][k]= 0x7E;
10
    }
11
  }
12
return 0;
13
}

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

von A. R. (redegle)


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.
1
#include <avr/io.h>
2
3
4
  int main(void)
5
{
6
  char array[360][10];
7
  for(int i=0;i<360;i++)
8
  {
9
    for(int k = 0; k<10; k++)
10
    {
11
      array[i][k]= 0x7E;
12
    }
13
  }
14
  DDRB= 0xFF;
15
  PORTB = array[23][4];
16
return 0;
17
}

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.