Problem mit lcd.blink()

Auch für mich ist es nach mehr als 40 jahren weg von der Uni schwierig mit C wieder an zu fangen und ich hoffe, dass Ihr mir helfen könnt.

Ich konstruiere zur Zeit ein morse trainingsgerät in Hardware und Software, das problem was ich habe liegt in der Steuerung des I2C displays,

[code]
#include <Wire.h>
#include <hd44780.h>                       // main hd44780 header
#include <hd44780ioClass/hd44780_I2Cexp.h> // i2c expander i/o class header
String mycall = "";       //
String opname = "";
#define pulsehigh(pin) {digitalWrite(pin, HIGH);delay(200); digitalWrite(pin, LOW); } // Write macro
hd44780_I2Cexp lcd(0x3f, 20, 4);
String selectstrings = "abcdefghijklmnopqrstuvwxyz1234567890 ";
String val1 = "";
String menustring1 = "  Operator Name?   ";
String menustring2 = " Operator Callsign?";
String spaces =      "                   ";
int maxsize = 37;
int negative = -37;
unsigned int selectIndex = 0;
int col = 0;
int row = 0;
#define leftpin 0
#define selectpin 1
#define rightpin 2
#define menupin 3
#define sound 14
#define ledpin 13
#define led1 A1
#define led2 A2
#define led3 A3
#define led4 A4
int ledstate = 1;
int count = 0;
int oldcount = 0;
int menuselect = 1;
static int state1 = 1;      // 1 because of pull-ups on encoder switch
static int oldstate1 = 1;
static int state2 = 1;
static int oldstate2 = 1;
static int state3 = 1;
static int oldstate3 = 1;
static int state4 = 1;
static int oldstate4 = 1;
bool issound = 1;
bool flag = false;
void beep() {
  tone(sound, 440, 100);
}
void setdisplay() {
  if (flag == 0) {
    row = 1;
    col = 0;
    lcd.setCursor(col, row);
    for (byte i = 0; i < maxsize; i++) {
      lcd.setCursor(col, row);
      lcd.print(selectstrings.charAt(i));
      col++;
      if (col == 19) {
        row++;
        col = 0;
      }
    }
  }
  lcd.setCursor (0, 1);
  lcd.blink();
  flag = 1;
  col = 0;
  row = 0;
}
void setdefault() {
  if (opname == "") {
    opname = "Daniel ";
  }
  if (mycall == "") {
    mycall = "DF5DG ";
  }
  lcd.setCursor(0, 0);
  lcd.print(spaces);
  lcd.setCursor(0, 1);
  lcd.print(spaces);
  lcd.setCursor(0, 2);
  lcd.print(spaces);
  lcd.setCursor(0, 3);
  lcd.print(spaces);
  lcd.setCursor(0, 0);
  lcd.print(opname);
  lcd.print(mycall);
  menuselect = 4;
}

void setuser() {
  if (flag == 1) {
    lcd.cursor();
    row = 1;
    col = 0;
    //col = negative + maxsize;
    lcd.print(selectstrings.charAt(count));
    lcd.setCursor(col, row);
    lcd.setCursor (0, 3);
    lcd.print ("row: ");
    lcd.print (row);
    lcd.print ("Col: ");
    lcd.print(col);
    lcd.setCursor(col, row);
    lcd.blink();
  }
}

void setup() {
  lcd.init();
  lcd.clear();
  lcd.backlight();
  col = 0;
  row = 0;
  lcd.cursor();
  lcd.setCursor(col, row);
  lcd.blink();
  Serial.begin(9600);
  pinMode (leftpin, INPUT_PULLUP);
  pinMode (selectpin, INPUT_PULLUP);
  pinMode (rightpin, INPUT_PULLUP);
  pinMode (menupin, INPUT_PULLUP);
  pinMode (sound, OUTPUT);
  pinMode (ledpin, OUTPUT);
  pinMode (led1, OUTPUT);
  pinMode (led2, OUTPUT);
  pinMode (led3, OUTPUT);
  pinMode (led4, OUTPUT);
  digitalWrite (ledpin, HIGH);

}

