ASCII in Dezimalzahlen in Arduino umwandeln

Hallo Arduino Forum,

ich bin ein absoluter Arduino Anfänger,
für ein IT Projekt muss ich eine 4 stellige 7 Sequement Anzeige ans laufen bringen.
Die Zahlen von 0000-9999 müssen angezeigt werden.
Mein Problem ist das der SerialMonitor die meine Eingaben in ASCII Zeichen ausgibt.
Wie kann ich die Zahlen auf dem Display in Deziamalzahlen umwandeln? Das ist für die meisten wahrscheinlich ein Kinderspiel :slight_smile:

Ich habe etwas davon gelesen das bei jeder Zahl -48 funktionieren soll. Habe ich wohl aber nicht so ganz verstanden. Auch mit Atoi habe ich es noch nicht so verstanden. Ist Atoi eine Bibliothek ? Dann dürfte ich die für das Projekt nicht nutzen.

Das ist mein Code zu dem Programm.

int pinA=6;
int pinB=8;
int pinC=12;
int pinD=10;
int pinE=9;
int pinF=7;
int pinG=13;
int pinDP=11;
int D1=2;
int D2=3;
int D3=4;
int D4=5;
int Eingabe;
int S1;
int S2;
int S3;
int S4;

void ziffer1();
void ziffer2();
void ziffer3();
void ziffer4();
void ziffer5();
void ziffer6();
void ziffer7();
void ziffer8();
void ziffer9();
void ziffer0();

void alleaus()
{
digitalWrite(pinA,LOW);
digitalWrite(pinB,LOW);
digitalWrite(pinC,LOW);
digitalWrite(pinD,LOW);
digitalWrite(pinE,LOW);
digitalWrite(pinF,LOW);
digitalWrite(pinG,LOW);
digitalWrite(pinDP,LOW);
}
void ziffer1(){
digitalWrite(pinA,LOW);
digitalWrite(pinB,HIGH);
digitalWrite(pinC,HIGH);
digitalWrite(pinD,LOW);
digitalWrite(pinE,LOW);
digitalWrite(pinF,LOW);
digitalWrite(pinG,LOW);
digitalWrite(pinDP,LOW);
}

void ziffer2(){

digitalWrite(pinA,HIGH);
digitalWrite(pinB,HIGH);
digitalWrite(pinC,LOW);
digitalWrite(pinD,HIGH);
digitalWrite(pinE,HIGH);
digitalWrite(pinF,LOW);
digitalWrite(pinG,HIGH);
digitalWrite(pinDP,LOW);}

void ziffer3(){
digitalWrite(pinA,HIGH);
digitalWrite(pinB,HIGH);
digitalWrite(pinC,HIGH);
digitalWrite(pinD,HIGH);
digitalWrite(pinE,LOW);
digitalWrite(pinF,LOW);
digitalWrite(pinG,HIGH);
digitalWrite(pinDP,LOW);
}

void ziffer4(){
digitalWrite(pinA,LOW);
digitalWrite(pinB,HIGH);
digitalWrite(pinC,HIGH);
digitalWrite(pinD,LOW);
digitalWrite(pinE,LOW);
digitalWrite(pinF,HIGH);
digitalWrite(pinG,HIGH);
digitalWrite(pinDP,LOW);
}

void ziffer5(){
digitalWrite(pinA,HIGH);
digitalWrite(pinB,LOW);
digitalWrite(pinC,HIGH);
digitalWrite(pinD,HIGH);
digitalWrite(pinE,LOW);
digitalWrite(pinF,HIGH);
digitalWrite(pinG,HIGH);
digitalWrite(pinDP,LOW);

}

void ziffer6(){
digitalWrite(pinA,HIGH);
digitalWrite(pinB,LOW);
digitalWrite(pinC,HIGH);
digitalWrite(pinD,HIGH);
digitalWrite(pinE,HIGH);
digitalWrite(pinF,HIGH);
digitalWrite(pinG,HIGH);
digitalWrite(pinDP,HIGH);
}

