SIK Keyboard Instrument

Pages
Contributors: Shawn Hymel
Favorited Favorite 5

The Code

To program the Arduino from your browser, select SparkFun RedBoard in the first drop-down menu in the window below, select the COM port associated with your RedBoard, and click Run on Arduino.

Note: This example assumes you are using the latest version of the Arduino IDE on your desktop. If this is your first time using Arduino, please review our tutorial on installing the Arduino IDE.

If you have not previously installed an Arduino library, please check out our installation guide.

Copy the following code into the editor and click the Upload button.

language:c
/**
 * SparkFun Inventor's Kit Project
 * Keyboard Instrument
 * Date: March 29, 2016
 * 
 * Description:
 *  Use the soft touch potentiometer as a keyboard segmented into
 *  8 keys: C, D, E, F, G, A, B, C. When each key is pressed, the 
 *  corresponding note is played through a buzzer.
 * 
 * Hardware Connections:
 *  Arduino | Soft Pot | Buzzer
 *  ---------------------------
 *    5V    |   pin 3  |   
 *    A0    |   pin 2  |   
 *    GND   |   pin 1  |   
 *    9     |          |   +
 *    GND   |          |   -
 *    
 *  You will also need to attach a 10k resistor from pin 2 to
 *  pin 1 (GND) on the soft pot.
 *  
 * License:
 *  Public Domain
 */

// Constants
const int SENSOR_PIN = 0;   // Analog input pin for soft pot
const int BUZZER_PIN = 9;   // PWM digital output pin for buzzer
const int DURATION = 10;    // Time (ms) to play a note

// This function is run only once as soon as the Arduino boots
void setup() 
{

  // Set the buzzer pin as an output
  pinMode(BUZZER_PIN, OUTPUT);
}

// This gets run over and over right after the setup() function
void loop() 
{
  int sensorValue;
  char note = 0;
  int freq;

  // Read the value (0 - 1023) from the ADC
  sensorValue = analogRead(SENSOR_PIN);

  // Map the key pressed to a note
  note = findNote(sensorValue);

  // If it's a note, play it!
  if ( note != 0 ) {
    freq = getFrequency(note);
    tone(BUZZER_PIN, freq, DURATION);
    delay(DURATION);
  }
}

// Given an ADC value (0 - 1023), map it to a note
char findNote(int val)
{

  // Return the note based on the key pressed
  if ( (val > 10) && (val <= 160) )
  {
    return 'c';
  }
  if ( (val > 160) && (val <= 250) )
  {
    return 'd';
  }
  if ( (val > 250) && (val <= 350) )
  {
    return 'e';
  }
  if ( (val > 350) && (val <= 450) )
  {
    return 'f';
  }
  if ( (val > 450) && (val <= 560) )
  {
    return 'g';
  }
  if ( (val > 560) && (val <= 690) )
  {
    return 'a';
  }
  if ( (val > 690) && (val <= 850) )
  {
    return 'b';
  }
  if ( (val > 850) && (val <= 1023) )
  {
    return 'C';
  }

  // Return 0 to show that no key was pressed
  return 0;
}

// Translate a note (a, b, c, d, e, f, g) to its frequency
int getFrequency(char note) 
{
  int i;
  const int numNotes = 8;  // number of notes we're storing

  // Arrays containing our notes and frequencies
  char names[] = { 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'C' };
  int frequencies[] = {262, 294, 330, 349, 392, 440, 494, 523};

  // Step though the notes
  for (i = 0; i < numNotes; i++)  // Step through the notes
  {

    // If it matches a note in our list, return the frequency
    if (names[i] == note)
    {
      return(frequencies[i]);
    }
  }

  // If we looked through everything and didn't find a note,
  // return 0, as we still need to return something.
  return(0);
}

Code to Note

We combine the code from Part 10: Reading a Soft Potentiometer and Part 11: Using a Piezo Buzzer in the SIK Guide, and we recommend you read the "Code to Note" sections in each of those to understand how we are getting data from the soft pot as well as playing particular frequencies on the buzzer.

language:c
if ( (val > 10) && (val <= 160) )
{
    return 'c';
}
...

We pass the findNote(int val) function the analog-to-digital (ADC) value read from the soft pot. This information is stored in the val parameter. If we touch the soft pot towards the breadboard end, it will produce a lower value than if we touched it at the other end. The ADC value on the Arduino can be between 0 and 1023 (inclusive). So, we would read a value close to 10 if we touched it on the breadboard end and a value close to 1023 on the other end.

Since we divided up the soft pot's length into 6 mm segments, we also need to divide up the values we might receive from the soft pot. Let's say we touched the soft pot on the third segment (the one we labeled "E"), and the ADC value was 296 as a result. The first two if statements would return false, but the third one would be true, since 296 falls between 250 and 350. So, 'e' is returned as the note we pressed on the soft pot.