Issue with two millis() timers interfering

 previousInteger1FromPC = integer1FromPC;

Try moving this line from where it lives in recvWithStartEndMarkers() to the very start of parseData() before the new value is set.

It maybe creating the timing glitch, and it does create a linkage between the two areas which are supposed to be independent.

cattledog:

 previousInteger1FromPC = integer1FromPC;

Try moving this line from where it lives in recvWithStartEndMarkers() to the very start of parseData() before the new value is set.

It maybe creating the timing glitch, and it does create a linkage between the two areas which are supposed to be independent.

Hi cattledog, clever idea, I moved this line to parseData(), ..sadly still the same issue.

// http://forum.arduino.cc/index.php?topic=499210.msg3407044#msg3407044
// http://forum.arduino.cc/index.php?topic=396450.0

// HC12 Communication between Arduinos

/*
  This program serves to send one integer (or byte) only from two different HC12
  transmitters at one sensor each (A and B)to one HC12 receiver at the central
  controller Arduino. The receiving HC12 has to know from which transmitter A or B
  the value comes.
  The data are sent with start- and endmarkers

  v5: two integers used, one for the sensor value (integer1FromPC) and one
  for the sensor identifier (integer2FromPC). At the transmitter the sensor A or B are
  identiefied by reading two digital inputs connected to a dipswitch with
  2 switches (max: 4 different sensor/transmitters).

  // RECEIVER PART
*/

#include <SoftwareSerial.h>
const byte HC12RxdPin = 4;                  // Recieve Pin on HC12
const byte HC12TxdPin = 5;                  // Transmit Pin on HC12
SoftwareSerial HC12(HC12TxdPin, HC12RxdPin); // Create Software Serial Port
const byte numChars = 32;
char receivedChars[numChars];
char tempChars[numChars];        // temporary array for use when parsing
// variables to hold the parsed data
char messageFromPC[numChars] = {0};
int integer1FromPC;
int integer2FromPC;
static int previousInteger1FromPC;
static int previousInteger2FromPC;
float floatFromPC = 0.0;

boolean newData = false;

//============

void setup()
{
  Serial.begin(115200);
  HC12.begin(115200);       // Open serial port to HC12

  // declare pin 10, 11 & 12 as output
  pinMode (10, OUTPUT); // sensor value from A
  pinMode (11, OUTPUT); // sensor value from B
  pinMode (12, OUTPUT); // data being received
  pinMode (9, OUTPUT); // data received is different from previous data
  delay(100);
}

void loop() {

  static const int interval2 = 1100;
  static unsigned long previousMillis2;

  recvWithStartEndMarkers();
  if (newData == true) {
    strcpy(tempChars, receivedChars);
    // this temporary copy is necessary to protect the original data
    //   because strtok() used in parseData() replaces the commas with \0
    newData = false;
    parseData();
    useParsedData();
    if (previousInteger1FromPC != integer1FromPC) {
      digitalWrite (9, HIGH); // new data different from previous data
      previousMillis2 = millis();
    }
  }
  if (digitalRead(9) == HIGH) {
    if (millis() - previousMillis2 >= interval2) {
      digitalWrite (9, LOW);
    }
  }
}

//============

void recvWithStartEndMarkers() {

  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;
  static unsigned long previousMillis1; // timer
  static const int interval1 = 1000;
  boolean rxStatus = false;
  boolean ledState = false;


  while (HC12.available() > 0 && newData == false) {
    rc = HC12.read();

    if (recvInProgress == true) {
      if (rc != endMarker) {
        receivedChars[ndx] = rc;
        ndx++;
        if (ndx >= numChars) {
          ndx = numChars - 1;
        }
      }
      else {
        receivedChars[ndx] = '\0'; // terminate the string
        recvInProgress = false;
        ndx = 0;
        newData = true;
      }
    }

    else if (rc == startMarker) {
      recvInProgress = true;
      digitalWrite(12, HIGH); // new data received
      previousMillis1 = millis();
      //    previousInteger1FromPC = integer1FromPC;
    }
  }

  if (digitalRead(12) == HIGH) {
    if (millis() - previousMillis1 >= interval1) {
      digitalWrite(12, LOW);
    }
  }
}


