Forum: Mikrocontroller und Digitale Elektronik Atmega8 vergleicht keine Variablen


von Hans P. (pillsky)


Lesenswert?

Guten Abend an alle Fach-Experten!

Im Moment schlage ich mich mit meiner Abschlussarbeit herum.
Kurz gesagt: Es ist eine Luftdrucküberwachung von einen P_innendruck und 
einem P_außendruck. Dieser wird als Differnzwert an den Atmega8 
übertragen.
Ist nun der Differenzwert (P_diff_ist) kleiner als der Soll-Wert 
(P_diff_soll), dann soll eine rote LED leuchten und ein Ventil 
angesteuert werden. Ansonsten leuchtet eine grüne LED.
Das nur mal kurz umrissen worum es geht.

Jetzt zum Problem:
Unten ist mein gesamtes Programm. Richtig interessant ist der Absatz 
"Ausgänge ansteuern" Dort wird unter anderen der Soll-Wert mit dem 
Ist-Wert verglichen. Hier der Auszug:
1
  if (P_diff_ist<P_diff_soll)
2
      {PORTB &=~_BV(PB2);           //LED 2 rot an
3
       PORTB |=_BV(PB1);}           //LED 1 gruen aus  
4
      else
5
      {PORTB |=_BV(PB2);            //LED 2 rot aus
6
       PORTB &=~_BV(PB1);}          //LED 1 gruen an

Nun wird ständig die grüne LED angesteuert - die Vergleichsfunktion hat 
überhaupt keinen Einfluss! Selbst wenn ich den Ist-Wert manuell im 
Programm vorgebe und am Poti drehe um den Soll-Wert zu verstellen - 
nichts passiert.

Hat jemand einen Gedankenblitz?
Ich hab vor ein paar Wochen schon mal ein Programm mit der gleichen 
Vergleichsfunktion gemacht und da funktionierte alles bestens.

Schönen Abend
- Pillsky



Gesamtes Programm
1
//############################################################################
2
// ______Luftdrucküberwachung_____
3
// 
4
// __Messbereich 
5
// A/D 10bit Aufloesung  0,0V bis 5,0V   0 bis 1023
6
// Pdiff-Sensor      0,25V bis 4,25V  0 bis 250Pa
7
// __Ein- und Ausgaenge
8
// Poti     an PC0 (ADC0) Pin23  MESSWERT(0) Schwellwert
9
// Sensor     an PC2 (ADC2) Pin25  MESSWERT(2)  Vout_Unidirektional
10
// Tür_Sensor  an PD7      Pin13
11
// Ventil    an PB0        Pin14
12
// LED 1 (grün) an PB1        Pin15
13
// LED 2 (rot)   an PB2        Pin16  
14
//############################################################################
15
16
#include <avr/io.h>
17
#include <stdio.h>
18
#include <util/delay.h>
19
#include "messen.h"
20
#include "lcd-routines.h"
21
#define F_CPU 1000000           // Takt-Frequenz in Hz (=1Mhz)
22
23
int main(void){
24
25
//Variablen deklarieren
26
//############################################################################
27
  int x=0, y=0, z=0, P_diff_ist=0, P_diff_soll=0;
28
  char messwertstring[20];
29
30
//Ein- und Ausgaenge festlegen
31
//############################################################################
32
  DDRB |= _BV(PB0);           //Ausgang PB0 Ventil
33
  DDRB |= _BV(PB1);           //Ausgang PB1 LED gruen
34
    DDRB |= _BV(PB2);           //Ausgang PB2 LED rot  
35
  DDRD &= _BV(PD7);            //Eingang PD7 Tür_Sensor
36
37
//Hauptprogramm
38
//############################################################################
39
  lcd_init();
40
  lcd_clear();
41
  while (1)  {
42
43
  //Berechnungen
44
  //####################################################################
45
  // -- Endpunktermittlung mit dem Einsetzungsverfahren
46
  // Pdiff = Vout = AD-Wandler-Wert
47
  //   0Pa = 0,25V = 51
48
  // 250Pa = 4,25V = 870
49
  //
50
  //   0Pa = 51 * z + y   >  y = 0Pa - 51 * z
51
    // 250Pa = 870 * z + y
52
  //
53
  // 250Pa = 870 * z - 51 * z + 0Pa
54
    // 250Pa = 819 * z
55
  // z = 250 / 819
56
    // z = 0.305250305250
57
    // y = 0Pa - (51 * 0.305250305250)
58
    // y =-15.56776556776
59
  // Der Druckwert ergibt sich also aus der gemessenen AD-Wert * z + y
60
  //####################################################################
61
    x =         99;              //max. Wertebereich für P_diff_soll-Poti
62
    z =        0.305250305250;
63
    y =        -15.56776556776;
64
    P_diff_soll =  (x/1023) * MESSWERT(0);   //A/D-Wert in 0-99Pa
65
    P_diff_ist  =  MESSWERT(2) * z + y;    //Berechnung durch Einsetzverfahren
66
    
67
    //P_diff_soll
68
    //#########################################
69
    set_cursor (0, 1);
70
    lcd_string ("Pdiff_SOLL: ");
71
  
72
    set_cursor (12, 1);    
73
    sprintf(messwertstring, "%d", P_diff_soll);  //Umwandlung P_diff_soll in messwertstring
74
    if (P_diff_soll<10) lcd_string (" ");    //10ner-stelle wird leer (Messwert<10)
75
    if (P_diff_soll<100) lcd_string (" ");    //100ter-stelle wird leer (Messwert<100)    
76
    lcd_string (messwertstring);        //LCD-Display Ausgabe
77
78
    set_cursor (14, 1);
79
    lcd_string ("Pa");
80
    
81
    //P_diff_ist
82
    //#########################################
83
    set_cursor (0, 2);
84
    lcd_string ("Pdiff_IST: ");
85
86
    set_cursor (11, 2);      
87
    sprintf(messwertstring, "%d", P_diff_ist);  //Umwandlung P_diff_ist in messwertstring    
88
    if (P_diff_ist<10) lcd_string (" ");    //10ner-stelle wird leer (Messwert<10)
89
    if (P_diff_ist<100) lcd_string (" ");    //100ter-stelle wird leer (Messwert<100)
90
    lcd_string (messwertstring);        //LCD-Display Ausgabe
91
  
92
    set_cursor (14, 2);
93
    lcd_string ("Pa");
94
  
95
    // Ansteuerung der Ausgaenge
96
    //#########################################
97
    if (P_diff_ist<P_diff_soll)
98
             {PORTB &=~_BV(PB2);            //LED 2 rot an
99
        PORTB |=_BV(PB1);}           //LED 1 gruen aus  
100
            else
101
            {PORTB |=_BV(PB2);            //LED 2 rot aus
102
        PORTB &=~_BV(PB1);}            //LED 1 gruen an
103
104
    if ((P_diff_ist<P_diff_soll)&&(bit_is_set(PIND,7)))
105
             {PORTB &=~_BV(PB0);}          //Ventil angezogen (Tuer gesperrt)
106
            else
107
            {PORTB |=_BV(PB0);}            //Ventil abgefallen (Tuer offen)
108
    
109
    _delay_ms(50);
110
  }  
111
  return(0);
112
}

