Zweistellige Zahlen

Hey Leute,

ich habe folgendes Problem:

Ich schaffe es ums verrecken nicht, eine zweistellige Zahl an mein Display zu übertragen.

So soll das Programm funktionieren:

Ich habe eine Eingabe (Keypad) und ein Display. Man soll eine zweistellige Zahl eingeben können (aber auch eine Einstellige) und dann muss man die Eingabe mit der Taste 'A' bestätigen. Wenn das Passiert ist, soll auf dem Display die Zahl erscheinen (also entweder eine Einstellige oder eine Zweistellige).

Ich habe folgenden Code:

#include <Keypad.h>
#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd (0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
//Hier wird die größe des Keypads definiert
const byte COLS = 4; //4 Spalten
const byte ROWS = 4; //4 Zeilen
//Die Ziffern und Zeichen des Keypads werden eingegeben:
char hexaKeys[ROWS][COLS] = {
  {'D', '#', '0', '*'},
  {'C', '9', '8', '7'},
  {'B', '6', '5', '4'},
  {'A', '3', '2', '1'}
};
byte colPins[COLS] = {A0, A1, A2, A3}; //Definition der Pins für die 4 Spalten
byte rowPins[ROWS] = {A4, A5, 9, 10}; //Definition der Pins für die 4 Zeilen
char Taste; //Taste ist die Variable für die jeweils gedrückte Taste.
int Anzahl;
int e;
int z;
Keypad Tastenfeld = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);
int Taste1;
int Taste2;
void setup()
{
  lcd.begin(20, 4);
  lcd.clear();
  lcd.setBacklight(HIGH);
}
void loop()
{ 
    Taste1 = Tastenfeld.getKey();
    z = Taste1;
    Taste2 = Tastenfeld.getKey();
    e = Taste2;
    Taste=Tastenfeld.getKey();
    if (Taste == 'A') {

      Anzahl = z * 10 + e;
    }
    lcd.setCursor(0, 0);
    lcd.print("Anzahl Chips:"); 
    lcd.setCursor(8, 1);
    lcd.print(Anzahl); 
    Taste='B';
    Taste2=0;
    Taste1=0;  
  }

Vielen Danke für jeden Beitrag :smiley:

3 mal getKey() direkt hintereinander kann nicht gehen. Eine Abfrage pro loop() Durchlauf und vor dem Rechnen überprüfen ob überhaupt eine Taste gedrückt wurde

Und wie in dem duplizierten Thread gesagt musst du von dem ASCII-Wert '0' substrahieren um auf eine Zahl zu kommen. Schau dir die ASCII Tabelle an

getkey() ist nicht blockierend. Das heißt, auch wenn keine Taste gedrückt wird, kommt die Funktion sofort zurück ( mit dem Wert NO_KEY ). Du musst also nach dem Aufruf erstmal prüfen, ob überhaupt eine Taste gedrückt wurde und wenn nicht, erneut aufrufen, bevor Du den Wert an z bzw. e zuweisen kannst.
Und wie schon gesagt, '0' subtrahieren.

Soll dein Sketch später auch noch was anderes machen, musst Du es aufbauen wie von Serenifly geschrieben ( einmal im loop abfragen ). Dann muss Du aber die ganze Programmstruktur anders aufbauen.

Hi

Weiter befürchte ich, daß Dein Keypad prellen kann - Du also auch eine Entprellung einbauen musst (sonst bekommst Du bei Druck auf die 1 eine 1111 oder Ähnliches).
Wenn die Tasten entprellt sind, musst Du prüfen, ob's eine Ziffer war, oder ein Steuerzeichen (hier das A) - bei Ziffer Alter_Wert=Alte_Wert*10+Neuer_Wert-0x30;
Die 0x30 ist der ASCII-Code der Null.
(bis zur 9 geht's bis 0x39, zum A sind's dann noch Mal 7 mehr, solltest Du HEX-Zahlen eingeben wollen ... zumindest bis zum D wäre hier ja möglich)

Beim A wird der Wert ans Display geschickt und Alter_Wert auf Null gesetzt (für die nächste Runde).

MfG

Das Entprellen macht schon die Keypad Library

Serenifly:
Und wie in dem duplizierten Thread gesagt musst du von dem ASCII-Wert '0' substrahieren um auf eine Zahl zu kommen. Schau dir die ASCII Tabelle an

Was meint ihr? Ich habe mich noch net mit der ASCII Tabelle befasst. Brauche ich die denn für den Sketch? Wenn ja, könnt ihr mir einen Link oder ähnliches schicken, in dem das kruz erklärt ist ? :smiley:

MicroBahner:
Soll dein Sketch später auch noch was anderes machen, musst Du es aufbauen wie von Serenifly geschrieben ( einmal im loop abfragen ). Dann muss Du aber die ganze Programmstruktur anders aufbauen.

