Go Down

Topic: Arduino MEGA behaving differently to Diecimila (Read 701 times) previous topic - next topic

niknak

I just got my new Arduino Mega to take advantage of the extra capabilities. I have upgraded to Arduino IDE 0015 and the IDE is set up correctly for the MEGA board.

I am building a GPS/compass unit using the GPS shield from Adafruit, a HMC6352 digital compass module and a 4x20 LCD with the LCD117 interface board from moderndevice.com

My code is working great on the Diecimila - compass works great, GPS is fine and the LCD displayss the correct output.

BUT - if I upload the sketch to the MEGA (upload is fine) and then try the MEGA (using the exact same pins on the GPS shield) then it doesn't work!!!

With the MEGA my sketch runs the "void setup()" function and then seems to die - it doesn't appear to enter the "void loop()".

Am I doing something wrong? Is this a known problem?

Here's my sketch - still a work in progress - if it'll help:

Code: [Select]
#include <SoftwareSerial.h>
#include <NewSoftSerial.h>
#include <Stdio.h>
#include <Wire.h>

// LCD variables
#define LcdRxPin 13  // LcdRxPin is immaterial - not used - just make this an unused Arduino pin number
#define LcdTxPin 3
SoftwareSerial LcdSerial =  SoftwareSerial(LcdRxPin, LcdTxPin);
// end LCD variables

// GPS variables
NewSoftSerial GpsSerial =  NewSoftSerial(0, 1);
#define GpsPwrPin 2
#define GPSRATE 4800
// GPS parser for 406a
#define BUFFSIZ 90 // plenty big
char buffer[BUFFSIZ];
char *parseptr;
char buffidx;
uint8_t hour, minute, second, year, month, date;
uint32_t latitude, longitude;
uint8_t groundspeed, trackangle;
char latdir, longdir;
char status;
// end GPS variables

// compass variables
int compassAddress = 0x42 >> 1;
int compassHeading;

int compassSWpin=4;
int compassWpin=5;
int compassNWpin=6;
int compassNpin=7;
int compassNEpin=8;
int compassEpin=9;
int compassSEpin=10;
int compassSpin=11;
// end compass variables

// initialise LCD
void initLcd(){
 pinMode(LcdTxPin, OUTPUT);
 LcdSerial.begin(9600);    // 9600 baud is chip comm speed
 LcdSerial.print("?G420");
 delay(100);                 // pause to allow LCD EEPROM to program
 LcdSerial.print("?Bff");  // set backlight to 40 hex
 delay(100);              // pause to allow LCD EEPROM to program
 LcdSerial.print("?s6");   // set tabs to six spaces
 delay(1000);              // pause to allow LCD EEPROM to program
/*  LcdSerial.print("?D0040E150404000000"); // N arrow
 delay(200);
 LcdSerial.print("?D10F03050910000000"); // NE arrow
 delay(200);
 LcdSerial.print("?D20004021F02040000"); // E arrow
 delay(200);
 LcdSerial.print("?D3000000100905030F"); // SE arrow
 delay(200);
 LcdSerial.print("?D40000000404150E04"); // S arrow
 delay(200);
 LcdSerial.print("?D5000000011214181E"); // SW arrow
 delay(200);
 LcdSerial.print("?D60004081F08040000"); // W arrow
 delay(200);
 LcdSerial.print("?D71E18141201000000"); // NW arrow
 delay(200);
*/
 LcdSerial.print("?c0");                            // turn cursor off
 delay(200);  
 LcdSerial.print("?f");                   // clear the LCD
 delay(1000);
 LcdSerial.print("?x00?y0");
 delay(100);
 LcdSerial.print("    LCD Ready...");
 delay(500);
}

// initialise GPS
void initGps(){
 if (GpsPwrPin) {
   pinMode(GpsPwrPin, OUTPUT);
 }
 pinMode(13, OUTPUT);
 GpsSerial.begin(GPSRATE);
 
 digitalWrite(GpsPwrPin, LOW);         // pull low to turn on!

 LcdSerial.print("?x00?y1");
 delay(100);
 LcdSerial.print("    GPS Ready...");
 delay(500);
}

