Does anyone have any code to play a tune on a GPIO pin

RogerClark
Sun Nov 13, 2016 3:41 am
Hi Guys,

I’ve been looking for some code that would play some simple tunes to a piezo buzzer, but most of the Arduino code seems to be AVR only.

I’ve had a look at the Arduino Play Melody example, which uses delaymicroseconds, but this didn’t work when I tried it, so I had to modify the code a lot even to get it to work at all.

Actually the Play Melody tutorial code is terrible, it has a function to play note for a specific duration, but it uses global variables to set both the note and the duration rather than passing those values into the function (aaarrggghhh)

I’m sure there must be some other Arduino beeper music playing code that must be better and gave a few example tunes ???


Rick Kimball
Sun Nov 13, 2016 4:09 am
rtttl

RogerClark
Sun Nov 13, 2016 5:21 am
Rick Kimball wrote:rtttl

ahull
Sun Nov 13, 2016 11:19 am
I vaguely remember someone mentioned the “tone” library a while back. If tone is working (or we write our own) then there are quite a number of examples…

https://gist.github.com/spara/1832855

Which co-incidentally is the first computer generated tune I ever heard (beeped from an AIM65, back in the dark ages when I was a lad).

You might also like to play with the stuff here

Star Wars Imperial March With Piezo

… and this …

https://learn.sparkfun.com/tutorials/si … ezo-buzzer

One more thing, since we have timers aplenty on the STM32, we can produce accurate frequency tones without actually tying up very many CPU cycles, unlike the AIM65, which required tight assembly routines with lots of NOPs to get anything resembling the correct notes.

EDIT: Found the tone() thread => http://www.stm32duino.com/viewtopic.php?t=496


Nutsy
Sun Nov 13, 2016 1:36 pm
Ahhh haaa, i was asking something similar a while back… Changing PWM frequency on the fly to change the tone of a piezo.

Thanks for links Andy, more reading to do :D


RogerClark
Sun Nov 13, 2016 7:54 pm
Andy

Thanks

I looked at the Arduino and also the ESP8266 implementation of the “tone” function, and I think both use hardware times.
The ESP8266 version looks like it would be the easiest to port to libmaple.

But I think STM may already have done this in their F1 core, so it may be easier just to use that core or this project – especially because I was really only testing some beeper hardware.

BTW. If you recall, I was looking for beepers some time ago, and I tried both piezo ( passive ) and active beepers.
Both worked Ok for one project and I will probably use a piezo for that one.

But on a commercial project I am helping with, they needed a beeper inside a closed box ( no holes to make it water resistant), so the manufacturer of the product (who is in China) suggested using a sort of small speaker that is resonant at about 2.5kHz, but which is 16 ohms, so needs to be driven by a transistor, as the current is too high to be driven straight from an MCU.

But the proposed a bipolar NPN transistor as the current amplifier, which its self needs quite a lot of base current ( several milliamps).
So I have been testing an N channel FET instead, and IMHO it works better, as FETs seem to have better current capacity and take less drive current.

I just need to pull the gate on the FET low to prevent it floating up and getting miss enabled by the MCU during startup when the GPIO pins are floating.


pcuguru
Tue Nov 15, 2016 9:40 am
BJTs are current-driven devices, FETs are voltage-driven (they’re like old valves).
If you could AC-couple the speaker to a complementary-pair, you might get more drive out of it.
Cheers.

sheepdoll
Tue Nov 15, 2016 5:23 pm
With AVR I have used this code http://elm-chan.org/works/mxb/report.html It uses the PWM peripheral of the AVR . I have not looked to see if there is a comparable function on the STM32. It is interrupt driven. Unfortunately it is written in ASM
for a more functional version that plays from a SD card there is also http://elm-chan.org/works/sd8p/report.html This is written in C, the critical time loops however are in ASM.

I would love to find a way that similar code could be done with STM32 and in the next few days ;) It would be nice to have something that I could use to monitor a pipe organ console other than a bank of LEDs or a character display.


RogerClark
Tue Nov 15, 2016 8:09 pm
Thanks Julie

Using high speed PWM has crossed my mind before.

I recall CD players using some sort of 1 bit streaming technique, which sounds a lot like PWM to me, but perhaps its not fixed period PWM.

Of course if you have access to a MCU with a DAC, its even easier ;-)


zoomx
Wed Nov 16, 2016 7:17 am
Have you seen this tone(), noTone()?
http://www.stm32duino.com/viewtopic.php?t=496

