Timed pulse sequence using micros()

Hi,

I’m trying to make some IO pulse with adjustable duty and frequency. I need to pulse one pin, then another. The timing would be like this… (the frequency is low <1kHz)

A ON
delayOnTime
A OFF
B ON
delay OnTime
A OFF
B OFF
delay OffTime

Here’s some code I’m trying but its just being weird. It is running in the main loop. Please could you have a look and offer any suggestions.

// Read Time
  unsigned long timeNow = micros();

// If not at zero Power
  if (onTime > 0 ) {
    // If full cycle has passed, begin a new one
    if (timeNow - cycleTimer >= periodUs) {
      digitalWrite(COILA,HIGH);  // COIL A ON
      digitalWrite(COILB,LOW); // COIL B OFF
      cycleTimer = timeNow;
      pulseAtimer = timeNow;
    }

    // if first pulse finished
    if ((timeNow - pulseAtimer > onTime) && (timeNow - cycleTimer < 2*onTime)) {
      digitalWrite(COILA,LOW);  // COIL A OFF
      digitalWrite(COILB,HIGH); // COIL B ON
      pulseAtimer = timeNow;
      pulseBtimer = timeNow;
    }

    // if second pulse finished, all coils off
    if ((timeNow - pulseBtimer > onTime) && (timeNow - cycleTimer < 2*onTime)) {
      digitalWrite(COILA,LOW);  // COIL A OFF
      digitalWrite(COILB,LOW); // COIL B OFF
      cycleTimer = timeNow;
      pulseAtimer = timeNow;
    }
  } else {
    digitalWrite(COILA,LOW);  // COIL A OFF
    digitalWrite(COILB,LOW); // COIL B OFF
  }

A ON delayOnTime A OFF B ON delay OnTime A OFF B OFF delay OffTime

Why do you turn A off twice? Which of the "A OFF"s is the correct one?

Please post your complete program. That extract does not compile.

The second A off is redundant

#define COILA 9
#define COILB 10

long optionValue[2] = {10,0};                    // Stores a value to represent the selected option of each menu item. Value here is the default startup value.
unsigned long duty = 0;                    // Holds the duty value from options
unsigned long periodUs = 0;    // The period of the signal in microseconds
unsigned long onTime = 0;     // Calculate on time when using duty percentage
unsigned long offTime = 0;        // Off time
unsigned long cycleTimer = 0;
unsigned long pulseAtimer = 0;
unsigned long pulseBtimer = 0;


void setup() {
  // put your setup code here, to run once:
// SET OUTPUTS  
  pinMode(COILA, OUTPUT);    // Set PWM outputs
  pinMode(COILB, OUTPUT); 
}

void loop() {
  // put your main code here, to run repeatedly:

// Output control
  duty = optionValue[1] / 2;                    // Holds the duty value from options
  periodUs = 1000000 / optionValue[0];    // The period of the signal in microseconds
  //onTime = periodUs * duty / 100;     // Calculate on time when using duty percentage
  onTime = optionValue[1]*10;
  offTime = periodUs - onTime;        // Off time
  if (onTime > 1000) onTime = 1000;     // Limit Max on time (prevents excess voltage at low frequencies)

   TimedPulse();
}


void TimedPulse() {

  // Read Time
  unsigned long timeNow = micros();
      
  // If not at zero Power
  if (onTime > 0 ) {
    // If full cycle has passed, begin a new one
    if (timeNow - cycleTimer >= periodUs) {
      digitalWrite(COILA,HIGH);  // COIL A ON
      digitalWrite(COILB,LOW); // COIL B OFF
      cycleTimer = timeNow;
      pulseAtimer = timeNow;
    }

    // if first pulse finished
    if ((timeNow - pulseAtimer > onTime) && (timeNow - cycleTimer < 2*onTime)) {
      digitalWrite(COILA,LOW);  // COIL A OFF
      digitalWrite(COILB,HIGH); // COIL B ON
      pulseAtimer = timeNow;
      pulseBtimer = timeNow;
    }

    // if second pulse finished, all coils off
    if ((timeNow - pulseBtimer > onTime) && (timeNow - cycleTimer < 2*onTime)) {
      digitalWrite(COILA,LOW);  // COIL A OFF
      digitalWrite(COILB,LOW); // COIL B OFF
      cycleTimer = timeNow;
      pulseAtimer = timeNow;
    }
  } else {
    digitalWrite(COILA,LOW);  // COIL A OFF
    digitalWrite(COILB,LOW); // COIL B OFF
  }

}

It might be simpler to consider that you have three possible states, and cycle constantly between them ...

State 1: A on, B off, duration onTime State 2: A off, B on, duration onTime State 3: A off, B off, duration offTime

The program would use one timer, setting the appropriate duration for the current state.

Something like this? You will need to add in the code for initialising and controlling the output pins, and for calculating the on and off durations from the period and duty cycle. Also, remove the serial prints from the actual program.

const unsigned long ON_DURATION =  2000000;  // for demo purposes, set to 2 seconds
const unsigned long OFF_DURATION = 4000000; // for demo purposes, set to 4 seconds

unsigned long previousTime;
unsigned long duration;

byte state;

void setup()
{
  Serial.begin(115200);  // remove serial output from real program
  Serial.println("State 1: A on / B off");
  // turn A on
  // turn B off
  state = 1;
  previousTime = micros();
  duration = ON_DURATION;
}

void loop()
{
  unsigned long timeNow = micros();
  if (timeNow - previousTime >= duration)
  {
    previousTime = timeNow;
    switch (state)
    {
      case 1:
        Serial.println("State 2: A off / B on");
        // turn A off
        // turn B on
        state = 2;
        duration = ON_DURATION;
        break;
      case 2:
        Serial.println("State 3: A off / B off");
        // turn A off
        // turn B off
        state = 3;
        duration = OFF_DURATION;
        break;
      case 3:
        Serial.println("State 1: A on / B off");
        // turn A on
        state = 1;
        duration = ON_DURATION;
        break;
    }
  }
}

By the way, it would be better to define constants for each of the values of state, to give them more meaningful names. For example:

// I have made up these state names.  I don't know what your states represent :-)
#define GO_LEFT 1
#define GO_RIGHT 2
#define STOP 3
...
state = GO_LEFT;

Thank you! That's working great!