Questions about this piezo... er... magnetic buzzer

Hello!
I have finished a model password door lock project with Arduino! I used a red LED, green LED, piezo buzzer, soft potentiometer, and 3 buttons. Now, I am just making improvements. When I enter the correct password, the Arduino plays a victory "charge" music. Now, I want to create an audible CLICK with the piezo (sounding like a lock opening) when I enter the correct password. But, I don't want it to sound like a little TAP. Can someone teach me how to do that?

Link to datasheet of piezo: http://www.sparkfun.com/datasheets/Components/CEM-1203.pdf
Picture of piezo (copy and paste to browser, and find CIRC-06):

http://myclass.peelschools.org/ele/7/25580/Resources/Arduino%20Resources/ARDX-EG-SPAR-PRINT-85-REV-10[1].pdf

Code for my project:

#include <MomentaryButton.h>
#include <Easy.h>
#include <avr/sleep.h>
#include <avr/power.h>
// Project 27 Keypad door lock
#include <EEPROM.h>
MomentaryButton button(2);
MomentaryButton sButton(3);
MomentaryButton nButton(4);
Song alarm(11);
String secretCode = "1234";
String code = "";
int position = 0;
boolean locked = true;
int note[] = {
  262, 262, 392, 523, 392, 523};
int duration[] = {
  100, 100, 100, 300, 100, 300};
int redPin = 9;
int greenPin = 8;
byte piezo = 11;
byte tries = 0;
boolean playing = 1;
void setup()                    
{
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  DDRD = 0;
  PORTD = 0x1c;
  loadCode();
  flash();
  updateOutputs();
  button.setup();
  sButton.setup();
  nButton.setup();
}

void loop()                    
{
  char key = getKey();
  if (key == '*'  && ! locked)
  {
    // unlocked and * pressed so change code
    position = 0;
    getNewCode();
    updateOutputs();
  }
  if (key == '#')
  {
    locked = true;
    playing = 1;
    code = "";
    position = 0;
    updateOutputs();
    for(int i = 1; i <= 3; i++){
      tone(11, 250, 250);
      delay(250);
    }
  }
  if (key >= '0' && key <= '9')///
  {
    code += (char)key;
    position++;
  }
  if(!digitalRead(2)) tone(11, 500);
  else noTone(11);
  //if (position == 4)//
  //{
  if(code == secretCode && position == 4){
    locked = false;
    tries = 0;
    updateOutputs();
    for (int thisNote = 0; thisNote < 6 && playing; thisNote ++) {
      // play the next note:
      tone(11, note[thisNote]);
      // hold the note:
      delay(duration[thisNote]);
      // stop for the next note:
      noTone(11);
      delay(25);
    }
    playing = 0;
  }
  else if (position == 4 && code != secretCode){
    noTone(11);
    alarm.siren();
    alarm.siren();
    noTone(11);
    position = 0;
    code = "";
    tries++;
  }
  if(tries >= 3){
    alarm.ambulance();
    alarm.ambulance();
    noTone(11);
    sleep();
  }
  //}
}

void updateOutputs()
{
  if (locked)
  {
    digitalWrite(redPin, HIGH);
    digitalWrite(greenPin, LOW);  
  }
  else
  {
    digitalWrite(redPin, LOW);
    digitalWrite(greenPin, HIGH); 
  }
}

void getNewCode()
{
  flash();
  for (int i = 0; i < 4; i++ )//
  {
    char key;
    key = getKey();
    while (key == 0)
    {
      key = getKey();
    }
    flash();
    secretCode[i] = key;
  }
  saveCode();
  flash();
  flash();
}

void loadCode()
{
  if (EEPROM.read(0) == 1)
  {
    for(int i = 0; i < 4; i++)//
      secretCode[i] = EEPROM.read(i+1);
  }
}

void saveCode()
{
  for(int i = 0; i < 4; i++){//
    EEPROM.write(i+1, secretCode[i]);
  }
  EEPROM.write(0, 1);
  tone(11, 500, 1000);  
}

void flash()
{
  digitalWrite(redPin, HIGH);
  digitalWrite(greenPin, HIGH);    
  delay(500);
  digitalWrite(redPin, LOW);
  digitalWrite(greenPin, LOW);    
}
char getKey(){
  button.check();
  sButton.check();
  nButton.check();
  if(button.wasClicked()){
    int reading = analogRead(A0);
    reading = map(reading, 0, 1023, 0, 7);
    return reading + 48;
  }
  if(sButton.wasClicked()) return '*';
  if(nButton.wasClicked()) return '#';
  return 0;
}
void sleep(){
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // sleep mode is set here
  DDRD = 0;
  DDRB = 0;
  PORTD = 0;
  PORTB = 0;
  sleep_enable();
  power_adc_disable();
  power_spi_disable();
  power_timer0_disable();
  power_timer1_disable();
  power_timer2_disable();
  power_twi_disable();
  MCUCR = _BV (BODS) | _BV (BODSE);
  MCUCR = _BV (BODS);
  sleep_mode();
}

Thanks!

I've been wondering about PWM audio, so I had a quick look and found this: PIC sound player (PCM to PWM converter) | Enide!
It describes using mplayer to convert a wav to a pcm file then they use another tool to produce a header file for use in your sketch.

You could then download some samples ( maybe clicks from an old mono mobile phone ), and convert them.

Otherwise just experiment with different PWM values changing rapidly to create your desired effect.

Using tone() to give a 1/2 duty cycle square wave to the piezo causes it the beep a certain tone. I think that the buzzer only works with square waves. Clicks don't have a particular tone; just volume. I will try using a transistor to amplify the volume! Also, I have a kit called "Fun with Computer Electronics" bought from Chapters book store. It uses a 4011 NAND gate chip, 4017 counter chip, 1uF and 10uF capicitors, piezo transducer, 10k, 100k, 1M ohm resistors, 10 LEDs, 9V battery to make various circuits on a cardboard box with metal springs. There are circuits that make thay piezo transducer click. I have another question: why does the black piezo buzzer I'm using creates no electricity from vibrations, but the other white piezo transducer from the Chapters kit does?

Does it have an internal drive circuit? I would think (although I'm not sure) that such a circuit would prevent any voltage produced from tapping it from appearing on the input wires.

What's the internal drive circuit? I need to provide it a square wave to generate a tone. The other white piezo transducer produces a current when I push it one way, and a reverse current when I push it another way. The black one generates no electricity. I changed the name of topic of this thread. Could this piezo buzzer respond fast enough to generate ultrasonic, or near ultrasonic tones (>= 17kHz)? I can still hear around 17kHz, according to a YouTube test. Also, do mosquitos actually keep some distance from you when you play a 17kHz+ noise?

Could this piezo buzzer respond fast enough to generate ultrasonic, or near ultrasonic tones (>= 17kHz)? I can still hear around 17kHz, according to a YouTube test.

Probably, but you'd have to check the specs (if they are available). Transducers don't suddenly stop working at some frequency. The output "drops-off" at higher (or lower) frequencies, eventually to the point where there is no useful output.

Also, do mosquitos actually keep some distance from you when you play a 17kHz+ noise?

No, but you can use it to [u]repel teenagers[/u]. :smiley:

Apparently the best thing (other than a mosquito net) is a [u]device that uses propane[/u]. I guess it actually attracts and traps or kiss them. Or, a big fan can work too... Mosquitoes like still-air and can't fly against the wind very well, and the fan may also throw them off your scent.

What's the internal drive circuit?

Some piezo have a semiconductors (transistor or IC) inside, so they would beep single tone when power is applied. The problem, the frequency couldn't be changed, it's only good for warning beeping, around 2 or 4 kHz.
Even regular piezo, w/o internal circuitry not good as a sound transducer, as it's quite non-linear over audio band.
I'd suggest try to build a small audio amplifier and use a normal speaker.
You could experiment with USB speakers, they really cheap nowadays, < 10$.

Magician:
...so they would beep single tone when power is applied.

My doesn't do that. It doesn't turn sound into electricity; it only turns electricity into sound. I have a link to the datasheet in the first post.

DVDdoug:
The output "drops-off" at higher (or lower) frequencies

What does that mean? My piezo buzzer is rated for 2048Hz; that means that it is the loudest at that frequency, according to my tests. The datasheet has some chart for dB at certain frequencies, but it is hard to understand.

DVDdoug:
No, but you can use it to repel teenagers.

How did you make the "repel teenagers" a link? That 17kHz sound is very annoying to me; I don't think it's healthy to listen to it, either. I should try hear that sound every year, until the age I can't hear it anymore. Some people claim that mosquitos hate the 17kHz sound, as humans hate the screeching sound sometimes made by scratching fingernails on a bad blackboard.

I also made some [old] code for selecting a frequency with a potentiometer, then playing it on the piezo when a button is pressed:

const int piezo = 9;
const int button = 2;
const int led = 13;
const int pot = 0;
int toggle = 0;
int potval = 0;
int srl = 0;

const int numReadings = 50;

int readings[numReadings];      // the readings from the analog input
int index = 0;                  // the index of the current reading
int total = 0;                  // the running total
int average = 0;                // the average

int inputPin = A0;

void setup(){
  pinMode(piezo, OUTPUT);
  pinMode(button, INPUT);
  pinMode(led, OUTPUT);
  Serial.begin(9600);
  for (int thisReading = 0; thisReading < numReadings; thisReading++)
    readings[thisReading] = 0;   
}
void loop(){
  toggle = digitalRead(button);
  // subtract the last reading:
  total= total - readings[index];         
  // read from the sensor:  
  readings[index] = analogRead(inputPin); 
  // add the reading to the total:
  total= total + readings[index];       
  // advance to the next position in the array:  
  index = index + 1;                    

  // if we're at the end of the array...
  if (index >= numReadings)              
    // ...wrap around to the beginning: 
    index = 0;                           

  // calculate the average:
  average = total / numReadings;
  potval = map(average, 0, 1023, 32, 5000);
  if(toggle == LOW){
    tone(piezo, potval);
    digitalWrite(led, HIGH);
  }
  else{
    noTone(piezo);
    digitalWrite(led, LOW);
  }
  srl = potval;

  Serial.print("Piezo = ");
  Serial.print(srl);
  Serial.print("\t Pot. Value = ");
  Serial.print(analogRead(pot));
  Serial.print("\n");
}

For some reason, every time I press the button, Pot. Value (analogRead(A0)) starts to jitter very much in the Serial Monitor printout, and the buzzer plays a very jittery tone. To smoothing was desperate attempt to stop that, but it did no good. That is only when I press the button; otherwise, the values are reasonably smooth.

Link in your OP is to

Description: magnetic buzzer

, it's not piezo at all. You can't drive it from arduino, look at page 3 how to build a driver with transistor.

Magician:
...it's not piezo at all...

The Sparkfun instruction sheet calls it "piezo element". Their example connected the buzzer directly to the Arduino's digital pin.

I tried sending a 17000Hz square wave to the buzzer, and it just sounded like a quiet, low rumble; not a very annoying sound. I did 1200Hz, and I can hear some of the high pitched noise. It is definitely not like the 17000Hz sound I heard on the computer.

Link to datasheet of piezo: http://www.sparkfun.com/datasheets/Components/CEM-1203.pdf

That's clearly not a piezo device; the datasheet refers to a coil resistance, and clearly states it is a magnetic buzzer.
It also says it has a peak response at about 2kHz, with 17kHz looking to be 20 or 30 dB down.

@AWOL: By "Sparkfun Instruction Sheet", I meant the link below (I cannot just write it here due to the "[1]" in the link):

http://myclass.peelschools.org/ele/7/25580/Resources/Arduino%20Resources/ARDX-EG-SPAR-PRINT-85-REV-10[1].pdf

It is an instruction sheet for the Sparkfun Arduino Inventor's Kit. In CIRC-06, they called the magnetic buzzer "piezo element". They connected it directly to the digital pin! Aren't you supposed to use a diode and a transistor?

In CIRC-06, they called the magnetic buzzer "piezo element".

But on inspection, the markings on the case match the markings on the drawing of the magnetic buzzer with a coil resistance of 42 ohms.

Applying Ohm's Law (though Cole's Law is tastier), V=IR, so I=V/R = 5/42 = 119mA.
Oh dear.
Better speak to Sparkfun. (neat way of raising revenue though, Sparkfun)

I sent an email to help@oomlout.com addressing the problem. It is a big problem, because it could damage people's Arduinos by drawing too much current, and possibility of back EMF.

I tried connecting the magnetic buzzer backwards, and it still worked, but more quiet. I held a wire from one of the magnetic buzzer's leads, and a wire from the digital pin, and heard very tiny noise.


Response from Oomlout:

Email:
Hi Daniel;

Thanks for drawing this to our attention.

We'll get in touch with SparkFun and work on fixing it.

Regards
Aaron Nielsen
aaron@oomlout.com

I have another question: in some of my sketches, I use Ken Shirriff's IR Remote library. I use IR Hash codes to receive commands from a small remote (unknown protocol) and play notes on the magnetic buzzer according to the command. Both the library and the tone() function use Timer 2, so they cannot run together. I try using this function:

void beep(word tone, word duration){
  for (unsigned long i = 0; i < duration * 1000UL; i += tone * 2) {
    digitalWrite(9, HIGH);
    delayMicroseconds(tone);
    digitalWrite(9, LOW);
    delayMicroseconds(tone);
  }
}

However, beep(244, 5000) is miuch quieter than tone(9, 2048, 5000). Why is that? tone(9, 2048, 5000) is VERY loud and annoying.
IR_Record_Notes.ino:

