Forum: Mikrocontroller und Digitale Elektronik ADC ansteuerung/auswertung ATmega16


von Mathias P. (aio)


Lesenswert?

Hallo!

Ich habe vor einigen Wochen ein Programm für einen ATtiny13 entworfen, 
dass über den ADC ein Potentiometer ausliest und den erhaltenen Wert 
über PWM an eine LED ausgibt. Nun möchte ich das gleiche mit einem 
ATmega16 probieren aber auf dem Chip funktioniert es einfach nicht.

(Nur für die die denken: "So ein Idiot, der weiß nicht, dass die 
Register, Ports und Pins anders sind." Ich hab natürlich das Programm an 
den Chip angepasst!)

Hier noch das Programm für den ATmega16:
1
#define F_CPU 16e6
2
3
#include <avr/io.h>
4
#include <util/delay.h>
5
6
unsigned int x;
7
8
int main(void)
9
{
10
  //Pin Initialisierung
11
  DDRA |= 0b00000000;
12
  DDRB |= 0b11111111; 
13
14
  //ADC Initialisierung
15
  ADMUX  |= ((1<<REFS0)|(1<<MUX0));
16
  ADCSRA |= ((1<<ADPS0)|(1<<ADPS1)|(1<<ADPS2));
17
  ADCSRA |= (ADEN);
18
19
  //PWM Initialisierung
20
  TCCR0 |= (0<<FOC0)|(0<<WGM01)|(1<<WGM00)|(1<<COM01)|(0<<COM00);
21
  TCCR0 |= (0<<CS02)|(0<<CS01)|(1<<CS00);
22
23
  
24
  //Dummy Conversation
25
  ADCSRA |= (1<<ADSC);
26
  while (ADCSRA & (1<<ADSC)){}
27
  x=ADCW;
28
  
29
  
30
  //Hauptschleife
31
    while(1)
32
    {
33
      x=0;
34
      ADCSRA |=(1<<ADSC);
35
      while(ADCSRA & (1<<ADSC));
36
      x=ADCH;
37
      OCR0 =x;  
38
    }
39
 }

Vielen Dank im Voraus
MP

von chris (Gast)


Lesenswert?

Mathias Pichler schrieb:
> x=ADCH;

Habe gerade keine Zeit, die ganzen Initialisierungen nachzuprüfen.
Aber mit dieser Codezeile liest du nur die obersten beiden Bits des 
Ergebnisses aus.
Versuchs mal mit:
1
x = ADC;

von Mathias P. (aio)


Lesenswert?

Danke für die Rasche Antwort Chris aber ich hab ADC und ADCW schon 
probiert und für dieses Programm, das ja nur ein "Testprogramm" für ein 
anderes Projekt ist, ist der ADCH-Wert genau genug.

von nörgel (Gast)


Lesenswert?

Mathias Pichler schrieb:
> ATmega16 probieren aber auf dem Chip funktioniert es einfach nicht.

Wenn man wenigstens wüßte was es werden soll und was "nicht 
funktioniert". Aus dem Programm kann man es wohl nicht entnehmen, da es 
da ja wohl "nicht funktioniert".

> (Nur für die die denken: "So ein Idiot, der weiß nicht, dass die
> Register, Ports und Pins anders sind." Ich hab natürlich das Programm an
> den Chip angepasst!)

Ob du das richtig angepaßt hast können wir auch nicht überprüfen mangels 
ursprünglichen Sourcecodes.

> Hier noch das Programm für den ATmega16:

Ohne aussagekräftige Kommentare im Begleittext oder im Programm ... 
mache ich auch nicht weiter mit irgendwelchen Überprüfungen (gegen was 
auch?)

Eigentlich hast du nur ein nicht funktonierendes Programm gepostet oder 
ist es am Ende vielleicht die HW.

von Alexander S. (alesi)


Lesenswert?

Mathias Pichler schrieb:
> #define F_CPU 16e6

Wird F_CPU irgendwo in

> #include <avr/io.h>
> #include <util/delay.h>

