Vor einem Monat bin ich auf
diesen Artikel gestoßen, in dem es um das Treten von Vim geht. Wenig später, nach meinem langen dreiminütigen Studium, stellte ich fest, dass dieses Thema nicht mehr neu und sehr beliebt ist. Ich selbst benutze Vim nur im Notfall (wenn ich in der Konsole arbeiten muss, bevorzuge ich Nano), aber Sie können dasselbe für andere Anwendungen tun.
Anfangs wollte ich einen kleinen Artikel machen, aber ich bekam ein ganzes Tutorial zum Erstellen dieses Geräts mit schrittweisem Schreiben von Code und einer Erklärung, was und wie. Um den Artikel nicht aufzublasen, gibt es unter den Spoilern verschiedene Informationen, die interessant und der Aufmerksamkeit von Neulingen in Arduino würdig erschienen. Fortgeschrittene und besonders voreilige Benutzer dürfen keine Zeit damit verschwenden. Der vollständige Quellcode wird ebenfalls am Ende des Artikels vorgestellt.
Warum brauche ich es?
Wenn Sie keinen Zweifel an der Notwendigkeit und Nützlichkeit dieses Geräts haben, können Sie diesen Punkt überspringen. Im Übrigen möchte ich zunächst auf die Voraussetzungen für die Erstellung dieses Geräts eingehen.
Programmierer und Designer haben stets versucht, eine bequeme und benutzerfreundliche Oberfläche zu erstellen, damit der Benutzer ohne unnötige Probleme mit Maus und Tastatur mit der Anwendung arbeiten kann. Warum benötigen wir also einen anderen Manipulator? Schauen wir uns ein wenig die Geschichte an, oder besser gesagt, zu Beginn des 18. Jahrhunderts, als ein Musikinstrument wie das Klavier erfunden wurde. Wie Sie wissen, bedeutet dieses Wort wörtlich „laut und leise“, aber nur wenige Menschen glauben, dass ein kluger italienischer Meister ein solches Instrument erhalten hat, indem er das damals existierende Cembalo tatsächlich „zerdrückt“ hat, wodurch es möglich war, die Lautstärke bis zu einem gewissen Grad ohne zu steuern Hände von den Schlüsseln nehmen.
Es gibt viele Beispiele. Das Auto hat Pedale, um das Lenkrad nicht zu werfen, wenn Sie Benzin nachfüllen müssen. Das Schlagzeug hat auch Pedale zum Klopfen auf die Bassdrum und die Becken. Und was können Pedale bei der Verwendung eines Computers geben? Sie können beispielsweise eine Tastenkombination einstellen oder sogar eine Taste hinzufügen, die nicht vorhanden ist, z. B. das Ein- und Ausschalten des Sounds. Die Pedale können helfen, wenn Ihre Hände beschäftigt sind: Ich spiele selbst Gitarre, und manchmal zur Begleitung wäre es für mich sehr praktisch, den Hintergrund zu rollen, ohne ständig die Tastatur zu erreichen. Und schließlich können Controller in Spielen völlig unmenschliche Möglichkeiten bieten: Es wäre cool, Ihre gesamte Basis in einer Strategie mit einem Klick aufzubauen oder Feinde mit einer Geschwindigkeit von einem Dutzend Schlägen pro Sekunde in Schützen zu zerstören, oder?
Generell hoffe ich, dass ich Sie überzeugt habe, was bedeutet, dass es Zeit ist, direkt mit der Entwicklung selbst zu beginnen.
Erforderliche Ressourcen
- Eigentlich die Pedale. Einige Schwierigkeiten entstanden sofort aufgrund der Tatsache, dass ich mir keinen Namen für ein solches Pedal vorstellen konnte. Ich wusste nur, dass solche Dinge in Nähmaschinen verwendet werden. Im Allgemeinen gelang es mir auf Wunsch eines elektrischen Pedals immer noch, das zu finden, was ich bei Aliexpress brauchte, und ohne nachzudenken, bestellte ich 3 Stück.
- Controller Das Pedalboard sollte die Tastatur und möglicherweise die Maus emulieren, um ohne unnötige Treiber eine Verbindung zu einem PC herstellen zu können. Dafür ist das Arduino Pro Micro Board perfekt, das zwar keine Schlussfolgerungen zieht, aber so kompakt wie möglich ist. Wir gehen zum selben Aliexpress und kaufen die chinesische Version dieses Wunders.
- Drähte. Um 3 Pedale unter den Tisch zu stellen, benötigen Sie mindestens einen vieradrigen Draht mit einer Länge von mindestens einem Meter. Hier sollten meiner Meinung nach keine Probleme auftreten.
- RGB LED und Taste. Der erste wird benötigt, um die Modi anzuzeigen, und der zweite ist, um sie zu wechseln.
- Natürlich brauchen wir eine Arduino IDE, einen Lötkolben und gerade Arme.
Gerätediagramm
Noch bevor die Pakete ankamen, begann ich mit der Erstellung eines Gerätediagramms. Obwohl dies viel gesagt wird, musste ich nur die Pedale, die Diode und den Knopf anschließen. Es stellte sich irgendwie so heraus:

