Forum: Mikrocontroller und Digitale Elektronik int nach 'Bar graphic' konvertieren


von Philipp G. (geiserp01)


Lesenswert?

CPU: ATMEGA328
LCD: 16x2 Zeichen

Der numerische Wert 'iTurbo10e' kann 0 bis maximal 16 haben. Dieser soll 
in einer Art 'Zeichenstrahl' auf dem LCD ausgegeben werden.

Beispiele:

bei 0:
----------------

bei 1:
*---------------

bei 5:
*****-----------

bei 16:
****************

Hierfür der Code:
1
    if (iTurbo10e > 0)
2
        {
3
            for (int i = 0; i < iTurbo10e; i++)
4
                {
5
                strTmp = strTmp + "*";
6
                }
7
            for (int i = iTurbo10e; i <= 16; i++)
8
            {
9
              strTmp = strTmp + "-";
10
            }
11
            strTmpLCDLine2 = strTmp;
12
        }
13
      else
14
        {
15
          strTmpLCDLine2 = "----------------";
16
        }
17
  break;

Kommt jemandem etwas performanteres hin?

: Bearbeitet durch User
von 50c (Gast)


Lesenswert?

Philipp G. schrieb:
> Kommt jemandem etwas performanteres hin?

zuerst
strTmpLCDLine2 = "----------------";

und dann die '*', wenn welche gezeichnet werden müssen.

von ... (Gast)


Lesenswert?

1
strTmpLCDLine2 = "----------------";
2
for (int i = 0; i < iTurbo10e; i++)
3
{
4
   strTmpLCDLine2[i] = "*";
5
}

von Philipp G. (geiserp01)


Lesenswert?

... schrieb:
> strTmpLCDLine2 = "----------------";
> for (int i = 0; i < iTurbo10e; i++)
> {
>    strTmpLCDLine2[i] = "*";
> }

Hach, dabei ist es doch so einfach. Danke jungs.

von hilfesteller (Gast)


Lesenswert?

1
// Mit der Annahme, dass strTmpLCDLine2 ein Array ist mit mindestens 17 bytes
2
3
int i = 0;
4
for(; i < iTurbo10e; i++) {
5
  strTmpLCDLine2[i] = '*';
6
}
7
for(; i < 16; i++) {
8
  strTmpLCDLine2[i] = '-';
9
}
10
strTmpLCDLine2[i] = 0;

von Philipp G. (geiserp01)


Lesenswert?

hilfesteller schrieb:
> // Mit der Annahme, dass strTmpLCDLine2 ein Array ist mit mindestens 17
> bytes
>
> int i = 0;
> for(; i < iTurbo10e; i++) {
>   strTmpLCDLine2[i] = '*';
> }
> for(; i < 16; i++) {
>   strTmpLCDLine2[i] = '-';
> }
> strTmpLCDLine2[i] = 0;

Dabei sind es aber zwei Loops, Begründung warum das performanter ist als 
die beiden Vorredner?

von zitter_ned_aso (Gast)


Lesenswert?

Philipp G. schrieb:
> for (int i = iTurbo10e; i <= 16; i++)

müsste es hier nicht bis 15 gehen?

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Wenn dir 16 Zeichen als Auflösung reichen, bist du fertig. Ich habe mir 
mal Blöcke mit einem bis 6 vertikalen Linien als Sonderzeichen 
definiert, um dann innerhalb eines Zeichens noch 5 Unterabstufungen zu 
machen.

: Bearbeitet durch User
von Random .. (thorstendb) Benutzerseite


Lesenswert?

Pseudocode:
1
const string A = "----------------";
2
const string B = "****************";
3
4
string C = A;
5
memcpy(C, B, percent16);

Ggf. ist es sogar performanter, die beiden Teilstücke mit Positionierung 
auf dem LCD einzelnd auf selbiges zu schreiben.

: Bearbeitet durch User
von Reiner Gast (Gast)


Lesenswert?

Ggf. ist das noch schneller....

strLCDLine = "****************----------------";
strLCDLinePtr = strLCDLine[16-iTurbo10e];

von Sascha W. (sascha-w)


Lesenswert?

eben, warum nicht gleich ausgeben
1
for(int i=0; i < 16; i++) {
2
  if (i<iTurbo10e) {
3
     DisplayPutChar('*');
4
  } else {
5
     DisplayPutChar('-');
6
  }
7
}

Sascha

von Mario M. (thelonging)


Lesenswert?

Philipp G. schrieb:
> Kommt jemandem etwas performanteres hin?

Cursor positionieren und nur die zu überschreibenden Zeichen ausgeben.

von Oliver S. (oliverso)


Lesenswert?

Eben. Die Berechung des Strings ist auch in der langsamsten Variante 
immer noch um Größenordnungen schneller als die Ausgabe aufs Display.

Oliver

von Philipp G. (geiserp01)


Lesenswert?

Matthias S. schrieb:
> Wenn dir 16 Zeichen als Auflösung reichen, bist du fertig. Ich habe mir
> mal Blöcke mit einem bis 6 vertikalen Linien als Sonderzeichen
> definiert, um dann innerhalb eines Zeichens noch 5 Unterabstufungen zu
> machen.

Ist eigentlich eine gute Idee von Dir. Denn das Display lässt 8 
Sonderzeichen programmieren.

Ich möchte also 4 Blöcke programmieren.

1) 1/4 Block
2) 1/2 Block
3) 3/4 Block
4) Full Block

Damit komme ich auf eine Auflösung von 64.

Nur weiss ich jetzt nicht, ob ich mit Arduino Mitteln das hinbekomme.

Anbei das DB:
https://cdn-reichelt.de/documents/datenblatt/A500/DS_DIP162.pdf

Jemand eine Idee hierzu? -> CG RAM Address Set

von M.K. B. (mkbit)


Lesenswert?

Philipp G. schrieb:
> Dabei sind es aber zwei Loops, Begründung warum das performanter ist als
> die beiden Vorredner?

Zwei Loops kosten ja erstmal nicht mehr. Außerdem wird i im zweiten Loop 
auch nicht nochmal initialisiert.
Das Array wird nicht unnötig mit - beschrieben und dann mit * 
überschrieben.

Wenn man die Performance wirklich bewerten will, dann sollte man die 
verschiedenen Arten nach der optimierten Übersetzung im Assembler 
anschauen.

von Yalu X. (yalu) (Moderator)


Angehängte Dateien:

Lesenswert?

Philipp G. schrieb:
> Matthias S. schrieb:
>> Wenn dir 16 Zeichen als Auflösung reichen, bist du fertig. Ich habe mir
>> mal Blöcke mit einem bis 6 vertikalen Linien als Sonderzeichen
>> definiert, um dann innerhalb eines Zeichens noch 5 Unterabstufungen zu
>> machen.
>
> Ist eigentlich eine gute Idee von Dir. Denn das Display lässt 8
> Sonderzeichen programmieren.
>
> Ich möchte also 4 Blöcke programmieren.
>
> 1) 1/4 Block
> 2) 1/2 Block
> 3) 3/4 Block
> 4) Full Block

Hier sind zwei Vorschläge für die gleichzeitige Darstellung von 2 bzw. 4
Balkendiagrammen mit einem Wertebereich von 0–64 bzw. 0–32 in einer
Form, die die Abstände zwischen den einzelnen Zeichen des Textdisplays
und damit dessen 16×2-Natur etwas kaschiert.

Unter den Beispielen sind die jeweils benötigten Zeichenmuster gezeigt.
Das jeweils erste braucht natürlich nicht neudefiniert zu werden, da es
als Leerzeichen schon existiert.

von M. K. (sylaina)


Lesenswert?

zitter_ned_aso schrieb:
> Philipp G. schrieb:
>> for (int i = iTurbo10e; i <= 16; i++)
>
> müsste es hier nicht bis 15 gehen?

Alternativ das "=" rauswerfen ;)

von Rolf M. (rmagnus)


Lesenswert?

M.K. B. schrieb:
> Philipp G. schrieb:
>> Dabei sind es aber zwei Loops, Begründung warum das performanter ist als
>> die beiden Vorredner?
>
> Zwei Loops kosten ja erstmal nicht mehr. Außerdem wird i im zweiten Loop
> auch nicht nochmal initialisiert.

Und in der anderen Variante gibt's auch eine zweite Schleife, nämlich 
die,  die das Array mit den Minussen ausfüllt. Und da muss diese 
Schleife immer alle Elemente beschreiben und nicht nur die, in denen 
tatsächlich am Ende ein Minus stehen soll.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Philipp G. schrieb:
> Nur weiss ich jetzt nicht, ob ich mit Arduino Mitteln das hinbekomme.

Ich habe das damals in ASM51 gemacht, aber das Prinzip war einfach. 
Ausgabewert durch 6 teilen, weil mein Display ein 6*8 Pixel/Letter war.
Das Ganzzahlergebnis als Anzahl der Vollblöcke aufs Display schicken und 
der Rest der Division war die Nummer des Sonderzeichens. Also 0 für 
keinen vertikalen Strich, 1 für einen Strich usw. Die Sonderbehandlung 
des Leerzeichens habe ich mir m.E. damals gespart.
Die Sonderzeichen sahen genauso aus, wie Yalu im seinem Beitrag im 
linken Bild illustriert.

: Bearbeitet durch User
von Philipp G. (geiserp01)


Lesenswert?

Matthias S. schrieb:
> Ich habe das damals in ASM51 gemacht, aber das Prinzip war einfach.
> Ausgabewert durch 6 teilen, weil mein Display ein 6*8 Pixel/Letter war.
> Das Ganzzahlergebnis als Anzahl der Vollblöcke aufs Display schicken und

Ja, das ist schon klar, aber ich muss meinem Display ja erst die 
Sonderzeichen beibringen. Frage ist halt ob ich das mit Arduino Mitteln 
hinbekomme.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Philipp G. schrieb:
> Frage ist halt ob ich das mit Arduino Mitteln
> hinbekomme.

Mit Arduino Libraries kenne ich mich nicht aus, aber in purem AVR-GCC 
ist das einfach - wobei ich schon lange keine LCD Routinen mehr selber 
mache, sondern Peter Fleury den Job überlassen habe. Seine LCD 
Funktionen sind einfach, anpassbar und idotensicher.
http://homepage.hispeed.ch/peterfleury/avr-software.html

Hier ist es dann die Funktion 'lcd_data()', mit der man den CG RAM 
befüllt.

: Bearbeitet durch User
von Cyblord -. (cyblord)


Lesenswert?

Philipp G. schrieb:
> Ja, das ist schon klar, aber ich muss meinem Display ja erst die
> Sonderzeichen beibringen. Frage ist halt ob ich das mit Arduino Mitteln
> hinbekomme.

Ich könnte die 100m in 8 Sekunden laufen aber ich weiß nicht ob ich das 
mit meinen Turnschuhen hinbekomme.

Will sagen:
Wenn man nicht Schwimmen kann ist seltenst die Badehose schuld.

Also schieb deine Unfähigkeit nicht auf deine falsche Entschiedung 
Arduino zu verwenden, sondern arbeite daran.

: Bearbeitet durch User
von Ozvald K. (Gast)


Lesenswert?

Hallo Philiph,

nur als Denkanstoß: ich habe die Bargraph Funktion nur mit einem 
Sonderzeichen realisiert. Man positioniert den Sonderzeichen und füllt 
den Inhalt zur Laufzeit dem Wert entsprechend: 0x10 für einen vertikalen 
Balken, 0x18 für 2, 0x1C für drei, 0x1E für 4 (natürlich das alles 8 mal 
damit das Symbol die volle Höhe erreicht) und für 5 Balken (Zeichen 
voll) nehme ich den Zeichencode 0xFF. Vorteil: du kannst die anderen 
Sonderzeichen für andere Zwecke nutzen. Der Bargrahp selbst hat Lücken 
zwischen einzelnen Zeichen (zwischen 5 und 6 , 10 und 11, usw.)  aber 
das ist Display bedingt.

von Philipp G. (geiserp01)


Lesenswert?

