Passing argument to mgos_set_timer function

#1

This will I guess be a basic question, but I’m new to C and trying to write a timer to be used inside a for loop (with the functionality of delay(10)). I have got timers to work previously, but now I need to pass the timer an argument (a counter) so I can add items to an array inside the timer function. I have read up on pointers as this is new to me, but am still not getting how to write the code. See error and code below:

error: passing argument 3 of ‘mgos_set_timer’ from incompatible pointer type

static void timer_read(int *i) {
  counter = *i;
  buf_pH[counter]=mgos_adc_read_voltage(SensorPin_pH);
}

float calc_pH() {
  LOG(LL_INFO, ("Starting calculation"));
  // Calculating pH:
  for(int i=0;i<10;i++)       //Get 10 sample values from the sensor to smooth the value
  {
    mgos_set_timer(10, 1, timer_read, &i);
  }
  for(int i=0;i<9;i++)        //sort the analog from small to large
  {
    for(int j=i+1;j<10;j++)
    {
      if(buf_pH[i]>buf_pH[j])
      {
        float temp_pH=buf_pH[i];
        buf_pH[i]=buf_pH[j];
        buf_pH[j]=temp_pH;
      }
    }
  }
  avgValue_pH=0;
  for(int i=2;i<8;i++) {                      //sum 6 center values
    avgValue_pH+=buf_pH[i];
  }
  LOG(LL_INFO, ("summed items (6): %ld", avgValue_pH));
  float pH_float=(float)avgValue_pH*5.0/1024/6; //convert the analog into millivolt
  pH_float=3.5*pH_float+Offset_pH;               //convert the millivolt into pH value
  LOG(LL_INFO, ("After calculating: pH=%f", pH_float));
  return pH_float;
}

static void timer_print(void *user_data) {
  float pH_float = calc_pH();
  float EC_float = calc_EC();
  LOG(LL_INFO, ("After calculating: pH=%f, EC=%f", pH_float, EC_float));
  (void) user_data;
}
#2

The signature of mgos_set_timer specifies that the 3rd argument is void*. If you want to pass a pointer to an int, you should cast it to void*:

mgos_set_timer(10, 1, timer_read, (void*)&i);

Your code will no do what you want. You are starting 10 repeating timers which will read the ADC after 10 ms. If you call calc_pH again, other 10 timers will start, and so on, and so on…

If you need something similar with Arduino’s delay, there is mgos_msleep.

#3

Thanks, it seems I have misunderstood the usage of the timers.

I did try mgos_msleep earlier, but of the ten pH values that are measured in the for loops (recurring), all apart from the first value then become 142 mV. Am not understanding why this should be the case. If I remove the delay I get values for all measurements.

for(int i=0;i<10;i++)       //Get 10 sample value from the sensor to smooth the value
  {
    buf_pH[i]=mgos_adc_read_voltage(SensorPin_pH);
    LOG(LL_INFO, ("loop: %i, buf item: %f", i, buf_pH[i]));
    mgos_msleep(10);
  }
#4

I can’t say why adding the delay will mess up the A/D read, but using a delay is not a good design. Consider setting a timer callback that just takes the reading and places it into another data structure, such as a queue or list or even a simple array. You can of course limit it to n readings.

When you need a reading generate one from the stored data. Now you can use any smoothing algorithm you want. I often use EWMA.

Finally, if you need these readings to be timed accurately then a software timer at 10ms won’t work well. Look at the timer docs and consider a hardware timer.