Odd problem with parsing serial data[solved]

Once again, I've hit another snag in my project :frowning:

Basically, I have 2 ATmega328's connected to each other via the serial UART, one uC is measuring cell voltages of a LiPo and spitting them out over serial, and the other is taking that data and displaying it on a LCD.

But for some reason, after a few seconds, the LCD just starts displaying 0.00's, or sometimes numbers like 0.04, 0.03 etc and doesn't seem to update at all any more (Can usually tell it's updating by the LCD flickering).

I am running it over about 2 metres of cat5, however I am monitoring the serial at the LCD end and there is no change in the data when the LCD starts reading 0.00's, so I'm really confused as to what could be going on here?

Code on the measurement uC:

#include "SPI.h"

#define LT_SPI_START digitalWrite(10,LOW)
#define LT_SPI_END digitalWrite(10,HIGH)
byte config[6] = { 0xE9,0x00,0x00,0xFC,0x71,0xC8 };  //Default config
float current_voltages[6];
String serialdata;


#define WRCFG 0x01  // Write config registers
#define RDCFG 0x02  // Read config registers
#define RDCV 0x04   // Read all cell voltages
#define RDCVA 0x06  // Read cells 1-4
#define RDCVB 0x08  // Read cells 5-8
#define LTCADDR 0x80 // LTC's Address - 0000
#define STCVAD 0x10

void setup(){
  pinMode(10, OUTPUT);
  Serial.begin(115200);
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE3);
  SPI.setClockDivider(SPI_CLOCK_DIV64);
  // Write LTC configs
  LT_SPI_START;
  sendToSPI(LTCADDR);  // Non-broadcast command
  sendToSPI(WRCFG);  // Write config
  sendMultipleToSPI(config, 6);
  LT_SPI_END; 
  // Finish LTC config
}

void loop(){
  // STUFF!
  beginCellVolt(); // Start cell 1-6 conversion
  readCellVolt(current_voltages,LTCADDR);
  Serial.print(".");
  Serial.print((int)current_voltages[0]/10);
  Serial.print(",");
  Serial.print((int)current_voltages[1]/10);
  Serial.print(",");
  Serial.print((int)current_voltages[2]/10);
  Serial.print(",");
  Serial.print((int)current_voltages[3]/10);
  Serial.print(",");
  Serial.print((int)current_voltages[4]/10);
  Serial.print(",");
  Serial.print((int)current_voltages[5]/10);
 delay(500);
}







// ---- FUNCTIONS ----

void beginCellVolt() {
  LT_SPI_START;
  sendToSPI(STCVAD);
  delay(11); //Time for conversions
  LT_SPI_END;
}

// Reads cell voltage registers  
void readCellVolt(float* cell_voltages, byte board) {
  LT_SPI_START;
  sendToSPI(board);  // Board address is selected
  sendToSPI(RDCV);  // Cell voltages to be read
  byte cvr[12];  // Buffer to store unconverted values
  getMultipleFromSPI(cvr, RDCV, 12);
  LT_SPI_END; 

  // Converting cell voltage registers to cell voltages
  cell_voltages[0] = (cvr[0] & 0xFF) | (cvr[1] & 0x0F) << 8;
  cell_voltages[1] = (cvr[1] & 0xF0) >> 4 | (cvr[2] & 0xFF) << 4;
  cell_voltages[2] = (cvr[3] & 0xFF) | (cvr[4] & 0x0F) << 8;
  cell_voltages[3] = (cvr[4] & 0xF0) >> 4 | (cvr[5] & 0xFF) << 4;
  cell_voltages[4] = (cvr[6] & 0xFF) | (cvr[7] & 0x0F) << 8;
  cell_voltages[5] = (cvr[7] & 0xF0) >> 4 | (cvr[8] & 0xFF) << 4;
  
  for(int i=0;i<6;i++) {
    cell_voltages[i] = (cell_voltages[i]-512)*1.5;
  }
} 