STM core seems to has tone too
https://github.com/fpistm/STM/blob/mast … ino/Tone.h


ahull
Sat Nov 19, 2016 10:01 pm
A quick mashup of various bits of code from here and elsewhere and I came up with this frankensketch..

It “kinda” plays a tune (Beethoven’s Für Elise) on one of my tiny, tinny piezos between wired between pin PB0 and GND – it sounds every bit as bad as those cheap greetings cards, so pretty authentic.
You might get the sound marginally louder by wiring the piezo between 5V and the GPIO pin. Either way, don’t expect miracles. :roll:
Enjoy…. ;)

///////////////////////////////////////////////////////////////////////
//
// tone(pin,frequency[,duration]) generate a tone on a given pin
//
// noTone(pin) switch off the tone on the pin
//
// setToneTimerChannel(timer,channel) force use of given timer/channel
//
///////////////////////////////////////////////////////////////////////

#include "Arduino.h"
#include <HardwareTimer.h>

// define default timer and channel
#ifndef TONE_TIMER
#define TONE_TIMER 4
#endif
#ifndef TONE_CHANNEL
#define TONE_CHANNEL 4
#endif

#define PinTimer(pin) (PIN_MAP[pin].timer_device->clk_id-RCC_TIMER1+1)
#define PinChannel(pin) (PIN_MAP[pin].timer_channel)

// if USE_PIN_TIMER is set, the PWM timer/channel is used for PWM pins
#define USE_PIN_TIMER

// if USE_BSRR is set the tone pin will be written via the fast BSRR register
// instead of using the slow digitalWrite() function in the interrupt handler
#define USE_BSRR

// construct static timer array (
HardwareTimer TTimer1(1), TTimer2(2), TTimer3(3), TTimer4(4);
#ifdef STM32_HIGH_DENSITY
HardwareTimer TTimer5(5), TTimer6(6), TTimer7(7), TTimer8(8);
#endif
HardwareTimer *TTimer[4] {
&TTimer1,&TTimer2,&TTimer3,&TTimer4
#ifdef STM32_HIGH_DENSITY
,&TTimer5,&TTimer6,&TTimer7,&TTimer8
#endif
};

uint8_t tone_force_channel = 0; // forced timer channel
uint8_t tone_force_ntimer = 0; // forced timer

HardwareTimer *tone_timer = TTimer[TONE_TIMER]; // timer used to generate frequency
uint8_t tone_channel = TONE_CHANNEL; // timer channel used to generate frequency
uint8_t tone_ntimer = TONE_TIMER; // timer used to generate frequency

bool tone_state = true; // last pin state for toggling
short tone_pin = -1; // pin for outputting sound
short tone_freq = 444; // tone frequency (0=pause)
uint32_t tone_nhw = 0; // tone duration in number of half waves
uint16_t tone_tcount = 0; // time between handler calls in 1/36 usec
uint16_t tone_ncount = 0; // handler call between toggling
uint16_t tone_n = 0; // remaining handler calls before toggling
uint32_t tone_next = 0; // counter value of next interrupt

#ifdef USE_BSRR
volatile uint32_t *tone_bsrr; // BSRR set register (lower 16 bits)
uint32_t tone_smask=0; // BSRR set bitmask
uint32_t tone_rmask=0; // BSRR reset bitmask
#endif

////////////////////////////////////////////////////////////////////////////////
// timer hander for tone with no duration specified,
// will keep going until noTone() is called
void tone_handler_1(void) {
tone_next += tone_tcount; // comparator value for next interrupt
tone_timer->setCompare(tone_channel, tone_next); // and install it
if(--tone_n == 0){
tone_state = !tone_state; // toggle tone output

#ifdef USE_BSRR
if(tone_state)
*tone_bsrr = tone_smask;
else
*tone_bsrr = tone_rmask;
#else
digitalWrite(tone_pin,tone_state);// and output it
#endif

tone_n = tone_ncount; // reset interrupt counter
}
}

////////////////////////////////////////////////////////////////////////////////
// timer hander for tone with a specified duration,
// will stop automatically when duration time is up.
void tone_handler_2(void) {
tone_next += tone_tcount;
tone_timer->setCompare(tone_channel, tone_next);
if(--tone_n == 0){
if(tone_freq>0){ // toggle pin
tone_state = !tone_state;
#ifdef USE_BSRR
if(tone_state)
*tone_bsrr = tone_smask;
else
*tone_bsrr = tone_rmask;
#else
digitalWrite(tone_pin,tone_state);// and output it
#endif
}
tone_n = tone_ncount;
if(!--tone_nhw){ // check if tone duration has finished
tone_timer->pause(); // disable timer
pinMode(tone_pin, INPUT); // disable tone pin
}
}
}

////////////////////////////////////////////////////////////////////////////////
// play a tone on given pin with given frequency and optional duration in msec
void tone(uint8_t pin, short freq, unsigned duration = 0) {
tone_pin = pin;

#ifdef USE_PIN_TIMER
// if the pin has a PWM timer/channel, use it (unless the timer/channel are forced)
if(PinChannel(tone_pin) && !tone_force_channel){
tone_channel = PinChannel(tone_pin);
tone_ntimer = PinTimer(tone_pin);
} else
#endif
{
// set timer and channel to default resp values forced with setToneTimerChannel
tone_ntimer = tone_force_channel?tone_force_ntimer:TONE_TIMER;
tone_channel = tone_force_channel?tone_force_channel:TONE_CHANNEL;
}

tone_timer = TTimer[tone_ntimer-1];
tone_freq = freq;
tone_nhw = 0;
tone_next = 0;

tone_timer->pause();

if(freq > 0 || duration >0 ){
uint32_t count = 18000000/freq; // timer counts per half wave
tone_ncount = tone_n = (count>>16)+1; // number of 16-bit count chunk
tone_tcount = count/tone_ncount; // size of count chunk
if(duration > 0) // number of half waves to be generated
tone_nhw = ((duration*(freq>0?freq:100))/1000)<<1;
else // no duration specified, continuous sound until noTone() called
tone_nhw = 0;

pinMode(tone_pin, PWM); // configure output pin
pinMode(tone_pin, OUTPUT); // configure output pin

#ifdef USE_BSRR
// Set up BSRR register values for fast ISR
tone_bsrr = &((PIN_MAP[tone_pin].gpio_device)->regs->BSRR);
tone_smask = (BIT(PIN_MAP[tone_pin].gpio_bit));
tone_rmask = tone_smask<<16;
#endif

// Set up an interrupt on given timer and channel
tone_next = tone_tcount; // prepare channel compare register
tone_timer->setMode(tone_channel,TIMER_OUTPUT_COMPARE);
tone_timer->setCompare(tone_channel,tone_next);
// attach corresponding handler routine
tone_timer->attachInterrupt(tone_channel,tone_nhw?tone_handler_2:tone_handler_1);

// Refresh the tone timer
tone_timer->refresh();

// Start the timer counting
tone_timer->resume();

} else {

// detach handler routine
tone_timer->detachInterrupt(tone_channel);
// disactive pin by configuring it as input
pinMode(tone_pin, INPUT);

}
}

////////////////////////////////////////////////////////////////////////////////
// disable tone on specified pin, if any
void noTone(uint8_t pin){
tone(pin,-1); // it's all handled in tone()
}

////////////////////////////////////////////////////////////////////////////////
// set timer and channel to some different value
// must be called before calling tone() or after noTone() was called
void setToneTimerChannel(uint8_t ntimer, uint8_t channel){
tone_force_ntimer = ntimer;
tone_force_channel = channel;
}

void setup() {
}