#include <Easy.h>
#include <MemoryFree.h>
#include "Arrays.h"
#include <IRremote.h>
#include <Streaming.h>
int RECV_PIN = 11;
IRrecv irrecv(RECV_PIN);
decode_results results;
Song piezo(9);
char nots[11] = "zcdefgabCD";
char rec[100] = "\0"; //notes
byte recBeats[100];
char prevNote;
byte j = 0;
boolean recording = false;
codeMode mode = NOTE;
void setup()
{
  irrecv.enableIRIn(); // Start the receiver
  irrecv.blink13(1);
  for(byte i = 0; i < 100; i++){
    recBeats[i] = 4;
    recBeats[i] = constrain(recBeats[i], 1, 16);
  }
  Serial.begin(9600);
  Serial << "Note mode" << endl;
}

// Compare two tick values, returning 0 if newval is shorter,
// 1 if newval is equal, and 2 if newval is longer
// Use a tolerance of 20%
int compare(unsigned int oldval, unsigned int newval) {
  if (newval < oldval * .8) {
    return 0;
  } 
  else if (oldval < newval * .8) {
    return 2;
  } 
  else {
    return 1;
  }
}

// Use FNV hash algorithm: http://isthe.com/chongo/tech/comp/fnv/#FNV-param
#define FNV_PRIME_32 16777619
#define FNV_BASIS_32 2166136261

/* Converts the raw code values into a 32-bit hash code.
 * Hopefully this code is unique for each button.
 */
unsigned long decodeHash(decode_results *results) {
  unsigned long hash = FNV_BASIS_32;
  for (int i = 1; i+2 < results->rawlen; i++) {
    int value =  compare(results->rawbuf[i], results->rawbuf[i+2]);
    // Add value into the hash
    hash = (hash * FNV_PRIME_32) ^ value;
  }
  return hash;
}

void loop() {
  if(freeMemory() < 100){
    pinMode(13, OUTPUT);
    digitalWrite(13, HIGH);
    while(1);
  }
  if (irrecv.decode(&results)) {
    if(decodeHash(&results) == NOTE_MODE){
      mode = NOTE;
      Serial << "Note mode" << endl;
    }
    else if(decodeHash(&results) == SONG_MODE){
      mode = SONG;
      Serial << "Song mode" << endl;
    }
    if(mode == NOTE){
      if(decodeHash(&results) == RECORD){
        recording = !recording;
        if (recording) Serial << "Recording..." << endl;
        else Serial << endl << "Stopped. Recorded " << strlen(rec) << " notes. " << endl;
      }
      if(recording && decodeHash(&results) == BEAT_UP){
        recBeats[j]++;
        beep(250, 200);
      }
      else if(recording && decodeHash(&results) == BEAT_DOWN){
        recBeats[j]--;
        beep(500, 200);
      }
      for(byte i = 0; i < 10; i++){
        if (decodeHash(&results) == hashes[i]){
          if(recording){
            Serial << nots[i] << " ";
            rec[j] = nots[i];
            piezo.playOne(nots[i], recBeats[j], 75);
            j++;
          }
          else piezo.playOne(nots[i], 4, 75);
          //prevNote = nots[i];
        }
      }
      if (decodeHash(&results) == REST && recording){
        rec[j] = ' ';
        Serial << "_ ";
        j++;
      }
      if(decodeHash(&results) == PLAY || j > 97){
        Serial << "Playing " << strlen(rec) << " notes. " << endl;
        for(byte i = 0; i < strlen(rec); i++) piezo.playOne(rec[i], recBeats[i], 75);
      }
      if(decodeHash(&results) == DUMP || j > 97){
        Serial << "Dumped " << strlen(rec) << " notes." << endl;
        for(byte i = 0; i < 100; i++) rec[i] = 0;
        for(byte i = 0; i < 100; i++) recBeats[i] = 4;
        j = 0;
      }
    }
    else{
      for(int i = 1; i <= 6; i++){
        if(decodeHash(&results) == hashes[i]){
          Serial << "Playing \"" << songNames[i-1] << "\"" << endl;
          for(int j = 0; j < length[i-1]; j++){
            piezo.playOne(notes[i-1][j],beats[i-1][j],tempo);
          }
        }
      }
    }
    irrecv.resume(); // Resume decoding (necessary!)
  }
}

void beep(word tone, word duration){
  for (unsigned long i = 0; i < duration * 1000UL; i += tone * 2) {
    digitalWrite(9, HIGH);
    delayMicroseconds(tone);
    digitalWrite(9, LOW);
    delayMicroseconds(tone);
  }
}

Look at the datasheet - the resonant frequency of the device is given

The magnetic buzzer datasheet says that the rated frequency is 2048Hz. It is also the loudest at that frequency. Frequencies approching 2048Hz is also loud. Shouldn't beep(244, 5000) emit almost 2048Hz frequency as tone(9, 2048, 5000)? But it doesn't sound like anything near 2048Hz.