Help with time delay in if_else statement

I've been using a Wii nunchuck as an input device and I've run into a bit of a snag. I have it set up so that when I press a button I have two output pins set HIGH. What I want to do is have a two second delay between transistorPin2 and transistorPin1 output HIGH, so that when I press the button transistorPin2 outputs HIGH, then a two second delay, then transistorPin1 outputs HIGH. Both pins have to output LOW when the button is released. I've tried all kinds of methods but no luck. I'm sure it's something simple I'm missing.....

Here's the bit of code:

if( nunchuck_zbutton() ) { digitalWrite(transistorPin2, HIGH); digitalWrite(transistorPin1, HIGH); } else { digitalWrite(transistorPin2, LOW); digitalWrite(transistorPin1, LOW); }

Any help would be greatly appreciated- thanks!

I'm not sure I understand the question, so if I'm being dense and stating the obvious, just bonk me on the head.

If you don't need to be doing anything else during those two seconds or waiting, and if you don't want the pins to go low as soon as the button is released, the simplest thing to do is:

   if( nunchuck_zbutton() ) {            
     digitalWrite(transistorPin2, HIGH); 
     delay(2000);   
     digitalWrite(transistorPin1, HIGH);  
 }
 else {
     digitalWrite(transistorPin2, LOW);
     digitalWrite(transistorPin1, LOW);
 }

I suspect it's not that simple, tho. You probably want the pins to go low as soon the button is released, even if the two seconds have not elapsed yet and only the first pin is high. Correct?

If that is the case, you need to detect the button press, set the first pin high, and record the current time with millis(). You can then go about your business and periodically check to see if the button is released (set both pins to low) or if the current time exceeds the recorded time plus 2,000 milliseconds before the button is released (set second pin high). Note that the second condition requires you to keep track of the fact that the button is pressed and has not yet been released, so you will need a true/false variable to keep track of that if you are not in a dedicated loop doing nothing but monitoring the button.

This is conceptually similar to debouncing, which checks for stability in an input by waiting for a certain period with no change, so you might be able to adapt the debounce example's code for this.

Thanks for the response. You're right- it's not that simple as I tried the exact code you posted. What it does in that instance is set the first pin high, wait two seconds, set the second pin high and then it stays high- it never goes low. The problem is that the pins have to go low as soon as the button is released.

I was figuring I would have to do something like debouncing or using a millis() function, I just didn't know exactly what or how to implement it.

If you want the pins to go high for two seconds OR until the button is released, try some code like this:

bool button_down = false;
unsigned long start;

void loop()
{
  if (nunchuck_zbutton())
  {
    if (!button_down)
    {
      button_down = true;
      start = millis();
      digitalWrite(transistorPin2, HIGH);
      digitalWrite(transistorPin1, HIGH);  
    }
    else if (millis() - start > 2000)
    {
      digitalWrite(transistorPin2, LOW);
      digitalWrite(transistorPin1, LOW);  
    }
  }
  else
  {
    button_down = false;
    digitalWrite(transistorPin2, LOW);
    digitalWrite(transistorPin1, LOW);  
  }
}

Does that seem like it would work?

Regards,

Mikal

not really eloquent, but should do what you are wanting :slight_smile:
there should be roughly max of delay(20) with this, and track state as well.

   if( nunchuck_zbutton() ) {
     digitalWrite(transistorPin2, HIGH);
     if (count < 100) {  //loop a delay 20 X times to reach time while watching nunchuck button state
         delay(20);
         count++;
         if (! nunchuck_zbutton()) {count = 0; break;} //poll nunchuck state
         } 
     if (count > 99) {digitalWrite(transistorPin1, HIGH);}   
 }
 else {
     count = 0;  //clear count for 2nd button here if it went high before
     digitalWrite(transistorPin2, LOW);
     digitalWrite(transistorPin1, LOW);
 }

Thanks guys! Basically what I'm trying to do is this: Imagine you have two momentary push buttons- push and release the first button, wait two seconds, then push and release the second button.

b94cast, I get an error when I compile the posted code..... hmmmm.

I'll work on it some more tonight.

I think I misunderstood what you are trying to accomplish. For logic flow purposes, is this what you are trying to do?

press button ----- turn on pin2 ------ wait 2seconds ------ turn on pin1 if button is released ------ deactivate pins if both active ------ cancel and clear pin timer if pin1 is not yet active

Honus--

I guess I still don't understand exactly what you want, but for small tasks, I have found that the general architecture I outlined above usually works best. Store the state in some variables, like "button_down" and "start" above. Then loop repeatedly, checking the current time every time through. If you know (a) the previous state, (b) the current state, (c) the previous time, and (d) the current time, you know every thing you need to generate the outputs you're looking for. Good luck!

Mikal

"I think I misunderstood what you are trying to accomplish. For logic flow purposes, is this what you are trying to do?

press button ----- turn on pin2 ------ wait 2seconds ------ turn on pin1 if button is released ------ deactivate pins if both active ------ cancel and clear pin timer if pin1 is not yet active"

That's exactly what I want. I'm slowly learning this stuff so all your guys help is greatly apprerciated! :)

What about this:

bool button_down = false;
unsigned long start;

void loop()
{
  if (nunchuck_zbutton())
  {
    if (!button_down) // If button was just pressed do this
    {
      button_down = true;
      start = millis();
      digitalWrite(transistorPin2, HIGH);
    }
    else if (millis() - start > 2000) // if timer has elapsed do this
    {
      digitalWrite(transistorPin1, HIGH);  
    }
  }
  else // if button is up do this
  {
    button_down = false;
    digitalWrite(transistorPin2, LOW);
    digitalWrite(transistorPin1, LOW);  
  }
}

Mikal

Thanks! I'll try that after I get home from work tonight.

Jerome

Nope- didn’t work. Maybe I inserted it wrong. Here’s the code I’m writing:

#include <Wire.h>

int controlPin1 = 11;           // Control pin for arm servo using c button 
int transistorPin1 = 12;        // Control pin for LED using z button
int transistorPin2 = 10;        // Control pin for sound using z button
int servoPin1 = 7;              // Control pin for servo motor 1 using accelerometer x axis
int servoPin2 = 6;              // Control pin for servo motor 2 using accelerometer y axis
int servoPin3 = 5;              // Control pin for servo motor 3 using joystick x axis
int servoPin4 = 4;              // Control pin for servo motor 4 using joystick y axis

int pulseWidth1 = 0;    // Amount to pulse the servo 1
int pulseWidth2 = 0;    // Amount to pulse the servo 2
int pulseWidth3 = 0;    // Amount to pulse the servo 3
int pulseWidth4 = 0;    // Amount to pulse the servo 4

int refreshTime = 20;   // the time in millisecs needed in between pulses
long lastPulse1;
long lastPulse2;
long lastPulse3;
long lastPulse4;
int minPulse = 700;     // minimum pulse width
int loop_cnt=0;

bool button_down = false;
unsigned long start;

void setup()
{
  Serial.begin(19200);
  pinMode(controlPin1, OUTPUT);    // Set control pin 1 as output
  pinMode(transistorPin1, OUTPUT); // Set transistor pin 1 as output
  pinMode(transistorPin2, OUTPUT); // Set transistor pin 2 as output 
  pinMode(servoPin1, OUTPUT);      // Set servo pin 1 as an output pin
  pinMode(servoPin2, OUTPUT);      // Set servo pin 2 as an output pin
  pinMode(servoPin3, OUTPUT);      // Set servo pin 3 as an output pin
  pinMode(servoPin4, OUTPUT);      // Set servo pin 4 as an output pin
  pulseWidth1 = minPulse;          // Set the motor position to the minimum
  pulseWidth2 = minPulse;          // Set the motor position to the minimum
  pulseWidth3 = minPulse;          // Set the motor position to the minimum
  pulseWidth4 = minPulse;          // Set the motor position to the minimum

  nunchuck_init(); // send the initilization handshake
  Serial.print("NunchuckServo ready\n");
}

void loop()
{
  checkNunchuck1();
  updateServo1();   // update servo 1 position
  checkNunchuck2();
  updateServo2();   // update servo 2 position
  checkNunchuck3();
  updateServo3();   // update servo 3 position
  checkNunchuck4();
  updateServo4();   // update servo 4 position
  
 
   if( nunchuck_cbutton() ) {          // turn on control pin 1 if c button is pressed
      digitalWrite(controlPin1, HIGH);
   } 
  else {    
      digitalWrite(controlPin1, LOW);
  }
 
 if (nunchuck_zbutton())
  {
    if (!button_down)  // If button was just pressed do this
    {
      button_down = true;
      start = millis();
      digitalWrite(transistorPin2, HIGH);
    }
    else if (millis() - start > 2000)  // if timer has elapsed do this
    {
      digitalWrite(transistorPin1, HIGH);  
    }
  }
  else  // if button is up do this
  {
    button_down = false;
    digitalWrite(transistorPin2, LOW);
    digitalWrite(transistorPin1, LOW);  
  }
 
 delay(1);  // this is here to give a known time per loop
}


void checkNunchuck1()
{
  if( loop_cnt > 100 ) {  // loop()s is every 1msec, this is every 100msec
    
    nunchuck_get_data();
    nunchuck_print_data();

    float tilt = nunchuck_accelx();      // x-axis, in this case ranges from ~70 - ~185
    tilt = (tilt - 70) * 1.5;            // convert to angle in degrees, roughly  
    pulseWidth1 = (tilt * 9) + minPulse; // convert angle to microseconds
    
    loop_cnt = 0;  // reset for 
  }
  loop_cnt++; 
  
}

// called every loop().
// uses global variables servoPin, pulsewidth, lastPulse, & refreshTime
void updateServo1()
{
  // pulse the servo again if rhe refresh time (20 ms) have passed:
  if (millis() - lastPulse1 >= refreshTime) {
    digitalWrite(servoPin1, HIGH);   // Turn the motor on
    delayMicroseconds(pulseWidth1);  // Length of the pulse sets the motor position
    digitalWrite(servoPin1, LOW);    // Turn the motor off
    lastPulse1 = millis();           // save the time of the last pulse
  }
}

void checkNunchuck2()
{
  if( loop_cnt > 100 ) {  // loop()s is every 1msec, this is every 100msec
    
    nunchuck_get_data();
    nunchuck_print_data();

    float tilt = nunchuck_accely();      // y-axis, in this case ranges from ~70 - ~185
    tilt = (tilt - 70) * 1.5;            // convert to angle in degrees, roughly  
    pulseWidth2 = (tilt * 9) + minPulse; // convert angle to microseconds
    
    loop_cnt = 0;  // reset for 
  }
  loop_cnt++; 
  
}

// called every loop().
// uses global variables servoPin, pulsewidth, lastPulse, & refreshTime
void updateServo2()
{
  // pulse the servo again if rhe refresh time (20 ms) have passed:
  if (millis() - lastPulse2 >= refreshTime) {
    digitalWrite(servoPin2, HIGH);   // Turn the motor on
    delayMicroseconds(pulseWidth2);  // Length of the pulse sets the motor position
    digitalWrite(servoPin2, LOW);    // Turn the motor off
    lastPulse2 = millis();           // save the time of the last pulse
  }
}

void checkNunchuck3()
{
  if( loop_cnt > 100 ) {  // loop()s is every 1msec, this is every 100msec
    
    nunchuck_get_data();
    nunchuck_print_data();

    float pitch = nunchuck_joyx();        // x-axis, in this case ranges from ~70 - ~185
    pitch = (pitch - 70) * 1.5;           // convert to angle in degrees, roughly  
    pulseWidth3 = (pitch * 9) + minPulse; // convert angle to microseconds
    
    loop_cnt = 0;  // reset for 
  }
  loop_cnt++; 
  
}

// called every loop().
// uses global variables servoPin, pulsewidth, lastPulse, & refreshTime
void updateServo3()
{
  // pulse the servo again if rhe refresh time (20 ms) have passed:
  if (millis() - lastPulse3 >= refreshTime) {
    digitalWrite(servoPin3, HIGH);   // Turn the motor on
    delayMicroseconds(pulseWidth3);  // Length of the pulse sets the motor position
    digitalWrite(servoPin3, LOW);    // Turn the motor off
    lastPulse3 = millis();           // save the time of the last pulse
  }
}

