Arduino Mega 2560 pin mapping and protocol writing...

Hey all.

I recently purchased an Arduino Mega 2560 because I felt that my I/Os were limited on my Duemilanove. I did not realize that the StandardFirmata does not work with the Mega, rendering the additional pins 22-53 unusable unless I write my own protocol, from my understanding.

Previously, I loaded the StandardFirmata on the Duemilanove and hooked up a series of rotary encoders and a joystick on pins 1-12 to control a Processing sketch that I am working on. This worked fine until I reached a point when I wanted to add more rotary encoders and a button, but with no more digital pins available, I decided to purchase a Mega.

Now I'm at a bit of a loss as to how to read and write to the Mega from my Processing sketch. I browsed the web and found a few threads explaining how the StandardFirmata is not compatible with the Mega, and that the pin mapping of the Mega differs from that of the Duemilanove. I found the Mega pin chart, but I don't know if I need to write my own protocol in Arduino to handle my I/O, or if there is a way to read and write to a Mega directly in Processing. Again, there aren't many examples or substantial libraries that accomplish this from what I found.

Forgive me for asking this for what may seem like the thousandth time, but I am very new to the world of Arduino. To be clear, here are my questions. First, what are the options for more than 12 digital I/O pins with Arduino, or how is it possible with the Mega? Second, if I proceed with the Mega, what's a simple example of a digitalRead(), digitalWrite(), or otherwise on pins 22-53?

Thanks! :grin:
-Dahm

What is it you want Processing to be able to do? Turn digital pins on or off? Read digital pins? Read analog pins?

Do you need to deal with interrupts?

Is the Arduino going to be doing anything on its own, or is it just going to do what Processing tells it to do?

What in the communication between Processing and the Arduino involves pin mapping?

Hi Paul.

Thanks for the response.

I simply need Processing to turn pins on and off and to read digital pins. I'm not dealing with anything analog or interrupts at the moment. The Arduino doesn't do anything on it's own. I'm simply making a video game controller of sorts to control Processing directly.

