The following code can be copied-and-pasted into a new project window in the Arduino IDE.

From the Tools→Board menu, select Adafruit Trinket 8 MHz (3.3V or 5V boards) or Trinket 16 MHz (5V board only). Connect the USB cable between the computer and Trinket, press the reset button on the board, then click the upload button (right arrow icon) in the Arduino IDE.

If you get an error message (or a huge list of them), it’s usually one of the following:

  • Is the Arduino IDE properly configured for Trinket use? Try compiling and uploading a simple sketch (like the Blink example, set for pin #1). From the Tools→Programmer menu, “USBtinyISP” should be selected.
  • Are the libraries properly installed? They must be correctly named and in the right location. If you already had one or more of these libraries previously installed, download the latest versions — some changes may have been made specifically for Trinket. (Same goes for Boards manager support…a recent change for Trinket removed the need for a separate TinyWireM library, so make sure the board definitions are current.)
  • If the code compiles but doesn’t upload, press the reset button and try again.
  Tap tempo sketch for Adafruit Trinket.  Tap a button in sync with
  a beat, LED display shows beats per minute.  Stop tapping for
  4 second to reset counter.

  Required libraries include Adafruit_LEDBackpack and Adafruit_GFX.

  Required hardware includes an Adafruit Trinket microcontroller
  (5V or 3.3V), an Adafruit 7-Segment LED Backpack, and a momentary,
  normally-open pushbutton.

  As written, this is specifically for the Trinket; would need
  modifications on other boards (Arduino Uno, etc.).

  Trinket :   5V/3V   Gnd   Pin #0   Pin #2
  Backpack:     +      -      D        C

  Pushbutton between Pin #1 and 5V/3V.

#include <Wire.h>
#include <Adafruit_LEDBackpack.h>
#include <Adafruit_GFX.h>
#include <avr/power.h>

Adafruit_7segment disp = Adafruit_7segment();

unsigned long
  prevBeat = 0L, // Time of last button tap
  sum      = 0L; // Cumulative time of all beats
  nBeats   = 0;  // Number of beats counted
  prevButton;    // Value of last digitalRead()

void setup() {
  if(F_CPU == 16000000) clock_prescale_set(clock_div_1);
  prevButton = digitalRead(1);

static unsigned long debounce() { // Waits for change in button state
  uint8_t       b;
  unsigned long start, last;
  long          d;

  start = micros();

  for(;;) {
    last = micros();
    while((b = digitalRead(1)) != prevButton) { // Button changed?
      if((micros() - last) > 25000L) {          // Sustained > 25 mS?
        prevButton = b;                         // Save new state
        return last;                            // Return time of change
    } // Else button other things...

    d = (last - start) - 4000000L; // Function start time minus 4 sec
    if(d > 0) {                    // > 4 sec with no button change?
      nBeats = 0;                  // Reset counters
      prevBeat = sum = 0L;

    // If no prior tap has been registered, program is waiting
    // for initial tap.  Show instructions on display.
    if(!prevBeat) {
      if(!(d & 0x00100000)) { // ~1.05 second cycle
        disp.writeDigitRaw(0, 0x78); // t
        disp.writeDigitRaw(1, 0x77); // A
        disp.writeDigitRaw(3, 0x73); // P
        disp.writeDigitRaw(4, 0x00);
      } else {
        disp.writeDigitRaw(0, 0x7C); // b
        disp.writeDigitRaw(1, 0x79); // E
        disp.writeDigitRaw(3, 0x77); // A
        disp.writeDigitRaw(4, 0x78); // t

void loop() {
  unsigned long t;
  uint16_t      b;

  t = debounce(); // Wait for new button state

  if(prevButton == HIGH) {             // Low-to-high (button tap)?
    if(prevBeat) {                     // Button tapped before?
      sum += 600000000L / (t - prevBeat); // BPM * 10
      b    = (sum / nBeats);           // Average time per tap
      if(b > 9999) b = 9999;
      disp.writeDigitNum(3, (b/10)%10, true); // .
    } else {                           // First tap
      disp.clear();                    // Clear display, but...
      disp.writeDigitRaw(3, 0x80);     // a dot shows it's on
    prevBeat = t;                      // Record time of last tap
There’s not much to it! This is the sort of project where Trinket really shines…a small, focused project where a full-blown Arduino would just be wasted potential.

The largest section of the code (aside from the comments up top) is simply to flash "TAP BEAT" at startup. Button input is debounced, time between button taps is then calculated using the micros() timer, and BPM is figured by dividing 600,000,000 (10X the number of microseconds in 1 minute) by this time interval. The 10X figure is just so we can look extra geeky by then adding a decimal point.

This guide was first published on Sep 07, 2013. It was last updated on Sep 07, 2013.

This page (Code) was last updated on Sep 06, 2013.

Text editor powered by tinymce.