void checkNunchuck4()
{
  if( loop_cnt > 100 ) {  // loop()s is every 1msec, this is every 100msec
    
    nunchuck_get_data();
    nunchuck_print_data();

    float yaw = nunchuck_joyy();        // y-axis, in this case ranges from ~70 - ~185
    yaw = (yaw - 70) * 1.5;             // convert to angle in degrees, roughly  
    pulseWidth4 = (yaw * 9) + minPulse; // convert angle to microseconds
    
    loop_cnt = 0;  // reset for 
  }
  loop_cnt++; 
  
}

// called every loop().
// uses global variables servoPin, pulsewidth, lastPulse, & refreshTime
void updateServo4()
{
  // pulse the servo again if rhe refresh time (20 ms) have passed:
  if (millis() - lastPulse4 >= refreshTime) {
    digitalWrite(servoPin4, HIGH);   // Turn the motor on
    delayMicroseconds(pulseWidth4);  // Length of the pulse sets the motor position
    digitalWrite(servoPin4, LOW);    // Turn the motor off
    lastPulse4 = millis();           // save the time of the last pulse
  }
}

And here's the second part:

//
// Nunchuck functions
//

static uint8_t nunchuck_buf[6];   // array to store nunchuck data,

// initialize the I2C system, join the I2C bus,
// and tell the nunchuck we're talking to it
void nunchuck_init()
{ 
  Wire.begin();                      // join i2c bus as master
  Wire.beginTransmission(0x52);      // transmit to device 0x52
  Wire.send(0x40);            // sends memory address
  Wire.send(0x00);            // sends sent a zero.  
  Wire.endTransmission();      // stop transmitting
}

// Send a request for data to the nunchuck
// was "send_zero()"
void nunchuck_send_request()
{
  Wire.beginTransmission(0x52);      // transmit to device 0x52
  Wire.send(0x00);            // sends one byte
  Wire.endTransmission();      // stop transmitting
}

// Receive data back from the nunchuck, 
// returns 1 on successful read. returns 0 on failure
int nunchuck_get_data()
{
  int cnt=0;
  Wire.requestFrom (0x52, 6);      // request data from nunchuck
  while (Wire.available ()) {
    // receive byte as an integer
    nunchuck_buf[cnt] = nunchuk_decode_byte(Wire.receive());
    cnt++;
  }
  nunchuck_send_request();  // send request for next data payload
  // If we recieved the 6 bytes, then go print them
  if (cnt >= 5) {
    return 1;   // success
  }
  return 0; //failure
}

// Print the input data we have recieved
// accel data is 10 bits long
// so we read 8 bits, then we have to add
// on the last 2 bits.  That is why I
// multiply them by 2 * 2
void nunchuck_print_data()
{ 
  static int i=0;
  int joy_x_axis = nunchuck_buf[0];
  int joy_y_axis = nunchuck_buf[1];
  int accel_x_axis = nunchuck_buf[2]; // * 2 * 2; 
  int accel_y_axis = nunchuck_buf[3]; // * 2 * 2;
  int accel_z_axis = nunchuck_buf[4]; // * 2 * 2;

  int z_button = 0;
  int c_button = 0;

  // byte nunchuck_buf[5] contains bits for z and c buttons
  // it also contains the least significant bits for the accelerometer data
  // so we have to check each bit of byte outbuf[5]
  if ((nunchuck_buf[5] >> 0) & 1) 
    z_button = 1;
  if ((nunchuck_buf[5] >> 1) & 1)
    c_button = 1;

  if ((nunchuck_buf[5] >> 2) & 1) 
    accel_x_axis += 2;
  if ((nunchuck_buf[5] >> 3) & 1)
    accel_x_axis += 1;

  if ((nunchuck_buf[5] >> 4) & 1)
    accel_y_axis += 2;
  if ((nunchuck_buf[5] >> 5) & 1)
    accel_y_axis += 1;

  if ((nunchuck_buf[5] >> 6) & 1)
    accel_z_axis += 2;
  if ((nunchuck_buf[5] >> 7) & 1)
    accel_z_axis += 1;

  Serial.print(i,DEC);
  Serial.print("\t");

  Serial.print("joy:");
  Serial.print(joy_x_axis,DEC);
  Serial.print(",");
  Serial.print(joy_y_axis, DEC);
  Serial.print("  \t");

  Serial.print("acc:");
  Serial.print(accel_x_axis, DEC);
  Serial.print(",");
  Serial.print(accel_y_axis, DEC);
  Serial.print(",");
  Serial.print(accel_z_axis, DEC);
  Serial.print("\t");

  Serial.print("but:");
  Serial.print(z_button, DEC);
  Serial.print(",");
  Serial.print(c_button, DEC);

  Serial.print("\r\n");  // newline
  i++;
}

// Encode data to format that most wiimote drivers except
// only needed if you use one of the regular wiimote drivers
char nunchuk_decode_byte (char x)
{
  x = (x ^ 0x17) + 0x17;
  return x;
}

// returns zbutton state: 1=pressed, 0=notpressed
int nunchuck_zbutton()
{
   return ((nunchuck_buf[5] >> 0) & 1) ? 0 : 1;  // voodoo
}

// returns zbutton state: 1=pressed, 0=notpressed
int nunchuck_cbutton()
{
   return ((nunchuck_buf[5] >> 1) & 1) ? 0 : 1;  // voodoo
}

// returns value of x-axis joystick
int nunchuck_joyx()
{
  return nunchuck_buf[0]; 
}

// returns value of y-axis joystick
int nunchuck_joyy()
{
  return nunchuck_buf[1];
}

// returns value of x-axis accelerometer
int nunchuck_accelx()
{
  return nunchuck_buf[2];   // FIXME: this leaves out 2-bits of the data
}

// returns value of y-axis accelerometer
int nunchuck_accely()
{
  return nunchuck_buf[3];   // FIXME: this leaves out 2-bits of the data
}

// returns value of z-axis accelerometer
int nunchuck_accelz()
{
  return nunchuck_buf[4];   // FIXME: this leaves out 2-bits of the data
}

Thanks again for all your help- I know I'll get it figured out one way or another! :)

I hate to say, Jerome, but I very slightly modified your code so that it read from an ordinary pushbutton (instead of nunchuck_zbutton), hooked up 2 LEDs to pins 12 and 10, and it seems to work fine. The first LED immediately pops on and the second one comes on 2 seconds later. If I lift my finger from the button, both LEDs go out. Perhaps a more descriptive account of what "doesn't work" would help.

I'm a little worried about the comment that pin 10 is the "control pin for sound". You're not trying to drive an ordinary piezo speaker this way, are you?

M

The control pin for sound just sends the signal to a separate sound board- it's only acting as a switch via a transistor.

I'll have to hook up my multimeter later today and check the output on the pins and do some debugging. I'm suspecting it has something to do with the nunchuck reading code.

Here's a little video of what I'm building: http://www.youtube.com/watch?v=tYScDwP3v8w

The complete code still has a way to go as I still need to add a smoothing function.

Jerome

Hey, wow, that's cool! Good luck! I'm sure you'll figure it out.

Mikal

WOW!

Awesome project :o can't wait to see the finished product!

Thanks guys- glad you like it! It's been a real learning curve making this and it still has a ways to go.....

Mikal,

I got the code working- thanks sooo much! I turns out I made a couple of small errors. Now I'm just adjusting the timing of the LED to work with my sounds. I wanted to add a laser tracking/targeting sound that was a couple of seconds long- it would happen before the cannon firing sound so I needed to delay the lighting of the LED by an equal amount of time.

Jerome

Way cool. I glad to have been some help on this awesome project.

I'll have a complete tutorial posted on Instructables when I'm finished. My member page is here: http://www.instructables.com/member/Honus/

I'll be building the animatronic head as well as the gauntlet blade mechanism.

Thanks again!

Jerome