//============

void parseData() {      // split the data into its parts

  previousInteger1FromPC = integer1FromPC;

  char * strtokIndx; // this is used by strtok() as an index. It creates the variable
  // strkIndx as a pointer to a variable of type char. It can hold the address of a
  // variable of type char.
  /*
    strtokIndx = strtok(tempChars, ",");     // get the first part - the string
    strcpy(messageFromPC, strtokIndx); // copy it to messageFromPC

    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    integer1FromPC = atoi(strtokIndx);     // convert this part to an integer
    /*
        strtokIndx = strtok(NULL, ",");
        floatFromPC = atof(strtokIndx);     // convert this part to a float
  */

  strtokIndx = strtok(tempChars, ",");     // get the first part - the string
  integer1FromPC = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  integer2FromPC = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  strcpy(messageFromPC, strtokIndx); // copy it to messageFromPC


}
//============

void useParsedData() {
  if (messageFromPC[0] == 'A') analogWrite (10, integer1FromPC);
  if (messageFromPC[0] == 'B') analogWrite (11, integer2FromPC);
}

I suspect we do not understand what you are trying to do and what is actually happening.

My understanding is that this is what happens ...
When a '<'' is detected pin 12 goes high and a timer is started that will turn that LOW after 1000 msecs

Regardless of the state of pin 12 ...
When a full message is received and parsed a value is placed in integer1FromPC
if that value is different from the previous value
pin9 goes HIGH and a timer is started that will turn that LOW after 1100 msecs

Is that what should be happening?

Have you measured the time that each of those LED's is on? (It would probably be better to give them significantly different times such as 1000 and 2000.) How long is each of them on?

You don't seem to have any code to show you the actual data that is received.

...R

Robin2:
I suspect we do not understand what you are trying to do and what is actually happening.

My understanding is that this is what happens ...
When a '<'' is detected pin 12 goes high and a timer is started that will turn that LOW after 1000 msecs

Regardless of the state of pin 12 ...
When a full message is received and parsed a value is placed in integer1FromPC
if that value is different from the previous value
pin9 goes HIGH and a timer is started that will turn that LOW after 1100 msecs

Is that what should be happening?

Have you measured the time that each of those LED's is on? (It would probably be better to give them significantly different times such as 1000 and 2000.) How long is each of them on?

You don't seem to have any code to show you the actual data that is received.

...R

Entirely correct.
When interval1 is 1000ms and interval2 os 1100ms then output pin9 goes HIGH only during 100ms, not 1100ms.
If interval2 is changed to 2000ms ten output pin9 goes HIGH during 1000ms.

brice3010:
When interval1 is 1000ms and interval2 os 1100ms then output pin9 goes HIGH only during 100ms, not 1100ms.
If interval2 is changed to 2000ms ten output pin9 goes HIGH during 1000ms.

Give some examples of the actual data that is in the array receivedChars[] that causes that result.

...R

Robin2:
Give some examples of the actual data that is in the array receivedChars[] that causes that result.

...R

This is what is being sent:
HC12.print('<');
HC12.print(val5);
HC12.print(',');
HC12.print(val5);
HC12.print(",B>");
I tried to print this (the array receivedChars[] ) out in the serial window on the receiver side but I am not sure how to.

Transmission side code:

// http://forum.arduino.cc/index.php?topic=499210.msg3407044#msg3407044
// http://forum.arduino.cc/index.php?topic=396450.0

// HC12 Communication between Arduinos

/*
  This program serves to send one integer (or byte) only from two different HC12
  transmitters at one sensor each (A and B)to one HC12 receiver at the central
  controller Arduino. The receiving HC12 has to know from which transmitter A or B
  the value comes.
  The data are sent with start- and endmarkers

  v5: two integers used, one for the sensor values (integer1FromPC & integer2FromPC) and
  one char for the sensor identifier (A or B). At the transmitter the sensors A or B are
  identiefied by reading two digital inputs connected to a dipswitch with
  2 switches (max: 4 different sensor/transmitters).

  // TRANSMITTER PART
*/

