2

Is it garanteed (with some precision) that the phase of a PWM-signal generated by tone is the same on each pin? Can it be altered (by internal means of Arduino) so that it's different on different pins?

I'm looking for a way to adjust phases of signals from several pueso-buzzers by either adjusting distances (least preferrable) or programmaticaly (most preferrable) or by external components (if they're not very complicated).

1
  • an inverter should work. the NOT gate kind, not the AC making kind...
    – dandavis
    Commented Apr 3, 2017 at 18:39

3 Answers 3

2

The arduino.cc description of tone() says “Only one tone can be generated at a time”, so presumably you are using some other software to generate tones on multiple pins. For example, Brett Hagman's play() code, which Arduino tone() is derived from, uses multiple timers, one per tone.

When using play(), you probably can adjust phase by calling delayMicroseconds() between the two play() calls that start up the tone generation; for example:

play(11, 440);
delayMicroseconds(235); // Move 2nd tone 8 cm closer
play(9, 440);

Note, because tone() and play() use one timer per output (for example, timer 2 for first tone, timer 1 for next tone, timer 0 for third tone) there usually will be some timer prescale mismatches between 8-bit and 16-bit timers, which may result in slightly different frequencies, leading to some constant phase shift rate if you use that method.

With the speed of sound about 340.29 m/s in air at standard pressure, the wavelength of say 440 Hz would be under a meter, so I presume you would move speakers just a few tens of cm for phasing; hence a few hundred to a few thousand microseconds of phase offset. If you want good programmatic control, and also want to have quite a few speakers, external hardware in the form of a delay line or a bucket brigade chip is an obvious approach.

You could simulate a program-controlled delay line fairly easily using a handful of 74HC595 SIPO shift registers, as follows: Connect the DS of the first '595 to your tone() output pin. Connect the Q7S output of each '595 except the last to the DS of the following '595.

Now use another timer to repeatedly clock your tone data into the shift register chain. That is, connect all STCP and SHCP inputs in parallel to a timer output pin. (Eg, OC1A, OC1B, OC2A, or OC2B, which might be pins like 9–12 on an Uno or Nano). Run that timer at 10 to 100 KHz, ie, at some rate f that gives you the resolution and range of phase changing that you need.

Calling the shift register outputs o₀, o₁, o₂..., we have oⱼ delayed by (j-i)/f seconds relative to oᵢ. That is, successive SR outputs represent different taps for different delays.

1
  • But is it garanteed that if I turn on two plays simultaneously than I get those PWMs with the same phase and if I turn those on with certain delay than I get phase difference = delay/period?
    – YakovL
    Commented Apr 4, 2017 at 16:55
2

The main principle behind working with buzzers, in its simplest form, comes down to something along the lines of

digitalWrite(buzzerPin,HIGH);
delay(half_tone_frequency);
digitalWrite(buzzerPin,LOW);
delay(half_tone_frequency)

that, when repeated is enough to generate some tone on a single buzzer. However - to get desired tones (frequencies) right, you have to be mindful of the exact time that passes between each part of the code (the pin needs to oscillate in some frequency to produce a tone of that frequency)

So technically, its possible to create different sounds on different buzzers connected on different(!) pins at the same time, if you know exactly how much time each pin spends HIGH and LOW. This is naturally simpler when they do not need to be active concurrently.

3
  • But is it garanteed that if I turn on two tones simultaneously than I get those PWMs with the same phase and if I turn those on with certain delay than I get phase difference = delay/period?
    – YakovL
    Commented Apr 4, 2017 at 16:52
  • No, this approach is to not use the tone API at all, rather control the "PWM" manually by manipulating the pin states at precise intervals
    – TanyaV
    Commented Apr 5, 2017 at 8:28
  • Ah, sorry, I wasn't attentive enough, very nice, I'll try suggested stuff, but your answer clarifies the issue in the simplest terms (at least theoretically).
    – YakovL
    Commented Apr 5, 2017 at 23:17
2

If you want fine control over the phases, I assume you may also care about having low phase noise. In this case your best bet is to avoid toggling the pins in software and go for a hardware signal generation.

With an Arduino Uno or similar board, this can probably achieved by programming a timer. I would try the following:

Configure Timer 1 in waveform generation mode 12, i.e. CTC mode with TOP = ICR1. Set the compare output mode of both channels to toggle on compare match. Set ICR1 so that the timer has half the period of the signal you want. Now you can independently adjust the phases of both outputs by writing to OCR1A and OCR1B.

Note that those registers are not double buffered in this mode, so you have to be careful about when you write them.

The Arduino core library has no support for such timer configuration: you will have to learn how to program it yourself. If you are not familiar with the subject matter, I recommend you start by reading Nick Gammon's tutorial on timers.

2
  • But is it garanteed that if I turn on two tones simultaneously than I get those PWMs with the same phase and if I turn those on with certain delay than I get phase difference = delay/period?
    – YakovL
    Commented Apr 4, 2017 at 16:53
  • @YakovL: No, with this approach you do not turn the PWMs one after the other: you configure the timer to generate both signals, and when you start the timer you get both of them. The phase difference is not controlled by when you start the signals. It is controlled by the difference between the numbers you write to the OCR1A and OCR1B registers. And you can get single-cycle accuracy on the phase difference provided your frequency is lower than 122 Hz. Commented Apr 4, 2017 at 18:32

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.