For those who are interested, I've created a tone generation library for the Arduino. It is non-blocking (it will play tones while the rest of your program is working) and produces square wave tones only.
Tom Igoe wrote this easy to use Theremin example. See how you can translate the values from the analog pin to frequencies directly using the map() function?
/*
Theremin
Plays notes based on a sensor reading
uses Tone library by Brett Hagman
http://code.google.com/p/arduino-tone/
circuit:
* potentiometer on analog in 0
* 8-ohm speaker on digital pin 8
created 18 Aug 2009
by Tom Igoe
*/
#include <Tone.h>
Tone musicMaker; // instance of the tone library
int lastSensorReading = 0; // value of the previous sensor reading
int threshold = 10; // minimum difference between readings
void setup() {
Serial.begin(9600);
// start the music:
musicMaker.begin(11);
}
void loop() {
// read an analog input:
int sensorReading = analogRead(0);
// map the analog readings to a range from A3 to G5:
int thisTone = map(sensorReading, 0, 1023, NOTE_A3, NOTE_G5);
// if the sensor reading is different enough
// from the last sensor reading, change the pitch:
if (abs(sensorReading - lastSensorReading) > threshold) {
musicMaker.play(thisTone);
// save the current sensor reading
// for next time through the loop:
lastSensorReading = sensorReading;
}
}
I was looking for just this kind of code library just yesterday. Absolutely brilliant! It works with a piezo transducer I picked up at Radio Shack too. Thanks!
Does the Tone Library work with an ATmega328P running at 1MHz from the internal oscillator? The tones seem way too low but I could easily be doing something wrong.
Is anyone else interested in the Tone Library working at 1MHz?
Why not modify the play method in that library to multiply the given frequency by 16. You could use the F_CPU define or clockCyclesPerMicrosecond() to check the actual clock frequency assuming you are setting this in your boards.txt file
adding something like this at the top of the play method should work (although I have not tried it):
frequency = frequency * (16 / clockCyclesPerMicrosecond());
Why not modify the play method in that library to multiply the given frequency by 16
Good thinking! That will at least tell me if I'm doing somthing wrong or if there's a deficiency in the library.
You could use the F_CPU define
The library uses F_CPU to calculate the configuration values for the counter. Unfortunately, I suspect the various frequency / divisor ranges are designed to only work for 16MHz and 8MHz clocks.
assuming you are setting this in your boards.txt file
I am. And from some blink / delay testing I think I did it correctly.
adding something like this at the top of the play method should work (although I have not tried it):
frequency = frequency * (16 / clockCyclesPerMicrosecond());
I think it will work for 16MHz and 1MHz but it will probably not work for 8MHz. But, I'll certainly try it.
The original code was never intended to produce frequencies below 123 Hz, because @16MHz, the 16 bit timers (set at ck/1) could not kill enough time to produce tones lower than that.
Thus, I've rewritten the code to accommodate almost all frequencies now on the 16 bit timers (2 -> 65535 Hz). 8 Bit timers will still choke, but now at 31 Hz.
Thanks bhagman and mem! I should have time tonight for some testing.
[edit]The results seem to be the same. At 8MHz NOTE_B2 is lower than at 16MHz. At 1MHz NOTE_B2 is even lower. I suspect I need to sleep on it... Good night to all! (or morning or afternoon to those not in America)[/edit]
Hi, i try, this and it seems that i can only have 2 tone?
the third one does not run?
i have a atmega 328 and it should give me 3 tone (at least this is what i anderstand in the .cpp and .h
am i wrong?
Thanks
Patgadget
#include <Tone.h>
Tone tone1;
Tone tone2;
Tone tone3;
void setup()
{
tone1.begin(13);
tone2.begin(12);
tone3.begin(6);
tone3.play(100);
tone1.play(35);
tone2.play(35);
}
void loop()
{
}
Patgadget: Silly boundary conditions. Amazing what a difference >= makes compared to >. Fixed. Get the latest version from Google Code SVN. Thanks for finding it.
Coding Badly: hmmm... methinks you have something else going on. Are you compiling the sketches against F_CPU set to 1MHz? Or are you just compiling based on an Duemilanove w/ATmega32 (@16 MHz) and putting it into a chip running at 1MHz? I'm betting dollars to donuts that you're doing the latter.