For playing around with digital and analog output, I built a metronome with an LED. A servo sweeps the needle back and forth at the set tempo. The LED blinks in sync with the servo motion. A potentiometer acts as a dial controlling the tempo, from 40 BPM up to 168 BPM. I wanted to have a power of 2 as the number of possible gradations on the dial, in order to make the math accurate when using `int` variables. 40 BPM is a common lower bound for a metronome. 40 + 256 would be 296, a very fast tempo that the servo might not keep up with. So I chose 128 gradations, giving a range from 40 to 168.

### Code

``````#include <Servo.h>

const int POT_PIN = A0;
const int SERVO_PIN = 6;
const int LED_PIN = 7;

const int MIN_BPM = 40; // A common lower bound for metronomes
const int MAX_BPM = 168; // Adding a power of two so that the math is accurate (potentiometer input has 1024 possible values)
const int MAX_ANGLE = 61; // Min angle is 1 degree, and I want 60 degrees of precision
const int LED_TICK_MS = 100; // How long (in milliseconds) the lED will flash for

int freq_bpm; // Current metronome frequency (beats per minute)
bool left_side = true; // Whether the servo should tick to the left (true) or to the right (false)

Servo servo;

void setup() {
pinMode(POT_PIN, INPUT);
pinMode(LED_PIN, OUTPUT);
servo.attach(SERVO_PIN);
Serial.begin(9600);
}

void loop() {
const unsigned long int loopStart_ms = millis(); // For accuracy of delay(...), track millis spent in executing loop()

freq_bpm = MIN_BPM + analogRead(POT_PIN) / 8; // 1024 possible input values, 128 possible bpms.
Serial.println(freq_bpm);

// Move servo
int angleFromCenter = map(freq_bpm, MIN_BPM, MAX_BPM, MAX_ANGLE, 1); // Notice that angle is smaller when bpm is faster
int angle = left_side ? (90 - angleFromCenter) : (90 + angleFromCenter);
servo.write(angle);
left_side = !left_side;

// Flash LED
digitalWrite(LED_PIN, HIGH);
delay(LED_TICK_MS);
digitalWrite(LED_PIN, LOW);

int interval_ms = 60000 / freq_bpm; // Do the unit analysis, this will be the equation you get.
delay(interval_ms - (millis() - loopStart_ms)); // I've done the math - given our max BPM, interval_ms will always be greater than LED_TICK_MS
}
``````

The tricky part of coding was getting the timing right. At first, my metronome would stop after about a minute, because I didn't realize that on the arduino platform, `int` is 16-bit by default. `millis()` actually returns an unsigned long integer, but I had been implicitly casting that into a signed 16-bit integer. It would wrap around from ~31000 ms to ~-32000 ms, breaking my delay interval. I'm used to `int` being 32-bit by default.