2
votes

I have a situation where I read values from sensors (attached to an arduino) which gets stored in a mysql database, which is then displayed on a webpage. At the same time relay values are read from a webpage, stored on mysql and then written to the arduino. I can do each separately but not at the same time. I've attached some code to show what Im trying to accomplish. I think it has something to do with Serial availability

/*----( SETUP: RUNS ONCE )----*/
void setup() {
  Serial.begin(115200);
  sensors.begin();     //Get DS18B20 temperatures
  sensors.setResolution(probe1, 10); //set resolution to 10bit
  sensors.setResolution(probe2, 10); //set resolution to 10bit
  Wire.begin();        // Start the Wire (I2C communications)
  RTC.begin();         // Start the RTC Chip

  digitalWrite(Relay_1, RELAY_OFF); //Relays
  digitalWrite(Relay_2, RELAY_OFF);

  pinMode(Relay_1, OUTPUT); //Set relays as outputs
  pinMode(Relay_2, OUTPUT);  
}
/*--(end setup )---*/

/****** LOOP: RUNS CONSTANTLY ******/
void loop() {
  ReadSensors();
  delay(1000);
  ReadRelays();  
}

/****** Read Sensors ******/
void ReadSensors()
{
  DateTime now = RTC.now();  //Get time from RTC
  photolevel = analogRead(photopin);  //Read light level

  sensors.requestTemperatures();
  dallas1 = sensors.getTempC(probe1);
  dallas2 = sensors.getTempC(probe2);

  dtostrf(photolevel, 1, 0, photo1);
  dtostrf(dallas1, 1, 2, temp1);
  dtostrf(dallas2, 1, 2, temp2);

  String tempAsString1 = String(photo1);
  String tempAsString2 = String(temp1);
  String tempAsString3 = String(temp2);

  Serial.print(now.year(), DEC);
  Serial.print('/');
  Serial.print(now.month(), DEC);
  Serial.print('/');
  Serial.print(now.day(), DEC);
  Serial.print(" ");
  Serial.print(now.hour(), DEC);
  Serial.print(':');
  Serial.print(now.minute(), DEC);
  Serial.print(" ");  
  Serial.println(tempAsString1 + " " + tempAsString2 + " " + tempAsString3);
  Serial.flush();
}

void ReadRelays()
{
  Serial.flush();
  // Read all serial data available, as fast as possible
  while(Serial.available() > 0)
  {
    char inChar = Serial.read();
    if(inChar == SOP)
    {
       index = 0;
       inData[index] = '\0';
       started = true;
       ended = false;
    }
    else if(inChar == EOP)
    {
       ended = true;
       break;
    }
    else
    {
      if(index < 79)
      {
        inData[index] = inChar;
        index++;
        inData[index] = '\0';
      }
    }
  }

  if(started && ended)
  {
    // The end of packet marker arrived. Process the packet 
    if (strlen(inData) > 0)
   {
      char *token = strtok(inData, ",");
      if(token)
      {
         index = 0;         
         array[index] = atoi(token);
         while (token = strtok(NULL, ","))
         {
            array[index++] = atoi(token);
         }
      }
    }

    Serial.println(array[0]);
    Serial.println(array[1]);

    // Reset for the next packet
    started = false;
    ended = false;
    index = 0;
    inData[index] = '\0';
  }
}

Any suggestions would be well appreciated??

1
You're not doing two things at the same time - there is just one core. The execution ping pong's between the two actions. Describe why you think this code does not work. You have not described the symptoms of the problem.jdr5ca
If I run the current code only ReadSensors appear to work. Meaning, the readings from sensors get displayed in the serial monitor and not the values from the python script which reads values into the arduino (ReadRelays). If I comment out ReadSensors then ReadRelays work just fine.user2081594
What kind of application(s) are interacting with the commport. To me this looks like a problem on the webserver (or whatever you have there) end and not the arduino.BetaRide
Please explain what the arduino is supposed to read from the serial port. You have Serial.flush() a couple of places, why? You also write to pins before pinmode is used in Setup, why?user2019047
Ok, with problem description, the failing is something writing over adjacent variables. The dstrtof is a good suspect. Show the global variable allocations.jdr5ca

1 Answers

1
votes

The key to do several things "at the same time" is to understand that the Arduino has only one core. Thus it will process stuff only one step after the other. Now suppose you want to perform three functions "action1()", "action2()" and "action3()" at "the same time. In order to achieve this you must ensure that

  1. all actions can be performed as fast as possible, preferably sub milliseconds
  2. none of them "blocks"

Then the desired effect is achieved by just putting them into succession like so

void loop() {
    action1();
    action2();
    action3();
}

This is the basic idea of "cooperative multitasking". It follows that none of the actions must utilize delay() or blocking waits. For example

  while(Serial.available() == 0);

is a blocking wait and must be avoided. Things get more complicated if any of the actions is a set of lengthy and involved computations. Say action1() takes 1s to process. Then action1() must be split into pieces that execute fast enough. The pieces can still be kept in action1() with the help of a "state machine". For example

void action1() {
    static uint8_t state = 0;

    switch (state) {
        case 1: sub_action1_1(); break;
        case 2: sub_action1_2(); break;
        case 3: sub_action1_2(); break;
        default: state = 0; return;
    }        
    ++state;
}

Of course the sub actions must perform fast enough. Another frequently encountered issue is how to wait without blocking. This is achieved by storing the required delay. E.g. like this

void action1() {
    static uint8_t state = 0;
    static unsigned long start_millis = 0;

    switch (state) {
        case 1: sub_action(); break;

        case 2: // this starts the delay
            start_millis = millis();
            break;

        case 3: // this checks if the delay has elapsed
            if (millis() - start_millis < 1000) {
                // if it did not yet elapse ensure that the state will not progress to the next step
                return;
            }
            // if the delay has elapsed proceed to next state
            break;

        case 4: next_sub_action(); break;

        default: state = 0; return;
    }        
    ++state;
}

Of course this is only the basic principle. In "real" implementations you may vary this as needed.

Another often needed thing is to have a main loop that does some stuff and a higher frequency "loop" that does some other stuff. This is usually performed with so called timer interrupts. This is more advanced but usually more efficient also. The tricky thing with interrupts is that they tend to be somewhat harder to debug. I have some documented examples for this in my blog.

blinking several LEDs with different frequencies. VU Meter experiment (scroll down!)