I need to accurately count negative and positive spikes

For my first project things are going well and I’m nearly there. My issue right now is to accurately count voltage drops on A2 and positive spikes on A3. A3s spikes derived from the motor being told to work. A2s drops are from the motor actually doing the work of opening and closing a valve. I want to count the number of each so I can compare and validate. Example: If the motor was told to work 80x and the actual voltage drops amount to 78x, I know there is a problem somewhere. I have it counting but I cant get it to only increment per spike. It seems like it continually counts the longer the voltage is up. I’ve already tried delays but I don’t want to hold the whole sketch up. I need something to work in the background. I’m sure millis is the answer but for the life of me, I cant get it to do what I need. Any help would be appreciated.

Here is my full sketch. void dropEventCounter() and void pulseEventCounter() are where I believe my tweaks need to be. Sorry about the organization of the sketch. Like I said, this is my first project.

// number of analog samples to take per reading, per channel
#define NUM_SAMPLES 10
// voltage divider calibration values
#define DIV_1    11.0935
#define DIV_2    11.0020
#define DIV_3    11.0716
#define DIV_4    2.0030
#define DIV_5    2.0000
#define DIV_6    2.0153
// ADC reference voltage / calibration value
#define V_REF    5.028

float baseline = 0;              // Initial sample for Bat Bus line
int sum[6] = {0};                // sums of samples taken
unsigned char sample_count = 0;  // current sample number
float voltage[6] = {0.00};       // calculated voltages
char l_cnt = 0;                  // used in 'for' loops
int vDrop = 0;                   // Voltage drop output
int vSpike = 0;
float dutyCycle = 0;             // Positive representation of voltage drop from motor duty cycle
float dropCountSum = 0;
float pulseCountSum = 0;
int IntervalNumber = 0;
long previousMillis = 0;
unsigned long dropInterval = 100;
unsigned long previousDropMillis = 0;
unsigned long spikeInterval = 1000;
unsigned long previousSpikeMillis = 0;

void setup()
{
    Serial.begin(115200);
    delay(5000);
    baseline = (analogRead(A2)* V_REF / 1024 * DIV_3);
}

void loop()
{
    // take a number of analog samples and add them up
    while (sample_count < NUM_SAMPLES) 
    {
        // sample each channel A0 to A5
        for (l_cnt = 0; l_cnt < 6; l_cnt++) 
        {
            sum[l_cnt] += analogRead(A0 + l_cnt);
        }
        sample_count++;
        delay(10);
    }
    // calculate the voltage for each channel
    for (l_cnt = 0; l_cnt < 6; l_cnt++) 
    {
        voltage[l_cnt] = ((float)sum[l_cnt] / (float)NUM_SAMPLES * V_REF) / 1024.0;
    }
    
    // each voltage is multiplied by the resistor network
    // division factor to calculate the actual voltage
    voltage[0] = voltage[0] * DIV_1;
    voltage[1] = voltage[1] * DIV_2;
    voltage[2] = voltage[2] * DIV_3;
    voltage[3] = voltage[3] * DIV_4;
    voltage[4] = voltage[4] * DIV_5;
    voltage[5] = voltage[5] * DIV_6;
    
    {
    voltageDrop();
    dropEventCounter();
    pulseEventCounter();
    }
   
    // send voltages to Processing application via serial port / USB
    // voltage 1 - Pin A0)
    Serial.print(voltage[0], 2);
    Serial.print(",");
    // voltage 2 - Pin A1)
    Serial.print(voltage[1], 2);
    Serial.print(",");
    // voltage 3 - Pin A2)
    Serial.print(voltage[2], 2);
    Serial.print(",");
    // voltage 4 - Pin A3)
    Serial.print(voltage[3], 2);
    Serial.print(",");
    // voltage 5 - Pin A4)
    Serial.print(voltage[4], 2);
    Serial.print(",");
    // voltage 6 - Pin A5)
    Serial.print(voltage[5], 2);
    Serial.print(",");
    // Pulse Event Count
    Serial.print(pulseCountSum, 1);
    Serial.print(",");
    // Drop Event Count
    Serial.print((dropCountSum) / 2, 1);
    Serial.println("");
    delay(10);
    // reset count and sums
    sample_count = 0;
    for (l_cnt = 0; l_cnt < 6; l_cnt++) 
    {
        sum[l_cnt] = 0;
    }
}


