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


von Martink11 M. (Firma: google) (martink11) Flattr this


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.
1
// Hier die Variablen definieren, die im Programm verwendet werden sollen
2
int ADCWert, result;
3
int spannung;
4
5
6
// Definitionen für Unterprogramme
7
void init(void);
8
9
10
//###########################################################################################################
11
// Das Unterprogramm init: Hier werden die Initialisierungen vorgenommen
12
void init(void)
13
{
14
15
16
// Port B initialisieren
17
  //DDRB=0b00000111;         // B0 B1 B2 sind Ausgang 
18
  //PORTB=0b00011000;      // Ausgänge auf 0 setzen, Pullups für Taster1 & 2 ein
19
  DDRA = 0b11111111;      // Port A ist alles Ausgang
20
  PORTA = 0b00000001;      // Alle Ausgänge auf 0, Enabled auf 1 (lowactive)
21
  DDRC = 0b01000000;
22
  PORTC = 0b00000000;
23
24
25
  sei();            // Interrupts zulassen (für timer.c wichtig)
26
  adc_init(0b00001100);    // ADC, Kanal 2 aktivieren
27
28
//--------------------------------------------------------------------------------------------------------
29
  UARTInit();     // initialize the UART (serial port)
30
  UCSR1A |= (1<<RXC0);
31
  UCSR0B |= ((1<<RXCIE0) | (1<<RXEN0) | (1<<TXEN0));
32
  rprintfInit(UARTSendByte);    //mit rprintf-Funktion verknüpfen
33
//---------------------------------------------------------------------------------------------------------
34
35
36
} // Ende des init- Unterprogramms
37
38
39
40
// Hauptprogramm, muss in jedem C Programm vorhanden sein
41
int main (void) 
42
{ 
43
  init();   // Aufruf des Unterprogramms init, nur einmal zum Programmbeginn notwendig
44
    
45
46
ADCSRA= (1<<ADPS2) | (1<<ADPS1)|  // prescale faktor= 128 ADC l�uft
47
48
    (1 <<ADPS0) |      // mit 14,7456MHz/ 128 = 115,2kHz 
49
50
    (1 << ADEN)|      // ADC an
51
52
    (1 << ADSC);      // Beginne mit der Konvertierung
53
54
      
55
56
  
57
      //Verstärkung x1
58
      ADMUX  = 0b11011011;
59
      ADCSRB = 0b00000000;
60
      sbi(ADCSRA, ADEN);
61
      sbi(ADCSRA, ADSC);
62
      //sbi (ADMUX, MUX4);
63
      //sbi (ADMUX, MUX3);
64
      //cbi (ADMUX, MUX2);
65
      //sbi (ADMUX, MUX1);
66
      //sbi (ADMUX, MUX0);
67
68
  while(1)  // Befehl für Endlosschleife
69
    {
70
  
71
    //ADCWert = adc_read(2);
72
  
73
while ( (ADCSRA & (1<<ADSC)) != 0){} //Warten bis konvertierung beendet
74
75
                // Das sollte 25 ADC-Zyklen dauern!
76
77
                // also 1/4608 s
78
79
  result= ADCL; 
80
81
  result+=(ADCH <<8);  // Ergebnis zusammenbauen
82
83
  _delay_ms(500);
84
85
    rprintf("\r\nErgebniss:  %d",result);
86
    spannung = (5000 / 1023.0) * result;
87
    rprintf("\r\nSpannung: %d mV",spannung);
88
89
90
  } // Ende Endlosschleife
91
} // Ende von main


Vielen Dank für jede Hilfe!!!
martin

von holger (Gast)


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.

von Martink11 M. (Firma: google) (martink11) Flattr this


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
1
// Include Dateien erweitern den Sprachumfang von C
2
#include "global.h"    // include our global settings
3
#include "lcd.h"          // Unterstützung für LCD-Anzeige
4
#include "adc.h"  // include printf function library
5
#include "delay.h"
6
#include "compat/deprecated.h"
7
#include "eeprom.h"
8
#include "uart.h"
9
#include "rprintf.h"
10
#include "stdio.h"
11
#include "stdlib.h"
12
#include "interrupt.h"
13
#include "dac8512.h"
14
#include "string.h"
15
16
17
// Hier die Variablen definieren, die im Programm verwendet werden sollen
18
int ADCWert, result;
19
int spannung;
20
21
22
// Definitionen für Unterprogramme
23
void init(void);
24
25
26
//###########################################################################################################
27
// Das Unterprogramm init: Hier werden die Initialisierungen vorgenommen
28
void init(void)
29
{
30
31
32
// Port B initialisieren
33
  //DDRB=0b00000111;         // B0 B1 B2 sind Ausgang 
34
  //PORTB=0b00011000;      // Ausgänge auf 0 setzen, Pullups für Taster1 & 2 ein
35
  DDRA = 0b11111111;      // Port A ist alles Ausgang
36
  PORTA = 0b00000001;      // Alle Ausgänge auf 0, Enabled auf 1 (lowactive)
37
  DDRC = 0b01000000;
38
  PORTC = 0b00000000;
39
40
41
  sei();            // Interrupts zulassen (für timer.c wichtig)
42
  adc_init(0b00001100);    // ADC, Kanal 2 aktivieren
43
44
//--------------------------------------------------------------------------------------------------------
45
  UARTInit();     // initialize the UART (serial port)
46
  UCSR1A |= (1<<RXC0);
47
  UCSR0B |= ((1<<RXCIE0) | (1<<RXEN0) | (1<<TXEN0));
48
  rprintfInit(UARTSendByte);    //mit rprintf-Funktion verknüpfen
49
//---------------------------------------------------------------------------------------------------------
50
51
52
} // Ende des init- Unterprogramms
53
54
55
56
// Hauptprogramm, muss in jedem C Programm vorhanden sein
57
int main (void) 
58
{ 
59
  init();   // Aufruf des Unterprogramms init, nur einmal zum Programmbeginn notwendig
60
    
61
62
63
      
64
65
  
66
      //Verstärkung x1
67
      ADMUX  = 0b11011011;
68
      ADCSRB = 0b00000000;
69
      sbi(ADCSRA, ADEN);
70
71
72
73
  while(1)  // Befehl für Endlosschleife
74
    {
75
  
76
    //ADCWert = adc_read(2);
77
78
//------------------------------------------------------------------------------------------------ Brauch ich das?? Kopiert aus adc.h
79
80
  ADCSRA= (1<<ADPS2) | (1<<ADPS1)|  // prescale faktor= 128 ADC l�uft
81
82
    (1 <<ADPS0) |      // mit 14,7456MHz/ 128 = 115,2kHz 
83
84
    (1 << ADEN)|      // ADC an
85
86
    (1 << ADSC);      // Beginne mit der Konvertierung
87
//-------------------------------------------------------------------------------------------------------------------------------
88
  
89
while ( (ADCSRA & (1<<ADSC)) != 0){} //Warten bis konvertierung beendet
90
91
                // Das sollte 25 ADC-Zyklen dauern!
92
93
                // also 1/4608 s
94
95
 
96
  
97
  result= ADCL; 
98
99
  result+=(ADCH <<8);  // Ergebnis zusammenbauen
100
101
    rprintf("\r\nErgebniss:  %d",result);
102
    spannung = (5000 / 1023.0) * result;
103
    rprintf("\r\nSpannung: %d mV",spannung);
104
105
_delay_ms(500);
106
  } // Ende Endlosschleife
107
} // 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