verwendet? Soweit ich weiß ist die nnEm Notation nur für float
und double erlaubt:

format_int.c
1
#include <stdio.h>
2
3
int main(int argc, char *argv[]) {
4
5
  printf("%ld\n", 16e6);
6
7
  return 0;
8
}

gcc> format_int.c:5:3: warning: format ‘%ld’ expects argument of type 
‘long int’, but argument 2 has type ‘double’ [-Wformat]

$ ./format_int
140725075173912

von M. K. (sylaina)


Lesenswert?

Fangen wir mal an:
1
#define F_CPU 16e6
ist schonmal nicht sehr gut, da muss stehen
1
#define F_CPU 16000000UL
andererseits wird der Compiler, je nach Version, hier versuchen was weg 
zu optimieren
1
TCCR0 |= (0<<FOC0)|(0<<WGM01)|(1<<WGM00)|(1<<COM01)|(0<<COM00);
Nullen mit ODER zu verknüpfen kannst du dir schenken, in diesem Beispiel 
wird bei FOC0 der Wert stehen, der im TCCR0-Register an der Stelle von 
FOC0 steht, so wirst du ihn nie zu 0 setzen können.
1
x=ADCW;
Da das Ergebniss wird ja nicht verwendet, warum also auslesen? Zeile ist 
überflüssig! Besser steht da
1
(void)ADCW
1
x=ADCH;
Macht nur Sinn, wenn man das ADLAR gesetzt ist, also das ADC-Ergebniss 
auch nach links schieben lässt. Sonst hat man nur zwei Bit und die sind 
mal für so gar nix gut.

von Dieter F. (Gast)


Lesenswert?

Mathias Pichler schrieb:
> (0<<WGM01)|(1<<WGM00)

Das sollte für den CTC-Mode umgekehrt sein. So zählt er bis zum 
TOP-Wert.

von Mathias P. (aio)


Lesenswert?

nörgel schrieb:
>Wenn man wenigstens wüsste was es werden soll
Die Ansteuerung einer LED über PWM, dimmbar über ein Potentiometer, das 
am ADC ausgelesen wird. Der ADC funktioniert in dem Programm nicht.

Funktionierendes Programm für ATtiny13:
1
//Target ATtiny13
2
3
#define F_CPU 16e6
4
5
#include <avr/io.h>
6
#include <util/delay.h>
7
8
unsigned int x;
9
10
int main(void)
11
{
12
  x =0;
13
14
  DDRB |= 0b000000;
15
  ADMUX |= (0<<REFS0)| (0<<ADLAR)|(1<<MUX0)|(0<<MUX1);
16
  ADCSRA |= (1<<ADEN)|(0<<ADPS0)|(1<<ADPS1)|(1<<ADPS2);
17
18
19
  DDRB |= (1<<DDB0);                    //PORT PB0 als Ausgang
20
  TCCR0A |=(1<<COM0A1)|(0<<COM0A0)|(1<<WGM00)|(0<<WGM01);  //definition,wann Pin geschalten wird & Waveformgenerator
21
  TCCR0B = (1<<CS00)|(0<<CS01)|(0<<CS02)|(0<<WGM02);    //Prescaler & Waveformgenerator
22
  
23
  //Dummy Conversation
24
  ADCSRA |= (1<<ADSC);
25
  while (ADCSRA & (1<<ADSC));
26
  (void)ADCW;
27
28
    //Hauptschleife
29
     while(1)
30
    {
31
      x=0;
32
        ADCSRA |=(1<<ADSC);
33
        while(ADCSRA & (1<<ADSC));
34
        x = ADCW;
35
      OCR0A =x;  
36
    }
37
}