// Send data to LTC
void sendMultipleToSPI(byte * data, int n) {
  for(int i=0; i<n; i++) {
    SPI.transfer(data[i]);
  }
  SPI.transfer(getPEC(data, n));
}

// Get data from LTC
byte * getMultipleFromSPI(byte * data, byte info, int n) {
  for(int i=0; i<n; i++) {
    data[i] = SPI.transfer(info);
  }
  byte pec = SPI.transfer(info);
}

void sendToSPI(byte data) {
  sendMultipleToSPI(&data, 1);
}

void readConfig(byte*config,byte board) {
  LT_SPI_START;   
  sendToSPI(board);  // Board address is selected
  sendToSPI(RDCFG);  // Configuration is read
  getMultipleFromSPI(config, RDCFG, 6);
  LT_SPI_END;
}

// Calculate PEC, n is  size of DIN
byte getPEC(byte * din, int n) {
  byte pec, in0, in1, in2;
  pec = 0x41;
  for(int j=0; j<n; j++) {
    for(int i=0; i<8; i++) {
      in0 = ((din[j] >> (7 - i)) & 0x01) ^ ((pec >> 7) & 0x01);
      in1 = in0 ^ ((pec >> 0) & 0x01);
      in2 = in0 ^ ((pec >> 1) & 0x01);
      pec = in0 | (in1 << 1) | (in2 << 2) | ((pec << 1) & ~0x07);
    }
  }
  return pec;
}

And the LCD uC:

String serial_data[6];
float cell_voltages[6];
int varcounter = 0;
boolean newdata = false;
#include <LiquidCrystal.h>
 
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(9, 8, 7, 4, 2, 5);
 
void setup() {
  pinMode(3, OUTPUT);
  analogWrite(3, 128);
  lcd.begin(16, 2);
  Serial.begin(115200);
}
 
void loop() {
while (Serial.available() > 0) {
    newdata = true;
    delay(10);  //small delay to allow input buffer to fill
    char c = Serial.read();  //gets one byte from serial buffer
    if (c == ',') {
      varcounter++;
    }  //breaks out of capture loop to print readstring
    if (c != ',' && c != '.'){
    serial_data[varcounter] += c;
    }
    if (c == '.'){
       memset(serial_data,0,sizeof(serial_data));
       varcounter = 0;
       newdata = true;
    }
  }
if (newdata == true){
  lcd.clear();
  lcd.setCursor(0,0);
  for (int i=0; i < 6; i++){
   cell_voltages[i] = serial_data[i].toInt();
   cell_voltages[i] = cell_voltages[i] / 100;
   if (i == 3){
   lcd.setCursor(0,1);
   }
   lcd.print(cell_voltages[i]);
   lcd.print(" ");
   delay(10);
  }
  newdata = false;
 }
 }

Cheers,
Dan

       memset(serial_data,0,sizeof(serial_data));

You should NOT write 0's over your String objects. Somewhere in that object is the pointer to the character data.

Change that to:

for (int i = 0; i<6; i++)
   serial_data[i] = "";

Huh, that function did cross my mind as I have never used it before, but I wasn't sure. I noticed a trend in that it seemed to break exactly 22s in from a reset every time. Swapping that line out seems to have fixed it, thanks :slight_smile:

for (int i = 0; i<6; i++)
   serial_data[i] = "";
[code]

vs

[code]
  serial_data = "";

or is that not allowed/ (i don't use the string class... )[/code][/code]

cjdelphi:

for (int i = 0; i<6; i++)

serial_data[i] = "";

[code]

vs

[code]
  serial_data = "";




or is that not allowed/ (i don't use the string class... )[/code][/code]

That was the first thing I tried before using the memset function .. but no, it needs an index :frowning:

cjdelphi:

for (int i = 0; i<6; i++)

serial_data[i] = "";




vs



serial_data = "";




or is that not allowed/ (i don't use the string class... )

In general, C will not iterate over an array for you. I think you have to make it explicit.