MEGA communication problem, but Duemilanove works

I've been stuck for far too long on this issue. The code below works perfectly on the Duemilanove but fails on the MEGA.

I am trying to communicate between an Arduino MEGA and a Touchshield slide. I have no problems at all sending from the MEGA to the Touchshield, but I cannot get data from the Touchshield to the MEGA. The exact same code works quite well for communication in both directions on multiple Duemilanove boards.

I've simplified my code to almost the bare minimum. I send the integer touch position on the Touchshield to the Arduino, send that information back to the Touchshield, and display the result.

I've tried both SoftwareSerial and NewSoftSerial, so there is some excess code due to that.

Any ideas on how to get the Touchshield to send data to the Arduino MEGA? I've tried many sample programs and they all fail.

Arduino code:

// Code for Arduino           

//#include <SoftwareSerial.h>
#include <NewSoftSerial.h>

#define RX_PIN 3 // Touchshield slide receiving pin
#define TX_PIN 2 // Touchshield slide transmission pin

//SoftwareSerial mySerial = SoftwareSerial(RX_PIN, TX_PIN);
NewSoftSerial mySerial = NewSoftSerial(RX_PIN, TX_PIN);

const char SignalStart = '*'; // The '*' is the signal that a new integer is now being passed
const char SignalStop = '!'; // The '!' is the signal that a new integer is done being passed

void setup() {
  pinMode(RX_PIN, INPUT); // This is absolutely critical if using SoftwareSerial for communications
  pinMode(TX_PIN, OUTPUT); // This is absolutely critical if using SoftwareSerial for communications
  mySerial.begin(9600); // Start communications with the Touchshield
}

void loop() {
  CommunicateRead(); // Look for a signal that was sent from the TouchShield Slide
}

void CommunicateRead() {
  static int SentData; // The integer read from the communications link
  static int LastSentData; // The previous integer read from the communications link
  static int i = 0; // A counter to prevent too many digits in the integer that is being passed
  char charIn = 0; // This is the character that was sent from the Touchshield board
  
  charIn = mySerial.read();
  if (charIn == SignalStart) { // A new integer has been passed
    SentData = 0;
    i = 0;
  }
  else if (charIn == SignalStop && SentData != LastSentData) { // The '!' is the signal that the integer is done being passed.  The second check is to prevent multiple sendings of the same data to the Touchshield.
    if (SentData > 500) SentData = 0; // Correction factor for the Touchshield which can occasionally get negative touch position numbers
    mySerial.print(SignalStart); // The SignalStart is the signal that a new integer is being passed.
    mySerial.print(SentData,DEC); // Send the integer that was received.  Any delay causes big communication problems here.
    mySerial.print(SignalStop); // The SignalStop is the signal that the integer is done being passed.
    LastSentData = SentData; // Store the data so that this message isn't repeatedly sent
  }
  else if (charIn > 47 && charIn < 58) { // The numbers 48 through 57 represent ASCII characters for the integers 0 through 9
    i++;
    if (i <= 3) SentData=SentData * 10 + charIn - 48; // The -48 adjusts from ASCII to integers.
  }
}

Touchshield code:

// Code for Touchshield

const char SignalStart = '*'; // The '*' is the signal that a new integer is being passed
const char SignalStop = '!'; // The '!' is the signal that a new integer is done being passed

void setup() {
  Serial.begin(9600); // Start communications with the Arduino board over Arduino pins 2 and 3
} // End of setup()

void loop() { 
  unsigned int Xstore = 1; // Mouse X position is stored here
  unsigned int Ystore = 1; // Mouse Y position is stored here

  gettouch(); // Find the pixel location where the user pressed and store it into mouseX and mouseY

  if ( mouseX != Xstore || mouseY != Ystore ) { // Only update when there was an actual touch 
    Xstore = mouseX; // Store previous position of the touch
    Ystore = mouseY; // Store previous position of the touch

    text(Xstore,0,0); text(Ystore,150,0); // Print the touch location on the screen
     
    Serial.print(SignalStart); // The '*' is the signal that a new integer is being passed

// The following code is for the SoftwareSerial version only.
   
//  int DigitHundreds = 0; // The hundreds digit in the integer
//  int DigitTens = 0; // The tens digit in the integer
//  int DigitOnes = 0; // The ones digit in the integer
//  DigitHundreds = int(mouseX / 100);
//  DigitTens = int((mouseX - DigitHundreds * 100) / 10);
//  DigitOnes = int(mouseX - DigitHundreds * 100 - DigitTens * 10);
//  const int SignalDelay = 10; // This delay helps send signals properly to the Arduino board when using SoftwareSerial instead of NewSoftSerial
//  delay(SignalDelay); // This delay helps send signals properly to the Arduino board when using SoftwareSerial instead of NewSoftSerial
//  Serial.print(DigitHundreds);
//  delay(SignalDelay); // This delay helps send signals properly to the Arduino board when using SoftwareSerial instead of NewSoftSerial
//  Serial.print(DigitTens);
//  delay(SignalDelay); // This delay helps send signals properly to the Arduino board when using SoftwareSerial instead of NewSoftSerial
//  Serial.print(DigitOnes);
//  delay(SignalDelay); // This delay helps send signals properly to the Arduino board when using SoftwareSerial instead of NewSoftSerial

    Serial.print(Xstore); // This works for the NewSoftSerial command but not the SoftwareSerial command
    Serial.print(SignalStop); // The '!' is the signal that the integer is done being passed
  } 
  // delay(100); // Give time for the Arduino to respond when using SoftwareSerial instead of NewSoftSerial
  CommunicateRead(); // Look for a signal that was sent from the Arduino board
} // End of loop()

