Driving a speaker, where's the volume?

I’ve got this darlington type circuit to drive a little speaker I pulled out of a US Robotics modem.

Driving it from an Arduino digital pin.

Using a multimeter, I tried different resistor combinations going for max volume. Ended up nothing in series with the SHR-4100 speaker, which measures 8-9 ohms
(Only internet data I have been able to find:
Mfg. - INTERVOX Mfg. # - SHR-4100
1-1/8" dia. x 3/8", 8 ohm .2 watt, 1200 Hz freq response. Low profile, mylar cone. PCB mountable, wave solderable.)
The transistors are date code 1980 & Marked Motorola 183. The package type is a 5/16" diamater can with a tab. I can’t find a datasheet (BC183 in a TO92 package keeps coming up).

With a multimeter ammeter on the base of the pre-driver, I kept dropping the resistance until I had ~30mA going into the transistor (should have taken better notes). The current thru the speaker seemed to peak at about 108mA wth a 12ohm resistor, dropping to 104mA with 10 ohm.

I figured I should been able to get more - the drive transistor is dropping 0.6, so I’ve got 4.4V across an 8 ohm speaker, shouldn’t I be getting more current & volume thru, like up towards several hundred mA?

code (with appropriate setup definitions) to make 5 bursts of tone, Tone=350.

    // create a buzz noise
    while (burst<6) {
      while (length<76){
        digitalWrite(speakerOut, LOW);
      delay (65);
      length = 0;
      burst = burst+1;
    burst = 0; // reset for next pass

5V from 9V 650mA wallwart thru Duemilanove regulator. Nothing else connected, just driving the one pin. Seems like it should be plenty, no?

Will do Richard. Have to wait until the morning now, everyone's gone to bed. Unless I can track down an 8ohm resistor. Guess I could put a 10 there, get an idea if the current increases. Looks like Vin is one diode drop from the raw 9V. In my final config, I have 12V available, that should let it get up there! I have a 12V wallwart, guess I could try that too, feed the speaker directly. P=I^2*R, sqrt(200mW/8)=158mA, speaker should be good for a little more volume anyway.

Just realized I didn't really have a Darlington - what I needed was the collector of both transistors going to the bottom of the speaker so both are pulling current. Instead I only had a pre-driver & then the actual driver. Moved one wire so now really have a darlington - still very quiet with 5V, and 9V raw. Changed to 12V supply with more currently capability as you suggested, now much louder!

Gotta tweak my code a little to go back to steady tone so I can get current measurements again. To the great annoyance of the rest of the family :-) Gotta dig up a low ohm resistor for quieter measurements.

Got some current going now! Just smoked a 10 ohm 1/8 watt resistor. Think I can tone down the the 30mA from the arduino, and go back to having a current limit resistor in series with the speaker.
PWM - won’t that change the speaker output frequency? I would think I’d need to use an analog pin change the voltage output level instead to change the overall gain, no?

Am rewiring now to get a pot in there to limit the gain of stage 1.

Alright, these little transistors are getting awful warm and making the speaker sound very funny.
Gonna change to a low rds mosfet when I get back from fencing, nice to-220 package that can take the 12V better.

PWM The pulse period will determine the frequency. The pulse width will determine the loudness.

hmm, really? I don't think this is right.

A PWM signal does not just represent one musical pitch unless you have an exact 50% duty cycle. Pulse width (duration) adds a second pitch to the acoustical mix. There are tree notes that will form the sound of a pwm signal: one pitch resulting from the overall period, one resulting from the (doubled) duration the signal is high, and one from the (doubled) duration from the low signal.

Each high (or low) part is like a half wave of a square wave, thats why you have to double the time to compute the perceived frequencies. But the high and low parts represent two different frequencies, two different pitches.

But maybe this is all wrong?

Yes, I am just looking to make a few bursts of tone to indicate an event has occurred. I did notice quite a variation in sound when the on time was different than the off time. Right now have both set at 350uS.

I revised my approach. The little speaker from the modem was only good for 200mW. Not loud enough in a busy fencing club. Tried a 75dB piezo $3.49 from Radio Shack (picked up on the way home yesterday), also not very loud. Think I will go with a real speaker.
Right now have this circuit driving an Advent 2.5" computer moniter speaker (the unpowered side of a self powered set).
The 100ohm into the gate doesn’t impact the volume. The 50ohm in series limits the max volume - which is pretty loud! With a 1Kohm pot it turns down nicely for debugging the melody.

I am using the Tone example from the playground as the basis for the alarm sound - have it warbling between 2 notes and sounding the last note a little longer to end.

Can I define a melody1 & melody2 etc in the pre-setup area and then select them with switch:case to play them?
case (1): // play melody1
case (2): // play melody2

 Plays a melody 
 * 8-ohm speaker on digital pin 8
 created 21 Jan 2010
 modified 14 Oct 2010
 by Tom Igoe 

This example code is in the public domain.
 #include "pitches.h"

// notes in the melody:
int melody[] = {
// note durations: 4 = quarter note, 8 = eighth note, etc.:
int noteDurations[] = {

void setup() {


void loop() {
  // iterate over the notes of the melody:
  for (int thisNote = 0; thisNote < 8; thisNote++) {

    // to calculate the note duration, take one second 
    // divided by the note type.
    //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
    int noteDuration = 1000/noteDurations[thisNote];
    noTone(8);    //apparent known bug - need this for the tone to play next.
    tone(8, melody[thisNote],noteDuration);

    // to distinguish the notes, set a minimum time between them.
    // the note's duration + 30% seems to work well:
    int pauseBetweenNotes = noteDuration * 1.10;
    // stop the tone playing:

I would use an LM386, if you look at the circuit in application note, there is a capacitor in series with the speaker.

http://www.biltek.tubitak.gov.tr/gelisim/elektronik/dosyalar/6/LM386.pdf http://www.national.com/mpf/LM/LM386.html

The "cap" is NOT just for filtering, not only does it stop DC bias from destroying your speaker, but stores a bit of energy.

You'll need to put a 10k pot in series between the Arduino pin and the input of the LM386. If you build the basic '386 circuit, it'll have a gain of 20, with a digital out put into an 8 ohm speaker it'll be pretty loud!

The reason you are getting less volume than you are expecting is that electromechanical speakers do not have the same characteristics as a piezio-electric speaker. Because it has a coil AND a magnet there is inductance and reluctance to take into account. The transistor circuit will work a whole lot better if you put an electrolytic cap in series with the speaker, say 250 uf, with the positive side of the cap going to your transistor amp, the negative side to the speaker, the other side of the speaker should go to ground.

Driving it the way you are will burn out the voice coil.

Thanks! I'll give that a try. I have some 2" speakers coming in from mpja.com, will try adding the cap to start and will check my parts on hand to see if I have a LM386 to play with as well.

I have the design I’m gonna go with.
Here’s the code, makes a nice litttle warble, good volume, calculated to be 3.5W.
I changed the circuit to look more like a MOSFET amplifier.

pitches.h is from the melody example in the playground

 #include "pitches.h"
 // can probably just add these 2 lines
 // #define NOTE_A5  880
 // #define NOTE_C6  1047
int speakerOut = 6; // D6, connect to speaker driver
int noteDuration = 0;
int thisNote = 0;
// notes in the melody:
int melody[] = {NOTE_C6, NOTE_A5,NOTE_C6, NOTE_A5,NOTE_C6, NOTE_A5,NOTE_C6};
// note durations: 4 = quarter note, 8 = eighth note, etc.:
int noteDurations[] = {12,12,12,12,12,12,4};

void setup()
{pinMode(speakerOut, OUTPUT); // to speaker driver}
void loop()
  // Buzzer section - connect pin 6 to speaker driver
  for (thisNote = 0; thisNote < 8; thisNote++) 
    // to calculate the note duration, take one second divided by the note type.
    //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
    noteDuration = 1000/noteDurations[thisNote];
    noTone(6);       //apparent known bug - need this for the tone to play next.
    tone(6, melody[thisNote],noteDuration);
    // to distinguish the notes, set a minimum time between them.
    // using the note's duration + 10%:
    int pauseBetweenNotes = noteDuration * 1.10;
    // stop the tone playing:
delay (3000);  // added for testing only
}  // end of void loop

Great! That's exactly what I meant, even if I didn't articulate it very well. Your speaker will last longer this way.

Took me a couple of trys to get there. At first I had a 0.47uF cap in series with the prior design, that just seemed to charge up & not do anything. So I tried a 0.22uF, also no sound. Bypassed the cap, had 180 ohm in series with speaker, that worked pretty well, but kind of quiet. Kept lowering the resistance, until went 1 step too low & smoked the speaker. Still didn't seem that loud prior to smoking. At that point went back to the protoboard and looked at how that LM386 worked, then looked up MOSFET amplifier to get the same kind of output. Most designs had stuff to offset the voltage for smoother AC - I just wanted 0 to 12v switching, but the AC kind of output, so I ignored the stuff that offset Vgate and got the output wired. The design is such that when the MOSFET is off the DC would go thru RL into the cap & speaker until the cap charged up to block the DC - and when the MOSFET was on it would drain the cap and drop the speaker voltage, etc.

With the breadboard and the only that program running it sounds great. Running with the rest of the program, it ends the warble with this kind of burp of sound - I don't what is causing that. The test program had 3 seconds of delay between warbles. I added 100mS of delay, didn't have any effect. Guess I need to put a scope on it and see what is happening when the tone ends.

Ok, had the box running tonight, works very well. If I use a PWM pin for the output, is it possible to have both the tone and the volume under s/w control? Wife was complaining it was too loud, having no sound was too weird. Seems like sticking in a pot with a knob is kinda crude after all the programming. Gonna go do some browsing....