www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik AVR AT90CAN128 ADC


Autor: Michael S. (elmsfeuer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich bin etwas ratlos aufgrund meines Problems. Ich möchte eine einfache 
Single-Channel ADC-Wandlung vornehmen, aber egal ob sich die 
Eingangsspannung ändert bleibt der gewandelte Wert konstant. Vielleicht 
weiß von Euch jemand rat oder kann mir auf die Spünge helfen was ich 
falsch mache.

Ich benutze das STK500 + STK501 + AT90CAN128 + JTAGICEmkII + aktl. 
Version AVR-Studio + aktl. Version Win-AVR

Hier "mein" Code:
#include "config.h"
#include "uart_lib.h"
#include "uart_drv.h"
#include "rtc_drv.h"

void init(void)
{
   Uart_select(UART_0);
   uart_init(CONF_8BIT_NOPAR_1STOP,38400);

   //Liefert die zu messende Spannung
   DDRB |= (1<<PB0);
   PORTB |= (1<<PB0);
}

unsigned int ReadChannel(unsigned char mux)
{
  unsigned char i;
  unsigned int result;

  ADMUX = mux;                      // Kanal waehlen
  ADMUX |= (0<<REFS1) | (1<<REFS0); // interne Referenzspannung nutzen
 
  ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);    // Frequenzvorteiler 
                               // setzen auf 8 (1) und ADC aktivieren (1)
 
  /* 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;
}

int main(void)
{
   unsigned int counter, adc, i;
   counter = adc = 0;
   init();
   rtc_int_init();

   while(1)
   {
      for (i = 0; i< 8; i++)
      {
         wait_for(500);
         adc = ReadChannel(i);
         uart_mini_printf ("\r%04X Spannung(%u):%04X %umV\n", counter++, i, adc, (unsigned int)(((double)adc/1023)*5000));
      }
   }
   return 0;
}

Die Funktionen wait_for() und rtc_... stammen aus den Atmel-Libs vom 
DVK90CAN1-Board.

FOSC = 8 Mhz.

Als Messspannung hab ich den Ausgang von PB0 mit zwei 1k R 
runtergeteilt. Als Referenzspannung ist AVCC ausgewählt und auf AREF ist 
ein 100nF C dran. Die Spannungen an PB0 und AVCC sind wie erwartet mit 
dem Oszi zu messen.
PB0/2 = 2.50V -> PA1
AVCC = 5.01V

Den Jumper AREF vom STK500 hab ich entfernt. Den Chip hab ich auch 
bereits getauscht.

Die Schleife in main() hab ich eingebaut, weil mir beim wechseln des 
Eingangsports aufgefallen ist, daß auf den anderen Eingangskanälen 
ebenfalls "feste" Werte zu messen sind.

Lege ich PA1 auf GND ändert sich an den Ausgabewerten nichts und es ist 
definitiv nur ein Kabel vom Spannungsteiler auf dem PA1-Pin gelegt, der 
Rest des Port A ist nicht belegt.

Hier die UART-Ausgabe (2 Schleifendurchgänge):
0038 Spannung(0):034F 4139mV
0039 Spannung(1):02F0 3675mV
003A Spannung(2):02D9 3563mV
003B Spannung(3):02F3 3690mV
003C Spannung(4):03FF 5000mV
003D Spannung(5):03FF 5000mV
003E Spannung(6):03FF 5000mV
003F Spannung(7):03FF 5000mV
0040 Spannung(0):034F 4139mV
0041 Spannung(1):02F0 3675mV
0042 Spannung(2):02D9 3563mV
0043 Spannung(3):02F4 3695mV
0044 Spannung(4):03FF 5000mV
0045 Spannung(5):03FF 5000mV
0046 Spannung(6):03FF 5000mV
0047 Spannung(7):03FF 5000mV

Ich hoffe es kann mir jemand helfen. Danke.

MfG
Michael

Autor: Lutz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Michael,

die Zeile
ADMUX |= (0<<REFS1) | (1<<REFS0); // interne Referenzspannung nutzen
bringt vermutlich schon mal nicht das, was Du wolltest (eine Null 
schieben ist schon schlecht).

Gruß
Lutz

Autor: Lutz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Michael,

in diesem Falle scheint es egal zu sein, wenn Du die Null um 7 Stellen 
nach links schieben willst. Falsch ist auf den ersten Blick aber der 
Kommentar
>> ADMUX |= (0<<REFS1) | (1<<REFS0); // interne Referenzspannung nutzen
da Du ja, wie weiter unten auch geschrieben, AVCC als Referenzspannung 
auswählst.

Vielleicht wählst Du für den Eingang des ADC aber lieber, wie im 
Datenblatt beschrieben, PORTF als ADC-Eingang und nicht PORTA? Die 
Beschreibung AD1 bei PA1 ist nämlich für External Memory Interfaces und 
nicht für den ADC ...

Gruß
Lutz

Autor: Michael S. (elmsfeuer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Guten morgen,

danke Dir Lutz für den Hinweis, das wär mir in tausend Jahren nicht 
aufgefallen, den Fehler der Portverwechselung habe ich gleich am Anfang 
gemacht und mit durchgeschleppt und war mir bei jedem Blick auf die 
Pin-Konfiguration im Datenblatt sicher AD0-AD7 wären die ADC-Eingänge. 
Also vielen Dank für den Hinweis und entschuldige bitte das ich durch 
meine Nachlässigkeit Deine Zeit verschwendet habe.

Du hast auch Recht im Bezug auf das ADMUX-Register. Habe beim ändern des 
Codes das Kommentar nicht geändert und war zu faul (1<<REFS1) zu löschen 
und habe stattdessen aus der 1 eine 0 gemacht.

Also in der Schaltung PB0/2 auf PF0 und zack es funktioniert.

Das ist der jetzt funktionierende Code:
#include "config.h"
#include "uart_lib.h"
#include "uart_drv.h"
#include "rtc_drv.h"

void init(void)
{
   Uart_select(UART_0);
   uart_init(CONF_8BIT_NOPAR_1STOP,38400);

   //Liefert die zu messende Spannung
   DDRB |= (1<<PB0);
   PORTB |= (1<<PB0);
}

unsigned int ReadChannel(unsigned char mux)
{
  unsigned char i;
  unsigned int result;

  ADMUX = mux;                      // Kanal waehlen
  ADMUX |= (1<<REFS0); // AVCC als Referenzspannung nutzen
 
  ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);    // Frequenzvorteiler 
                               // setzen auf 8 (1) und ADC aktivieren (1)
 
  /* 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;
}

int main(void)
{
   unsigned int counter, adc, i;
   counter = adc = 0;
   init();
   rtc_int_init();

   while(1)
   {
      wait_for(500);
      adc = ReadChannel(0);
      uart_mini_printf ("\r%04X Spannung:%04X %umV\n", counter++, adc, (unsigned int)(((double)adc/1023)*5000));
   }
   return 0;
}

Danke für die Hilfe!!! Kann man den Thread eigentlich als erledigt 
markieren/schließen?

MfG
Michael

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.