void CommunicateRead()
{
  char charIn = 0; // This is the character that was sent from the Arduino board
  static boolean StopReading = false; // This is a signal to ignore any other characters sent until the new integer signal is sent
  static int SentData; // The integer read from the communications link

  while(Serial.available()) { // Monitor serial buffer of TouchShield, keep going if there is any new data
    charIn = Serial.read();
    if (charIn == SignalStart) { // The '*' is the signal that a new integer is being passed
      SentData = 0; // Reset the integer reader
      StopReading = false; // Allow data to be recorded
    }
    else if (charIn == SignalStop) { // The '!' is the signal that the integer is done being passed
      StopReading = true; // All other data is ignored until the new integer signal is passed
      text(SentData, 100, 100); // Display the number that was sent
    }
    else if (charIn > 47 && charIn < 58 && StopReading == false) SentData = SentData * 10 + charIn - 48; // The numbers 48 through 57 represent ASCII characters for the integers 0 through 9.  The -48 adjusts from ASCII to integers.
  }
} // End of CommunicateRead()

last I knew newsoftserial didn't support the Mega.

The Mega, however, has 4 hardware serial ports.

Richard Crowley:

Here are the symptoms with that code:

  1. Anything that I send from the Arduino boards to the Touchshield seems to work. Thus, if I send "123" from either the MEGA or the Duemilanove, then the Touchshield will recieve it and display "123" on the screen.

  2. Anything that I send from the Touchshield to the Duemilanove seems to work. Thus if I send "456" from the Touchshield to the Duemilanove, then I can use the Duemilanove to work with that integer. I can use that integer to change the speed of a motor, to do math, or to send back to the Touchshield (which correctly displays "456").

  3. When I send anything from the Touchshiled to the MEGA, nothing works. At least, nothing that I can see so far. The MEGA ususally sits there acting like it never recieved any data. Occasionally, depending on how I tweak the code, the MEGA might get some data, but it is completely random. Instead of receiving "456" it might get "K&~" one time and "7(z" the next time. I cannot use that to control a motor, to do math, or to send back to the MEGA (at least with that code).

I have tried using the MEGA to talk with a computer over the USB port. That communication works flawlessly in either direction. But, the USB port uses pins 0 and 1, while the code (and PCBs like the Touchshield) use pins 2 and 3.

jrraines:

Thanks. It looks like it will send data, but not receive it. The webpage here: NewSoftSerial | Arduiniana says that it will support the MEGA, but not yet. Ok, at least that is the cause of the problem.

But, will anything else support communication from the MEGA over pins 2 and 3? The built in serial communication won't, SoftwareSerial won't and it looks like NewSoftSerial doesn't (at least not now).

I could try crossing pins around (such as hardwire pins 14 and 15 instead of 2 and 3). I'll see if I can get that working, but that seems quite a pain for each new PCB (especially for shields and other things that I don't make myself).

Is your problem that you want the same code to run on both a Duemilanove and a Mega?

If so and the above libraries don't work why not just have some preprocessor conditional blocks to swap a few definitions?


Rob

Graynomad suggests exactly what I am doing. You have 3 more hardware serial ports on the MEGA at your disposal. I am using some nearly identical GPS code on a MEGA and on a Pro Mini, but the Pro Mini uses NSS to read the GPS while the Mega has it on Rx1. #define GPSSer to either be Serial1 or your NSS object variable depending on which you are building for.

Graynomad and arbarnhart,

Thanks for the replies.

Graynomad, you are close, but have what I want backwards. I want the same hardware to work on both the Duemilanove (it already does) and the Mega. I don't care what the software has to do, if a software change is all that is needed.

I'm not a highly skilled programmer. Can you point me to examples of swapping definitions? I have many different boards (custom that with money I could change and aftermarket that for the most part are unchangeable) that work with communication on pins 2/3 on the Duemilanove. The Mega (by default) won't communicate on those pins (its communication pins are 0, 1, and 14-21).

Here is a snippet from my actual MEGA code:

#define GPSSer Serial1  

void setup()
{
    GPSSer.begin(4800);

Here is some code for the Pro Mini:

NewSoftSerial GPSSer (2,3);

void setup()   
{
  GPSSer.begin(4800);

that code is different, but then in another part that I share, I do stuff like this:

#include <TinyGPS.h>

TinyGPS oGPS;  // TinyGPS is an object library that decodes NMEA strings and stores tbe data in an object

// in our loop funtion, all we do is check for data and ask TinyGPS to process it if there is any
void GPS_Loop()
{
  // see if there's incoming serial data:
  while (GPSSer.available() > 0) 
   {
     int inByte;
    // read the oldest byte in the serial buffer:
    inByte = GPSSer.read();
   oGPS.encode(inByte);
   }
}

Note - by "share" I mean copying the file (a secondary tab in the projects) between projects or copying and pasting changes, not using a library.

This is the sort of thing I've done in the past

#define __MEGA__


void mySendSerial (byte c) {

#ifdef __MEGA__
  // code to handle the Mega
  Serial2.print(c);
#else
  // code to handle the UNO
  NewSoftSerialObject.print(c);
#endif
}


void setup() {}

void loop () {
  mySendSerial ("A");
}

NOTE: Untested and doesn't compile as is, but that's the idea.


Rob