In Processing, I define the pins as integers, and then run those through the arduino.digitalRead(pin#) method in draw() to detect changes and interaction with the knobs, buttons, and joystick. I haven't modified any pin mapping between Arduino and Processing, but I'm simply wondering how it's done. For instance, if I'm running a simple push-button LED light script in Processing, and my button is grounded and plugged in to pin #22, how do I get Processing to read it?

-Dahm

If Processing were to send something like "<R,14>", the Arduino could run code like this:

#define SOP '<'
#define EOP '>'

bool started = false;
bool ended = false;

char inData[80];
byte index;

void setup()
{
   Serial.begin(57600);
   // Other stuff...
}

void loop()
{
  // Read all serial data available, as fast as possible
  while(Serial.available() > 0)
  {
    char inChar = Serial.read();
    if(inChar == SOP)
    {
       index = 0;
       inData[index] = '\0';
       started = true;
       ended = false;
    }
    else if(inChar == EOP)
    {
       ended = true;
       break;
    }
    else
    {
      if(index < 79)
      {
        inData[index] = inChar;
        index++;
        inData[index] = '\0';
      }
    }
  }

  // We are here either because all pending serial
  // data has been read OR because an end of
  // packet marker arrived. Which is it?
  if(started && ended)
  {
    // The end of packet marker arrived. Process the packet

    // Reset for the next packet
    started = false;
    ended = false;
    index = 0;
    inData[index] = '\0';
  }
}

Where it says "Process the packet", inData would contain "R,14". The strtok() function could get the two tokens, "R" and "14", and convert the second one to an int. Then, it could read pin 14, and send a response.

You could have other commands, like "<W,35,0>" to write a 0 to pin 35, or "<M,22,I>" to set the mode of pin 22 to INPUT. Defining a protocol is relatively simple. Implementing it isn't all that challenging, either, for simple things.

If the encoder generates a lot of pulse close together, so that you need to use interrupts to deal with all the pulses, then reading the encoder value requires another command, and the value that was returned might be old before the transmission was complete.

Thanks Paul.

That gives me somewhere to start, although I'm still having issues because my Processing sketch is massive. Let's use the basic code below as a simple example instead. How do I detect a button push on pin 22 and have Processing call "runThisMethod();"? From what you are describing, it sounds like all of my reads and writes are handled on the Arduino side of things, when in reality, I want to call methods within my Processing sketch as changes are made to what's hooked up to the Arduino board. Maybe my initial description was unclear, and if so, I apologize. StandardFirmata works perfectly on the Mega with my inputs for 1-12, but I feel like I need to modify the code to account for the remaining pins.

-Dahm

PROCESSING CODE
Simple pushbutton script:

import processing.serial.*;
import cc.arduino.*;

Arduino arduino;

int button = 22; //Ideally I want this to be digital pin 22 on the Mega 
int ledPin = 13; 
int buttonState = 1; 

void setup() 
{
  size(400, 400);
  arduino = new Arduino(this, Arduino.list()[0], 57600);

  //Button init
  arduino.pinMode(button, Arduino.INPUT);
  arduino.digitalWrite(button, Arduino.HIGH);

  //LED init
  arduino.pinMode(ledPin, Arduino.OUTPUT);
}

void draw() 
{
  // read the state of the pushbutton value:
  buttonState = arduino.digitalRead(button);

  // check if the pushbutton is pressed.
  // if it is, the buttonState is HIGH:
  if (buttonState == Arduino.LOW) 
  {     
    // turn LED on:    
    arduino.digitalWrite(ledPin, Arduino.HIGH);
    runThisMethod();
  } 

  else 
  {
    // turn LED off:
    arduino.digitalWrite(ledPin, Arduino.LOW);
  }
}

How do I detect a button push on pin 22 and have Processing call "runThisMethod();"?

Using that code? You can't. It assumes that you have Firmata installed on the Arduino, which, as you;ve noted, is not a good fit with the Mega.

Thanks again Paul.

Of course the script wouldn't work... it was a crude example showing what I might expect a portion of the Processing code to execute. This seems to be the crux of my issue. I don't know how to ask the question any other way. With what code is this possible?

How do I use Processing to read a signal on pin X (22, in this hypothetical) that isn't already in the StandardFirmata? Again, I think this involves PaulS's suggestion of writing my own protocol for the Mega. How this interfaces with Processing is critical because that is where the events occur. If this is possible all in Processing, that's fine too.

-Dahm

How do I use Processing to read a signal on pin X (22, in this hypothetical) that isn't already in the StandardFirmata?

Simple. Ditch the reliance on Firmata. Develop your own functions in Processing and on the Arduino to send and receive commands that match your protocol.

Hey Paul.

Here's what I have so far. The light turns on and off with a button on pin 22! $)

Have a look at the sends on the Arduino side of things and tell me what the best practice is for writing changes to serial for Processing to read. Is it best to choose arbitrary numbers or strings in Arduino and then redefine them locally as I'm doing?

The println sending my turnCount variable to the Processing console text area doesn't seem to update every full turn. Maybe there are some tweaks to the code that can fix this.

-Dahm

ARDUINO

#define Input 22                 
#define Output 13               

#define Rotary1U 2
#define Rotary1D 3
#define Rotary1B 4

char InByte ;                    

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

  #ifdef Output
    pinMode(Output, OUTPUT);       
  #endif
  
  #ifdef Input
    pinMode(Input, INPUT);         
    digitalWrite(Input, HIGH);     
  #endif 
 
  #ifdef Rotary1U
    pinMode(Rotary1U, INPUT);         
    digitalWrite(Rotary1U, HIGH);     
  #endif  
 
  #ifdef Rotary1D
    pinMode(Rotary1D, INPUT);       
    digitalWrite(Rotary1D, HIGH);   
  #endif  
  
  #ifdef Rotary1B
    pinMode(Rotary1B, INPUT);       
    digitalWrite(Rotary1B, HIGH);     
  #endif    

  delay(2000) ;
}