void ziffer7(){

digitalWrite(pinA,HIGH);
digitalWrite(pinB,HIGH);
digitalWrite(pinC,HIGH);
digitalWrite(pinD,LOW);
digitalWrite(pinE,LOW);
digitalWrite(pinF,LOW);
digitalWrite(pinG,LOW);
digitalWrite(pinDP,LOW);

}

void ziffer8(){

digitalWrite(pinA,HIGH);
digitalWrite(pinB,HIGH);
digitalWrite(pinC,HIGH);
digitalWrite(pinD,HIGH);
digitalWrite(pinE,HIGH);
digitalWrite(pinF,HIGH);
digitalWrite(pinG,HIGH);
digitalWrite(pinDP,LOW);
}

void ziffer9(){
digitalWrite(pinA,HIGH);
digitalWrite(pinB,HIGH);
digitalWrite(pinC,HIGH);
digitalWrite(pinD,HIGH);
digitalWrite(pinE,LOW);
digitalWrite(pinF,HIGH);
digitalWrite(pinG,HIGH);
digitalWrite(pinDP,LOW);
}

void ziffer0(){

digitalWrite(pinA,HIGH);
digitalWrite(pinB,HIGH);
digitalWrite(pinC,HIGH);
digitalWrite(pinD,HIGH);
digitalWrite(pinE,HIGH);
digitalWrite(pinF,HIGH);
digitalWrite(pinG,LOW);
digitalWrite(pinDP,LOW);
}

void zifferntrennung(int Eingabe)
{
S1=Eingabe%10;
Eingabe-=S1;
S2=Eingabe%100/10;
Eingabe-=10S2;
S3=Eingabe%1000/100;
Eingabe-=100
S3;
S4=Eingabe%10000/1000;
}

void setup() {

Serial.begin(9600);

pinMode(pinA,OUTPUT);
pinMode(pinB,OUTPUT);
pinMode(pinC,OUTPUT);
pinMode(pinD,OUTPUT);
pinMode(pinE,OUTPUT);
pinMode(pinF,OUTPUT);
pinMode(pinG,OUTPUT);
pinMode(pinDP,OUTPUT);
pinMode(D1,OUTPUT);
pinMode(D2,OUTPUT);
pinMode(D3,OUTPUT);
pinMode(D4,OUTPUT);

}
void a_zahl (byte z){
switch (z){
case 1: ziffer1(); break;
case 2: ziffer2(); break;
case 3: ziffer3(); break;
case 4: ziffer4(); break;
case 5: ziffer5(); break;
case 6: ziffer6(); break;
case 7: ziffer7(); break;
case 8: ziffer8(); break;
case 9: ziffer9(); break;
case 0: ziffer0(); break;
}
}
void loop()
{ if(Serial.available())
Eingabe =Serial.read();
zifferntrennung(Eingabe);

alleaus();
a_zahl(S1);

digitalWrite(D1,HIGH);
digitalWrite(D2,HIGH);
digitalWrite(D3,HIGH);
digitalWrite(D4,LOW);

delay(2);

alleaus();
a_zahl(S2);

digitalWrite(D1,HIGH);
digitalWrite(D2,HIGH);
digitalWrite(D3,LOW);
digitalWrite(D4,HIGH);

delay(2);
alleaus();
a_zahl(S3);

digitalWrite(D1,HIGH);
digitalWrite(D2,LOW);
digitalWrite(D3,HIGH);
digitalWrite(D4,HIGH);

delay(2);
alleaus();
a_zahl(S4);

digitalWrite(D1,LOW);
digitalWrite(D2,HIGH);
digitalWrite(D3,HIGH);
digitalWrite(D4,HIGH);

delay(2);
}

Es wäre toll wenn mir jemand helfen kann. Stehe doch etwas unter Zeitdruck mit dem Projekt.

Vielen Dank.

Denis

DenisDe:
Ich habe etwas davon gelesen das bei jeder Zahl -48 funktionieren soll.

Das geht für eine Ziffer. Nicht für eine Zahl! Schau dir die ASCII Tabelle an um das verstehen. '0' ist einfach 48. '1' ist 49 etc. Also subtrahiert man 48