von Simon K. (simon) Benutzerseite


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?

von Martink11 M. (Firma: google) (martink11) Flattr this


Lesenswert?

hallo

der verbesserte code mit gescheiten initialisierungen und ADCW, 
Ergebniss ist aber das gleiche!!
1
//###########################################################################################################
2
// Das Unterprogramm init: Hier werden die Initialisierungen vorgenommen
3
void init(void)
4
{
5
6
7
// Port B initialisieren
8
  //DDRB=0b00000111;         // B0 B1 B2 sind Ausgang 
9
  //PORTB=0b00011000;      // Ausgänge auf 0 setzen, Pullups für Taster1 & 2 ein
10
  DDRA = 0b11111111;      // Port A ist alles Ausgang
11
  PORTA = 0b00000001;      // Alle Ausgänge auf 0, Enabled auf 1 (lowactive)
12
  DDRC = 0b01000000;
13
  PORTC = 0b00000000;
14
15
16
  //sei();            // Interrupts zulassen (für timer.c wichtig)
17
  cli();
18
  adc_init(0b00001100);    // ADC, Kanal 2 aktivieren
19
20
//--------------------------------------------------------------------------------------------------------
21
  UARTInit();     // initialize the UART (serial port)
22
  UCSR1A |= (1<<RXC0);
23
  UCSR0B |= ((1<<RXCIE0) | (1<<RXEN0) | (1<<TXEN0));
24
  rprintfInit(UARTSendByte);    //mit rprintf-Funktion verknüpfen
25
//---------------------------------------------------------------------------------------------------------
26
27
28
} // Ende des init- Unterprogramms
29
30
31
32
// Hauptprogramm, muss in jedem C Programm vorhanden sein
33
int main (void) 
34
{ 
35
  init();   // Aufruf des Unterprogramms init, nur einmal zum Programmbeginn notwendig
36
    
37
38
39
      
40
41
  
42
  //Verstärkung x1, Vref = 2,56V
43
  ADMUX |= (1<<REFS1) | (1<<REFS0) | (1 <<MUX4) | (1 << MUX3) | (1 << MUX1) | (1 << MUX0);
44
  ADCSRB = 0x00;
45
46
47
48
49
  ADCSRA |= (1<<ADPS2) | (1<<ADPS1) | (1 <<ADPS0) | (1 << ADEN);  // prescale faktor= 128 ADC l�uft
50
51
                                  // mit 14,7456MHz/ 128 = 115,2kHz 
52
53
                                  // ADC an
54
55
  while(1)  // Befehl für Endlosschleife
56
    {
57
  
58
    //ADCWert = adc_read(2);
59
  
60
//------------------------------------------------------------------------------------------------ Brauch ich das?? Kopiert aus adc.h
61
62
63
64
  ADCSRA |= (1 << ADSC);      // Beginne mit der Konvertierung
65
//-------------------------------------------------------------------------------------------------------------------------------
66
67
68
while ( (ADCSRA & (1<<ADSC)) != 0){} //Warten bis konvertierung beendet
69
70
                // Das sollte 25 ADC-Zyklen dauern!
71
72
                // also 1/4608 s
73
74
75
76
77
78
  
79
result = ADCW;  // Ergebnis zusammenbauen
80
81
    rprintf("\r\nErgebniss:  %d",result);
82
    spannung = (2560 / 512.0) * result;
83
    rprintf("\r\nSpannung: %d mV",spannung);
84
85
_delay_ms(500);
86
  } // Ende Endlosschleife
87
} // 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

von Hc Z. (mizch)


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
1
>  ADMUX |= (1<<REFS1) | (1<<REFS0) | (1 <<MUX4) | (1 << MUX3) | (1 << MUX1) | (1 << MUX0);
und
1
> 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.

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.