1

I am using this code to generate a square wave with Arduino and shift it by 90 and 180 degrees. However, this code is not able to shift it to 270 degrees. Could you please suggest how may I modify the code so that it supports a 270 degrees square wave phase shift operation.

void setup() {
  pinMode( 9 , OUTPUT );    // Arduino Pin  9 = OCR1A
  pinMode( 10 , OUTPUT );   // Arduino Pin 10 = OCR1B
  // Both outputs in toggle mode
  TCCR1A = _BV( COM1A0 ) |_BV( COM1B0 );
  // CTC Waveform Generation Mode
  // TOP=ICR1  
  // Note clock is left off for now
  TCCR1B = _BV( WGM13) | _BV( WGM12);
  OCR1A = 0;    // First output is the base, it always toggles at 0
}
// prescaler of 1 will get us 8MHz - 488Hz
// User a higher prescaler for lower freqncies

#define PRESCALER 1
#define PRESCALER_BITS 0x01
#define CLK 16000000UL    // Default clock speed is 16MHz on Arduino Uno


// Output phase shifted wave forms on Arduino Pins 9 & 10
// freq = freqnecy in Hertz (  122 < freq <8000000 )
// shift = phase shift in degrees ( 0 <= shift < 180 )
// Do do shifts 180-360 degrees, you could invert the OCR1B by doing an extra toggle using FOC
/// Note phase shifts will be rounded down to the next neared possible value so the higher the frequency, the less phase shift resolution you get. At 8Mhz, you can only have 0 or 180 degrees because there are only 2 clock ticks per cycle.  
int setWaveforms( unsigned long freq , int shift ) {
  // This assumes prescaler = 1. For lower freqnecies, use a larger prescaler.
  unsigned long clocks_per_toggle = (CLK / freq) / 2;    // /2 becuase it takes 2 toggles to make a full wave
  ICR1 = clocks_per_toggle;
  unsigned long offset_clocks = (clocks_per_toggle * shift) / 180UL; // Do mult first to save precision
  OCR1B= offset_clocks;
  // Turn on timer now if is was not already on
  // Clock source = clkio/1 (no prescaling)
  // Note: you could use a prescaller here for lower freqnencies
  TCCR1B |= _BV( CS10 ); 
}
// Demo by cycling through some phase shifts at 50Khz  
void loop() {
  setWaveforms( 40000 , 0 );
  delay(1000); 
  setWaveforms( 40000 , 90 );
  delay(1000); 
  setWaveforms( 40000 , 180 );
  delay(1000); 
}
7
  • 1
    The answer is in the code you posted, in a comment: “To do shifts 180-360 degrees, you could invert the OCR1B by doing an extra toggle using FOC”. Apr 6, 2018 at 7:35
  • I tried to understand that statement and it doesn't make much sense to me. Could you please help me modify the code or understand the statement? @EdgarBonet Apr 6, 2018 at 7:37
  • Not your own code?
    – AJD
    Apr 6, 2018 at 8:00
  • No, I took it from here: electronics.stackexchange.com/questions/174656/… Apr 6, 2018 at 8:01
  • It sounds like it means "Invert the waveform, and do a 90 degree shift".
    – Majenko
    Apr 6, 2018 at 9:24

1 Answer 1

1

The Arduino can only shift across a range of 180 degrees in CTC-mode using a 16 bit Timer. If you shift one channel to 90 degrees (other OCR set to 1, not zero) and then add a logic-inverter, you'll get the equivalent of 270 degrees as mentioned by Edgar Bonet.

As for using FOC (forced output compare), Edgar B. is again correct. It's possible to preset a channel as inverted, then perform the shift with an OCR set for 90 degrees -- you won't need an extra logic inverter. But this method is not for someone new. You'll want an O-Scope handy to make it work (and some time to study FOC and CTC mode-12).

I think it easier to use a single section from a 7404 hex-inverter to flip your 90 degree shifted waveform to 270.

Search for "Phase Shift Square Waves" and you'll find a VIDEO (as of 2022) for an example project that uses FOC tactics to create runtime-adjustable phase shifts on an Arduino. Perhaps you'll see a way to make an easy code change for the flipped-phase you want...

FWIW stockvu

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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