Für Pedale habe ich beschlossen, 4 Ports PB1-PB4 gleichzeitig zuzuweisen, dh zwei für den linken und zwei für den rechten Fuß, obwohl ich bisher nur 3 Pedale habe. Außerdem gehören sie alle zur selben Gruppe und befinden sich an einem Ort. Unter der LED habe ich die Ausgänge PD0, PD1 und PD4 unter der Taste - PD7 genommen.
In diesem Fall benötigen wir keine Pull-up-Widerstände, wenn Sie die im Controller eingebauten verwenden. Wenn Sie dann jedoch eine Taste oder ein Pedal drücken, ist der Eingang niedrig, und wenn er losgelassen wird, ist er hoch, dh die Druckvorgänge werden invertiert, und Sie sollten dies nicht vergessen.
Code schreiben
Diese Phase war die schwierigste: Aufgrund einiger Fehler in den Zeigern habe ich den Bootloader mehrmals gelöscht und infolgedessen die Karte auf Softwareebene fast ausgefallen. Im Folgenden werden alle Phasen der Erstellung der Firmware ausführlich beschrieben. Für diejenigen, die nur einen funktionierenden Code erhalten möchten, befindet sich dieser am Ende des Artikels.
Vorbereitung
Zuerst müssen wir verstehen, was das Pedal in Bezug auf das Programm ist. Ich habe mich entschlossen, die Pedale in einem von zwei Modi einzustellen - Echtzeit und Trigger. In diesem Fall hat jedes Pedal zwei Programme: Das erste wird ausgeführt, wenn das Pedal in Echtzeit oder mit ungeraden Drücken im Triggermodus gehalten wird, das zweite wird ausgeführt, wenn das Pedal in Echtzeit losgelassen wird oder wenn die Pedale im Triggermodus gleichmäßig gedrückt werden. Das Pedal hat auch einen Port, einen Status und zwei Variablen - die aktuellen Positionen in den Programmen 1 und 2. Ich habe diese Struktur:
struct pedal { char port;
Arduino hat ziemlich viel Speicher und ist auch 8-Bit, daher ist es am besten, wenn möglich zu versuchen, char anstelle von int zu verwenden.
Wir benötigen auch die Standard-Tastaturbibliothek, um als Tastatur arbeiten zu können.
Klicken Sie auf Verarbeitung
Jetzt müssen wir einen Interpreter erstellen, der Daten aus dem Array liest und in Form von Tastenanschlägen an die Maschine sendet sowie mehrere Werte für verschiedene interne Befehle auswählt. Wir öffnen die
Seite mit den Schlüsselcodes und sehen, was und wie wir klicken können. Ich habe nicht tief gegraben und alle möglichen Tastaturstandards studiert, da mir die Informationen hier für ein solches Projekt völlig ausreichend erschienen. Die erste Hälfte ist für Standard-ASCII-Zeichen reserviert (obwohl einige von ihnen nicht druckbar sind oder nicht verwendet werden), die zweite Hälfte ist für verschiedene Modifizierertasten vorgesehen. Es gibt sogar separate Codes für die linke und rechte Taste, was sehr erfreulich ist, aber ich habe keine speziellen Codes für die Zahlen aus dem Nampad gesehen, obwohl sie meines Wissens im System auf besondere Weise wahrgenommen werden als gewöhnliche Zahlen. Vielleicht befinden sich ihre Codes irgendwo in den „Löchern“ zwischen den Bereichen, aber jetzt geht es nicht darum. Der größte Schlüssel ist also der Aufwärtsschlüssel - 218, was bedeutet, dass der Bereich 219-255 als frei angesehen werden kann, oder zumindest gibt es keine wichtigen Schlüssel.
void pedalAction() {
Ich denke, dass selbst eine Person mit nicht dem höchsten Kenntnisstand von C keine Fragen darüber haben wird, was hier passiert. Zunächst wählt die Funktion das gewünschte Pedal aus und bestimmt je nach Modus und Zustand des Pedals, welches Programm ausgeführt werden soll. Wenn beim Lesen jedes Elements des Arrays kein Steuerzeichen verwendet wird, wird die Funktion Keyboard.write () aufgerufen, die das Drücken und Loslassen einer Taste emuliert. Die Steuerzeichen werden separat verarbeitet und werden benötigt, um die Tastenkombinationen zu klemmen und im Programm zu navigieren.
Einige Funktionen des TastaturmodusKeyboard.write () hat einige einfache, aber für Anfänger nicht offensichtliche Nuancen, basierend auf der Tatsache, dass wir Daten nicht in Rohform, sondern als Tastenanschläge senden. Erstens kann der Computer seltsamerweise ohne zusätzliche Treiber nur Zeichen von der Tastatur akzeptieren, die sich auf der Tastatur befinden, was bedeutet, dass wir keine 0x03 (Interrupt-Signal) oder 0x1B (Beginn der ESCAPE-Sequenz) senden können. Zweitens können wir die Großbuchstaben so anpassen, wie sie in der ASCII-Tabelle enthalten sind, aber die Maschine erhält die Tastenkombination Umschalt + <Kleinbuchstaben>. Dies kann zu einem Problem werden, wenn CapsLock aktiviert ist und wir "unerwartet" kleine Buchstaben anstelle von großen Buchstaben erhalten und umgekehrt. Drittens können wir die russische Sprache nicht so gut wie in jeder anderen Sprache verwenden. Dies geschieht erneut aufgrund von nervigen Dingen wie Schlüsselcodes . Obwohl Keyboard.write () dies als Argument akzeptiert, wird der Code, der dem Schlüssel entspricht, auf dem er sich im englischen Standardlayout befindet, weiterhin über USB gesendet. Wenn wir versuchen, das kyrillische Alphabet zu senden, wissen wir nicht, was. Wenn wir unseren russischsprachigen Freunden über Arduino Hallo sagen möchten, müssen wir im Code „Ghbdtn“ schreiben und es dann senden, nachdem wir das russische Layout ausgewählt haben. Eine solche „Begrüßung“ funktioniert im ukrainischen Layout, aber im Bulgarischen wird trotz der Tatsache, dass es auch ein kyrillisches Alphabet gibt, nichts daraus, da sich die Buchstaben dort an völlig anderen Stellen befinden. (Ich habe einmal die Meinung gehört, dass es für viele amerikanische und englische Entwickler unverständlich ist, dass jemand möglicherweise sogar mehrere Layouts verwenden, diese aber auch wechseln muss.)
Wir haben also einen Dolmetscher und ein grobes Verständnis dafür, wie unser Pedalboard mit einem Computer interagiert. Jetzt müssen wir all dies auf den Zustand der vollständigen Firmware bringen und die Leistung auf einem Pedal überprüfen. Wenn Sie eine Instanz des Pedals erstellen und zyklisch pedalAction () aufrufen, führen wir theoretisch das in der Struktur angegebene Programm aus.
struct pedal *pedal1 = {15, 0, 0, 0, 0, 0, "Hello, world!\0", 0}; void prepare () { pinMode(15, 2);
Vergessen Sie übrigens niemals Null-Terminatoren in diesen „Programmen“, wenn ihre Länge kleiner als die Größe des Arrays ist und wenn sie nicht zyklisch sind, da Arduino nicht nur versucht, die nicht eingestellten Daten zu interpretieren, sondern sie auch mit hoher Geschwindigkeit an die Maschine sendet. und das ist das gleiche wie einem Affen eine Tastatur zu geben.
Ein Pedal ist gut und zwei sind besser
Jetzt ist es an der Zeit, sich mit der Verarbeitung von Signalen von mehreren Pedalen zu befassen und Schaltmodi hinzuzufügen. Zu Beginn des Artikels wurden 4 Ports für Pedale zugewiesen, von denen jeder in sieben Modi arbeiten darf. Warum 7? Denn ohne PWM kann unsere LED nur 7 Farben liefern und die achte aus. Diese Menge ist für den durchschnittlichen Benutzer völlig ausreichend, kann jedoch in extremen Fällen leicht erhöht werden. Wir werden die Pedale also in einem zweidimensionalen Array von 7 x 4 speichern. Um den Speicher nicht zu verstopfen, können Werte, die mehreren Strukturen gemeinsam sind, wie z. B. die Portnummer, in separaten Arrays herausgenommen werden. Als Ergebnis erhalten wir ungefähr Folgendes:
struct pedal { unsigned char type; unsigned char act1[16]; unsigned char act2[16]; }; struct pedal pedals[7][4] = { { { 255, {"Hello, world!\0"}, {255}}, {255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}} }, { { 255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}} }, { { 255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}} }, { { 255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}} }, { { 255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}} }, { { 255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}} }, { { 255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}} } }; char ports[4] = {15, 16, 14, 8}; char pos1[4] = {0, 0, 0, 0}; char pos2[4] = {0, 0, 0, 0}; char state[4] = {0, 0, 0, 0}; char oldState[4] = {0, 0, 0, 0}; char mode = 0;
Die Magie der Nummer 255Sie haben wahrscheinlich bemerkt, dass in dem Artikel häufig die Nummer 255 erscheint, wo es logischer wäre, 0 zu setzen. Mit Blick auf die Zukunft werde ich sagen, dass dies für die bequeme Speicherung von Pedalen im EEPROM erforderlich ist, da ab Werk jede ihrer Zellen nicht 0 enthält, sondern Nur 255, was bedeutet, dass diese Zahl viel bequemer ist, um undefinierte Variablen als 0 anzuzeigen, damit Sie den Speicher nicht jedes Mal überschreiben.
Es ist wichtig, dass wir nur die Art des Pedals und zwei Programme kennen, damit wir sie nur direkt in der Struktur belassen und den Rest von der Automatisierung erledigen lassen. Die Prepare- und Loop-Methoden sehen nun folgendermaßen aus:
void prepare(){ pinMode(2, 1); pinMode(3, 1); pinMode(4, 1); pinMode(6, 2); for (int i : ports) pinMode(i, 2); Keyboard.begin(); } void loop() { for (int i = 0; i < 6; i++) { int current; if ((current = digitalRead(modeButton)) != last) { if (!current) { if (++mode >= 7) mode = 0; while (pedals[mode][0].type == 255 && pedals[mode][1].type == 255 && pedals[mode][2].type == 255 && pedals[mode][3].type == 255) if (++mode >= 7) { mode = 0; break; } } last = current; digitalWrite(2, (mode + 1) & 0b001); digitalWrite(3, (mode + 1) & 0b010); digitalWrite(4, (mode + 1) & 0b100); for (int i = 0; i < 4; i++) { pos1[i] = 0; pos2[i] = 0; state[i] = 0; oldState[i] = 0; } delay(50); } curPedal = i; pedalAction } } }
Der Controller betrachtet den Modus als nicht verwendet, wenn kein einziges Pedal darin deklariert ist (Modus = 255). Dies bedeutet, dass er beim Auftreffen sofort zum nächsten wechselt, der erste Modus jedoch immer vorhanden ist. Beim Umschalten des Modus werden alle Werte in den Arrays auf Null gesetzt, da sie nicht für jeden Modus gespeichert werden müssen (richtig?). Dann umgeht die Schleife alle Pedale und ruft pedalAction für sie auf.
Außerdem müssen Sie zu Beginn der pedalAction () -Methode die folgende Zeile hinzufügen, damit verstanden wird, mit welcher der Strukturen umgegangen werden soll:
struct pedal *pedal1 = &pedals[mode][curPedal];
Die vorhandene Pedal1-Struktur kann als unnötig entfernt werden.
All dies funktioniert auch ganz gut, aber ich bin auf ein Problem gestoßen: Einige Programme haben keine Zeit, Klicks mit der Geschwindigkeit zu empfangen, mit der Arduino sie sendet. Die naheliegendste Lösung besteht darin, die Möglichkeit hinzuzufügen, bei Bedarf Verzögerungen zwischen Aktionen festzulegen. Nur wenn wir uns hinsetzen, um Programme für Mikrocontroller zu schreiben, blieben alle Chips, wie Hardware-Multithreading, irgendwo auf High-Level-Computern. Wenn wir eine Verzögerung hinzufügen, stoppt das gesamte Programm, bis der Controller die richtige Anzahl von Zyklen zählt. Da wir kein Multithreading haben, müssen wir es erstellen.
Schwer zu sagen, ja einfach zu machen
Ich habe kein Fahrrad erfunden, sondern die fertige ArduinoThread-Bibliothek genommen.
Hier können Sie ein wenig darüber lesen, wie es funktioniert, und es herunterladen. Sie können die Bibliothek von der Arduino IDE selbst herunterladen. Kurz gesagt, Sie können regelmäßig eine Funktion mit einem bestimmten Intervall ausführen, ohne in eine Endlosschleife zu wechseln, wenn die Ausführung länger als das Intervall dauert. Was du brauchst. Erstellen Sie ein weiteres Array mit Threads für jedes Pedal:
Thread pedalThreads[6] = {Thread(pedalAction, 10), Thread(pedalAction, 10), Thread(pedalAction, 10), Thread(pedalAction, 10), Thread(pedalAction, 10), Thread(pedalAction, 10)};
Jetzt haben wir 6 identische virtuelle Threads, aber gleichzeitig sind sie verschiedene Objekte.
Schreiben wir den Pedal-Bypass-Zyklus neu, um mit der neuen Funktionalität zu arbeiten:
... for (int i = 0; i < 4; i++) { if (pedalThreads[i].shouldRun()) { curPedal = i; pedalThreads[i].run(); } } ...
Jetzt ergibt der Wert 252 im Programmarray, der "nichts tun" entspricht, eine Verzögerung von 10 Millisekunden (obwohl tatsächlich etwas mehr, da die Codeausführung auch Zeit benötigt). Durch Hinzufügen einiger Zeilen zum Interpreter können Sie die Verzögerung in mehreren dieser "Quanten" einstellen und nur 2 Bytes des Arrays ausgeben:
... if (wait[num]) { wait[num]--; return; } else if (prg[*pos] == 250) { wait[num] = prg[++*pos]; } ...
Im Gegensatz zu anderen Befehlen muss dieser Befehl genau am Anfang des Interpreters hinzugefügt werden, dh unmittelbar nach "while (1) {", da die Verzögerung verarbeitet werden muss, bevor der Interpreter das Programm liest. Das Wartearray muss ebenfalls deklariert werden, wie dies bei Ports, Status usw. der Fall war. und auch seine Zellen zurücksetzen, wenn der Modus umgeschaltet wird, so dass die Verzögerung nicht zu einem anderen Programm geht.
Mit der Möglichkeit, die Verzögerung auf 2,55 Sekunden einzustellen, sollten nun keine Probleme bei der Definition von Schlüsseln durch Programme auftreten.
Unterwegs programmieren
Im Prinzip wäre es hier möglich, mit dem Code fertig zu werden und mit dem Zusammenbau des Geräts zu beginnen. In diesem Fall muss jemand, der plötzlich die Pedale neu programmieren möchte, die Arduino IDE öffnen, den Code bearbeiten und die Firmware erneut herunterladen. Natürlich ist diese Option nicht die beste, daher habe ich beschlossen, die Möglichkeit hinzuzufügen, das Programm über die serielle Arduino-Schnittstelle zu ändern und die Programme selbst im EEPROM zu speichern. Um mit nichtflüchtigem Speicher zu arbeiten, müssen Sie die Standardbibliothek EEPROM.h verbinden. Der Programmiermoduscode lautet wie folgt:
... if (!digitalRead(modeButton)) {
Was dieser Code bewirkt, wird durch die darin enthaltene Hilfe erklärt: Für die Modusnummer, die Pedalnummer und einen Befehl wird eine Leerzeichen-Nummer eingegeben, von denen es 3 gibt - Lesen, Schreiben und
Ausführen des Programmlöschens. Alle Daten auf den Pedalen werden nacheinander in einer Folge von 33 Bytes, dh dem Pedaltyp und zwei Programmen, gespeichert, und wir belegen 7 * 4 * 33 = 924 von 1024 Bytes EEPROM. Ich habe die Option, die dynamische Größe der Pedale im Speicher zu verwenden, verworfen, da in diesem Fall beim Neuprogrammieren eines Pedals fast alle Zellen überschrieben werden müssen und es eine begrenzte Anzahl von Umschreibzyklen gibt. Wir empfehlen daher, dies so wenig wie möglich zu tun.
Funktionen der Arbeit mit EEPROMIch möchte auch auf die Linien des Formulars aufmerksam machen:
PORTD = 0b00000010 + (PORTD & 0b11101100); ... PORTD = 0b00000001 + (PORTD & 0b11101100);
Dank dieser Bibliothek ist nichtflüchtiger Speicher aus Sicht des Programmierers ein gewöhnliches Char-Array. Als „Arduino“ müssen wir jedoch verstehen, dass das Schreiben in ein ROM eine sehr schwierige Operation ist, die vom Controller bis zu ~ 3 Sekunden dauert, und es ist ratsam, dies nicht zu unterbrechen Prozess. Dieses Design lässt die Diode während solcher Vorgänge rot leuchten und gibt dann die „sichere“ grüne Farbe zurück.
Im Programmaufzeichnungsmodus erfolgt die Eingabe direkt durch die Bytewerte im Dezimalzahlensystem mit einem Leerzeichen. Es stellt sich als ziemlich schwerwiegend heraus, aber Sie müssen keinen komplexen Parser schreiben. Darüber hinaus tritt eine Neuprogrammierung nicht so häufig auf, und in diesen Fällen ist es durchaus möglich, in die ASCII-Tabelle zu schauen.
Nachdem die Strukturen erhalten geblieben sind, müssen wir jetzt irgendwie unsere Daten von dort herausziehen und sie in die "Pedal" -Ansicht konvertieren:
... for (int i = 0; i < 7; i++) { for (int j = 0; j < 4; j++) { struct pedal *p = &pedals[i][j]; int beginAddress = sizeof(struct pedal) * (i * 6 + j); int curAddress = beginAddress; unsigned char type = EEPROM[curAddress++]; if (type == 0 || type == 1) { p->type = type; for (int k = 0 ; k < 16; k++) { p->act1[k] = EEPROM[curAddress++]; } for (int k = 0 ; k < 16; k++) { p->act2[k] = EEPROM[curAddress++]; } } } } ...
Auch hier passiert nichts Übernatürliches: Der Controller liest die Daten aus dem Speicher und füllt die vorhandenen Strukturen damit.
Der Vorteil der Programmierung über UART besteht darin, dass wir wiederum keine speziellen Treiber benötigen, sodass Sie das Verhalten des Manipulators auch vom Telefon aus einstellen können.
Demonstration
Vollständiger Quellcode
Er ist hier #include <Keyboard.h> #include <Thread.h> #include <EEPROM.h> #define modeButton 6 struct pedal { unsigned char type; //0 — , 1 — , 255 — unsigned char act1[16]; unsigned char act2[16]; }; struct pedal pedals[7][4] = { { { 255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}} }, { { 255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}} }, { { 255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}} }, { { 255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}} }, { { 255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}} }, { { 255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}} }, { { 255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}}, {255, {255}, {255}} } }; char ports[4] = {8, 16, 15, 14}; char pos1[4] = {0, 0, 0, 0}; char pos2[4] = {0, 0, 0, 0}; char state[4] = {0, 0, 0, 0}; char oldState[4] = {0, 0, 0, 0}; char wait[4] = {0, 0, 0, 0}; void pedalAction(); char mode = 0; char curPedal; Thread pedalThreads[6] = {Thread(pedalAction, 10), Thread(pedalAction, 10), Thread(pedalAction, 10), Thread(pedalAction, 10), Thread(pedalAction, 10), Thread(pedalAction, 10)}; void setup() { pinMode(2, 1); pinMode(3, 1); pinMode(4, 1); pinMode(modeButton, 2); if (!digitalRead(modeButton)) { // Serial.begin(9600); while (!Serial) { PORTD = 0b00000000 + (PORTD & 0b11101100); delay(250); PORTD = 0b00010000 + (PORTD & 0b11101100); delay(250); } Serial.println(F("***Programming mode***")); Serial.println(F("Write the command as <m> <p> <c>")); Serial.println(F("m - number of mode, one digit")); Serial.println(F("p - number of pedal, one digit")); Serial.println(F("c - command, it can be:")); Serial.println(F("\tr - read pedal info")); Serial.println(F("\tw - enter to writing mode and change pedal programm")); Serial.println(F("\te - erase pedal programm and delete it")); Serial.println(F("There are up to 7 modes and 6 pedals per mode can be configured")); Serial.println(F("Mode will be incative if there is no pedal configured in it")); while (1) { while (Serial.available()) { Serial.read(); delay(1); } PORTD = 0b00000001 + (PORTD & 0b11101100); Serial.println(""); Serial.println(F("Enter command")); while (!Serial.available()); PORTD = 0b00000010 + (PORTD & 0b11101100); delay(3); if (Serial.available() == 3) { int curMode = Serial.read() - 48; int curPedal = Serial.read() - 48; char cmd = Serial.read(); if (curMode > 6 || curMode < 0) { Serial.print(F("Mode must be in 0-6. You entered ")); Serial.println(curMode); continue; } if (curPedal > 3 || curPedal < 0) { Serial.print(F("Pedal must be in 0-3. You entered ")); Serial.println(curPedal); continue; } Serial.println(); if (cmd == 'r') { int beginAddress = sizeof(struct pedal) * (curMode * 6 + curPedal); Serial.print("type: "); int curAddress = beginAddress; Serial.println(EEPROM[curAddress++]); Serial.print("act1: "); for (int i = curAddress ; i < curAddress + (sizeof(struct pedal) - 1) / 2; i++) { Serial.print(EEPROM[i]); Serial.print("\t"); } Serial.println(); curAddress = beginAddress + 1 + (sizeof(struct pedal) - 1) / 2; Serial.print("act2: "); for (int i = curAddress ; i < curAddress + (sizeof(struct pedal) - 1) / 2; i++) { Serial.print(EEPROM[i]); Serial.print("\t"); } Serial.println(); } else if (cmd == 'w') { Serial.println(F("Enter type:")); PORTD = 0b00000001 + (PORTD & 0b11101100); while (!Serial.available()); int beginAddress = sizeof(struct pedal) * (curMode * 6 + curPedal); int curAddress = beginAddress; PORTD = 0b00000010 + (PORTD & 0b11101100); EEPROM[curAddress++] = (char)Serial.parseInt(); PORTD = 0b00000001 + (PORTD & 0b11101100); Serial.println(F("Enter act1 in DEC divided by space:")); while (Serial.available()) { Serial.read(); delay(1); } while (!Serial.available()); PORTD = 0b00000010 + (PORTD & 0b11101100); while (Serial.available()) { EEPROM[curAddress++] = (char)Serial.parseInt(); delay(1); } PORTD = 0b00000001 + (PORTD & 0b11101100); curAddress = beginAddress + 1 + (sizeof(struct pedal) - 1) / 2; Serial.println(F("Enter act2 in DEC divided by space:")); while (Serial.available()) { Serial.read(); delay(1); } while (!Serial.available()); PORTD = 0b00000010 + (PORTD & 0b11101100); while (Serial.available()) { EEPROM[curAddress++] = (char)Serial.parseInt(); delay(1); } PORTD = 0b00000001 + (PORTD & 0b11101100); Serial.println(F("Finished, don't forget to verify written data!")); } else if (cmd == 'e') { int beginAddress = sizeof(struct pedal) * (curMode * 6 + curPedal); Serial.println(F("Disabling pedal...")); PORTD = 0b00000010 + (PORTD & 0b11101100); EEPROM[beginAddress] = 255; PORTD = 0b00000001 + (PORTD & 0b11101100); Serial.println(F("Pedal disabled")); } } else { Serial.println(F("Incorrect command, please read help above")); } }; } for (int i : ports) pinMode(i, 2); pinMode(17, 1); for (int i = 0; i < 7; i++) { for (int j = 0; j < 4; j++) { struct pedal *p = &pedals[i][j]; int beginAddress = sizeof(struct pedal) * (i * 6 + j); int curAddress = beginAddress; unsigned char type = EEPROM[curAddress++]; if (type == 0 || type == 1) { p->type = type; for (int k = 0 ; k < 16; k++) { p->act1[k] = EEPROM[curAddress++]; } for (int k = 0 ; k < 16; k++) { p->act2[k] = EEPROM[curAddress++]; } } } } Keyboard.begin(); } int last = 0; void loop() { int current; if ((current = digitalRead(modeButton)) != last) { if (!current) { if (++mode >= 7) mode = 0; while (pedals[mode][0].type == 255 && pedals[mode][1].type == 255 && pedals[mode][2].type == 255 && pedals[mode][3].type == 255) if (++mode >= 7) { mode = 0; break; } } last = current; digitalWrite(2, (mode + 1) & 0b001); digitalWrite(3, (mode + 1) & 0b010); digitalWrite(4, (mode + 1) & 0b100); for (int i = 0; i < 4; i++) { pos1[i] = 0; pos2[i] = 0; state[i] = 0; oldState[i] = 0; wait[i] = 0; } delay(50); } for (int i = 0; i < 4; i++) { if (pedalThreads[i].shouldRun()) { curPedal = i; pedalThreads[i].run(); } } } void pedalAction() { struct pedal *pedal1 = &pedals[mode][curPedal]; if (pedal1->type == 255) return; unsigned char *prg; char *pos; if (pedal1->type) { int current; if ((current = digitalRead(ports[curPedal])) != oldState[curPedal]) { if (!current) state[curPedal] = !state[curPedal]; oldState[curPedal] = current; } if (!state[curPedal]) { //act1 pos2[curPedal] = 0; pos = &(pos1[curPedal]); prg = pedal1->act1; } else { //act2 pos1[curPedal] = 0; pos = &(pos2[curPedal]); prg = pedal1->act2; } } else { if (!digitalRead(ports[curPedal])) { //act1 pos2[curPedal] = 0; pos = &(pos1[curPedal]); prg = pedal1->act1; } else { //act2 pos1[curPedal] = 0; pos = &(pos2[curPedal]); prg = pedal1->act2; } } while (1) { if (wait[curPedal]) { wait[curPedal]--; return; } else if (prg[*pos] == 250) { wait[curPedal] = prg[++*pos]; } else if (prg[*pos] == 254) { // , *pos Keyboard.press(prg[++*pos]); } else if (prg[*pos] == 253) { // , *pos Keyboard.release(prg[++*pos]); } else if (prg[*pos] == 252) { delay(10); //" ", ++*pos; return; } else if (prg[*pos] == 251) { // *pos+1 *pos = prg[*pos + 1]; return; } else if (prg[*pos] == 255 || prg[*pos] == 0) { // , return; } else { // Keyboard.write(prg[*pos]); } // , if (++*pos >= 16) pos = 0; } }
Nachwort
Obwohl ich anfangs ein Pedalboard für die Möglichkeit gemacht habe, die Aufnahme während des Gitarrenspiels zu scrollen, fand ich es persönlich praktisch, die Pedale bei normalen Aufgaben zu verwenden. Die Hauptsache ist, mich ein wenig an einen so ungewöhnlichen Manipulator zu gewöhnen. Und hier liegt noch ein weiteres Problem: Bereits ohne Ihre Lieblingspedale wird das Arbeiten im Gegenteil schwieriger, da Sie sich daran erinnern müssen, was, wo und warum Sie drücken müssen. Wenn Pedale noch getragen und mit dem Büro verbunden werden können, ist es am Institut schwieriger, mit ihnen in Klassenzimmern herumzulaufen. Die Verwendung dieses Geräts für einen anderen Zweck als den ursprünglichen Zweck erfolgt auf eigene Gefahr und Gefahr.Zusammengebautes Pedalboard: