Delay Using millis() - Please Help/Explain

So I'm trying to make a vibration motor pulse and an LED blink. I want them to pulse four times with a 60ms delay between pulses.

So far, I have this:

      analogWrite(motorPin, 255);      //Strobe the motor four times
      digitalWrite(ledPin, HIGH);      //Strobe the LED four times
      delay(30);                       //With a short delay in between pulses
      analogWrite(motorPin, 0);
      digitalWrite(ledPin, LOW);
      delay(30);
      analogWrite(motorPin, 255);
      digitalWrite(ledPin, HIGH);
      delay(30);
      analogWrite(motorPin, 0);
      digitalWrite(ledPin, LOW);
      delay(30);
      analogWrite(motorPin, 255);
      digitalWrite(ledPin, HIGH);
      delay(30);
      analogWrite(motorPin, 0);
      digitalWrite(ledPin, LOW);
      delay(30);
      analogWrite(motorPin, 255);
      digitalWrite(ledPin, HIGH);
      delay(30);
      analogWrite(motorPin, 0);
      digitalWrite(ledPin, LOW);
      delay(30);

It works, but because the future of this project involves heavy use of resources, I would like to avoid using the delay(ms) function anywhere in this code, especially since I can't let a simple physical notification of an event pause everything, even if it's only for 240ms.

I looked around, and decided using millis() might be my best bet.

The only code example I could find was http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay, but it doesn't suit my needs or help me very much. It's a looping state-sensitive thing.

Still, I tried, and I came up with this:

const int motorPin = 12;        //vibration motor is attached to motorPin
const int ledPin = 13;          //status LED is attached to ledPin
int ledState = LOW;
int motorState = 0;
long previousVibeMillis = 0;
long intervalVibe = 30;

void setup()
{
  pinMode(ledPin, OUTPUT);
}

void loop()
{
  if (millis() - previousVibeMillis > intervalVibe)
  {
  previousVibeMillis = millis();
  if (ledState == LOW)
  {
    ledState = HIGH;
  }
  else
  {
    ledState = LOW;
  }
  if (motorState == 0)
  {
    motorState = 255;
  }
  else
  {
    motorState = 0;
  }
  analogWrite(motorPin, motorState);
  digitalWrite(ledPin, ledState);
  }
}

That works alright, if I just want to strobe the motor and the LED on and off endlessly, but it won't let me control the finite number of times I want it to pulse (4 times per notification).

I tried using this in my main program, modified as such:

      if (millis() - previousMillis > 30)
      {
        previousMillis = millis();
        analogWrite(motorPin, 255);
        digitalWrite(ledPin, HIGH);
      }
      if (millis() - previousMillis > 30)
      {
        previousMillis = millis();
        analogWrite(motorPin, 0);
        digitalWrite(ledPin, LOW);
      }

It does not have the desired effect.

Does anybody have any ideas that will help me get a hold on this thing? All I want is (basically) for a button to be pressed, and as a result, an LED blinks four times, while simultaneously a vibration motor pulses four times. The idea is for this whole thing to later be in-synch with a sound effect (four chirps, hence four blinks and four vibration pulses)...but that's VERY far down the road, and absolutely not a priority.

The button-press code is already taken care of. I'm using the one-pin no-component touch sensor found here: http://www.arduino.cc/playground/Code/CapacitiveSensor, but slightly modified for my purposes (one pin, global access to the variables).

When somebody touches the button, I want the motor to pulse and light to blink, and I only want the cycle to occur once, until the button is released and pressed again. For some reason this is VERY hard for me to figure out. I've been wracking my brain for days, and making very little progress.

So basically, I need to know how to effectively mimic the delay() function, without actually causing a delay in code execution. Any ideas?

Also, found a workaround for the no-links-in-first-post-thing. Lucky me.

The button press is going to generate an event. The event is going to cause a change in a state machine. When that change occurs, you want to execute the code in the middle block in a for loop, 4 times. Then, you want to change state, back to the button-not-pressed state.

To simulate that, without a button:

int buttonPressed = 1; // the button was pressed

void loop()
{
   if(buttonPressed == 1)
   {
      for(int i=0; i<4; i++)
      {
         // Do the stuff with the motor and LED
      }
      buttonPressed = 0;
   }
}

Wow. It really never occurred to me to use a for loop.

I've got to go, but I'll try it later and get back to you.

