The issue was that you are not allowed to block shared resources (like Serial1) in a software timer.
Moving that stuff into serialEvent1() isn’t really anything other than having the same code inside loop() since these “events” are no real events, but just a synchronous function that’s called between iterations of loop().
But this will still have impact on the execution speed of loop() whereas this (untested) code would be non-blocking
char buf[31];
int bufIndex = -1; // current index in message buffer (-1 indicates not started)
void SerialEvent1()
{
int b = 0;
// when not already started a message, flush everything up to first 'B'
while (bufIndex < 0 && (b = Serial1.read()) >= 0 && b != 'B') Particle.process();
// if we got a start byte start a new message
if ('B' == b) bufIndex = 0; // had en error here, hence the following discussion (if (`B` = b) caused the problem)
// fill all available bytes into open message buffer
while (0 <= bufIndex && bufIndex < sizeof(buf) && Serial1.available())
{
buf[bufIndex++] = Serial1.read();
Particle.process();
}
if (bufIndex == sizeof(buf))
{
if(buf[0] == 0x4d && checkValue(buf,LENG))
{
PM01Value=transmitPM01(buf); //count PM1.0 value of the air detector module
PM2_5Value=transmitPM2_5(buf);//count PM2.5 value of the air detector module
PM10Value=transmitPM10(buf); //count PM10 value of the air detector module
}
bufIndex = -1; // mark as treated and ready for next message
}
}
The reason why software timers are not impacted by a blocking app code is that these are handled by RTOS, which executes them “asynchronously” to the main application.
If you add a D7 blink code like digitalWrite(D7, (millis() >> 2) & 0x88); to loop() you should see frequent glitches in the pattern when your code blocks, but with the above, these glitches should be less noticeable.
Non-blocking code, gave these values initially:
PM1.0: 15 ug/m3
PM2.5: 20 ug/m3
PM1 0: 22 ug/m3
and these values remain forever. Would be nice if this works...
Will attempt to debug when I'm back from work...
This code:
void serialEvent1() {
if(Serial1.find("B")) { //start to read when detect 0x42
Serial1.readBytes(buf,LENG);
if(buf[0] == 0x4d) {
if(checkValue(buf,LENG)) {
PM01Value=transmitPM01(buf); //count PM1.0 value of the air detector module
PM2_5Value=transmitPM2_5(buf);//count PM2.5 value of the air detector module
PM10Value=transmitPM10(buf); //count PM10 value of the air detector module
}
}
}
}
it updates nicely. But as you said, I think it has an impact on the loop()... It didn't completely hang or crash, but there was occasional WiFi disconnects with blinking cyan... Have to study more into this...
if (bufIndex == sizeof(buf))
{
if(buf[0] == 0x4d && checkValue(buf,LENG))
{
PM01Value=transmitPM01(buf); //count PM1.0 value of the air detector module
PM2_5Value=transmitPM2_5(buf);//count PM2.5 value of the air detector module
PM10Value=transmitPM10(buf); //count PM10 value of the air detector module
}
bufIndex = -1; // mark as treated and ready for next message
}
Only once, the first time: if (bufIndex == sizeof(buf)) came true if(buf[0] == 0x4d) came true
Never again!
what bytes did you get comming in after the first successful message?
Adding some extra Serial.print() statements to see the behaviour of variables (e.g. bufIndex, buf[] and the data from Serial1) would be the first step to debug the cause.
I have no such sensor, so I can’t really test anything.
If you can expect full messages to come back to back - without garbage in between - you could try setting bufIndex = 0; instead of -1 after a successful read.
void serialEvent1()
{
int b = 0;
// when not already started a message, flush everything up to first 'B'
// Serial.print("Serial1 Read: ");
// Serial.println(Serial1.read());
while (bufIndex < 0 && (b = Serial1.read()) >= 0 && b != 'B'){
Particle.process();
// Serial.println("BufIndex is less than zero, AND b is eqial to Serial1 Read AND b is not equal to B");
}
// if we got a start byte start a new message
if (b = 'B') {
// Serial.println("b is equal to B");
bufIndex = 0;
}
// fill all available bytes into open message buffer
// Serial.print("Serial1 Available: ");
// Serial.println(Serial1.available());
while (0 <= bufIndex && bufIndex < sizeof(buf) && Serial1.available())
{
// Serial.println("Serial1 Read while 0<=bufIndex & bufIndex < sizeof(buf): ");
// Serial.println(Serial1.read());
Serial.print("bufIndex: ");
Serial.println(bufIndex);
buf[bufIndex++] = Serial1.read();
Particle.process();
}
// Serial.print("Buffer Index: ");
// Serial.println(bufIndex);
// Serial.print("Size of buf: ");
// Serial.println(sizeof(buf));
if (bufIndex == sizeof(buf))
{
Serial.println("bufIndex == sizeof(buf)");
// Serial.print("Buffer at Zero: ");
// Serial.println(buf[0]);
if(buf[0] == 0x4d) {
Serial.println("buf[0] == 0x4d");
if(checkValue(buf,LENG)) {
// Serial.println("Checked Value buf,length");
PM01Value=transmitPM01(buf); //count PM1.0 value of the air detector module
PM2_5Value=transmitPM2_5(buf);//count PM2.5 value of the air detector module
PM10Value=transmitPM10(buf); //count PM10 value of the air detector module
}
}
bufIndex = 0; // mark as treated and ready for next message
}
}
Thanks @rickkas7, that’s so embarrasing
In another thread myself suggested to another member to flip if statements round to if ('B' == b) to get build errors when failing to use the correct ==
@ilak2k, I think you can now put the -1 back in place, where it’s supposed to be.
So my PMS7003 arrived today… but it might be a bit before I get it working.
You were right - it’s small… REALLY small. So small that the 2x5 connector for it is on - get this - 0.05" centers! Not the usual 0.1" centers… 0.05". Fortunately they paired it with an equally tiny socket connector so I have something to wire it to… but it’s going to be a challenge either way.
Will update when I’ve gotten it wired up and connected.
So, after one tricky soldering job and a few translations of similar datasheets, I got mine connected and got some data out. Currently it’s serial, but I’ll probably change that to cloud soon, once I better-understand what all the data means.
I hope you got the PMS7003 with cable like in this picture here...
Even though the connectors on the sensor side for 5003 and 7003 are different, it looks like the same connector that goes to the micro controller side...
To connect the sensor, I did this:
Removed/popped the leads off the small white connector
Connected the leads to a header strip, not soldered yet!
I got a tiny 1.27mm pitch 2x5 female header and that was all. No carrier board, no wire, no nothing else (it looks like that board is made to adapt that 1003/3003/5003 cable to the 7003’s new, microscopic header… would be nice to be able to get one of those eventually). Had my AliExpress order gone through I would’ve gotten the one pictured. That’d’ve saved a lot of time.
Still, at least it seems to work OK… I’m busy integrating this into my multi-sensor hobby project now. Hopefully it’s instructive (this sensor’s code is NOT fully integrated yet - just dabbling with it as I have free personal time).
EDIT: And yes, my old code had a subtle bug in it (which is why the checksums would mismatch periodically)… I’ve uploaded the updated demo code for the PMS7003 at:
EDIT2: A photo of the project as it is today. Inset shows my dodgy soldering job on that tiny connector… if half-pitch perf boards weren’t so rare it’d have been a lot easier.
I won’t say it’s final, but the repos above are current (and the sensor manager project is going to be the most current for now). It ought to work with the 5003, 3003, etc. but I haven’t tested those… I think (but am not sure) that the generations of Plantower’s devices vary primarily in size, not API/interface.
In other news, DigiKey appears to carry the vexing little 1.27mm pitch connector for the PMS7003 - part #609-3754-ND (part of Amphenol’s Minitek 127 series). I’ll probably be buying a couple of these to improve upon my current soldering job (I’ve already sourced some 1.27mm pitch double-sided plated perfboard for my bench supplies).
The half-pitch perfboard is neither cheap nor readily available (it’s still on its way from China). I wasn’t about to wait. (You’re rather lucky with the 5003 - it’s not hard to get a connector for that, versus the 7003 - nobody sells a breakout board or converter for that.)
I’m glad you like the code! It’s still very much a work in progress… still need to update the backend code to be more useful, and interpret the PM data more usefully as well.
In other news, Plantower has released an even smaller sensor, the A003… haven’t seen it for sale yet but it uses that same tiny connector as the 7003