www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik AVR ADC Gain Differential Mode funktioniert nicht richig!


Autor: Martin 567 (martink11)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo C-Kollegen,

ich möchte gerne die Verstärkungsfunktion des ADC nutzen.

Ich verwende einen AT90Can128 und programmiere in C.
Benutzen will ich ADC2 und ADC3, vorerst mal mit 1facher Verstärkung.
Kann ich auch als Referenzspannung 5V nehmen oder muss es 2,56V sein?
Wird das Ergebniss anders berechnet als beim normalen ADC?

Hier ist mein Code. ich weiß nicht ob die Initialisierungen des ADC alle 
korrekt sind. Vielleicht seht ihr ja gleich den Fehler.
// Hier die Variablen definieren, die im Programm verwendet werden sollen
int ADCWert, result;
int spannung;


// Definitionen für Unterprogramme
void init(void);


//###########################################################################################################
// Das Unterprogramm init: Hier werden die Initialisierungen vorgenommen
void init(void)
{


// Port B initialisieren
  //DDRB=0b00000111;         // B0 B1 B2 sind Ausgang 
  //PORTB=0b00011000;      // Ausgänge auf 0 setzen, Pullups für Taster1 & 2 ein
  DDRA = 0b11111111;      // Port A ist alles Ausgang
  PORTA = 0b00000001;      // Alle Ausgänge auf 0, Enabled auf 1 (lowactive)
  DDRC = 0b01000000;
  PORTC = 0b00000000;


  sei();            // Interrupts zulassen (für timer.c wichtig)
  adc_init(0b00001100);    // ADC, Kanal 2 aktivieren

//--------------------------------------------------------------------------------------------------------
  UARTInit();     // initialize the UART (serial port)
  UCSR1A |= (1<<RXC0);
  UCSR0B |= ((1<<RXCIE0) | (1<<RXEN0) | (1<<TXEN0));
  rprintfInit(UARTSendByte);    //mit rprintf-Funktion verknüpfen
//---------------------------------------------------------------------------------------------------------


} // Ende des init- Unterprogramms



// Hauptprogramm, muss in jedem C Programm vorhanden sein
int main (void) 
{ 
  init();   // Aufruf des Unterprogramms init, nur einmal zum Programmbeginn notwendig
    

ADCSRA= (1<<ADPS2) | (1<<ADPS1)|  // prescale faktor= 128 ADC l�uft

    (1 <<ADPS0) |      // mit 14,7456MHz/ 128 = 115,2kHz 

    (1 << ADEN)|      // ADC an

    (1 << ADSC);      // Beginne mit der Konvertierung

      

  
      //Verstärkung x1
      ADMUX  = 0b11011011;
      ADCSRB = 0b00000000;
      sbi(ADCSRA, ADEN);
      sbi(ADCSRA, ADSC);
      //sbi (ADMUX, MUX4);
      //sbi (ADMUX, MUX3);
      //cbi (ADMUX, MUX2);
      //sbi (ADMUX, MUX1);
      //sbi (ADMUX, MUX0);

  while(1)  // Befehl für Endlosschleife
    {
  
    //ADCWert = adc_read(2);
  
while ( (ADCSRA & (1<<ADSC)) != 0){} //Warten bis konvertierung beendet

                // Das sollte 25 ADC-Zyklen dauern!

                // also 1/4608 s

  result= ADCL; 

  result+=(ADCH <<8);  // Ergebnis zusammenbauen

  _delay_ms(500);

    rprintf("\r\nErgebniss:  %d",result);
    spannung = (5000 / 1023.0) * result;
    rprintf("\r\nSpannung: %d mV",spannung);


  } // Ende Endlosschleife
} // Ende von main


Vielen Dank für jede Hilfe!!!
martin

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Vielleicht seht ihr ja gleich den Fehler.

Der sich wie äußert?

>  UCSR0B |= ((1<<RXCIE0) | (1<<RXEN0) | (1<<TXEN0));

Interrupt freigeben ohne Interruptroutine ist schon mal
ganz schlecht.

Autor: Martin 567 (martink11)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ja, ich habe ja alles unnötige aus dem sichtbarem code entfert um nicht 
zu verwirren, das wird nicht benötigt.

aber es gibt eine Uart-interrupt-routine