Kommentiertes und abgeändertes Programm:
(funktioniert immer noch nicht)
1
//Target ATmega16
2
3
#define F_CPU 16e6 //Taktfrequenz Initialisierung
4
5
//Einbinden benötigter resourcen
6
#include <avr/io.h>
7
#include <util/delay.h>
8
9
//definieren verwendeter Variablen
10
unsigned int x;
11
12
//Start des eigentlichen Programmes
13
int main(void)
14
{
15
  //Port Initialisierung
16
  DDRA |= 0b00000000;  //Initialisierung für Port PA0 bis PA7
17
  DDRB |= 0b11111111; //Initialisierung für Port PB0 bis PB7
18
19
  //ADC Initialisierung
20
21
  //Auswählen der internen Versorgungsspannung als Referenz und
22
  //auswahl des auszulesenden Pins
23
  ADMUX |= 0b00000000;
24
  ADMUX |= ((1<<REFS0)|(1<<MUX0))|(1<<ADLAR);//ADLAR-Bit gesetzt
25
26
  //Frequenzvorteiler auswählen für eine Frequenz zwischen 50 und 200 kHz (128)
27
  ADCSRA |= 0b00000000;
28
  ADCSRA |= ((1<<ADPS0)|(1<<ADPS1)|(1<<ADPS2));
29
30
  //ADC aktivieren
31
  ADCSRA |= (ADEN);
32
33
  //PWM Initialisierung
34
  TCCR0 |= 0b00000000;
35
  TCCR0 |= (1<<WGM00)|(0<<FOC0)|(0<<WGM01)|(1<<COM01)|(0<<COM00);
36
  TCCR0 |= (1<<CS00)|(0<<CS02)|(0<<CS01);
37
38
  
39
  //Dummy Conversation
40
  ADCSRA |= (1<<ADSC);  //Starte die Messung
41
  while (ADCSRA & (1<<ADSC)){}  //Warte bis die Messung abgeschlossen ist
42
  (void)ADCW;  //Verwerfung des ersten Messwertes
43
  
44
  
45
  
46
  
47
  //Hauptschleife (hoffentlich selbsterklärend[funktion wie Dummy Conversation])
48
    while(1)
49
    {
50
      x=0;
51
      ADCSRA |=(1<<ADSC);
52
      while(ADCSRA & (1<<ADSC));
53
      x=ADCH;  //Zuordnung des ADCH wertes an x
54
      OCR0 =x;//Übernahme des x Wertes von OCR0 (diese schritte sind eigentlich Überflüssig)
55
    }
56
 }

@Alexander S.: bis jetzt gab es keine Probleme mit der Frequenz weil der 
PWM Generator auch von der verwendeten Frequenz abhängt.

@Michael Köhler: alle Tips übernommen

@Dieter: PWM funktioniert

von S. Landolt (Gast)


Lesenswert?

Das Potenziometer ist an ADC1, also PA1, angeschlossen?

von asdfasd (Gast)


Lesenswert?

Hat dir schon mal jemand gesagt, dass man mit | und entpsrechend auch |= 
Bits nicht auf 0 setzten kann?



.oO(immer diese Voodoo-Programmierer...)

von Mathias P. (aio)


Lesenswert?

@ Landolt

Ja ist es. Ich habe schon alle Pins durchprobiert aber die LED bleibt 
dunkel.

