Problems with code for receiving data from GPS

I have now twisted my brain over this code all day, and finally I understand that I'm just not skilled enough to figure this out. The code below is put together from various sources I found here on Arduino.cc. I know it's rather chaotic and it's probably quite obviously that I don't understand all that is going on. Anyway; The code read an NMEA string from a GPS receiver connected by using software UART on pin 2 and 4. The received data is then passed on to the serial port.

The problem is that not all the data in the string send to the serial port seems to be updated, with other words; Some of the GPS data keeps repeating itself (like latitude and longitude) while other data (like the date and time) updates aright. I have tried to connect the GPS receiver directly to my laptop and monitor the output through HyperTerminal, and there all data is updated for each sentence received from the GPS.

Any tip whatsoever is highly appreciated.

First half of the code:

#define BR_4800     //!< Desired baudrate...choose one, comment the others.
//This section chooses the correct timer values for the chosen baudrate.
#ifdef  BR_4800
    #define TICKS2COUNT         51  //!< Ticks between two bits.
    #define TICKS2WAITONE       51  //!< Wait one bit period.
    #define TICKS2WAITONE_HALF  77  //!< Wait one and a half bit period.
#endif


#define ENABLE_TIMER_INTERRUPT( )       ( TIMSK2 |= ( 1<< OCIE2A ) )
#define DISABLE_TIMER_INTERRUPT( )      ( TIMSK2 &= ~( 1<< OCIE2A ) )
#define CLEAR_TIMER_INTERRUPT( )        ( TIFR2 |= ((1 << OCF2A) ) )
#define ENABLE_EXTERNAL0_INTERRUPT( )   ( EIMSK |= ( 1<< INT0 ) )
#define DISABLE_EXTERNAL0_INTERRUPT( )  ( EIMSK &= ~( 1<< INT0 ) )
  
#define SW_UART_TX_PIN            4
#define SW_UART_RX_PIN            2  

#define INTERRUPT_EXEC_CYCL   2       //!< Cycles to execute interrupt rutine from interrupt.
  
typedef enum
{
    IDLE,                                       //!< Idle state, both transmit and receive possible.
    TRANSMIT,                                   //!< Transmitting byte.
    TRANSMIT_STOP_BIT,                          //!< Transmitting stop bit.
    RECEIVE,                                    //!< Receiving byte.
    DATA_PENDING                                //!< Byte received and ready to read.

}AsynchronousStates_t;

static volatile AsynchronousStates_t state;     //!< Holds the state of the UART.
static volatile unsigned char SwUartTXData;     //!< Data to be transmitted.
static volatile unsigned char SwUartTXBitCount; //!< TX bit counter.
static volatile unsigned char SwUartRXData;     //!< Storage for received bits.
static volatile unsigned char SwUartRXBitCount; //!< RX bit counter.

byte out_status;
char unitID[8] = "5500005";// Unique unitID
char linea[300] = "";
char comandoGPR[7] = "$GPRMC";
int cont=0;
int conta=0;
int bien=0;
int indices[13];

int pin14 = LOW;
int pin15 = LOW;
int pin16 = LOW;


int trackint = 3; // Message interval from GPS to send out


int teller = 0;  // Counter 

