Pages: [1]   Go Down
Author Topic: Did I reinvent delay() w/ a while() loop while trying to make a pulse function?  (Read 324 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Jr. Member
**
Karma: 0
Posts: 82
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I came up with a function to pulse a digital output:

Code:
void pulseOutLow(int pin, long duration){ // pulses a digital output for a certain length of time, meant for active low relays
  unsigned long timeStart = millis();
  boolean exitThis = false;
  digitalWrite(pin, LOW);
  while(!exitThis){
    if(millis() >= (timeStart + duration)){
      digitalWrite(pin, HIGH);
      exitThis = true;
    } // end if
  } // end while()
} // end pulseOutLow


However, I notice it seem to work about the same as delay().  What I mean is that if I do something like:
Code:
pulseOutLow(3, 500);
pulseOutLow(4, 500);

The first pin pulses for half a second, then the second pin pulses for half a second, much like if I would have just used delay()s and digitalWrite()s.  What I would like to happen is that the events fire in that order, but practically at the same time and then later they both turn off at practically the same time.  It seems to me the while() loop is keeping execution there as opposed to executing other code.

Does that happen because the Arduino is single threaded?  Did I just reinvent delay()?  My intent was to make a pulse function that I could call from within the main loop().  I want to make it a function rather than a copy/paste block of code for ease of use and elegance.  I have been able to make a timer of sorts using

Code:
    if (millis() == (whatTimeIsIt + idleEngineKill) && (!firstTimeOn) ){ // if 5 seconds has passed since entering the ready state, kill the motor and engage the brakes
      engineKill();
      brakesEngage();
      //timeOut = true;
    } // end test for timeOut

But I would prefer to make it a function.

Total source of what I am working on:

Code:
#include <ServoDecode.h>

char * stateStrings[] = {"NOT_SYNCHED", "ACQUIRING", "READY", "in Failsafe"};
 
// Define readable non-backwards states for relays.
// This is because relays are active LOW.  That means you can ground the pin and activate the relay.
const byte relayOn = 0;
const byte relayOff = 1;

// Give each relay friendly name and map to Arduino Digital I/O pin number
const byte relay1 = 2;  // wire 1 of the engine kill actuator.  Pulse to allow engine to run.
const byte relay2 = 3;  // wire 2 of the engine kill actuator.  Pulse to kill engine.
const byte relay3 = 4;  // brake controller
const byte relay4 = 5;  // currently unused

// For reading/feedback purposes, compare to the on off constants above
byte relay1State;
byte relay2State;
byte relay3State;
byte relay4State;

const unsigned long idleEngineKill = 50000; // delay to kill the motor
const unsigned long engineStartPeriod = 15000; // length of time allowed on a new connection to allow for starting the mower engine
long whatTimeIsIt = 0;
boolean timeOut = false;

// Initialize to zero to give it an obvious out of range starting value
// valid values will be from 1000 - 2000 with maybe some spillage in either direction

int curVal[7] = {0, 0, 0, 0, 0, 0, 0}; // Current values of the channel signals
int prevVal[7] = {0, 0, 0, 0, 0, 0, 0}; // Previous values of the channel signals
int arraySize = 7;
int numChannels = 6; // size of both arrays, used for feedback purposes

const int chChangeThreshold = 15; // Used to determine if there was user input on a given channel
// boolean userInput = false;
boolean firstTimeOn = true;
boolean firstTimeOff = true;
byte throttleChannel = 3; // sets the throttle channel to remove it from idle calculations.  Set to 0 to include all channels in idle calculations.  This is selectable as the transmitter is programmable.


void setup(){
 
  //ServoDecode setup
  ServoDecode.begin();
  ServoDecode.setFailsafe(3,1234); // set channel 3 failsafe pulse width
 
  // Relay Setup Initialize Pins so relays are inactive at reset
  digitalWrite(relay1, relayOff);
  digitalWrite(relay2, relayOff);
  digitalWrite(relay3, relayOff);
  digitalWrite(relay4, relayOff);
  relay1State = relayOff;
  relay2State = relayOff;
  relay3State = relayOff;
  relay4State = relayOff;
 
  // THEN set pins as outputs
  pinMode(relay1, OUTPUT);   
  pinMode(relay2, OUTPUT); 
  pinMode(relay3, OUTPUT); 
  pinMode(relay4, OUTPUT);   
  delay(1000); // Check that all relays are inactive at Reset
 
  // Prevent motor from starting and engage breaks
  engineKill();
  brakesEngage();

} // end setup()


void loop(){

  if(ServoDecode.getState()!= READY_state) { // transmitter is off or out of range
    if(firstTimeOff){
      engineKill(); // kill motor
      brakesEngage(); // engage brakes
      whatTimeIsIt = 0; // used as a semaphore
      //timeOut = false; // resets this semaphore
      firstTimeOff = false;
      firstTimeOn = true;
    } // end if(firsTimeOff)
  } // end if() transmitter not ready
 
  if(ServoDecode.getState()== READY_state) { // transmitter is on
   
    if (firstTimeOn){
      whatTimeIsIt = millis(); // if it's the first loop through, make a note of the time
      firstTimeOn = false; // resets this semaphore
      firstTimeOff = true;
      engineAllow(); // allow motor to be cranked
      brakesDisengage(); //disengage brakes
    } //enf if() firstTimeOn


    if (millis() == (whatTimeIsIt + idleEngineKill) && (!firstTimeOn) ){ // if 5 seconds has passed since entering the ready state, kill the motor and engage the brakes
      engineKill();
      brakesEngage();
      //timeOut = true;
    } // end test for timeOut
   
    if(testInput()){
      pulseOutLow(relay4, 500);
    } // end if() testInput()
   
  } // end if() transmitter ready
 
} // end main loop()

void engineKill(){
 
  if(relay1State == relayOn){ // just in case it was on for some random reason
    digitalWrite(relay1, relayOff); // prevents frying relays and/or actuators
    relay1State = relayOff;
  } // end safety check
 
  if(relay2State == relayOff){ // if it's already on, no need to do anything, so only do something if its off
    relay2State = relayOn;
    pulseOutLow(relay2, 500);
    relay2State = relayOff;
  } // end if()
 
  //digitalWrite(relay2, relayOn); // eventually pulse it, but for now just latch it
} // end engineKill

void engineAllow(){
  if(relay2State == relayOn){
    digitalWrite(relay2, relayOff); // just in case it was on for some random reason; prevents frying relays and/or actuators
    relay2State = relayOff;
  } // end safety check
 
  if(relay1State == relayOff){ // if it's already on, no need to do anything, so only do something if its off
    relay1State = relayOn;
    pulseOutLow(relay1, 500);
    relay1State = relayOff;
  } // end if()
 
  //digitalWrite(relay1, relayOn); // eventually pulse it, but for now just latch it
} // end instantEngineKill

void brakesEngage(){
 
  if(relay3State == relayOn){ // if it's already onn, no need to do anything, so only do something if its off
    digitalWrite(relay3, relayOff); // engages the brakes by removing power, allowing the mower to move
    relay3State = relayOff;
  } // end if() 
} // end brakesEngage

void brakesDisengage(){
 
  if(relay3State == relayOff){ // if it's already on, no need to do anything, so only do something if its on
    digitalWrite(relay3, relayOn); // disengages the brakes by applying voltage
    relay3State = relayOn;
  } // end if()   
} // end brakesDisengage

void pulseOutLow(int pin, long duration){ // pulses a digital output for a certain length of time, meant for active low relays
  unsigned long timeStart = millis();
  boolean exitThis = false;
  digitalWrite(pin, LOW);
  while(!exitThis){
    if(millis() >= (timeStart + duration)){
      digitalWrite(pin, HIGH);
      exitThis = true;
    } // end if
  } // end while()
} // end pulseOutLow

void pulseOutHigh(int pin, long duration){ // pulses a digital output for a certain length of time
  unsigned long timeStart = millis();
  boolean exitThis = false;
  digitalWrite(pin, HIGH);
  while(!exitThis){
    if(millis() >= (timeStart + duration)){
      digitalWrite(pin, LOW);
      exitThis = true;
    } // end if
  } // end while()
} // end pulseOutHIGH

boolean testInput(){ // tests for user input via the transmitter
  boolean userInput = false;
  boolean curPrevChange[arraySize]; // used an array to test for ignore channel.  May not be needed but makes it simpler
 
  // move current values to previous array, sample current values, populate current array
  for ( int i = 1; i <= numChannels; i++ ){
    prevVal[i] = curVal[i];
    curVal[i] = ServoDecode.GetChannelPulseWidth(i); // GetChannelPulseWidth technically requires a byte, but the number won't get high enough to cause problems
  } // end move old values to proper variable
 
     // Compute if there was a change
  for ( int i = 1; i <= numChannels; i++ ){
    if(i==throttleChannel){
      curPrevChange[i] = false; // set to false b/c this is excluded from calculations
    } // end if     
    else{ curPrevChange[i] =  (curVal[i] - prevVal[i]) > chChangeThreshold;  }
         //end else
    userInput = userInput | curPrevChange[i]; // if anything changes, the value will go true
    } // end for() of compare channel values from each array and populate curPrevChange array
  return userInput;
} // end testInput


Logged

Offline Offline
Edison Member
*
Karma: 9
Posts: 1016
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You have to do some reading :
http://arduino.cc/forum/index.php/topic,115352.0.html
http://arduino.cc/forum/index.php/topic,116640.msg877776.html
« Last Edit: August 05, 2012, 05:12:21 pm by Krodal » Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 615
Posts: 49388
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Did I just reinvent delay()?
Look at your time based loop:
Code:
  while(!exitThis){
    if(millis() >= (timeStart + duration)){
      digitalWrite(pin, HIGH);
      exitThis = true;
    } // end if
The only way to exit the while loop is for exitThis to become true, and the only way for that to happen is for the amount of time defined by duration to pass, so, yes, you have reinvented delay().

Logged

Pages: [1]   Go Up
Jump to: