Reading values from a motorsport datalogger on RS232?

Hi,

I'm trying to make a device using an Arduino Uno to read values from a motorsport datalogger (RaceTechnology DL1) from its RS232 serial port, then display the values on a 16x2 LCD display.
I'll need to manipulate the raw values to display the real values that I'm looking for, but I'm already comfortable doing the required maths.

What I need assistance with, is configuring the Arduino to talk to the DL1 datalogger, and extract the values I'm looking for.

I believe I'll need to an adaptor such as a Max232 to interface between the Arduino's TTL Rx and Tx, to the 12V RS323 of the datalogger.

RaceTechnology advise that the message format is :-

Header byte data1 data2 data3 ... dataN checksum

and the data rate is 115200 baud, RS232 levels. 1 start bit, 1 stop bit, no parity bit(s), no handshaking.

http://www.race-technology.com/wiki/index.php/General/SerialDataFormat

I'm looking to continuously retrieve values for message index 20 & 21, which both have a length of 4.

How do I do that?
Have I left out any important details?

Thanks in advance :slight_smile:

Anyone have any comment to make?

The documentation describes how you have to do that. Although you're just interested in message types 20 and 21 you have to insert the complete table with message lengths into your sketch because you cannot know which message will be transfered when. Then read the message as if it would be starting where you started listening. If the checksum is wrong drop the first byte and try to decode the message with the new message type. Go on until you are calculate the same checksum as you got transfered. It's best to use this same algorithm for all following messages because there is a small chances that you got a wrong message although the checksum byte was correct.

For the hardware you need a converter chip to adapt to the RS-232 levels. A MAX232 is a good choice.

Hi Pylon,
"The documentation describes how you have to do that"
Unfortunately, I'm a bit of a novice, and I need a little more help than that :frowning:

Where might I find suitable sample code?

The tutorial by @Robin2 is the standard place to start learning about Serial I/O:

OK,
With more that a little assistance from my friend Colin.
I’ve copied bits of Colin’s code which he has running in a Mega (I’m using an UNO). He’s doing way more than I want to do, so his code is huge…

I think he’s suggesting that something like this should work.

I can’t get it to compile yet, but I can’t work out why :frowning:

I’d appreciate a little help please.

#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

#define MAX_LEN    42
#define MAX_MESS  107

// Variables used to decode serial data from DL1
int buffer[MAX_LEN] = {0};       //Our Buffer
unsigned int bytesInBuffer = 0;  //Keep track of bytes in Our Buffer
byte messageLengths[] = {9, 11, 0, 7, 21, 6, 6, 6, 5, 14, 10, 3, 0, 5, 5, 5, 5, 5, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 11, 6, 10, 10, 10, 11, 11, 11, 11, 11, 3, 5, 30, 11, 4, 4, 42, 42, 3, 5, 5, 5, 6, 24, 3, 6, 4, 4, 5, 5, 5, 5, 10, 5, 5, 5, 5, 6, 5, 4, 5, 6, 5, 10, 8, 0, 0, 0, 19, 0, 17, 9, 11, 0, 0};
int currentMessageLength = 0;    //number of bytes in the current message
//int i;                           //generic, used for all for loops
int bytesNeededInBuffer;         //Amount of bytes needed in buffer to complete message
byte calculatedCheckSum;         //checksum calculated from bytes in message


/*
Analoge input
Channel Number 20-51
Total Length  4 bytes
Channel Data1 Data2 Checksum
Voltage [V]= (Data1 * 256 + Data2 )/1000
*/

unsigned long decodeAnalogueInput() {
  unsigned long result = 0;
  byte checksum = 0;
  for (int k=0; k<3; k++) {
    checksum += buffer[k];
  }
  if (checksum == buffer[3]) {
    result = (buffer[1] * 256 + buffer[2]);
    return result;  //in mV
  } else { // invalid checksum
    return -1;
  }
}