#include <SoftwareSerial.h>
const byte HC12RxdPin = 4;                  // Recieve Pin on HC12
const byte HC12TxdPin = 5;                  // Transmit Pin on HC12
SoftwareSerial HC12(HC12TxdPin, HC12RxdPin); // Create Software Serial Port
int analogValue5, val5;
int previousAnalogValue5;
int HC12power = 8;
const int interval1 = 3000; // HC12 power-on time in milliseconds
const int interval2 = 2000; // HC12 retransmission time delay
static unsigned long previousMillis1; // timer1
static unsigned long previousMillis2; // timer2
boolean HC12ResendReady = true;

void setup()
{
  Serial.begin(115200);     // Open serial port to computer
  HC12.begin(115200);       // Open serial port to HC12
  pinMode(HC12power, OUTPUT);
}

void loop()
{
  // read analog pin 5
  analogValue5 = analogRead(5);
  // remap values from the analogValue5 variable to 0 / 255
  val5 = map(analogValue5, 0, 1023, 0, 255);
  // detect if there is a change in value, if so: switch on HC12
  if (analogValue5 > (previousAnalogValue5 + 10) || analogValue5 < (previousAnalogValue5 - 10))
  {
    previousAnalogValue5 = analogValue5;
    // start or extend timer if power is off or on and analogValue5 changes
    previousMillis1 = millis();  //reset timer as long as changes are detected within interval window
    
    if (digitalRead(HC12power) == LOW)
    {
      digitalWrite(HC12power, HIGH);
      delay(40);
    }

    if (HC12ResendReady == true)
    {
      HC12.print('<');
      HC12.print(val5);
      HC12.print(',');
      HC12.print(val5);
      HC12.print(",B>");
      HC12ResendReady = false;
      previousMillis2 = millis();

    }
  }
  if ((millis() - previousMillis2) >= interval2) {
    //previousMillis2 = millis();
    HC12ResendReady = true;
  }

  
    //when no more change in value for analogValue5, then start timer before switching off HC12
    if ((millis() - previousMillis1) >= interval1) {
      digitalWrite(HC12power, LOW);
    }
}

Robin2:
Give some examples of the actual data that is in the array receivedChars[] that causes that result.

...R