von g457 (Gast)


Lesenswert?

∗hüstel∗Datentypen</hüstel>

von Karl H. (kbuchegg)


Lesenswert?

Hans Peter schrieb:


> Unten ist mein gesamtes Programm. Richtig interessant ist der Absatz
> "Ausgänge ansteuern" Dort wird unter anderen der Soll-Wert mit dem
> Ist-Wert verglichen. Hier der Auszug:
>
>
1
>   if (P_diff_ist<P_diff_soll)
2
>       {PORTB &=~_BV(PB2);           //LED 2 rot an
3
>        PORTB |=_BV(PB1);}           //LED 1 gruen aus
4
>       else
5
>       {PORTB |=_BV(PB2);            //LED 2 rot aus
6
>        PORTB &=~_BV(PB1);}          //LED 1 gruen an
7
>
>

Was sagt denn dein LCD, wie gross die Werte sind?

PS:
Das hier

>     sprintf(messwertstring, "%d", P_diff_soll);  //Umwandlung
>     if (P_diff_soll<10) lcd_string (" ");    //10ner-stelle wird leer
>     if (P_diff_soll<100) lcd_string (" ");    //100ter-stelle wird leer

kannst du auch einfacher machen, indem du sprintf einfach sagst, dass es 
die Zahlenausgabe in ein Feld der Breite 3 hineinmachen soll. sprintf 
füllt dann selbst mit Leerzeichen auf
1
      sprintf(messwertstring, "%3d", P_diff_soll);  //Umwandlung
2
      lcd_string (messwertstring);        //LCD-Display Ausgabe

von Torsten K. (ago)


Lesenswert?

Worauf g457 hinweisen wollte, ist folgendes nicht funktionierendes 
Konstrukt :)
  int x=0, y=0, z=0, P_diff_ist=0, P_diff_soll=0;
...
    z =        0.305250305250;
    y =        -15.56776556776;

von Karl H. (kbuchegg)


Lesenswert?

Das hier
1
    x =         99;              //max. Wertebereich für P_diff_soll-Poti
2
    P_diff_soll =  (x/1023) * MESSWERT(0);

ergibt immer für P_Diff_soll eine glatte 0. Hast du die auf deinem LCD 
nicht gesehen?

und wie soll
1
    z =        0.305250305250;
2
    y =        -15.56776556776;
z und y mit deinen Kommastellen umgehen, wenn sie nur int Variablen 
sind? (Was jetzt nicht heißen soll, dass du sie auf double ändern 
sollst!)

http://www.mikrocontroller.net/articles/FAQ#Datentypen_in_Operationen

von Oliver J. (skriptkiddy)


Lesenswert?

>P_diff_soll =  (x/1023) * MESSWERT(0);    // =0!!!!!!!!!

so ist es besser:
P_diff_soll =  x * MESSWERT(0)/1023;