void loop() 
{  
  #ifdef Output
    while (Serial.available() > 0) 
    { 
      InByte = Serial.read();
      
      if (InByte == 'u') 
      {           
        digitalWrite(Output, HIGH);
      }
      
      if (InByte == 'd') 
      {           
        digitalWrite(Output, LOW) ; 
      }
    }
  #endif
  
  #ifdef Input
    if (digitalRead(Input) == HIGH) 
    {
      Serial.write('u');       // If switch is open/high send "u" to Processing
    } 
    else 
    {     
      Serial.write('d');       // else switch is closed/low, send "d" to Processing
    }
  #endif

  #ifdef Rotary1U
    if (digitalRead(Rotary1U) == HIGH) 
    {
      Serial.write(2);      
    } 
    else 
    {     
      Serial.write(3);       
    }
  #endif
  
  #ifdef Rotary1D
    if (digitalRead(Rotary1D) == HIGH) 
    {
      Serial.write(4);       
    } 
    else 
    {     
      Serial.write(5);      
    }
  #endif  
  
  #ifdef Rotary1B
    if (digitalRead(Rotary1B) == HIGH) 
    {// test switch
      Serial.write(1);       
    } 
    else 
    {     
      Serial.write(0);      
    }
  #endif  
  
  delay(125);                      // EigthSecond updates
}

PROCESSING

import processing.serial.*;    

final String test = "Both"; 

Serial port; 

int val1, val2 = 0;
int val3 = 1; 

int oldVal1 = 0, oldVal2 = 0;
int rotPos = 0, rotOldPos = 0;
int turn = 0, oldTurn = 0, turnCount=0;

void setup()  
{
  size(400, 400);    
  port = new Serial(this, Serial.list()[1], 9600); 

}

void draw() 
{ 
  int inChar;
  if ( test.equals("Input") || test.equals("Both") ) 
  {
    while ( port.available () > 0) 
    {
      inChar = port.read();       
 
      if (inChar == 'u') 
      {         
        fill(50);                   
        port.write('d'); 
        rect( width/2, 0, width/2, height);
      }

      if (inChar == 'd') 
      {        
        fill(200);                  
        port.write('u'); 
        rect( width/2, 0, width/2, height);
      }
      
      int valX = port.read();
      
      if (valX ==2)
        val1=0;
      else if(valX == 3)
        val1=1;
        
      else if(valX == 4)
        val2=0;
      else if(valX == 5)
        val2=1;   

      val3 = port.read();
      
//      println("Val1:  "+val1+",  Val2:  "+val2);
      
      if (val3 == 0 )
      {
        println("WOO!");
      }

      // Detect changes
      if ( val1 != oldVal1 || val2 != oldVal2) 
      {
        //for each pair there's a position out of four
        if      ( val1 == 1 && val2 == 1 ) // stationary position
          rotPos = 0;
        else if ( val1 == 0 && val2 == 1 )
          rotPos = 1;
        else if ( val1 == 0 && val2 == 0 )
          rotPos = 2;
        else if ( val1 == 1 && val2 == 0 )
          rotPos = 3;

        turn = rotPos-rotOldPos;

        if (abs(turn) != 2) // impossible to understand where it's turning otherwise.
        {
          if (turn == -1 || turn == 3)
          {
            turnCount++;
          }
          else if (turn == 1 || turn == -3)
          {
            turnCount--;
          }
        }  

        if (rotPos == 0) 
        { // only assume a complete step on stationary position
          if (turnCount > 0)
          {
            println(turnCount+"   <");
          }
          else if (turnCount < 0)
          {
            println("    >  "+turnCount);
          }

          turnCount=0;
        }

        oldVal1 = val1;
        oldVal2 = val2;
        rotOldPos  = rotPos;
        oldTurn = turn;
      }
    }
  }
}