@asdfasd
1
//Target ATmega16
2
3
#define F_CPU 16e6 //Taktfrequenz Initialisierung
4
5
//Einbinden benötigter resourcen
6
#include <avr/io.h>
7
#include <util/delay.h>
8
9
//definieren verwendeter Variablen
10
unsigned int x;
11
12
//Start des eigentlichen Programmes
13
int main(void)
14
{
15
  //Port Initialisierung
16
  DDRA |= 0b00000000;  //Initialisierung für Port PA0 bis PA7
17
  DDRB |= 0b11111111; //Initialisierung für Port PB0 bis PB7
18
19
  //ADC Initialisierung
20
21
  //Auswählen der internen Versorgungsspannung als Referenz und
22
  //auswahl des auszulesenden Pins
23
  ADMUX |= ((1<<REFS0)|(1<<MUX0))|(1<<ADLAR);
24
25
  //Frequenzvorteiler auswählen für eine Frequenz zwischen 50 und 200 kHz (128)
26
  ADCSRA |= ((1<<ADPS0)|(1<<ADPS1)|(1<<ADPS2));
27
28
  //ADC aktivieren
29
  ADCSRA |= (ADEN);
30
31
  //PWM Initialisierung
32
  TCCR0 |= (1<<WGM00)|(1<<COM01);
33
  TCCR0 &= ~(1<<FOC0)|(1<<WGM01)|(1<<COM00);
34
  TCCR0 |= (1<<CS00);
35
  TCCR0 &= ~(1<<CS02)|(1<<CS01);
36
37
  
38
  //Dummy Conversation
39
  ADCSRA |= (1<<ADSC);  //Starte die Messung
40
  while (ADCSRA & (1<<ADSC)){}  //Warte bis die Messung abgeschlossen ist
41
  (void)ADCW;  //Verwerfung des ersten Messwertes
42
  
43
  
44
  
45
  
46
  //Hauptschleife (hoffentlich selbsterklärend[funktion wie Dummy Conversation])
47
    while(1)
48
    {
49
      x=0;
50
      ADCSRA |=(1<<ADSC);
51
      while(ADCSRA & (1<<ADSC));
52
      x=ADCH;  //Zuordnung des ADCH wertes an x
53
      OCR0 =x;//Übernahme des x Wertes von OCR0 (diese schritte sind eigentlich Überflüssig)
54
    }
55
 }

Ich hoffe es gefällt dir jetzt besser, aber der ADC funktioniert leider 
noch immer nicht.

von Fritz G. (fritzg)


Lesenswert?

Lies doch endlich mal ADC und nicht ADCH!

von Mathias P. (aio)


Lesenswert?

@ Fritz Ganter

Hab ich ausprobiert und es hat nicht geholfen.

von M. K. (sylaina)


Lesenswert?

Mathias Pichler schrieb:
> @ Fritz Ganter
>
> Hab ich ausprobiert und es hat nicht geholfen.

Aber ADC wäre zumindest der richtige Registername bei Atmega16, nicht 
wie du z.B. geschrieben hast ADCW.

Dann fällt mir grade auf, einmal schreibst du
1
while (ADCSRA & (1<<ADSC)){}

und einmal schreibst du
1
while(ADCSRA & (1<<ADSC));

Sage uns doch bitte, was du dir dabei gedacht hast? Warum diese 
unterschiedliche Schreibweise?
1
DDRA |= 0b00000000;
Eine ODER-Verknüpfung mit 0 kann keine Bits verändern, warum versuchst 
du das immer noch? Die Zeile hat keinen Effekt ausser Prozessorzeit zu 
verbraten.

Und dass die LED dunkel bleibt, ich hab mir die PWM-Sachen nicht genau 
angeschaut aber du benutzt hat nur das ADCH-Register zum Einstellen der 
PWM…also nur 2 von 16 Bits die in OCR0 rein passen. Wie lang ist bzw. 
soll deine LED so an sein? Je nach PWM-Mode hast du bis zu 255 Counts, 
deine ADC-Auslesetechnik aber führt dazu, dass du nach maximal 4 Counts 
schalten lässt.
Vielleicht ist auch dein LED falsch angeschlossen oder kaputt. Schließe 
einfach mal ein Oszilloskop an PB3 und schau nach, was der Portpin 
macht.

von Mathias P. (aio)


Lesenswert?

@ Michael Köhler

Dabei habe ich mir gar nichts gedacht sondern nur vergessen die zweite 
Wartesequenz zu ändern.
Ich habe jetzt beide abschnitte in
1
while (ADCSRA & (1<<ADSC))//Warte bis die Messung abgeschlossen ist
2
  {
3
  }
geändert.

Es tut miraußerdem leid, dass ich jedes mal vergesse diese Zuweisung zu 
ändern.
->geändert in
1
DDRA = 0b00000000;
2
DDRB = 0b11111111;
Ich hoffe sie ist jetzt richtig