Here is the output at the receiver side (sorry, I had forgotten to download the code with Serial.print(); to the receiver when writing post #25):

12,12,B

This is just an example; the values of the first two characters change every time.

Every time val5 changes on the receiver side, 2 more characters and a ,B are added

The strange thing is that:

  1. not consistently identical values for the first two characters are sent.
  2. there are instances when the values are not ASCII numbers (ie characters with x, or ~< , or \ instead of comma)
    But when the bursts are made with at least 5 second intervals then the data in the serial window appears regular: identical for both first values, commas in place,..

brice3010:
The strange thing is that:

  1. not consistently identical values for the first two characters are sent.
  2. there are instances when the values are not ASCII numbers (ie characters with x, or ~< , or \ instead of comma)
    But when the bursts are made with at least 5 second intervals then the data in the serial window appears regular: identical for both first values, commas in place,..

You are losing me here. You need to post examples of the unusual messages that are being received. For example, if a message incorrectly contains two '<' characters your timing algorithms will behave strangely.

Why have you added any timing code into the function recvWithStartEndMarkers()? The way I wrote the function it is not intended to have any meaningful result until it gets to the point of newData = true.

Also, I did not design the function so it could deal with corrupted data. That would require more complex code - for example what should it do if a 2nd start-marker was detected? Should it treat the whole message so far as invalid and wait for a 3rd start-marker? I think you can see how the complexity could snowball.

...R

Robin2:
You are losing me here. You need to post examples of the unusual messages that are being received. For example, if a message incorrectly contains two '<' characters your timing algorithms will behave strangely.

output from the serial window:

231,231,B
237\237,B
243,24c,B
228,228,B
207,2`7,B
197,19g,B
178,178,B
164\164,B
152,a52,B
130,130,B
117,117,B
101,101,B
y5,95,B
79,79,B
68,f8,B
63,63\B
68,68,B
74,74\B
87,87,⸮
90,y0,B
103\103,B
113,113,⸮
125,125,B?<137,a37,B
148,148,B
1e8,158,B
173,1g3,B
180,180,B
183,183,B
199,199,⸮
211,211,B~<230,230\B
222,222,B~<229,2b9,B
217,21g,B
200,200,B
187,18g,B
176,176,B
167,167\B
172,1g2,B
181,181,B
a98,198,B
214\214,B
227,2b7,B
238,238,B
145,245,B
250,250,B
236,236,B~<222,222,B
21c,213,B
204,204\B

Robin2:
Why have you added any timing code into the function recvWithStartEndMarkers()? The way I wrote the function it is not intended to have any meaningful result until it gets to the point of newData = true.

I understand that; the timing code in that function is executed after newData = true.

Robin2:
I wonder how your program would behave if you change this piece of the function so it resets the index when it detects the start marker. I will reflect on whether this would be a worthwhile change in the tutorial.

else if (rc == startMarker) {

recvInProgress = true;
     ndx = 0;                //  NEW
     digitalWrite(12, HIGH); // new data received
     previousMillis1 = millis();
     //    previousInteger1FromPC = integer1FromPC;
}




...R

The quality of the received characters do not seem to impact the timing issue for interval2: every time a transmission takes place, the 2 outputs behave consistently: output pin12 goes HIGH for 1000ms, immediately after that the output pin9 goes HIGH 100ms (when actually the timer for interval2 = 1100ms)

brice3010:
I understand that; the timing code in that function is executed after newData = true.

That is not correct. The timing process is started when the start-marker is detected. In fact the code that you have at the end of the function

  if (digitalRead(12) == HIGH) {
    if (millis() - previousMillis1 >= interval1) {
      digitalWrite(12, LOW);
    }
  }

probably should not be in that function at all as it has nothing to do with receiving characters.

And you have not said WHY you are turning on an LED. It is much easier to help when we understand what you are trying to achieve.

...R

When looking at the output from the serial window I notice that in all except 4 cases the received charactersets nicely contain 3 characters each: 2 times a value for val5, and then -mostly- a ,B

But the fact that they all, except in 4 cases, start on a new line, means that the execution of the parsing happens right, regardless of the contents: and that is shown by the behaviour of outputs 12 and 9: every time first 1000ms for output12, then 100ms for output 9 (even though that should be 1100ms).

Robin2:
That is not correct. The timing process is started when the start-marker is detected.

I stand corrected; sorry, indeed. Should I place this line elsewhere, ie, after newData=true?

Robin2:
And you have not said WHY you are turning on an LED.

...R

I assume you mean the second LED? Because I intend to use that in the future, for example to verify if data is being correctly read, or as a visual indicator with a LED.

If I move the command to turn on output 12 to where newData=true, still the same issue,

// http://forum.arduino.cc/index.php?topic=499210.msg3407044#msg3407044
// http://forum.arduino.cc/index.php?topic=396450.0

// HC12 Communication between Arduinos

/*
  This program serves to send one integer (or byte) only from two different HC12
  transmitters at one sensor each (A and B)to one HC12 receiver at the central
  controller Arduino. The receiving HC12 has to know from which transmitter A or B
  the value comes.
  The data are sent with start- and endmarkers

  v5: two integers used, one for the sensor value (integer1FromPC) and one
  for the sensor identifier (integer2FromPC). At the transmitter the sensor A or B are
  identiefied by reading two digital inputs connected to a dipswitch with
  2 switches (max: 4 different sensor/transmitters).

  // RECEIVER PART
*/

#include <SoftwareSerial.h>
const byte HC12RxdPin = 4;                  // Recieve Pin on HC12
const byte HC12TxdPin = 5;                  // Transmit Pin on HC12
SoftwareSerial HC12(HC12TxdPin, HC12RxdPin); // Create Software Serial Port
const byte numChars = 32;
char receivedChars[numChars];
char tempChars[numChars];        // temporary array for use when parsing
// variables to hold the parsed data
char messageFromPC[numChars] = {0};
int integer1FromPC;
int integer2FromPC;
static int previousInteger1FromPC;
static int previousInteger2FromPC;
float floatFromPC = 0.0;

boolean newData = false;

//============

void setup()
{
  Serial.begin(115200);
  HC12.begin(115200);       // Open serial port to HC12

  // declare pin 10, 11 & 12 as output
  pinMode (10, OUTPUT); // sensor value from A
  pinMode (11, OUTPUT); // sensor value from B
  pinMode (12, OUTPUT); // data being received
  pinMode (9, OUTPUT); // data received is different from previous data
  delay(100);
}

void loop() {

  const int interval2 = 1100;
  static unsigned long previousMillis2;

  recvWithStartEndMarkers();
  if (newData == true) {
    strcpy(tempChars, receivedChars);
    Serial.println(receivedChars);
    // this temporary copy is necessary to protect the original data
    //   because strtok() used in parseData() replaces the commas with \0
    newData = false;
    parseData();
    useParsedData();
    if (previousInteger1FromPC != integer1FromPC) {
      digitalWrite (9, HIGH); // new data different from previous data
      previousMillis2 = millis();
    }
  }
  if (digitalRead(9) == HIGH) {
    if (millis() - previousMillis2 >= interval2) {
      digitalWrite (9, LOW);
    }
  }
}

//============

void recvWithStartEndMarkers() {

  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;
  static unsigned long previousMillis1; // timer
  static const int interval1 = 1000;
  boolean rxStatus = false;
  boolean ledState = false;


  while (HC12.available() > 0 && newData == false) {
    rc = HC12.read();

    if (recvInProgress == true) {
      if (rc != endMarker) {
        receivedChars[ndx] = rc;
        ndx++;
        if (ndx >= numChars) {
          ndx = numChars - 1;
        }
      }
      else {
        receivedChars[ndx] = '\0'; // terminate the string
        recvInProgress = false;
        ndx = 0;
        newData = true;
        digitalWrite(12, HIGH); // new data received
        previousMillis1 = millis();

      }
    }

    else if (rc == startMarker) {
      recvInProgress = true;
    }
  }

  if (digitalRead(12) == HIGH) {
    if (millis() - previousMillis1 >= interval1) {
      digitalWrite(12, LOW);
    }
  }
}


//============

void parseData() {      // split the data into its parts

  previousInteger1FromPC = integer1FromPC;

  char * strtokIndx; // this is used by strtok() as an index. It creates the variable
  // strkIndx as a pointer to a variable of type char. It can hold the address of a
  // variable of type char.
  /*
    strtokIndx = strtok(tempChars, ",");     // get the first part - the string
    strcpy(messageFromPC, strtokIndx); // copy it to messageFromPC

    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    integer1FromPC = atoi(strtokIndx);     // convert this part to an integer
    /*
        strtokIndx = strtok(NULL, ",");
        floatFromPC = atof(strtokIndx);     // convert this part to a float
  */

  strtokIndx = strtok(tempChars, ",");     // get the first part - the string
  integer1FromPC = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  integer2FromPC = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  strcpy(messageFromPC, strtokIndx); // copy it to messageFromPC


}
//============

void useParsedData() {
  if (messageFromPC[0] == 'A') analogWrite (10, integer1FromPC);
  if (messageFromPC[0] == 'B') analogWrite (11, integer2FromPC);
}

Robin2:
And you have not said WHY you are turning on an LED. It is much easier to help when we understand what you are trying to achieve.

...R

For the first output (interval1) the purpose is to visually show a message is received, intended later to be used as a marker for further programming. The purpose of the second output (interval2) is to identify a correct message (ie different from the previous) is received.
And sending two values as character may be used to verify that the received value is correct (ie both values must be identical).

But regardless of that I am puzzled by the fact that I seem unable to use interval2 as intended, ie set output9 HIGH during the time interval2.

I changed the transmitter program to transmit in fixed timeperiods (set with interval1=500ms) instead of relying on a change in value for val5:

// http://forum.arduino.cc/index.php?topic=499210.msg3407044#msg3407044
// http://forum.arduino.cc/index.php?topic=396450.0

// HC12 Communication between Arduinos

/*
  This program serves to send one integer (or byte) only from two different HC12
  transmitters at one sensor each (A and B)to one HC12 receiver at the central
  controller Arduino. The receiving HC12 has to know from which transmitter A or B
  the value comes.
  The data are sent with start- and endmarkers

  v2: two integers used, one for the sensor values (integer1FromPC & integer2FromPC) and
  one char for the sensor identifier (A or B). At the transmitter the sensors A or B are
  identiefied by reading two digital inputs connected to a dipswitch with
  2 switches (max: 4 different sensor/transmitters).

  v3: fixed retransilission timing

  // TRANSMITTER PART
*/

#include <SoftwareSerial.h>
const byte HC12RxdPin = 4;                  // Recieve Pin on HC12
const byte HC12TxdPin = 5;                  // Transmit Pin on HC12
SoftwareSerial HC12(HC12TxdPin, HC12RxdPin); // Create Software Serial Port
int analogValue5, val5;
int HC12power = 8;
const int interval1 = 500; // HC12 power-on time in milliseconds
// const int interval2 = 500; // HC12 retransmission time delay
const int interval3 = 200; // HC12 fixed retransmission timings
unsigned long previousMillis1; // timer1
// unsigned long previousMillis2; // timer2
unsigned long previousMillis3 = 0; // timer3
void setup()
{
  Serial.begin(115200);     // Open serial port to computer
  HC12.begin(115200);       // Open serial port to HC12
  pinMode(HC12power, OUTPUT);
}

void loop()
{
  // read analog pin 5
  analogValue5 = analogRead(5);
  // remap values from the analogValue5 variable to 0 / 255
  val5 = map(analogValue5, 0, 1023, 0, 255);
  if (millis() - previousMillis3 >= interval3) {
    previousMillis3 = millis();

    if (digitalRead(HC12power) == LOW)
    {
      digitalWrite(HC12power, HIGH);
      delay(100);
    }
    HC12.print('<');
    HC12.print(val5);
    HC12.print(',');
    HC12.print(val5);
    HC12.print(",B>");
    previousMillis3 = millis();
      if (millis() - previousMillis1 >= interval1) {
    digitalWrite(HC12power, LOW);
    previousMillis1 = millis();
  }
  }
  //start timer to switch off HC12

}

Serial window output:

1d3,143,B
143,1d3,B
143,143,B
143\143,B
143,143,⸮
143,143,B
143,1d3,B
143,143,B
143,a43,B
143,143,B~<1d3,143,B
143,14c,B
143,143,B
143,a43,B
143,143,⸮
14c,143,B
143,1d3,B
143,143,B
143\143,B
143,143,⸮
14c,143,B
143,143\B
143,143,B
143,a43,B
143,143,B~<14c,143,B
143,14c,B
143,143,B
143,a43,B
143,143,B~<14c,143,B
143,143\B
a43,143,B
143,1d3,B
143,143,B~<143,143,B
143,143\B
1d3,143,B
143,a43,B
143,143,B
143\143,B
143,143,⸮
1d3,143,B
143,1d3,B
143,143,B
143\143,B
143,143,C
1d3,143,B
143,14c,B
143,143,B
143\143,B
143,143\B
14c,143,B
143,1d3,B
143,143,B
143\143,B
143,143,⸮
1d3,143,B
143,14c,B
143,143,B
143,a43,B
143,143,B~<14c,143,B
143,14c,B
143,143,B
143,a43,B
143,143,B~<1d3,143,B
143,14c,B
a43,143,B
143,1d3,B
143,143,B~<14c,143,B
143,143\B
a43,143,B
143,a43,B
143,143,B~<143,143,B
143,143.B
1d3,143,B
143,1d3,B
143,143,B
143\143,B
143,143,⸮
a43,143,B
143,1d3,B
143,143,B
143\143,B
143,143\B
14c,143,B
143,1d3,B
143,143,B?<143\143,B
143,143,⸮
1d3,143,B
143,14c,B
143,143,B
143\143,B
143,143,⸮
14c,143,B
143,14c,B
143,143,B

And now subsequently also changed the code for the receiver to always blink output9 right after output12 has gone LOW again.
Still the same issus: output9 blinks for a period = interval2 - interval1 instead of the expected period = interval2.

// http://forum.arduino.cc/index.php?topic=499210.msg3407044#msg3407044
// http://forum.arduino.cc/index.php?topic=396450.0

// HC12 Communication between Arduinos

/*
  This program serves to send one integer (or byte) only from two different HC12
  transmitters at one sensor each (A and B)to one HC12 receiver at the central
  controller Arduino. The receiving HC12 has to know from which transmitter A or B
  the value comes.
  The data are sent with start- and endmarkers

  v5: two integers used, one for the sensor value (integer1FromPC) and one
  for the sensor identifier (integer2FromPC). At the transmitter the sensor A or B are
  identiefied by reading two digital inputs connected to a dipswitch with
  2 switches (max: 4 different sensor/transmitters).

  // RECEIVER PART
*/

#include <SoftwareSerial.h>
const byte HC12RxdPin = 4;                  // Recieve Pin on HC12
const byte HC12TxdPin = 5;                  // Transmit Pin on HC12
SoftwareSerial HC12(HC12TxdPin, HC12RxdPin); // Create Software Serial Port
const byte numChars = 32;
char receivedChars[numChars];
char tempChars[numChars];        // temporary array for use when parsing
// variables to hold the parsed data
char messageFromPC[numChars] = {0};
int integer1FromPC;
int integer2FromPC;
static int previousInteger1FromPC;
static int previousInteger2FromPC;
float floatFromPC = 0.0;

boolean newData = false;

//============

void setup()
{
  Serial.begin(115200);
  HC12.begin(115200);       // Open serial port to HC12

  // declare pin 10, 11 & 12 as output
  pinMode (10, OUTPUT); // sensor value from A
  pinMode (11, OUTPUT); // sensor value from B
  pinMode (12, OUTPUT); // data being received
  pinMode (9, OUTPUT); // data received is different from previous data
  delay(100);
}

void loop() {

  const int interval2 = 200;
  static unsigned long previousMillis2;

  recvWithStartEndMarkers();
  if (newData == true) {
    strcpy(tempChars, receivedChars);
    Serial.println(receivedChars);
    // this temporary copy is necessary to protect the original data
    //   because strtok() used in parseData() replaces the commas with \0
    parseData();
    useParsedData();
    if (newData == true) {
      digitalWrite (9, HIGH); // new data different from previous data
      previousMillis2 = millis();
    }
    newData = false;

  }
  if (digitalRead(9) == HIGH) {
    if (millis() - previousMillis2 >= interval2) {
      digitalWrite (9, LOW);
    }
  }
}

//============

void recvWithStartEndMarkers() {

  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;
  static unsigned long previousMillis1; // timer
  static const int interval1 = 100;
  boolean rxStatus = false;
  boolean ledState = false;


  while (HC12.available() > 0 && newData == false) {
    rc = HC12.read();

    if (recvInProgress == true) {
      if (rc != endMarker) {
        receivedChars[ndx] = rc;
        ndx++;
        if (ndx >= numChars) {
          ndx = numChars - 1;
        }
      }
      else {
        receivedChars[ndx] = '\0'; // terminate the string
        recvInProgress = false;
        ndx = 0;
        newData = true;
      }
    }

    else if (rc == startMarker) {
      recvInProgress = true;
      digitalWrite(12, HIGH); // new data received
      previousMillis1 = millis();
      //    previousInteger1FromPC = integer1FromPC;
    }
  }

  if (digitalRead(12) == HIGH) {
    if (millis() - previousMillis1 >= interval1) {
      digitalWrite(12, LOW);
    }
  }
}


//============

void parseData() {      // split the data into its parts

  previousInteger1FromPC = integer1FromPC;

  char * strtokIndx; // this is used by strtok() as an index. It creates the variable
  // strkIndx as a pointer to a variable of type char. It can hold the address of a
  // variable of type char.
  /*
    strtokIndx = strtok(tempChars, ",");     // get the first part - the string
    strcpy(messageFromPC, strtokIndx); // copy it to messageFromPC

    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    integer1FromPC = atoi(strtokIndx);     // convert this part to an integer
    /*
        strtokIndx = strtok(NULL, ",");
        floatFromPC = atof(strtokIndx);     // convert this part to a float
  */

  strtokIndx = strtok(tempChars, ",");     // get the first part - the string
  integer1FromPC = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  integer2FromPC = atoi(strtokIndx);     // convert this part to an integer

  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  strcpy(messageFromPC, strtokIndx); // copy it to messageFromPC


}
//============

void useParsedData() {
  if (messageFromPC[0] == 'A') analogWrite (10, integer1FromPC);
  if (messageFromPC[0] == 'B') analogWrite (11, integer2FromPC);
}

Sometimes the startmarker is missed and output12 is not set HIGH, yet the parsing program puts out an array with twice as many data (which is seen in the serial output window as strings twice as long), at those instances output¨9 blinks as it should: interval2 time length.

This means that the timer routine for output12 using interval1 in void recWithStartEndMarkers() does inhibit proper functioning of the timer routine in void loop()

How is it possible that a called function interferes with a timer used in void loop() ?

Hold on. Slow down. Just post one message and wait for a response, I can't keep up with you.

Back in Reply #32 you said

I assume you mean the second LED? Because I intend to use that in the future, for example to verify if data is being correctly read, or as a visual indicator with a LED.

I have no idea which one is the 2nd LED in your mind. I was referring to the LED that is turned on in the function recvWithStartEndMarkers(). Personally I can't see how that LED adds any value.

Before you can make any progress you need to figure out why the data is being corrupted - or at least have a system so that the receiving code knows it is corrupt.

I don't have any HC12 devices so I have no idea whether corruption is common - but I don't recall it being mentioned in other Threads. How far apart are your Rx and Tx? Maybe they are too close to, or too far from each other?

One way to enable the receiver to verify the received data is to include a checksum byte. But if you will need to ensure that the checksum is never '>'.

...R

Robin2:
Hold on. Slow down. Just post one message and wait for a response, I can't keep up with you.

Back in Reply #32 you said
I have no idea which one is the 2nd LED in your mind. I was referring to the LED that is turned on in the function recvWithStartEndMarkers(). Personally I can't see how that LED adds any value.

Before you can make any progress you need to figure out why the data is being corrupted - or at least have a system so that the receiving code knows it is corrupt.

I don't have any HC12 devices so I have no idea whether corruption is common - but I don't recall it being mentioned in other Threads. How far apart are your Rx and Tx? Maybe they are too close to, or too far from each other?

One way to enable the receiver to verify the received data is to include a checksum byte. But if you will need to ensure that the checksum is never '>'.

...R

Hi Robin2, "the second LED" refers to output9 (using interval2): this is switched HIGH as soon as newData == true. The "first LED" is switched as soon as a start marker is detected.

But here the issue is not so much that incoming data is corrupted, at least not as long as nice 3-word strings are parsed (2 values and a character 'B'). The issue I have is that the timer used in void loop() is affected by the timer in void recWithStartEndMarkers().

I rewrote the TX program so that now at fixed intervals transmissions are taking place.

(Although there is a small error in the timing there, I will fix that later the coming hours).

Tx is set to every 500ms
RX listens continuously