hier nochmal der code
// Include Dateien erweitern den Sprachumfang von C
#include "global.h"    // include our global settings
#include "lcd.h"          // Unterstützung für LCD-Anzeige
#include "adc.h"  // include printf function library
#include "delay.h"
#include "compat/deprecated.h"
#include "eeprom.h"
#include "uart.h"
#include "rprintf.h"
#include "stdio.h"
#include "stdlib.h"
#include "interrupt.h"
#include "dac8512.h"
#include "string.h"


// Hier die Variablen definieren, die im Programm verwendet werden sollen
int ADCWert, result;
int spannung;


// Definitionen für Unterprogramme
void init(void);


//###########################################################################################################
// Das Unterprogramm init: Hier werden die Initialisierungen vorgenommen
void init(void)
{


// Port B initialisieren
  //DDRB=0b00000111;         // B0 B1 B2 sind Ausgang 
  //PORTB=0b00011000;      // Ausgänge auf 0 setzen, Pullups für Taster1 & 2 ein
  DDRA = 0b11111111;      // Port A ist alles Ausgang
  PORTA = 0b00000001;      // Alle Ausgänge auf 0, Enabled auf 1 (lowactive)
  DDRC = 0b01000000;
  PORTC = 0b00000000;


  sei();            // Interrupts zulassen (für timer.c wichtig)
  adc_init(0b00001100);    // ADC, Kanal 2 aktivieren

//--------------------------------------------------------------------------------------------------------
  UARTInit();     // initialize the UART (serial port)
  UCSR1A |= (1<<RXC0);
  UCSR0B |= ((1<<RXCIE0) | (1<<RXEN0) | (1<<TXEN0));
  rprintfInit(UARTSendByte);    //mit rprintf-Funktion verknüpfen
//---------------------------------------------------------------------------------------------------------


} // Ende des init- Unterprogramms



// Hauptprogramm, muss in jedem C Programm vorhanden sein
int main (void) 
{ 
  init();   // Aufruf des Unterprogramms init, nur einmal zum Programmbeginn notwendig
    


      

  
      //Verstärkung x1
      ADMUX  = 0b11011011;
      ADCSRB = 0b00000000;
      sbi(ADCSRA, ADEN);



  while(1)  // Befehl für Endlosschleife
    {
  
    //ADCWert = adc_read(2);

//------------------------------------------------------------------------------------------------ Brauch ich das?? Kopiert aus adc.h

  ADCSRA= (1<<ADPS2) | (1<<ADPS1)|  // prescale faktor= 128 ADC l�uft

    (1 <<ADPS0) |      // mit 14,7456MHz/ 128 = 115,2kHz 

    (1 << ADEN)|      // ADC an

    (1 << ADSC);      // Beginne mit der Konvertierung
//-------------------------------------------------------------------------------------------------------------------------------
  
while ( (ADCSRA & (1<<ADSC)) != 0){} //Warten bis konvertierung beendet

                // Das sollte 25 ADC-Zyklen dauern!

                // also 1/4608 s

 
  
  result= ADCL; 

  result+=(ADCH <<8);  // Ergebnis zusammenbauen

    rprintf("\r\nErgebniss:  %d",result);
    spannung = (5000 / 1023.0) * result;
    rprintf("\r\nSpannung: %d mV",spannung);

_delay_ms(500);
  } // Ende Endlosschleife
} // Ende von main




hier ein paar terminal-ergebnisse:

Spannung: 4095 mV
Ergebniss:  978
Spannung: 4780 mV
Ergebniss:  250
Spannung: 1221 mV
Ergebniss:  225
Spannung: 1099 mV
Ergebniss:  971
Spannung: 4745 mV
Ergebniss:  837
Spannung: 4090 mV
Ergebniss:  63
Spannung: 307 mV
Ergebniss:  251
Spannung: 1226 mV
Ergebniss:  1007
Spannung: 4921 mV
Ergebniss:  838
Spannung: 4095 mV