void loop () {
  if (menuselect == 1) {
    setdisplay();
    col = 0;
    row = 0;
    lcd.setCursor(0, 0);
    lcd.print (menustring1);
    setuser();
  }
  if (menuselect == 2) {
    col = 0;
    row = 0;
    lcd.setCursor (0, 0);
    lcd.print(menustring2);
    setdisplay();
  }
  if (menuselect == 3) {
    setdefault();
  }
  state1 = digitalRead(leftpin);
  state2 = digitalRead(selectpin);
  state3 = digitalRead(rightpin);
  state4 = digitalRead(menupin);
  if (state1 != oldstate1) {
    if (state1 == 1) {
      tone (sound, 440, 100);
      //setuser;
      if (count > 0) {
        digitalWrite (led1, 1);
        count--;
      }
      if (count == 0) {
        count = 0;
        digitalWrite (led1, 0);
        digitalWrite (led3, 1);
      }
    }
    oldstate1 = state1;
  }
  if (state2 != oldstate2) {
    if (state2 == 1) {
      tone (sound, 440, 100);
      flag = 1;
      pulsehigh(led2);
      val1 = selectstrings.charAt(count);

      if (menuselect == 1) {
        opname = opname + val1;
        val1 = "";
      } else {
        mycall = mycall + val1;
        val1 = "";
      }
    }
    oldstate2 = state2;
  }
  if (count == 0) {
    digitalWrite (led3, 1);
  }
  if (state3 != oldstate3) {
    if (state3 == 1) {
      tone (sound, 440, 100);
      //setuser();
      if (count < maxsize) {
        count++;
        col++;
        digitalWrite (led3, 1);
        if (count > 0) {
          digitalWrite (led1, 1);
        }
      }
      if (count == maxsize) {
        count = maxsize;
        digitalWrite (led3, 0);
        digitalWrite (led1, 1);
      }
    }
    oldstate3 = state3;

  }
  if (state4 != oldstate4) {
    if (state4 == 1) {
      tone (sound, 440, 100);
      menuselect++;
      if (menuselect == 5) {
        menuselect = 1;
      }
    }
    oldstate4 = state4;
  }
}
[/code]
Meine frage: wie kann ichz den blinkende cursor auf das A hinbekommen und ihn dann mittels den tasten verschieben sodass ich den buchstaben darunter selektoeren kann ?

auf was für einem Controller läuft das?
Ich sehe sehr viele strings - das wird Dir evtl. auf die Füsse fallen.

Das ganze läuft auf einen atmega1284, 16 mhz.

Schau dir das mall an

Das habe ich schon desöfteren, habe auch das gefühl, dass ich im code etwas übersehe, denn der cursor blink funktioniert an sich, ich kann den auf ein leeres display setzen und dort alle buchstaben anzeigen lassen. Aber ich möchte die auswahl vereinfachen in dem der cursor sich über dass bereits abgebildete alphabet bewegt und so den buchstaben hervorhebt, der selektiert werden kann um damit ein benutzername und im späteren verlauf, das rufzeichen des benutzers eingeben zu können

das gibt es nicht auf den Character LCDs. Der Cursor (der blinken kann) gibt die nächste Scheibeposition an. Ein Zeichen "Blinken" lassen müsstest du manuell machen sprich Zeichen setzen/Zeichen löschen.
Oder die Zeile unterhalb opfern und einen Cursor / Pfeil nach Oben in dieser Zeile als Markierung setzen.

BTW: du hat ziemlich viele Variablen als int. Du könntest jede dieser Variablen überprüfen ob das wirklich zwei byte signed sein müssen und checken ob nicht auch ein uint8_t oder int8_t reicht.

@noiasca

