0

I have a 4kHz pulse as trigger and I need two phase-shifted PWM output with divided frequency from arduino uno.

Now I've managed one PWM output using the following code:

int cnt = 0;
void setup() {
  pinMode(3, OUTPUT);
  pinMode(2, INPUT);
  attachInterrupt(digitalPinToInterrupt(2), rising_edge, RISING);
}

void loop() {

}

void rising_edge() {
  cnt = cnt + 1;
  if (cnt >= 4) {                           //divide by 8
    digitalWrite(3,(digitalRead(3)^1));
    cnt = 0;
  }
}

As suggested by Majenko♦, I tried using Timer1 lib, but the phase shift is always 15us, regardless timer1 period.

#include <TimerOne.h>

int cnt = 0;

void setup() {
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(2, INPUT);
  Timer1.initialize(10000);
  Timer1.attachInterrupt(ISP_T1);
  attachInterrupt(digitalPinToInterrupt(2), ISP_INTx, RISING);
}

void loop() {

}

void ISP_INTx() {
  cnt = cnt + 1;
  if (cnt >= 4) {
    digitalWrite(3,(digitalRead(3)^1));
    cnt = 0;
    Timer1.start();
  }
}

void ISP_T1() {
  digitalWrite(4,(digitalRead(4)^1));
  Timer1.stop();
}

Shift should be arbitrary value between 0-1 x period (depends on divider)

Adjustable duty is preferred but not necessary.

  • Phase shifted by how much? – Majenko May 28 '18 at 14:23
  • 0-1 x period, which depends on the divider (integer) – 7E10FC9A May 28 '18 at 14:39
  • So you want a variable phase shift then? That makes it harder. – Majenko May 28 '18 at 14:40
  • For this question, fixed phase shift is fine. I can listen serial port on loop function and reassign registers later. – 7E10FC9A May 28 '18 at 14:44
  • If you can live with a fixed duty cycle of 50%, then you could set Timer 1 to mode 4 (CTC with TOP = OCR1A), put both outputs into toggle mode, and use OCR1B to control the phase shift. No interrupts, no involvement of the CPU once the timer is set up. The tricky part would be selecting between the phase shifts φ and φ+π. For that, TCCR1C could help. – Edgar Bonet May 28 '18 at 15:38
0

If I understand correctly, it uses timer0 for interrupt and CPU for counting.

No, it doesn't. The interrupt is an interrupt. Timer0 is a timer. At the moment you just have an external interrupt triggering an ISR which adds to a variable and toggles an output.

Timer0 is used to drive millis() and delay().

What you need to do is set up a timer (not Timer0 since it's already reserved) which will time out with a period equal to the time difference of the phase shift. Start it in your existing ISR (when the output is toggled), and in the timer's ISR stop the timer and toggle the second output (or set it the same as the 0° output).

You may find the TimerOne library helpful for this.

  • But why timer0 functions doesn't work with attachInterrupt ? – 7E10FC9A May 28 '18 at 14:55
  • timer0 has nothing to do with attachInterrupt. – Majenko May 28 '18 at 14:55
  • link here it says 'Inside the attached function, delay() won’t work and the value returned by millis() will not increment'. – 7E10FC9A May 28 '18 at 14:59
  • That is correct. the Timer0 ISR won't run while the INTx ISR is running. But that has nothing at all to do with your question, so why are you asking? – Majenko May 28 '18 at 15:01
  • I tried setting up Timer1, but the shift is always 15us. – 7E10FC9A May 29 '18 at 10:45
0

I think your first example is very close. What about:

int cnt = 0;
void setup() {
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(2, INPUT);
  attachInterrupt(digitalPinToInterrupt(2), rising_edge, RISING);
}

void loop() {

}

void rising_edge() {
  cnt = cnt + 1;
  if (cnt >= 4) {                           //divide by 8
    cnt = 0;
  }
  switch(cnt){
    case 0: digitalWrite(3,HIGH);break;
    case 1: digitalWrite(4,HIGH);break;
    case 2: digitalWrite(3,LOW);break;
    case 3: digitalWrite(4,LOW);break;
  }
}

Assuming a uniform input frequency, pin 3 will be 90 degrees out of phase with pin 4. You could make this adjustable if you don't mind a larger divider by expanding the switch/case to eg 6 or 8 steps.

You could get more steps by triggering on rising and falling edges (although that may not give uniform phase if the incoming PWM is not at 50% duty cycle.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.