Clustered MCUs

Enter Your Electronics & Design Project for Your Chance to Win a Grand Prize for the craziest project or a $100 Shopping Cart!

Back to The Project14 homepage

Project14 Home
Monthly Themes
Monthly Theme Poll

 

Introduction

 

Somehow or other I've ended up doing another music project (how did that happen?). My project14 this time is going to be the

'Microbit Quartet': four micro:bits playing music in time with each other. Here's the video of the group playing the traditional song

'Early One Morning'. The three yellow micro:bits appear by kind permission of Colchester Public Library (ie I've borrowed them

on my library card).

 

 

How it Works

 

To keep things simple, I used the existing sound capability but added an additional amplifier so that it could drive a miniature 8

ohm loudspeaker at a reasonable volume. Each micro:bit is monophonic and plays a single note at a time. Synchronisation between the

microbits keeps them in time (one micro:bit acts as the conductor).

 

For the amplifier, I'm using an NJM2073 (New Japan Radio Co. Ltd.). This is a small, dual amplifier that can be used either for

stereo or in a bridge configuration. I'm using it mono in a bridge because of the low supply voltage. The datasheet says it will

work down to 1.8V, so it will do fine on the 3V battery pack. The datasheet gives this recommended circuit for the bridge

arrangement but I'm a little unclear as to what I feed to it so I'm going to prototype it on a breadboard first so that I can

experiment with it and make sure it works how I think it does.

 

 

Here it is on a breadboard. I've included the Zobel network that they recommend (the resistor and capacitor across the speaker),

but I've increased the resistor value from 1R to 5.6R, in line with their suggestion to make it closer to the real resistance of

the speaker at low supply voltages.

 

 

Testing the Circuit

 

Here's the circuit I've ended up with but without the speaker and Zobel network which you can get from the circuit above. This will

look a little odd - I wanted to try it in the simulator but didn't have a model so I created the innards from two 'ideal' op amps

and two current-controlled current sources to replace the transistor mirrors. It won't be a particularly good model overall but it

does model the internal biasing arrangement shown in the datasheet which I was curious about. Anyhow, ignore all that - what's

