Program lock up

Dear all,

I would like to replace the delay function with sleep, and wake up after 0.5sec

With some effort, I modified the code from this blog into a 0.5sec timer.

Now I wanted to include the code into my sensor.

#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/wdt.h>

volatile int f_wdt=1;
/////////////////////////////////////////////////////////////////////////////////////////////////////////
#define echoPin 7 // Echo Pin
#define trigPin 8 // Trigger Pin
#define LEDPin 13 // Onboard LED
#define motorPin 3

//////////////////////////////////////////////////////////////////////////////////////////////////////
ISR(WDT_vect)
{
  if(f_wdt == 0)
  {
    f_wdt=1;
  }
  else
  {
    Serial.println("WDT Overrun!!!");
  }
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void enterSleep(void)
{
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);   /* EDIT: could also use SLEEP_MODE_PWR_DOWN for lowest power consumption. */
  sleep_enable();
  
  /* Now enter sleep mode. */
  sleep_mode();
  
  /* The program will continue from here after the WDT timeout*/
  sleep_disable(); /* First thing to do is disable sleep. */
  
  /* Re-enable the peripherals. */
  power_all_enable();
}




/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int motorState = 0;             // motorState used to set the LED
unsigned long previousMillis;        // will store last time LED was updated
unsigned long startTime;
long interval = 1000;
boolean lastTrip;
boolean lastTrip2;
//
int maximumRange = 200; // Maximum range needed
int minimumRange = 10; // Minimum range needed
int triggerDistance = 10;
int crashDistance = 5;
//long duration, distance; // Duration used to calculate distance
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup() 
{
  pinMode(motorPin, OUTPUT);
  Serial.begin (9600);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(LEDPin, OUTPUT); // Use LED indicator (if required)
  
  ////////////////////////////////////////////////////////////////////////////////////////////////////////
   /*** Setup the WDT ***/
  
  /* Clear the reset flag. */
  MCUSR &= ~(1<<WDRF);
  
  /* In order to change WDE or the prescaler, we need to
   * set WDCE (This will allow updates for 4 clock cycles).
   */
  WDTCSR |= (1<<WDCE) | (1<<WDE);

  /* set new watchdog timeout prescaler value */
  WDTCSR = 1<<WDP0 | 1<<WDP2; /* 0.5 seconds */
  
  /* Enable the WD interrupt (note no reset). */
  WDTCSR |= _BV(WDIE);
  //////////////////////////////////////////////////////////////////////////////////////////////////////////////
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
long getDistance()
{
  digitalWrite(trigPin, LOW); 
  delayMicroseconds(2); 
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10); 
  digitalWrite(trigPin, LOW);
  long duration = pulseIn(echoPin, HIGH);
  long dist = duration/58.2;
  return dist;
}
//////////////////////////////////////////////////////////////////////////////////
void runMotor()
{
  if( millis() - startTime < 3000) // Three Second Interval
  {
    analogWrite(motorPin, 25);
    //or digitalWrite(motorPin, HIGH);
 
  }
  else
  {
    analogWrite(motorPin, 0);
    //or digitalWrite(motorPin, LOW);
    motorState = 0;
  }
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
void runMotor2()
{
  if( millis() - startTime < 3000) // Three Second Interval
  {
    analogWrite(motorPin, 200);
    //or digitalWrite(motorPin, HIGH);
 
  }
  else
  {
    analogWrite(motorPin, 0);
    //or digitalWrite(motorPin, LOW);
    motorState = 0;
  }
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop() 
{
  long distance = getDistance();
  if (distance > minimumRange)
  {
    Serial.println(distance);
    digitalWrite(LEDPin, LOW); 
  }
  if (distance < minimumRange)
  {
    Serial.println(distance);
    digitalWrite(LEDPin, HIGH); 
  }
  ////////////////////////////////////////////////////////////////////////////////////////////////////////
  boolean tripped = (distance <= triggerDistance ? 1 : 0); // flag if triggered
  if (tripped)
  {
    if (tripped != lastTrip)
    {
      startTime = millis();
      motorState = 1;
    }
  }
  lastTrip = tripped;
  if (motorState == 1)
  {
    runMotor();
  }
  
  ////////////////////////////////////////////////////////////////////////////////////////////////////////
  boolean tripped2 = (distance <= crashDistance ? 1 : 0); // flag if triggered
  if (tripped2)
  {
    if (tripped2 != lastTrip2)
    {
      startTime = millis();
      motorState = 2;
    }
  }
  lastTrip = tripped;
  if (motorState == 2)
  {
    runMotor2();
  }
  
  //////////////////////////////////////////////////////////////////////////////////////////////////////////
if (distance > triggerDistance)
{analogWrite(motorPin, 0);
motorState = 0;
    /* Don't forget to clear the flag. */
    f_wdt = 0;
    
    /* Re-enter sleep mode. */
  delay (100);
   enterSleep();
}

}

While it does function as delay 500ms when distance > triggerDistance,

when my runmotor () triggers, it locks up and the runmotor script and the motor won't stop
In addition, sometimes it runs a wrong script.
.
Interestingly, if I trigger the ultrasonic sensor and quickly removes the object in front of it,
the program WILL NOT lock up and functions normally.

Any ideas?

You get rid of the delay/dleep by using blink with out delay and an FSM (look in the playground). You only need to make the arduino sleep if you want to save power, you don't do it for any other reason. Never use delay() in a program!.

Mark

holmes4:
Never use delay() in a program!

That's a bit harsh. I'm sure there are cases where its use is justified or at least acceptable, although I understand "where you're coming from" as the cliché goes.

How about this snippet.....

// below is the write function, untouched from playground, except ***
void i2c_eeprom_write_byte( int deviceaddress, unsigned int eeaddress, byte data ) {
  int rdata = data;
  Wire.beginTransmission(deviceaddress);
  Wire.write((int)(eeaddress >> 8)); // MSB
  Wire.write((int)(eeaddress & 0xFF)); // LSB
  Wire.write(rdata);
  Wire.endTransmission();
  delay(5);  //added at cattledog's suggestion *** <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
}

..... where without the delay(5) on the end it didn't work.

So do I, without the delay function I cannot even see the results from serial.

Anyway, I am guessing the sleep function messing up the motor state, boolean flags , etc, is there a way to fix it?

My intention is to put the device to sleep for 500ms if distance > triggerdistance,
and resume ultrasonic sensing after 500ms passed

There is little value in sleeping an Arduino board, as the peripherals will use quite a few milliamps even with the processor asleep. Sleeping only has value on a bare board where you can control all the peripherals.

The sleep function should not be affecting anything in the RAM. It's highly unlikely that that's the problem.

You seem to be using the watchdog timer in a HORRIBLE way. Why are you activating in in setup? Only activate it when you are about to sleep, then disable it immediately when you wake up.

I had a problem with my project involving the watchdog timer. Something was causing my system to reset randomly. When that happens while the WDT is active, the WDT stays active with a default 15 ms prescaler value. If your system does not deal with this, it will be caught in a reset loop, as mine was.

To test this theory, at the very beginning of your setup function, flash an LED for a very breif period of time (25 ms or so) like this:

pinMode( 13, OUTPUT );
digitalWrite(13, HIGH);
delay(25);
digitalWrite(13, LOW);

Upload the sketch to your board, then induce the fault. If the LED stays on, your system is caught in a reset loop.