Forum: Mikrocontroller und Digitale Elektronik ATmega168 ADC nur Single Conversion trotz Free Run


von Tungsten (Gast)


Lesenswert?

Hallo Forum,

ich bin gerade dabei ein Projekt von ATmega8 (4MHz) auf ATmega168 
(18,432MHz) zu transferieren, aber der ADC will nicht so richtig 
arbeiten.

Ich lese über den ADC-Eingang einen NTC-Wert, verwende die internen 1,1V 
als Referenz und habe dafür die Spannungsteiler (wegen 2,56V beim mega8) 
angepasst.

Nach dem Reset bekomme ich beim ersten Lesen des ADC einen plausiblen 
Wert, jedes weitere Lesen liefert nur 1023.

Habe schon einiges probiert. Vielleicht könnt ihr mich auf eine 
Eigenschaft oder Fehler aufmerksam machen.

Lg,
Tungsten
1
void init_adc(){
2
  // Set ADC reference
3
  ADMUX |= (1 << REFS1) | (1 << REFS0); // Internal 1.1V Voltage Reference with external cap at AREF
4
5
  ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Prescaler 128
6
    
7
  ADCSRB |= (0 << ADTS2) | (0 << ADPS1) | (0 << ADPS0); // Free Running mode
8
  //ADCSRA |= (1 << ADATE); // Enable ADC Interrupt
9
    
10
  ADCSRA |= (1 << ADEN);// Enable ADC
11
12
  ADCSRA |= (1 << ADSC); // Start conversions
13
}
14
void setchannel_adc(uint8_t channel)
15
{
16
  ADMUX &= 0b11110000; //clean channel
17
  channel = channel & 0b00001111;
18
  ADCSRA &= ~(1 << ADEN);
19
  ADMUX = channel; //set channel
20
  ADCSRA |= (1 << ADEN);
21
}
22
23
/*
24
 * read from adc channel
25
 */
26
uint16_t read_adc(uint8_t channel) 
27
{
28
  setchannel_adc(channel);
29
  ADCSRA |= (1 << ADSC); // Start conversion
30
  while( !(ADCSRA & (1<<ADIF)) ); // Wait for conversion to complete 
31
  uint16_t adc = ADC;
32
  ADCSRA |= (1 << ADIF); // Clear ADIF by writing one to it
33
  return(adc);
34
}

Aufruf:
1
uint16_t ntcValue = read_adc(1);

von Spess53 (Gast)


Lesenswert?

Hi

>  ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Prescaler 128

>  ADCSRB |= (0 << ADTS2) | (0 << ADPS1) | (0 << ADPS0); // Free Running mode

Sieht ulkig aus. Aber der wirkliche Fehler ist, das du Autotrigger 
(ADATE in ADCSRA) gar nicht erlaubst.

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?

>   ADMUX = channel; //set channel


gratuliere. Du hast dir gerade die Einstellung der Referenzspannung 
unter dem Allerwertesten weggeschaltet.

von Tungsten (Gast)


Lesenswert?

@ Spess, danke für den Hinweis, ADATE habe ich hinzugefügt.
@K.H. .. der Allerwerteste ist wichtig, darauf werde ich jetzt achten.

Ich habe die Änderungen eingebracht, leider gleiches Verhalten. Nach dem 
Reset liefert das erste read_adc einen Wert (z.B.609) und jedes folgende 
read_adc 1023,1023,1023,...

????

1
void setchannel_adc(uint8_t channel)
2
{
3
  ADCSRA &= ~(1 << ADEN);
4
  ADMUX |= (channel&0x0F); //set channel
5
  ADMUX |= (1 << REFS1) | (1 << REFS0); // Internal 1.1V Voltage Reference with external cap at AREF
6
  ADCSRA |= (1 << ADEN);
7
}
8
9
/*
10
 * read from adc channel
11
 */
