Forum: Mikrocontroller und Digitale Elektronik ADC Frage (2 Kanäle abfragen geht nicht) ohne Interrupt zu nutzen


von Hannes (Gast)


Lesenswert?

Hi,

ich habe folgende Routinen:

#define AD_MUX_CHANNEL(y)   ADMUX |= ((y)&0x0f)


void ADC_Init (void)
{
  /*
                        ADMUX
                        .-----.-----.---....
                        |REFS1|REFS0|
                        '-----'-----'---...
                            |     |
                            |     |
                            |     |
       .--.               |\|     |
  AVCC |  |---------------|0 \    |
       '--'               |   |  _|_
                          |   |-------.
       .---------------.  |   |       |
       | Internal 1.1V |--|1 /        |
       |  Reference    |  |/          |
       '---------------'              |
                                      |
       .--.                           |     .-------....
  AREF |  |---------------------------o-----| A/D Conf
       '--'                                 '-------....


  .---.-------.-------.-----------------------------------------------.
  |Nb.| REFS1 | REFS0 | Voltage Reference Selecttion (23.8.1 / P.256) |
  .---+-------+-------+-----------------------------------------------.
  | 0 |   0   |   0   | AREF, Internal VRef turned off                |
  .---+-------+-------+-----------------------------------------------.
  | 1 |   0   |   1   | AVcc with external cap. at AREF               |
  .---+-------+-------+-----------------------------------------------.
  | 2 |   1   |   0   | Reserverd                                     |
  .---+-------+-------+-----------------------------------------------.
  | 3 |   1   |   1   | Int. VRef 1.1V with ext. cap. at AREF         |
  '---'-------'-------'-----------------------------------------------'
  */

  ADMUX &=~ (1<<REFS0);
  ADMUX &=~ (1<<REFS1);                     //Referenzquelle wählen


  ADCSRA =  (1<<ADPS1) | (1<<ADPS0);    // Frequenzvorteiler
                               // setzen auf 8 (1)
}

und

uint16_t ADC_ReadChannel(uint8_t mux)
{
  uint8_t i;
  uint16_t result;

  AD_MUX_CHANNEL(mux);              //Kanal waehlen

  ADCSRA |= (1<<ADEN);

  /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man 
liest
     also einen Wert und verwirft diesen, um den ADC "warmlaufen zu 
lassen" */
  ADCSRA |= (1<<ADSC);              // eine ADC-Wandlung
  while ( ADCSRA & (1<<ADSC) ) {
     ;     // auf Abschluss der Konvertierung warten
  }
  result = ADCW;  // ADCW muss einmal gelesen werden,
                  // sonst wird Ergebnis der nächsten Wandlung
                  // nicht übernommen.

  /* Eigentliche Messung - Mittelwert aus 4 aufeinanderfolgenden 
Wandlungen */
  result = 0;
  for( i=0; i<4; i++ )
  {
    ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
    while ( ADCSRA & (1<<ADSC) ) {
      ;   // auf Abschluss der Konvertierung warten
    }
    result += ADCW;        // Wandlungsergebnisse aufaddieren
  }
  ADCSRA &= ~(1<<ADEN);             // ADC deaktivieren (2)

  result /= 4;                     // Summe durch vier teilen = arithm. 
Mittelwert

  return result;
}

Die Routine hatte ich aus dem Tutorial und dann in init() und read() 
aufgetreilt.

Ich habe nach wie vor das Problem, wenn ich sie mit read(5) und dann mit 
read(3) aufrufe, dass ich nur noch schrott bekomme, es passiert quasi 
keine Werteänderung mehr an ch5.

wenn ich nur ch5 abfrage - kein Problem.

Für einen Tip wäre ich dankbar.

Hannes
von Matthias L. (Gast)


Lesenswert?

Das Problem liegt hier:
1
#define AD_MUX_CHANNEL(y)   ADMUX |= ((y)&0x0f)

Mit der &0x0f sorgst du nur dafür, das y kleiner 16 bleibt.
Das tust du dann in das Register ADMUX rein-verodern.
Aber wenn da vorher schon ein Kanal drinstand, kommt Unsinn raus.

Versuch mal das:
1
#define AD_MUX_CHANNEL(y)  ( ADMUX = (ADMUX & 0xF0) | (y&0x0f) )

>read(5) und dann mit read(3) aufrufe

Dadurch ensteht im ADMUX der Kanal 7 = 5 OR 3
von Hannes (Gast)


Lesenswert?

danke :-)

H
von Uwe (de0508)


Lesenswert?

Hallo,

es sei noch auf

Atmel AVR126: ADC of megaAVR in Single Ended Mode

http://www.atmel.com/dyn/resources/prod_documents/doc8444.pdf

verwiesen, dort steht, wann und wie man den Kanal wechseln kann.

Wir hatten letzte Woche auch die Frage und habe eine Lösung ohne das 
Paper AVR126 gefunden - Kein Autotrigger zu verwenden..

So werden nun N-Kanäle über M-Mittelwerte gewandelt, alle X-ms, bei uns 
1ms, liegt das Ergebnis für alle ADC-Kanäle vor und wird durch die 
main() dann verarbeitet.
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.