Bezüglich ADC und ADCW ist kein unterschied, denn im iom16.h File steht:
1
/* Combine ADCL and ADCH */
2
#ifndef __ASSEMBLER__
3
#define ADC   _SFR_IO16(0x04)
4
#endif
5
#define ADCW  _SFR_IO16(0x04)
6
#define ADCL    _SFR_IO8(0x04)
7
#define ADCH    _SFR_IO8(0x05)
Soweit ich mir das angesehen habe bedeutet das, dass ADC funktioniert, 
wenn es nicht im Assembler Code geschrieben ist, ADCW aber immer 
funktioniert.
oder liege ich da falsch???

Die LED funktioniert einwandfrei, denn ich habe jetzt eine Sequenz in 
mein Programm eingefügt, bei der jedes mal, wenn das System einen Reset 
erfährt einmal kurz hoch- und runter- dimmt(Ich habe die LED richtig 
herum eingebaut ;-) )
1
        //Testen ob LED funktioniert
2
  for (int x = 0;x<=255;x++)//Max: 255
3
    {
4
      OCR0 = x;  
5
      _delay_ms(5);
6
    }
7
8
    for (int x = 255;x>=0;x--)//Max: 255
9
    {
10
      OCR0 = x;  
11
      _delay_ms(5);
12
    }
Damit ist das überprüfen mittels Oszi überflüssig und bewiesen, dass der 
PWM-ausgang funktioniert.

Ich lasse das ADC Ergebnis jetzt auch durch vier teilen (,weil wie du 
richtig bemerkt hast der PWM-Mode nur 255 schaltstufen kennt der ADC 
aber 1024 werte ausgibt)
1
    //Hauptschleife (hoffentlich selbsterklärend[funktion wie Dummy Conversation])
2
    while(1)
3
    {
4
      x=0;
5
      ADCSRA |=(1<<ADSC);
6
      while(ADCSRA & (1<<ADSC))
7
      {
8
      }
9
      x=ADCW;  //Zuordnung des ADC wertes an x
10
      x /= 4;
11
      OCR0 =x;//Übernahme des x Wertes von OCR0 
12
    }

Ich hoffe, dass das genügend Infos waren, dass Ihr mir helfen könnt, 
denn es funktioniert leider immer noch nicht.

Lg MP

von Steffen (Gast)


Lesenswert?

Mathias Pichler schrieb:
> //ADC aktivieren
>   ADCSRA |= (ADEN);

sollte das nicht
1
ADCSRA |= (1<<ADEN);
sein?

Lass dir doch mal den ADC Wert per RS Ausgeben. Damit sieht du ob 
überhaupt was gewandelt wird.

Zeig mal deine Beschaltung. Nicht das da was fehlt. Läuft der µC mit 
16Mhz?

von Mathias P. (aio)


Lesenswert?

@ Steffen

OMG wie konnte ich das übersehen...

Jetzt Funktioniert es endlich!!
Ich danke dir und allen anderen Leuten, die sich dazu herabgelassen 
haben, mir zu helfen.
Vielenvielen Dank an euch alle.

Lg MP

von Steffen (Gast)


Lesenswert?

Mathias Pichler schrieb:
> OMG wie konnte ich das übersehen...

Mit deinen eigenen Worten gesagt:

Mathias Pichler schrieb:
> (Nur für die die denken: "So ein Idiot, der weiß nicht, dass die
> Register, Ports und Pins anders sind." Ich hab natürlich das Programm an
> den Chip angepasst!)

;-)

von Mathias P. (aio)


Lesenswert?

Du hast ja so recht
Shame on me ;-)

Lg MP

von Steffen (Gast)


Lesenswert?

Das ist bei unterschiedlichen µC halt das Problem, dass man sehr genau 
lesen muss. Ging mir auch schon so, da macht man schnell mal 
Schusselfehler.

von Mathias P. (aio)


Lesenswert?

Man denkt, dass man alles richtig Initialisiert hat und überliest dann 
die Fehler, weil man sie einfach nicht wahrhaben will

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.