Ja es gibt noch einen Schrittmotor der die eingegebene Zahl als Umdrehungen durchführen soll. Also so:
Eingabe: 1 2 A
Display: 12
Motor: 12 Umdrehungen, dann stopp bis zur nächsten Eingabe

Rahmschnitzel:
Was meint ihr? Ich habe mich noch net mit der ASCII Tabelle befasst.

Ein Computer kennt eigentlich keine Buchstaben und Ziffern. Er kennt letzendlich nur binäre Zahlenwerte, die in den Variablen gespeichert werden. Um 'Buchstaben' oder 'Ziffern' zu speichern, muss man jedem darzustellenden Buchstaben,Ziffer oder Sonderzeichen einen Zahlenwert zuordnen, der dann vom Computer gespeichert werden kann. So eine Zuordnung macht die ASCII-Tabelle s.a. (Wikipedia zu ASCII). Deine Keyboard-Lib gibt für jede gedrückte Taste den entsprechenden Zahlenwert des aufgedruckten Buchstabens, bzw. der Ziffer zurück. Wenn Du also '0' drückst, erhältst Du nicht den Zahlenwert 0, sondern den Zahlenwert, der gemäß der ASCII-Tabelle für die Ziffer '0' steht, also 48 oder HEX 30 . Wenn Du den Zahlenwert haben willst, musst Du das also wieder entsprechend umwandeln.

Was den Schrittmotor angeht: soll man auch wieder Zahlenwerte eingeben können, während der Motor noch dreht, oder soll das streng abwechselnd gehen?

Wikipedia: ASCII
So wie du fragst, ist dir dieser Artikel zu kompliziert, daher meine Kurzfassung:
A-Z, a-z, 0- 9, die üblichen Sonderzeichen, und ein paar nicht-druckbare Zeichen ( Wagenrücklauf, Neue Zeile, Tabulator ) die es auf ( amerikanischen ) Schreibmaschinen gab, sind international standardisiert und das Grundgerüst jedes anderen erweiterten Zeichensatzes. Deutsche Umlaute sind in dieser ASCII-Tabelle nicht enthalten! Auch das € Zeichen nicht, wohl aber $ :slight_smile:

Sie belegen die erste Hälfte eines byte
oder die positive Hälfte eines char : 0 .. 127 oder 0 .. 0x7F

Das Zeichen '0' hat da die Codierung 48 oder 0x30. Das braucht man sich aber nichtmal zu merken
(obwohl sich das auf Dauer kaum vermeiden lässt),
denn man kann in C/C++ Rechenanweisungen 48, 0x30, oder '0' gleichwertig verwenden.
In der Tabelle char hexaKeys[ROWS][COLS] ist festgelegt, welche Werte getKey() zurückliefert. Hier wird aus Gründen der Lesbarkeit die Schreibweise '1' 'A' usw. verwendet. Der Datentyp ist char, also genaugenommen eine Zahl {-128, ... , +127 }.

Die Zeichen '1' , '2' , ... folgen direkt auf '0'.
Das kann man sich leicht merken und erleichtert alles folgende:
Wenn also getKey() eine 48 zurückliefert, wurde die Taste '0' gedrückt, 49 bei einer '1'...
Die Rechnung (getKey() - '0') liefert bei '1' also die Zahl 1, bei '9' die Zahl 9.

michael_x:
Wenn also getKey() eine 48 zurückliefert, wurde die Taste '0' gedrückt, 49 bei einer '1'...
Die Rechnung (getKey() - '0') liefert bei '1' also die Zahl 1, bei '9' die Zahl 9.

Ok das hab ich verstanden, aber wie hilft mir das bei zweisteliigen zahlen weiter?

Na die erste Zahl * 10 und die nächste hinzu addieren.

Gruß Tommy

Rahmschnitzel:
Ok das hab ich verstanden, aber wie hilft mir das bei zweisteliigen zahlen weiter?

Wenn du das nicht machst kommt nie das korrekte Ergebnis. Egal wie viele Stellen du hast

Dass du getKey() richtig verwenden musst um mehrere Ziffern einzulesen wurde auch schon gesagt

Ok ich habe das mit der "-'0'" gemacht und es funktioniert auch bei '1,2,3,4,5,6,7,8,9' jedoch wenn ich '0' drücke und danach etwas anderes, kommen komische Zeichen auf dem Bildschirm.
Woran liegt das?

Wie sollen wir das erraten, ohne Deinen Sketch und ohne zu wissen, was Du gedrückt hast und was erscheint?

Gruß Tommy

Hey kurzes Update. Ich habe es geschafft, jedoch mit einem ziemlich blöden Manko:

