adding Arduino Support for Matrix Keyboards

This Feature was requested in Discord.
With This Update your Arduino now can read Matrix Keyboards.
Keys are send with Identifier "M".
This commit is contained in:
Alexander Richter 2023-03-28 16:24:39 +02:00
parent 474c57a8e1
commit f49181389a

View File

@ -20,6 +20,8 @@
To begin Transmitting Ready is send out and expects to receive E: to establish connection. Afterwards Data is exchanged. To begin Transmitting Ready is send out and expects to receive E: to establish connection. Afterwards Data is exchanged.
Data is only send everythime it changes once. Data is only send everythime it changes once.
LinuxCNC HAL Pins:
Inputs = 'I' -write only -Pin State: 0,1 Inputs = 'I' -write only -Pin State: 0,1
Outputs = 'O' -read only -Pin State: 0,1 Outputs = 'O' -read only -Pin State: 0,1
PWM Outputs = 'P' -read only -Pin State: 0-255 PWM Outputs = 'P' -read only -Pin State: 0-255
@ -28,9 +30,17 @@
Latching Potentiometers = 'L' -write only -Pin State: 0-max Position Latching Potentiometers = 'L' -write only -Pin State: 0-max Position
Absolute Encoder input = 'K' -write only -Pin State: 0-32 Absolute Encoder input = 'K' -write only -Pin State: 0-32
Keyboard Input:
Matrix Keypad = 'M' -write only -Pin State: Number of Matrix Key.
Communication Status = 'E' -read/Write -Pin State: 0:0
The Keyboard is encoded in the Number of the Key in the Matrix. The according Letter is defined in the receiving end in the Python Skript.
Here you only define the Size of the Matrix.
Command 'E0:0' is used for connectivity checks and is send every 5 seconds as keep alive signal. If the Signal is not received again, the Status LED will Flash.
The Board will still work as usual and try to send it's data, so this feature is only to inform the User.
Command 'E0:0' is used for connectivity checks and is send every 5 seconds as keep alive signal
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -79,21 +89,22 @@
#endif #endif
//#define LPOTIS
/*This is a special mode of AInputs. My machine had originally Selector Knobs with many Pins on the backside to select different Speed Settings. /*This is a special mode of AInputs. My machine had originally Selector Knobs with many Pins on the backside to select different Speed Settings.
I turned them into a "Potentiometer" by connecting all Pins with 10K Resistors in series. Then i applied GND to the first and 5V to the last Pin. I turned them into a "Potentiometer" by connecting all Pins with 10K Resistors in series. Then i applied GND to the first and 5V to the last Pin.
Now the Selector is part of an Voltage Divider and outputs different Voltage for each Position. This function generates Pins for each Position in Linuxcnc Hal. Now the Selector is part of an Voltage Divider and outputs different Voltage for each Position. This function generates Pins for each Position in Linuxcnc Hal.
It can happen, that when you switch position, that the selector is floating for a brief second. This might be detected as Position 0. It can happen, that when you switch position, that the selector is floating for a brief second. This might be detected as Position 0.
This shouldn't be an issue in most usecases, but think about that in your application. This shouldn't be an issue in most usecases, but think about that in your application.
Connect it to an Analog In Pin of your Arduino and define how many of these you want.
Then in the Array, {which Pin, How many Positions} Connect it to an Analog In Pin of your Arduino and define how many of these you want.
Note that Analog Pin numbering is different to the Print on the PCB. Then in the Array, {which Pin, How many Positions}
Note that Analog Pin numbering is different to the Print on the PCB.
*/
*/
//#define LPOTIS
#ifdef LPOTIS #ifdef LPOTIS
const int LPotis = 2; const int LPotis = 2;
int LPotiPins[LPotis][2] = { int LPotiPins[LPotis][2] = {
@ -109,14 +120,15 @@
#endif #endif
//#define STATUSLED //The Software will detect if there is an communication issue. When you power on your machine, the Buttons etc won't work, till LinuxCNC is running. THe StatusLED will inform you about the State of Communication. //The Software will detect if there is an communication issue. When you power on your machine, the Buttons etc won't work, till LinuxCNC is running. THe StatusLED will inform you about the State of Communication.
// Slow Flash = Not Connected // Slow Flash = Not Connected
// Steady on = connected // Steady on = connected
// short Flash = connection lost. // short Flash = connection lost.
// if connection is lost, something happened. (Linuxcnc was closed for example or USB Connection failed.) It will recover when Linuxcnc is restartet. (you could also run "unloadusr arduino", "loadusr arduino" in Hal) // if connection is lost, something happened. (Linuxcnc was closed for example or USB Connection failed.) It will recover when Linuxcnc is restartet. (you could also run "unloadusr arduino", "loadusr arduino" in Hal)
// Define an Pin you want to connect the LED to. it will be set as Output indipendand of the OUTPUTS function, so don't use Pins twice. // Define an Pin you want to connect the LED to. it will be set as Output indipendand of the OUTPUTS function, so don't use Pins twice.
// If you use Digital LED's such as WS2812 or PL9823 (only works if you set up the DLED settings below) you can also define a position of the LED. In this case StatLedPin will set the number of the Digital LED Chain. // If you use Digital LED's such as WS2812 or PL9823 (only works if you set up the DLED settings below) you can also define a position of the LED. In this case StatLedPin will set the number of the Digital LED Chain.
//#define STATUSLED
#ifdef STATUSLED #ifdef STATUSLED
const int StatLedPin = 5; //Pin for Status LED const int StatLedPin = 5; //Pin for Status LED
const int StatLedErrDel[] = {1000,10}; //Blink Timing for Status LED Error (no connection) const int StatLedErrDel[] = {1000,10}; //Blink Timing for Status LED Error (no connection)
@ -125,25 +137,27 @@
//#define DLED
/* Instead of connecting LED's to Output pins, you can also connect digital LED's such as WS2812 or PL9823. /* Instead of connecting LED's to Output pins, you can also connect digital LED's such as WS2812 or PL9823.
This way you can have how many LED's you want and also define it's color with just one Pin. This way you can have how many LED's you want and also define it's color with just one Pin.
DLEDcount defines, how many Digital LED's you want to control. Count from 0. For Each LED an output Pin will be generated in LinuxCNC hal.
To use this funcion you need to have the Adafruit_NeoPixel.h Library installed in your Arduino IDE.
In LinuxCNC you can set the Pin to HIGH and LOW, for both States you can define an color per LED.
This way, you can make them glow or shut of, or have them Change color, from Green to Red for example.
DledOnColors defines the color of each LED when turned "on". For each LED set {Red,Green,Blue} with Numbers from 0-255. DLEDcount defines, how many Digital LED's you want to control. Count from 0. For Each LED an output Pin will be generated in LinuxCNC hal.
depending on the Chipset of your LED's Colors might be in a different order. You can try it out by setting {255,0,0} for example. To use this funcion you need to have the Adafruit_NeoPixel.h Library installed in your Arduino IDE.
You need to define a color to DledOffColors too. Like the Name suggests it defines the color of each LED when turned "off". In LinuxCNC you can set the Pin to HIGH and LOW, for both States you can define an color per LED.
If you want the LED to be off just define {0,0,0}, . This way, you can make them glow or shut of, or have them Change color, from Green to Red for example.
DledOnColors defines the color of each LED when turned "on". For each LED set {Red,Green,Blue} with Numbers from 0-255.
depending on the Chipset of your LED's Colors might be in a different order. You can try it out by setting {255,0,0} for example.
You need to define a color to DledOffColors too. Like the Name suggests it defines the color of each LED when turned "off".
If you want the LED to be off just define {0,0,0}, .
If you use STATUSLED, it will also take the colors of your definition here. If you use STATUSLED, it will also take the colors of your definition here.
*/ */
//#define DLED
#ifdef DLED #ifdef DLED
#include <Adafruit_NeoPixel.h> #include <Adafruit_NeoPixel.h>
@ -178,8 +192,29 @@ Adafruit_NeoPixel strip(DLEDcount, DLEDPin, NEO_GRB + NEO_KHZ800);//Color sequen
#endif #endif
/*
Matrix Keypads are supported. The input is NOT added as HAL Pin to LinuxCNC. Instead it is inserted to Linux as Keyboard direktly.
So you could attach a QWERT* Keyboard to the arduino and you will be able to write in Linux with it (only while LinuxCNC is running!)
*/
#define KEYPAD
#ifdef KEYPAD
const int numRows = 4; // Define the number of rows in the matrix
const int numCols = 4; // Define the number of columns in the matrix
// Define the pins connected to the rows and columns of the matrix
const int rowPins[numRows] = {2, 3, 4, 5};
const int colPins[numCols] = {6, 7, 8, 9};
int keys[numRows][numCols] = {
{1,2,3,4},
{5,6,7,8},
{9,10,11,12},
{13,14,15,16}
};
int lastKey= 0;
#endif
//###Misc Settings### //###Misc Settings###
@ -210,7 +245,9 @@ const int timeout = 10000; // timeout after 10 sec not receiving Stuff
#ifdef ABSENCODER #ifdef ABSENCODER
int oldAbsEncState; int oldAbsEncState;
#endif #endif
#ifdef KEYPAD
byte KeyState = 0;
#endif
//### global Variables setup### //### global Variables setup###
@ -278,6 +315,14 @@ void setup() {
initDLED(); initDLED();
#endif #endif
#ifdef KEYPAD
for(int col = 0; col < numCols; col++) {
for (int row = 0; row < numRows; row++) {
keys[row][col] = row * numRows + col+1;
}
}
#endif
//Setup Serial //Setup Serial
Serial.begin(115200); Serial.begin(115200);
while (!Serial){} while (!Serial){}
@ -289,7 +334,6 @@ void setup() {
StatLedErr(1000,1000); StatLedErr(1000,1000);
#endif #endif
} }
} }
@ -312,6 +356,10 @@ void loop() {
readAbsKnob(); //read ABS Encoder & send data readAbsKnob(); //read ABS Encoder & send data
#endif #endif
#ifdef KEYPAD
readKeypad(); //read Keyboard & send data
#endif
} }
@ -486,6 +534,40 @@ int readAbsKnob(){
} }
#endif #endif
void readKeypad(){
//detect if Button is Pressed
for (int col = 0; col < numCols; col++) {
pinMode(colPins[col], OUTPUT);
digitalWrite(colPins[col], LOW);
// Read the state of the row pins
for (int row = 0; row < numRows; row++) {
pinMode(rowPins[row], INPUT_PULLUP);
if (digitalRead(rowPins[row]) == LOW && lastKey != keys[row][col]) {
// A button has been pressed
Serial.print("M");
Serial.print(keys[row][col]);
Serial.print(":");
Serial.println(1);
lastKey = keys[row][col];
row = numRows;
}
if (digitalRead(rowPins[row]) == HIGH && lastKey == keys[row][col]) {
// The Last Button has been unpressed
Serial.print("M");
Serial.print(keys[row][col]);
Serial.print(":");
Serial.println(0);
lastKey = 0;
row = numRows;
}
}
// Set the column pin back to input mode
pinMode(colPins[col], INPUT);
}
}
void commandReceived(char cmd, uint16_t io, uint16_t value){ void commandReceived(char cmd, uint16_t io, uint16_t value){
#ifdef OUTPUTS #ifdef OUTPUTS
if(cmd == 'O'){ if(cmd == 'O'){
@ -497,11 +579,12 @@ void commandReceived(char cmd, uint16_t io, uint16_t value){
writePwmOutputs(io,value); writePwmOutputs(io,value);
} }
#endif #endif
//#ifdef DLED #ifdef DLED
if(cmd == 'D'){ if(cmd == 'D'){
controlDLED(io,value); controlDLED(io,value);
} }
//#endif #endif
if(cmd == 'E'){ if(cmd == 'E'){
lastcom=millis(); lastcom=millis();
} }
@ -516,6 +599,7 @@ void commandReceived(char cmd, uint16_t io, uint16_t value){
#endif #endif
} }
//This Funktion checks if Received Command is valid. Insert your custom Letter here by inserting another "||cmd == 'X'"
int isCmdChar(char cmd){ int isCmdChar(char cmd){
if(cmd == 'O'||cmd == 'P'||cmd == 'E'||cmd == 'D') {return true;} if(cmd == 'O'||cmd == 'P'||cmd == 'E'||cmd == 'D') {return true;}
else{return false;} else{return false;}