Frequency counter Arduino

Hello there! Hope this find you well! This time, I'm asking for your guidance in a small project I'm developing. Where I'm counting events (the state change of a button) with an ESP8266, and after a certain time (10 seconds in my testing code), the system prints and restarts the counter.

My code works well overall, being able to count at a relatively high frequency according to my goal (i.e. around 5 state changes per second, or just 5 Hertz) but the problem is that, if I push the button too fast (faster than 5 Hertz), it obviates the time condition to restart the counter and keeps counting, so maybe, it doen't restart at 10 seconds all the times, but it could restart after 20, 40 or 60 seconds.

That's why I added some goto commands to try to ensure the time condition restart, and even when it does it more often, it still fails.

Here I add my code, any advice would be great. Anyway, thanks for your help!

// this constant won't change:
const int  buttonPin = 5;    // the pin that the pushbutton is attached to
const int ledPin = 15;       // the pin that the LED is attached to
const int ledPin2 = 13;      // LED reboot D7

// Variables will change:
int buttonPushCounter = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button

void setup() {
  // initialize the button pin as a input:
  pinMode(buttonPin, INPUT);
  // initialize the LED as an output:
  pinMode(ledPin, OUTPUT);
  pinMode(ledPin2, OUTPUT);
  // initialize serial communication:
  Serial.begin(115200);
}


void loop() {

  if ( ((millis()) % 10000 == 0) ) {
      label1:
      Serial.println();
      Serial.print("MASTER 1 min: ");
      Serial.println(buttonPushCounter);
      Serial.print("Reboot: ");
      buttonPushCounter = 0;
      Serial.println();
      digitalWrite(ledPin2, HIGH);
      delay(1500);
      digitalWrite(ledPin2, LOW);      
  } else {

          // read the pushbutton input pin:
          buttonState = digitalRead(buttonPin);
          
                  if ( ((millis()) % 10000 == 0) ) {
                    goto label1;
                  }
        
          // compare the buttonState to its previous state
          if (buttonState != lastButtonState) {

                  if ( ((millis()) % 10000 == 0) ) {
                    goto label1;
                  }
            
            // if the state has changed, increment the counter
            if (buttonState == HIGH) {
      
                  if ( ((millis()) % 10000 == 0) ) {
                    goto label1;
                  }              
              
              // if the current state is HIGH then the button went from off to on:
              buttonPushCounter++;
              digitalWrite(ledPin, LOW);
        
            } else {
              // if the current state is LOW then the button went from on to off:
              digitalWrite(ledPin, HIGH);
              
            }
            
            // Delay a little bit to avoid bouncing
                  if ( ((millis()) % 10000 == 0) ) {
                    goto label1;
                  }

            
            delay(50);
          }
          // save the current state as the last state, for next time through the loop
          lastButtonState = buttonState;

  }


  
}

AS soon as I say this line, I decided to not bother with your code. There is no reason to have a "goto" in any Arduino code. Your logic is faulty if you believe a goto is useful. Please try again.
Paul

That's why I asked for an advice, that's an empiric solution that barely worked better. I tried before with a while loop, but it wasn't much different.

Because the code works fine, but seems to ignore the time condition at the restart if the state change is too fast, counts just fine tho.

Try restructuring without using delays or gotos. For example (compiles, not tested...)

#define BTN_READ_INTERVAL       5ul         //read button every 5mS
#define BTN_PRESS_LEVEL         HIGH        //logic level corresponding to pressed
#define TIME_LED                1500ul      //time LED is on after reboot
#define SAMPLE_TIME             10000ul     //sample period

enum sampleStates_e
{
    ST_REBOOT=0,
    ST_SAMPLE
};

// this constant won't change:
const int  buttonPin = 5;    // the pin that the pushbutton is attached to
const int ledPin = 15;       // the pin that the LED is attached to
const int ledPin2 = 13;      // LED reboot D7

// Variables will change:
int buttonPushCounter = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button

void setup() 
{
    // initialize the button pin as a input:
    pinMode(buttonPin, INPUT);
    // initialize the LED as an output:
    pinMode(ledPin, OUTPUT);
    pinMode(ledPin2, OUTPUT);
    // initialize serial communication:
    Serial.begin(115200);

    buttonPushCounter = 0;
    lastButtonState = digitalRead( buttonPin );
}

void loop() 
{
    static bool
        bLED = false;
    static uint8_t
        stateSample = ST_REBOOT;
    static uint32_t
        timeSample = 0ul;
    uint32_t
        timeNow = millis();
        
    switch( stateSample )
    {
        case    ST_REBOOT:
            Serial.println();
            Serial.print("MASTER 10-sec: ");
            Serial.println(buttonPushCounter);
            Serial.print("Reboot: ");
            
            digitalWrite(ledPin2, HIGH);
            bLED = true;
            
            buttonPushCounter = 0;
            timeSample = timeNow;
            stateSample = ST_SAMPLE;
            
        break;

        case    ST_SAMPLE:
            if( bLED )
            {
                if( (timeNow - timeSample) >= TIME_LED )
                {
                    bLED = false;
                    digitalWrite(ledPin2, LOW);
                    
                }//if
                
            }//if
            
            if( (timeNow - timeSample) < SAMPLE_TIME )
            {
                if( ReadButton() )
                    buttonPushCounter++;
                
            }//if
            else
            {
                stateSample = ST_REBOOT;
                
            }//else
            
        break;
        
    }//switch

}//loop

