Forum: Mikrocontroller und Digitale Elektronik Atmega8 Analog Messung


von AVR Neuling (Gast)


Lesenswert?

Hallo,

ich habe folgendes Problem, vielleicht für den ein oder anderen banal, 
aber mir macht es zur Zeit ein paar Schwierigkeiten. Ich will mit einem 
Atmega8 zwei Spannungen messen.
1
while (1)
2
  {                        
3
    ADMUX = 0x05;  // Pin wählen ADC5
4
    ADMUX = 0x04;  // Pin wählen ADC4
5
    ADMUX |= (1<<REFS0) | (1<<REFS1);       
6
// 2,56 Volt wird als Referenzspannung zum vergleich benutzt
7
    
8
                          // Start der Messung - Viermalig mit Mittelung 
9
    voltage = 0;
10
    voltage2= 0;            
11
    for(int i=0;i<4;i++)
12
    {  ADCSRA |= (1<<ADSC);  // einfache Messung
13
      while ( ADCSRA & (1<<ADSC) );     
14
      voltage += ADCW;
15
      voltage2+= ADCW;          
16
    }
17
    Ausgabe ((voltage2*cal)-3); _delay_ms(500);
18
  }

Das ist soweit meine Messung. Eine einzelne Messung funktioniert. Ich 
denke es liegt daran, dass ich voltage in ADCW schreibe und voltage2 in 
ADCW.

Aber wo kann ich eines der beiden kurz zwischenparken, damit ich in der 
Ausgabe damit noch ein wenig rumrechnen kann??

von Karl H. (kbuchegg)


Lesenswert?

AVR Neuling schrieb:

