Reading 8 buttons and 1 joystick Arduino to max

R_Gol's icon

What will be the best way of doing the above and receiving the data inside max?

here is my Arduino code:

const int numButtons = 8;
const int buttonPins[numButtons] = {2, 3, 4, 5, 6, 7, 8, 9};

const int joyX = A0;
const int joyY = A1;
const int joyButton = 10;

const unsigned long debounceDelay = 20;  // Debounce time in ms
unsigned long lastDebounceTime[numButtons] = {0};
int buttonStates[numButtons] = {1};  // Default HIGH (INPUT_PULLUP)
int lastButtonStates[numButtons] = {1}; 

unsigned long lastReadTime = 0;
const unsigned long readInterval = 50;  // Read every 50ms

void setup() {
    Serial.begin(115200);

    for (int i = 0; i < numButtons; i++) {
        pinMode(buttonPins[i], INPUT_PULLUP);
    }
    pinMode(joyButton, INPUT_PULLUP);
}

void loop() {
    unsigned long currentMillis = millis();

    // Read Buttons with Debounce
    for (int i = 0; i < numButtons; i++) {
        int reading = digitalRead(buttonPins[i]);
        
        if (reading != lastButtonStates[i]) {
            lastDebounceTime[i] = currentMillis;
        }

        if ((currentMillis - lastDebounceTime[i]) > debounceDelay) {
            buttonStates[i] = reading;
        }
        
        lastButtonStates[i] = reading;
    }

    // Read and Send Data at Interval
    if (currentMillis - lastReadTime >= readInterval) {
        lastReadTime = currentMillis;

        // Read Joystick
        int xVal = analogRead(joyX);
        int yVal = analogRead(joyY);
        int joyBtnState = digitalRead(joyButton);

        // Send data to Max/MSP
        Serial.print("B ");  // Identifier for buttons
        for (int i = 0; i < numButtons; i++) {
            Serial.print(buttonStates[i]);
            Serial.print(" ");
        }

        Serial.print("J ");  // Identifier for Joystick
        Serial.print(xVal);
        Serial.print(" ");
        Serial.print(yVal);
        Serial.print(" ");
        Serial.println(joyBtnState);
    }
}

how can I unpack this data inside max?

Source Audio's icon

print ID for each element followed by it's value.

for example if you use for loop to read 8 buttons, then first

print i , then space followed by button readout.

then use route 0 1 2 3 4 5 6 7 in max to output 8 buttons

for (int i = 0; i < 8; i++) {
Serial.print(i); Serial.print(" "); Serial.println(buttonStates[i]);
        }
R_Gol's icon

print ID for each element followed by it's value.

ID you mean for each button? for example A B C D E F G H

and for each pot: X and Y ?

I should use the built in pull-up resistor for buttons right?

and if debounce is needed - better doing it inside Arduino then in Max?

R_Gol's icon

Here is my Arduino latest code:

const int numButtons = 8;
const int buttonPins[numButtons] = {2, 3, 4, 5, 6, 7, 8, 9};
const char buttonIDs[numButtons] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'};

const int joyX = A0;
const int joyY = A1;
const int joyButton = 10;

const unsigned long debounceDelay = 20;  // Debounce time in ms
unsigned long lastDebounceTime[numButtons] = {0};
int buttonStates[numButtons];  // Default HIGH (INPUT_PULLUP)
int lastButtonStates[numButtons];

unsigned long lastReadTime = 0;
const unsigned long readInterval = 50;  // Read every 50ms

// Joystick filtering
const int threshold = 10;  // Minimum change required to send new data
int lastXVal = 0;
int lastYVal = 0;
int lastJoyBtnState = HIGH;

void setup() {
    Serial.begin(115200);

    for (int i = 0; i < numButtons; i++) {
        pinMode(buttonPins[i], INPUT_PULLUP);
        buttonStates[i] = HIGH;  // Initialize to HIGH
        lastButtonStates[i] = HIGH;
    }

    pinMode(joyButton, INPUT_PULLUP);
    lastXVal = analogRead(joyX);
    lastYVal = analogRead(joyY);
    lastJoyBtnState = digitalRead(joyButton);
}

void loop() {
    unsigned long currentMillis = millis();
    
    // Read Buttons with Debounce
    for (int i = 0; i < numButtons; i++) {
        int reading = digitalRead(buttonPins[i]);
        
        if (reading != lastButtonStates[i]) {
            lastDebounceTime[i] = currentMillis;
        }

        if ((currentMillis - lastDebounceTime[i]) > debounceDelay) {
            if (buttonStates[i] != reading) {
                buttonStates[i] = reading;
                Serial.print(buttonIDs[i]);  // Print button ID
                Serial.print(" ");
                Serial.println(!reading);  // Print 1 for pressed, 0 for released
            }
        }
        
        lastButtonStates[i] = reading;
    }

    // Read Joystick
    int xVal = analogRead(joyX);
    int yVal = analogRead(joyY);
    int joyBtnState = digitalRead(joyButton);

    // Check if joystick values changed beyond threshold
    if (abs(xVal - lastXVal) > threshold) {
        Serial.print("X ");
        Serial.println(xVal);
        lastXVal = xVal;
    }

    if (abs(yVal - lastYVal) > threshold) {
        Serial.print("Y ");
        Serial.println(yVal);
        lastYVal = yVal;
    }

    if (joyBtnState != lastJoyBtnState) {
        Serial.print("J ");
        Serial.println(!joyBtnState);
        lastJoyBtnState = joyBtnState;
    }
}

I print each value independetly.

For some reason I don't get the data inside max. Here is my patch:

Max Patch
Copy patch and select New From Clipboard in Max.

R_Gol's icon

I try to add the dtr 1 message to the serial object and this not solved the problem.

I'm using Arduino Uno, Max 8.6.2, Mac M1 Pro Sonoma 14.5

edit: I needed to close arduino, now everything is working as expected

Source Audio's icon

with IDs I meant count which you have anyway when scanning buttons.

I posted it in my first reply.

You add so many unneeded declarations .