12
uint16_t read_adc(uint8_t channel) 
13
{
14
  setchannel_adc(channel);
15
  ADCSRA |= (1 << ADSC); // Start conversion
16
  while( !(ADCSRA & (1<<ADIF)) ); // Wait for conversion to complete 
17
  uint16_t adc = ADC;
18
  ADCSRA |= (1 << ADIF); // Clear ADIF by writing one to it
19
  return(adc);
20
}
21
22
void init_adc(){
23
  // Set ADC reference
24
  ADMUX |= (1 << REFS1) | (1 << REFS0); // Internal 1.1V Voltage Reference with external cap at AREF
25
  ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Prescaler 128  
26
  ADCSRB |= (0 << ADTS2) | (0 << ADPS1) | (0 << ADPS0); // Free Running mode
27
  ADCSRB |= (1 << ADATE); // Auto Trigger Enable
28
    
29
  ADCSRA |= (1 << ADEN);// Enable ADC
30
  ADCSRA |= (1 << ADSC); // Start conversions
31
}

von Karl H. (kbuchegg)


Lesenswert?

Mir ist eines nicht klar.
Wozu der ganze Hackmack mit dem Free Running, wenn du dann sowieso in 
der read Funktion den ADC händisch triggerst.

Hast du schon mal die ADC Funktionen aus dem AVR-GCC-Tutorial so wie sie 
sind (mit der Ausnahme der Referenzspannungseinstellung) benutzt?

AVR-GCC-Tutorial/Analoge Ein- und Ausgabe: Nutzung des ADC

von Tungsten (Gast)


Lesenswert?

Die Änderungen passen!!!!!

Es geht, war ein nach den Änderungen noch ein Fehler beim Compilieren.

Jetzt geht es, SUPER, DANKE

von Tungsten (Gast)


Lesenswert?

K.H. da hast du schon recht, nach einigen Stunden Fehlersuchen probiert 
man alles, egal ob logisch oder nicht...
Jetzt wo es geht werde ich alles redundante weggeben und auch händisch 
triggern.

DANKE.

von Spess53 (Gast)


Lesenswert?

Hi

>@ Spess, danke für den Hinweis, ADATE habe ich hinzugefügt.

>  ADCSRB |= (1 << ADATE); // Auto Trigger Enable

Nö. ADATE ist in ADCSRA.

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?

Tungsten schrieb:
> K.H. da hast du schon recht, nach einigen Stunden Fehlersuchen probiert
> man alles, egal ob logisch oder nicht...
> Jetzt wo es geht werde ich alles redundante weggeben und auch händisch
> triggern.

Tip:
Lass das ADIF Flag in Ruhe. Du brauchst es nicht, und es macht nur 
Arbeit. Die Sache ist ganz einfach: Du setzt das ADSC Bit und wenn der 
ADC fertig ist, zieht er es wieder auf 0 zurück.

Siehe Tutorial.

von Tungsten (Gast)


Lesenswert?

@ Spess, danke für den Hinweis, das war jetzt wirklich schlamping, 
wirklich schlampig...

@K.H. Danke, ich habe das geändert.

Vermutlich könnte ich auch ADC direkt zurückgeben und bräuchte die adc 
Variable auch nicht.

Schönen Abend noch...
Tungsten

1
uint16_t adc_read(uint8_t channel) 
2
{
3
  adc_setchannel(channel);
4
  ADCSRA |= (1 << ADSC); // Start conversion
5
  while( IS_BIT_SET(ADCSRA,ADIF) ); // Wait for conversion to complete 
6
  uint16_t adc = ADC;
7
  return(adc);
8
}

von Karl H. (kbuchegg)


Lesenswert?

>   while( IS_BIT_SET(ADCSRA,ADIF) ); // Wait for conversion to complete

ADSC, nicht ADIF


Studier doch bitte die Routinen aus dem Tutorial. Es macht keinen 
wirklichen Spass deine ganzen Tippfehler zu korrigieren, wenn du dort 
fix fertige, sauber funktionierende Funktionen finden kannst.

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.