Tastaturbefehle über Tasten und Drehgeber und LED

Das ist genau das Problem, das ich schonmal angesprochen hatte. Du lötest und schaffst dadurch Fakten "ich möchte das aber ungerne ändern!", ohne zu wissen, ob zu der von Dir gelöteten Hardware auch eine Software möglich ist.

Diejenigen, die sich wegen dieser Situation die Haare raufen oder, bei Fehlen derselben, die Hände über dem Kopf zusammenschlagen, neigen dann dazu, Dich auf einen sichereren Pfad zu lotsen. Mit zwei PCF könnte es funktionieren, mit drei recht sicher.

Mit meinem Aufbau, also Teensy mit zwei PCF8575 und zwei Drehgebern, zusätzlich durch Nutzung einer Bibliothek, funktioniert es bei mir mit zwei Portexpandern.

Was ein Leonardo mit dem Programm macht, mußt Du selbst herausfinden.

Dann mußt Du entscheiden, ob es bei Dir mit zwei Portexpandern funktioniert, oder ob Du doch drei benötigst.

Bitte teste das Programm in #114 mit zwei PCF8575 und ziehe Schlüsse daraus :blush:

Ah,
Macht bestimmt den Eindruck, aber das hatte ich diesmal nicht so vor.

Ich hab bis jetzt das gelötet, was Fakt oder getestet ist.
Fakt wie die Expander angeschossen werden, aber noch nicht an die Push Pins , mit Ausnahme der Matrix, weil es nun nicht anders geht, bei einer 8x8 Matrix.
Alle 8Drehgeber sind dran, aber die Pushbutton Leitung hängt noch frei rum.
Mit Headern und dem Gegenstück hab ich mir Buchsen /Steck Möglichkeiten geschaffen .

Es fehlen an den Expandern noch VDD, GND, SCL, SDA und Header

An LEDs hab ich jeweils 2lange Leitungen, damit ich da auch flexibel bin.

An die Pushbuttons werde ich eine PINLeiste für die Header, die ich an den Expander angebracht habe, löten, ebenso die Minus Seite der LEDs, das ist dann ggf. Schnell abgezogen.
Und ggf. Der Dritte dann ins Spiel gebracht.

EDIT" Den 3ten lass ich also erstmal weg "
Nach Klärung mit Agmue doch mit 3
Und ALLE LEDs auf den dritten Expander
PIN 13 wird also frei am Leonardo

und teste wenn das soweit gelötet ist das ich das unklare mit Steckfeld experimentieren kann... So der Plan... hätte ich auch mal sagen können.

LG Rebecca

1 Like
Programm mit zwei PCF8575 und LED_CLR an P16
// getestet mit Teensy 3.2
//#define DEBUGGING                      // Einkommentieren für die Serielle Ausgabe

#ifdef DEBUGGING
#define DEBUG_B(...) Serial.begin(__VA_ARGS__)
#define DEBUG_P(...) Serial.print(__VA_ARGS__)
#define DEBUG_L(...) Serial.println(__VA_ARGS__)
#else
#define DEBUG_B(...)
#define DEBUG_P(...)
#define DEBUG_L(...)
#endif

#include <Wire.h>
#include <Keyboard.h>                    // available when you chose Arduino Leonardo or Pro Micro or Teensy
#include <I2CKeyPad8x8.h>                // https://github.com/RobTillaart/I2CKeyPad8x8
I2CKeyPad8x8 keyPad(0x20);               // I²C-Adresse für PCF8575 mit Tastenmatrix
uint32_t vorhin;
enum prioritaet {FREI, DREH, MATRIX};
byte prio = FREI;                        // entweder Drehgeber oder Tastenmatrix darf einen Tastendruck erzeugen
byte aktKeyIndex = 255, altKeyIndex = 255;

#define NOT_SEQUENTIAL_PINOUT            // P00 bis P07, P10 bis P17, nicht benutzt, dafür buttonLed benutzt
enum buttonLed {PB_A, PB_B, PB_C, PB_D, PB_E, PB_F, PB_X, PB_Y, LED_FAN, LED_LOCATE, LED_HIGHLIGHT, LED_ODDEVEN, LED_SINGLE, LED_SHIFT, LED_CLR};
#include <PCF8575.h>                     // https://github.com/xreef/PCF8575_library
PCF8575 pcf8575(0x21);                   // I²C-Adresse für PCF8575 mit Drehencoder-PushButton und LEDs
const bool pcfLEDein = LOW;              // invertierte Logik, LEDs werden nach GND geschaltet zum Leuchten
const bool pcfLEDaus = !pcfLEDein;
const char NOKEY = ' ';                  // keine gedrückte Taste
#include <NoiascaEncoder.h>              // TwoKnobs Example; download library from http://werner.rothschopf.net/microcontroller/202202_noiasca_encoder_en.htm

//const byte pinINT = 12;                  // INT von PCF8575 Matrix                      << agmue anpassen!

#include "mq_one.h"

struct Dreh : public Encoder
{
  const byte pinPUSH;
  const char keyL;
  const char keyR;
  const char nachricht;
  char altKey;

  Dreh (const byte pinA, const byte pinB, const byte pinPUSH, const char keyL, const char keyR, const char nachricht)
    : Encoder(pinA, pinB), pinPUSH(pinPUSH), keyL(keyL), keyR(keyR), nachricht(nachricht), altKey(NOKEY)
  {}
  void init()
  {
    begin();
  }

  void tastenDruck(const char key, const char * txt)
  {
    prio = DREH;
    if (altKey == NOKEY) {
      Keyboard.press(KEY_LEFT_SHIFT);
      Keyboard.press(key);
      if (pinPUSH != PB_A) pcf8575.digitalWrite(LED_CLR, pcfLEDein);  // Erinnerungs-LED einschalten, nicht bei Rotary A
      DEBUG_P(nachricht); DEBUG_P(txt); DEBUG_P("\tkey: "); DEBUG_P(key);
      if ( !pcf8575.digitalRead(pinPUSH) ) {
        altKey = key;
        DEBUG_P(F("\tTaster gedrückt"));
      } else {
        Keyboard.release(KEY_LEFT_SHIFT);
        Keyboard.release(key);
        prio = FREI;
        DEBUG_P("\trelease key: "); DEBUG_P(key);
      }
      DEBUG_L();
    }
  }

  void run()
  {
    //uint16_t bitMuster = 0;
    switch (getDirection()) // the current direction: 1 (clockwise) or -1 (counter clockwise)
    {
      case 1:
        tastenDruck(keyR, " rechtsrum");
        break;
      case -1:
        tastenDruck(keyL, " linksrum");
        break;
      default:
        if ( (altKey != NOKEY) && pcf8575.digitalRead(pinPUSH) ) {
          Keyboard.release(KEY_LEFT_SHIFT);
          Keyboard.release(altKey);
          DEBUG_P("\taltKey: "); DEBUG_P(altKey); DEBUG_L(F("\tTaster losgelassen"));
          altKey = NOKEY;
          prio = FREI;
        }
        break;
    }
  }
};

Dreh dreh[]
{
  //        pinPUSH PB_A ... PB_Y
  //        |                nachricht
  //DT  CLK |      keyL keyR |
  //|   |   |      |    |    |
  { 23, 22, PB_A, '1', '2', 'A'},  // Rotary A                                             << agmue DT und CLK anpassen!
  { 21, 20, PB_B, '3', '4', 'B'},  // Rotary B                                             << agmue DT und CLK anpassen!
};

void loop() {
  uint32_t jetzt = millis();
  if (prio != MATRIX) for (Dreh &d : dreh) d.run();
  if (prio != DREH) {
    if ( jetzt - vorhin >= 100 ) {  // Tastenabfrage nach Zeitintervall
      vorhin = jetzt;
      aktKeyIndex = keyPad.getKey();  // 0 bis 63 gültig; I2C_KEYPAD8x8_NOKEY = 64; I2C_KEYPAD8x8_FAIL = 65
      if (aktKeyIndex != altKeyIndex) {
        if (altKeyIndex < I2C_KEYPAD8x8_NOKEY) {
          if ( matrix[altKeyIndex].modSC == 'S' ) Keyboard.release(KEY_LEFT_SHIFT);
          if ( matrix[altKeyIndex].modSC == 'C' ) Keyboard.release(KEY_LEFT_CTRL);
          Keyboard.release( matrix[altKeyIndex].key );
          DEBUG_P(millis()); DEBUG_P(F("\taltKeyIndex: ")); DEBUG_P(altKeyIndex);
          DEBUG_P(F("\tTaste: ")); DEBUG_P(matrix[altKeyIndex].modSC); DEBUG_L(matrix[altKeyIndex].key);
          prio = FREI;
        }
        altKeyIndex = aktKeyIndex;
        if (aktKeyIndex < I2C_KEYPAD8x8_NOKEY) {
          if ( matrix[aktKeyIndex].modSC == 'S' ) Keyboard.press(KEY_LEFT_SHIFT);
          if ( matrix[aktKeyIndex].modSC == 'C' ) Keyboard.press(KEY_LEFT_CTRL);
          Keyboard.press( matrix[aktKeyIndex].key );
          DEBUG_P(millis()); DEBUG_P(F("\taktKeyIndex: ")); DEBUG_P(aktKeyIndex);
          DEBUG_P(F("\tTaste: ")); DEBUG_P(matrix[aktKeyIndex].modSC); DEBUG_L(matrix[aktKeyIndex].key);
          prio = MATRIX;
        }
      }
    }
  }

  static uint32_t blinkZeit = 0;
  static bool anAus = pcfLEDaus;
  if (jetzt - blinkZeit >= 1000) {
    blinkZeit = jetzt;
    pcf8575.digitalWrite(LED_FAN, anAus);
    pcf8575.digitalWrite(LED_LOCATE, !anAus);
    pcf8575.digitalWrite(LED_HIGHLIGHT, anAus);
    pcf8575.digitalWrite(LED_ODDEVEN, !anAus);
    pcf8575.digitalWrite(LED_SINGLE, anAus);
    pcf8575.digitalWrite(LED_SHIFT, !anAus);
    anAus = !anAus;
  }
}

void setup() {
  Wire.begin();
  Wire.setClock(400000);
  DEBUG_B(115200);
  delay(5000);  // zur Sicherheit, sollten die Tastendrücke spinnen
  DEBUG_L(F("\nStart"));

  if ( !keyPad.begin() ) DEBUG_L(F("\nERROR: cannot communicate to keypad.\nPlease reboot.\n"));

  for (byte j = PB_A; j <= PB_Y; j++) pcf8575.pinMode(j, INPUT);
  for (byte j = LED_FAN; j <= LED_CLR; j++) pcf8575.pinMode(j, OUTPUT);
  pcf8575.begin();
  //pinMode(pinINT, INPUT_PULLUP);

  for (Dreh &d : dreh) d.init();
}
mq_one.h unverändert
struct Matrix
{
  char modSC;  // Modifier 'S' für Shift, 'C' für Ctrl
  char key;
};

Matrix matrix[]
{
  //modSC, key
  //{' ', 'p'},  // Taste pur
  //{'S', 'p'},  // Taste mit Shift
  //{'C', 'p'}   // Taste mit Ctrl
  {' ', 'a'},  //  0
  {' ', 'b'},  //  1
  {' ', 'c'},  //  2
  {' ', 'd'},  //  3
  {' ', 'e'},  //  4
  {' ', 'f'},  //  5
  {' ', 'g'},  //  6
  {' ', 'h'},  //  7
  {' ', 'i'},  //  8
  {' ', 'j'},  //  9
  {' ', 'k'},  // 10
  {' ', 'l'},  // 11
  {' ', 'm'},  // 12
  {' ', 'n'},  // 13
  {' ', 'o'},  // 14
  {' ', 'p'},  // 15
  {' ', 'q'},  // 16
  {' ', 'r'},  // 17
  {' ', 's'},  // 18
  {' ', 't'},  // 19
  {' ', 'u'},  // 20
  {' ', 'v'},  // 21
  {' ', 'w'},  // 22
  {' ', 'x'},  // 23
  {' ', 'y'},  // 24
  {' ', 'z'},  // 25
  {' ', '0'},  // 26
  {' ', '1'},  // 27
  {' ', '2'},  // 28
  {' ', '3'},  // 29
  {' ', '4'},  // 30
  {' ', '5'},  // 31
  {' ', '6'},  // 32
  {' ', '7'},  // 33
  {' ', '8'},  // 34
  {' ', '9'},  // 35
  {' ', 'A'},  // 36
  {' ', 'B'},  // 37
  {' ', 'C'},  // 38
  {' ', 'D'},  // 39
  {' ', 'E'},  // 40
  {' ', 'F'},  // 41
  {' ', 'G'},  // 42
  {' ', 'H'},  // 43
  {' ', 'I'},  // 44
  {' ', 'J'},  // 45
  {' ', 'K'},  // 46
  {' ', 'L'},  // 47
  {' ', 'M'},  // 48
  {' ', 'N'},  // 49
  {' ', 'O'},  // 50
  {' ', 'P'},  // 51
  {' ', 'Q'},  // 52
  {' ', 'R'},  // 53
  {' ', 'S'},  // 54
  {' ', 'T'},  // 55
  {' ', 'U'},  // 56
  {' ', 'V'},  // 57
  {' ', 'W'},  // 58
  {' ', 'X'},  // 59
  {' ', 'Y'},  // 60
  {'S', '1'},  // 61
  {'S', '3'},  // 62
  {'S', '4'},  // 63
};

Bin gespannt, ob es funktioniert :slightly_smiling_face:

EDIT: P06
Bibliothekslink ergänzt

1 Like

Du meinst glaube ich PIN 16

Zur Erklärung für die Mitlesenden:
Agmue möchte Wissen ob es mit 2 Klappt, dafür mach ich einen Versuchsaufbau.
Das Teil wird am Ende aber dann 3 XPander bekommen.

2 Likes

Meine ich, ja!

1 Like

da würde sich ein Konstruktor auszahlen der das Blank defaultiert ... (wenns das braucht)

wenn du unbedingt bei der Reihenfolge bleiben willst, dann halt mit zwei Konstruktoren (test.h)

constructor test - Wokwi ESP32, STM32, Arduino Simulator

sonnst würde ich eher die Reihenfolge ändern (test2.h), zuerst den key übergeben und optional den modifier mit Defaultwert, dann brauchst nur einen Konstruktor.

1 Like

Das ist Gut so, so hast Du ja noch reichlich Entfalltungsmöglichkeiten so können wir mit vielen neuen Ideen @agmue herrausfordern :joy: :joy: :joy: :innocent:

1 Like

Gute Idee, schon wieder was gelernt :grinning:

Auch eine gute Idee, nochwas gelernt :grinning:

Aber Rebecca schreibt:

Zu den Tasten allgemein:
Für grob ein Drittel ist pure Taste
Das 2te Drittel mit Shift
Das dritte Drittel mit Strg

Die derzeitige Struktur ist nur ein Platzhalter, um die "chaotisch" verlöteten Taster zu identifizieren und dann mit Ctrl und Shift oder nix zu füllen. Kannst Du nicht wissen, das Thema ist einfach zu lang :wink:

Vermutlich wird sich die Struktur nur inhaltlich ändern, aber Deine Vorschläge behalte ich im Hinterkopf und sei es für das nächste Thema!

1 Like

:wink:

Als ich das Design für die BUSQUEEN fertig hatte, hab ich diverse Angebote von Blechlaserschneide Firmen angesehen.
Da wo ich es dann hab machen lassen, gab es einen MINDESTAUFTRAGSWERT.
Das bedeutete das mich das EINE Blech soviel gekostet hätte, wie DREI Verschiedene zusammen.
Also setzte ich mich ran und hab zu der BUSQUEEN auch noch das MQ ONE und den BUSKING designt.

Hier mal alle Bleche vor der Oberflächenbehandlung (Chromatieren)
Das hatte natürlich den Vorteil, daß alle 3 Bleche jetzt beim Chromatieren Exakt die gleiche Farbe bekommen haben. Das ist normalerweise mit jeder Charge immer etwas unterschiedlich.

Also,
Ein nächstes Projekt wird es geben
:wink:

LG Rebecca

Man könnte es Leichtsinn nennen, aber von so viel Optimismus möchte ich mich mitreißen lassen!

Es gibt Wasservögel, wohl etwas größer als Enten, die sich von gefährlichen Strudeln im Meerwasser in die Tiefe zu den leckeren Muscheln reißen lassen, um dann von Aufwärtsströmungen nach oben getragen zu werden. Bei ca. 100 Muscheln am Tag ist so ein Strömungsfahrstuhl vermutlich das damit verbundende Risiko wert.

1 Like

Wer nicht wagt, kann nur verlieren.
So meine Variante des Spruchs.

Am Anfang hatte ich mich an dem was es so gibt orientiert.
Aber mit jedem
"das könnte doch so... oder so..."
hab ich mich immer weiter von dem üblichen entfernt.
Es ist so geil, sich nicht mit dem was andere möchten... oder wie es andere machen, auseinander setzen zu müssen.
Meine Vorgaben waren:
was ist für mich ein MUSS!
Und was wäre Nett.
Wie bedien ich das,
und wie komm ich daran,
wie leicht finde den richtigen Regler/Taster ohne auf eine Beschriftung immer gucken zu müssen ...

Das ist so coooool, einfach etwas sooo äusserst unübliches zu entwickeln, das man dabei auf niemanden anderen Achten muss, sondern einfach macht wie es mir gefällt. Es stecken sehr viele Überlegungen und Taktiken darin, die bei der BUSQUEEN alle schon wunderbar funktionieren ...
Und dann soll das dabei auch noch schön aussehen!

Ein Traum der sich immer weiter entwickelt und Realität dank eurer Hilfe wird.

Nochmals mein GROSSES DANKESCHÖN an alle die hier mitmachen.

:blue_heart:
Rebecca

Guten Morgen

Sooo, gelötet ist, soweit ich jedenfalls weiß was zu tun ist, fertig.
Heute nochmal die Sicherheitsüberprüfung mit der Lupe nach Lötbrücken, Zinnkrümelbrücken und kalten Lötstellen suchen .

INT noch frei lassen war richtig?

LG Rebecca

Ja, von mir derzeit nicht verwendet.

1 Like

moin,
heute früher Feierabend, das passt ja gut...

jetzt hab ich noch ein Problem mit der mq_one.h

ich hab es in die zwischen Ablage Kopiert, doch wie gehts weiter?
im Texteditor mit auf schreibweise geachteten Namen gespeichert.
nö will nicht
das in Zip gepackt
in die library Laden wie die anderen
nö will nicht

Error: 13 INTERNAL: Installation der Bibliothek fehlgeschlagen: moving extracted archive to destination dir: reading directory C:\Users\Win11 Pro\AppData\Local\Temp\488764278\mq_one.h content: %!!(MISSING)w(*fs.PathError=&{readdir C:\Users\Win11 Pro\AppData\Local\Temp\488764278\mq_one.h 3})

was mach ich falsch?

Ich schreib Dir mal wie ich das gemacht habe hier.
Ich habe IDE 2..... dort habe ich einfach eine neue Registerkarte erstellt und diese als mq_one.h benannt.
Dann in die Daten dort hineinkopert. Copy Paste...
Fertich is.

1 Like

Sieht dann so aus:

image

Datei mq_one.h ins selbe Verzeichnis wie die ino-Datei kopieren und dann die IDE starten, geht auch.

1 Like

Nach laaaanger Suche hab ich dann auch herausgefunden wie man ein Tab dazu bekommt.
Ja so geht es.

Also:
Tasten Matrix Funktioniert

7Drehgeber drehen funzen auch ( bis auf "E" ), aber der Push leider bei keinem.
Mal die Leitung von "E" überprüfen.

LED leuchtet keine.

Mehr Tests nach der BandProbe.
Muss jetzt los.

LRebecca

Guten Morgen

Fieser Fehler bei Regler E
Das Kaufteil selbst hatte eine Lötbrücke.


Nun geht auch das.

LED und PUSH leider noch nicht.
Mit dem Scanner im SingleScan hab ich folgende Treffer, das kommt mir bekannt vor, ich glaub, das passt so :slightly_smiling_face:

295461	32	0x20		V	V	V	V	V	V	V	V
295462	33	0x21		V	V	V	V	V	V	V	V
295464	34	0x22		V	V	V	V	V	V	V	V

Beim befüllen der mq_one.h hab ich noch ein Problem:
Wie kann ich dort folgendes einbinden?:
ENTER
BACKSPACE
CURSOR (Alle Richtungen)
SHIFT
STRG
Bild AUF
BILD AB

LG Rebecca

Schau bitte mal in \libraries\Keyboard\src\Keyboard.h mit den vielen Definitionen.

KEY_RETURN dürfte ENTER entsprechen. Meine Erfahrungen sind eher, wie Du weißt, gegen Null.

{' ', KEY_RETURN},

1 Like

Dankeschön

hier jetzt mal die aktualisierte Tabelle mit 3 PCF

000 001 010
LEONARDO Funktion PCF EXPANDER 0 Funktion PCF EXPANDER 1 Funktion PCF EXPANDER 2 Funktion
IOREF GND GND GND
RESET VDD VDD VDD
3.3V P00 1 Matrix A Braun P00 1 Rotary Push A Braun P00 LED 1 CLR braun
5V P01 2 Matrix A Orange P01 2 Rotary Push B Orange P01 LED 2 FAN Orange
GND P02 3 Matrix A Gelb P02 3 Rotary Push C Gelb P02 LED 3 LOCATE Gelb
GND P03 4 Matrix A Grün P03 4 Rotary Push D Grün P03 LED 4 HIGHLIGHT Grün
Vin P04 5 Matrix A Blau P04 5 Rotary Push E Blau P04 LED 5 ODD/EVEN Blau
A0 Rotary A DT Lila P05 6 Matrix A Lila P05 6 Rotary Push F Lila P05 LED 6 SINGLE Lila
A1 Rotary A CLK blau P06 7 Matrix A Grau P06 7 Rotary Push X Grau P06 LED 7 Shift Grau
A2 Rotary B DT Lila P07 8 Matrix A Weiß P07 8 Rotary Push Y Weiß P07
A3 Rotary B CLK blau
A4 Rotary C DT Lila P10 9 Matrix B Braun P10 P10
A5 Rotary C CLK blau P11 10 Matrix B Orange P11 P11
P12 11 Matrix B Gelb P12 P12
SCL >PCF gelb P13 12 Matrix B Grün P13 P13
SDA >PCF grün P14 13 Matrix B Blau P14 P14
AREF P15 14 Matrix B Lila P15 P15
GND P16 15 Matrix B Grau P16 P16
~13 P17 16 Matrix B Weiß P17 P17
12 >PCF INT VDD VDD VDD
~11 Rotary Y CLK blau GND GND GND
~10 Rotary Y DT Lila
~9 Rotary X CLK blau
8 Rotary X DT Lila INT <LEO INT INT <LEO INT INT <LEO INT
7 Rotary F CLK blau SCL <LEO SCL gelb SCL <LEO SCL gelb SCL <LEO SCL
~6 Rotary F DT Lila SDA <LEO SDA grün SDA <LEO SDA grün SDA <LEO SDA
~5 Rotary E CLK blau VCC VCC VCC
4 Rotary E DT Lila GND GND GND
~3 SCL
2 SDA
TX1>1 Rotary D CLK blau
RX1<0 Rotary D DT Lila

LG Rebecca