// The Reactor project is combining ATTiny85 and WTV020-SD-20S chip // the electronic board is made for stand alone audio player controlled by a knitted sensor fabric // this sketch implement sleep mode to reduce power consumption // you will need first to install ATTiny library for Arduino // http://hlt.media.mit.edu/?p=1695 // change the boards.txt ligne attiny85at8.upload.using=usbtiny depending on you programmer // Tools > Board > ATTiny85 @ 8 MHz //////////////////////////////////////// CONSTANTES declaration and initialisation int sensorPin = 3; // PB3 (ADC3) ATTiny analog pin 3 to sens potentiometer scarf (voltage divider) int volumePin = 2; // PB4 (ADC2) ATTiny analog pin 2 as input to trigger SOMO volume (10k pullUp resistor) #define resetPin PB0 // ATTiny analog 1 to SOMO reset pin #define clockPin PB1 // SOMO clock pin #define dataPin PB2 // SOMO data pin #define MIN_SOUND 16 // reserved sound file for volume menu 0...7 #define MAX_SOUND 64 // how many sound file you have on the SD card #define DEBOUNCETIME 20 // debounce to avoid double playing instructions #define THRESHOLD_SENS 20 // threshold apply on derivative sensor value #define THRESHOLD_SWITCH 100 // threshold apply on derivative sensor value #define INACTIVETIME 5000 // time before sleeping mode //////////////////////////////////////// variables declaration and initialisation unsigned long curentMillis = 0; // unsigned long lastMillisSens = 0; // unsigned long lastMillisSleep = 0; // unsigned int rowSensorScarfVal = 0; // unsigned int lastrowSensorScarfVal = 0; // int deriveeScarf = 0; // derivative variable used to detect mouvments unsigned int rowSensorSwitchVal = 0; // boolean debounceToggleScarf = true; // avoid double clic instructions boolean debounceToggleSwitch = true; // avoid double clic instructions boolean toggelsomoLowPower = false; // avoid SOMO waking up during sleep mode boolean wakeUpToggelVolumeSwitch = true; // unsigned int volumeArray[] = { 0xFFF0, 0xFFF1, 0xFFF2, 0xFFF3, 0xFFF4, 0xFFF5, 0xFFF6, 0xFFF7 }; unsigned int curentVolume = 7; // initial volume level //////////////////////////////////////// Initialisation void setup(){ pinMode(clockPin, OUTPUT); // set pin has an output for clock pinMode(dataPin, OUTPUT); // set pin has an output for data pinMode(resetPin, OUTPUT); // set pin has an output to reset SOMO digitalWrite(clockPin, HIGH); // digitalWrite(dataPin, LOW); // digitalWrite(resetPin, HIGH); // /////////////////////// initialize watchdog timer somoReset(); sendData(volumeArray[curentVolume]); // set SOMO-14D volume } //////////////////////////////////////// boucle principale void loop(){ curentMillis = millis(); // set SOMO lowPower MODE if( ((curentMillis - lastMillisSleep) >= INACTIVETIME) && toggelsomoLowPower){ toggelsomoLowPower = false; // invert toggle to give sleep instruction only one time wakeUpToggelVolumeSwitch = true; // invert toggle to permit reset after wakeUn somoLowPower(); // put SOMO in to idle MODE } // slow down analog readings if((curentMillis - lastMillisSens) >= DEBOUNCETIME){ // read switch plugged on to Analog pin rowSensorSwitchVal = analogRead(volumePin); if((rowSensorSwitchVal <= THRESHOLD_SWITCH) && debounceToggleSwitch){ // wakeUp SOMO with the first volume switch presed if(wakeUpToggelVolumeSwitch){ wakeUpToggelVolumeSwitch = false; // invert toggle to reset only one time lastMillisSleep = curentMillis; // reset sleep counter somoReset(); // reset SOMO } else { curentVolume++; // increase the volume sendData(curentVolume % 8); // play coresponding file sendData(volumeArray[curentVolume % 8]); // set SOMO volume debounceToggleSwitch = false; // invert toggle value to avoid double instructions lastMillisSleep = curentMillis; // reset sleep counter } } if((rowSensorSwitchVal > THRESHOLD_SWITCH) && !debounceToggleSwitch){ debounceToggleSwitch = true; // invert toggle to debounce playing instructions } rowSensorScarfVal = analogRead(sensorPin); deriveeScarf = abs(rowSensorScarfVal - lastrowSensorScarfVal); if((deriveeScarf >= THRESHOLD_SENS) && debounceToggleScarf){ sendData(random(MIN_SOUND, MAX_SOUND)); // play a sample randomly debounceToggleScarf = false; // invert toggle to debounce playing instructions toggelsomoLowPower = true; // invert toggle to avoide SOMO sleep MODE lastMillisSleep = curentMillis; // reset sleep counter } if(!debounceToggleScarf && (deriveeScarf < THRESHOLD_SENS)){ // wait until derivative go under threshold debounceToggleScarf = true; // invert toggle to debounce playing instructions } lastrowSensorScarfVal = rowSensorScarfVal; // remind curent scarf sensor value lastMillisSens = curentMillis; // reset sleep counter } } /////////////////////////////// send data to SOMO module void sendData(unsigned int command){ // start bit digitalWrite(clockPin, LOW); delay(2); // bit15, bit14, ... bit0 for (unsigned int mask = 0x8000; mask > 0; mask >>= 1) { if (command & mask) { digitalWrite(dataPin, HIGH); } else { digitalWrite(dataPin, LOW); } // clock low digitalWrite(clockPin, LOW); delayMicroseconds(15); // clock high digitalWrite(clockPin, HIGH); delayMicroseconds(15); } // stop bit delay(2); } /////////////////////// Reset SOMO void somoReset(){ digitalWrite(resetPin, LOW); delay(10); digitalWrite(resetPin, HIGH); delay(10); } /////////////////////// SOMO lowPower MODE // Stops playing the current audio file and puts the module in the ow power idle mode. void somoLowPower(){ sendData(0xFFFF); }