MASSO G3 - ovládací panel (emulovaná USB klávesnice)

Odpovědět
Uživatelský avatar
Thomeeque
Příspěvky: 8870
Registrován: 30. 1. 2012, 10:20
Bydliště: Mimo ČR

22. 11. 2021, 5:37

Ahoj,

trochu už bylo nakousnuto zde. Modrošův ovládací panel využívá pro obsluhu většiny tlačítek Arduino s ATmega32U4 čipem (např. Leonardo) emulující USB klávesnici, čímž ušetří mnoho fyzických IO na MASSO kartě pro jiné využití. Jde o Modrošův nápad, já psal program. V SZ se mi ozval GeminiRacing, že by ho to také zajímalo, tak jsem se rozhodl založit toto téma (Modroš byl pro).

Zjednodušené schéma:

masso_g3_hid.jpg

Mapa tlačítek:

Pin 2 = CTRL + ALT + Home (Homing)
Pin 3 = CTRL + ALT + P (Parking)
Pin 4 = U (Z+)
Pin 5 = D (Z-)
Pin 6-9 = Šipky (Jog XY)
Pin 10 = SHIFT (plus šipka nebo U nebo D = Rapid)
Pin 11 = F11 (Feed, +- dělá ruční kolečko)
Pin 12 = F12 (Spindle RPM , +- dělá ruční kolečko)

Program:

Kód: Vybrat vše

/*
 * MASSO G3 HID control v4
 */

#include <Keyboard.h>

#define DEBOUNCE_MS 50
#define BEEP_PRESS_MS 20
#define BEEP_RELEASE_MS 5 // 0 = no key-release beep

#define KEY_HOMING_PIN 2 // ctrl-alt-home
#define KEY_PARKING_PIN 3 // ctrl-alt-p
#define KEY_U_PIN 4
#define KEY_D_PIN 5
#define KEY_ARROW_LEFT_PIN 6
#define KEY_ARROW_RIGHT_PIN 7
#define KEY_ARROW_UP_PIN 8
#define KEY_ARROW_DOWN_PIN 9
#define KEY_SHIFT_PIN 10
#define KEY_F11_PIN 11
#define KEY_F12_PIN 12

#define KEY_PRESSED_LED LED_BUILTIN
#define SPEAKER_PLUS_PIN A4
#define SPEAKER_MINUS_PIN A5
#define HEARTBEAT_PIN A0

#define KEY_BUFFERS_SIZE 13 // highest KEY_xxx_PIN number used + 1

//---------------------------------------------------------
// global variables
//---------------------------------------------------------

boolean keyStates[KEY_BUFFERS_SIZE];
byte keyTimers[KEY_BUFFERS_SIZE];
byte beepTimer;

//---------------------------------------------------------
// setup
//---------------------------------------------------------

void clearBuffers() {
    for (byte i = 0; i < KEY_BUFFERS_SIZE; i++) {
        keyStates[i] = false;
        keyTimers[i] = 0;
    }
}

void setup() {
    pinMode(KEY_HOMING_PIN, INPUT_PULLUP);
    pinMode(KEY_PARKING_PIN, INPUT_PULLUP);
    pinMode(KEY_U_PIN, INPUT_PULLUP);
    pinMode(KEY_D_PIN, INPUT_PULLUP);
    pinMode(KEY_ARROW_LEFT_PIN, INPUT_PULLUP);
    pinMode(KEY_ARROW_RIGHT_PIN, INPUT_PULLUP);
    pinMode(KEY_ARROW_UP_PIN, INPUT_PULLUP);
    pinMode(KEY_ARROW_DOWN_PIN, INPUT_PULLUP);
    pinMode(KEY_SHIFT_PIN, INPUT_PULLUP);
    pinMode(KEY_F11_PIN, INPUT_PULLUP);
    pinMode(KEY_F12_PIN, INPUT_PULLUP);

    pinMode(KEY_PRESSED_LED, OUTPUT);
    pinMode(SPEAKER_PLUS_PIN, OUTPUT);
    pinMode(SPEAKER_MINUS_PIN, OUTPUT);
    pinMode(HEARTBEAT_PIN, OUTPUT);

    clearBuffers();
    Keyboard.begin();
}

//---------------------------------------------------------
// core methods
//---------------------------------------------------------

#define KEY_STATE_PRESSED 0
#define KEY_STATE_RELEASED 1
#define KEY_STATE_STILL 2

byte fetchKeyState(byte inputPin) {
    if (keyTimers[inputPin] == 0) {
        boolean pressedBefore = keyStates[inputPin];
        boolean pressedNow = digitalRead(inputPin) == 0;

        if (pressedBefore != pressedNow) {
            keyStates[inputPin] = pressedNow;
            keyTimers[inputPin] = DEBOUNCE_MS;

            if (pressedNow) {
                beepTimer = BEEP_PRESS_MS;
                return KEY_STATE_PRESSED;
            }

            beepTimer = BEEP_RELEASE_MS;
            return KEY_STATE_RELEASED;
        }
    } else {
        keyTimers[inputPin]--;
    }
    return KEY_STATE_STILL;
}

void handleSingleKey(byte inputPin, char code) {
    byte keyState = fetchKeyState(inputPin);

    if (keyState == KEY_STATE_PRESSED) {
        Keyboard.press(code);
    } else if (keyState == KEY_STATE_RELEASED) {
        Keyboard.release(code);
    }
}

void handleMultiKey(byte inputPin, void (*callbackFunction)(byte)) {
    byte keyState = fetchKeyState(inputPin);

    if (keyState != KEY_STATE_STILL) {
        callbackFunction(keyState);
    }
}

void handleBeep() {
    if (beepTimer > 0) {
        digitalWrite(SPEAKER_PLUS_PIN, beepTimer & 1);
        digitalWrite(SPEAKER_MINUS_PIN, !(beepTimer & 1));
        beepTimer--;
    } else {
        digitalWrite(SPEAKER_PLUS_PIN, false);
        digitalWrite(SPEAKER_MINUS_PIN, false);
    }
}

void handleStatusLed() {
    boolean keyPressed = false;

    for (byte i = 0; i < BUFFERS_SIZE; i++) {
        keyPressed = keyStates[i] || keyPressed;
    }

    digitalWrite(KEY_PRESSED_LED, keyPressed);
}

//---------------------------------------------------------
// multi-key callbacks
//---------------------------------------------------------

void homing(byte keyState) {
    if (keyState == KEY_STATE_PRESSED) {
        Keyboard.press(KEY_LEFT_CTRL);
        Keyboard.press(KEY_LEFT_ALT);
        Keyboard.press(KEY_HOME);
    } else {
        Keyboard.release(KEY_HOME);
        Keyboard.release(KEY_LEFT_ALT);
        Keyboard.release(KEY_LEFT_CTRL);
    }
}

void parking(byte keyState) {
    if (keyState == KEY_STATE_PRESSED) {
        Keyboard.press(KEY_LEFT_CTRL);
        Keyboard.press(KEY_LEFT_ALT);
        Keyboard.press('p');
    } else {
        Keyboard.release('p');
        Keyboard.release(KEY_LEFT_ALT);
        Keyboard.release(KEY_LEFT_CTRL);
    }
}

//---------------------------------------------------------
// main loop
//---------------------------------------------------------

void loop() {
    digitalWrite(HEARTBEAT_PIN, true);

    handleMultiKey(KEY_HOMING_PIN, homing);
    handleMultiKey(KEY_PARKING_PIN, parking);
    handleSingleKey(KEY_U_PIN, 'u');
    handleSingleKey(KEY_D_PIN, 'd');
    handleSingleKey(KEY_ARROW_LEFT_PIN, KEY_LEFT_ARROW);
    handleSingleKey(KEY_ARROW_RIGHT_PIN, KEY_RIGHT_ARROW);
    handleSingleKey(KEY_ARROW_UP_PIN, KEY_UP_ARROW);
    handleSingleKey(KEY_ARROW_DOWN_PIN, KEY_DOWN_ARROW);
    handleSingleKey(KEY_SHIFT_PIN, KEY_RIGHT_SHIFT);
    handleSingleKey(KEY_F11_PIN, KEY_F11);
    handleSingleKey(KEY_F12_PIN, KEY_F12);

    handleStatusLed();
    handleBeep();

    digitalWrite(HEARTBEAT_PIN, false);
    delayMicroseconds(855); // cca 1ms per loop
}
Bohužel to nefunguje zcela ideálně, nefungují modifikační klávesy (SHIFT, CTRL a ALT) :( Mezi Arduinem a Massem je zřejmě nějaká nekompatibilita (na PC či MACu funguje vše bez problémů). Osobně bych zkusil dotaz na MASSO support fóru, protože ale sám MASSO kontroler nemám a Modroš měl jiné starosti, nechali jsme to zatím být (postižená tlačítka jsou momentálně řešena přes fyzické IO, viz schema*).

Další možnost by byla použít modul ze skutečné USB klávesnice.

T.

* Tady možná trochu kecám, nevím úplně přesně, jak to má Modroš vyřešeno (motal jsem se jen kolem toho Arduina).
Naposledy upravil(a) Thomeeque dne 22. 11. 2021, 6:55, celkem upraveno 1 x.
mimooborová naplavenina • kolowratský zázrak™ • NPS • GCU • HirthCalc • ncDP.ino
Modros
Příspěvky: 1652
Registrován: 31. 3. 2019, 7:58

22. 11. 2021, 6:17

má je zapojené na IO vstupy místo ATC u kterého čekám na aktualizaci. Pokud zprovozníme ALT CTRL a SHIFT budu mít místo i na ATC a všechny blbosti co sem tam připojil...:)

při této konfiguraci jede pomocí šipek rovnou JOG RAPID aniž by byl použit SHIFT...záhada
Masso, stroje všemožný, autoservis, amatérské závody Nissan GTR
Uživatelský avatar
GeminiRacing
Příspěvky: 273
Registrován: 29. 11. 2011, 6:46
Bydliště: Trenčín - Slovakia
Kontaktovat uživatele:

22. 11. 2021, 7:53

jop, super, diky za nakopnutie :D 8)
Renault 5 Turbo in progress ;)

http://www.geminiracing.sk/" onclick="window.open(this.href);return false;
Odpovědět

Zpět na „Ostatní elektronika“