Okay, I'll let you in on a secret... The Public Radio is a mechanically tuned device. Sssshhhhhhhh.
For a number of reasons, cost and ease of build/debugging being most important, the Public Radio went from a fully digital device with a small amount of firmware, to a digital IC that requires mechanical (read using a screw driver) tuning. It's not a huge pain, but there's an important catch in producing this device, which the main selling point remember, is that it's pre-tuned: you have to be able to always measure it's tuning frequency. Typically this is easy, you just tune it and verify by listening that you're on the right station. However, it get's a little trickier when the station doesn't exist locally, because you have no reference as to which station your listening, or not listening, to.
There are FM transmitters, like the kind we used to use in the early iPod days that broadcast on an open frequency band over the car's radio and these are helpful to have though they can be problematic in a major city like NYC where there are a lot of FM stations and not a lot of space on the air. So, what to do when you need to tune your Public Radio and there's no UI on the device, or simply a reference station to listen to.
Unfortunately, the FM IC we're using doesn't offer up any tuning information in the form of a station id that it can send to a microcontroller, to confirm the station it thinks it's tuned to. So this afternoon, in anticipation for our REV 3 boards showing up later this week, I put together a quick tuning calibration sketch with an Arduino - mapping the radio's varying voltages on its tune pins, to FM stations. It seems pretty accurate, and precise to within 20Khz, which is a good start.
We're open source on github. So, here's this too.
/*
A tuning routine for the Public Radio to test for station freqs, by Zach Dunham.
Averaging function from Tom Igoe at http://arduino.cc/en/Tutorial/Smoothing
www.thepublicrad.io
***steps***
connect A0 to tuning pot, center pin 2
connect grounds
connect radio pwr to 3.3V
run sketch, open serial monitor and tune until the appropriate station
appears in the serial monitor
*/
const int numReadings = 5; // number of readings, indices for the averaging array
float readings[numReadings]; // the readings from the analog input
int index = 0; // the index of the current reading
float total = 0; // the running total
float average = 0; // the average
int PotPin2 = A0; //input from the radio, wiper of the tune pot
float tune = 0.00; //variable for station id
void setup() {
for (int thisReading = 0; thisReading < numReadings; thisReading++)
readings[thisReading] = 0;
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
}
// the loop routine runs over and over again forever:
void loop() {
// read the input on analog pin 0:
tune = analogRead(PotPin2); //read the pot value
tune = constrain(tune, 0.0, 212.0); //constrain it's range
tune = mapfloat(tune, 0.0, 212.0, 86.33, 108.43); //map the potpin2 readings into the FM range with floats
tune = averagestation(tune); //smooth the readings with the average function
Serial.println(tune); // print the station
delay(100);
}
//maps from floating point number to floating point number
float mapfloat(float x, float in_min, float in_max, float out_min, float out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
//taken from the great, Tom Igoe!
//this averages the readings to help smooth data in the serial monitor
float averagestation(float tune){
// subtract the last reading:
total= total - readings[index];
// read from the sensor:
readings[index] = tune;
// add the reading to the total:
total= total + readings[index];
// advance to the next position in the array:
index = index + 1;
// if we're at the end of the array...
if (index >= numReadings)
// ...wrap around to the beginning:
index = 0;
// calculate the average:
average = total / numReadings;
// send it to the computer as ASCII digits
return (average);
delay(1); // delay in between reads for stability
}