Coding Circuit Playground

Prep the Circuit Playground

Before you get started, make sure you've been through the basic tutorials on using the Circuit Playground. You'll need to have installed the Arduino IDE, added the Circuit Playground board to Arduino, and added the Circuit Playground library. This excellent guide, Introducing Circuit Playground and Circuit Playground lesson #0 will show you how to do all of that and get you going.

If you are using the Circuit Playground Express, be sure to check out the next page of the guide to see how to program the Freefall Deck using MakeCode

Plug your Circuit Playground into your computer now, and launch the Arduino IDE. Double check that you've selected the board and port as in the Lesson #0 tutorial and are ready to upload code.

Freefall Deck Logic

The Freefall Deck sketch is quite simple, it can only do two things: check the state of it's accelerometer, and beep a pre-coded Morse message when the accelerometer reaches a state of freefall.

 

Download: file
//Circuit Playground Freefall Deck
//created by John Park for Adafruit Industries
//a sealed deck of cards is tossed in the air or dropped, at which point it reveals a Morse code message
//Freefall detection by Phil Burgess
//Morse table by Usman Muzaffar
////////////////////////////////////////
#include "Adafruit_CircuitPlayground.h"

volatile boolean interruptHappened = false;
//*******************************************************//
//Morse code playback variables
//Adjust PITCH to your liking and DOT for speed faster/slower 
const int PITCH = 600; // Morse code audio is sent at 600-800 Hz. 680 is quite nice
const int DOT = 200;   //time duration in millis, change this to adjust transmission speed

const int DASH = 3 * DOT; //Morse standard dash is 3x longer than dot
const int GAP = DOT; //Morse inter-element gap within a character is same length as dot
const int INTER_LETTER = 3 * DOT; //Morse short gap between letters is 3x dot length
const int INTER_WORD = 7 * DOT; //Morse medium gap between words is 7x dot length
//*******************************************************//
void setup() {

  CircuitPlayground.begin();
  CircuitPlayground.strip.clear();
  CircuitPlayground.strip.show();

  // Bypass library and brute-force LIS3DH registers for freefall detect.
  // From ST App Note AN3308 w/changes to threshold & duration.
  writeReg8(LIS3DH_REG_CTRL1  , 0xA7); // Sensor on, enable X,Y,Z, 100 Hz
  writeReg8(LIS3DH_REG_CTRL2  , 0x00); // Disable high-pass filter
  writeReg8(LIS3DH_REG_CTRL3  , 0x40); // Enable I1_INT1 interrupt gen
  writeReg8(LIS3DH_REG_CTRL4  , 0x00); // 2G
  writeReg8(LIS3DH_REG_CTRL5  , 0x00); // Interrupt not latched
  writeReg8(LIS3DH_REG_INT1THS, 0x0A); // ~160 mG threshold
  writeReg8(LIS3DH_REG_INT1DUR, 0xFF); // Duration
  writeReg8(LIS3DH_REG_INT1CFG, 0x95); // Configure free-fall recognition

  pinMode(7, INPUT_PULLUP); // LIS3DH INT1 is connected to D7
  attachInterrupt(digitalPinToInterrupt(7), interruptHandler, FALLING);
}

void writeReg8(uint8_t reg, uint8_t value) {
  SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
  digitalWrite(CPLAY_LIS3DH_CS, LOW);
  SPI.transfer(reg & 0x7F);
  SPI.transfer(value);
  digitalWrite(CPLAY_LIS3DH_CS, HIGH);
  SPI.endTransaction();
}

void interruptHandler() {
  interruptHappened = true;
}

void loop() {
  if (interruptHappened) { //Accelerometer has detected free fall, do something here
    //*******************************************************//
    //Place your message here.
    //Each letter or number on one line.
    //Spaces between words are denoted with a slash / symbol.
    //Only use A-Z 0-9 
    //Other characters will cause trouble!
    
    playMorseLetter('/');//good to have a slight delay at the beginning
    
    playMorseLetter('O');
    playMorseLetter('N');
    playMorseLetter('/');
    playMorseLetter('P'); 
    playMorseLetter('A');
    playMorseLetter('G'); 
    playMorseLetter('E');
    playMorseLetter('/'); 
    playMorseLetter('X');

    //*******************************************************//
    interruptHappened = false;
  }
}

void playMorseLetter(char letter) {
  // Morse table by Usman Muzaffar
  // Adapted from: http://stackoverflow.com/a/28058216
  // Define two tables of strings one for letters and one for numbers,
  // that return the Morse encoding. By using two separate tables, we
  // can just offset the ASCII value of either a number or letter as
  // the index to look up the Morse encoding.
  static const char *ALPHA_TABLE[] = {
    ".-",   //A
    "-...", //B
    "-.-.", //C
    "-..",  //D
    ".",    //E
    "..-.", //F
    "--.",  //G
    "....", //H
    "..",   //I
    ".---", //J
    "-.-",  //K
    ".-..", //L
    "--",   //M
    "-.",   //N
    "---",  //O
    ".--.", //P
    "--.-", //Q
    ".-.",  //R
    "...",  //S
    "-",    //T
    "..-",  //U
    "...-", //V
    ".--",  //W
    "-..-", //X
    "-.--", //Y
    "--..", //Z
  };
  static const char *NUM_TABLE[] = {
    "-----", //0
    ".----", //1
    "..---", //2
    "...--", //3
    "....-", //4
    ".....", //5
    "-....", //6
    "--...", //7
    "---..", //8
    "----.", //9
  };
    if(letter == '/'){// use "/" as space between words
        delay(INTER_WORD);
        return;
    }

    // Look up the morseCode string for this letter
    // by finding the right table.

    char* morseCode;
    if (isalpha(letter)) {
        morseCode = ALPHA_TABLE[letter - 'A'];
    } else {
        morseCode = NUM_TABLE[letter - '0'];
    }

    for (int i = 0; i < strlen(morseCode); i++){
        int duration = morseCode[i] == '-' ? DASH : DOT;
        CircuitPlayground.playTone(PITCH, duration);
        delay(GAP);
    }
    delay(INTER_LETTER);
}

Download the Code

You can click "Copy Code" in the code above, then paste it into a new sketch in Arduino. Save the file as CircuitPlaygroundFreefallDeck.ino in your Arduino sketch directory, then upload it to your Circuit Playground.

To test it out, drop the powered Circuit Playground from one hand to another. Thanks to the physics and programming prowess of our own Phil Burgess, the Circuit Playground will detect a state of freefall and begin beeping the coded message.

Adjust the Code

If you'd like to change the message, look for this section in the code:

Download: file
    //*******************************************************//
    //Place your message here.
    //Each letter or number on one line.
    //Spaces between words are denoted with a slash / symbol.
    //Only use A-Z 0-9 
    //Other characters will cause trouble!
    
    playMorseLetter('/');//good to have a slight delay at the beginning
    
    playMorseLetter('O');
    playMorseLetter('N');
    playMorseLetter('/');
    playMorseLetter('P'); 
    playMorseLetter('A');
    playMorseLetter('G'); 
    playMorseLetter('E');
    playMorseLetter('/'); 
    playMorseLetter('X');

    //*******************************************************//
    

Place any message you like by replacing the letters in the single quotes on each line with letters A-Z or numbers 0-9. Use a slash / symbol to represent the spaces between words.

Morse code follows conventions on timing for the lengths of dots and dashes, spaces between elements, spaces between letters, and spaces between words. These are represented in the code above.

It's a good idea to keep your messages short and easy to transcribe. One thing you may want to adjust is the speed of the message transmission. Do this by changing the variable DOT in the code. It is currently set to 200 milliseconds, a fairly moderate rate, but you can certainly increase that number to slow things down further.

This guide was first published on Jan 15, 2017. It was last updated on Jan 15, 2017. This page (Coding Circuit Playground) was last updated on Nov 30, 2019.