user15863: I am looking for a more elegant way to write a function that performs timer-based tasks as in the case of the code below, which essentially collects 5 sample values from a microphone module over a given period of time and then computes their average. It is important that it does not use the delay() function because other tasks are supposed to run in the background which should not be affected by the delay. 
  int sensorPin = A0; 
  int ledPin = 13; //  pin for the LED
  int sensorValue = 0; // variable to store the value coming from the sensor
  unsigned long timer;
  int interv = 50;
  unsigned long sampleArray[] = {0, 0, 0, 0 , 0};
  unsigned long millisaver;


  void setup ()
  {
    pinMode (ledPin, OUTPUT);
    Serial.begin (9600);

  }

  void loop ()
  {

    if (millis() > 2000) {
      if (millis() < 2050) {
        millisaver = millis();
        timer = (int) millisaver;
        Serial.println(timer);
      }
      if ( millis() > timer && millis() < timer + interv ) {
        sampleArray[0] = sensorValue = analogRead (sensorPin);
      }
      else if ( millis() > timer+interv && millis() < timer + interv*2 ) {
        sampleArray[1] = sensorValue = analogRead (sensorPin);
      }
      else if ( millis() > timer+interv*2 && millis() < timer + interv*3 ) {
        sampleArray[2] = sensorValue = analogRead (sensorPin);

      }
      else if ( millis() > timer+interv*3 && millis() < timer + interv*4 ) {
        sampleArray[3] = sensorValue = analogRead (sensorPin);

      }
      else if ( millis() > timer+interv*4 && millis() < timer + interv*5 ) {
        sampleArray[4] = sensorValue = analogRead (sensorPin);
      }
      else if ( millis() > timer+interv*5) {
        unsigned long averageVal = (sampleArray[0] + sampleArray[1] + sampleArray[2] +sampleArray[3] + sampleArray[4])/5 ;
        Serial.println(averageVal);
        millisaver = millis();
        timer = (int) millisaver;
      }
    }
  }


user4143: You need to make a function which is pretty much completely self contained. Within the function should be a counter so it knows which sample it is on, and a timestamp to know when it should next run. The function should also inform the caller when it has a full sample set to process.
I haven't tested this (don't know if it even compiles) but something like this might work:
bool getSample(uint8_t pin, unsigned long *samples) {
    static uint32_t ts = millis();
    static uint8_t sampleNumber = 0;

    if (millis() - ts >= 50) {
        ts += 50;
        samples[sampleNumber++] = analogRead(pin);
        if (sampleNumber == 5) {
            sampleNumber = 0;
            return true; // We have 5 samples
        }
    }
    return false; // We don't have 5 samples yet.
}

// ... later ...

if (getSample(sensorPin, sampleArray)) {
    // Process Samples
}


user7508: You didn't say what you want to do with those samples. If you want to
estimate the level of sound intensity, your whole approach is completely
wrong. First, your sampling rate (20 Hz) is way too low: you should
sample at least at twice the frequency of interest, typically at
8 kHz or more. Then you have to subtract the DC offset added by the
microphone module, then square the result in order to get an
instantaneous intensity, then low-pass filter to get a usable intensity
reading. As Majenko said, if you average (or low-pass filter) the
samples before squaring, you would detect zero sound.
I've written a sound meter program for an Arduino Uno that does exactly
that, and it's available as a GitHub Gist:
sound-meter.ino.
It uses the auto-trigger mode as explained by KIIV, but with free
running mode instead of a timer. This gives 9.6 kHz sampling rate.