> P_diff_ist  =  MESSWERT(2) * z + y;
Achja Int darf man nicht mit Gleitkommazahlen kommen.

Gruß Skriptkiddy

von Hans P. (pillsky)


Lesenswert?

@all: Na mensch das ging ja schnell! Ist das immer so hier? Davon können 
sich anderen Foren eine Scheibe anschneiden ;)

@ Karl heinz Buchegger
Danke für den Tipp mit den Kommastellen! Werde ich umgehend einbinden.
1
    x =         99;              
2
    P_diff_soll =  (x/1023) * MESSWERT(0);
Stimmt das funktionierte nicht, ich hab dann 99 durch 1023 gerechnet und 
den Faktor direkt als Zahl fest eingetragen.

>so ist es besser:
>P_diff_soll =  x * MESSWERT(0)/1023;
--> Danke!

>Achja Int darf man nicht mit Gleitkommazahlen kommen.
Ahh okay verstehe! Also darf ich z und y nicht direkt mit den 
Kommastellen hinschreiben, sondern muss sie ausrechnen lassen von 
GanzZahlen?

Gruß!

von Karl H. (kbuchegg)


Lesenswert?

Hans Peter schrieb:

>
1
>     x =         99;
2
>     P_diff_soll =  (x/1023) * MESSWERT(0);
3
>
> Stimmt das funktionierte nicht, ich hab dann 99 durch 1023 gerechnet und
> den Faktor direkt als Zahl fest eingetragen.

Das war der falsche Fix.

>
>>so ist es besser:
>>P_diff_soll =  x * MESSWERT(0)/1023;
> --> Danke!
>
>>Achja Int darf man nicht mit Gleitkommazahlen kommen.
> Ahh okay verstehe! Also darf ich z und y nicht direkt mit den
> Kommastellen hinschreiben, sondern muss sie ausrechnen lassen von
> GanzZahlen?

Nein.
Du sollst deine Berechnungen so umstellen, dass du die bei der Division 
entstehenden 'Kommastellen' erst ganz zum Schluss wegwirfst. (denn 
Int-Divisionen erzeugen keine Kommastellen!)

     5 / 9 * 7

ergibt ein anderes Ergebnis als

     5 * 7 / 9

obowhl beide mathematisch identisch sind. Nur C rechnet die Division nun 
mal nicht mit Kommastellen und damit ergibt 5 / 9 in

     5 / 9 * 7

eine glatte 0. Die Multiplikation mit 7 reißt das dann auch nicht mehr 
raus. 0 mal 7 ist nun mal 0

     5 / 9 * 7

ergibt 0!

während

     5 * 7 / 9

als 5 * 7 ergibt 35, das durch 9 dividiert ergibt 3 gerechnet wird.

0 ist aber ein anderes Ergebnis als 3! Und das nur weil du die 
Berechnung in mathematisch zulässiger Weise umgestellt hast.

von Hans P. (pillsky)


Lesenswert?

@kbuchegg

perfekte Erklärung - Problematik verstanden (:
Ich habs nun hinbekommen das mein Programm funktioniert.
Recht ungewöhnlich nu direkt mit den Faktoren und ohne viel zu brechnen.
Egal es funktioniert und das ich wichtig, ich bin ziemlich unter 
Zeitdruck.

Danke für die Tipps!

Gruß Pillsky

von PicoPSU (Gast)


Lesenswert?

Und wenn wir schon dabei sind:

    P_diff_soll =  (x/1023) ...


Ist auch falsch. Wenn x ein 10-Bit ADC Resultat ist, musst du durch 1024 
teilen.
Ist zwar nur eine kleine Abweichung, aber warum falsch machen, wenn die 
richtige Rechnung für den µC auch noch viel einfacher ist.

Bitte jetzt keine erneute Diskussion 1024 vs 1023 vom Zaun brechen, 
hatten wir hier schon zur genüge, und jedes mal hat am Schluß der 
1023-Verfechter eingesehen, dass er falsch lag.

von Pillsky (Gast)


Lesenswert?

Okay danke!
Ich hatte es von einer Mikrocontroller-Seite so übernommen.
Eigentlich gehts ja von 0 bis 1023 - also 1024 Werte. Ich lasse mich 
natürlich auch eines Besseren belehren.

Gruß

von Εrnst B. (ernst)


Lesenswert?

Pillsky schrieb:

> Ich hatte es von einer Mikrocontroller-Seite so übernommen.

hoffentlich nicht von hier :)

> Eigentlich gehts ja von 0 bis 1023 - also 1024 Werte. Ich lasse mich
> natürlich auch eines Besseren belehren.

Hier wird das nochmal hergeleitet:

AVR-Tutorial: ADC: Ein paar ADC-Grundlagen

Vor allem das Beispiel mit dem 5-Stufen-ADC sollte beim verstehen 
helfen.

von Hans P. (pillsky)


Lesenswert?

>hoffentlich nicht von hier :)
Nein ;) mikrocontrollerspielwiese.de ist hier der Übeltäter!

>Vor allem das Beispiel mit dem 5-Stufen-ADC sollte beim verstehen
>helfen.
Hat es!

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.