void loop() {
// Fur Elise.. almost...
// Notes (and mistakes) unashamedly stolen from -> https://gist.github.com/spara/1832855

int our_tone_pin=PB0;
// play e4
delay(600);
tone(our_tone_pin, 329.63, 300);
delay(350);
// play d4#
tone(our_tone_pin, 311.13, 300);
delay(350);
// play e4
tone( 10, 329.63, 300);
delay(350);
// play d4#
tone( 10,311.13, 300);
delay(350);
// play e4
tone(our_tone_pin, 329.63, 300);
delay(350);
// play b3
tone( 10, 246.94, 300);
delay(400);
// play d4
tone(our_tone_pin, 293.66,300);
delay(400);
// play c4
tone(our_tone_pin, 261.63,300);
delay(400);
// play a3
tone(our_tone_pin, 220, 900);
delay(1000);
// play d3
tone(our_tone_pin,146.83, 300);
delay(350);
//play f3
tone(our_tone_pin, 174.61, 300);
delay(400);
//play a3
tone(our_tone_pin, 220, 300);
delay(400);
// play b3
tone(our_tone_pin, 246.94, 900);
delay(1000);
// play f3
tone(our_tone_pin, 174.61, 300);
delay(400);
// play a3#
tone(our_tone_pin, 233.08, 300);
delay(400);
// play b3
tone(our_tone_pin, 246.94, 300);
delay(400);
// play c4
tone(our_tone_pin, 261.63, 900);
delay(1000);
delay(300);
// play e4
tone(our_tone_pin, 329.63, 300);
delay(400);
// play d4#
tone(our_tone_pin, 311.13, 300);
delay(400);
// play e4
tone(our_tone_pin, 329.63, 300);
delay(400);
// play d4#
tone(our_tone_pin, 311.13, 300);
delay(400);
// play e4
tone(our_tone_pin, 329.63, 300);
delay(400);
// play b3
tone(our_tone_pin, 246.94, 300);
delay(400);
// play d4
tone(our_tone_pin, 293.66, 300);
delay(400);
// play c4
tone(our_tone_pin, 261.63, 300);
delay(400);
// play a3
tone(our_tone_pin, 220, 900);
delay(1000);
// play d3
tone(our_tone_pin, 146.83, 300);
delay(400);
// play f3
tone(our_tone_pin, 174.61, 300);
delay(400);
// play a3
tone(our_tone_pin, 220, 300);
delay(400);
// play b3
tone(our_tone_pin, 246.94, 900);
delay(1000);
// play f3
tone(our_tone_pin, 174.61, 300);
delay(400);
// play c4
tone(our_tone_pin, 261.63, 300);
delay(400);
// play b3
tone(our_tone_pin, 246.94, 300);
delay(400);
// play a3
tone(our_tone_pin, 220, 900);
delay(1000);
// play b3
tone(our_tone_pin,246.94, 300);
delay(400);
// play c4
tone(our_tone_pin, 261.63, 300);
delay(400);
// play d4
tone(our_tone_pin, 293.66, 300);
delay(400);
// play e4
tone(our_tone_pin, 329.63, 900);
delay(1000);
// play g3
tone(our_tone_pin, 196, 300);
delay(400);
// play f4
tone(our_tone_pin, 349.23, 300);
delay(400);
//play e4
tone(our_tone_pin, 329.23, 300);
delay(400);
// play d4
tone(our_tone_pin, 293.63, 900);
delay(1000);
// play e3
tone(our_tone_pin,164.81, 300);
delay(400);
// play e4
tone(our_tone_pin, 329.63, 300);
delay(400);
// play d4
tone(our_tone_pin, 293.63, 300);
delay(400);
// play c4
tone(our_tone_pin, 261.63, 900);
delay(1000);
// play d3
tone(our_tone_pin, 146.83, 300);
delay(400);
// play d4
tone(our_tone_pin, 293.63, 300);
delay(400);
// play c4
tone(our_tone_pin, 261.63, 300);
delay(400);
// play b3
tone(our_tone_pin, 246.94, 900);
delay(1000);
delay(400);
// play e4
tone(our_tone_pin, 329.63, 300);
delay(400);
// play d4#
tone(our_tone_pin, 311.13, 300);
delay(350);
// play e4
tone( 10, 329.63, 300);
delay(350);
// play d4#
tone( 10,311.13, 300);
delay(350);
// play e4
tone(our_tone_pin, 329.63, 300);
delay(350);
// play b3
tone( 10, 246.94, 300);
delay(400);
// play d4
tone(our_tone_pin, 293.66,300);
delay(400);
// play c4
tone(our_tone_pin, 261.63,300);
delay(400);
// play a3
tone(our_tone_pin, 220, 900);
delay(1000);
// play d3
tone(our_tone_pin,146.83, 300);
delay(350);
//play f3
tone(our_tone_pin, 174.61, 300);
delay(400);
//play a3
tone(our_tone_pin, 220, 300);
delay(400);
// play b3
tone(our_tone_pin, 246.94, 900);
delay(1000);
// play f3
tone(our_tone_pin, 174.61, 300);
delay(400);
// play a3
tone(our_tone_pin, 233.08, 300);
delay(400);
// play b3
tone(our_tone_pin, 246.94, 300);
delay(400);
// play c4
tone(our_tone_pin, 261.63, 900);
delay(1000);
delay(300);
// play e4
tone(our_tone_pin, 329.63, 300);
delay(400);
// play d4#
tone(our_tone_pin, 311.13, 300);
delay(400);
// play e4
tone(our_tone_pin, 329.63, 300);
delay(400);
// play d4#
tone(our_tone_pin, 311.13, 300);
delay(400);
// play e4
tone(our_tone_pin, 329.63, 300);
delay(400);
// play b3
tone(our_tone_pin, 246.94, 300);
delay(400);
// play d4
tone(our_tone_pin, 293.66, 300);
delay(400);
// play c4
tone(our_tone_pin, 261.63, 300);
delay(400);
// play a3
tone(our_tone_pin, 220, 900);
delay(1000);
// play d3
tone(our_tone_pin, 146.83, 300);
delay(400);
// play f3
tone(our_tone_pin, 174.61, 300);
delay(400);
// play a3
tone(our_tone_pin, 220, 300);
delay(400);
// play b3
tone(our_tone_pin, 246.94, 900);
delay(1000);
// play f3
tone(our_tone_pin, 174.61, 300);
delay(400);
// play c4
tone(our_tone_pin, 261.63, 300);
delay(400);
// play b3
tone(our_tone_pin, 246.94, 300);
delay(400);
// play a3
tone(our_tone_pin, 220, 900);
delay(1000);

delay(5000);

}


ahull
Sat Nov 19, 2016 10:36 pm
For good measure (pun intended)… here is a little Super Mario fun..
Again the code is a mashup of the tone() stuff from here… -> http://www.stm32duino.com/viewtopic.php?t=496#p4853
… this time the tunes are from here -> http://www.princetronics.com/supermariothemesong/ Full credit to the author (Dipto Pratyaksa) for the original sketch.
///////////////////////////////////////////////////////////////////////
//
// tone(pin,frequency[,duration]) generate a tone on a given pin
//
// noTone(pin) switch off the tone on the pin
//
// setToneTimerChannel(timer,channel) force use of given timer/channel
//
///////////////////////////////////////////////////////////////////////

#include "Arduino.h"
#include <HardwareTimer.h>

// define default timer and channel
#ifndef TONE_TIMER
#define TONE_TIMER 4
#endif
#ifndef TONE_CHANNEL
#define TONE_CHANNEL 4
#endif

#define PinTimer(pin) (PIN_MAP[pin].timer_device->clk_id-RCC_TIMER1+1)
#define PinChannel(pin) (PIN_MAP[pin].timer_channel)

// if USE_PIN_TIMER is set, the PWM timer/channel is used for PWM pins
#define USE_PIN_TIMER

// if USE_BSRR is set the tone pin will be written via the fast BSRR register
// instead of using the slow digitalWrite() function in the interrupt handler
#define USE_BSRR

// construct static timer array (
HardwareTimer TTimer1(1), TTimer2(2), TTimer3(3), TTimer4(4);
#ifdef STM32_HIGH_DENSITY
HardwareTimer TTimer5(5), TTimer6(6), TTimer7(7), TTimer8(8);
#endif
HardwareTimer *TTimer[4] {
&TTimer1,&TTimer2,&TTimer3,&TTimer4
#ifdef STM32_HIGH_DENSITY
,&TTimer5,&TTimer6,&TTimer7,&TTimer8
#endif
};

uint8_t tone_force_channel = 0; // forced timer channel
uint8_t tone_force_ntimer = 0; // forced timer

HardwareTimer *tone_timer = TTimer[TONE_TIMER]; // timer used to generate frequency
uint8_t tone_channel = TONE_CHANNEL; // timer channel used to generate frequency
uint8_t tone_ntimer = TONE_TIMER; // timer used to generate frequency

bool tone_state = true; // last pin state for toggling
short tone_pin = -1; // pin for outputting sound
short tone_freq = 444; // tone frequency (0=pause)
uint32_t tone_nhw = 0; // tone duration in number of half waves
uint16_t tone_tcount = 0; // time between handler calls in 1/36 usec
uint16_t tone_ncount = 0; // handler call between toggling
uint16_t tone_n = 0; // remaining handler calls before toggling
uint32_t tone_next = 0; // counter value of next interrupt

#ifdef USE_BSRR
volatile uint32_t *tone_bsrr; // BSRR set register (lower 16 bits)
uint32_t tone_smask=0; // BSRR set bitmask
uint32_t tone_rmask=0; // BSRR reset bitmask
#endif