ISR(TIMER2_COMPA_vect) {  
 
  switch (state) {
  // Transmit Byte.
  case TRANSMIT:
    // Output the TX buffer.
    if( SwUartTXBitCount < 8 ) {            
      if( SwUartTXData & 0x01 ) {           // If the LSB of the TX buffer is 1:
        digitalWrite(SW_UART_TX_PIN,HIGH);   // Send a logic 1 on the TX_PIN.
      }
      else {                                // Otherwise:
        digitalWrite(SW_UART_TX_PIN,LOW);    // Send a logic 0 on the TX_PIN.
      }
      SwUartTXData = SwUartTXData >> 1;     // Bitshift the TX buffer and
      SwUartTXBitCount++;                   // increment TX bit counter.
    }

    //Send stop bit.
    else {
      digitalWrite(SW_UART_TX_PIN,HIGH);    // Output a logic 1.
      state = TRANSMIT_STOP_BIT;
    }
  break;

  // Go to idle after stop bit was sent.
  case TRANSMIT_STOP_BIT:
    DISABLE_TIMER_INTERRUPT( );           // Stop the timer interrupts.
    state = IDLE;                         // Go back to idle.
    ENABLE_EXTERNAL0_INTERRUPT( );        // Enable reception again.
  break;

  //Receive Byte.
  case RECEIVE:
    if(out_status == 1){
      out_status = 0;
      digitalWrite(4, LOW);
    }
    else{
      out_status =1;
      digitalWrite(4, HIGH);
    }
      
    OCR2A = TICKS2WAITONE;                  // Count one period after the falling edge is trigged.
    //Receiving, LSB first.
    if( SwUartRXBitCount < 8 ) {
        SwUartRXBitCount++;
        SwUartRXData = (SwUartRXData>>1);   // Shift due to receiving LSB first.
        if( digitalRead(SW_UART_RX_PIN) != 0 ) {
            SwUartRXData |= 0x80;           // If a logical 1 is read, let the data mirror this.
        }
    }

    //Done receiving
    else {
        state = DATA_PENDING;               // Enter DATA_PENDING when one byte is received.
        DISABLE_TIMER_INTERRUPT( );         // Disable this interrupt.
        EIFR |= (1 << INTF0 );           // Reset flag not to enter the ISR one extra time.
        ENABLE_EXTERNAL0_INTERRUPT( );      // Enable interrupt to receive more bytes.
    }
  break;

  // Unknown state.
  default:        
    state = IDLE;                           // Error, should not occur. Going to a safe state.
  }
}

ISR(INT0_vect) {
 

  state = RECEIVE;                  // Change state
  DISABLE_EXTERNAL0_INTERRUPT( );   // Disable interrupt during the data bits.
        out_status =1;
  digitalWrite(4, HIGH);
  DISABLE_TIMER_INTERRUPT( );       // Disable timer to change its registers.
  TCCR2B=0;        // Reset prescaler counter, disable counter

  TCNT2 = INTERRUPT_EXEC_CYCL;      // Clear counter register. Include time to run interrupt rutine.
  OCR2A = TICKS2WAITONE_HALF;         // Count one and a half period into the future.

  TCCR2B |= ( 1 << CS22 );          // Start prescaler clock



  SwUartRXBitCount = 0;             // Clear received bit counter.
  CLEAR_TIMER_INTERRUPT( );         // Clear interrupt bits
  ENABLE_TIMER_INTERRUPT( );        // Enable timer0 interrupt on again

}

void setup() { 
  pinMode(13, OUTPUT);  //we'll use the debug LED to output a heartbeat
  digitalWrite(13,LOW);
  
  // port setting
  pinMode(SW_UART_TX_PIN, OUTPUT);
  pinMode(SW_UART_RX_PIN, INPUT);
    
  // Setup timer2 -- CTC mode
   // Timer0
  DISABLE_TIMER_INTERRUPT( );
  TCCR2A =0x2;
   TCCR2B = 0;      // prescale = 0 -- stop timer clock
  
  ASSR &=~(1<<AS2);  // TImer2 clock is i/o clock
  

  ENABLE_EXTERNAL0_INTERRUPT();
  // tigger at INT0 falling edge
  EICRA = 0x02;
  
  state = IDLE;

 out_status  =0;
    
  SREG|=1<<SREG_I;
   
   
  pinMode(14, INPUT);
  pinMode(15, INPUT);
  pinMode(16, INPUT);
  
  pin14 = digitalRead(14);
  pin15 = digitalRead(15);
  pin16 = digitalRead(16);
  
  if (pin14 = HIGH) {
   
  } 
  
  if (pin15 = HIGH) {
   
  } 
  
  if (pin16 = HIGH) {
   
  } 
  
  Serial.begin(9600);
  
  // initialize the buffer
  for (int i=0;i<300;i++){
    linea[i]=' ';
  }
}

Second half of the code:

void loop()
{
   
    if( state == DATA_PENDING )
    {
      state = IDLE;
      
      
      // Serial.print(SwUartRXData);
      
     
        
   if (SwUartRXData == -1) {           // See if the port is empty yet
     delay(100); 
   } else {
     linea[conta]=SwUartRXData;        // If there is serial port data, it is put in the buffer
     conta++;                      
     //printByte(byteGPS);
     if (SwUartRXData==13){            // If the received byte is = to 13, end of transmission
       
       cont=0;
       bien=0;
       for (int i=1;i<7;i++){     // Verifies if the received command starts with $GPR
         if (linea[i]==comandoGPR[i-1]){
           bien++;
         }
       }
       if(bien==6){               // If yes, continue and process the data
         for (int i=0;i<300;i++){
           if (linea[i]==','){    // check for the position of the  "," separator
             indices[cont]=i;
             cont++;
           }
           if (linea[i]=='*'){    // ... and the "*"
             indices[12]=i;
             cont++;
           }
         }

        
         
         if (teller > trackint) {
         //Serial.print("RFU");
         //Serial.print(";");
         Serial.print(unitID);
         Serial.print(";");
         for (int j=indices[3];j<(indices[3+1]-1);j++){      // N/S
           Serial.print(linea[j+1]); 
         }
         Serial.print(";");
         for (int j=indices[2];j<(indices[2+1]-1);j++){    // Latitude
           Serial.print(linea[j+1]); 
         }
         
         Serial.print(";");         
         for (int j=indices[5];j<(indices[5+1]-1);j++){    // E/W
           Serial.print(linea[j+1]); 
         }
         Serial.print(";");    
         for (int j=indices[4];j<(indices[4+1]-1);j++){  // Longitude
           Serial.print(linea[j+1]); 
         }
         Serial.print(";");                                // UTC Time
         for (int j=indices[0];j<(indices[0+1]-1);j++){
           Serial.print(linea[j+1]); 
         }
         Serial.print(";");                                // UTC date
         for (int j=indices[8];j<(indices[8+1]-1);j++){
           Serial.print(linea[j+1]); 
         }
         Serial.print(";");                                // Speed in knots
         for (int j=indices[6];j<(indices[6+1]-1);j++){
           Serial.print(linea[j+1]); 
         }
         Serial.print(";");                                // Heading in degrees
         for (int j=indices[7];j<(indices[7+1]-1);j++){
           Serial.print(linea[j+1]); 
         }
         Serial.print(";");                                // Valid GPS fix A=yes, V=no
         for (int j=indices[1];j<(indices[1+1]-1);j++){
           Serial.print(linea[j+1]); 
         }

   
         
         Serial.println("");

         teller = 0;
         } else {
           teller = teller + 1;
           
         }
       }
       

       
       
       conta=0;                    // Reset the buffer
       for (int i=0;i<300;i++){    //  
         linea[i]=' ';             
       }   

       
     }
     }
     
     // End
      
    }
     
}

Some of the GPS data keeps repeating itself (like latitude and longitude) while other data (like the date and time) updates aright

Pardon me if this is a dumb question, but wouldn't you expect the latitude and longitude to repeat itself, more or less, unless you were moving? I haven't dissected the code, but it's surprising that date and time work, but not lat/long.

Mikal

Good point, but believe me; I have tried to move around with the GPS receiver as well, but with no luck :).

When I connect the GPS directly to my computer, I see the position drift a little, even though I'm standing still, so no matter what I would expect the latitude and longitude to change a little.

sta--

My first instinct is that this is unnecessarily complicated. It looks like you have a complete implementation of SoftwareSerial in your sketch. Why not just #include SoftwareSerial.h, or better yet, AFSoftSerial.h (third party software serial library)?

Can you share some sample of the output serial stream your program generates and identify which parts seems suspicious to you?

Mikal

I'm embarrassed to say that I found the error. It wasn't in the code, stupid as I am, I simply forgot to provide the active GPS antenna with power.

Thank you for the tip about including part of the code as a library. This is absolutely something I will look into.