im abstand von 500ms gemessen, schwankt total hin und her  ? :(

hilfee

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hab jetzt nicht genau nachgeschaut, aber lass das zusammenbasteln des 
ADC Wertes sein. Nimm "ADC" (oder ADCW?). Da ist das bereits auf 
Compilerebene erledigt.

Die Initkonstanten sind leider als nichtssagende Bit-Konstanten 
ausgeführt, statt mit Bitnamen.

Wie sieht die Beschaltung aus?

Autor: Martin 567 (martink11)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hallo

der verbesserte code mit gescheiten initialisierungen und ADCW, 
Ergebniss ist aber das gleiche!!
//###########################################################################################################
// Das Unterprogramm init: Hier werden die Initialisierungen vorgenommen
void init(void)
{


// Port B initialisieren
  //DDRB=0b00000111;         // B0 B1 B2 sind Ausgang 
  //PORTB=0b00011000;      // Ausgänge auf 0 setzen, Pullups für Taster1 & 2 ein
  DDRA = 0b11111111;      // Port A ist alles Ausgang
  PORTA = 0b00000001;      // Alle Ausgänge auf 0, Enabled auf 1 (lowactive)
  DDRC = 0b01000000;
  PORTC = 0b00000000;


  //sei();            // Interrupts zulassen (für timer.c wichtig)
  cli();
  adc_init(0b00001100);    // ADC, Kanal 2 aktivieren

//--------------------------------------------------------------------------------------------------------
  UARTInit();     // initialize the UART (serial port)
  UCSR1A |= (1<<RXC0);
  UCSR0B |= ((1<<RXCIE0) | (1<<RXEN0) | (1<<TXEN0));
  rprintfInit(UARTSendByte);    //mit rprintf-Funktion verknüpfen
//---------------------------------------------------------------------------------------------------------


} // Ende des init- Unterprogramms



// Hauptprogramm, muss in jedem C Programm vorhanden sein
int main (void) 
{ 
  init();   // Aufruf des Unterprogramms init, nur einmal zum Programmbeginn notwendig
    


      

  
  //Verstärkung x1, Vref = 2,56V
  ADMUX |= (1<<REFS1) | (1<<REFS0) | (1 <<MUX4) | (1 << MUX3) | (1 << MUX1) | (1 << MUX0);
  ADCSRB = 0x00;




  ADCSRA |= (1<<ADPS2) | (1<<ADPS1) | (1 <<ADPS0) | (1 << ADEN);  // prescale faktor= 128 ADC l�uft

                                  // mit 14,7456MHz/ 128 = 115,2kHz 

                                  // ADC an

  while(1)  // Befehl für Endlosschleife
    {
  
    //ADCWert = adc_read(2);
  
//------------------------------------------------------------------------------------------------ Brauch ich das?? Kopiert aus adc.h



  ADCSRA |= (1 << ADSC);      // Beginne mit der Konvertierung
//-------------------------------------------------------------------------------------------------------------------------------


while ( (ADCSRA & (1<<ADSC)) != 0){} //Warten bis konvertierung beendet

                // Das sollte 25 ADC-Zyklen dauern!

                // also 1/4608 s





  
result = ADCW;  // Ergebnis zusammenbauen

    rprintf("\r\nErgebniss:  %d",result);
    spannung = (2560 / 512.0) * result;
    rprintf("\r\nSpannung: %d mV",spannung);

_delay_ms(500);
  } // Ende Endlosschleife
} // Ende von main


habt ihr nicht so etwas wie ein Beispiel für mich für die Einstellungen

Momentan existiert eig keine Beschaltung ich hab an den Adc2 ein 
Netzteil gehängt und an den ADC3 auch eins, beide mit GND verbunden und 
stelle hier meine spannungen ein.
Da es sich nur um einen Versuch zu Hause handelt und die Schaltung 
selber sich in der Arbeit befindet :)

aber es sollte ja auch so gehen

Autor: Hc Zimmerer (mizch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Martin 567 schrieb:
> adc_init(0b00001100);    // ADC, Kanal 2 aktivieren

Hierzu fehlt der Code - es ist unbekannt, was adc_init macht. 
Möglicherweise macht es etwas, was durch
>  ADMUX |= (1<<REFS1) | (1<<REFS0) | (1 <<MUX4) | (1 << MUX3) | (1 << MUX1) | (1 << MUX0);
und
> ADCSRA |= (1<<ADPS2) | (1<<ADPS1) | (1 <<ADPS0) | (1 << ADEN);
nicht rückgängig gemacht wird, denn bei beiden wird verodert.  Wenn Du 
willst, dass genau dieser Wert drinsteht (wie es bei einer 
Initialisierung üblicherweise der Fall ist), solltest Du besser nicht 
verodern, sondern direkt zuweisen.

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.