////////////////////////////////////////////////////////////////////////////////
// timer hander for tone with no duration specified,
// will keep going until noTone() is called
void tone_handler_1(void) {
tone_next += tone_tcount; // comparator value for next interrupt
tone_timer->setCompare(tone_channel, tone_next); // and install it
if(--tone_n == 0){
tone_state = !tone_state; // toggle tone output

#ifdef USE_BSRR
if(tone_state)
*tone_bsrr = tone_smask;
else
*tone_bsrr = tone_rmask;
#else
digitalWrite(tone_pin,tone_state);// and output it
#endif

tone_n = tone_ncount; // reset interrupt counter
}
}

////////////////////////////////////////////////////////////////////////////////
// timer hander for tone with a specified duration,
// will stop automatically when duration time is up.
void tone_handler_2(void) {
tone_next += tone_tcount;
tone_timer->setCompare(tone_channel, tone_next);
if(--tone_n == 0){
if(tone_freq>0){ // toggle pin
tone_state = !tone_state;
#ifdef USE_BSRR
if(tone_state)
*tone_bsrr = tone_smask;
else
*tone_bsrr = tone_rmask;
#else
digitalWrite(tone_pin,tone_state);// and output it
#endif
}
tone_n = tone_ncount;
if(!--tone_nhw){ // check if tone duration has finished
tone_timer->pause(); // disable timer
pinMode(tone_pin, INPUT); // disable tone pin
}
}
}

////////////////////////////////////////////////////////////////////////////////
// play a tone on given pin with given frequency and optional duration in msec
void tone(uint8_t pin, short freq, unsigned duration = 0) {
tone_pin = pin;

#ifdef USE_PIN_TIMER
// if the pin has a PWM timer/channel, use it (unless the timer/channel are forced)
if(PinChannel(tone_pin) && !tone_force_channel){
tone_channel = PinChannel(tone_pin);
tone_ntimer = PinTimer(tone_pin);
} else
#endif
{
// set timer and channel to default resp values forced with setToneTimerChannel
tone_ntimer = tone_force_channel?tone_force_ntimer:TONE_TIMER;
tone_channel = tone_force_channel?tone_force_channel:TONE_CHANNEL;
}

tone_timer = TTimer[tone_ntimer-1];
tone_freq = freq;
tone_nhw = 0;
tone_next = 0;

tone_timer->pause();

if(freq > 0 || duration >0 ){
uint32_t count = 18000000/freq; // timer counts per half wave
tone_ncount = tone_n = (count>>16)+1; // number of 16-bit count chunk
tone_tcount = count/tone_ncount; // size of count chunk
if(duration > 0) // number of half waves to be generated
tone_nhw = ((duration*(freq>0?freq:100))/1000)<<1;
else // no duration specified, continuous sound until noTone() called
tone_nhw = 0;

pinMode(tone_pin, PWM); // configure output pin
pinMode(tone_pin, OUTPUT); // configure output pin

#ifdef USE_BSRR
// Set up BSRR register values for fast ISR
tone_bsrr = &((PIN_MAP[tone_pin].gpio_device)->regs->BSRR);
tone_smask = (BIT(PIN_MAP[tone_pin].gpio_bit));
tone_rmask = tone_smask<<16;
#endif

// Set up an interrupt on given timer and channel
tone_next = tone_tcount; // prepare channel compare register
tone_timer->setMode(tone_channel,TIMER_OUTPUT_COMPARE);
tone_timer->setCompare(tone_channel,tone_next);
// attach corresponding handler routine
tone_timer->attachInterrupt(tone_channel,tone_nhw?tone_handler_2:tone_handler_1);

// Refresh the tone timer
tone_timer->refresh();

// Start the timer counting
tone_timer->resume();

} else {

// detach handler routine
tone_timer->detachInterrupt(tone_channel);
// disactive pin by configuring it as input
pinMode(tone_pin, INPUT);

}
}

////////////////////////////////////////////////////////////////////////////////
// disable tone on specified pin, if any
void noTone(uint8_t pin){
tone(pin,-1); // it's all handled in tone()
}

////////////////////////////////////////////////////////////////////////////////
// set timer and channel to some different value
// must be called before calling tone() or after noTone() was called
void setToneTimerChannel(uint8_t ntimer, uint8_t channel){
tone_force_ntimer = ntimer;
tone_force_channel = channel;
}

