Atmega328 + TLC5940 and Piezo Buzzing

I have a working project using an Atmega328 with a TLC5940 LED driver. It drives a 4x2 multiplexed grid of RGB LEDs.

I would like to add some beeps to my project, using a piezo buzzer. Unfortunately, the TLC5940 uses the timers that the tone() method uses and all the PWM pins on the Atmega chip are taken.

I was able to get some good tones by using this code on a digital pin:

for (wumbo = 0; wumbo < 50; wumbo++) {
  digitalWrite(2, HIGH);
  delayMicroseconds(500);
  digitalWrite(2, LOW);
  delayMicroseconds(500);
}

Unfortunately, if I do this then the LED multiplexing will pause, causing a flicker for ~50 ms which is unacceptable.

Is there any way I could make a beep using a piezo buzzer without adding any additional hardware? If not, what would be the best approach to this?

You are writing a blocking function that loops 50 times and expends 1ms each time through the loop. It's not a surprise this delays your sketch by 50 ms almost exactly.

If you did this in a non-blocking way, that would solve the problem. But the fact that you want to change the state of that pin 2000 times a second might make it hard to do that in a non-blocking way if there are other parts of the sketch that might take any more time than 500us in a blocking manner. If this is not the case, in your main sketch loop (and it probably has to be entered at least every 200us or so) you check to see if 500us has elapsed since the last time you changed the pin state, and if it has you reset your counter and toggle the pin. You use the micros() function to determine how many microseconds has elapsed in sketch time. Don't call delay() at all.

READ THIS: http://playground.arduino.cc/Code/AvoidDelay

If there is no way to do this, you can do it in hardware. I see you need a 50% duty cycle square wave at 1Khz. Do you have room for a 555 timer? That's a real cheap piece of hardware that would give you that square wave. You could run it through an AND gate and use a pin to enable or disable the 1Khz signal to your peizo in the sketch.

Thank you for the reply :smiley:

What am I doing wrong?

if (micros() - beeptiming >= 500) {
  PORTD ^= 1 << 2; //This toggles pin 2
  beeptiming = micros();
}

beeptiming is an unsigned long.

This produces a tone but it is very high pitched (doesn’t sound like the tone I made with the original code) and I can’t seem to make the pitch change.

Also, there is no room for the timer. However, I’m only using 6 of the 16 outputs on the TLC5940… Is there anything smaller that could do the same thing? If I get a smaller driver than I might be able to fit it

That looks OK to me and I think the logic is right. Is that in the main loop? I don't know what else you are doing, are there other calls that might be blocking or long running calls that prevent this from toggling about every 500us or so? Can you look at that pin on an oscilloscope or logic analyzer and see how often it actually is toggling?

This produces a tone but it is very high pitched

To lower the pitch change:-

if (micros() - beeptiming >= 500)

to

if (micros() - beeptiming >= 1000)

Better still use

if (micros() - beeptiming >= pitch)

Where pitch is a variable controlling the pitch of the note.

Ah, that makes sense Mike. Thank you.

But there are many other calls which is probably messing it up like JoeN described. In addition to multiplexing a 4x2 grid of RGB LEDs, I am multiplexing a grid of 4x2 tactile switches - I've noticed that the speed of the main loop changes depending on whether or not I am currently pressing a button. This also affects the pitch.

I think I may have my terminology mixed up... I'm struggling to find the difference between a piezo buzzer, piezo transducer, and a piezo speaker. I know that at least one of those has a built in oscillator that will let me get a tone by just supplying 5v. I think I might go to Radio Shack and see what I can get. I only need to make 3 different pitches, so I may be able to work something out.

've noticed that the speed of the main loop changes depending on whether or not I am currently pressing a button.

It depends on how you have written the code. Do you have a blocking function in there somewhere? Why not post the code and let us see.

Thanks for the help everybody, but I was able to get it working using a piezo buzzer that just requires voltage be applied rather than a square wave.

I got it from Radio Shack. It's 90db (maybe a little too loud) and 2800hz

juhkob: Thanks for the help everybody, but I was able to get it working using a piezo buzzer that just requires voltage be applied rather than a square wave.

I got it from Radio Shack. It's 90db (maybe a little too loud) and 2800hz

Add a resistor if it's too loud. It may already be pulling too much current. Otherwise, good job!