Muss dich widersprechen, das hd44780 display kann den fullblock cursor durchaus auf einen beschriebenen platz setzen. 'Bei mir tut er es nur nicht und ich frage mich, warum :slight_smile: Werde in ruhe weiter daran basteln und irgendwann die lösung meines kumpels nachvollziehen können, denn der hatte es schon mal so gemacht, da er aber voriges jahr gestorben ist, kann ich ihm nicht mehr nach seinem code fragen

Und wo bitte hat @noiasca was anderes gesagt, und was bedeutet bei dir ' fullblock cursor`'?

Nur so am Rande, @noiasca hat eine Lib geschrieben für den hd44780 welsche kann ein wenig mehr als die Standard Lib's

Es gibt 2 möglichkeiten einen cursor anzeigen zu lassen, der erste ist einen strich, welcher mit lcd.cursor aktiviert werden kann, der zweite ist der fullblock cursor, welcher mit lcd.blink() aktiviert werden kannes ist nicht kompliziert, nur will es nicht funzen, das ist alles

Ich hab das auch schon mit blinkendem Cursor und schreiben an der richtigen Stelle gemacht.
Du kannst auch den _ an der richtigen Stelle blinken lassen.
Der Trick ist, einfach das Zeichen schreiben und dann den Cursor an die alte Position stellen mit .setCursor.

Allerdings sehe ich in dem Code noch so einige dicke Baustellen.
Daher meine Überlegung, ob es nicht sinnvoller wäre, das über den haufen zu werfen und einen komplett neuen Ansatz zu wählen.
I2C-Lcd-libs gibts wie Sand am Meer und Du bist ganz bestimmt nicht der Erste, der auf dem Display 4 Zeilen und 20 Spalten onTheFly angezeigt und geändert haben möchte :slight_smile:

Das merkwördige bei mir ist, dass mein system es manchmal willkürlich macht, gestern kam es beim hochladen einer aktualisierung vor, dass der blinkende cursor auf das 'R von operator name stand und friedlich vor sich hin blinkte, es geht also. Das ändern ist an sich kein problem, das werde ich wohl hinkriegen. Den cursor auf dem ersten buchstabens des alphabets blinken zu lassen, scheint schwierig. Naja, zur not hänge ich am system eine tastatur dran, auch wenn es genau das ist, was ich nicht möchte :slight_smile:
Dass in meinen code noch baustellen sind, weiß ich, die verwenduing der String klasse ist zum beispiel nicht optimal, aber einen anfang braucht alles

Nein.
Das Problem sehe ich eher darin, das Du mit dem Array voller Zeichen arbeiten willst.
Würde ich nicht machen.
Die Frage ist, was Du an Zeichen verwenden willst.
In Deinem festen String hast Du ein D drin, im array nur kleinbuchstaben und Zahlen.
Ich würde mich nicht so eng beschränken und alles nehmen, was anzeigbar ist.

Zudem hast Du Pin 0 und 1 belegt. Das wird nix. Da liegt die USB-Schnittstelle drauf.
Da ich die lib nicht kenne, müsstest Du Dich auf was neues einlassen, wenn ich Dir einen Ansatz zeigen soll.

nur mal so als Idee.

Zeichen Eingeben mit 4 Tasten:

/*******************************************************************************
   Zeicheneingabe mit 4 Tasten

   LCD with PCF8574 - 8-Bit I/O Expander with I2C Interface

   Hardware:
   LCD with PCF8574 Backpack should be wired as follows:

   LCD          PCF8574
   --------------------------
   VSS    GND   GND
   VDD    5V    Vin
   V0           -             contrast - connect a poti to GND
   RS           P0 RS
   RW           P1 RW
   E            P2 EN
   DB0          -
   DB1          -
   DB2          -
   DB3          -
   D4           P4 DB4
   D5           P5 DB5
   D6           P6 DB6
   D7           P7 DB7
   LEDA   GND   P3 Backlight circuitry (HIGH signal enables backlight using a simple NPN transistor)
   LEDK   5V

   by noiasca
   2023-05-31   Einen c-String mit Tasten eingeben
   *******************************************************************************/

#include <Wire.h>                      // needed for the I2C interface
#include <NoiascaLiquidCrystal.h>      // download library from https://werner.rothschopf.net/202009_arduino_liquid_crystal_intro.htm 
#include <NoiascaHW/lcd_PCF8574.h>     // include the proper IO interface
#include <OneButton.h>

const byte cols = 16;                  // columns/characters per row
const byte rows = 2;                   // how many rows
const byte addr = 0x3F;                // set the LCD address to 0x3F or 0x27

LiquidCrystal_PCF8574 lcd(Wire, addr, cols, rows);               // create lcd object - with support of special characters

const uint8_t leftpin = A0;            // button pins
const uint8_t rightpin = A1;
const uint8_t selectpin = A2;
const uint8_t menupin = A3;

uint8_t posInput = 0;                  // position in der Eingabe "Cursor"
uint8_t posAllowed = 0;                // position in den allowed Zeichen
char input[cols + 1] {"abc"};          // die eingegebenen Zeichen, könnte man auch leer lassen

char allowed[] = "abcdefghijklmnopqrstuvwxyz 1234567890"; // alle erlaubten Zeichen der Eingabe
const uint8_t maxAllowed = sizeof(allowed);               // wie viele verschiedene Zeichen können eingegeben werden
const uint8_t maxInput = sizeof(input) - 1;               // wie viele Zeichen dürfen maximal in den c String eingegeben werden

enum Mode {ZEICHENEINGABE, BEWEGEN, WASANDERES} mode;     // was kann unser Sketch alles

OneButton buttonLeft(leftpin, true);                      // aktive LOW Buttons
OneButton buttonRight(rightpin, true);
OneButton buttonSelect(selectpin, true);
OneButton buttonMenu(menupin, true);

byte char2pos(char needle) {  // such das übergebene Zeichen in den erlaubten Zeichen
  for (byte i = 0; i < maxAllowed; i++) {
    if (needle == allowed[i]) return i;
  }
  return 26;  // magic number for blank
}

void debug() {                 // nur ein paar debug Ausgaben einiger Variablen
  Serial.print(F(" mode=")); Serial.print(mode);
  Serial.print(F(" posAllowed=")); Serial.print(posAllowed);
  Serial.print(F(" posInput=")); Serial.print(posInput);
  Serial.print(F(" input=")); Serial.print(input); Serial.print('|');
  Serial.println();
}

void zeile(uint8_t row = 1) {  // aktuellen c-string mit Markierung ausgeben
  lcd.setCursor(0, row);
  lcd.print(input);
  lcd.setCursor(posInput, row);
  lcd.blink();
}

void doLeft() {                // minus
  switch (mode) {
    case ZEICHENEINGABE :
      if (posAllowed > 0) posAllowed--; else posAllowed = maxAllowed - 1; // um 1 zurück
      input[posInput] = allowed[posAllowed];    // abhänging von der Cursor position das blättern zum nächsten Zeichen erleichtern
      zeile();                                  // string ausgeben
      break;
    case BEWEGEN :
      if (posInput > 0) posInput--; else posInput = maxInput - 1;         // um 1 vor
      posAllowed = char2pos(input[posInput]);
      zeile();
      break;
    case WASANDERES :
      //was anderes...;
      break;
  }
  debug();
}

void doRight() {    // plus
  switch (mode) {
    case ZEICHENEINGABE :
      if (posAllowed < maxAllowed - 1) posAllowed++; else posAllowed = 0;
      input[posInput] = allowed[posAllowed];
      zeile();
      break;
    case BEWEGEN :
      if (posInput < maxInput - 1) {
        posInput++;
        if (posInput >= strlen(input)) {  // String Ende erreicht - verlängern
          input[posInput] = 'a';          // init new character with a common character
          input[posInput + 1] = 0;        // terminate c string
        }
      }
      else
        posInput = maxInput - 1;

      posAllowed = char2pos(input[posInput]);
      zeile();
      break;
    case WASANDERES :
      //was anderes...;
      break;
  }
  debug();
}