/*
Arduino Mario Bros Tunes
With Piezo Buzzer and PWM

Connect the positive side of the Buzzer to pin 3,
then the negative side to a 1k ohm resistor. Connect
the other side of the 1 k ohm resistor to
ground(GND) pin on the Arduino.

by: Dipto Pratyaksa
last updated: 31/3/13
*/

/*************************************************
* Public Constants
*************************************************/

#define NOTE_B0 31
#define NOTE_C1 33
#define NOTE_CS1 35
#define NOTE_D1 37
#define NOTE_DS1 39
#define NOTE_E1 41
#define NOTE_F1 44
#define NOTE_FS1 46
#define NOTE_G1 49
#define NOTE_GS1 52
#define NOTE_A1 55
#define NOTE_AS1 58
#define NOTE_B1 62
#define NOTE_C2 65
#define NOTE_CS2 69
#define NOTE_D2 73
#define NOTE_DS2 78
#define NOTE_E2 82
#define NOTE_F2 87
#define NOTE_FS2 93
#define NOTE_G2 98
#define NOTE_GS2 104
#define NOTE_A2 110
#define NOTE_AS2 117
#define NOTE_B2 123
#define NOTE_C3 131
#define NOTE_CS3 139
#define NOTE_D3 147
#define NOTE_DS3 156
#define NOTE_E3 165
#define NOTE_F3 175
#define NOTE_FS3 185
#define NOTE_G3 196
#define NOTE_GS3 208
#define NOTE_A3 220
#define NOTE_AS3 233
#define NOTE_B3 247
#define NOTE_C4 262
#define NOTE_CS4 277
#define NOTE_D4 294
#define NOTE_DS4 311
#define NOTE_E4 330
#define NOTE_F4 349
#define NOTE_FS4 370
#define NOTE_G4 392
#define NOTE_GS4 415
#define NOTE_A4 440
#define NOTE_AS4 466
#define NOTE_B4 494
#define NOTE_C5 523
#define NOTE_CS5 554
#define NOTE_D5 587
#define NOTE_DS5 622
#define NOTE_E5 659
#define NOTE_F5 698
#define NOTE_FS5 740
#define NOTE_G5 784
#define NOTE_GS5 831
#define NOTE_A5 880
#define NOTE_AS5 932
#define NOTE_B5 988
#define NOTE_C6 1047
#define NOTE_CS6 1109
#define NOTE_D6 1175
#define NOTE_DS6 1245
#define NOTE_E6 1319
#define NOTE_F6 1397
#define NOTE_FS6 1480
#define NOTE_G6 1568
#define NOTE_GS6 1661
#define NOTE_A6 1760
#define NOTE_AS6 1865
#define NOTE_B6 1976
#define NOTE_C7 2093
#define NOTE_CS7 2217
#define NOTE_D7 2349
#define NOTE_DS7 2489
#define NOTE_E7 2637
#define NOTE_F7 2794
#define NOTE_FS7 2960
#define NOTE_G7 3136
#define NOTE_GS7 3322
#define NOTE_A7 3520
#define NOTE_AS7 3729
#define NOTE_B7 3951
#define NOTE_C8 4186
#define NOTE_CS8 4435
#define NOTE_D8 4699
#define NOTE_DS8 4978