void initCompass(){
 // this for debugging the data
 //Serial.begin(9600);
 // set up
 CLKPR = (1<<CLKPCE);
 CLKPR = 0;
 // initialize the HMC6352
 Wire.begin(); // join i2c bus (compassAddress optional for master)
 
 //
 pinMode(compassSWpin, OUTPUT);
 pinMode(compassWpin, OUTPUT);
 pinMode(compassNWpin, OUTPUT);
 pinMode(compassNpin, OUTPUT);
 pinMode(compassNEpin, OUTPUT);
 pinMode(compassEpin, OUTPUT);
 pinMode(compassSEpin, OUTPUT);
 pinMode(compassSpin, OUTPUT);
 LcdSerial.print("?x00?y2");
 delay(100);
 LcdSerial.print("  Compass Ready...");
 delay(500);
}

// setup
void setup(){
 initLcd();
 delay(1000);
 initGps();
 delay(1000);
 initCompass();
 delay(2000);
}

// main
void loop()
{
 uint32_t tmp;
 
 readline();
 
 // check if $GPRMC (global positioning fixed data)
 if (strncmp(buffer, "$GPRMC",6) == 0) {
   
   // hhmmss time data
   parseptr = buffer+7;
   tmp = parsedecimal(parseptr);
   hour = tmp / 10000;
   minute = (tmp / 100) % 100;
   second = tmp % 100;
   
   parseptr = strchr(parseptr, ',') + 1;
   status = parseptr[0];
   parseptr += 2;
   
   // grab latitude & long data
   // latitude
   latitude = parsedecimal(parseptr);
   if (latitude != 0) {
     latitude *= 10000;
     parseptr = strchr(parseptr, '.')+1;
     latitude += parsedecimal(parseptr);
   }
   parseptr = strchr(parseptr, ',') + 1;
   // read latitude N/S data
   if (parseptr[0] != ',') {
     latdir = parseptr[0];
   }
   
   // longitude
   parseptr = strchr(parseptr, ',')+1;
   longitude = parsedecimal(parseptr);
   if (longitude != 0) {
     longitude *= 10000;
     parseptr = strchr(parseptr, '.')+1;
     longitude += parsedecimal(parseptr);
   }
   parseptr = strchr(parseptr, ',')+1;
   // read longitude E/W data
   if (parseptr[0] != ',') {
     longdir = parseptr[0];
   }
   

   // groundspeed
   parseptr = strchr(parseptr, ',')+1;
   groundspeed = parsedecimal(parseptr);

   // track angle
   parseptr = strchr(parseptr, ',')+1;
   trackangle = parsedecimal(parseptr);


   // date
   parseptr = strchr(parseptr, ',')+1;
   tmp = parsedecimal(parseptr);
   date = tmp / 10000;
   month = (tmp / 100) % 100;
   year = tmp % 100;
   
   LcdSerial.print("?f");
   LcdSerial.print("?x00?y0");
   char datetime[17];
   sprintf(datetime,"%02d/%02d/%02d %02d:%02d:%02d",date,month,year,hour,minute,second);
   LcdSerial.print(datetime);
   
   LcdSerial.print("?x00?y1");
   //char latitude[13];
   //sprintf(latitude,"%s %02do%02d'%2d.$2d\"",latdir,
   LcdSerial.print(latdir);
   LcdSerial.print(' ');
   LcdSerial.print(latitude/1000000, DEC);
   LcdSerial.print("o");
   LcdSerial.print((latitude/10000)%100, DEC);
   LcdSerial.print('\'');
   LcdSerial.print((latitude%10000)*6/1000, DEC);
   LcdSerial.print('.');
   LcdSerial.print(((latitude%10000)*6/10)%100, DEC);
   LcdSerial.print('"');
 
   LcdSerial.print("?x00?y2");
   LcdSerial.print(longdir);
   LcdSerial.print(' ');
   LcdSerial.print(longitude/1000000, DEC);
   LcdSerial.print("o");
   LcdSerial.print((longitude/10000)%100, DEC);
   LcdSerial.print('\'');
   LcdSerial.print((longitude%10000)*6/1000, DEC);
   LcdSerial.print('.');
   LcdSerial.print(((longitude%10000)*6/10)%100, DEC);
   LcdSerial.print('"');
   
   Wire.beginTransmission(compassAddress);
   Wire.send('A');
   Wire.endTransmission();
   delay(10);
   Wire.requestFrom(compassAddress, 2);

   if(2 <= Wire.available())    // if two bytes were received
   {
     compassHeading = Wire.receive();  // receive high byte (overwrites previous compassHeading)
     compassHeading = compassHeading << 8;    // shift high byte to be high 8 bits
     compassHeading += Wire.receive(); // receive low byte as lower 8 bits
     compassHeading /= 10;
     lightNorth(compassHeading);
     //Serial.println(compassHeading);   // print the compassHeading
   }
 }
}