Ich muss vor jeder neuen Eingabe '' drücken, dann die beiden Zahlen, dann '#'. Dann wird es ausgegeben und wenn ich wieder '' drücke, löscht sich der Display.

Ich würde es gerne so haben, dass man nur einmal beim Start des Arduinos '*' drücken muss, und es dann reicht, wenn man zwei Zahlen eingibt und '#' drückt.

Hier erstmal der Sketch:

#include <Keypad.h>
#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd (0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

char C1, C2; // Unter C1 bis C2 werden im Loop die zwei eingegebenen Zeichen gespeichert
int Anzahl;
int zehner , einer;

//Hier wird die größe des Keypads definiert
const byte COLS = 4; //4 Spalten
const byte ROWS = 4; //4 Zeilen
int z1 = 0, z2; // Diese Variablen werden verwendet um für die einzelnen Zahlencodes die Eingabe freizuschalten. Damit wird im Sketch verhindert, dass eine einzene Codeziffer einer falschen Position zugeordnet wird.
//Die Ziffern und Zeichen des Keypads werden eingegeben:
char hexaKeys[ROWS][COLS] = {
  {'D', '#', '0', '*'},
  {'C', '9', '8', '7'},
  {'B', '6', '5', '4'},
  {'A', '3', '2', '1'}
};

byte colPins[COLS] = {A0, A1, A2, A3}; //Definition der Pins für die 4 Spalten
byte rowPins[ROWS] = {A4, A5, 9, 10}; //Definition der Pins für die 4 Zeilen
char Taste; //Taste ist die Variable für die jeweils gedrückte Taste.
Keypad Tastenfeld = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); //Das Keypad kann absofort mit "Tastenfeld" angesprochen werden

void setup()
{
  lcd.begin(20, 4);
  lcd.clear();
  lcd.setBacklight(HIGH);
}

void loop()
{
  // lcd.setCursor(0, 0);
  // lcd.print("Drücke '*' um die ");
  // lcd.setCursor(0, 1);
  // lcd.print("Anzahl einzugeben!");
Anfang: // Dies ist eine Markierung, zu der per "goto-"Befehl gesprungen werden kann.
  Taste = Tastenfeld.getKey(); //Mit Unter der Variablen pressedKey entspricht der gedrückten Taste
  if (Taste) //Wenn eine Taste gedrückt wurde...
    //Ab hier werden die Eingaben des Tastenfeldes verarbeitet. Zunächst die "*"Taste, da diese eine Sonderfunktion für die Verriegelung besitzt und danach die #-Taste, nach deren Eingabe der zuvor eingegebene Code auf Richtigkeit geprüft wird.
  {
    if (Taste == '*') // Wenn die "*" Taste gedrückt wurde...
    {

      if ( z1 != 0 && z2 != 1) {
        lcd.clear();
      }
      z1 = 0; z2 = 1; // Zugang zur ersten Zeicheneingabe freischalten

      goto Anfang; //An dieser Stelle springt der Sketch zur Eingabe der Taste zurück, damit das Zeichen "*" nicht im folgenden Abschlitt als Codeeingabe gewertet wird.
    }

    if (Taste == '#') // Wenn die Rautetaste gedrückt wurde...
    {
      if (z1 == 1 && z2 == 1 ) //wird gepüft, ob die eingaben Codezeichen (z1 bis z2) getätigt wurden
      {
        zehner = C1 - 48;
        einer = C2 - 48;

        Anzahl = zehner * 10 + einer;
        lcd.setCursor(0, 0);
        lcd.print("Anzahl Chips: ");
        lcd.setCursor(8, 1);
        lcd.print(Anzahl);

        delay(300);
      
        Anzahl = 0;
        C1 = '0';
        C2 = '0';
        z1 = 0;
        z2 = 0;
      }
      else
      {
        lcd.setCursor(0, 0);
        lcd.print("Zwei Zahlen!");
        z1 = 0; z2 = 1;  // Der Zugang für die erste Zeicheneingabe wird wieder freigeschaltet
        goto Anfang; //An dieser Stelle springt der Sketch zur Eingabe der Taste zurück, damit das Zeichen "#" nicht im folgenden Abschlitt als Codeeingabe gewertet wird.
      }
    }
    // Ab hier werden die zwei Code-positionen unter den Variablen C1 bis C2 abgespeichert. Damit die eingegebenen Zeichen auch an der richtigen Position des Passwortes gespeichert werden, wird mit den Variablen z1 bis z2 der Zugang zu den einzelnen Positinen freigegeben oder gesperrt.
    if (z1 == 0) // Wenn das erste Zeichen noch nicht gespeichert wurde...
    {
      C1 = Taste; //Unter der Variablen "C1" wird nun die aktuell gedrückte Taste gespeichert

      z1 = 1; z2 = 0;  // Zugang zur zweiten Zeicheneingabe freischalten
      goto Anfang;
    }

    if (z2 == 0) // Wenn das zweite Zeichen noch nicht gespeichert wurde...
    {
      C2 = Taste; //Unter der Variablen "C2" wird nun die aktuell gedrückte Taste gespeichert

      z1 = 1; z2 = 1;
      goto Anfang;
    }
  }
}