void doSelect() {
  switch (mode) {
    case ZEICHENEINGABE :
      mode = BEWEGEN;              // umschalten auf bewegen
      lcd.clear();
      lcd.print(F("bewegen"));
      zeile();
      break;
    case BEWEGEN :
      mode = ZEICHENEINGABE;       // umschalten auf zeichen eingeben
      lcd.clear();
      lcd.print(F("eingeben"));
      zeile();
      break;
    case WASANDERES :
      //was anderes...;
      break;
  }
  debug();
}

void doMenu() {
  switch (mode) {
    case ZEICHENEINGABE :
    case BEWEGEN :
      mode = WASANDERES;                // c string akzeptieren und mit was anderem fortsetzen
      lcd.clear();
      lcd.noBlink();
      lcd.print(F("was anderes tun"));
      break;
    case WASANDERES :
      mode = ZEICHENEINGABE;            // c string eingeben
      lcd.clear();
      lcd.print(F("eingeben"));
      zeile();
      break;
  }
}

void setup() {
  Serial.begin(115200);
  Wire.begin();                        // start I2C library
  lcd.init();                          // initialize the LCD (.init() is according to the LCD API 1.0, .begin() will also work)
  lcd.backlight();                     // turn on backlight
  lcd.setCursor(1, 0);
  lcd.print(F("input c-string"));
  lcd.setCursor(0, 1);

  buttonLeft.attachClick(doLeft);
  buttonRight.attachClick(doRight);
  buttonSelect.attachClick(doSelect);
  buttonMenu.attachClick(doMenu);
  mode = ZEICHENEINGABE;
  delay(750);                // dirty delay nur damit man den splash screen sieht
  doSelect();                // damit am anfang was da steht
}

void loop() {
  buttonLeft.tick();
  buttonRight.tick();
  buttonSelect.tick();
  buttonMenu.tick();
  switch (mode) {
    case ZEICHENEINGABE :
    case BEWEGEN :
      // background tasks in diesen Phasen
      break;
    case WASANDERES :
      // was anderes tun
      break;
  }
}
  • links ist "minus", rechts ist "plus"
  • der Select schaltet um zwischen Zeicheneingabe oder Bewegen
  • sollte auch mit anderen LCD Lib's gehen

Zu Beachten:

  • möglicherweise gibts ein paar off by one Fehler
  • man sollte noch erweitern/besser absichern bei den Sprüngen
  • vieleicht kann man die Bedienung in einigen Edge Cases noch verbessern, z.B. wenn man von der "Eingabe" auf "bewegen schaltet, auf die nächste Position vorrücken...
  • und ein "löschen" eines Zeichens wäre auch noch nett, wenigestens das letzte Zeichen. Als Idee vieleicht ein Blank am Ende als Löschzeichen interpretieren?

aber so im Großen und Ganzen geht es meines Erachtens.

Bei einem 328P würde ich dir recht geben, beim 1284 ist das nicht der fall, da ligen rx und TX auf anderen pins, pin 0 ist pB0, der clko/clki pin Aber mit den array hast du natürlich recht, bedenke aber, dass der code nichts endgültiges ist, sondern erst der anfang eines projektes darstellt UNd ich bedanke mich für deinen code, das probier ich am WE aus Sieht wsentlich logischer aus als mein geschriebsel.
habe den code ausprobiert und funzt prima, musste ein paar anpassungen vornehmen aber das geht so wie ich es gerne hätte, vielen Dank nochmal dafür

Gut, das es jetzt bekannt ist.

Das habe ich am anfang in einem anderen post bereits geschrieben gehabt :slight_smile:

Hm... Du weisst das.
Du hast 366 Beiträge insgesamt gelesen.
Ich glaube soviel lese ich in 2 Tagen.
Manchmal auch an einem.
Und ich benutzte auch mehrere Controller.
Auch für ein und die selbe Aufgabe.

:thinking:

[edit]
Es sind nur 77.500 gelesene in 1100 Tagen. Wobei mehrfach gelesene nicht mitgezählt werden.
[/edit]

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.