> while (1)
>   {
>     ADMUX = 0x05;  // Pin wählen ADC5
>     ADMUX = 0x04;  // Pin wählen ADC4


Ähm.
Nein.

Du musst schon die Messungen hintereinander machen.

Also: Alles für die EINE Messung einstellen
      Dann die Messung machen

      Dann alles für die ANDERE Messung einstellen
      Messung machen


So ein Programm ist nicht EXCEL, das sich selber zusammensucht, was du 
wahrscheinlich gemeint haben könntest. Es gibt ein paar einfache 
Prinzipien in der Programmierung:
* Anweisungen werden hintereinander ausgeführt.
* Eine Zuweisung zu einer Variablen überschreibt den alten Wert komplett
  mit einem neuen Wert.
  du würdest dich schön bedanken, wenn nach
   i = 5;
   i = 8;
  das i danach nicht 8 wäre, sondern da noch irgendwas von der 5
  'durchschimmern' würde.


Du hast nur EINEN ADC!
Du kannst diesen einen ADC auf verschiedene Eingangspins aufschalten. 
Aber immer nur EINEN bestimmten Pin zu einem beliebigen Zeitpunkt. 
Willst du also mehrere Pins messen, dann muss der ADC nacheinander auf 
jeweils den nächsten Pin aufgeschaltet werden, der zu messen ist. Und 
dann wird dieser gemessen und nur dieser.


AVR-GCC-Tutorial: Analoge Ein- und Ausgabe

von AVR Neuling (Gast)


Lesenswert?

Super,

habs gelöst, kann geschlossen werden,


danke schön

von AVR Neuling (Gast)


Lesenswert?

Ok, vielleicht doch nicht so schnell fertig......

....die beiden Messungen funktionieren, nur habe ich jetzt das Problem, 
dass ich den gemessenen Wert nicht weiterverarbeiten kann...
1
for(int i=0;i<4;i++)
2
    {  ADCSRA |= (1<<ADSC);
3
      while ( ADCSRA & (1<<ADSC) );
4
      voltage2+= ADCW;          
5
    }
6
    
7
    voltage22= voltage2*cal-wert;
8
    
9
    Ausgabe (voltage22); _delay_ms(500);

Ich will diesen voltage2 Wert verändert, hier in diesem Beispiel banal 
mit einem anderen Wert. Aber wenn ich 5 Volt messe und als "wert" oben 3 
definieren bekomme ich immer noch auf meinem LED Display 5 Volt 
angezeigt, anstatt 2 Volt??

Meine Ausgabe sieht wie folgt aus(für ein 4x7 Segment LED Display):
1
const int8_t numbers [10] = {20, 215, 76, 69, 135, 37, 36, 87, 4, 5}; 
2
3
volatile uint8_t Digit_X000, Digit_0X00, Digit_00X0, Digit_000X;
4
volatile uint8_t active_digit = 0;                  
5
6
void initialize_LED_display()
7
{
8
  DDRD = 0b11111111;  
9
  DDRC = 0b00001111;  
10
  OCR1A = 8;    
11
  TIMSK |= (1<<OCIE1A);               
12
13
// interrupt if compare match
14
  TCCR1B = (1<<CS12) | (1<<CS10) | (1<<WGM12);  // div 1024 & clear counter on compare match
15
  sei();
16
}
17
18
// Write number at indicated position to display
19
void digit (uint8_t value, uint8_t pin)
20
{
21
  PORTD = numbers[value];  // send number to output
22
  PORTC &= ~(1 << pin);  // PinLow => current digit on
23
}
24
25
// Dig Nummer
26
void Ausgabe (uint16_t number)       
27
{
28
  Digit_X000 = number/1000; number %= 1000;
29
  Digit_0X00 = number/100;  number %= 100;
30
  Digit_00X0 = number/10;    number %= 10;
31
  Digit_000X = number;    
32
}
33
34
35
36
37
ISR (SIG_OUTPUT_COMPARE1A)  
38
{
39
  PORTC = 0b00001111;     // Digits off
40
  if(active_digit == 0) digit (Digit_000X, PC0);
41
  if(active_digit == 1) digit (Digit_00X0, PC1);
42
  if(active_digit == 2) digit (Digit_0X00, PC2);
43
  if(active_digit == 3) digit (Digit_X000, PC3);
44
45
  
46
  active_digit ++; if (active_digit == 4) active_digit = 0;
47
  
48
}


Oder bin ich jetzt total auf dem Holzweg???

von AVR Neuling (Gast)


Lesenswert?

Also jetzt bin ich verwirrt, wenn ich meinen cal-Wert weglasse, das 
bekommt der yC mit.
1
for(int i=0;i<4;i++)
2
    {  ADCSRA |= (1<<ADSC);
3
      while ( ADCSRA & (1<<ADSC) );
4
      voltage2+= ADCW;          
5
    }
6
    
7
    voltage22= voltage2*cal-wert;
8
    
9
    Ausgabe (voltage22); _delay_ms(500);


Oder muss ich für Subtraktion ne math.h einfügen??? Eigentlich ja 
nicht!!!

von Karl H. (kbuchegg)


Lesenswert?

Zeig doch bitte endlich mal dein komplettes Programm.
Inklusive aller Variablen Defintionen, damit man auch mal die Datentypen 
und eventuelle Makros sieht.
Die sind nämlich nicht einfach nur schmückendes Beiwerk sondern haben 
auch Konsequenzen!

von AVR Neuling (Gast)


Lesenswert?

1
#define XTAL  8e6
2
#define F_CPU  XTAL
3
#include <avr/io.h>
4
#include <util/delay.h>    
5
#include <avr/interrupt.h>
6
7
8
9
#include "...\BitUtilities.h"
10
#include "...\LED_display_low_dot.h"
11
12
float voltage;
13
float voltage2;
14
float cal = 0.6882;
15
float wert = 4.0000;
16
float voltage22;
17
18
19
20
int main()
21
{  initialize_LED_display();            
22
  Ausgabe (0);
23
24
  
25
  ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1);            
26
27
         // Aktivieren Analog Digital Converter 
28
  //Test Messung für ADC5
29
  ADMUX = 0x05;                       // Pin auswählen, an dem gemessen werden soll (ADC5)
30
  
31
        ADMUX |= (1<<REFS0) | (1<<REFS1); 
32
  // 2,56 Volt wird als Referenzspannung zum vergleich benutzt
33
                             // Test Messung
34
ADCSRA |= (1<<ADSC);           // Einfache Wandlung
35
while ( ADCSRA & (1<<ADSC) );   // Warten das Analog digital Converter fertig ist 
36
voltage = ADCW;      // Wert bekommen
37
voltage = 0;      // Wert mit 0 überschreiben, damit kein unsinniger Wert aufgenommen wird  
38
  
39
//Test Messung für ADC4
40
  
41
ADMUX = 0x04;      // Pin auswählen, an dem gemessen werden soll (ADC4)
42
ADMUX |= (1<<REFS0) | (1<<REFS1); // 2,56 Volt wird als Referenzspannung zum vergleich benutzt
43
                          // Test Messung
44
ADCSRA |= (1<<ADSC);    // Einfache Wandlung
45
while ( ADCSRA & (1<<ADSC) );  // Warten das Analog digital Converter fertig ist 
46
voltage2 = ADCW;    // Wert bekommen
47
voltage2 = 0;      // Wert mit 0 überschreiben, damit kein unsinniger Wert aufgenommen wird  
48
  
49
  while (1)
50
  {                        // Daten an Messleitung einlesen - AREF =2,56V, 10 Bit A/D-Converter: 2^10-
51
52
1=1023
53
ADMUX = 0x05;      // Pin wählen ADC5                
54
ADMUX |= (1<<REFS0) | (1<<REFS1);   // 2,56 Volt wird als Referenzspannung zum vergleich benutzt
55
    
56
                          // Start der Messung - Viermalig mit Mittelung 
57
voltage = 0;
58
                
59
for(int i=0;i<4;i++)
60
    {  ADCSRA |= (1<<ADSC);  
61
      while ( ADCSRA & (1<<ADSC) );     
62
      voltage += ADCW;            
63
    }
64
    
65
ADMUX = 0x04;  
66
ADMUX |= (1<<REFS0) | (1<<REFS1); 
67
voltage2= 0;
68
    
69
for(int i=0;i<4;i++)
70
    {  ADCSRA |= (1<<ADSC);
71
      while ( ADCSRA & (1<<ADSC) );     
72
      voltage2+= ADCW;          
73
    }
74
    
75
    
76
    number_output (voltage2*cal-wert); _delay_ms(500);
77
  }
78
  return 0;
79
}