user23841: For excact timing there is feature called ADC Auto Trigger mode. For example millis() are usually counted by timer 0 overflow (on AVR based Arduinos) every 1024us (I suppose it's because of PWM - otherwise it could be set exactly to 1ms). So if you don't mind that little offset, you can configure 
ADC with Timer 0 Overflow and use every 20 measure only.
But don't forget that analogRead on another pin changes ADC channel and you will get something else if you don't check it.
As an auto trigger source can be used one of these:

Free Running Mode
Analog Comparator
External Interrupt 0
Timer/Counter 0 Compare Match A
Timer/Counter 0 Overflow
Timer/Counter 1 Compare Match B
Timer/Counter 1 Overflow
Timer/Counter 1 Capture Event

For ATMega328 it can be something like this:
void setup() {
    Serial.begin(57600);

    // ADC setup is done by arduino framework, but it's possible to change it slightly (for ATMega328) :
    ADCSRB  = _BV(ADTS2); // ADTS2..0 = 100, Timer 0 overflow as trigger source
    ADCSRA |= _BV(ADATE); // enable auto trigger mode    
    ADCSRA |= _BV(ADIF); // reset conversion interrupt flag (by writing log 1)

    analogRead(A0); // dummy read to set correct channel and to start auto trigger mode
}

int8_t sample_count = 0;
int8_t sample_index = 0;
uint16_t  samples[] = {0, 0, 0, 0, 0};
uint16_t sample_sum = 0;

void loop() {
    if (ADCSRA & _BV(ADIF)) {
        ADCSRA |= _BV(ADIF); // reset ADIF flag by writing logic 1 into it (mentioned in datasheet)
        if (++sample_count == 20) {
            sample_count = 0; // reset sample_count, as we wan't every 20th

            sample_sum -= samples[sample_index];
            samples[sample_index] = ADC; // read value
            sample_sum += samples[sample_index];

            if (++sample_index == 5) { // reset index and count and send average
                sample_index = 0;
                Serial.println(sample_sum);
            }
        }
    }
}


15863: <p>I am looking for a more elegant way to write a function that performs timer-based tasks as in the case of the code below, which essentially collects 5 sample values from a microphone module over a given period of time and then computes their average. It is important that it does not use the <code>delay()</code> function because other tasks are supposed to run in the background which should not be affected by the delay. </p>

<pre><code>  int sensorPin = A0; 
  int ledPin = 13; //  pin for the LED
  int sensorValue = 0; // variable to store the value coming from the sensor
  unsigned long timer;
  int interv = 50;
  unsigned long sampleArray[] = {0, 0, 0, 0 , 0};
  unsigned long millisaver;


  void setup ()
  {
    pinMode (ledPin, OUTPUT);
    Serial.begin (9600);

  }

  void loop ()
  {

    if (millis() &gt; 2000) {
      if (millis() &lt; 2050) {
        millisaver = millis();
        timer = (int) millisaver;
        Serial.println(timer);
      }
      if ( millis() &gt; timer &amp;&amp; millis() &lt; timer + interv ) {
        sampleArray[0] = sensorValue = analogRead (sensorPin);
      }
      else if ( millis() &gt; timer+interv &amp;&amp; millis() &lt; timer + interv*2 ) {
        sampleArray[1] = sensorValue = analogRead (sensorPin);
      }
      else if ( millis() &gt; timer+interv*2 &amp;&amp; millis() &lt; timer + interv*3 ) {
        sampleArray[2] = sensorValue = analogRead (sensorPin);

      }
      else if ( millis() &gt; timer+interv*3 &amp;&amp; millis() &lt; timer + interv*4 ) {
        sampleArray[3] = sensorValue = analogRead (sensorPin);

      }
      else if ( millis() &gt; timer+interv*4 &amp;&amp; millis() &lt; timer + interv*5 ) {
        sampleArray[4] = sensorValue = analogRead (sensorPin);
      }
      else if ( millis() &gt; timer+interv*5) {
        unsigned long averageVal = (sampleArray[0] + sampleArray[1] + sampleArray[2] +sampleArray[3] + sampleArray[4])/5 ;
        Serial.println(averageVal);
        millisaver = millis();
        timer = (int) millisaver;
      }
    }
  }
</code></pre>
 4143: <p>You need to make a function which is pretty much completely self contained. Within the function should be a counter so it knows which sample it is on, and a timestamp to know when it should next run. The function should also inform the caller when it has a full sample set to process.</p>

<p>I haven't tested this (don't know if it even compiles) but something like this might work:</p>

