www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Atmega8 vergleicht keine Variablen


Autor: Hans Peter (pillsky)
Datum:

Bewertung
0 lesenswert
nicht 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:
  if (P_diff_ist<P_diff_soll)
      {PORTB &=~_BV(PB2);           //LED 2 rot an
       PORTB |=_BV(PB1);}           //LED 1 gruen aus  
      else
      {PORTB |=_BV(PB2);            //LED 2 rot aus
       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
//############################################################################
// ______Luftdrucküberwachung_____
// 
// __Messbereich 
// A/D 10bit Aufloesung  0,0V bis 5,0V   0 bis 1023
// Pdiff-Sensor      0,25V bis 4,25V  0 bis 250Pa
// __Ein- und Ausgaenge
// Poti     an PC0 (ADC0) Pin23  MESSWERT(0) Schwellwert
// Sensor     an PC2 (ADC2) Pin25  MESSWERT(2)  Vout_Unidirektional
// Tür_Sensor  an PD7      Pin13
// Ventil    an PB0        Pin14
// LED 1 (grün) an PB1        Pin15
// LED 2 (rot)   an PB2        Pin16  
//############################################################################

#include <avr/io.h>
#include <stdio.h>
#include <util/delay.h>
#include "messen.h"
#include "lcd-routines.h"
#define F_CPU 1000000           // Takt-Frequenz in Hz (=1Mhz)

int main(void){

//Variablen deklarieren
//############################################################################
  int x=0, y=0, z=0, P_diff_ist=0, P_diff_soll=0;
  char messwertstring[20];

//Ein- und Ausgaenge festlegen
//############################################################################
  DDRB |= _BV(PB0);           //Ausgang PB0 Ventil
  DDRB |= _BV(PB1);           //Ausgang PB1 LED gruen
    DDRB |= _BV(PB2);           //Ausgang PB2 LED rot  
  DDRD &= _BV(PD7);            //Eingang PD7 Tür_Sensor

//Hauptprogramm
//############################################################################
  lcd_init();
  lcd_clear();
  while (1)  {

  //Berechnungen
  //####################################################################
  // -- Endpunktermittlung mit dem Einsetzungsverfahren
  // Pdiff = Vout = AD-Wandler-Wert
  //   0Pa = 0,25V = 51
  // 250Pa = 4,25V = 870
  //
  //   0Pa = 51 * z + y   >  y = 0Pa - 51 * z
    // 250Pa = 870 * z + y
  //
  // 250Pa = 870 * z - 51 * z + 0Pa
    // 250Pa = 819 * z
  // z = 250 / 819
    // z = 0.305250305250
    // y = 0Pa - (51 * 0.305250305250)
    // y =-15.56776556776
  // Der Druckwert ergibt sich also aus der gemessenen AD-Wert * z + y
  //####################################################################
    x =         99;              //max. Wertebereich für P_diff_soll-Poti
    z =        0.305250305250;
    y =        -15.56776556776;
    P_diff_soll =  (x/1023) * MESSWERT(0);   //A/D-Wert in 0-99Pa
    P_diff_ist  =  MESSWERT(2) * z + y;    //Berechnung durch Einsetzverfahren
    
    //P_diff_soll
    //#########################################
    set_cursor (0, 1);
    lcd_string ("Pdiff_SOLL: ");
  
    set_cursor (12, 1);    
    sprintf(messwertstring, "%d", P_diff_soll);  //Umwandlung P_diff_soll in messwertstring
    if (P_diff_soll<10) lcd_string (" ");    //10ner-stelle wird leer (Messwert<10)
    if (P_diff_soll<100) lcd_string (" ");    //100ter-stelle wird leer (Messwert<100)    
    lcd_string (messwertstring);        //LCD-Display Ausgabe

    set_cursor (14, 1);
    lcd_string ("Pa");
    
    //P_diff_ist
    //#########################################
    set_cursor (0, 2);
    lcd_string ("Pdiff_IST: ");

    set_cursor (11, 2);      
    sprintf(messwertstring, "%d", P_diff_ist);  //Umwandlung P_diff_ist in messwertstring    
    if (P_diff_ist<10) lcd_string (" ");    //10ner-stelle wird leer (Messwert<10)
    if (P_diff_ist<100) lcd_string (" ");    //100ter-stelle wird leer (Messwert<100)
    lcd_string (messwertstring);        //LCD-Display Ausgabe
  
    set_cursor (14, 2);
    lcd_string ("Pa");
  
    // Ansteuerung der Ausgaenge
    //#########################################
    if (P_diff_ist<P_diff_soll)
             {PORTB &=~_BV(PB2);            //LED 2 rot an
        PORTB |=_BV(PB1);}           //LED 1 gruen aus  
            else
            {PORTB |=_BV(PB2);            //LED 2 rot aus
        PORTB &=~_BV(PB1);}            //LED 1 gruen an

    if ((P_diff_ist<P_diff_soll)&&(bit_is_set(PIND,7)))
             {PORTB &=~_BV(PB0);}          //Ventil angezogen (Tuer gesperrt)
            else
            {PORTB |=_BV(PB0);}            //Ventil abgefallen (Tuer offen)
    
    _delay_ms(50);
  }  
  return(0);
}

Autor: g457 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
∗hüstel∗Datentypen</hüstel>

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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:
>
>
>   if (P_diff_ist<P_diff_soll)
>       {PORTB &=~_BV(PB2);           //LED 2 rot an
>        PORTB |=_BV(PB1);}           //LED 1 gruen aus
>       else
>       {PORTB |=_BV(PB2);            //LED 2 rot aus
>        PORTB &=~_BV(PB1);}          //LED 1 gruen an
> 
>

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
      sprintf(messwertstring, "%3d", P_diff_soll);  //Umwandlung
      lcd_string (messwertstring);        //LCD-Display Ausgabe

Autor: Torsten K. (ago)
Datum:

Bewertung
0 lesenswert
nicht 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;

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das hier
    x =         99;              //max. Wertebereich für P_diff_soll-Poti
    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
    z =        0.305250305250;
    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#Datent...

Autor: Oliver Ju. (skriptkiddy)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Hans Peter (pillsky)
Datum:

Bewertung
0 lesenswert
nicht 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.
    x =         99;              
    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ß!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hans Peter schrieb:

>
>     x =         99;
>     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.

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.

Autor: Hans Peter (pillsky)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: PicoPSU (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Pillsky (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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ß

Autor: Εrnst B✶ (ernst)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Hans Peter (pillsky)
Datum:

Bewertung
0 lesenswert
nicht 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!

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.