Auch mit Atoi habe ich es noch nicht so verstanden. Ist Atoi eine Bibliothek ? Dann dürfte ich die für das Projekt nicht nutzen.

atoi() ist eine Standard C Funktion in der stdlib.h Bibliothek:
http://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html

Das ist aber für Null-terminierte C Strings (nicht für einzelne Zeichen) und geht mit deiner primitiven Einlese-Funktion nicht

Das Einlesen kann so nicht funktionieren. Division und Modulo ist theoretisch schon korrekt um eine Zahl in Ziffern zu splitten, aber dafür musst du auch erst mal eine ganze Zahl haben. Mit Serial.read() liest du nur ein Zeichen an.

Entweder du liest auch wirklich einen ganzen String ein (das macht man normal mit einem LF oder CR als Endzeichen), konvertierst diesen in einen Integer und splittest den wieder. Oder einfach, du liest immer nur ein Zeichen ein und dann hast du schon eine einzelne Ziffer (nach der Subtraktion)!
Aber auch hier bietet es sich an abfragen ob du ein CR oder LF hast. Dann weißt du wann du fertig bist. Den Serial Monitor kann man so einstellen dass das automatisch am Ende gesendet wird.

Serenifly:
Das geht für eine Ziffer. Nicht für eine Zahl! Schau dir die ASCII Tabelle an um das verstehen. '0' ist einfach 48. '1' ist 49 etc. Also subtrahiert man 48
atoi() ist eine Standard C Funktion in der stdlib.h Bibliothek:
avr-libc: <stdlib.h>: General utilities

Das ist aber für Null-terminierte C Strings (nicht für einzelne Zeichen) und geht mit deiner primitiven Einlese-Funktion nicht

Das Einlesen kann so nicht funktionieren. Division und Modulo ist theoretisch schon korrekt um eine Zahl in Ziffern zu splitten, aber dafür musst du auch erst mal eine ganze Zahl haben. Mit Serial.read() liest du nur ein Zeichen an.

Entweder du liest auch wirklich einen ganzen String ein (das macht man normal mit einem LF oder CR als Endzeichen), konvertierst diesen in einen Integer und splittest den wieder. Oder einfach, du liest immer nur ein Zeichen ein und dann hast du schon eine einzelne Ziffer (nach der Subtraktion)!
Aber auch hier bietet es sich an abfragen ob du ein CR oder LF hast. Dann weißt du wann du fertig bist. Den Serial Monitor kann man so einstellen dass das automatisch am Ende gesendet wird.

Erstmal vielen vielen Dank für die schneller Antwort.
Ich denke ich bin einen Schritt weiter.
Die Zahlen werden jetzt in Dezimalzahlen umgewandelt.
Ich kann jetzt Zahlen eingeben, diese werden mal korrekt und mal falsch angezeigt.
Kann es sein das ich das Array z[] vor dem while wieder löschen muss. Das der Puffer vor jeder neuen Eingabe wieder leer ist ? Díe Stelle im Loop ist etwas erweitert. z[4] ist ein Array und als int deklariert.