Habt ihr eine schnelle Idee, wie ich das schreiben kann?

PS: Ich muss noch schreiben, dass man nur die Zahlen eingeben kann (Wenn man nach dem '', entweder 'A,B,C,D,#,' drückt, kommt was komisches raus)

Hallo,

letztlich willst Du wahrscheinlich für deine beiden Schrittmotoren 2 Werte eingeben die du mittels dem Endzeichen A oder B den beiden Variablen und damit Motoren zuordnen kannst, damit dann jeweils der angesprochene Motor seine Umdrehungen fährt.

also z.B..
Eingabe 12A damit soll der Motor1 12 Undrehungen fahren
Eingabe 15B damit soll der Motor2 15 Umdrehungen fahren

Also brauchst Du z.B 2 Variable jeweils 1 für jeden Motor, aber das ist der nächste Schritt.

ich habe vor einigen Monaten mal was mit dem Keypad rumgespielt und die Taste D als Endzeichen "enter" verwendet. Ich hab das heute mal erweitert auf die Endzeichen A & B.

Herausgekommen ist der beigefügte Sketch, er basiert auf einem Beispiel aus der LIB

Eigendlich müsste man das noch erweitern um auch negative Zahlen eingeben zu können (z.B mit der Taste "*" damit der Motor auch in die andere Richtung fahren kann. Du sollst ja aber auch noch was zu tun haben.

Eingelesen werden max 4 Zeichen also eine 4 stellige Zahl. Diese wird zunächst zu einem CString zusammen gebaut und bei Erkennung des Endzeichens in einen Integer gewandet.

Um die Sollwerte dann auf die Motoren zu geben, könnte man eine Abfrage einbauen ob sich die Werte geändert haben und dann eine Function aufrufen die die Motoren ansteuert. Aber da gibts tausend Lösungen. Ich hatte ja schon mal zu dem Thema geschrieben und dir vorgeschlagen mal einen Ablauf zu erstellen. Hier mal das was ich mir dazu gedacht hatte.

wenn Taste gedrückt
Enzeichen Abfagen wenn A
string wandeln und der variabeln 1 zuordnen
Eingabe reset
Endzeichen abfragen wenn B
string wandeln und der variablen 2 zuordnen
Eingabe reste
sonst neus zeichen an string anhängen wenn Eingabe 0-9 ist.

Heinz

/* Beispiel basierend auf Beispiel aus LIB
 * Beispiel FolienTastatur zur Eingabe von zwei
 * Integer Werten mit der Zuweisung  A  für Wert1 B für Wert2 
 * Eingabe z.B 123A wird der variablen Wert1 zugewiesen
 * Hardware UNO, Keypad 
 * Nov. 2018 erweitert Mai 2019 auf 2 Werte
 */


#include <Keypad.h>

const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
//define the cymbols on the buttons of the keypads
char hexaKeys[ROWS][COLS] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};
byte rowPins[ROWS] = {9, 8, 7, 6}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {5, 4, 3, 2}; //connect to the column pinouts of the keypad

//initialize an instance of class NewKeypad
Keypad customKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);

char zeile[10];// Eingabe Zeile 
byte i;// Index CString
int wert1, wert2;

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

void loop() {
  readKeypad();
}


void readKeypad(){
char Key = customKeypad.getKey();

  if (Key) {  // Taste gedrückt
    //Serial.print(Key,DEC);
    Serial.print(Key);
    //Serial.print(Key,DEC);
    if (Key == 65) { // "A" erkannt
      zeile[i] = char(0); // C string Endzeichen
      wert1 = atoi(zeile);
      Serial.print("\n Wert1 ");Serial.println(wert1);
      //Serial.print (strlen(zeile));
      i = 0;  // Zeiger auf Anfang string löschen
    }

    if (Key == 66) { // "B" erkannt
      zeile[i] = char(0);
      wert2 = atoi(zeile);
      Serial.print("\n Wert2 ");Serial.println(wert2);
      i = 0;
    }

    // Zeichen inten anhängen und Index erhöhen 
    else if (i < 4 && Key >= 48 && Key <= 57 ) {
      zeile[i] = Key;
      i++;
    }

  }  
}

Rentner:
Hallo,

Hey,
dein Sketch hilft mir sehr :smiley:
vielen Dank ich werde Teile daraus verwenden :wink:
Ich probiere mal weiter rum und melde mich sobald es etwas neues gibt.