void voltageDrop()
{
  dutyCycle = (baseline - voltage[2]);
}


void dropEventCounter()
{
  unsigned long currentMillis = millis();
  //previousMillis = currentMillis;
  
  if((unsigned long)(currentMillis - previousMillis) >= dropInterval)
  {
    if (dutyCycle >= 0.5)
    {
      vDrop = 0;
      dropCountSum ++;
      while(dutyCycle < 0.5);
      vDrop = 1;
    }
  }  
}


void pulseEventCounter()
{
  unsigned long currentMillis = millis();
  //previousMillis = currentMillis;
  
  if((unsigned long)(currentMillis - previousMillis) >= spikeInterval)
  {
    if (voltage[3] >= 2.5)
    {
      vSpike = 0;
      pulseCountSum ++;
      while(voltage[3] < 2.5);
      vSpike = 1;
    }
  }
}

Then state change example shows how to detect a positive and negative transition so you can count only the positive or negative edges. The example is in the IDE examples under digital.

Sounds like a job of the interrupts!

Mark

    if (dutyCycle >= 0.5)
    {
      vDrop = 0;
      dropCountSum ++;
      while(dutyCycle < 0.5);

If dutyCycle is greater than 0.5, enter an infinite loop while dutyCycle is less than 0.5. It’s a good thing that can never happen.

groundfungus, I went into the state change example like you recommended and was able to tweak the sketch to my needs. Works great! This is what I came up with:

void dropEventCounter()
{
  voltageDropState = dutyCycle;
  // compare the voltage state to its previous state
  if (voltageDropState != lastVoltageDropState)
  {
    // if the state has changed, increment the counter
    if (voltageDropState >= 0.3)
    {
      // if the current state is >= 0.3 then the state went from high to low:
      voltageDropCounter++;
    }
  }
  lastVoltageDropState = voltageDropState;  
}

void pulseEventCounter()
{
  voltagePulseState = voltage[3];
  // compare the voltage state to its previous state
  if (voltagePulseState != lastVoltagePulseState)
  {
    // if the state has changed, increment the counter
    if (voltagePulseState >= 4.5)
    {
      // if the current state is >= 4.5 then the state went from high to low:
      voltagePulseCounter++;
    }
  }
  lastVoltagePulseState = voltagePulseState;  
}

Sadly, I thought getting this working would finish the project. Today, I've been testing this on a different tool and the tool actually acts a little different. It actually produces voltage drops as soon as it turns on for the first five seconds or so which skews my count. I need to now add in a delay of sorts (probably millis or interrupt) that will not let dropEventCounter() and pulseEventCounter() run until about 15 seconds after the tool turns on. ALMOST THERE!

Loop your code in setup() for 15-20 seconds. ;)

Since the tool puts out a steady 5.5 volts on A4 when the tool turns on, I was hoping there was a way I could do something like an if statement saying something like: if A4 is > 5.0 start counting millis. When millis >= 15000 run dropEventCounter() and pulseEventCounter(). I've tried it, but its not working, so I must be missing something.

This is what I wrote up, but dropEventCounter() and pulseEventCounter() are not counting now:

if (voltage[4] > 2.5)
    {
      unsigned long currentMillis = millis();
      (targetMillis = currentMillis + interval);
      if (currentMillis >= targetMillis)
      {
        dropEventCounter();
        pulseEventCounter();
      }
    }

Gixxerman1980: Since the tool puts out a steady 5.5 volts on A4 when the tool turns on, I was hoping there was a way I could do something like an if statement saying something like: if A4 is > 5.0 start counting millis. When millis >= 15000 run dropEventCounter() and pulseEventCounter(). I've tried it, but its not working, so I must be missing something.

5.5V sounds a bit high. For one thing, you won't be able to detect the difference between 5V and 5.5V as AREF will be 5V (won't it?).

Sorry, I'm going through a divider so it is half that coming into the board but corrected back in the sketch.

There is an analog comparator what can be configured to trigger on positive or negative-going changes in an analog signal.

http://www.gammon.com.au/forum/?id=11916