uint32_t parsedecimal(char *str) {
 uint32_t d = 0;
 
 while (str[0] != 0) {
  if ((str[0] > '9') || (str[0] < '0'))
    return d;
  d *= 10;
  d += str[0] - '0';
  str++;
 }
 return d;
}

void readline(void) {
 char c;
 
 buffidx = 0; // start at begninning
 while (1) {
     c=GpsSerial.read();
     if (c == -1)
       continue;
     //Serial.print(c);
     if (c == '\n')
       continue;
     if ((buffidx == BUFFSIZ-1) || (c == '\r')) {
       buffer[buffidx] = 0;
       return;
     }
     buffer[buffidx++]= c;
 }
}

void lightNorth(int compassHeading){
 digitalWrite(compassSWpin, LOW);
 digitalWrite(compassWpin, LOW);
 digitalWrite(compassNWpin, LOW);
 digitalWrite(compassNpin, LOW);
 digitalWrite(compassNEpin, LOW);
 digitalWrite(compassEpin, LOW);
 digitalWrite(compassSEpin, LOW);
 digitalWrite(compassSpin, LOW);
 if ((compassHeading>=338 && compassHeading<=360) || (compassHeading>=0 && compassHeading<23))
   digitalWrite(compassNpin, HIGH);
 else if (compassHeading>=23 && compassHeading<68)
   digitalWrite(compassNEpin, HIGH);
 else if (compassHeading>=68 && compassHeading<113)
   digitalWrite(compassEpin, HIGH);
 else if (compassHeading>=113 && compassHeading<158)
   digitalWrite(compassSEpin, HIGH);
 else if (compassHeading>=158 && compassHeading<203)
   digitalWrite(compassSpin, HIGH);
 else if (compassHeading>=203 && compassHeading<248)
   digitalWrite(compassSWpin, HIGH);
 else if (compassHeading>=248 && compassHeading<293)
   digitalWrite(compassWpin, HIGH);
 else if (compassHeading>=293 && compassHeading<338)
   digitalWrite(compassNWpin, HIGH);
}

etracer

The I2C pins are in a different location on the Mega. On a standard Arduino they're on Analog 4 & 5, on the Mega they're on digital 20 & 21. If you change your connections to the HMC6352 you'll probably be good.

Another possible problem: Why are you using pins 0 & 1 for your NewSoftSerial connection? Those are the hardware serial pins. I can imagine all kinds of bad interactions trying to use these pins for a non-hardware based serial.

niknak

Thanks for the pointers on the pins - the compass module works fine on the MEGA pins 20 and 21.

And the 0 and 1 pins I forgot to change to 3 and 4 after I finished testing the GPS shield with the Arduino onboard FTDI connection  ::)

But the project still doesn't work properly - I *think* the NewSoftSerial library is not compatible with the Arduino Mega yet - the author had to release a new version when the Atmega 328 chips  started appearing in Arduinos. I'm sure an update for MEGA support will be coming soon.

Thanks for the help.

jpgr87

The MEGA has 4 hardware serial ports, why not use one of those instead of the NewSoftSerial port?

niknak

Quote
why not use one of those instead of the NewSoftSerial port?


Basically... because I'm a newb  :-[. And I've largely been relying on pasting together bits of other people's code so far.

But again, thanks for the pointer!

I always avoided the hardware serial port on the Diecimila because it's also connected to the FTDI. I didn't realize that the additional UARTS on the MEGA are separate from the FTDI chip.

I wonder if I can use one for the LCD interface too, and eliminate both the SoftSerial libraries from my sketch?

Lots to experiment with later...if only I didn't have to work now.


mem

#5
Apr 06, 2009, 07:51 pm Last Edit: Apr 06, 2009, 07:54 pm by mem Reason: 1
Quote
I wonder if I can use one for the LCD interface too, and eliminate both the SoftSerial libraries from my sketch?


That should work  - give it a try.

Serial1 (the second UART)  is on pins 18 & 19 (TX,RX)
Serial2  is on pins 16 & 17 (TX,RX)
Serial3  is on pins 14 & 15 (TX,RX)

Go Up