Ultrasonic Transducer Frequency Driver

Hey guys, I'm trying to get my head around creating a variable frequency output driver to power ultrasonic transducers, the frequency output will be used to drive fets that are on both sides of a centre taped transformer. The idea is to have control over the frequency and offtime between the two fets so I can control frequency sweeps between ~19kHz and 40kHz. I've been looking at http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1235060559/0#4 but think I might need some ideas on how to have specific control over this output? Any ideas are greatly appreciated.

Cheers

Do you need Pulse Width Modulation or just a variable frequency square wave?

The frequency output of a timer can be adjusted with a combination of clock pre-scaler and how far you let the timer run before you reset. To generate a square wave at a particular frequency you generally have to specify both. The source code for the Tone() function (Tone.cpp) is a good starting place for generating a square wave at a specified frequency.

I have downloaded the Arduino zip file for Windows. It does not appear to contain the source code file for Tone(), "Tone.cpp". Where can I get the source files for functions like Tone(). I want to be able to generate multiple frequencies simultaneously. I want some of those frequencies to be the same, but phase offset from a primary. I doubt that anyone has done this before. In looking at the ATmega 2560 data sheet, I believe that this can be done. What I need is some software example to use as a guide. Since Tone() does this for a single frequency at a time, perhaps I can use this as a guide to write software to do it for multiple simultaneous frequencies. I appreciate any help that anyone is willing to give.

Here is the code I use to generate a required frequency on the OCR1A pin of an atmega328p or ATtiny.

// Set the frequency that we will get on pin OCR1A
void setFrequency(uint16_t freq)
{
  uint32_t requiredDivisor = (F_CPU/2)/(uint32_t)freq;

#if defined(__AVR_ATtiny85__)
  // Code for attiny85
  uint16_t prescalerVal = 1;
  uint8_t prescalerBits = 1;
  uint32_t maxVal = 256;
  while (requiredDivisor > maxVal)
  {
    ++prescalerBits;
    maxVal <<= 1;
  }
  
  uint8_t top = ((requiredDivisor + (prescalerVal/2))/prescalerVal) - 1;
  TCCR1 = (1 << CTC1) | prescalerBits;
  GTCCR = 0;
  OCR1A = top;
#else
  // Code for atmega328p
  uint16_t prescalerVal;
  uint8_t prescalerBits;
  if (requiredDivisor < 65536UL)
  {
    prescalerVal = 1;
    prescalerBits = 1;
  }
  else if (requiredDivisor < 8 * 65536UL)
  {
    prescalerVal = 8;
    prescalerBits = 2;
  }
  else if (requiredDivisor < 64 * 65536UL)
  {
    prescalerVal = 64;
    prescalerBits = 3;
  }
  else if (requiredDivisor < 256 * 65536UL)
  {
    prescalerVal = 256;
    prescalerBits = 4;
  }
  else
  {
    prescalerVal = 1024;
    prescalerBits = 5;
  }

  uint16_t top = ((requiredDivisor + (prescalerVal/2))/prescalerVal) - 1;
  TCCR1A = 0;
  TCCR1B = (1 << WGM12) | prescalerBits;
  TCCR1C = 0;
  OCR1A = (top & 0xFF);
#endif
}

// Turn the frequency on
void on()
{
#if defined(__AVR_ATtiny85__)
  TCNT1 = 0;
  TCCR1 |= (1 << COM1A0);
#else
  TCNT1H = 0;
  TCNT1L = 0;  
  TCCR1A |= (1 << COM1A0);
#endif
}

// Turn the frequency off
void off()
{
#if defined(__AVR_ATtiny85__)
  TCCR1 &= ~(1 << COM1A0);
#else
  TCCR1A &= ~(1 << COM1A0);
#endif
}

to power ultrasonic transducers,

Are you sure your transducer is rated to work over that complete range? Most pizo based elements are pretty narrow bandwidth devices both for sending and receiving and if operated too far from their resonant frequency can have really poor sensitivity. A datasheet I guess is what would hold the answer.

Lefty