#define melodyPin PB0
//Mario main theme melody
int melody[] = {
NOTE_E7, NOTE_E7, 0, NOTE_E7,
0, NOTE_C7, NOTE_E7, 0,
NOTE_G7, 0, 0, 0,
NOTE_G6, 0, 0, 0,

NOTE_C7, 0, 0, NOTE_G6,
0, 0, NOTE_E6, 0,
0, NOTE_A6, 0, NOTE_B6,
0, NOTE_AS6, NOTE_A6, 0,

NOTE_G6, NOTE_E7, NOTE_G7,
NOTE_A7, 0, NOTE_F7, NOTE_G7,
0, NOTE_E7, 0, NOTE_C7,
NOTE_D7, NOTE_B6, 0, 0,

NOTE_C7, 0, 0, NOTE_G6,
0, 0, NOTE_E6, 0,
0, NOTE_A6, 0, NOTE_B6,
0, NOTE_AS6, NOTE_A6, 0,

NOTE_G6, NOTE_E7, NOTE_G7,
NOTE_A7, 0, NOTE_F7, NOTE_G7,
0, NOTE_E7, 0, NOTE_C7,
NOTE_D7, NOTE_B6, 0, 0
};
//Mario main them tempo
int tempo[] = {
12, 12, 12, 12,
12, 12, 12, 12,
12, 12, 12, 12,
12, 12, 12, 12,

12, 12, 12, 12,
12, 12, 12, 12,
12, 12, 12, 12,
12, 12, 12, 12,

9, 9, 9,
12, 12, 12, 12,
12, 12, 12, 12,
12, 12, 12, 12,

12, 12, 12, 12,
12, 12, 12, 12,
12, 12, 12, 12,
12, 12, 12, 12,

9, 9, 9,
12, 12, 12, 12,
12, 12, 12, 12,
12, 12, 12, 12,
};
//Underworld melody
int underworld_melody[] = {
NOTE_C4, NOTE_C5, NOTE_A3, NOTE_A4,
NOTE_AS3, NOTE_AS4, 0,
0,
NOTE_C4, NOTE_C5, NOTE_A3, NOTE_A4,
NOTE_AS3, NOTE_AS4, 0,
0,
NOTE_F3, NOTE_F4, NOTE_D3, NOTE_D4,
NOTE_DS3, NOTE_DS4, 0,
0,
NOTE_F3, NOTE_F4, NOTE_D3, NOTE_D4,
NOTE_DS3, NOTE_DS4, 0,
0, NOTE_DS4, NOTE_CS4, NOTE_D4,
NOTE_CS4, NOTE_DS4,
NOTE_DS4, NOTE_GS3,
NOTE_G3, NOTE_CS4,
NOTE_C4, NOTE_FS4, NOTE_F4, NOTE_E3, NOTE_AS4, NOTE_A4,
NOTE_GS4, NOTE_DS4, NOTE_B3,
NOTE_AS3, NOTE_A3, NOTE_GS3,
0, 0, 0
};
//Underwolrd tempo
int underworld_tempo[] = {
12, 12, 12, 12,
12, 12, 6,
3,
12, 12, 12, 12,
12, 12, 6,
3,
12, 12, 12, 12,
12, 12, 6,
3,
12, 12, 12, 12,
12, 12, 6,
6, 18, 18, 18,
6, 6,
6, 6,
6, 6,
18, 18, 18, 18, 18, 18,
10, 10, 10,
10, 10, 10,
3, 3, 3
};

void setup(void)
{
pinMode(PB0, OUTPUT);//buzzer
pinMode(PC13, OUTPUT);//led indicator when singing a note

}
void loop()
{
//sing the tunes
sing(1);
sing(1);
sing(2);
}
int song = 0;

void sing(int s) {
// iterate over the notes of the melody:
song = s;
if (song == 2) {
Serial.println(" 'Underworld Theme'");
int size = sizeof(underworld_melody) / sizeof(int);
for (int thisNote = 0; thisNote < size; 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 / underworld_tempo[thisNote];

buzz(melodyPin, underworld_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.30;
delay(pauseBetweenNotes);

// stop the tone playing:
buzz(melodyPin, 0, noteDuration);

}

} else {

Serial.println(" 'Mario Theme'");
int size = sizeof(melody) / sizeof(int);
for (int thisNote = 0; thisNote < size; 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 / tempo[thisNote];

buzz(melodyPin, 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.30;
delay(pauseBetweenNotes);

// stop the tone playing:
buzz(melodyPin, 0, noteDuration);

}
}
}

void buzz(int targetPin, long frequency, long length) {
digitalWrite(PC13, HIGH);
long delayValue = 1000000 / frequency / 2; // calculate the delay value between transitions
//// 1 second's worth of microseconds, divided by the frequency, then split in half since
//// there are two phases to each cycle
long numCycles = frequency * length / 1000; // calculate the number of cycles for proper timing
//// multiply frequency, which is really cycles per second, by the number of seconds to
//// get the total number of cycles to produce
for (long i = 0; i < numCycles; i++) { // for the calculated length of time...
digitalWrite(targetPin, HIGH); // write the buzzer pin high to push out the diaphram
delayMicroseconds(delayValue); // wait for the calculated delay value
digitalWrite(targetPin, LOW); // write the buzzer pin low to pull back the diaphram
delayMicroseconds(delayValue); // wait again or the calculated delay value
}
digitalWrite(PC13, LOW);

}


RogerClark
Sun Nov 20, 2016 7:26 am
Thanks Andy

I have added tone() and notone() based on @enif’s code

I tested with your example and it played fine.


Leave a Reply

Your email address will not be published. Required fields are marked *