void RunSerial(void) {

void setup() {
ISR(TIMER4_COMPA_vect) { //timer4 interrupt to perform Decode of incomming serial data at 115200 kbps
    cli();
    RunSerial();
    sei();  // put your setup code here, to run once:

}
void loop() {
  
  }  //End of Interrupt Routine

  /***************************************************/
  /*************   serial comm From DL1   ************/
//  void RunSerial(void) { //move to before void loop or void setup

    if (bytesInBuffer == 0) {           //Check if our buffer is empty
      if (Serial.available() >= 1) {   //Check if serial buffer is empty
        buffer[0] = Serial.read();     //read first byte into our buffer
        bytesInBuffer = 1;              //Update buffer counter
      } else {
        goto endOfSerial;
      }//end if to check if serial buffer is empty
    }//end if to check if there are bytes in our buffer

    if (buffer[0] > MAX_MESS) { //check to see if 1st byte could be a message
      moveBytesDown();
      goto endOfSerial;
      //Serial.println(2);
    }//end check of message number check

    currentMessageLength = messageLengths[(buffer[0] - 1)];    //get message length from array

    if (currentMessageLength == 0 ) { //check to see if 1st byte could be a message
      moveBytesDown();
      goto endOfSerial;
      //Serial.println(3);
    }//end check of message number check

    if (currentMessageLength > bytesInBuffer) {   //check if we have enough bytes in our buffer
      bytesNeededInBuffer = currentMessageLength - bytesInBuffer;
      if (Serial.available() >= bytesNeededInBuffer) { //check if there are enough bytes in serial array
        int bytesInBufferOld = bytesInBuffer;
        for (int i = bytesInBufferOld; i < currentMessageLength; i++) { //for loop to add bytes to end of our array
          buffer[i] = Serial.read();
          bytesInBuffer = bytesInBuffer + 1;
        }//end for loop
      } else {
        goto endOfSerial;
      }
    }

    calculatedCheckSum = 0;                      //reset checksum
    for (int i = 0; i < (currentMessageLength - 1); i++) { //for loop to sum checksum value
      calculatedCheckSum = calculatedCheckSum + buffer[i];
    }//end if checksum for loop

    if (calculatedCheckSum == buffer[currentMessageLength - 1]) { //if message has been proven
      //    Serial.print (buffer[0]);
      //    Serial.println();

      if (DL1LogOnVerify1 == 1) {                               //check if logger storage was last message sent
        if (buffer[0] == 63) {                                //if it was then check if current message is run start
          DL1LogOnFlag = 1;                                   //Set Logging flag to on
        } else {
          DL1LogOnVerify1 =  0;                                 //Reset flag indicating that logger storage was the last message recieved
        }
      }
      //  if (DL1LogOffVerify1 == 1) {                               //check if logger storage was last message sent
      //      if (buffer[0]==55){                                   //if it was then check if current message is data storage channell
      //        DL1LogOnFlag = 0;                                   //Set Logging flag to off
      //      }else{
      //        DL1LogOffVerify1 = 0;                                 //Reset flag indicating that logger storage was the last message recieved
      //      }
      //   }
      if (buffer[0] == 6)  {                                  //check if logger storage has been set, this is the first message to be recieved when logging has swithed on, the next is 63
        DL1LogOnVerify1 = 1;
      }
     


     
      if (buffer[0] == 20) {
       int Front_Brake_Press_mV = decodeAnalogueInput();     // Analog 01 - Front brake pressure
      }
      if (buffer[0] == 21) {
       int Rear_Brake_Press_mV = decodeAnalogueInput();      // Analog 02 - Rear brake pressure
      } 
      
 

      //bytesInBuffer = 0;

      for (int i = 0; i < currentMessageLength; i++) {
        moveBytesDown();
      }
    } else {
      // for(int i = 0; i < currentMessageLength; i++){
      moveBytesDown();
      // }
    }

endOfSerial:

    if (Serial.available() > 60) {   //Check if serial buffer is full
      while (Serial.available() > 0) trash = Serial.read(); //if full, clear buffer to ensure full messages are recorded
    }  // end of serial comm (DL-1)
    }


// calculate brake pressue and bias, and display on 20x4 LCD
  
   float Front_Brake_Bar = (62.5 * (Front_Brake_Press_mV/1000)) - 31.3;  // 0bar = 0.5V and 350bar = 4.5V
   float Rear_Brake_Bar = (62.5 * (Rear_Brake_Press_mV/1000)) - 31.3;    // 0bar = 0.5V and 350bar = 4.5V
   float Front_Bias = (1/((Front_Brake_Bar + Rear_Brake_Bar)/Front_Brake_Bar))*100;  // calculate % front bias
   float Rear_Bias = (1/((Front_Brake_Bar + Rear_Brake_Bar)/Rear_Brake_Bar))*100;    // calculate % rear bias
      lcd.clear();                  
  lcd.print("Front Bar");
  lcd.setCursor(0, 1);
  lcd.print("Front Bias");
  lcd.setCursor(0, 2);
  lcd.print("Rear Bias");
  lcd.setCursor(0, 3);
  lcd.print("Rear bar");
      lcd.setCursor(14, 0);
      lcd.print(Front_Brake_Bar);
      lcd.setCursor(14, 1);
      lcd.print(Front_Bias);
      lcd.setCursor(14, 2);
      lcd.print(Rear_Bias);
      lcd.setCursor(14, 3);
      lcd.print(Rear_Brake_Bar);
      delay(05);
}
void RunSerial(void) {

void setup() {
ISR(TIMER4_COMPA_vect) { //time

You are trying to define the ISR() function inside the setup() function, which you are trying to define in the RunSerial() function.

That is NOT going to work.

Hi PaulS,

can you expand on that please?

are the two not compatible with each other, or should either be placed in a different part of the code?

can you expand on that please?

Suppose you want to create three books. Are any pages from one book going to be in the another book? Or does each book have a front cover (an open curly brace), some content (code), and a back cover (close curly brace)?

When you are writing code, and type an open curly brace, you should IMMEDIATELY hit enter and then type the matching close curly brace. Then, go back and put the code between the braces.

You’d have:

void RunSerial(void)
{
}

void setup()
{
}

ISR(TIMER4_COMPA_vect)
{
}

in which you would put code.

If you did that, there is no way that you could have a function defined inside a function.

OK,
Again, with more than a little help, I’ve got it to compile, but, when I download it, I have no idea if the coms part is working, because, my LCD doesn’t work :frowning:

What’s stopping my LCD working, and, does it look like I should be able to read from my datalogger?

#include <LiquidCrystal_I2C.h>

//Declare LCD parameters
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

// Define message data
#define MAX_LEN    42
#define MAX_MESS  107



// Variables used to decode serial data from DL1
int buffer[MAX_LEN] = {0};       //Our Buffer
unsigned int bytesInBuffer = 0;  //Keep track of bytes in Our Buffer
byte messageLengths[] = {9, 11, 0, 7, 21, 6, 6, 6, 5, 14, 10, 3, 0, 5, 5, 5, 5, 5, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 11, 6, 10, 10, 10, 11, 11, 11, 11, 11, 3, 5, 30, 11, 4, 4, 42, 42, 3, 5, 5, 5, 6, 24, 3, 6, 4, 4, 5, 5, 5, 5, 10, 5, 5, 5, 5, 6, 5, 4, 5, 6, 5, 10, 8, 0, 0, 0, 19, 0, 17, 9, 11, 0, 0};
int currentMessageLength = 0;    //number of bytes in the current message
//int i;                           //generic, used for all for loops
int bytesNeededInBuffer;         //Amount of bytes needed in buffer to complete message
byte calculatedCheckSum;         //checksum calculated from bytes in message
int trash;

//Global Variables declared
int Front_Brake_Press_mV;
int Rear_Brake_Press_mV;




void setup(){ //Code that only runs once on power up
  Serial.begin(115200);  //Turn on serial port
} //end setip()
void loop() {

RunSerial();  //Run the serial function to check serial buffer for DL1 messages

// calculate brake pressue and bias, and display on 20x4 LCD

   float Front_Brake_Bar = (62.5 * (Front_Brake_Press_mV/1000)) - 31.3;  // 0bar = 0.5V and 350bar = 4.5V
   float Rear_Brake_Bar = (62.5 * (Rear_Brake_Press_mV/1000)) - 31.3;    // 0bar = 0.5V and 350bar = 4.5V
   float Front_Bias = (1/((Front_Brake_Bar + Rear_Brake_Bar)/Front_Brake_Bar))*100;  // calculate % front bias
   float Rear_Bias = (1/((Front_Brake_Bar + Rear_Brake_Bar)/Rear_Brake_Bar))*100;    // calculate % rear bias
      lcd.clear();                  
  lcd.print("Front Bar");
  lcd.setCursor(0, 1);
  lcd.print("Front Bias");
  lcd.setCursor(0, 2);
  lcd.print("Rear Bias");
  lcd.setCursor(0, 3);
  lcd.print("Rear bar");
      lcd.setCursor(14, 0);
      lcd.print(Front_Brake_Bar);
      lcd.setCursor(14, 1);
      lcd.print(Front_Bias);
      lcd.setCursor(14, 2);
      lcd.print(Rear_Bias);
      lcd.setCursor(14, 3);
      lcd.print(Rear_Brake_Bar);
      delay(05);
      
} //End of main loop

//Start of function area

void RunSerial(void){
    
if (bytesInBuffer == 0){            //Check if our buffer is empty
  if (Serial.available()>=1){      //Check if serial buffer is empty
    buffer[0] = Serial.read();     //read first byte into our buffer   
    bytesInBuffer = 1;              //Update buffer counter
  }else{
    goto endOfSerial;
  }//end if to check if serial buffer is empty
}//end if to check if there are bytes in our buffer

if(buffer[0] > MAX_MESS){//check to see if 1st byte could be a message
  moveBytesDown();
  goto endOfSerial;
  //Serial.println(2); 
  }//end check of message number check
  
currentMessageLength = messageLengths[(buffer[0]-1)];      //get message length from array
  
if(currentMessageLength == 0 ){//check to see if 1st byte could be a message
  moveBytesDown();
  goto endOfSerial;
  //Serial.println(3); 
  }//end check of message number check

if (currentMessageLength > bytesInBuffer){    //check if we have enough bytes in our buffer
  bytesNeededInBuffer = currentMessageLength-bytesInBuffer;
    if (Serial.available()>=bytesNeededInBuffer){ //check if there are enough bytes in serial array
      int bytesInBufferOld = bytesInBuffer;
      for(int i=bytesInBufferOld; i < currentMessageLength; i++){    //for loop to add bytes to end of our array
        buffer[i]= Serial.read();                
        bytesInBuffer=bytesInBuffer + 1;
      }//end for loop
    }else{
      goto endOfSerial;
    }  
}     
      
calculatedCheckSum = 0;                      //reset checksum
for (int i=0; i<(currentMessageLength-1); i++){      //for loop to sum checksum value
    calculatedCheckSum = calculatedCheckSum + buffer[i];
  }//end if checksum for loop
  
if (calculatedCheckSum == buffer[currentMessageLength-1]){ //if message has been proven
//    Serial.print (buffer[0]);
//    Serial.println(); 
  


  if (buffer[0] == 20) {
   int Front_Brake_Press_mV = decodeAnalogueInput();     // Analog 01 - Front brake pressure
  }
  if (buffer[0] == 21) {
   int Rear_Brake_Press_mV = decodeAnalogueInput();      // Analog 02 - Rear brake pressure
  }                 
    //bytesInBuffer = 0;

    for(int i = 0; i < currentMessageLength; i++){
    moveBytesDown();
   }
  }else{
   // for(int i = 0; i < currentMessageLength; i++){
    moveBytesDown();
   // }
  }

endOfSerial:

if (Serial.available()>60){      //Check if serial buffer is full
  while(Serial.available()>0) trash = Serial.read();    //if full, clear buffer to ensure full messages are recorded
// end of serial comm (DL-1)
  }

}// End of RunSerial Function


/*
Analoge input
Channel Number 20-51
Total Length  4 bytes
Channel Data1 Data2 Checksum
Voltage [V]= (Data1 * 256 + Data2 )/1000
*/

unsigned long decodeAnalogueInput() {
  unsigned long result = 0;
  byte checksum = 0;
  for (int k=0; k<3; k++) {
    checksum += buffer[k];
  }
  if (checksum == buffer[3]) {
    result = (buffer[1] * 256 + buffer[2]);
    return result;  //in mV
  } else { // invalid checksum
    return -1;
  }
}

void moveBytesDown(void){
    for (int i=0; i<=bytesInBuffer; i++){
    buffer[i] = buffer[i+1];
    }//end of for loop to move bytes down
  bytesInBuffer=bytesInBuffer-1;
  }

GET RID OF ALL THOSE goto statements!

Take action if needed. Do NOT use goto to skip doing stuff.

GET RID OF ALL THOSE goto statements!

I guess I can't just delete them?

What should I do instead?

What should I do instead?

The term "structured programming" comes to mind.

Draw a flow chart. There are C statement for everything on the flow chart.

if(thisIsTrue)
{
   DoThis();
}

No need to go to some other place if it isn't. Just put all the code that is to be executed in the curly braces. The "goto" point is the end of the function, where flow will go if the if statement evaluates to false.