bool ReadButton( void )
{
    static uint32_t
        timeButton = 0ul;
    uint32_t
        timeNow = millis();

    if( (timeNow - timeButton) >= BTN_READ_INTERVAL )
    {
        timeButton = timeNow;
        uint8_t bNow = digitalRead( buttonPin );
        if( bNow != lastButtonState )
        {
            lastButtonState = bNow;
            if( bNow == BTN_PRESS_LEVEL )
                return true;
                
        }//if
        
    }//if
            
}//ReadButton

1 Like

bool haveIbeenPressed = false;
int IhaveBeenPressedSkipTime = 5000;
int PressedTime = millis()

checkbutton if !haveIbeenPressed, if checkbutton do the checkbutton things, set haveIbeenPressed to true, and PressedTime = millis()

if( haveBeenPressed )
if( millis()- PressedTime >= IhaveBeenPressedSkipTime )
{
haveBeenPressed = !haveBeenPressed;
}

Using millis the time the button was pressed is recorded and the button pressed variable to true, which prevents the processing if button press code. The other if activates on button press, checks for 5000 ms to pass and resets the button press bool to reenable the button press functions.

Consider, if you just wait gcjr will write the code for you.

1 Like

consider

const byte pinBut = A1;

byte          butState = HIGH;
unsigned long msecLst;

int           count;

// -----------------------------------------------------------------------------
void
loop (void)
{
    unsigned long msec = millis ();

#define Timeout 5000
    if ( (msec - msecLst) > Timeout)  {
        msecLst = msec;
        Serial.println (count);
        count = 0;
    }
    
    if (butState != digitalRead (pinBut))  {
        butState = ! butState;

        if (LOW == butState)
            count++;
    }
}

// -----------------------------------------------------------------------------
void
setup (void)
{
    Serial.begin (9600);

    pinMode (pinBut, INPUT_PULLUP);
}
1 Like

Hello again! As yourelves said, some parts of your codes gave me compilation issues, nonetheless, since the logic was right, after testing them, they've helped me to realize how to set the time condition, to which I added some +/- 100 milliseconds interval in order to assure its fulfillment.

Anyway, I want to thank you all for your help ( Blackfin, Idahowalker, and gcjr), I'll leave my code (yet to be optimized and improved) as a solution to other people that may need it!

// this constant won't change:
const int  buttonPin = 5;    // the pin that the pushbutton is attached to
const int ledPin = 15;       // the pin that the LED is attached to
const int ledPin2 = 13;      // LED reboot D7

// Variables will change:
int buttonPushCounter = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button

//Variables time
int temp = 0;
int tempnow = millis();
int templast = 0;

//Depends
const int tempout = 10000;

void setup() {
  // initialize the button pin as a input:
  pinMode(buttonPin, INPUT);
  // initialize the LED as an output:
  pinMode(ledPin, OUTPUT);
  pinMode(ledPin2, OUTPUT);
  // initialize serial communication:
  Serial.begin(115200);
}


void loop() {
 tempnow = millis();
 temp = tempnow - templast;

 
  if ( ( temp >= (tempout - 100) ) and ( temp <= (tempout + 100) ) ) {
  //if ( ((millis()) % 10000 == 0) ) {
      Serial.println();
      Serial.print("MASTER 1 min: ");
      Serial.println(buttonPushCounter);
      Serial.print("Reboot: ");
      buttonPushCounter = 0;

      templast = millis();
      
      Serial.println();
      digitalWrite(ledPin2, HIGH);
      delay(1500);
      digitalWrite(ledPin2, LOW);      
  } else {

          // read the pushbutton input pin:
          buttonState = digitalRead(buttonPin);
          
          // compare the buttonState to its previous state
          if (buttonState != lastButtonState) {
            // if the state has changed, increment the counter
            if (buttonState == HIGH) {                           
              // if the current state is HIGH then the button went from off to on:
              buttonPushCounter++;
              //Serial.print("number of button pushes: ");
              //Serial.println(buttonPushCounter);
              //Serial.println("on");
              digitalWrite(ledPin, LOW);
            } else {
              // if the current state is LOW then the button went from on to off:
              //Serial.println("off");
              digitalWrite(ledPin, HIGH);              
            }
            delay(50);
          }
          // save the current state as the last state, for next time through the loop
          lastButtonState = buttonState;
  } //IF END
}   //LOOP END
1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.