important is the external circuitry [I've labelled the pins for my virtual amplifier component so you can see what's internal and

what's external]. Sorry if this is a bit confusing, say in the comments if you want a more straightforward version.

 

 

The logic signal at the input is attenuated with the potential divider and then ac coupled to the amplifier input with a capacitor.

I've lightly filtered the signal with the 5nF capacitor [odd value - really two 10nF in series] to round off the edges of the

digital waveform.

 

Here's how it behaves on the breadboard with a 1kHz 3V pk/pk squarewave at the input. Looks a bit noisy, but sounds ok. The bridge

is working nicely with each side roughly centred between the supply rails. [The scope traces show each side of the speaker relative

to GND and are ac coupled. The speaker sees the difference between the two.]

 

 

Here's what it looks like without the RC network on the output. I thought that I might get away without it but it is necessary to

stop it trying to oscillate.

 

 

Building the Amplifiers

 

Here are the interface boards after I finished soldering them together (they come as a kit of parts). I'm using these

because three of the Micro:bits are on loan from my local library so I need to be careful with them - everything will get

tested with my own Micro:bit (the one in the picture) and the loan ones only plugged in once I'm sure of the circuits and

power connections. Sorry about the picture - taken quickly under a desk lamp.

 

 

My aim at the moment is just to throw something together quickly for the video, so construction is on some tripad board.

Here they are as I built them but without the connecting wires (different desk lamp, just to confuse the camera). They're

meant to be identical yet all are subtly different (which pleases my natural sense of disorder and untidyness).

 

 

Here are the three performers that are appearing courtesy of Colchester Public Library. They each come in a neat little

plastic box holding the processor, the USB lead, and a pair of batteries with a battery box. I thought I'd have to mark my

own board but I've noticed that all the library ones are yellow so I'll immediately be able to tell my cyan one apart from

the rest. The piece of paper with a date on it is the return date. My little assistant looks nervous - I don't think he's

happy at the prospect of meeting all these super-clever thinking machines.

 

 

I've wired the amplifier boards to the interface boards [feels like a production line around here at the moment] and done

a quick test using my own micro:bit. They all play music.

 

 

My own battery pack hasn't had the batteries changed for a long time (if ever) and only reads 2.57V but they still work

quite happily. At the moment the only music I've tried is the music.BLUES tune that comes with the Python music library

but, if it works with that, it'll work with anything I throw at it. One thing that I discovered is that the output from

the micro:bit (on P0) isn't a square wave. It looks like they're doing it with PWM (I'd guess with the hardware, given how

awful the software-emulated PWM that can go on any pin is) with a fairly large mark/space ratio. Here's what the 'scope sees measured

across the speaker:

 

 

It's good because it actually makes for a more interesting sound than the square waves I was using from the generator.

 

Next job is to wire in the synchronisation lead between the boards and then apply myself to sorting out the music and

setting up the world premiere performance.

 

I'm too late to compete for the prizes now but that's ok, there'll be plenty more Project14 competitions - I'm doing it for the fun of it now.

 

Synchronisation

 

The synchronisation between the boards is very simple. I just wired all the P1 pins together (there's a ground wire between the boards too, to act as a return). My own micro:bit outputs on that pin and all the others input on the same pin. The line goes high at the start of the note and low at the end. The lead does the note timing and the others watch for the changes and react accordingly.

 

Code

 

At the start I was going to use Python but, unlike the blocks, it doesn't seem to have a suitable function for sounding a note without also giving it a duration. I tried using the blocks but got very confused about how on earth to do do an array of values. At that point, I tried changing to Javascript and discovered that it's basically the same thing as the blocks (to the extent that you can view what you've done as either by swapping back and forth). Once I could see an actual programming language it was all plain sailing (children now must be really, really clever to cope with the block stuff - had me totally confused). Mind you, I never thought I'd see the day when I'd be programming a microcontroller in Javascript.

 

Here's the code I ended up with for each processor. It was surprisingly simple in the end, though it took me quite a while with a large sheet of paper to sort out the music. In case you don't recognise it, the music is the traditional song 'Early One Morning'. My micro:bit (the cyan one) plays the melody and the others play a succession of three-note chords as an accompaniment. The code struggles a little at times - if you watch the video closely you may notice that the displays have difficulty keeping up and the music is a bit off-beat in a couple of places - but it works well enough for this, even if it isn't 'production quality'.

 

Player 1 (Conductor):

 

let musicTones = [
    0, 0,
    0, 0, 0, 0,
    392, 392, 392,
    392, 466, 587, 587,
    659, 523, 440, 392,
    370, 440, 294, 294,
    392, 392, 392,
    392, 466, 587, 587,
    659, 523, 440, 370,
    392,
    440, 466, 523,
    587, 466, 392,
    440, 466, 523,
    587, 466, 392,
    392, 466, 587, 784,
    740, 659, 587, 523,
    466, 440, 392, 370,
    392]
let musicDurations = [
    400, 400,
    400, 400, 400, 400,
    400, 200, 200,
    200, 200, 200, 200,
    200, 200, 200, 200,
    200, 200, 200, 200,
    400, 200, 200,
    200, 200, 200, 200,
    200, 200, 200, 200,
    800,
    400, 200, 200,
    200, 200, 400,
    400, 200, 200,
    200, 200, 400,
    200, 200, 200, 200,
    200, 200, 200, 200,
    200, 200, 200, 200,
    800]
let musicCharacters = [
    "1", "2",
    "1", "2", "3", "4",
    "G", "G", "G",
    "G", "B", "D", "D",
    "E", "C", "A", "G",
    "F", "A", "D", "D",
    "G", "G", "G",
    "G", "B", "D", "D",
    "E", "C", "A", "F",
    "G",
    "A", "B", "C",
    "D", "B", "G",
    "A", "B", "C",
    "D", "B", "G",
    "G", "B", "D", "G",
    "F", "E", "D", "C",
    "B", "A", "G", "F",
    "G"
]
basic.forever(() => {
    for (let i = 0; i < musicTones.length; i++) {
        pins.digitalWritePin(DigitalPin.P1, 1)
        basic.showString(musicCharacters[i])
        music.ringTone(musicTones[i])
        basic.pause(musicDurations[i])
        pins.digitalWritePin(DigitalPin.P1, 0)
        music.ringTone(0)
        basic.pause(20)
    }
    music.ringTone(0)
    basic.pause(1000)
})

 

Player 2:

 

let musicTones = [
    0, 0,
    0, 0, 0, 0,
    196, 196, 196,
    196, 196, 196, 196,
    131, 131, 131, 131,
    147, 147, 147, 147,
    196, 196, 196,
    196, 196, 196, 196,
    131, 131, 147, 147,
    196,
    147, 147, 147,
    196, 196, 196,
    147, 147, 147,
    196, 196, 196,
    196, 196, 196, 196,
    131, 131, 131, 131,
    147, 147, 147, 147,
    196]
let musicCharacters = [
    " ", " ",
    "1", "2", "3", "4",
    "G", "G", "G",
    "G", "G", "G", "G",
    "C", "C", "C", "C",
    "D", "D", "D", "D",
    "G", "G", "G",
    "G", "G", "G", "G",
    "C", "C", "D", "D",
    "G",
    "D", "D", "D",
    "G", "G", "G",
    "D", "D", "D",
    "G", "G", "G",
    "G", "G", "G", "G",
    "C", "C", "C", "C",
    "D", "D", "D", "D",
    "G"
]
basic.forever(() => {
    for (let i = 0; i < musicTones.length; i++) {
        while (pins.digitalReadPin(DigitalPin.P1) == 0)
        { }
        basic.showString(musicCharacters[i])
        music.ringTone(musicTones[i])
        while (pins.digitalReadPin(DigitalPin.P1) == 1)
        { }
        basic.showString(" ")
        music.ringTone(0)
        //        basic.pause(20)
    }
    basic.showString(" ")
    music.ringTone(0)
    basic.pause(1000)
})

 

Player 3:

 

let musicTones = [
    0, 0,
    0, 0, 0, 0,
    247, 247, 247,
    247, 247, 247, 247,
    165, 165, 165, 165,
    185, 185, 185, 185,
    247, 247, 247,
    247, 247, 247, 247,
    165, 165, 185, 185,
    247,
    185, 185, 185,
    247, 247, 247,
    185, 185, 185,
    247, 247, 247,
    247, 247, 247, 247,
    165, 165, 165, 165,
    185, 185, 185, 185,
    247]
let musicCharacters = [
    " ", " ",
    "1", "2", "3", "4",
    "B", "B", "B",
    "B", "B", "B", "B",
    "E", "E", "E", "E",
    "F", "F", "F", "F",
    "B", "B", "B",
    "B", "B", "B", "B",
    "E", "E", "F", "F",
    "B",
    "F", "F", "F",
    "B", "B", "B",
    "F", "F", "F",
    "B", "B", "B",
    "B", "B", "B", "B",
    "E", "E", "E", "E",
    "F", "F", "F", "F",
    "B"
]
basic.forever(() => {
    for (let i = 0; i < musicTones.length; i++) {
        while (pins.digitalReadPin(DigitalPin.P1) == 0)
        { }
        basic.showString(musicCharacters[i])
        music.ringTone(musicTones[i])
        while (pins.digitalReadPin(DigitalPin.P1) == 1)
        { }
        basic.showString(" ")
        music.ringTone(0)
        //        basic.pause(20)
    }
    basic.showString(" ")
    music.ringTone(0)
    basic.pause(1000)
})

 

Player 4:

 

let musicTones = [
    0, 0,
    0, 0, 0, 0,
    294, 294, 294,
    294, 294, 294, 294,
    196, 196, 196, 196,
    262, 262, 262, 262,
    294, 294, 294,
    294, 294, 294, 294,
    196, 196, 262, 262,
    294,
    220, 220, 220,
    294, 294, 294,
    220, 220, 220,
    294, 294, 294,
    294, 294, 294, 294,
    196, 196, 196, 196,
    265, 265, 265, 265,
    294]
let musicCharacters = [
    " ", " ",
    "1", "2", "3", "4",
    "D", "D", "D",
    "D", "D", "D", "D",
    "G", "G", "G", "G",
    "C", "C", "C", "C",
    "D", "D", "D",
    "D", "D", "D", "D",
    "G", "G", "C", "C",
    "D",
    "A", "A", "A",
    "D", "D", "D",
    "A", "A", "A",
    "D", "D", "D",
    "D", "D", "D", "D",
    "G", "G", "G", "G",
    "C", "C", "C", "C",
    "D"
]
basic.forever(() => {
    for (let i = 0; i < musicTones.length; i++) {
        while (pins.digitalReadPin(DigitalPin.P1) == 0)
        { }
        basic.showString(musicCharacters[i])
        music.ringTone(musicTones[i])
        while (pins.digitalReadPin(DigitalPin.P1) == 1)
        { }
        basic.showString(" ")
        music.ringTone(0)
        //        basic.pause(20)
    }
    basic.showString(" ")
    music.ringTone(0)
    basic.pause(1000)
})

 

Here are links to the four pieces of code above on microbit.org:

 

Player 1: https://makecode.microbit.org/_HR0DDXC4MVUC

Player 2: https://makecode.microbit.org/_FCKDYcfi333d

Player 3: https://makecode.microbit.org/_3zm9gUMsE4z7

Player 4: https://makecode.microbit.org/_4hsYcsMqVEUT

 

 

Links to other blogs I've written can be found here: jc2048 Blog Index