Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * Keyboard Piano
- * Mark Mouritsen
- * u0606723
- * Last revised 05/06/2015
- *
- * Current version uses keys 1234567890-=ASDFGHJKL;'(BLACK KEYS) QWERTYUIOP[]|ZXCVBNM<>/(WHITE KEYS) for the piano and the UP, DOWN, LEFT and RIGHT arrow keys to change the notes.
- *
- *
- * This program has 4 functions (and one helper function):
- * - setup: intialize everything
- * - loop: constantly read data and parse complete data
- * - blink: interrupt that begins moving data from the data line into the data variable
- * on the negative edge of the input clock from the keyboard
- * - getNote: converts data from keyboard into a note number which note can be retrieved from an array
- *
- * The program ultimately reads data from the keyboard, triggering the read via interrupt on the negative edge of the clock.
- * The data is then parsed and the program sends a clock frequency to the output pin based on keys pressed. The frequency is
- * no longer driven once all recognized note keys have been released.
- *
- * The program is compiled in Energia and run with the MSP-EXP430G2 Evaluation board on a MSP430G2553 MCU.
- */
- // Constants
- const int dataPin = 6; // P1.4
- const int clkPin = 7; // P1.5
- const int soundPin = 11; // P1.6 (on MSP430G2553, it would be GND on 14 pin models)
- int soundOut = 0; // Which pin to output the next note onto, this is a rolling value
- int soundMax = 2; // Max output pins (+1), hardware forces a max of 3 different clock outputs
- int last[3]; // Keeps track of which notes are playing
- // Variables used by interrupts:
- volatile int done = LOW; // Signals main program that reading is done
- volatile int bit_count = -1; // Keeps track of which bit is being read
- volatile int data = 0; // The data coming from dataPin (the keyboard)
- volatile int kbd_data = 0; // Complete data stored as captured from the dataPin
- // Variables
- int release = LOW; // Signals when a button release has occured
- int kbd_data_ = 0; // Stores kbd_data so corruption doesn't occur from a following interrupt
- int modi = 3; // Which octave we are on (+1, i.e: modi 3 is 4th octave)
- int lo_m = 0; // Modifier for the lower keys
- int hi_m = 0; // Modifier for the upper keys
- int shift = 0; // 0 = Shift key up, 1 = Shift key down
- int note = -1; // The note being played, -1 = Not recognized
- // Data queue
- const int data_max = 9; // Queue size (needs to be something that our program can keep up with so we don't overwrite values in the queue, 0-3 should be more than enough though since the keyboard's clock is 16khz and the MSP430G2553 is 16Mhz)
- int data_in[data_max + 1]; // Queue array
- int data_read = 0; // Read pointer
- int data_write = 0; // Write pointer
- // Notes array
- const int white[53] = {-1,31,33,37,41,44,49,55,62,65,73,82,87,98,110,123,131,147,165,175,196,220,247,262,294,330,349,392,440,494,523,587,659,698,784,880,988,1047,1175,1319,1397,1568,1760,1976,2093,2349,2637,2794,3136,3520,3951,4186,4699};
- const int black[53] = {-1,-1,35,39,-1,46,52,58,-1,69,78,-1,93,104,117,-1,139,156,-1,185,208,233,-1,277,311,-1,370,415,466,-1,554,622,-1,740,831,932,-1,1109,1245,-1,1480,1661,1865,-1,2217,2489,-1,2960,3322,3729,-1,4435,4978};
- //const int notes[89] = {31,33,35,37,39,41,44,46,49,52,55,58,62,65,69,73,78,82,87,93,98,104,110,117,123,131,139,147,156,165,175,185,196,208,220,233,247,262,277,294,311,330,349,370,392,415,440,466,494,523,554,587,622,659,698,740,784,831,880,932,988,1047,1109,1175,1245,1319,1397,1480,1568,1661,1760,1865,1976,2093,2217,2349,2489,2637,2794,2960,3136,3322,3520,3729,3951,4186,4435,4699,4978};
- /*
- * Init
- */
- void setup()
- {
- //Initialize serial and wait for port to open:
- //Serial.begin(9600);
- // Enable the red LED and turn it off until setup is done
- pinMode(2, OUTPUT);
- digitalWrite(2, LOW);
- // Enable internal pullup for CLK and DATA lines
- pinMode(clkPin, INPUT_PULLUP);
- pinMode(dataPin, INPUT_PULLUP);
- // Enable the output pins and turn them off
- for (int i = 0; i <= soundMax; i++) {
- pinMode(soundPin + i, OUTPUT);
- analogWrite(soundPin + i, 0);
- last[i] = -1;
- }
- // Disable interrupts during setup (so keyboard does not trigger anything)
- noInterrupts();
- // Interrupt is fired whenever CLK falls
- attachInterrupt(clkPin, blink, FALLING);
- // Re-enable interrupts
- interrupts();
- // Setup complete, turn red light on
- digitalWrite(2, HIGH);
- }
- /*
- * Main Loop
- */
- void loop()
- {
- // Store the current DATA state into our data variable
- data = digitalRead(dataPin);
- /* If the interrupt has finished reading (after 11 bits)
- * print out the code that was read */
- if (done == HIGH) {
- // Set done to LOW so we can read more incoming data
- done = LOW;
- // Store kbd_data into a new variable so it isn't corrupted while we use it
- kbd_data_ = data_in[data_read];
- data_read++;
- // DEBUG - Print data
- //Serial.println(kbd_data_);
- if (data_read > data_max)
- data_read = 0;
- // Next input will be a release
- if (kbd_data_ == 240) {
- release = HIGH;
- // Release arrived
- } else if (release == HIGH) {
- release = LOW; // Reset the relase
- switch (kbd_data_) {
- // Modifiers UP & DOWN modify the upper keys, LEFT & RIGHT modify the lower keys
- case 117: //UP
- hi_m++;
- break;
- case 114: //DOWN
- hi_m--;
- break;
- case 107: //LEFT
- lo_m--;
- break;
- case 116: //RIGHT
- lo_m++;
- break;
- }
- // Get the note
- note = getNote(kbd_data_);
- // If the note is recognized
- if (note != 0)
- {
- // Get which of the notes was playing and turn it off
- // If none of the last 3 notes were what was released, do nothing
- int store = soundOut; // In case we need to restore it later
- for (int i = 0; i <= soundMax; i++) {
- // If this was the note released, set soundOut to this
- if (note == last[i]) {
- soundOut = i;
- break;
- }
- // Otherwise, the note released wasn't in the array
- if (i == soundMax)
- soundOut = -1;
- }
- // Remove the tone being played from the specific pin
- if (soundOut >= 0) {
- last[soundOut] = -1;
- noTone(soundPin + soundOut);
- }
- // If we released a note that is not in our array, reset the soundOut position
- else
- soundOut = store;
- }
- } else {
- // Get the note based on which key was pressed
- note = getNote(kbd_data_);
- // If a recognized note was played...
- if (note != 0) {
- // Play the note
- // ...If it's not already being played
- if (soundOut <= soundMax && !contains(note, last, soundMax + 1)) {
- // Store the note so we can check it for release later
- last[soundOut] = note;
- // Check if it was a black key
- if (note < 0) {
- if (black[note * -1] > 0)
- tone(soundPin + soundOut++, black[note * -1]);
- }
- // Or white key
- else
- tone(soundPin + soundOut++, white[note]);
- // Roll our array counter over if we get greater than our max # of pins
- if (soundOut > soundMax)
- soundOut = 0;
- }
- }
- }
- }
- // Finish input parse
- }
- /*
- * contains - Returns a true or false based on
- * whether or not the given array arr contains
- * the given value val
- */
- boolean contains(int val, int *arr, int size){
- int i;
- for (i=0; i < size; i++) {
- if (arr[i] == val)
- return true;
- }
- return false;
- }
- /*
- * blink - Captures any bits sent along the data
- * line while the clock is active and stores them
- * into kbd_data
- */
- void blink()
- {
- // bit_count will be '-1' if we're beginning the read
- if (bit_count < 0) {
- bit_count = 0;
- kbd_data = 0;
- // bit_count will be between 0 and 7 during the read
- } else if (bit_count < 8) {
- // If the data line is high, store a 1 at the current bit position
- if (data == HIGH) {
- kbd_data |= (1<<bit_count);
- }
- // Increment bit_count
- bit_count++;
- // The last bit will be a parity bit (we will ignore these for now)
- } else if (bit_count == 8) {
- // Increment bit_count
- bit_count++;
- // After the parity bit we will have our stop bit
- } else {
- // Reset the bit_count
- bit_count = -1;
- // Set done high to let the main loop know we're ready to print the value
- done = HIGH;
- data_in[data_write] = kbd_data;
- data_write++;
- if (data_write > data_max)
- data_write = 0;
- }
- // Return from the interrupt
- return;
- }
- /*
- * Returns a note value (that can be used in the
- * note array to get a specific clock frequency)
- * based on the key pressed and modifiers used
- */
- int getNote(int in)
- {
- int ret = 0; // The return value
- int bar = 0; // Used to increase or decrease by an additional octave
- int color = 1;
- boolean low = false;
- switch (in) {
- // Notes QWERTYUIOP[]|
- case 21: //Q
- ret = 5;
- bar = -1;
- break;
- case 29: //W
- ret = 6;
- bar = -1;
- break;
- case 36: //E
- ret = 7;
- bar = -1;
- break;
- case 45: //R
- ret = 1;
- break;
- case 44: //T
- ret = 2;
- break;
- case 53: //Y
- ret = 3;
- break;
- case 60: //U
- ret = 4;
- break;
- case 67: //I
- ret = 5;
- break;
- case 68: //O
- ret = 6;
- break;
- case 77: //P
- ret = 7;
- break;
- case 84: //[
- ret = 1;
- bar = 1;
- break;
- case 91: //]
- ret = 2;
- bar = 1;
- break;
- case 93:
- ret = 3;
- bar = 1;
- break;
- // Notes 1234567890-=
- case 22: //1
- ret = 4;
- bar = -1;
- color = -1;
- break;
- case 30: //2
- ret = 5;
- bar = -1;
- color = -1;
- break;
- case 38: //3
- ret = 6;
- bar = -1;
- color = -1;
- break;
- case 37: //4
- ret = 7;
- bar = -1;
- color = -1;
- break;
- case 46: //5
- ret = 1;
- bar = 0;
- color = -1;
- break;
- case 54: //6
- ret = 2;
- bar = 0;
- color = -1;
- break;
- case 61: //7
- ret = 3;
- bar = 0;
- color = -1;
- break;
- case 62: //8
- ret = 4;
- bar = 0;
- color = -1;
- break;
- case 70: //9
- ret = 5;
- bar = 0;
- color = -1;
- break;
- case 69: //0
- ret = 6;
- bar = 0;
- color = -1;
- break;
- case 78: //-
- ret = 7 ;
- bar = 0;
- color = -1;
- break;
- case 85: //=
- ret = 1;
- bar = 1;
- color = -1;
- break;
- // Keys ASDFGHJKL;'
- case 28: //a
- ret = 1;
- bar = -2;
- low = true;
- color = -1;
- break;
- case 27: //s
- ret = 2;
- bar = -2;
- low = true;
- color = -1;
- break;
- case 35: //d
- ret = 3;
- bar = -2;
- low = true;
- color = -1;
- break;
- case 43: //f
- ret = 4;
- bar = -2;
- low = true;
- color = -1;
- break;
- case 52: //g
- ret = 5;
- bar = -2;
- low = true;
- color = -1;
- break;
- case 51: //h
- ret = 6;
- bar = -2;
- low = true;
- color = -1;
- break;
- case 59: //j
- ret = 7;
- bar = -2;
- low = true;
- color = -1;
- break;
- case 66: //k
- ret = 1;
- bar = -1;
- low = true;
- color = -1;
- break;
- case 75: //l
- ret = 2;
- bar = -1;
- low = true;
- color = -1;
- break;
- case 76: //;
- ret = 3;
- bar = -1;
- low = true;
- color = -1;
- break;
- case 82: //'
- ret = 4;
- bar = -1;
- low = true;
- color = -1;
- break;
- // Keys ZXCVBNM,./
- case 26: //z
- ret = 2;
- bar = -2;
- low = true;
- break;
- case 34: //x
- ret = 3;
- bar = -2;
- low = true;
- break;
- case 33: //c
- ret = 4;
- bar = -2;
- low = true;
- break;
- case 42: //v
- ret = 5;
- bar = -2;
- low = true;
- break;
- case 50: //b
- ret = 6;
- bar = -2;
- low = true;
- break;
- case 49: //n
- ret = 7;
- bar = -2;
- low = true;
- break;
- case 58: //m
- ret = 1;
- bar = -1;
- low = true;
- break;
- case 65: //,
- ret = 2;
- bar = -1;
- low = true;
- break;
- case 73: //.
- ret = 3;
- bar = -1;
- low = true;
- break;
- case 74: ///
- ret = 4;
- bar = -1;
- low = true;
- break;
- default:
- return 0;
- break;
- }
- if (modi + bar > 6 || modi + bar < 0)
- return 0;
- if (low)
- return ((ret + (7 * (modi + bar)) + 1 - lo_m) * color);
- return ((ret + (7 * (modi + bar)) + 1 - hi_m) * color);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement