Umrechnung von Dez zu Hex mit Kontrolle und Begrenzung

achim S.

Mitglied
16. Jan. 2010
704
13
18
Berlin Biesdorf
Sprachen
  1. ANSI C
Hallo Gemeinde
such ein Stück Code in C zur Umrechnung von Dezi zu Hex.
Zum Problem (alles in C)

0x30 bis 0x39 sind die Zahlen 0 bis 9
0x41 bis 0x46 sind A bis F

Zur Ansteuerung eines Graphigdisplays muss ich den Wert von 0x00 bis
0xFF (hexa) übertragen (bis zu 3 mal). Zur Eingabe der Werte kann ich nur 0 bis
255 (dezimal) nutzen.
Wie kann ich die Werte in C umrechnen und gleizeitig die Eingabewerte
kontrollieren (Begrenzung der Hexzahlen)?
Hat da jemand eine Idde dazu?
achim
 
0x30 bis 0x39 sind die Zahlen 0 bis 9
0x41 bis 0x46 sind A bis F
Das ist doch die ganz normale ASCII...
0x30=48dezimal="0" als Character/String.
Im AVR in jedem Fall 00110000 binär.
Die Frage ist also nur, wie Du den Compiler auf die Speicherzelle zugreifen/ihn den Inhalt interpretieren läßt.
Unter ASM kümmerst Du Dich eh umalles selbst.
Unter BASCOM kann man dieselbe Variable (Speicherzelle) mit unterschiedlichen Namen (Overlay) als unterschiedliche Typen verwenden lassen.
Unter C mußt Du wahrscheinlich beim Zugriff nur festlegen (casten?) ob da irgendein Ergebnis als Byte/Char/dezimal weiterzuverwenden ist.

Wie gesagt. Im AVR ist das eh immer nur 8bit-binär.
gleizeitig die Eingabewerte kontrollieren (Begrenzung der Hexzahlen)?
Mit einer If...Then-Abfrage, als Bedingung halt die vier HEX-Grenzen mit AND und OR?
 
Irgendwie schnall ich die Frage nicht so richtig...
In welcher Form werden denn die "dezimalen Zahlen" erhalten? Als ein Byte? als Zwei-Byte-Variable, oder wie?
Und was soll da konkret zum Display gesendet werden?
Der Wert der Zahl (der wäre ja in jedem Zahlensystem gleich)?

Ähm...
oder hast Du eine Zahl von 0..4095 dezimal bzw 000hex..FFFhex bzw 000000000000bin..111111111111bin, und willst die drei Zeichen der hex-Darstellung quasi als String, also die entsprechenden ASCII dazu senden?
 
So wie ich verstanden habe bekommst du also bis zu 3 Bytes (ASCII) und musst daraus ein Byte formen?
Ich kann jetzt kein C, daher ungetesteter PseudoCode:



CodeBox BascomAVR
Function ConvertToByte(InBytes As Byte()) As Byte

  Dim RetVal As Byte = 0
  RetVal += ByteToBcd(InBytes(0)) * 100
  RetVal += ByteToBcd(InBytes(1)) * 10
  RetVal += ByteToBcd(InBytes(2))
  Return RetVal

End Function

Function ByteToBcd(InByte As Byte) As Byte

  Select Case InByte
    Case 0x30 To 0x39 : Return InByte - 0x30
    Case 0x41 To 0x46 : Return InByte - 0x37
    Case Else ' Fehler behandeln
  End Select

End Function


Select Case ist halt switch in c. Aber das Prinzip ist ja einfach.

Edit: Könnte auch ggf. 2, 1, 0 sein statt 0, 1, 2, je nachdem, letzteres ist bei Ascii aber eher unwahrscheinlich.
 
Zuletzt bearbeitet:
bekommst du also bis zu 3 Bytes (ASCII) und musst daraus ein Byte formen?
Das wären Dezimalstellen in Form eines Stringes (Array of Char oder sowas), die zu einer Zahl (im Sinne des Controllers ein Byte) zusammengefaßt werden.
Achim wollte aber dezimale Zahlen umwandeln... was er meinte, ist mir nicht klar.
Ich hätte jetzt von C als Hochsprache bereits 'ne fertige ByteToBcd-Funktion erwartet...
 
Das wären Dezimalstellen in Form eines Stringes (Array of Char oder sowas), die zu einer Zahl (im Sinne des Controllers ein Byte) zusammengefaßt werden.
So habe ich es interpretiert. Beispielsweise Eingabe per UART, Ausgabe als Byte.
Achim wollte aber dezimale Zahlen umwandeln... was er meinte, ist mir nicht klar.
Ich hätte jetzt von C als Hochsprache bereits 'ne fertige ByteToBcd-Funktion erwartet...
Mir auch nicht ;)
Und zu C... Kann ich nich, will ich nicht, bin kein Klammeraffe ^^
Ob es eine fertige Funktion dafür gibt... Könnte sein, kenn ich nicht.
Aber in ASM hättst du es ja auch nicht viel anders gemacht, oder? ;)
 
Hmmm...er wollte hex, nicht bcd..ist zwar auch hex, aber nur etwas :)
Ausserdem, wenn er 255 in ein byte quetscht, dann ist die form(hex, dec oder bin) eigentlich egal.
Es muss also die form des rüberschuebens eine andere sein.
Addi
 
Das müsste eigentlich schon so passen. Streng genommen kann man den 2. Part (für A-F) weg lassen, wäre bei Dezimal ja unnötig / ungültig. Dann wäre "0" = 0x00, "1" = 0x01, ... Bei Einsern ist Hex und BCD identisch ;) Und dann pro Zehner-/ Hunderterstelle dementsprechend multipliziert und addiert.
Ok, ich hab keine Overflow Überprüfung drin (Ascii > "255"). Details ;)
 
Aber in ASM hättst du es ja auch nicht viel anders gemacht, oder?
Ich bin noch am Grübeln, ob es im ersten Teil nicht besser wäre, statt der Multiplikationen mit 10 und 100 zweimal mit 10 zu multiplizieren
(Hunderter mal 10, Zehner addiert, mal zehn, Einer addiert). Zehn ist ja 00001010binär, Hundert hingegen 01100100binär.
Man könnte die Multiplikationsschleife also bereits nach vier Durchläufen terminieren lassen (beim Schieben kommt das "Z"-Flag)...
Hmm... andererseits sind die "Zehn" ja konstant - man braucht also eigentlich nichtmal wirklich die Schleife mit Prüfen auf "Bit=1" (Carry beim Schieben) usw... man kann das dann auch "blind" rechnen (Zahl einmal linksschieben, in ein Register kopieren, Zahl noch zweimal linksschieben, und in dasselbe Register addieren. Fertig)
Entweder ich hab jetzt 'n Dejavu, oder wir hatten das hier irgendwo schon mal...
Bei Controllern mit Multiplikationsinstruktion sieht das natürlich anders aus...
Hmmm...er wollte hex, nicht bcd
Ich bin mir nicht sicher, ob das was er wollte dem was er schrieb entspricht...
 
Entweder ich hab jetzt 'n Dejavu, oder wir hatten das hier irgendwo schon mal...
Bei Controllern mit Multiplikationsinstruktion sieht das natürlich anders aus...
Kann sein, gelegentlich hab ich n Hirn wie n Sieb, nur nicht ganz so dicht :D
Mit MUL hatten wir mal was, also dem Befehl, nicht der von Hand Geschichte. Aber ich wüsste jetzt auch nicht mehr wo. Ist ja auch egal, soll ja in C.
 
So ganz genau habe ich nicht verstanden, was erreicht werden soll.
Aber vielleicht hilft hier ja schon einmal itoa().
 
Guten Morgen
Kurz zur Erklärung. Das Display verlangt die Eingabe der Farben Rot, Grün, Blau durcj die Eingabe dieser 6 Werte.


CodeBox C
i2c_write(DOL);   bcc+=DOL;   // $ Vordergrund   
     i2c_write('F');   bcc+='F';   // Rot
     i2c_write('F');   bcc+='F'; 
   
     i2c_write('0');   bcc+='0';   // Grün
     i2c_write('0');   bcc+='0'; 
   
     i2c_write('0');   bcc+='0';   // Blau
     i2c_write('0');   bcc+='0';

Eigentlich sieht es nach Hersteller Angaben so aus: $FF0000
Muss also für die Darstellung einer Farbe 6 Werte in Hex übertragen. Das ganze muss ich mehrfach machen für Farbe Vordergrund, Transparent Vordergrung, Farbe Hintergrung und Transparenz Hintergrund.
Mann könnte es so machen:


CodeBox C
// YDC - TFM_Farbeinstellung
        // VR1-Vordergrund Rot, VG1-Vordergrund Grün, VB1-Vordergrund Blau, VT-Vordergrund Transparenz
        // VR2-Vordergrund Rot, VG2-Vordergrund Grün, VB2-Vordergrund Blau, VT-Vordergrund Transparenz
        // HR1-Hintergrund Rot, HG1-Hintergrund Grün, HB1-Hintergrund Blau, HT-Hintergrund Transparenz
        // HR2-Hintergrund Rot, HG2-Hintergrund Grün, HB2-Hintergrund Blau, HT-Hintergrund Transparenz
         TFM_Farbeinstellung( VR1, VR2, VG1, VG2, VB1, VB2);

Bei dieser Angabe kann es viel Fehler geben, da sehr viel Parameter. Nehme ich die Eingabe von Windows, z.B. 210 für VR1 und VR2, übertrage ich die Farbe Rot durch die Eingabe von einer Zahl die je nach Sättigung zwischen 0 und 255 liegen darf. Das wieder 3 mal für die Farbe Vordergrund.
Die Zahl 210 ist in Hex 0xD2. Jetzt besteht die Möglichkeit der falschen Eingabe. Die Hex Werte sind für
0 - 9 > 0x30 bis 0x39
A - F > 0x41 bis 0x46
für die Eingabe der 3 Farben möchte ich es so machen
TFM_Farbeinstellung( 255, 0, 0);
Diese 3 Werte muss ich danach in Hex umrechnen und kontrollieren ob die Einstellung korrekt ist. Es besteht ja die Möglichkeit das statt 255 auch 256 eingeben könnte. Dann brauche ich die Kontrolle und Begrenzung auf 255. Das ist wahrscheinlich das kleinste Problem.
Bei der Übergabe brauche ich teilweise bis zu 30 Parameter, was teilweise kompliziert ist.
Das Display ist eine uniTFT von EA mit 64 Millionen Farben, gefühlte 200 Befehle, einem eigenen Prozessor und Übertragung mit dem I2C Bus und Prüfsummen bildung.
Hoffe das ich mich Verständlich ausgedrückt habe
achim
 
Vielleicht hilft dies weiter ...



CodeBox C
const uint8_t hextable[16] = {
   '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
};

void SendAsHexString(uint8_t data)
{
   i2c_write(hextable[(data>>4) & 0x0F]);   // high
   i2c_write(hextable[data & 0x0F]);       // low
   
}
/* Beispiel:
 SendAsHexString(223);
 223d = 0xDF
 Sendet 'D' und 'F'
*/


Bei RGB übertragen entsprechend drei mal verwenden und wenn notwendig die Checksumme berechnen.
 
Hallo Dirk
hatte bereits in etwa so was im Netz gefunden.
Hatte gerade eine andere Version getestet. Die Ausgabe ist zwar korrekt, aber etwas fehlt. Es wird zwar 39 ausgegeb, müsste aber 0x39 sein.


CodeBox C
itoa( Zah1, Buffer, 16 );
     lcd_printlc(4,1,Buffer);
     itoa( Zah2, Buffer, 16 );
     lcd_printlc(4,7,Buffer);
     itoa( Zah3, Buffer, 16 );
     lcd_printlc(4,12,Buffer);

Nach meinen C-Buch ist doch die Wandlung mit itoa oder atoa (??) möglich.
Werde deine Version testen.
Es geht immer noch um das Display von den letzten Themen. Ist halt sehr anspruchsvoll (kompliziert)
achim
 
Es wird zwar 39 ausgegeb, müsste aber 0x39 sein.
Ein String "0x" brauchst du doch nicht und überträgst du auch nicht, der String mit der Zahl stellt ja bereits den Wert als Hexadezimalzahl dar.

Meine Version macht nichts anderes, ist nur etwas kürzer als itoa ;)
Du kannst ja auch einfach die zwei Zeilen von meiner Funktion direkt bei dir einbauen. Ich denke mal kürzer, schneller und einfacher gehts nicht.
Du brauchst dann nichtmal eine Funktion einbinden, das itoa bläht deinen Code noch etwas auf, da die Funktion komplexer ist.
 
Hallo Dirk
leider hat sich der Hersteller was ausgedacht.
Gebe ich z.B. 0x39 oder eine andere Zahl in dieser Schreibweise gibt es keine Probleme. Gebe ich aber nur 39 ein kommt die korrekte Prüfsumme zurück aber das Display bleibt schwarz (Mist).
Wennich das richtig verstanden habe, machst du damit eine Kontrolle der Eingabe


CodeBox C
const uint8_t hextable[16] =
  {
   '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
  };

Mit diesem Stück gibst du einen Wert von (Eingabe) 223 vor


CodeBox C
/* Beispiel:
 SendAsHexString(223);
 223d = 0xDF
 Sendet 'D' und 'F'  */

und sendest es an


CodeBox C
void SendAsHexString(uint8_t data)
  {
    i2c_write(hextable[(data>>4) & 0x0F]);   // high
    i2c_write(hextable[data & 0x0F]);       // low
  }

