Although I’d go a completely different route if this was my project, I have tried to tweak your code a bit to address some of the issues I see.
Give this a try and feel free to report back
#include <ParticleSoftSerial.h>
ParticleSoftSerial MHZ_16(D5, D6);
const unsigned char cmd_get_sensor[] = {0xff,0x01,0x86,0x00,0x00,0x00,0x00,0x00,0x79};
const unsigned char cmd_calibratea[] = {0xff,0x87,0x87,0x00,0x00,0x00,0x00,0x00,0xf2};
int temMH;
int CO2MH;
SerialLogHandler logHandler;
void setup() {
MHZ_16.begin(9600,SERIAL_8N1);
Serial.begin(115200);
Log.info("Main start");
Log.info("System version: %s", (const char*)System.version());
//MHZ_16.write(cmd_calibratea,9);
}
void loop() {
static uint32_t msDelay = 0;
if (millis() - msDelay < 3000) return;
msDelay = millis();
if(dataRecieve()) {
Log.info("Temperature: %d", temMH);
Log.info("CO2--------: %d", CO2MH);
}
}
bool dataRecieve(void) {
byte data[9], chksum=0x00;
int len = -1, ntry=0, nmtry=10, i =0;
while((len < 9 && ntry < nmtry)) {
MHZ_16.flush(); // flush TX buffer
while(MHZ_16.read() >= 0); // flush RX buffer
MHZ_16.write(cmd_get_sensor, 9);
// delay until 9 bytes are present in RX buffer, timeout after 500ms
for(uint32_t msTimeout = millis(); (len = MHZ_16.available()) < 9 && (millis() - msTimeout < 500); Particle.process());
ntry++;
Log.info("Available--: %d", len);
Log.info("NumMHZ try-: %d", ntry);
}
if (len < 9) {
Log.warn("Not enough data received - bailing out!");
return false; // no valid data found
}
// only read the first set of returned data
for(i = 0; i < len; i++) {
data[i] = MHZ_16.read();
Serial.print(data[i], HEX);
}
Serial.println();
for(i = 1; i < 9; i++)
chksum += data[i];
Serial.println(chksum, HEX);
if(len == 9)
CO2MH = (int)data[2] * 256 + (int)data[3];
// this is invalid as it would access array indexes beyond the array length!!!
//if(len == 18)
// CO2MH = (int)data[2+8] * 256 + (int)data[3+8];
temMH = (int)data[4] - 40;
return true;
}
One thing puzzled me completely, you have your dataReceived()
return a bool
you even check in your loop()
but that function always returns true
, even if it would fail - that’s rather confusing IMO.
The other thing was the “illegal” access to out of bound indexes for your ˋdataˋ array.
This would be my (untested) take on the matter
#include <ParticleSoftSerial.h>
const uint8_t cmd_get_sensor[] = { 0xff, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79 };
const uint8_t cmd_calibratea[] = { 0xff, 0x87, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2 };
const uint8_t READ_DELAY = 3000;
SerialLogHandler logHandler(LOG_LEVEL_ALL);
ParticleSoftSerial MHZ_16(D5, D6);
void setup() {
Serial.begin(115200);
MHZ_16.begin(9600, SERIAL_8N1);
MHZ_16.setTimeout(500); // wait up to 500ms for the data to return in full
Log.info("Main start");
Log.info("System version: %s", (const char*)System.version());
//MHZ_16.write(cmd_calibratea, sizeof(cmd_calibratea));
}
void loop() {
// non-blocking delay to reduce cadence of loop()
static uint32_t msDelay = 0;
if (millis() - msDelay < READ_DELAY) return;
int temMH;
int CO2MH;
if(dataRecieve(temMH, CO2MH)) {
Log.info("Temperature: %d", temMH);
Log.info("CO2--------: %d", CO2MH);
msDelay = millis(); // delay next read attempt
}
}
bool dataRecieve(int& temp, int& co2) {
char data[9];
char chksum = 0x00;
MHZ_16.flush(); // flush TX buffer
while(MHZ_16.read() >= 0); // flush RX buffer
MHZ_16.write(cmd_get_sensor, sizeof(cmd_get_sensor)); // send read request
if (MHZ_16.readBytes(data, sizeof(data)) < sizeof(data)) { // attempt to read response frame
Log.warn("Not enough data received - bailing out!");
return false; // bail out
}
for(int i = 0; i < sizeof(data); i++)
Serial.print(data[i], HEX);
Serial.println();
for(int i = 1; i < sizeof(data); i++)
chksum += data[i];
if (chksum != data[0]) {
Log.warn("wrong checksum (%02x vs. %02x)", chksum, data[0]);
return false; // bail out
}
co2 = (int)data[2] * 256 + (int)data[3];
temp = (int)data[4] - 40;
return true;
}