Thank you very much.

I couldn’t wait. :stuck_out_tongue:

I tried it, it worked. Thank you so much. Sometimes, being too close to the project can really get in the way of innovation. Your solution works perfectly (except in my implementation, I needed the for loop to go until 8), since each loop either turns it on or off.

if (capval > 1)   //If the cap sensor is pressed
    {
      for (int i = 0; i < 8 ; i++)       //Do the following 8 times:
      {
        previousVibeMillis = millis();   //Store the current value of millis() in previousVibeMillis
        if (ledState == LOW)             //Check the current state of ledPin
        {
          ledState = HIGH;               //Change the current state of ledPin
        }
        else
        {
          ledState = LOW;
        }
        if (motorState == 0)             //Check the current state of motorPin
        {
          motorState = 255;              //Change the current state of motorPin
        }
        else
        {
          motorState = 0;
        }
        analogWrite(motorPin, motorState);    //Activate or deactivate motorPin
        digitalWrite(ledPin, ledState);       //Activate or deactivate ledPin
        Serial.print("motorState: ");
        Serial.println(motorState);
        Serial.print("ledState: ");
        Serial.println(ledState);
      }

You could, in each pass, turn the motor and led on, wait, turn them off, and wait.

Anyway, I'm glad you're now making process.

I'm not sure how I could effect a delay like that without getting into recursive if statements...and my brain is not yet ready for that. :P

It's odd. I set up my code to work based on your for loop, and tested it, and it worked. Then I left the house and came back, and it doesn't work. I must have accidentally changed something.

I'm going to have to spend a while debugging the heck out of my code now. :P

I’m not sure how I could effect a delay like that without getting into recursive if statements…and my brain is not yet ready for that.

No recursion at all…

for(int pass=0; pass<4; pass++)
{
// Turn motor on
// Turn light on
// Twiddle thumbs
// Turn motor off
// Turn light off
// Twiddle thumbs some more
}

The thumb twiddling stuff is common, so you could create a function:

void twiddleThumbs(long howLong)
{
    long now = millis();
    long end = now + howLong;
    while(millis() < end)
    {
       // Do nary a thing
    }
}

So, if I leave my Serial communication stuff active (put in for debugging purposes to view variable values in realtime), everything works fine. If I comment any of it out so it won't be streaming Serial crap all the time and hogging resources, it stops working. I'm confused, but whatever. It works, kind of.

Post your code. It's probably something relatively simple.

When I comment out all the Serial communication lines, it stops working, but when they’re active, and sending data it works. WTF?

//TNGBadge for Arduino 0017
//Created by Adrian Thomas-Prestemon
//
//The purpose of this sketch is to duplicate as many features
//of the communication badge seen in Star Trek, The Next Generation.
//
//Connect one wire with a foil square attached to the end to pin 8.
//Attach vibration motor to motorPin.
//Attach status LED to ledPin.

char capval;                    //Variable to sotre value of capacitive sensor pin
char pinval = {1<<PINB0};       //Capacitive sensor is attached to pinval
const int motorPin = 12;        //Vibration motor is attached to motorPin
const int ledPin = 13;          //Status LED is attached to ledPin
int ledState = LOW;             //Default state of ledPin is LOW
int motorState = 0;             //Default state of motorPin is 0
int waitTime = 0;               //custom variable used to create a delay and debounce touch input
long previousVibeMillis = 0;    //Default state of preiousVibeMillis is 0
long intervalVibe = 30;         //Interval between vibrations is 30ms

void setup()
{
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);      // connect to the serial port
}

