Created
January 3, 2013 16:11
-
-
Save davidcool/4444564 to your computer and use it in GitHub Desktop.
This worked fine the first couple of times and now it's dead. Trying to figure out what the conflict is here.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//single pixel sound sketch | |
//by David Cool 2012 | |
//http://davidcool.com/ | |
//This is a merge of the two programs credited below to work with the MPU6050 IMU | |
//accelerometer test- single pixel | |
//by Amanda Ghassaei 2012 | |
//http://www.instructables.com/id/Use-an-Accelerometer-and-Gyroscope-with-Arduino/ | |
/* | |
* This program is free software; you can redistribute it and/or modify | |
* it under the terms of the GNU General Public License as published by | |
* the Free Software Foundation; either version 2 of the License, or | |
* (at your option) any later version. | |
* | |
*/ | |
// I2C device class (I2Cdev) demonstration Arduino sketch for MPU6050 class | |
// 10/7/2011 by Jeff Rowberg <jeff@rowberg.net> | |
// Updates should (hopefully) always be available at https://github.com/jrowberg/i2cdevlib | |
// | |
// Changelog: | |
// 2011-10-07 - initial release | |
/* ============================================ | |
I2Cdev device library code is placed under the MIT license | |
Copyright (c) 2011 Jeff Rowberg | |
Permission is hereby granted, free of charge, to any person obtaining a copy | |
of this software and associated documentation files (the "Software"), to deal | |
in the Software without restriction, including without limitation the rights | |
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
copies of the Software, and to permit persons to whom the Software is | |
furnished to do so, subject to the following conditions: | |
The above copyright notice and this permission notice shall be included in | |
all copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
THE SOFTWARE. | |
=============================================== | |
*/ | |
// Arduino Wire library is required if I2Cdev I2CDEV_ARDUINO_WIRE implementation | |
// is used in I2Cdev.h | |
#include "Wire.h" | |
// I2Cdev and MPU6050 must be installed as libraries, or else the .cpp/.h files | |
// for both classes must be in the include path of your project | |
#include "I2Cdev.h" | |
#include "MPU6050.h" | |
// class default I2C address is 0x68 | |
// specific I2C addresses may be passed as a parameter here | |
// AD0 low = 0x68 (default for InvenSense evaluation board) | |
// AD0 high = 0x69 | |
MPU6050 accelgyro; | |
int16_t ax, ay, az; | |
int16_t gx, gy, gz; | |
//pin connections | |
#define ledLatchPin 43 | |
#define ledClockPin 44 | |
#define ledDataPin 42 | |
#define buttonLatchPin 45 | |
#define buttonClockPin 46 | |
#define buttonDataPin 47 | |
//setup varibles for Gyroscope/Accelerometer | |
int xGyroRAW; | |
int yGyroRAW; | |
int xAccRAW; | |
int yAccRAW; | |
int zAccRAW; | |
byte xGyro; | |
byte yGyro; | |
byte xAcc; | |
byte yAcc; | |
byte zAcc; | |
//looping variables | |
byte i; | |
byte j; | |
byte k; | |
//storage for led states, 4 bytes | |
byte ledData[] = {0, 0, 0, 0}; | |
//storage for buttons, 4 bytes | |
byte buttonCurrent[] = {0,0,0,0}; | |
byte buttonLast[] = {0,0,0,0}; | |
byte buttonEvent[] = {0,0,0,0}; | |
byte buttonState[] = {0,0,0,0}; | |
//button debounce counter- 16 bytes | |
byte buttonDebounceCounter[4][4]; | |
//variables for accelerometer pixel movement | |
boolean firstPress = 1; | |
byte movingPixel[] = {0, 0, 0, 0}; | |
byte yPosition; | |
byte xPosition; | |
int timeX = 0; | |
int timeY = 0; | |
boolean dirX = 0; | |
boolean dirY = 0; | |
byte lastX = 4; | |
byte lastY = 4; | |
//MIDI variables | |
int velocity = 100; | |
int noteON = 144; | |
int MIDIoffset = 60; | |
byte currentX; | |
void setup() { | |
// join I2C bus (I2Cdev library doesn't do this automatically) | |
Wire.begin(); | |
// initialize serial communication | |
// (38400 chosen because it works as well at 8MHz as it does at 16MHz, but | |
// it's really up to you depending on your project) | |
Serial.begin(38400); | |
Serial.println("Starting up single pixel sketch!"); | |
// start serialsoftware midi communication | |
Serial1.begin(31250); | |
Serial.println("Starting MIDI @ 31250 on Serial1..."); | |
// initialize device | |
Serial.println("Initializing I2C devices..."); | |
accelgyro.initialize(); | |
// verify connection | |
Serial.println("Testing device connections..."); | |
Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed"); | |
// Amanda's setup | |
DDRL = 0xFA;//set pins D7-D4 as output, D2 as input | |
cli();//stop interrupts | |
//set timer1 interrupt at 1kHz | |
TCCR1A = 0;// set entire TCCR1A register to 0 | |
TCCR1B = 0;// same for TCCR1B | |
TCNT1 = 0;//initialize counter value to 0; | |
// set timer count for 1khz increments | |
OCR1A = 1999;// = (16*10^6) / (1000*8) - 1 | |
// turn on CTC mode | |
TCCR1B |= (1 << WGM12); | |
// Set CS11 bit for 8 prescaler | |
TCCR1B |= (1 << CS11); | |
// enable timer compare interrupt | |
TIMSK1 |= (1 << OCIE1A); | |
sei();//allow interrupts | |
} // end setup() | |
ISR(TIMER1_COMPA_vect) {//Interrupt at freq of 1kHz | |
timeX++;//increment timeX | |
timeY++;//increment timeY | |
shift();//send data to leds | |
} | |
// buttonCheck - checks the state of a given button. | |
//this buttoncheck function is largely copied from the monome 40h firmware by brian crabtree and joe lake | |
void buttonCheck(byte row, byte index) | |
{ | |
if (((buttonCurrent[row] ^ buttonLast[row]) & (1 << index)) && // if the current physical button state is different from the | |
((buttonCurrent[row] ^ buttonState[row]) & (1 << index))) { // last physical button state AND the current debounced state | |
if (buttonCurrent[row] & (1 << index)) { // if the current physical button state is depressed | |
buttonEvent[row] = 1 << index; // queue up a new button event immediately | |
buttonState[row] |= (1 << index); // and set the debounced state to down. | |
} | |
else{ | |
buttonDebounceCounter[row][index] = 12; | |
} // otherwise the button was previously depressed and now | |
// has been released so we set our debounce counter. | |
} | |
else if (((buttonCurrent[row] ^ buttonLast[row]) & (1 << index)) == 0 && // if the current physical button state is the same as | |
(buttonCurrent[row] ^ buttonState[row]) & (1 << index)) { // the last physical button state but the current physical | |
// button state is different from the current debounce | |
// state... | |
if (buttonDebounceCounter[row][index] > 0 && --buttonDebounceCounter[row][index] == 0) { // if the the debounce counter has | |
// been decremented to 0 (meaning the | |
// the button has been up for | |
// kButtonUpDefaultDebounceCount | |
// iterations/// | |
buttonEvent[row] = 1 << index; // queue up a button state change event | |
if (buttonCurrent[row] & (1 << index)){ // and toggle the buttons debounce state. | |
buttonState[row] |= (1 << index); | |
} | |
else{ | |
buttonState[row] &= ~(1 << index); | |
} | |
} | |
} | |
} | |
void shift(){ | |
for (i=0;i<4;i++){ | |
buttonLast[i] = buttonCurrent[i]; | |
byte dataToSend = (1 << (i+4)) | (15 & ~ledData[i]); | |
// set latch pin low so the LEDs don't change while sending in bits | |
PORTL&=B10111111;//digitalWrite(ledLatchPin, LOW); | |
// shift out the bits of dataToSend | |
//shiftOut(ledDataPin, ledClockPin, LSBFIRST, dataToSend); | |
for (j=0;j<8;j++){ | |
PORTL&=B11011111;//digitalWrite(ledClockPin,LOW); | |
//digitalWrite(ledDataPin,((dataToSend>>j)&1)); | |
if ((dataToSend>>j)&1){ | |
PORTL|=B10000000; | |
} | |
else{ | |
PORTL&=B01111111; | |
} | |
PORTL|=B00100000;//digitalWrite(ledClockPin,HIGH); | |
} | |
//set latch pin high so the LEDs will receive new data | |
PORTL|=B01000000;//digitalWrite(ledLatchPin, HIGH); | |
// SlowDown is put in here to waste a little time while we wait for the state of the output | |
// pins to settle. Without this time wasting loop, a single button press would show up as | |
// two presses (the button and its neighbour) | |
volatile int SlowDown = 0; | |
while (SlowDown < 15) | |
{ | |
SlowDown++; | |
} | |
//once one row has been set high, receive data from buttons | |
//set latch pin high | |
PORTL|=B00010000;//digitalWrite(buttonLatchPin, HIGH); | |
//shift in data | |
//buttonCurrent[i] = shiftIn(buttonDataPin, buttonClockPin, LSBFIRST) >> 3; | |
for (j=0;j<4;j++){ | |
PORTL&=B11110111;//digitalWrite(buttonClockPin,LOW); | |
PORTL|=B00001000;//digitalWrite(buttonClockPin,HIGH); | |
} | |
for (j=0;j<4;j++){ | |
PORTL&=B11110111;//digitalWrite(buttonClockPin,LOW); | |
if ((PIND>>2)&1){//digitalRead(buttonDataPin) | |
buttonCurrent[i]|=1<<j; | |
} | |
else{ | |
buttonCurrent[i]&=~(1<<j); | |
} | |
PORTL|=B00001000;//digitalWrite(buttonClockPin,HIGH); | |
} | |
//latchpin low | |
PORTL&=B11101111;//digitalWrite(buttonLatchPin, LOW); | |
for (k=0;k<4;k++){ | |
buttonCheck(i,k); | |
} | |
} | |
//turn off leds- this way one row does not appear brighter than the rest | |
// set latch pin low so the LEDs don't change while sending in bits | |
PORTL&=B10111111;//digitalWrite(ledLatchPin, LOW); | |
// shift out 0 | |
//shiftOut(ledDataPin, ledClockPin, LSBFIRST, 0); | |
for (j=0;j<8;j++){ | |
PORTL&=B11011111;//digitalWrite(ledClockPin,LOW); | |
PORTL&=B01111111; | |
PORTL|=B00100000;//digitalWrite(ledClockPin,HIGH); | |
} | |
//set latch pin high so the LEDs will receive new data | |
PORTL|=B01000000;//digitalWrite(ledLatchPin, HIGH); | |
} | |
void checkFirstButton(){ | |
for (byte a=0;a<4;a++){ | |
if (buttonEvent[a]){ | |
for (byte b=0;b<4;b++){ | |
if (buttonState[a]&(1<<b)){ | |
//toggle firstPress variable | |
firstPress = 0; | |
//display pressed pixel | |
ledData[a] = buttonEvent[a]; | |
//store current position | |
yPosition = a; | |
xPosition = 1<<b; | |
//reset timers | |
timeX = 0; | |
timeY = 0; | |
return; | |
} | |
} | |
} | |
} | |
} | |
byte scaleAcc(int RAW){ | |
if (RAW<=10000 && RAW>=-10000){ | |
return 5; | |
} | |
else if (RAW<-10000){ | |
if (RAW<-50000){ | |
return 0; | |
} | |
else if (RAW<-40000){ | |
return 1; | |
} | |
else if (RAW<-30000){ | |
return 2; | |
} | |
else if (RAW<-20000){ | |
return 3; | |
} | |
else{ | |
return 4; | |
} | |
} | |
else if (RAW>10000){ | |
if (RAW>50000){ | |
return 10; | |
} | |
else if (RAW>40000){ | |
return 9; | |
} | |
else if (RAW>30000){ | |
return 8; | |
} | |
else if (RAW>20000){ | |
return 7; | |
} | |
else{ | |
return 6; | |
} | |
} | |
} | |
void checkAccelerometer(){ | |
// read raw accel/gyro measurements from device | |
accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz); | |
/* | |
Serial.print("ax: "); | |
Serial.print(ax); | |
Serial.print("ay: "); | |
Serial.print(ay); | |
Serial.print("az: "); | |
Serial.print(az); | |
Serial.print("gx: "); | |
Serial.print(gx); | |
Serial.print("gy: "); | |
Serial.print(gy); | |
Serial.print("gz: "); | |
Serial.println(gz); | |
*/ | |
// these methods (and a few others) are also available | |
//accelgyro.getAcceleration(&ax, &ay, &az); | |
//accelgyro.getRotation(&gx, &gy, &gz); | |
//for now just use raw data to see what happens | |
xGyroRAW = gx; | |
yGyroRAW = gy; | |
xAccRAW = ax; | |
yAccRAW = ay; | |
zAccRAW = az; | |
if (xAccRAW>0){ | |
dirX = 1; | |
} | |
else{ | |
dirX = 0; | |
} | |
if (yAccRAW>0){ | |
dirY = 1; | |
} | |
else{ | |
dirY = 0; | |
} | |
//convert to 0-10 | |
xAcc = scaleAcc(xAccRAW); | |
yAcc = scaleAcc(yAccRAW); | |
} | |
int getTime(byte acceleration){ | |
switch (acceleration){ | |
case 0://max - acceleration | |
return 25; | |
break; | |
case 1: | |
return 25; | |
break; | |
case 2: | |
return 50; | |
break; | |
case 3: | |
return 100; | |
break; | |
case 4: | |
return 150; | |
break; | |
case 5://lying flat | |
return 0; | |
break; | |
case 6: | |
return 150; | |
break; | |
case 7: | |
return 100; | |
break; | |
case 8: | |
return 50; | |
break; | |
case 9: | |
return 25; | |
break; | |
case 10://max + acceleration | |
return 25; | |
break; | |
} | |
} | |
void moveXPixel(int timeComp){ | |
if (timeComp==0){ | |
} | |
else{ | |
if (timeX>timeComp){ | |
timeX = 0; | |
if (dirX){ | |
if (xPosition==8){ | |
} | |
else{ | |
xPosition = xPosition<<1; | |
} | |
} | |
else{ | |
if (xPosition==1){ | |
} | |
else{ | |
xPosition = xPosition>>1; | |
} | |
} | |
} | |
} | |
} | |
void moveYPixel(int timeComp){ | |
if (timeComp==0){ | |
} | |
else{ | |
if (timeY>timeComp){ | |
timeY = 0; | |
if (dirY){ | |
if (yPosition==7){ // changed to 7 to reference 4x8 board (was set at 3) | |
} | |
else{ | |
yPosition = yPosition+=1; | |
} | |
} | |
else{ | |
if (yPosition==0){ | |
} | |
else{ | |
yPosition = yPosition-=1; | |
} | |
} | |
} | |
} | |
} | |
void checkMIDI(){ | |
//convert xPosition to decimal | |
switch (xPosition){ | |
case 1: | |
currentX = 0; | |
break; | |
case 2: | |
currentX = 1; | |
break; | |
case 4: | |
currentX = 2; | |
break; | |
case 8: | |
currentX = 3; | |
break; | |
} | |
//if pixel has moved send midi | |
if (lastX != currentX || lastY != yPosition){ | |
MIDImessage(noteON,(lastX+5*lastY+MIDIoffset),0);//turn off last note | |
MIDImessage(noteON,(currentX+5*yPosition+MIDIoffset),velocity);//turn on next note | |
} | |
lastX = currentX; | |
lastY = yPosition; | |
} | |
void MIDImessage(int command, int MIDInote, int MIDIvelocity) {//send s a MIDI message | |
Serial1.write(command);//send note on or note off command | |
Serial1.write(MIDInote);//send pitch data | |
Serial1.write(MIDIvelocity);//send velocity data | |
} | |
void loop() { | |
if (firstPress){ | |
checkFirstButton(); | |
} | |
else{ | |
for (byte pixel=0;pixel<8;pixel++){ | |
if (pixel==yPosition){ | |
ledData[pixel]=xPosition; | |
} | |
else{ | |
ledData[pixel] = 0; | |
} | |
} | |
checkAccelerometer(); | |
moveXPixel(getTime(xAcc)); | |
moveYPixel(getTime(yAcc)); | |
checkMIDI(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment