3

I have this code:

void setup() {
  pinMode(11, OUTPUT);
  TCCR2B = 0;
  TCNT2 = 0;
  TCCR2A = _BV(WGM21);
  TCCR2A |= _BV(COM2A0);
  OCR2A = 249;
}

void loop() {
  soundBuzzer();
}

void soundBuzzer() {
  TCCR2B |= _BV(CS21);
}

void silenceBuzzer() {
  TCCR2B &= ~_BV(CS21);
  TCNT2 = 0;
}

(Got it from here).

And I have an ultrasonic water atomizer that works in a frequency of 1.7 Mhz. Writing another number instead of 249 in the line "OCR2A = 249;", the frequency generated changes. With 249 it generates a frequency of 4 Khz. So, my question is: Which number do I have to write to get approximately 1.7 Mhz?

5
  • You can only divide the clock by an integer, so with a 16 MHz clock the closest you can achieve is 2 MHz. The data sheet will show you how to find the divider ratio register setting (specifically, if the division will be one more than the loaded count, and if there is a prescaler upstream of what you get to divide). If there is no perscaler it would seem like switching the board to a 12 MHz crystal and dividing by 7 might be a fit, but you'll need a custom bootloader. – Chris Stratton Apr 27 '17 at 19:13
  • More realistically, to operate this usefully you'll need the power and voltage amplifier from the intended driver circuit, so why not just take the entire original driver circuit, frequency generator and all, and figure out a way to enable/disable it from the Arduino? Do take appropriate precautions for the voltages which it may generate! – Chris Stratton Apr 27 '17 at 19:14
  • 5
    You cannot generate 1.7 MHz on an Uno. The closest you can get is 16 MHz / 9 = 1.778 MHz. – Edgar Bonet Apr 27 '17 at 19:21
  • You need to set the CS20 bit, not CS21. That way you have no prescaler. Then have it count to 9, like Edgar calculated. So set OCR2A to 8. – Gerben Apr 27 '17 at 19:43
  • 1
    Wow, how did I miss 16/9? That's not much worse than 12/7, for a lot less trouble. – Chris Stratton Apr 28 '17 at 2:00
3

Expanding from my comment... any signal level generated by this kind of microcontroller can only last for an integer number of CPU cycles. In order to generate it, you first have to compute the timing characteristics of the desired signal in terms of CPU cycles:

period = 16 MHz ÷ 1.7 MHz = 9.412 cycles

The closest you can get is 9 cycles, which gives the frequency

frequency = 16 MHz ÷ 9 = 1.778 MHz

Assuming this is acceptably close to your target, you can configure a timer to do it. The example code you provided uses Timer 2 with the OC2A output set to toggle mode. This approach can only give periods which are an even number of cycles, thus I am using the regular “non-inverting fast PWM” mode instead in the solution below. In this mode, the pin OC2A cannot be used with a controlled frequency, then I changed it to OC2B (pin 3 on the Uno). Here is the code:

const uint8_t OUTPUT_PIN = 3;  // = OC2B
const uint8_t PERIOD = 9;      // 9 CPU cycles ~ 1.778 MHz

void setup()
{
    pinMode(OUTPUT_PIN, OUTPUT);
    TCCR2B = 0;           // stop timer
    TCNT2  = 0;           // reset timer
    TCCR2A = _BV(COM2B1)  // non-inverting PWM on OC2B
           | _BV(WGM20)   // fast PWM mode, TOP = OCR2A
           | _BV(WGM21);  // ...ditto
    TCCR2B = _BV(WGM22);  // ...ditto
    OCR2A = PERIOD - 1;
    OCR2B = PERIOD/2 - 1;
}

void soundBuzzer() {
    TCCR2B |= _BV(CS20);  // F_CPU / 1
}

void silenceBuzzer() {
    TCCR2B &= ~_BV(CS20);
    TCNT2 = 0;
}

The generated signal is slightly asymmetric: it stays HIGH during 4 cycles and LOW for 5 cycles. If you want a symmetric signal (50% duty cycle), you can set PERIOD to 10 (5 cycles HIGH and 5 cycles LOW), but then the frequency drops to 1.6 MHz.

Edit: You could also replace your Arduino Uno by a cheap ATtiny85 microcontroller, or maybe an Arduino-compatible dev board based on it, like the Trinket or the Digispark.

This microcontroller has a built-in PLL which allows it to run one of its timers at 64 MHz, even though the CPU is running much slower. A 64 MHz timer allows you to hit the target 1.7 MHz frequency to within 1%:

64 MHz ÷ 38 = 1.684 MHz
1
  • Ditto for SAMD21-based Arduinos; a built-in PLL lets you run a timer at 96MHz. – ocrdu Oct 16 '20 at 14:10
-3

And I have an ultrasonic water atomizer that works in a frequency of 1.7 Mhz.

configure the timer into one of the pwm mode and 50% dc, all in the setup().

ATtiny85 family has a PLL oscillator and is better suited for this.

1
  • 4
    You seem to only be repeating part of an answer posted a month ago. – Chris Stratton May 29 '17 at 5:19

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.