Ozvald K. schrieb:
> nur als Denkanstoß: ich habe die Bargraph Funktion nur mit einem
> Sonderzeichen realisiert. Man positioniert den Sonderzeichen und füllt
> den Inhalt zur Laufzeit dem Wert entsprechend: 0x10 für einen vertikalen
> Balken, 0x18 für 2, 0x1C für drei, 0x1E für 4 (natürlich das alles 8 mal
> damit das Symbol die volle Höhe erreicht) und für 5 Balken (Zeichen

Gute Idee, ich habe eben bemerkt, ich kann sogar jedes einzelne Pixel 
frei definieren, könnte sogar eine Graphik hinterlegen.

Danke für den Tipp, so mach ichs.

von Philipp G. (geiserp01)


Lesenswert?

Ok, das funktioniert. Ich habe 5 Zeichen definiert, Zeichen 0 entspricht 
einem Balken, 1 entspricht 2 Balken, etc.

Ab jetzt wird es ein bisschen tricky.

-> (Max vertikale Balken = 5 * 16 = 80)

Wenn ich die 40 schreibe, ist der Balken in der Mitte. Schreibe ich dann 
eine 21, löscht mein Code die gesamte Zeile und schreibt den Balken 
entsprechend der 21.

Jetzt wäre natürlich viel schöner, er würde die 20 stehen lassen, den 
Rest löschen und nur einen Balken mehr schreiben.

Beispiel:

Wert = 40
Bar = 5 Balken * 8 Digits sind ausgefüllt, Rest leer.

Neuer Wert = 21
Bar = 1 Balken, 2 Digits sind ausgefüllt, Rest leer

Hierzu muss er also 6 Digits löschen, und dann nur ein Balken schreiben. 
Anbei bei Code:
1
void loop()
2
{
3
    int iCursor = 0;
4
  int iBarC = 0;
5
    iRandom = random(0,80); // generate a random number
6
  // byte(0) = |
7
   // byte(1) = ||
8
  // byte(2) = |||
9
  // byte(2) = ||||
10
  // byte(4) = |||||
11
12
  for (int i = 0; i <= iRandom; i++)
13
    {
14
    if (i >= (iCursor + 1) * 5)
15
      {
16
        iCursor = iCursor + 1;
17
        iBarC = 0;
18
      }
19
    LCD.setCursor(iCursor,0);
20
    LCD.write(byte(iBarC));  
21
    iBarC = iBarC + 1;
22
    }
23
24
 delay(300);
25
 LCD.clear();
26
}

Das muss dann natürlich in beide Richtungen funktionieren. Oder meint 
ihr, das ist unnötig?

: Bearbeitet durch User
von Ozvald K. (Gast)


Lesenswert?

Philipp G. schrieb:
> Neuer Wert = 21
> Bar = 1 Balken, 2 Digits sind ausgefüllt, Rest leer

4 Digits sind ausgefüllt und 1 Balken

Philipp G. schrieb:
> Jetzt wäre natürlich viel schöner,

Geschmacksache. Dazu müsstest du den letzten Wert merken und den 
Unterschied zu neuem Wert ausrechnen. Ich habe es folgendermaßen 
realisiert: Wert = 21 ->
21/5= 4 volle Zeichen, 1 Rest ist Anzahl der Balken im Sonderzeichen.
Leerzeichen = 16 - volle Digits - Sonderzeichen wenn gebraucht wird (bei 
0 Rest nicht) Die Routine geht immer komplett durch und füllt alle 16 
Stellen. Es mag jetzt nicht so high sophisticated erscheinen, aber wenn 
der µC nicht ausgelastet ist, dann ist es egal, du merkst den 
Unterschied nicht was die Geschwindigkeit angeht.
Umso mehr Logik, desto mehr Speicher wird benötigt. Bei ATMEGA328 gibt 
es eh genug davon, aber bei mir läuft es auf TINY13 und musste ich mit 
Flash sparsam umgehen. Die viele "wenn, dann..."-s brauchen mehr 
Speicher und am Ende sieht nicht besser aus.

von Philipp G. (geiserp01)


Lesenswert?

Ozvald K. schrieb:
>> Bar = 1 Balken, 2 Digits sind ausgefüllt, Rest leer
>
> 4 Digits sind ausgefüllt und 1 Balken

Ja. Stimmt.

Ozvald K. schrieb:
> Ich habe es folgendermaßen
> realisiert: Wert = 21 ->

Hättest Du Lust, diesen zu teilen?

von Sascha W. (sascha-w)


Lesenswert?

Philipp G. schrieb:
> Das muss dann natürlich in beide Richtungen funktionieren. Oder meint
> ihr, das ist unnötig?

ob das nötig ist hängt davon ab was der Controller sonst noch mach. Der 
entstehende Geschwindigkeitsgewinn bringt dir fürs Display nichts da das 
eh nicht so schnell in der Darstellung ist.

Sascha

von Ozvald K. (Gast)


Lesenswert?

Philipp G. schrieb:
> Hättest Du Lust, diesen zu teilen?

Ich habe es in Assembler realisiert, ob du damit Freude haben willst? 
:-)
Deswegen "nur" die Beschreibung aber kein Code hier

von Philipp G. (geiserp01)


Lesenswert?

Ozvald K. schrieb:
> Philipp G. schrieb:
> Hättest Du Lust, diesen zu teilen?
>
> Ich habe es in Assembler realisiert, ob du damit Freude haben willst?
> :-)
> Deswegen "nur" die Beschreibung aber kein Code hier

Nein, bitte nicht, davon bekomme ich Kopfschmerzen.

Aber cool dass du sowas in ASM hinbekommst.

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.