void loop()
{ if(Serial.available());

while (Serial.available())
{ Eingabe=Serial.read()-48;
z[Serial.available()]=Eingabe;
Serial.println(z[Serial.available()]);
Eingabe=z[0]+10z[1]+100z[2]+1000*z[3];

}

Dann solltest du dir nun Serial.available() ansehen, und bedenken, dass Serial relativ langsam ist:

Bei deiner Geschwindigkeit 9600 kommt dauert es ca 1000µs, bis available() sich von 1 auf 2 ändert.

Besser ist ein Code, dem die Geschwindigkeit egal ist, und der eine neue Zahl am vorangegangenen Endezeichen erkennt. ( Z.B. ein '\n' NewLine, das kann auch der SerialMonitor ausgeben. )

https://www.gammon.com.au/serial

Ausserdem, wenn du eine serielle Eingabe hast, z.B. "1234" und die Anzeige einzelner Ziffern auf 4 7Seg-Leds durchführen willst, brauchst du da jemals die Zahl 1234 (= 11000 + 2100 + 3*10 +4)?
Eigentlich nicht, finde ich....
Viel interessanter finde ich die Fragen, was du bei einer Eingabe von "98765" machst, oder bei

"0", " ", "12 34",  "007", " 007" ,  "007 ", "AFFE" , ...

int ist übrigens leicht zu tippen, aber meist ein unpassender nicht immer der optimale Datentyp auf einem 8bit-Controller.

Ach ja, noch was: Man spart am falschen Ende, wenn Variable unterschiedliche Bedeutung haben:

Eingabe = Serial.read(); // eingelesenes Zeichen
Eingabe = z[0]+10z[1]+100z[2]+1000*z[3]; // was ganz anderes

Und vollkommen unnützer Müll wie z.B.   if(Serial.available());  sollte sofort raus.

Um nur eine Zahl pro Zeile einzulesen, kann man die hereinkommenden Zeichen direkt verarbeiten.

void setup() {
  Serial.begin(250000);
}
void loop() {
  static unsigned long wert;
  if (Serial.available()) {
    byte zeichen = Serial.read();
    switch (zeichen) {
      case '0' ... '9':
        wert *= 10;
        wert += zeichen - '0';
        break;
      case 10:
        Serial.print(F("Zahl fertig "));
        Serial.println(wert);
        wert = 0;
        break;
    }
  }
}

So macht man es richtig wenn man es über einen String macht. Die Methode von Whandall ist aber auch gut und für diesen Fall eigentlich besser:

const int SERIAL_BUFFER_SIZE = 5;
char serialBuffer[SERIAL_BUFFER_SIZE];

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

void loop()
{
  if (readSerial(Serial) == true)
  {
    Serial.println(atoi(serialBuffer));
  }
}

bool readSerial(Stream& stream)
{
  static byte index;

  while (stream.available())
  {
    char c = stream.read();

    if (c >= 32 && index < SERIAL_BUFFER_SIZE - 1)
    {
      serialBuffer[index++] = c;
    }
    else if (c == '\n' && index > 0)
    {
      serialBuffer[index] = '\0';
      index = 0;
      return true;
    }
  }
  return false;
}

Dabei den Serial Monitor so einstellen dass ein newline/LF am Ende gesendet wird!

Das kann man auch einfach auf die Additions/Multiplikations-Methode ändern:

unsigned int number;

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

void loop()
{
  if (readSerial(Serial) == true)
  {
    Serial.println(number);
    number = 0;
  }
}

bool readSerial(Stream& stream)
{
  while (stream.available())
  {
    char c = stream.read();

    if (c >= '0' && c <= '9')
    {
      number *= 10;
      number += c - '0';
    }
    else if (c == '\n')
    {
      return true;
    }
  }
  return false;
}

Gewöhne dir jedenfalls an available() korrekt zu verwenden (was soll das als Array Index?!) und auf die Array Grenzen abzufragen. Und ein Endzeichen zu senden damit man weiß dass man fertig ist (so muss man nur "0" statt "0000" senden)

Aber wie gesagt braucht man das hier eigentlich nicht. Sowas in der Art reicht völlig für diesen spezifischen Anwendungsfall:

byte number[4];
byte digit;

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

void loop()
{
  if(Serial.available())
  {
    char c = Serial.read();

    if (c == '\n')
    {
      for (byte i = 0; i < digit; i++)
        Serial.print(number[i]);
      Serial.println();

      digit = 0;
    }
    else if (c >= '0' && c <= '9' && digit < sizeof(number))
    {
      number[digit++] = c - '0';
    }
  }
}

So hast du gleich alle Ziffern. Man muss nicht erst aus den einzelnen Ziffern ein Zahl machen nur um sie gleich wieder zu zerlegen. Und über die digit Variable weist du wie viele Ziffern eingetippt wurden. Das kann man z.B. für führende Nullen verwenden

Auch hier am Ende ein LF senden.

Ich würde die zweite oder letzte Variante verwenden. Das mit String verwirrt hier nur. Bei anderen Anwendungen muss man es aber so machen.