Components needed for this project are:
- Micro:bit
- zbit:toolbelt
- breadboard
- push button switch
- 10kohm pull up resistor
- jumper wires
- audio jack
- speaker
The audio jack is required to connect the micro:bit to the speaker through which we hear the note being played. The audio jack is connected to PIN_P4 of the micro:bit. The wiring is shown:
We will be playing the B, A and G notes: the B note has a frequency of 987.8Hz; the A note has a frequency of 880.0Hz; and the G note has a frequency of 784.0Hz. PWM is used to generate the frequency of these notes. Since these notes are all sine waves, a sine wave has to be generated for each of these notes at their frequency. The figure below shows a sine wave:
As shown from the figure above, a sine wave has varying amplitude at each time step. So we define an array that represents the amplitude (in percentage pulse width units) at each time step. For simplification, I use an array with a length of 16 and load it with values that are approximations of the digital value of the sine wave. Note that if higher order array length is used, the digital value will be more precise and continuous. The code representing this is given:
float B_wave = 987.8; float A_wave = 880.0; float G_wave = 784.0; float sine_wave[] = {0.53,0.72,0.84,0.91,0.94,0.86,0.78,0.63,0.47,0.28,0.16,0.09,0.06,0.13,0.22,0.38};Since each note has different frequencies, I use the wait_us() function to define the time in microseconds at which each value in the sine_wave array is outputted. This value is specified by:
where f is the frequency and is therefore different for each note. The code is given by:
if(uBit.buttonA.isPressed()) { speaker.period(1/B_wave); // 987.8Hz for (int i=0; i<16; i++) { speaker.write(sine_wave[i]); wait_us(63); } } else if(uBit.buttonB.isPressed()) { speaker.period(1/A_wave); // 880.0Hz for (int i=0; i<16; i++) { speaker.write(sine_wave[i]); wait_us(71); } } else if(sw3 == 0) { // negative logic speaker.period(1/G_wave); // 784.0Hz for (int i=0; i<16; i++) { speaker.write(sine_wave[i]); wait_us(80); } }The code above is in a while loop. Though it is better to put the code in an Interrupt Service Routine (ISR) at a specified frequency, the above tested code still works okay. The code is written in C++ as shown on the mbed platform. The complete code is given:
#include "MicroBit.h" DigitalIn sw3(P0_4); //MICROBIT_PIN_P3 PwmOut speaker(P0_5); //MICROBIT_PIN_P4 float B_wave = 987.8; float A_wave = 880.0; float G_wave = 784.0; float sine_wave[] = {0.53,0.72,0.84,0.91,0.94,0.86,0.78,0.63,0.47,0.28,0.16,0.09,0.06,0.13,0.22,0.38}; MicroBit uBit; int main(void) { uBit.init(); uBit.display.disable(); //disables the display while (1) { if(uBit.buttonA.isPressed()) { speaker.period(1/B_wave); // 987.8Hz for (int i=0; i<16; i++) { speaker.write(sine_wave[i]); wait_us(63); } } else if(uBit.buttonB.isPressed()) { speaker.period(1/A_wave); // 880.0Hz for (int i=0; i<16; i++) { speaker.write(sine_wave[i]); wait_us(71); } } else if(sw3 == 0) { // negative logic speaker.period(1/G_wave); // 784.0Hz for (int i=0; i<16; i++) { speaker.write(sine_wave[i]); wait_us(80); } } else { speaker.write(0); } } }
A video demonstration is shown:
No comments:
Post a Comment