void loop ()                           //Checking the touch sensor for activity
{                                      //
//  char capval;                         //
//  char pinval = {1<<PINB0};
//  delay(100);
  for(char i = 0; i < 1; i++)
  {
    capval = getcap(pinval);
    Serial.print("digital ");
    Serial.print(i+8, DEC);
    Serial.print(": ");
    Serial.println(capval, DEC);
  }
    if (capval < 2)                    //If capacitive sensor is not touched
    {
      waitTime ++;                        //Add to waitTime
    }
    if (waitTime > 10000)                    //If waitTime has reached higher than 10
    {
      waitTime = 1;                       //Reduce waitTime back to 1 to avoid overflow
    }
    if (capval > 1 && waitTime >= 100)   //If the cap sensor is pressed and waitTime is 1 or greater
    {
      for (int x = 0; x < 8 ; x++)       //Do the following 8 times:
      {
        previousVibeMillis = millis();   //Store the current value of millis() in previousVibeMillis
        if (ledState == LOW)             //Check the current state of ledPin
        {
          ledState = HIGH;               //Change the current state of ledPin
        }
        else
        {
          ledState = LOW;
        }
        if (motorState == 0)             //Check the current state of motorPin
        {
          motorState = 255;              //Change the current state of motorPin
        }
        else
        {
          motorState = 0;
        }
        analogWrite(motorPin, motorState);    //Activate or deactivate motorPin
        digitalWrite(ledPin, ledState);       //Activate or deactivate ledPin
        waitTime = 0;                         //Add to debouncing variable
        Serial.print("motorState: ");
        Serial.println(motorState);
        Serial.print("ledState: ");
        Serial.println(ledState);
      }
    }
    else if (capval > 1 && waitTime < 1)    //If the button is pressed before waittime reaches 1
    {
      waitTime = 0;      //Reset waitTime
    }                                          //waitTime effectively debounces the cap sensor to prevent looping when held down
    else                                       //If nothing is happening
    {
      analogWrite(motorPin, 0);                //Keep motorPin off
      digitalWrite(ledPin, LOW);               //and keep ledPin off, too
    }
//    Serial.print("waitTime: ");                //Output waitTime for debugging purposes
//    Serial.println(waitTime);
//  }
}

// returns capacity on one input pin
// pin must be the bitmask for the pin e.g. (1<<PB0)
char getcap(char pin)
{
  char i = 0;
  DDRB &= ~pin;          // input
  PORTB |= pin;          // pullup on
  for(i = 0; i < 16; i++)
    if( (PINB & pin) ) break;
  PORTB &= ~pin;         // low level
  DDRB |= pin;           // discharge
  return i;
}

I don't see anything obviously wrong. I did wonder why you have a for loop that executes the body only once.

You are storing, but never using, previousVibeMillis.

There is no delay after turning the motor pin and led pin on. I'd bet that what is happening is that the light and motor are on while for the time that Serial.print takes to execute. Removing that delay makes it seem that the motor and led aren't working.

So, I put in the part I apparently forgot, and it works, but only somewhat.

When I touch the capacitive button, I get a single (very) short pulse on the motor and led, unless I’m touching something (like my laptop) at the same time, which produces a higher capval (range is 1 to 16, normal touch rarely goes higher than 7, touch while touching an electrical ground goes up to 16)…in which case it just loops continuously.

I keep trying not to be an information hoarder, but it seems like every time I delete even the most “useless” scrap of information (the in-between version of my experimental delay removal, which had all my attempts at fixing the problem, for example), it turns out that I need it…yet when I keep everything, I almost never need any of it. Damned if I do, damned if I don’t.

Anyway, code:

//TNGBadge for Arduino 0017
//Created by Adrian Thomas-Prestemon
//
//The purpose of this sketch is to duplicate as many features
//of the communication badge seen in Star Trek, The Next Generation.
//
//Connect one wire with a foil square attached to the end to pin 8.
//Attach vibration motor to motorPin.
//Attach status LED to ledPin.

char capval;                    //Variable to sotre value of capacitive sensor pin
char pinval = {1<<PINB0};       //Capacitive sensor is attached to pinval
const int motorPin = 12;        //Vibration motor is attached to motorPin
const int ledPin = 13;          //Status LED is attached to ledPin
int ledState = LOW;             //Default state of ledPin is LOW
int motorState = 0;             //Default state of motorPin is 0
int waitTime = 0;               //custom variable used to create a delay and debounce touch input
long previousVibeMillis = 0;    //Default state of preiousVibeMillis is 0
long intervalVibe = 30;         //Interval between vibrations is 30ms

void setup()
{
  pinMode(ledPin, OUTPUT);
//  Serial.begin(9600);      // connect to the serial port
}

void loop ()                           //Checking the touch sensor for activity
{                                      //
//  char capval;                         //
//  char pinval = {1<<PINB0};
//  delay(100);
  for(char i = 0; i < 1; i++)
  {
    capval = getcap(pinval);
//    Serial.print("digital ");
//    Serial.print(i+8, DEC);
//    Serial.print(": ");
//    Serial.println(capval, DEC);
  }
    if (capval < 2)                    //If capacitive sensor is not touched
    {
      waitTime ++;                        //Add to waitTime
    }
    if (waitTime > 10000)                    //If waitTime has reached higher than 10
    {
      waitTime = 1;                       //Reduce waitTime back to 1 to avoid overflow
    }
    if (capval > 1 && waitTime >= 100)   //If the cap sensor is pressed and waitTime is 1 or greater
    {
      for (int x = 0; x < 8 ; x++)       //Do the following 8 times:
      {
        if (millis() - previousVibeMillis > intervalVibe)
        {
          previousVibeMillis = millis();   //Store the current value of millis() in previousVibeMillis
          if (ledState == LOW)             //Check the current state of ledPin
          {
            ledState = HIGH;               //Change the current state of ledPin
          }
          else
          {
            ledState = LOW;
          }
          if (motorState == 0)             //Check the current state of motorPin
          {
            motorState = 255;              //Change the current state of motorPin
          }
          else
          {
            motorState = 0;
          }
          analogWrite(motorPin, motorState);    //Activate or deactivate motorPin
          digitalWrite(ledPin, ledState);       //Activate or deactivate ledPin
          waitTime = 0;                         //Add to debouncing variable
//          Serial.print("motorState: ");
//          Serial.println(motorState);
//          Serial.print("ledState: ");
//          Serial.println(ledState);
        }
      }
    }
    else if (capval > 1 && waitTime < 1)    //If the button is pressed before waittime reaches 1
    {
      waitTime = 0;      //Reset waitTime
    }                                          //waitTime effectively debounces the cap sensor to prevent looping when held down
    else                                       //If nothing is happening
    {
      analogWrite(motorPin, 0);                //Keep motorPin off
      digitalWrite(ledPin, LOW);               //and keep ledPin off, too
    }
//    Serial.print("waitTime: ");                //Output waitTime for debugging purposes
//    Serial.println(waitTime);
//  }
}

// returns capacity on one input pin
// pin must be the bitmask for the pin e.g. (1<<PB0)
char getcap(char pin)
{
  char i = 0;
  DDRB &= ~pin;          // input
  PORTB |= pin;          // pullup on
  for(i = 0; i < 16; i++)
    if( (PINB & pin) ) break;
  PORTB &= ~pin;         // low level
  DDRB |= pin;           // discharge
  return i;
}

It seems like it’s just ignoring the for loop and instead just running the motor.

I think the only reason it runs continuously at all is because I’m holding the vibration motor while I touch the capacitive panel, and the motor is receiving the discharge pulses from the capacitive sensor and/or my laptop case (I touch the button with my left hand, while my right hand is either holding the motor or touching my laptop). So basically, it pulses once, weakly, when I touch the button, and I’m not holding the motor or touching my laptop.

It keeps seeming like we’re almost there, and then it gets farther away. We’ll catch the elusive solution eventually. :stuck_out_tongue:

So I removed some stuff I deemed no longer necessary and/or possibly extraneous, so I could focus on the heart of the problem.

//TNGBadge for Arduino 0017
//Created by Adrian Thomas-Prestemon
//
//The purpose of this sketch is to duplicate as many features as possible
//of the communication badge seen in Star Trek: The Next Generation.
//
//Connect one wire with a foil square attached to the end to pin 8.
//Attach vibration motor to motorPin.
//Attach status LED to ledPin.

char capval;                    //Variable to sotre value of capacitive sensor pin
char pinval = {1<<PINB0};       //Capacitive sensor is attached to pinval
const int motorPin = 12;        //Vibration motor is attached to motorPin
const int ledPin = 13;          //Status LED is attached to ledPin
int ledState = LOW;             //Default state of ledPin is LOW
int motorState = 0;             //Default state of motorPin is 0
int waitTime = 0;               //custom variable used to create a delay and debounce touch input
long previousVibeMillis = 0;    //Default state of preiousVibeMillis is 0
long intervalVibe = 30;         //Interval between vibrations is 30ms

void setup()
{
  pinMode(ledPin, OUTPUT);
//  Serial.begin(9600);      // connect to the serial port
}

void loop ()                           //Checking the touch sensor for activity
{                                      //
  capval = getcap(pinval);
  if (capval > 1)
  {
    for (int x = 0; x < 8; x++)       //Do the following 8 times:
    {
      if (millis() - previousVibeMillis > intervalVibe)
      {
        previousVibeMillis = millis();   //Store the current value of millis() in previousVibeMillis
        if (ledState == LOW)             //Check the current state of ledPin
        {
          ledState = HIGH;               //Change the current state of ledPin
        }
        else
        {
          ledState = LOW;
        }
        if (motorState == 0)             //Check the current state of motorPin
        {
          motorState = 255;              //Change the current state of motorPin
        }
        else
        {
          motorState = 0;
        }
        analogWrite(motorPin, motorState);    //Activate or deactivate motorPin
        digitalWrite(ledPin, ledState);       //Activate or deactivate ledPin
      }
    }
  }
  else                                       //If nothing is happening
  {
    analogWrite(motorPin, 0);                //Keep motorPin off
    digitalWrite(ledPin, LOW);               //and keep ledPin off, too
  }
}

// returns capacitance on one input pin
// pin must be the bitmask for the pin e.g. (1<<PB0)
char getcap(char pin)
{
  char i = 0;
  DDRB &= ~pin;          // input
  PORTB |= pin;          // pullup on
  for(i = 0; i < 16; i++)
    if( (PINB & pin) ) break;
  PORTB &= ~pin;         // low level
  DDRB |= pin;           // discharge
  return i;
}

Now it tirelessly pulses the motor and led with 30ms delays as long as I hold the button down. Now to get it to only do it 8 times until the button is released and pressed again…

So I rewrote the code from scratch. Then I checked it against my original code. My logic is the same, and the code is almost identical.

char capval;
char pinval = {1<<PINB0};
const int motorPin = 12;
const int ledPin = 13;
int ledState = LOW;
int motorState = 0;
long previousVibeMillis = 0;
long intervalVibe = 30;

void setup()
{
  pinMode (ledPin, OUTPUT);
}

void loop()
{
  capval = getcap(pinval);
  if (capval > 1)
  {
    for (int x = 0; x < 8; x ++)
    {
      if (millis() - previousVibeMillis > intervalVibe)
      {
        previousVibeMillis = millis();
        if (ledState == LOW)
        {
          ledState = HIGH;
        }
        else
        {
          ledState = LOW;
        }
        if (motorState == 0)
        {
          motorState = 255;
        }
        else
        {
          motorState = 0;
        }
        digitalWrite (ledPin, ledState);
        analogWrite (motorPin, motorState);
      }
    }
  }
  else
  {
    digitalWrite (ledPin, LOW);
    analogWrite (motorPin, 0);
  }
}

char getcap(char pin)
{
  char i = 0;
  DDRB &= ~pin;          // input
  PORTB |= pin;          // pullup on
  for(i = 0; i < 16; i++)
    if( (PINB & pin) ) break;
  PORTB &= ~pin;         // low level
  DDRB |= pin;           // discharge
  return i;
}

When I touch the cap sensor, the led and motor pulse endlessly on-off-on-off, etc., except it’s not steady. It’s kind of erratic, almost spastic. Also, it’s still looping continuously. I thought the for loop was supposed to make it only do it 8 times?

I experimented with the same code structure and for loop, but putting the delay version back into that framework, and I think I see what’s happening. So long as the button is touched, it repeats indefinitely, but once the button is released, it continues the cycle on last time (8 for loops).

//TNGBadge for Arduino 0017
//Created by Adrian Thomas-Prestemon
//
//The purpose of this sketch is to duplicate as many features as possible
//of the communication badge seen in Star Trek: The Next Generation.
//
//Connect one wire with a foil square attached to the end to pin 8.
//Attach vibration motor to motorPin.
//Attach status LED to ledPin.

char capval;                    //Variable to sotre value of capacitive sensor pin
char pinval = {1<<PINB0};       //Capacitive sensor is attached to pinval
const int motorPin = 12;        //Vibration motor is attached to motorPin
const int ledPin = 13;          //Status LED is attached to ledPin
int ledState = LOW;             //Default state of ledPin is LOW
int motorState = 0;             //Default state of motorPin is 0
long previousVibeMillis = 0;    //Default state of preiousVibeMillis is 0
long intervalVibe = 30;         //Interval between vibrations is 30ms

void setup()
{
  pinMode(ledPin, OUTPUT);
//  Serial.begin(9600);      // connect to the serial port
}

void loop ()                           //Checking the touch sensor for activity
{                                      //
  capval = getcap(pinval);
  if (capval > 1)
  {
    for (int x = 0; x < 8; x++)       //Do the following 8 times:
    {
      analogWrite (motorPin, 255);
      digitalWrite (ledPin, HIGH);
      delay(30);
      analogWrite (motorPin, 0);
      digitalWrite (ledPin, LOW);
      delay(30);
    }
  }
  else                                       //If nothing is happening
  {
    analogWrite(motorPin, 0);                //Keep motorPin off
    digitalWrite(ledPin, LOW);               //and keep ledPin off, too
  }
}

// returns capacitance on one input pin
// pin must be the bitmask for the pin e.g. (1<<PB0)
char getcap(char pin)
{
  char i = 0;
  DDRB &= ~pin;          // input
  PORTB |= pin;          // pullup on
  for(i = 0; i < 16; i++)
    if( (PINB & pin) ) break;
  PORTB &= ~pin;         // low level
  DDRB |= pin;           // discharge
  return i;
}

So now I need to figure out what to change to make it only loop 8 times while the button is touched, and not start looping again until the button is released and touched again.

THINK THINK THINK
:-/

Think about what you want to have happen.

State 1: The button has not been pressed State 2: The button has been pressed but not released State 3: The button has been pressed and released

Then, think about what you want to do while in each state, and what you want to have happen when you transition between each state.

You want the motor and led to operate when transitioning from state 1 to state 2, but at no other time.

Note, also, the similarities between state 1 and state 3.

If these are not enough hints, more can be provided.

So using your button-states concept, I came up with the following:

//TNGBadge for Arduino 0017
//Created by Adrian Thomas-Prestemon
//
//The purpose of this sketch is to duplicate as many features as possible
//of the communication badge seen in Star Trek: The Next Generation.
//
//Connect one wire with a foil square attached to the end to pin 8.
//Attach vibration motor to motorPin.
//Attach status LED to ledPin.

char capval;                    //Variable to sotre value of capacitive sensor pin
char pinval = {1<<PINB0};       //Capacitive sensor is attached to pinval
const int motorPin = 12;        //Vibration motor is attached to motorPin
const int ledPin = 13;          //Status LED is attached to ledPin
int ledState = LOW;             //Default state of ledPin is LOW
int motorState = 0;             //Default state of motorPin is 0
long previousVibeMillis = 0;    //Default state of preiousVibeMillis is 0
long intervalVibe = 30;         //Interval between vibrations is 30ms
int buttonState = 0;

void setup()
{
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);      // connect to the serial port
}

void loop ()                           //Checking the touch sensor for activity
{                                      //
  capval = getcap(pinval);
  if (capval > 1)       //If button was not pressed, but is now pressed
  {
    Serial.println ("button pressed");
    buttonState = 1;
  }
  if (capval < 2 && buttonState == 1)
  {
    Serial.println ("button just released");
    for (int x = 0; x < 4; x ++)
    {
      analogWrite (motorPin, 255);
      digitalWrite (ledPin, HIGH);
      delay(30);
      analogWrite (motorPin, 0);
      digitalWrite (ledPin, LOW);
      delay(30);
    }
  }
  if (capval < 2)
  {
//    Serial.println ("button not pressed");
    buttonState = 0;
  }
}

// returns capacitance on one input pin
// pin must be the bitmask for the pin e.g. (1<<PB0)
char getcap(char pin)
{
  char i = 0;
  DDRB &= ~pin;          // input
  PORTB |= pin;          // pullup on
  for(i = 0; i < 16; i++)
    if( (PINB & pin) ) break;
  PORTB &= ~pin;         // low level
  DDRB |= pin;           // discharge
  return i;
}

It has the desired effect, but acting upon button-release, instead. I could make do with this behaviour, but I’d like to try and get the action to take place on button-press. One problem, however, is the inclusion of the delay function, again. I included the delay function because of the following problem:

When I try and include the millis() method of creating a delay, it doesn’t work right:

//TNGBadge for Arduino 0017
//Created by Adrian Thomas-Prestemon
//
//The purpose of this sketch is to duplicate as many features as possible
//of the communication badge seen in Star Trek: The Next Generation.
//
//Connect one wire with a foil square attached to the end to pin 8.
//Attach vibration motor to motorPin.
//Attach status LED to ledPin.

char capval;                    //Variable to sotre value of capacitive sensor pin
char pinval = {1<<PINB0};       //Capacitive sensor is attached to pinval
const int motorPin = 12;        //Vibration motor is attached to motorPin
const int ledPin = 13;          //Status LED is attached to ledPin
int ledState = LOW;             //Default state of ledPin is LOW
int motorState = 0;             //Default state of motorPin is 0
long previousVibeMillis = 0;    //Default state of preiousVibeMillis is 0
long intervalVibe = 30;         //Interval between vibrations is 30ms
int buttonState = 0;

void setup()
{
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);      // connect to the serial port
}

void loop ()                           //Checking the touch sensor for activity
{                                      //
  capval = getcap(pinval);
  if (capval > 1)       //If button was not pressed, but is now pressed
  {
    Serial.println ("button pressed");
    buttonState = 1;
  }
  if (capval < 2 && buttonState == 1)
  {
    Serial.println ("button just released");
    for (int x = 0; x < 4; x ++)
    {
      if (millis() - previousVibeMillis > intervalVibe)
      {
        previousVibeMillis = millis();
        if (ledState == LOW)
        {
          ledState = HIGH;
        }
        else
        {
          ledState = LOW;
        }
        if (motorState == 0)
        {
          motorState = 255;
        }
        else
        {
          motorState = 0;
        }
        analogWrite (motorPin, motorState);
        digitalWrite(ledPin, ledState);
      }
    }
  }
  if (capval < 2)
  {
//    Serial.println ("button not pressed");
    buttonState = 0;
  }
}

// returns capacitance on one input pin
// pin must be the bitmask for the pin e.g. (1<<PB0)
char getcap(char pin)
{
  char i = 0;
  DDRB &= ~pin;          // input
  PORTB |= pin;          // pullup on
  for(i = 0; i < 16; i++)
    if( (PINB & pin) ) break;
  PORTB &= ~pin;         // low level
  DDRB |= pin;           // discharge
  return i;
}

This, instead of causing the motor/led to pulse four times, causes the touch button to act like a latching switch, so when I touch the button and release it, the motor and the led go full-on, and then when I touch and release the button again, it turns them off again. This pattern is consistent and repeatable. On, off, on, off, each touch switching its state.

I think I’m missing something. Also, I’m having difficulty abstracting the button state idea into code. I tried a simple method to keep track of the button state and output the results to the Serial terminal:

//TNGBadge for Arduino 0017
//Created by Adrian Thomas-Prestemon
//
//The purpose of this sketch is to duplicate as many features as possible
//of the communication badge seen in Star Trek: The Next Generation.
//
//Connect one wire with a foil square attached to the end to pin 8.
//Attach vibration motor to motorPin.
//Attach status LED to ledPin.

char capval;                    //Variable to sotre value of capacitive sensor pin
char pinval = {1<<PINB0};       //Capacitive sensor is attached to pinval
const int motorPin = 12;        //Vibration motor is attached to motorPin
const int ledPin = 13;          //Status LED is attached to ledPin
int ledState = LOW;             //Default state of ledPin is LOW
int motorState = 0;             //Default state of motorPin is 0
long previousVibeMillis = 0;    //Default state of preiousVibeMillis is 0
long intervalVibe = 30;         //Interval between vibrations is 30ms
int buttonState = 0;

void setup()
{
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);      // connect to the serial port
}

void loop ()                           //Checking the touch sensor for activity
{                                      //
  capval = getcap(pinval);
  if (capval > 1)       //If button was not pressed, but is now pressed
  {
    Serial.println ("button pressed");
    buttonState = 1;
  }
  if (capval < 2 && buttonState == 1)
  {
    Serial.println ("button just released");
  }
  if (capval < 2)
  {
    Serial.println ("button not pressed");
    buttonState = 0;
  }
  delay (1000);  //to make output more readable
}

// returns capacitance on one input pin
// pin must be the bitmask for the pin e.g. (1<<PB0)
char getcap(char pin)
{
  char i = 0;
  DDRB &= ~pin;          // input
  PORTB |= pin;          // pullup on
  for(i = 0; i < 16; i++)
    if( (PINB & pin) ) break;
  PORTB &= ~pin;         // low level
  DDRB |= pin;           // discharge
  return i;
}

…but I’m not sure if I got the idea right. What am I missing?

It has the desired effect, but acting upon button-release, instead. I could make do with this behaviour, but I'd like to try and get the action to take place on button-press.

You don't need to live with it. You have a line that reads "Serial.print("button pressed");". Move the code that runs the motor and led after that statement.

In the second code section, you keep resetting previousVibeMillis in the if block. No wonder it keeps going and going.

Remind me, again, why you don't want to use delay.

In the third block, you show some code, but no output. I can't tell from that whether the output does, or does not, match your expectations. As it is, it looks OK to me.

I took a look at the example at http://arduino.cc/en/Tutorial/ButtonStateChange, and I did my best to adapt it to use the touch button.

Here is the result:

//TNGBadge for Arduino 0017
//Created by Adrian Thomas-Prestemon
//
//The purpose of this sketch is to duplicate as many features as possible
//of the communication badge seen in Star Trek: The Next Generation.
//
//Connect one wire with a foil square attached to the end to pin 8.
//Attach vibration motor to motorPin.
//Attach status LED to ledPin.

char capval;                    //Variable to sotre value of capacitive sensor pin
char pinval = {1<<PINB0};       //Capacitive sensor is attached to pinval
const int motorPin = 12;        //Vibration motor is attached to motorPin
const int ledPin = 13;          //Status LED is attached to ledPin
int ledState = LOW;             //Default state of ledPin is LOW
int motorState = 0;             //Default state of motorPin is 0
long previousVibeMillis = 0;    //Default state of preiousVibeMillis is 0
long intervalVibe = 30;         //Interval between vibrations is 30ms
int buttonState = 0;

void setup()
{
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);      // connect to the serial port
}

void loop ()                           //Checking the touch sensor for activity
{                                      //
  capval = getcap(pinval);
  if (capval > 1)       //If button was not pressed, but is now pressed
  {
    Serial.println ("button pressed");
    buttonState = 1;
  }
  if (capval < 2 && buttonState == 1)
  {
    Serial.println ("button just released");
    for (int x = 0; x < 4; x ++)
    {
      analogWrite (motorPin, 255);
      digitalWrite (ledPin, HIGH);
      delay(30);
      analogWrite (motorPin, 0);
      digitalWrite (ledPin, LOW);
      delay(30);
//      if (millis() - previousVibeMillis > intervalVibe)
//      {
//        previousVibeMillis = millis();
//        if (ledState == LOW)
//        {
//          ledState = HIGH;
//        }
//        else
//        {
//          ledState = LOW;
//        }
//        if (motorState == 0)
//        {
//          motorState = 255;
//        }
//        else
//        {
//          motorState = 0;
//        }
//        analogWrite (motorPin, motorState);
//        digitalWrite(ledPin, ledState);
//      }
    }
  }
  if (capval < 2)
  {
//    Serial.println ("button not pressed");
    buttonState = 0;
  }
}

// returns capacitance on one input pin
// pin must be the bitmask for the pin e.g. (1<<PB0)
char getcap(char pin)
{
  char i = 0;
  DDRB &= ~pin;          // input
  PORTB |= pin;          // pullup on
  for(i = 0; i < 16; i++)
    if( (PINB & pin) ) break;
  PORTB &= ~pin;         // low level
  DDRB |= pin;           // discharge
  return i;
}

The only problem is that as long as my finger is on the capacitive button, it increments the number of button presses constantly, until I remove my finger from the capacitive button. Also, depending on the timing with which I release the capacitive button, the led sometimes stays on, even after I release.

I tried the code with a regular button, and I don’t get that problem. Press the button, and it stays at 1 button press. Release it, and it says “off.” Press it again, and hold it, and it says 2 presses, until I let go and press it again.

How do I get the touch button to behave like a regular button?

You don't need to live with it. You have a line that reads "Serial.print("button pressed");". Move the code that runs the motor and led after that statement.

But when I do that, it just loops over and over again, until I release the button.

Remind me, again, why you don't want to use delay.

I want this button-press code and the resulting haptic feedback to be a minor function of the device. I have read in many places that using delay() makes it so no code at all can be run while the delay is occurring. I read that by using the millis() thing instead, I can allow other code to run simultaneously. I want the button-watcher and haptic feedback to not get in the way of other code execution. That is possible, yes?

In the future of this project, the Arduino will be managing bluetooth/wifi communications constantly, and I can't afford for a button press to get in the way of those communications, no matter how few milliseconds are being wasted. Hence why I can't use delay. I think.