In Prozent umrechnen

Ich habe zB die Heizleistung oder eben die Lüfter Leistung Werte in 0-255.
Nun will ich das ganze in Prozent anzeigen lassen und auch ändern per Tasten, in Prozent.
So hab ichs versucht, ih glaub aber dass es nicht richtig ist, wie ist es richtig?
Es soll nur von 0-100% gehen, also nicht über 100% zB 110%

Mit jedem Tastendruck soll um 1% erhöht werden, ich habs mit LUEFTER_leistung+3; versucht, aber das funktionirte nicht, wahrscheinlich wieder wegen Klammern.
Die Lüfter fangen erst ab ca analog.Write(50); an zu drehen.

void LCDML_DISP_loop(LCDML_FUNC_LUEFTER_leistung) 
{

    uint8_t LUEFTER_leistungi;
   // uint8_t LUEFTER_leistungi = ((leistung/255) * 100); 
 // LUEFTER_leistungi = map(LUEFTER_leistung, 0, 255, 0, 100);
  lcd.setCursor(0, 1); lcd.print(F("Leistung:")); lcd.print(LUEFTER_leistungi); lcd.print(F("%   "));
  
      if (LCDML_BUTTON_checkUp())    { LUEFTER_leistung++; LUEFTER_leistung++; LUEFTER_leistung++; LCDML_BUTTON_resetUp(); }
      if (LCDML_BUTTON_checkDown())  { LUEFTER_leistung--; LUEFTER_leistung--; LUEFTER_leistung--; LCDML_BUTTON_resetDown(); }
      if (LCDML_BUTTON_checkEnter()) { LCDML_DISP_funcend(); }  
    }

Hallo,

deine map Funktion sollte funktionieren. Nur deine manuelle Umrechnung ist leider falsch.
100% entsprechen 255, wieviel y% entsprechen Leistung x ?
Klassischer Dreisatz, Prozentrechnung.
y% = 100/255*x

uint8_t LUEFTER_leistungi = (100 / 255 * LUEFTER_leistung);

Wegen Ganzzahlrechnung muss man das künstlich erhöhen mit mindestens 100 für "2 Kommastellen Genauigkeit".
Was mir auch auffällt, dass du mit Wertebereich byte bei der Formel auch nicht weit kommst.
Probiere mal ...

uint8_t LUEFTER_leistungi = (10000UL / 255 * LUEFTER_leistung / 100);

Aber wie gesagt, deine map Funktion ist auch richtig, darin sehe ich keinen Fehler.
Kann auch sein das die map Funktion das gleiche Problem hat wie manuelle Rechnung ohne künstliche Überhöhung. Denn 100/255 ist in Ganzzahl immer 0 und 0 mal irgendwas bleibt 0.

Doc_Arduino:

uint8_t LUEFTER_leistungi = (100 / 255 * LUEFTER_leistung);

Es geht ja darum Prozent in Lüfterleistung umzurechnen also der Kehrwert deiner Formel:

LUEFTER_PWM=255/100*LUEFTER_Prozent

So wird das mit Integer aber sehr ungenau, da 255/100 ganzzahlig 2 ergibt.

Doc_Arduino:
Wegen Ganzzahlrechnung muss man das künstlich erhöhen mit mindestens 100 für "2 Kommastellen Genauigkeit".
Was mir auch auffällt, dass du mit Wertebereich byte bei der Formel auch nicht weit kommst.
Probiere mal ...

uint8_t LUEFTER_leistungi = (10000UL / 255 * LUEFTER_leistung / 100);

Oft hilft auch eine geschickte Umformung schon um keine Überhöhung zu brauchen.

LUEFTER_PWM=int(255*LUEFTER_Prozent)/100

Wenn man das Ergebnis grob gerundet haben will:
LUEFTER_PWM=int(255*LUEFTER_Prozent +1)/100

Oder obige Rechnung

uint8_t LUEFTER_leistungi = int(100 * LUEFTER_leistung)/255;

Also Anzeige in % ist so schon mal richtig (0-100%), Problem ist jetzt nur, Lüfter wird erst von ca 45% langsamer, bis 15%.
Wie macht man denn dass jetzt?

void LCDML_DISP_loop(LCDML_FUNC_LUEFTER_leistung) 
{
  uint8_t LUEFTER_Prozent;
  LUEFTER_Prozent = int(100 * LUEFTER_PWM)/255;
  lcd.setCursor(0, 1); lcd.print(F("Leistung:")); lcd.print(LUEFTER_Prozent); lcd.print(F("%   "));
  
      if (LCDML_BUTTON_checkUp())    { LUEFTER_PWM++; LCDML_BUTTON_resetUp(); }
      if (LCDML_BUTTON_checkDown())  { LUEFTER_PWM--; LCDML_BUTTON_resetDown(); }
      if (LCDML_BUTTON_checkEnter()) { LCDML_DISP_funcend(); }  
    }

15% = 40
45% = 115

Meinst Du das so?

void setup()
{
  Serial.begin(9600);
  Serial.println("Anfang\nWert\tProzent");
  for (int b = 2; b <= 255; b += 11) {
    int a = map(b, 40, 115, 0, 100);
    a = constrain(a, 0, 100);
    Serial.print(b);
    Serial.print("\t");
    Serial.println(a);
  }
}

void loop() {}

15% = 40
45% = 115

ist richtig.

Den rest weiß ich grad nicht anzuwenden.

Mit dem Taschenrechner: a = (b-40) * 100 / (115-40)

Die Werte b im Bereich 40 bis 115 liegen dann zwischen 0 und 100%. Werte außerhalb liegen dann unter 0 und über 100, was Du wahrscheinlich nicht möchtest, weshalb constrain die unerlaubten Werte auf die Grenzwerte abschneidet.

Nunja, bin kein Mathematiker, so ungefähr :slight_smile:

Genau, hab grad den UNO mit Serial ausgepackt und hochgeladen.
Das Problem ist halt, die Werte über 115 werden per Tastendruck ja trotzdem erhöht.

Also, Lüfter geht auf volle Pulle=255.
Taste runter wäre dann 244, nochmal 233... usw bis 112, dann wäre ich erst bei 96%, ist nicht der Sinn der Sache.
Es soll mit jedem Tastendruck um 1% erhöht bzw weniger werden.

Ich glaub so wäre dasselbe was du gemacht hast.

 LUEFTER_Prozent= constrain(LUEFTER_PWM, 0, 100);

Hallo,

ich glaube du verrennst dich gerade selbst in deinen zwei Wertebereichen, Prozent und Lüfterleistung.
Einfach mal Ruhe bewahren und mitdenken was die anderen gemeint haben.

Bislang habe ich nur auf die Prozentrechnung geschaut, nicht auf Deine Tasten. Die 11 ist ein willkürlicher Wert, um nicht 256 Werte zu haben, nur wegen der Übersichtlichkeit.

Reset.

Du möchtest per Tastendruck auf dem Display einen Sollwert von 0 bis 100% eingeben können und möchtest als Stellwert für den Lüfter einen PWM-Wert zwischen 40 und 115?

Du möchtest per Tastendruck auf dem Display einen Sollwert von 0 bis 100% eingeben können und möchtest als Stellwert für den Lüfter einen PWM-Wert zwischen 40 und 115?

Genau richtig.

Dann willst Du Prozent in einen PWM-Wert umrechnen:

void setup()
{
  Serial.begin(9600);
  Serial.println("Anfang\nProzent\tWert");
  for (int b = 0; b <= 100; b += 10) {
    int a = map(b, 0, 100, 40, 115);
    a = a <= 40 ? 0 : a;
    Serial.print(b);
    Serial.print("\t");
    Serial.println(a);
  }
}

void loop() {}

Sieht gut aus aber wie wende ich das jetzt bei meinem Code an?

So könntest du das in Programmcode umsetzen. Ich hoffe, ich habe keine Fehler drin.

LUEFTER_Prozent = int(100 * (LUEFTER_PWM-40))/(115-40);

void LCDML_DISP_loop(LCDML_FUNC_LUEFTER_leistung) 
{
  uint8_t LUEFTER_Prozent;
   LUEFTER_PWM= LUEFTER_PWM == 0 ? 40 :LUEFTER_PWM ;
   LUEFTER_PWM= LUEFTER_PWM == 255 ? 115 :LUEFTER_PWM ;
      if (LCDML_BUTTON_checkUp() && (LUEFTER_PWM<115))    { LUEFTER_PWM++; LCDML_BUTTON_resetUp(); }
      if (LCDML_BUTTON_checkDown() && (&& (LUEFTER_PWM>40))  { LUEFTER_PWM--; LCDML_BUTTON_resetDown(); }
      if (LCDML_BUTTON_checkEnter()) { LCDML_DISP_funcend(); }  
   LUEFTER_Prozent = int(100 * (LUEFTER_PWM-40))/(115-40);
   lcd.setCursor(0, 1); lcd.print(F("Leistung:")); lcd.print(LUEFTER_Prozent); lcd.print(F("%   "));

   LUEFTER_PWM= LUEFTER_PWM <= 40 ? 0 :LUEFTER_PWM ;
   LUEFTER_PWM= LUEFTER_PWM >= 115 ? 255 :LUEFTER_PWM ;

    }

Die Umständlichen ? Abfragen sorgen dafür, dass der Lüfter ab 40 auf Null gesetzt wird und ab 115 auf volle Leistung. Wenn du den gesamten Code hier hättest, könnte man es bestimmt eleganter einbinden.

Das ist eigentlich schon der ganze Sketch, wer will kann auch das große ganze laden.
Danke Jungs, so wollt ichs haben, zumindest funktionierts so wie ich es will.

void LCDML_DISP_setup(LCDML_FUNC_LUEFTER_leistung) {}
void LCDML_DISP_loop(LCDML_FUNC_LUEFTER_leistung) 
{
  uint8_t LUEFTER_Prozent;
   LUEFTER_PWM= LUEFTER_PWM == 0 ? 40 :LUEFTER_PWM ;
   LUEFTER_PWM= LUEFTER_PWM == 255 ? 115 :LUEFTER_PWM ;
      if (LCDML_BUTTON_checkUp())    { LUEFTER_PWM++; LCDML_BUTTON_resetUp(); }
      if (LCDML_BUTTON_checkDown())  { LUEFTER_PWM--; LCDML_BUTTON_resetDown(); }
      if (LCDML_BUTTON_checkEnter()) { LCDML_DISP_funcend(); }  
     LUEFTER_Prozent = (LUEFTER_PWM-40) * 100 / (115-40);//7068 Bytes
  // LUEFTER_Prozent = int(100 * (LUEFTER_PWM-40))/(115-40); //7068 Bytes
  // LUEFTER_Prozent = map(LUEFTER_PWM, 40, 115, 0, 100);//7160 Bytes

lcd.setCursor(0, 1); lcd.print(F("Prozent:")); lcd.print(LUEFTER_Prozent); lcd.print(F("%   "));
lcd.setCursor(0, 2); lcd.print(F("    PWM:")); lcd.print(LUEFTER_PWM); 
analogWrite(FAN_PIN, LUEFTER_PWM);

   LUEFTER_PWM= LUEFTER_PWM <= 40 ? 0 :LUEFTER_PWM ;
   LUEFTER_PWM= LUEFTER_PWM >= 115 ? 255 :LUEFTER_PWM ;

    }
void LCDML_DISP_loop_end(LCDML_FUNC_LUEFTER_leistung) {}

LCDML_liquidcrystal.zip (7.88 KB)

Wenn ich das richtig verstanden habe möchte man hier einen regelbaren Bereich von 75, 115-40, prozentual einstellen, oder?
Also ist 100% von 75 aus gesehen 1,33333 mal größer.
256 / 1,33 ist dann 192 als Multiplikator:
100 * 192 / 256 = 75
50 * 192 / 256 = 37
1 * 192 / 256 = 0
Danach muss man nur noch den Bereichsbeginn von 40 aufaddieren:
PWM_Wert = Prozent_Wert * 192 / 256 + 40;
Dank inteligentem Compiler sind das dann auch nur ein paar Maschinencodes.

Falls ich jetzt total falsch lieg, duck und weg ^^

Neee, das läuft jetzt so, da ändere ich jetzt nichts mehr, bin froh dass es endlich läuft, danke jungs!

Eine Sache noch.
Mal angenommen ich bin bei 1% (41 PWM).
Der Lüfter läuft nicht vonalleine los, also dreht nicht.
Selbst bei 50 PWM läuft der nicht los, erst bei ca 80 PWM.
Wie kann man das schlau lösen?
Lüfter haben nur VCC und GND, fals es was zu sagen hat.

Der Lüfter läuft auch noch bei 40 PWM (wenn man von 100% auf 0% runtergeht) aber den hab ich ausgeschaltet, wären dann ja 0%.
if(LUEFTER_PWM<=40) digitalWrite(FAN_PIN, LOW);

skorpi08:
Wie kann man das schlau lösen?

Schon mal darauf geachtet, daß der PC-Lüfter nach dem Einschalten einmal aufheult, um dann seine ruhige Drehzahl zu erreichen? Ob das eine für Deine Anwendung schlaue Lösung ist, entzieht sich aber meiner Kenntnis.

  if (LCDML_BUTTON_checkUp())    { If (LUEFTER_PWM==40) {analogWrite(FAN_PIN, 255); delay(200);}
                                        LUEFTER_PWM++; LCDML_BUTTON_resetUp(); }

Wenn man von Null den Lüfter startet, wird er für kurze Zeit auf volle Spannung gestellt. Wenn er deutlich länger zum Anlaufen braucht, sodass das Delay stört, müsste man von Delay auf millis umstellen.

Mir ist noch aufgefallen:

analogWrite(FAN_PIN, LUEFTER_PWM);

   LUEFTER_PWM= LUEFTER_PWM <= 40 ? 0 :LUEFTER_PWM ;
   LUEFTER_PWM= LUEFTER_PWM >= 115 ? 255 :LUEFTER_PWM ;

Hier solltest du analogwrite hinter die Abfragen setzen. Ansonsten könnte man sie sich auch sparen. Der Lüfter soll ja bei 40 stehen bleiben und bei 115 auf Vollgas laufen.

analogwrite hab ich jetzt nicht mehr in der Funktion drin, schon ausserhalb.

So hab ichs auch gelöst:

   LUEFTER_PWM= LUEFTER_PWM <= 40 ? 0 :LUEFTER_PWM ;
   LUEFTER_PWM= LUEFTER_PWM >= 115 ? 255 :LUEFTER_PWM ;
if( LUEFTER_PWM<70) { analogWrite(FAN_PIN, 100); delay(10); analogWrite(FAN_PIN, LUEFTER_PWM);}

zuckt der halt klein wenig aber passt schon, danke.