<pre><code>bool getSample(uint8_t pin, unsigned long *samples) {
    static uint32_t ts = millis();
    static uint8_t sampleNumber = 0;

    if (millis() - ts &gt;= 50) {
        ts += 50;
        samples[sampleNumber++] = analogRead(pin);
        if (sampleNumber == 5) {
            sampleNumber = 0;
            return true; // We have 5 samples
        }
    }
    return false; // We don't have 5 samples yet.
}

// ... later ...

if (getSample(sensorPin, sampleArray)) {
    // Process Samples
}
</code></pre>
 7508: <p>You didn't say what you want to do with those samples. If you want to
estimate the level of sound intensity, your whole approach is completely
wrong. First, your sampling rate (20&nbsp;Hz) is way too low: you should
sample at least at twice the frequency of interest, typically at
8&nbsp;kHz or more. Then you have to subtract the DC offset added by the
microphone module, then square the result in order to get an
instantaneous intensity, then low-pass filter to get a usable intensity
reading. As Majenko said, if you average (or low-pass filter) the
samples <em>before</em> squaring, you would detect zero sound.</p>

<p>I've written a sound meter program for an Arduino Uno that does exactly
that, and it's available as a GitHub Gist:
<a href="https://gist.github.com/edgar-bonet/e693799f58a545ca89a2" rel="nofollow">sound-meter.ino</a>.
It uses the auto-trigger mode as explained by KIIV, but with free
running mode instead of a timer. This gives 9.6&nbsp;kHz sampling rate.</p>
 23841: <p>For excact timing there is feature called ADC Auto Trigger mode. For example millis() are usually counted by timer 0 overflow (on AVR based Arduinos) every 1024us (I suppose it's because of PWM - otherwise it could be set exactly to 1ms). So if you don't mind that little offset, you can configure 
ADC with Timer 0 Overflow and use every 20 measure only.
But don't forget that analogRead on another pin changes ADC channel and you will get something else if you don't check it.</p>

<p>As an auto trigger source can be used one of these:</p>

<ul>
<li>Free Running Mode</li>
<li>Analog Comparator</li>
<li>External Interrupt 0</li>
<li>Timer/Counter 0 Compare Match A</li>
<li>Timer/Counter 0 Overflow</li>
<li>Timer/Counter 1 Compare Match B</li>
<li>Timer/Counter 1 Overflow</li>
<li>Timer/Counter 1 Capture Event</li>
</ul>

<p>For ATMega328 it can be something like this:</p>

<pre><code>void setup() {
    Serial.begin(57600);

    // ADC setup is done by arduino framework, but it's possible to change it slightly (for ATMega328) :
    ADCSRB  = _BV(ADTS2); // ADTS2..0 = 100, Timer 0 overflow as trigger source
    ADCSRA |= _BV(ADATE); // enable auto trigger mode    
    ADCSRA |= _BV(ADIF); // reset conversion interrupt flag (by writing log 1)

    analogRead(A0); // dummy read to set correct channel and to start auto trigger mode
}

int8_t sample_count = 0;
int8_t sample_index = 0;
uint16_t  samples[] = {0, 0, 0, 0, 0};
uint16_t sample_sum = 0;

void loop() {
    if (ADCSRA &amp; _BV(ADIF)) {
        ADCSRA |= _BV(ADIF); // reset ADIF flag by writing logic 1 into it (mentioned in datasheet)
        if (++sample_count == 20) {
            sample_count = 0; // reset sample_count, as we wan't every 20th

            sample_sum -= samples[sample_index];
            samples[sample_index] = ADC; // read value
            sample_sum += samples[sample_index];

            if (++sample_index == 5) { // reset index and count and send average
                sample_index = 0;
                Serial.println(sample_sum);
            }
        }
    }
}
</code></pre>
