ATmega168 ADC nur Single Conversion trotz Free Run

Gast #3063240
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);
Gast #3063280
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
Gast #3063379
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
}
Gast #3063397
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.
#3063403
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.
Gast #3063500
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
}
#3063508
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren