BarGraph ändern über Berechnung

Hallo,

ich stehe gerade auf dem Schlauch, wie kann ich sinnvoll aus verfügbaren Variablen die länge des Graphen berechnen?

Denke man müsste erst Prozent auswählen und bei 100% die maximale länge festlegen können.
Insgesamt sind es 5 BarGraphen mit verschiedenen Werten und Größen.

Die Länge des Graphen ist hier im Meinem Sketch mit 20,40,60 und 80 eingestellt auf Fest gerade.

#include <Arduino.h>
#include <U8g2lib.h>

#include <Wire.h> // library requires for IIC communication

U8G2_GP1294AI_256X48_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/2, /* dc=*/U8X8_PIN_NONE, /* reset=*/15);


void setup(void) {
  u8g2.begin(); // start the u8g2 library
}

void loop(void) {
  u8g2.clearBuffer();

  // Display 2
  // u8g2.drawFrame(80, 34, 176, 14);
  // u8g2.drawBox(82, 36, 20, 10); // 20 ist die länge  !!!!!!!!!!!!!!!!!!!!!!

  // Display 3
  u8g2.drawFrame(20, 2, 100, 14);
  u8g2.drawBox(22, 4, 20, 10); // 20 ist die länge  !!!!!!!!!!!!!!!!!!!!!!
  
  u8g2.drawFrame(20, 33, 100, 14);
  u8g2.drawBox(22, 35, 40, 10); // 40 ist die länge  !!!!!!!!!!!!!!!!!!!!!!

  u8g2.drawFrame(156, 2, 100, 14);
  u8g2.drawBox(158, 4, 60, 10); // 60 ist die länge  !!!!!!!!!!!!!!!!!!!!!!
  
  u8g2.drawFrame(156, 33, 100, 14);
  u8g2.drawBox(158, 35, 80, 10); // 80 ist die länge  !!!!!!!!!!!!!!!!!!!!!!


  u8g2.sendBuffer();


}

Vielen Dank

#include <Arduino.h>
#include <U8g2lib.h>

#include <Wire.h> // library requires for IIC communication

U8G2_GP1294AI_256X48_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/2, /* dc=*/U8X8_PIN_NONE, /* reset=*/15);

byte variable;

const byte maxBox = 100;    // PIXEL-Weite!!
const byte minValue = 0;
const byte maxValue = 255;
byte value;

void setup(void)
{
  Serial.begin(9600);
  u8g2.begin(); // start the u8g2 library
}

void loop(void)
{
  if (value > maxValue)
  { value = maxValue; }
  if (value < minValue)
  { value = minValue; }
  byte myValue = map(value, minValue, maxValue, 0, maxBox - 5);
  Serial.print(F("Value: "));
  Serial.print(value);
  Serial.println(F("Weite: "));
  Serial.println(myValue);
  u8g2.clearBuffer();
  u8g2.drawFrame(20, 2, maxBox, 14);
  u8g2.drawBox(22, 4, myValue, 10);
  u8g2.sendBuffer();
//
  delay(50);
  value++;
}

ungetestet - bitte den Seriellen Monitor beobachten.

1 Like

Vielen Dank Meister,

der Ansatz ist mir manchmal wichtig. Versuche es mal auszubauen.

Grüße

1 Like

Habe es gerade ausprobiert, vielleicht habe ich es nicht ganz verstanden.
Ich kann die MaxValue nicht verändern? ist dort mehr oder weniger wie 255 eingetragen, bleibt der Balken am ende stehen.

Oder hat es nur mit der Beispiel Value zutun, die auf ++ läuft?
Ich habe eine Value z.B. von 0 bis 7800, oder eine andere 1,34 - 4,56 z.B. kann aber gerade nicht damit testen da ich nicht Zuhause bin.

byte myValue = map(value, minValue, maxValue, 0, maxBox - 5);

Meine Value kommt anstatt der value nach "map(----- ?

#include <Arduino.h>
#include <U8g2lib.h>

#include <Wire.h> // library requires for IIC communication

U8G2_GP1294AI_256X48_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/2, /* dc=*/U8X8_PIN_NONE, /* reset=*/15);

byte variable;

const byte maxBox_2_1 = 176;    // PIXEL-Weite!!
const byte minValue_2_1 = 0;
const byte maxValue_2_1 = 255;
byte value;

void setup(void)
{
  Serial.begin(9600);
  u8g2.begin(); // start the u8g2 library
}

void loop(void)
{
  if (value > maxValue_2_1)
  { value = maxValue_2_1; }
  if (value < minValue_2_1)
  { value = minValue_2_1; }
  byte myValue_2_1 = map(value, minValue_2_1, maxValue_2_1, 0, maxBox_2_1 - 4);
  Serial.print(F("Value: "));
  Serial.print(value);
  Serial.println(F("Weite: "));
  Serial.println(myValue_2_1);
  u8g2.clearBuffer();
  u8g2.drawFrame(80, 34, maxBox_2_1, 14);
  u8g2.drawBox(82, 36, myValue_2_1, 10);
  u8g2.sendBuffer();
//
  delay(20);
  value++;
}

Grüße und vielen Dank für die Tipps

#include <Arduino.h>
#include <U8g2lib.h>

#include <Wire.h> // library requires for IIC communication

U8G2_GP1294AI_256X48_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/2, /* dc=*/U8X8_PIN_NONE, /* reset=*/15);

const byte maxBox_2_1 = 176;          // PIXEL-Weite!!
const uint16_t minValue_2_1 = 0;      // untere Grenze, ab der angezeigt werden soll
const uint16_t maxValue_2_1 = 7800;   // obere Grenze bis zu der angezeigt werden soll

uint16_t value;  // Variabel irgendein Wert

void setup(void)
{
  Serial.begin(9600);
  u8g2.begin(); // start the u8g2 library
}

void loop(void)
{
  if (value > maxValue_2_1)
  { value = maxValue_2_1; }
  if (value < minValue_2_1)
  { value = minValue_2_1; }
  byte myValue_2_1 = map(value, minValue_2_1, maxValue_2_1, 0, maxBox_2_1 - 4);
  Serial.print(F("Value: "));
  Serial.print(value);
  Serial.println(F("Weite: "));
  Serial.println(myValue_2_1);
  u8g2.clearBuffer();
  u8g2.drawFrame(80, 34, maxBox_2_1, 14);
  u8g2.drawBox(82, 36, myValue_2_1, 10);
  u8g2.sendBuffer();
  //
  delay(20);
  value++;
  if (value > maxValue)
  { value = 0; }
}

das wäre mein Ansatz.
Und jetzt noch das, mit den floatWerten.

#include <Arduino.h>
#include <U8g2lib.h>

#include <Wire.h> // library requires for IIC communication

U8G2_GP1294AI_256X48_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/2, /* dc=*/U8X8_PIN_NONE, /* reset=*/15);

const byte maxBox_2_1 = 176;          // PIXEL-Weite!!
const uint16_t minValue_2_1 = 134;      // untere Grenze, ab der angezeigt werden soll
const uint16_t maxValue_2_1 = 456;   // obere Grenze bis zu der angezeigt werden soll

float value;  // Variabel irgendein Wert

void setup(void)
{
  Serial.begin(9600);
  u8g2.begin(); // start the u8g2 library
}

void loop(void)
{
  if (value * 100 > maxValue_2_1)
  { value = maxValue_2_1 / 100; }
  if (value * 100 < minValue_2_1)
  { value = minValue_2_1 / 100; }
  byte myValue_2_1 = map(value * 100, minValue_2_1, maxValue_2_1, 0, maxBox_2_1 - 4);
  Serial.print(F("Value: "));
  Serial.print(value);
  Serial.println(F("Weite: "));
  Serial.println(myValue_2_1);
  u8g2.clearBuffer();
  u8g2.drawFrame(80, 34, maxBox_2_1, 14);
  u8g2.drawBox(82, 36, myValue_2_1, 10);
  u8g2.sendBuffer();
  //
  delay(20);
  value += 0.01;
  if (value >maxValue/100)
  value=0;
}

Nur ein floatwert, der rest komplett in Ganzzahl :slight_smile:
Bei der Berechnung z.B. maxValue/100 könnte ein cast notwendig werden.

1 Like

oder implizit

value / 100.0;

TGruß Tommy

2 Likes

Vielen Dank euch für die Antworten!!!

Probiere gleich aus.

oder implizit

value / 100.0;

Hmmm wahrscheinlich nicht mein Liga :face_with_hand_over_mouth: :grinning:

Beachte: auf der rechten Seite wird, wenn nicht anders angegeben immer mit int gerechnet.

687/100 sind also 6 und nicht 6.87
Es gibt mehrere Varianten:
implizit: 687/100.0 -> 6.87
explizit: static_cast<float>(687)/100 -> 6.87
explizit: float(687)/100 -> 6.87

:slight_smile:

1 Like

Dankeschön für die Erklärung, dann kann man es ja anders herum auch umrechnen, wenn Ausgangsdaten wären z.B.: 6,7 ?

Dankeschön für die anderen Vorschläge, der erste Sketch funktioniert gut, würde ich sagen.

Der zweite ist nicht korrekt, der Graphen ist sofort ausgefüllt und Serielleausgabe gibt immer gleiche Werte aus:

Value: 1.00Weite: 
238

Habe versucht bei value unten zu den einen + noch einen + hinzufügen, da mag aber Arduino IDE nicht so wirklich mit ++=.

Welche Methode wäre den die "bessere", bei der zweiten hat man ja zusätzlich ja noch umrechenwege. Geht wahrscheinlich auch nicht anders.

uint16_t value;
uint16_t meine Value;

und hier ersetze ich meine die Value durch irgend eine von mir? Weiter unten um Sketch müsste man bestimmt auch noch umbenennen.

Hier nen Beispiel der Werte die ich dann von einem anderen Gerät bekomme:

int rpm = 101;
int vss = 60;
int temp_cool = 103;
int temp_air = 104;
float abs_pres = 105;
float atm_pres = 106;
int thr_pos = 107;
float volt_lz1 = 108;
float volt_lz2 = 109;
float volt_net = 110;
float load_gen = 111;
float load_eld = 112;
float pos_egr = 113;
int st_cor = 114;
int lt_cor = 115;
float time_inj = 1;
int ign = 117;
int limit_ign = 118;
float valv_idle = 119;
float valve_egr = 120;
float pos_valve_egr = 121;
int fuelc = 1;
u8g2.print(volt_net, 2);

Die werden mir dann so ausgespuckt

Moin,

konnte jetzt erst vernünftig die Beispeiele gescheit austesten.
Sieht gut aus! Funktioniert gut, vielen Dank für die Hilfe!
So was einfaches und schmales hätte ich gewünscht auf GitHub gefunden zu haben.

Habe noch ne kurze Frage, ist es sehr kompliziert sanfte veränderung des Bars hinzufügen?
jetzt springt es ja von z.B. 30% auf 100%, das es evtl. schnell dahin läuft oder eben runter.

Und überhaupt das beste dazu wäre noch ein kleiner Strich kurz auf max Wert stehen bleiben zu lassen, der nach ca. 100ms runter läuft zum aktuellen Wert. Änhlich wie bei den Analysern.

Aber an der stelle ein dickes Dankeschön an euch, hab mir da sehr weiter geholfen!!! :smiling_face_with_three_hearts:

Hat vielleicht jemand nen Tipp wie ich die Bewegung von springen auf gleiten so zusagen ändern kann?

Müsste ja mit ++ und -- funktionieren. Kurz herum experimentiert, leider ohne Erfolg.

Grüße

Ja nu.
Weil es so einfach ist, wirst Du dort sowas nicht finden.
Und was nutzt es Dir, wenn Du sowas findest, aber nix mit anfangen kannst?

Womit wir beim Thema wären:

Ja.

Damit ist die Frage beantwortet. :laughing:

Das, was Du suchst, könnte eine Mittelwertermittlung leisten.

Welcher von Deinen Werten da oben verändert sich denn so extrem?

1 Like

Wenn du so fragst: ja!

Statt einer Ausgabe per drawBox müsstest du zig unterschiedliche machen, mit jeweils einem Pixel mehr, dir jeweils die Zeit merken damit du weißt, wann der nächste Pixel dazu kommen soll (damit es schön langsam wird, und evtl. dir noch merken, zu welchem Zielwert du willst.
Langsame Änderung zu einem kleineren Wert ist übrigens die eigentliche Aufgabe dabei, wenn du nicht immer wieder den BarGraph komplett neu auf einen gelöschten Hintergrund (flackernd) malen willst.

Stimmt, das wäre auch hübsch. Diesen Strich nach einem ähnlichen Verfahren wie oben runterwandern zu lassen wäre das Sahnetüpfelchen.

Den Min Wert willst du nicht markieren (durch eine kleine Lücke) ? Das wäre dann nochmal eine Herausforderung, weil entweder aus jedem drawBox zwei werden müssten oder du den Strich in Hintergrundfarbe in die Box malen musst.

Alternativ könntest du auch --statt drawBox zu verwenden-- alle zu ändernden Werte des BarGraph in einer der Farben (VG / HG) als einzelne Striche malen.

Mach mal ! :stuck_out_tongue:

1 Like

Dankeschön für die Antworten, denke sind mehr oder weniger alle Werte schnell. Drosselklappe z.B.

Scheint also doch komplexer zu sein wie ich dachte.
Da wie oben im Beispiel value++ das mehr oder weniger auch gut funktionierte, so optisch zumindest auf dem Display.

Werde morgen mal mehrere Beispiele dazu anschauen.

Grüße

Du könntest einen Istwert dem Sollwert nachziehen und dabei die maximale Änderung pro Zyklus begrenzen.

Ungefähr so:

void setup(){
  Serial.begin(115200);
}

int16_t current = 0;
constexpr auto maxStep = 10;

void loop(){
  auto value = analogRead(A0);
  
  auto dx = value - current;
  
  dx = min(dx, maxStep);
  dx = max(dx, -maxStep);
  
  current += dx;

  drawBarGraph(current);
    
  char buf[32];
  snprintf(buf, sizeof(buf), "Soll: %d, ist: %d", value, current);
  Serial.println(buf);
  
  delay(100);
}
1 Like

Nein.
Ich hab mir mal Gedanken gemacht.
Wenn ich nachher in den Zug steige, werde ich das mal in Code bauen.
Als erstes nur die Variante, das am oberen Ende ein kleiner Balken als Spike stehen bleibt und nach einer festgelegten Zeit verschwindet.
Das ist gar nicht so schwer.

Da ich mit der Grafik-lib noch nie was zutun hatte, was über die Verwendung von fixen Vorgaben hinaus geht, muss ich erstma sehen, was die

Zeilen eigentlich beinhalten.
Dann baue ich Dir zwei Kästchen mit zwei Balken :slight_smile:

Du wirst Dich vermutlich in ein paar Dinge einlesen müssen - aber das wird...

1 Like

Einen Peakwert würde ich ungefähr so berechnen:

void setup(){
  Serial.begin(115200);
}

unsigned long peakLast = 0;
uint16_t peakValue = 0;

constexpr auto cooldown = 5000;
constexpr auto fallRate = 50;

uint16_t calcCurrentPeak(){
  auto now = millis();
  
  if((now - peakLast) < cooldown)
    return peakValue;
  
  auto dt = now - peakLast;
  auto dx = dt / fallRate;
  
  if(dx >= peakValue)
    return 0;
  
  return peakValue - dx;
}

void loop(){
  auto value = analogRead(A0);
  
  auto current = calcCurrentPeak();
  if(current <= value){
    peakLast = millis();
    peakValue = value;
    current = value;
  }

  drawPeak(current);
    
  char buf[32];
  snprintf(buf, sizeof(buf), "soll: %d, peak: %d", value, current);
  Serial.println(buf);
}
1 Like

Den braucht man nicht berechnen.
Den bekommst Du mit jedem Umlauf gratis auf die Hand geliefert.

1 Like

Echt? Was übersehe ich da gerade?

1 Like

Mein Versuch mit zwei Boxen und zwei unterschiedlichen Wertebereichen.
Es kompiliert fehler- und warnungsfrei.

Ich habe keine Hardware und hab mir ein wenig zusammengereimt.

#include <Arduino.h>
#include <U8g2lib.h>

#include <Wire.h> // library requires for IIC communication

U8G2_GP1294AI_256X48_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/2, /* dc=*/U8X8_PIN_NONE, /* reset=*/15);

struct BOX
{
  const uint16_t x;        // Frame !
  const uint16_t y;
  const uint16_t w;
  const uint16_t h;
  const uint16_t minValue; // untere Grenze, ab der angezeigt werden soll
  const uint16_t maxValue; // obere Grenze bis zu der angezeigt werden soll
  uint16_t peek;           // Merker für oberen Anzeigewert
  uint32_t peektime;       // Merker, wann oberer Wert zuletzt berechnet
  uint16_t value;          // Variable -> Den Wert musst Du liefern!
};

BOX box[] =
{
  {20,  2, 100, 14, 100, 500, 0, 0, 0},       // X, Y, Widht, High, Min-Begrenzung, Max-Begrenzung, merker, merker, Messwert
  {20, 33, 100, 14,   0, 999, 0, 0, 0}
} ;

const byte frameFree = 2;                     // Pixel zwischen Frame und Balken
const uint32_t refreshTime = 30;              // "delay"
const uint32_t intervall = refreshTime * 6;   // Berechnet, damit der Balken stehen bleibt :)

void setup(void)
{
  Serial.begin(9600);
  u8g2.begin();
  randomSeed(analogRead(A0));
}

void loop(void)
{
  // RANDOM Value setzen
  for (byte b = 0; b < sizeof(box) / sizeof(box[0]); b++)
  { box[b].value = random(box[b].minValue, box[b].maxValue); }
  // Wenn nicht random, muss ein Realwert mit jedem Umlauf eingefügt werden
  /*
    box[0].value = ;
    box[1].value = ;
  */
  setDisplay();
}


void setDisplay()
{
  u8g2.clearBuffer();
  for (byte b = 0; b < sizeof(box) / sizeof(box[0]); b++)
  {
    // Begrenzung für map
    if (box[b].value > box[b].maxValue)
    { box[b].value = box[b].maxValue; }
    if (box[b].value < box[b].minValue)
    { box[b].value = box[b].minValue; }
    // Balkenlänge ermitteln
    uint16_t balken = map(box[b].value, box[b].minValue, box[b].maxValue, 0, box[b].w - frameFree * 2);
    Serial.print(F("\r\n BoxNummer / Value / Balkenlänge: "));
    Serial.print(b);
    Serial.print(' ');
    Serial.print(box[b].value);
    Serial.print(' ');
    Serial.println(balken);
    // Frame setzen
    u8g2.drawFrame(box[b].x, box[b].y, box[b].w, box[b].h);
    // Balken in den Frame
    u8g2.drawBox(box[b].x + frameFree, box[b].y + frameFree, box[b].w + frameFree + balken, box[b].h - frameFree);
    if (box[b].peek < balken)
    {
      box[b].peek = balken;
      box[b].peektime = millis();
    }
    else
    {
      if (millis() - box[b].peektime < intervall)
      {
        const byte lines = 1;
        u8g2.drawBox(box[b].x + frameFree + box[b].peek - lines, box[b].y + frameFree, lines, box[b].h - frameFree);
      }
      else
      { box[b].peek = 0; }
    }
  }
  u8g2.sendBuffer();
  delay(refreshTime);
}

Der Peek soll nen Moment mit einer 1pixel-Line stehen und dann verschwinden.
Wenn das auf dem Display verschoben ist, dann hab ich mich mit den x/y-Koordinaten verhauen...
Der Balken als solches wird Dir immer noch zu hektisch sein, aber eins nach dem anderen :slight_smile:

Ich bin da jetzt irgendwie raus, auf was Du Dich beziehst, aber ich hab ja geschrieben, dass da ein cast notwendig ist.
Und bei meiner Erklärug hab ich mich mit jeweils einer Klammer vertan.
Nicht die gesamte Rechnerei gehört da rein, sondern nur der erste Wert.
Ich habs geändert.

Na dann...

1 Like