müsste also nur das ändern


CodeBox C
i2c_write(Zah1);   bcc+=Zah1;   // Rot
     i2c_write(Zah2);   bcc+=Zah2; 

Jeweils für eine Farbe.
bleibt wieder die Frage zur Eingabe 39 oder 0x39.
Vom Hersteller habe ich das bekommen. Einiges ist gleich. Komme leider nicht ganz klar damit.


CodeBox C
static const char nybble_chars[] = "0123456789ABCDEF";
void get_byte_hex( unsigned char b, char *buf)
  {
    buf[0] = nybble_chars[ ( b >> 4 ) & 0x0F ];
    buf[1] = nybble_chars[ b & 0x0F ];
  }
Macht dann als Aufruf:
Byte R,G,B;
R=10; G=20; B=40;

Byte buf[2];
i2c_write(DOL);   bcc+=DOL;   // $ Vordergrund     
get_byte_hex(R,buf);
i2c_write(buf[0]);   bcc+= buf[0];   // $ Vordergrund     
i2c_write(buf[1]);   bcc+= buf[1];   // $ Vordergrund     
get_byte_hex(G,buf);
i2c_write(buf[0]);   bcc+= buf[0];   // $ Vordergrund     
i2c_write(buf[1]);   bcc+= buf[1];   // $ Vordergrund     
get_byte_hex(B,buf);
i2c_write(buf[0]);   bcc+= buf[0];   // $ Vordergrund     
i2c_write(buf[1]);   bcc+= buf[1];   // $ Vordergrund     
i2c_write(‘,’);   bcc+=’,’;   // $ Vordergrund     


achim
 
Wennich das richtig verstanden habe, machst du damit eine Kontrolle der Eingabe
Nein, ich hole mit die Ascii Werte je Nibble (4bit) aus der Tabelle. Das entspricht ja deinem nybble_chars[] ... macht ja genau das selbe.

Bei deinem Display kann ich dir selber leider nicht helfen.

Wenn du als Parameter für eine Farbe einmal 39 und einmal 0x39 angibst, bedeutet es lediglich, dass bei der hexadezimalen Zahl der Farbanteil stärker sein wird, da ja 0x39>39.

So wie ich es verstanden habe, benötigt das Display die Werte als hexadezimale Zahl (zwei Byte Ascii). Dein oberes Beispiel sollte in diesem Fall dann so stimmen, zumindest bezüglich der Bytes für Farbwerte.
 
Hallo
der erste Teil mit der Eingabe von 0-F hat jetzt wunderbar geklappt. Habe aber noch ein anderes Problem bekommen. Muss die transparenz eingeben und diese von 0-100 begrenzen.Der Code zur übertgabe ans Display sieht so aus


CodeBox C
i2c_write(KOM);   bcc+=KOM;   // Komma
     i2c_write('1');   bcc+='1';   // Transparenz in Prozent
     i2c_write('0');   bcc+='0';   // Hintergrund
     i2c_write('0');   bcc+='0'; 

habe erst mal Zahlen zur Kontrolle eingesetzt. Die Begrenzung auf max ist auch kein Problem, einfach durch eine if Abfrage ob grösser als 100.
Bleibt aber noch das umrechnen der Zahlen. Im oberen Beispiel habe wir es ja so gemacht:


CodeBox C
static const char nybble_chars[] = "0123456789ABCDEF";
static const char nybble_charsT[] = "0123456789";

void get_byte_hex( unsigned char b, char *buf)       // wird durch RGB aufgerufen
  {
   buf[0] = nybble_chars[ ( b >> 4 ) & 0x0F ];
    buf[1] = nybble_chars[ b & 0x0F ];
  }
 
void get_byte_hex( unsigned char b, char *buf)       // wird durch RGB aufgerufen
{
   buf[0] = nybble_charsT[ ( b >> 4 ) & 0x0F ];
   buf[1] = nybble_charsT[ b & 0x0F ];
}

habe mal angefangen, zwei Werte sind klar und wie mache ich das mit dem dritten Wert?
achim
 
Hallo Achim,
zwei Werte sind klar und wie mache ich das mit dem dritten Wert?

das funktioniert so nicht. Über die Nibble geht es nur mit hexadezimalen Zahlen.

Wenn du einen Dezimalwert als einzelne Ascii Character benötigst, könntest du es so machen ...
(nicht getestet)



CodeBox C
uint8_t d;

d = 100;
// vorher ggf. begrenzen
buf[0] = ((d / 100) % 10) + '0';  // 100er
buf[1] = ((d / 10) % 10) + '0';  // 10er
buf[2] = (d % 10) + '0';  // 1er
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)