Troubleshooting: Part of a program failing after ~30s

Hello there!

I've run into a strange issue with a very simple program I've written for an Arduino UNO. The program is (mainly) designed to shoot a 50ms digi-pulse out of a pin and light the on-board LED every time that it does. The frequency of the pulse is selected through a simple case-switch & pushbutton as defined by the user (1 Hz, 2 Hz, etc. . .). The program starts and runs just fine for about 25 seconds and then the digital output terminal and LED get locked out to HIGH indefinitely. I thought this may have been some strange debouncing issue, but I even tried putting a grounding resistor on the outputs (which I don't think is necessary) and it did nothing.

Here's the code:

#include <LiquidCrystal.h>
// Saved by Simulator for Arduino V0.97B (Free Version)

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
/* RS -> 12 | Enable -> 11 | D4 -> 5 | D5 -> 4 | D6 -> 3 | D7 -> 2 | R/W -> GND
POT ---- +5/GND Wiper to Vo (third LCD pin) */

const int pwrPin = 1;      //pin controlling on/off
const int meterPin = 7;    //pin controlling output to meter
const int togglePin = 10;  //pin controlling input
const int ledPin = 13;     //LED pin 
int toggleState = 0;       //button pushed
int prevtoggleState = 0;
int previousTime = 0;      //counter
const int firstFreq = 1;   //beginning frequency
int currFreq = firstFreq;  //Frequency in Hz of first value
const int resetValue = 5;  //Value to reset
int pwrOn = 0;             //Run or stop
int waitTime = 0;          //1000 / freq
int pwrOnFirst = 0;	   //Set first screen
int plusFivePin = 6;

void setup() {
  pinMode( pwrPin , INPUT );
  pinMode( meterPin , OUTPUT );
  pinMode( togglePin , INPUT );
  pinMode( ledPin , OUTPUT );
  pinMode( plusFivePin , OUTPUT );
  pinMode( 13 , OUTPUT );
  lcd.begin(16,2);
  lcd.setCursor(0,0);
  lcd.print(" Initialization ");
  lcd.setCursor(0,1);
  lcd.print("    Complete    ");
  lcd.noCursor();
}

void loop() {
  pwrOn = digitalRead(pwrPin);
  toggleState = digitalRead(togglePin);
  
  if (toggleState != prevtoggleState) {
    prevtoggleState = toggleState;
    if (toggleState == HIGH) {
      if (currFreq < resetValue) {
        currFreq++;
      }
      else {
        currFreq = firstFreq;
      }
      setWait:
      waitTime = 1000 / currFreq;
      lcd.clear();
      lcd.setCursor(0,0);
      lcd.print("  Frequency:  ");
      lcd.setCursor(3,1);
      lcd.print(currFreq);
      lcd.print("  Hz");
    }
  }
  
  if (pwrOn == HIGH) {
    
    if (pwrOnFirst == 0 || pwrOnFirst == 2) {
      pwrOnFirst = 1;
      lcd.clear();
      goto setWait;
    }
    if ((millis() - previousTime) >= waitTime) {
      previousTime = millis();
      digitalWrite(meterPin, HIGH);
      digitalWrite(ledPin, HIGH);
      delay(50);
      digitalWrite(meterPin, LOW);
      digitalWrite(ledPin, LOW);
    }
  }

  if (pwrOnFirst == 1 && pwrOn != HIGH) {
    pwrOnFirst = 2;
    lcd.clear();
    lcd.home();
    lcd.print(" Not Running ");
  }
}

I'm very new to Arduino and the language so I'm sure I'm just overlooking something. Any insight would be greatly appreciated! It can't hurt to learn.

Thanks!

I think the problem is using an 'int' (16 bits) for previousTime. The millis() function returns an 'unsigned long' (32 bits). Are 32.768 seconds the int will overflow and go negative.

Ah! Fantastic. That didn't even cross my mind. I'll try that and I'll also look into some way to reset the millis function to avoid overflow on the 32 bit as well. This program will need to run for probably up to 30 minutes in some situations.

Any suggestions on that? I'm about to walk out the door to go to work so I won't be able to look into anything for a while.

Thanks for the help!

  • Jonathan

Actually, I didn't think that through. Unless I did some mental math wrong a 32 bit long should give almost a month worth of milliseconds and an unsigned long would be about 50 days. That should suffice!

I'll try your suggestion as soon as I get a chance to get back to work on the project. Thanks again!

If you use:

unsigned long interval;   // Timer interval in milliseconds
unsigned long startTime = 0;  // Global (or static) 
.
.
.
startTime = millis();
.
.
.
if (millis() - startTime > interval)
     // This runs after the interval has expired

This code works across the roll-over.