5
\$\begingroup\$

I am establishing a serial connection with my Arduino. In order to get data from it I have to send data in the form of byte arrays. I am able to send the command and read the ACK. But I can't figure out how to get the data after the ACK.

The developer documentation for the protocol I am using says it goes: command to access data -> ACK REPONSE ->DATA

I can't figure out how to get the data after the ack response. It should be a byte array of 14 hex values.

This is my code

byte GetData[] = {0x02,0x12,0x00}
byte GetDataACK[] = {0x02,0x06,0x06,0x06,0x06,0x06}; 

void setup(){

  Serial.begin(9600); 
  Serial.write(GetData,sizeof(GetData)); //Send the byte array
  delay(200); 
  if(Serial.available() > 5) {
    for(int i=0;i<6;i++){
      if(ackmodule[i]!=Serial.read()){
        // Do something
      }
    }
  }

}

void loop(){

}  
\$\endgroup\$
2
  • \$\begingroup\$ To clarify, you are using a serial monitor program (eg. Hyperterminal) on a PC to communicate over RS232 to the Arduino's USART (Tx and Rx) pins, correct? \$\endgroup\$
    – tyblu
    Jan 5, 2011 at 5:32
  • \$\begingroup\$ Instead of a delay and an if, why not make it sit in a while until enough characters are available, or process and check the characters one by one as they come in? This will also help as you can manually interact with it from the PC since there won't be a time limit for the response. \$\endgroup\$ Jan 5, 2011 at 5:57

2 Answers 2

2
\$\begingroup\$

Shouldn't some of that code be inside of loop()? Specifically, everything but Serial.begin(9600)? Anyway, this code won't work because ackmodule is not defined. Is it supposed to be GetDataACK? It's also a good idea to implement error handling, especially when having to debug, like this:

  if(Serial.available() > 0) {
    received_byte[i] = Serial.read();
    if(received_byte[i++] == -1) {  // no data available
      // error handling
    }
  }

I'm not sure what types the Arduino sketch libraries support, but i can just be an unsigned char (I would call it uint8_t) instead of a full singed 16-bit number (int). As Chris Stratton mentioned, there are better ways to wait for characters; for example the error handling example, or this:

while(Serial.available() < 5) {}; // 5 can be 0 to fetch 1 char at a time

This can be implemented without the library in this form:

char rx()
{
        while ((UCSRA & (1<<RXC)) == 0) {};
        return UDR;
}

... Calling it with something like char nextbyte = rx(). Arduino serial tutorial is here.

\$\endgroup\$
4
  • \$\begingroup\$ If some of the above looks foreign, it's because I haven't programmed with the Arduino libraries or IDE before, and am not sure what nomenclature is used. \$\endgroup\$
    – tyblu
    Jan 5, 2011 at 13:28
  • \$\begingroup\$ correct most of the code should be in the loop(), but you would not want to call the serial.write every loop. \$\endgroup\$
    – jsolarski
    Jan 5, 2011 at 13:49
  • \$\begingroup\$ I believe the Arduino Serial library internally uses the UART receive interrupt and stores the received bytes in a managed circular buffer, so there's no need to implement the (polling/blocking) rx function you've described in at the end of your post. \$\endgroup\$
    – vicatcu
    Jan 5, 2011 at 15:36
  • \$\begingroup\$ @vicatu, Ah, that would make sense. \$\endgroup\$
    – tyblu
    Jan 5, 2011 at 20:27
0
\$\begingroup\$

If you just want to send the command once at startup, and then read the response you want to do this:

byte GetData[] = {0x02,0x12,0x00}
byte GetDataACK[] = {0x02,0x06,0x06,0x06,0x06,0x06}; 

void setup(){   
  Serial.begin(9600); 
  Serial.write(GetData,sizeof(GetData)); //Send the byte array    
}

void loop(){
  if(Serial.available() > 5) {
    for(int i=0;i<6;i++){
      if(GetDataACK[i]!=Serial.read()){
        // Do something
      }
    }
  }    
}  

Now I'm not sure what you're trying to accomplish with the inner if statement of loop, but it seems kind of backwards to me. Wouldn't you only want to "do something" after you have successfully read the data Ack? I think what you really want is a little state machine:

#define DATA_LENGTH           14 // or whatever the length of your data segment is

#define STATE_IDLE            0
#define STATE_SEND_COMMAND    1
#define STATE_WAITING_FOR_ACK 2
#define STATE_GET_DATA        3

byte GetData[] = {0x02,0x12,0x00}
byte GetDataACK[] = {0x02,0x06,0x06,0x06,0x06,0x06}; 
byte RxData[DATA_LENGTH] = {0};
byte state = STATE_SEND_COMMAND;

void setup(){   
  Serial.begin(9600); 
  state = STATE_SEND_COMMAND;            // redundant
}

void loop(){
  switch(state){
  case STATE_IDLE: break;
  case STATE_SEND_COMMAND:
     Serial.write(GetData,sizeof(GetData)); //Send the byte array             
     state = STATE_WAITING_FOR_ACK;
     break;
  case STATE_WAITING_FOR_ACK:
     if(Serial.available() > 5) {
        for(int i=0;i<6;i++){
           if(GetDataACK[i]!=Serial.read()){
           // ACK doesn't match what you expect
           // you should go to some other state at this point
           // i'll just send you to idle
              state = STATE_IDLE;
              break;
           }
        }
     }
     break;
  case STATE_GET_DATA:
     if(Serial.available() > DATA_LENGTH) {
        for(int i = 0; i < DATA_LENGTH; i++){
           RxData[i] = Serial.read();
        }

        // congratulations you have data in your array
        // presumably now you want to something with it

        // and then switch back to some other state
        // i'll send you back to IDLE :)
        state = STATE_IDLE;
        break;
     }       
  }      
}  
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.