Der Plan ist das ich den gemessenen Wert vor der Ausgabe noch verändern 
will.....umrechnen.....doch komischerweise wenn ich meinen "cal" Faktor 
rausnehme merkt er das, das "-wert" kratzt ihn absolut nicht ob das da 
steht oder nicht

von Karl H. (kbuchegg)


Lesenswert?

float cal = 0.6882;
float wert = 4.0000;
float voltage22;

...
      voltage2+= ADCW;
    }


    number_output (voltage2*cal-wert); _delay_ms(500);



Nehmen wir mal an, der ADC liefert ständig 1023 (weil deine Spannung 
wirklich 5V hätte).

Dann haben wir

 4 mal 1023  ... macht 4092

4092 * 0.6882  macht 2816.114

davon dann 4 abgezogen  macht 2812.1144

und das dann ausgegeben sollte auf deiner Anzeige die Ziffern 2812 
anzeigen.
Was zeigt deine Anzeige wirklich?

Beachte: Deine 4 wirken sich nur auf die letzte Stelle aus! Dein Faktor 
cal sieht mir aber eher danach aus, als ob du eigentlich MilliVolt 
anzeigen willst und nicht Volt. D.h. wenn du mit wert eine 
'Verschiebung' im Voltbereich haben willst, dann würde ich da eher 
Zahlen im 1000-er Bereich erwarten.


Und aufpassen, wenn das Ergebnis negativ wird!
Deine Ausgaberoutine, wie gepostet, kann damit nicht umgehen.

Und räum deinen Code ein wenig auf. Das ist ja furchtbar. Ich hab da ja 
eine Hypothese, nach der die mit dem scheuslichsten Code immer die 
dümmsten Fehler haben. Bis jetzt funktioniert die Hypothese hervorragend 
und deinen Code kann man nicht wirklich als ein Gegenbeispiel 
akzeptieren.

von AVR Neuling (Gast)


Lesenswert?

Mit dem Cal Wert bekomme ich 5,01 Volt als Wert, in diesem Fall messe 
ich die Betriebsspannung.....

....ich habe auch schon eine 9 Volt Batterie angeschlossen, diesen Wert 
kann ich auch über die Anzeige auslesen.

Ich habe vor dem Messeingang ein Spannungsteiler, um auch höhere 
Spannungen messen zu können....darauf ergibt sich dieser Cal Faktor:

cal= 11/4 *(2,56/1023)*100

Spannungsteiler : 1/11
Faktor 1/4 wegen 4 facher Messung
Faktor 2,56 Referenzspannung
Faktor 1023 ...10 Bit
Faktor 100 wegen zwei Nachkommastellen....

von AVR Neuling (Gast)


Lesenswert?

Kann ich das jetzt so sehen:

Mein Spannungsteiler besteht aus 100kOhm und 10kOhm, das bedeutet einen 
Faktor von 1 /11 also kann ich statt 5V nun 55 V messen.

Wenn ich nun 5 V messen möchte, bedeutet dies, dass am yC MessPIN 0,45 
Volt anliegen, wegen dem Spannungsteiler.

Die Messreferenzspannung ist doch 2,56 Volt......sind nunr 2,56V = 1023 
oder 5V 1023????

von Karl H. (kbuchegg)


Lesenswert?

AVR Neuling schrieb im Beitrag #3191964:
> Mit dem Cal Wert bekomme ich 5,01 Volt als Wert, in diesem Fall messe
> ich die Betriebsspannung.....
>
> ....ich habe auch schon eine 9 Volt Batterie angeschlossen, diesen Wert
> kann ich auch über die Anzeige auslesen.
>
> Ich habe vor dem Messeingang ein Spannungsteiler, um auch höhere
> Spannungen messen zu können....darauf ergibt sich dieser Cal Faktor:
>
> cal= 11/4 *(2,56/1023)*100

schön langsam kommen alle Fakten auf den Tisch
>
> Spannungsteiler : 1/11
> Faktor 1/4 wegen 4 facher Messung
> Faktor 2,56 Referenzspannung
> Faktor 1023 ...10 Bit
> Faktor 100 wegen zwei Nachkommastellen....

ok, also 100.
Das bedeutet aber trotzdem, dass du, wenn die Anzeige um 1 Volt weniger 
anzeigen soll, du 100 abziehen musst und nicht 1

> Aber wenn ich 5 Volt messe und als "wert" oben 3
> definieren bekomme ich immer noch auf meinem LED Display
> 5 Volt angezeigt, anstatt 2 Volt?

von AVR Neuling (Gast)


Lesenswert?

Ahhh jetzt funktioniert es.....vielen vielen DANK,


aber die ein oder andere Frage hätte ich noch!!!


Meine Auflösung von 1023 Bit bezieht sich die auf die Referenzspannung 
von 2,56V oder auf den max Messbereich des yC, also 5 V, das ist mir 
noch nicht so klar....

Und zum Thema Code aufräumen....in meinem AVR-Studio ist der schon 
aufgeräumt, aber sobald ich ihn hier rein kopiere zerschießt es 
ihn....gibt es da einen Trick???

Danke nochmal!!!!

von Karl H. (kbuchegg)


Lesenswert?

AVR Neuling schrieb im Beitrag #3192113:
> Ahhh jetzt funktioniert es.....vielen vielen DANK,
>
>
> aber die ein oder andere Frage hätte ich noch!!!
>
>
> Meine Auflösung von 1023 Bit bezieht sich die auf die Referenzspannung
> von 2,56V oder auf den max Messbereich des yC, also 5 V, das ist mir
> noch nicht so klar....

auf die Referenzspannung.
Der ADC liefert dir im Grunde eine Prozentangabe: Wieviele Prozent der 
Referenzspannung macht die zu messende Spannung aus.
Nur dass aus praktischen Gründen die 100% hier eben 1023 heißen.

> Und zum Thema Code aufräumen....in meinem AVR-Studio ist der schon
> aufgeräumt, aber sobald ich ihn hier rein kopiere zerschießt es
> ihn....gibt es da einen Trick???

Tabulatoren durch Leerzeichen ersetzen lassen

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.