Arduino Serial print shows variable 0 always on serial monitor

I've a problem to print integer value on serial monitor of Arduino, below codes are to communicate with Honda car ECU, using sevseg.setNumber() I'm able to display ect variable on the 7-segment, but the same variable is showing Zero on the serial as declared ...

I tried to use all other variables and all are showing Zeros (just as declared)..

What am I missing here ??


#include <SoftwareSerialWithHalfDuplex.h>
#include <SevSeg.h>
SevSeg sevseg;
/*
* DLC pin 12
*/
SoftwareSerialWithHalfDuplex dlcSerial(12, 12, false, false);

void dlcInit() {
  dlcSerial.write(0x68);
  dlcSerial.write(0x6a);
  dlcSerial.write(0xf5);
  dlcSerial.write(0xaf);
  dlcSerial.write(0xbf);
  dlcSerial.write(0xb3);
  dlcSerial.write(0xb2);
  dlcSerial.write(0xc1);
  dlcSerial.write(0xdb);
  dlcSerial.write(0xb3);
  dlcSerial.write(0xe9);
  delay(300);
}

int dlcCommand(byte cmd, byte num, byte loc, byte len, byte data[]) {
  byte crc = (0xFF - (cmd + num + loc + len - 0x01)); // checksum FF - (cmd + num + loc + len - 0x01)

  unsigned long timeOut = millis() + 250; // timeout @ 250 ms
  memset(data, 0, sizeof(data));

  dlcSerial.listen();

  dlcSerial.write(cmd);  // header/cmd read memory ??
  dlcSerial.write(num);  // num of bytes to send
  dlcSerial.write(loc);  // address
  dlcSerial.write(len);  // num of bytes to read
  dlcSerial.write(crc);  // checksum
  
  int i = 0;
  while (i < (len+3) && millis() < timeOut) {
    if (dlcSerial.available()) {
      data[i] = dlcSerial.read();
      i++;
    }
  }
  
  if (data[0] != 0x00 && data[1] != (len+3)) { // or use checksum?
    return 0; // error
    Serial.println("ECU readout error !");
  }
  if (i < (len+3)) { // timeout
    return 0; // error
    Serial.println("ECU readout timeout !");
  }
  return 1; // success
  Serial.println("ECU readout success [OK]");
}

void procdlcSerial(void) {
  byte data[20];
  unsigned int rpm=0,vss=0,ect=0,iat=0,maps=0,tps=0,volt=0, imap=0;

  if (dlcCommand(0x20,0x05,0x00,0x10,data)) { // row 1
    rpm = (data[2] * 256 + data[3]) / 4;
    vss = data[4];
  }
  
  if (dlcCommand(0x20,0x05,0x10,0x10,data)) { // row2
    float f;
    f = data[2];
    f = 155.04149 - f * 3.0414878 + pow(f, 2) * 0.03952185 - pow(f, 3) * 0.00029383913 + pow(f, 4) * 0.0000010792568 - pow(f, 5) * 0.0000000015618437;
    ect = round(f);
    f = data[3];
    f = 155.04149 - f * 3.0414878 + pow(f, 2) * 0.03952185 - pow(f, 3) * 0.00029383913 + pow(f, 4) * 0.0000010792568 - pow(f, 5) * 0.0000000015618437;
    iat = round(f);
    maps = data[4];
    tps = (data[6] - 24) / 2;
    f = data[9];
    f = (f / 10.45) * 10.0; // cV
    volt = round(f);
  }
  
  // IMAP = RPM * MAP / IAT / 2
  // MAF = (IMAP/60)*(VE/100)*(Eng Disp)*(MMA)/(R)
  // Where: VE = 80% (Volumetric Efficiency), R = 8.314 J/°K/mole, MMA = 28.97 g/mole (Molecular mass of air)
  float maf = 0.0;
  imap = (rpm * maps) / (iat + 273);
  // ve = 75, ed = 1.5.95, afr = 14.7
  maf = (imap / 120) * (80 / 100) * 1.595 * 28.9644 / 8.314472;
  
// Serial Print
   Serial.print("RPM    : ");
   Serial.println(ect);
   Serial.print("data 0 : ");
   Serial.println(data[0]);
   Serial.print("data 1 : ");
   Serial.println(data[1]);

// Display ECT 7 Segment
   sevseg.setNumber(ect, 2);
   sevseg.refreshDisplay();
  
}  

void setup() {
    byte numDigits = 3;
    byte digitPins[] = {13, 9, 8};
    byte segmentPins[] = {7, 6, 5, 4, 3, 2, 1, 0};

    bool resistorsOnSegments = true; 
    bool updateWithDelaysIn = false;
    byte hardwareConfig = COMMON_ANODE; 
    sevseg.begin(hardwareConfig, numDigits, digitPins, segmentPins, resistorsOnSegments);
    sevseg.setBrightness(90);
    
  Serial.begin(9600);
  dlcSerial.begin(9600);
  delay(200);
  dlcInit();
}

void loop() {
  procdlcSerial();
  delay(300);
}

Do you using the same pin for rx and tx? :nerd_face:

SoftwareSerialWithHalfDuplex dlcSerial(12, 12, false, false);

are you saying that in this part:

  // Serial Print
  Serial.print("RPM    : ");
  Serial.println(ect);
  Serial.print("data 0 : ");
  Serial.println(data[0]);
  Serial.print("data 1 : ");
  Serial.println(data[1]);

  // Display ECT 7 Segment
  sevseg.setNumber(ect, 2);
  sevseg.refreshDisplay();

You don't see the same value for ect? (what do you see?)

———

Side note: when you call this function

int dlcCommand(byte cmd, byte num, byte loc, byte len, byte data[]) {
  byte crc = (0xFF - (cmd + num + loc + len - 0x01)); // checksum FF - (cmd + num + loc + len - 0x01)

  unsigned long timeOut = millis() + 250; // timeout @ 250 ms
  memset(data, 0, sizeof(data));

the data array has lost its length. so the memset() will just set 2 bytes to 0 (the size of the pointer).

Yes, using pin 12 as RX and TX to read/write to the ECU's serial pinout.

Yes, this part.. I see zero on serial monitor, but if I put any value to ect after the math code eg. ect = 3;, then I see on serial monitor 3.. But it doesn't show the read of ect which the ECU is sending..

about the memset line.. Could you please provide me with more clarification?

You were not clear: do you see something different on the 7 segment display than in the Serial monitor or they both show 0 ? (meaning the reading has failed as the data is initialized in a if)

regarding memset: when you pass an array to a function, the array data type decays into a pointer, meaning the size is lost, what the function sees is only a pointer to the first element of the array. so your data parameter is a pointer and the size of a pointer is 2 bytes (or 4 on an ARM / ESP Arduino)

try to run this:

void printSize(byte d[]) {
  Serial.println(sizeof d);
}

void setup() {
  byte data[20];
  Serial.begin(115200);
  printSize(data);
}

void loop() {}

7 segment is displaying the correct value (coolant temperature) while serial monitor is showing ect as 0..

I will run this code and will feedback the result.

Yes, I have run the codes and got size of 2..

really weird...

You are trying to print things out after the function has returned so you will never see these messages

...
  if (data[0] != 0x00 && data[1] != (len + 3)) { // or use checksum?
    return 0; // error
    Serial.println("ECU readout error !");
  }
  if (i < (len + 3)) { // timeout
    return 0; // error
    Serial.println("ECU readout timeout !");
  }
  return 1; // success
  Serial.println("ECU readout success [OK]");
}

Many thanks, I have put the print before the return and I got the messages on the monitor, I will try the code on the car at morning without

if(dlcSerial.available()) {} 

I will try it with this one

int i = 0;
while (i < (len+3) && millis() < timeOut) {
data[i] = dlcSerial.read();
i++;
}

Let's see the result.

    return 0; // error
...
    return 1; // success

It's your choice, but usually programmers do the opposite.

I found the issue (really so wierd!! But of course there is a reason)..

All my last trials, the arduino was powered by the USB cable that was hooked into the laptop to read the serial messages (I was taking the laptop with me inside the car) ... Today, when I got tired of failed trials... I powered the arduino by the car's 12v to 5v adapter... And BINGO.. I got the serial messages successfully on the laptop!!!!

So wierd... Why changing from USB power to jack 5v power got things work ?!!!!

ah not same ground levels for the Serial line probably !!

Probably yes, I just want to know deeply why that happens, I will search for it..

Many thanks for your kind help bro.

when you have 2 devices powered independently they might not share the same ground, so levels for Tx/Rx won't be the meaningful (could even damage the board)