// XYZ textile pad // (procedural abstraction) void analogPullup(int pin, boolean activate) { pinMode(14+pin, INPUT); // magic to active pullups 14 is the numbering of the analog pins digitalWrite(14+pin, activate ? HIGH : LOW); // if activate is true then HIGH else LOW <--- pseudocode } // establish a potential difference between two analog pins void analog_establish_potential(int pinhigh, int pinlow) { pinMode(14+pinhigh,OUTPUT); // digitalWrite(14+pinhigh, HIGH); //3.3v pinMode(14+pinlow,OUTPUT); // digitalWrite(14+pinlow, LOW); //0v } // data abstraction (reuse which allows for scaling this to a lot of sensors and cool stuff) const int left_strip_pin=0; const int right_strip_pin=1; const int top_strip_pin=2; const int bottom_strip_pin= 3; const int led_pin = 13; void setup() { pinMode(led_pin, OUTPUT); Serial.begin(9600); // debugging } void loop() { delay(500); // slow sensing down so we have time to read values on serial console analog_establish_potential(top_strip_pin, bottom_strip_pin); analogPullup(right_strip_pin, true); analogPullup(left_strip_pin, true); // analogRead functions numbers from 0 (not 14)! int sensorValue = analogRead(right_strip_pin); Serial.print(sensorValue); Serial.print(' '); if(sensorValue < 900) { // disable pullup to get an accurate value analogPullup(right_strip_pin, false); analogPullup(left_strip_pin, false); int sensorValue = analogRead(right_strip_pin); Serial.print(sensorValue);Serial.print("v "); // now we do left and right analog_establish_potential(left_strip_pin, right_strip_pin); analogPullup(top_strip_pin, false); analogPullup(bottom_strip_pin, false); // analogRead functions numbers from 0 (not 14)! sensorValue = analogRead(bottom_strip_pin); Serial.print(sensorValue); Serial.print("h "); // int ledFadeValue = map(sensorValue, 300, 700, 0, 255); // analogWrite(led_pin, ledFadeValue); } Serial.println(); }
// Touch Synth // Copyright 2009 Adrian Freed. All Rights Reserved. // tested on the lilypad // requires rework to deal with different port assignments on the mega // //shorthands to turn on the built-in pullup resistors for each pin inline void digitalPullup(byte pin, boolean b) { pinMode(pin, INPUT); digitalWrite(pin, b?HIGH:LOW); } #if defined(__AVR_ATmega1280__) inline void analogPullup(byte pin, boolean b) { digitalPullup(pin+54,b); } #else inline void analogPullup(byte pin, boolean b) { digitalPullup(pin+14,b); } #endif const byte speakerPin = 0; //a0 const byte speakerPinbis = 1; // differential drive for extra loudness and lower power consumption const boolean debugging = false; void setup() { if(debugging) { Serial.begin(9600); } pinMode(speakerPin, OUTPUT); // sets the speakerPin to be an output pinMode(speakerPinbis, OUTPUT); // sets the other speakerPin to be an output } //touch sensing on the 14 digial pins on ports d and b // http://www.arduino.cc/en/Reference/PortManipulation [1] typedef struct tr { byte t[14+8]; // >1 when touched. The number is larger the better your bodies path is to ground } touchresult; struct tr touchsense(int pins); // a bit field to set which pins you want to be touch active. #define TRANGE 32 struct tr touchsense(unsigned long pins) { byte portd = pins &0xff; byte portb = (pins>>8) &0x3f; byte portc = (pins>>13)&0xff; byte i,j; byte result[TRANGE]; touchresult r= { 0,0,0,0, 0,0,0,0 ,0,0,0,0, 0,0}; // concurrent sensing for portb portb &= ~DDRB; // don't mess with direction of existing output pins // xxxhow do we know what input pins are in use? // how do we not disturb state of existing output pins? if(portb) { PORTB &= ~portb; // low level DDRB |= portb; // discharge for(i=0;i<TRANGE;++i) result[i] = 0; DDRB &= ~portb; PORTB |= portb; result[0] = PINB; result[1] = PINB; result[2] = PINB; result[3] = PINB; result[4] = PINB; result[5] = PINB; result[6] = PINB; result[7] = PINB; result[8] = PINB; result[9] = PINB; result[10] = PINB; result[11] = PINB; result[12] = PINB; result[13] = PINB; result[14] = PINB; result[15] = PINB; result[16] = PINB; result[17] = PINB; result[18] = PINB; result[19] = PINB; result[20] = PINB; result[21] = PINB; result[22] = PINB; result[23] = PINB; result[24] = PINB; result[25] = PINB; result[26] = PINB; result[27] = PINB; result[28] = PINB; result[29] = PINB; result[30] = PINB; result[31] = PINB; for(i=2;i<TRANGE;++i) { // Serial.println(result[i], HEX); for(j=0;j<6;++j) { if(portb&(1<<j)) r.t[j+8] += !(result[i] & (1<<j)); } } } // concurrent sensing for portc portc &= ~DDRC; // don't mess with direction of existing output pins // xxxhow do we know what input pins are in use? // how do we not disturb state of existing output pins? if(portc) { PORTC &= ~portc; // low level DDRC |= portc; // discharge for(i=0;i<TRANGE;++i) result[i] = 0; DDRC &= ~portc; PORTC |= portc; result[0] = PINC; result[1] = PINC; result[2] = PINC; result[3] = PINC; result[4] = PINC; result[5] = PINC; result[6] = PINC; result[7] = PINC; result[8] = PINC; result[9] = PINC; result[10] = PINC; result[11] = PINC; result[12] = PINC; result[13] = PINC; result[14] = PINC; result[15] = PINC; result[16] = PINC; result[17] = PINC; result[18] = PINC; result[19] = PINC; result[20] = PINC; result[21] = PINC; result[22] = PINC; result[23] = PINC; result[24] = PINC; result[25] = PINC; result[26] = PINC; result[27] = PINC; result[28] = PINC; result[29] = PINC; result[30] = PINC; result[31] = PINC; for(i=2;i<TRANGE;++i) { // Serial.println(result[i], HEX); for(j=0;j<8;++j) { if(portc&(1<<j)) r.t[j+14] += !(result[i] & (1<<j)); } } } // concurrent sensing for port D portd &= ~DDRD; // don't mess with direction of existing output pins // xxxhow do we know what input pins are in use? // how do we not disturb state of existing output pins? if(portd) { PORTD &= ~portd; // low level DDRD |= portd; // discharge for(i=0;i<TRANGE;++i) result[i] = 0; DDRD &= ~portd; PORTD |= portd; result[0] = PIND; result[1] = PIND; result[2] = PIND; result[3] = PIND; result[4] = PIND; result[5] = PIND; result[6] = PIND; result[7] = PIND; result[8] = PIND; result[9] = PIND; result[10] = PIND; result[11] = PIND; result[12] = PIND; result[13] = PIND; result[14] = PIND; result[15] = PIND; result[16] = PIND; result[17] = PIND; result[18] = PIND; result[19] = PIND; result[20] = PIND; result[21] = PIND; result[22] = PIND; result[23] = PIND; result[24] = PIND; result[25] = PIND; result[26] = PIND; result[27] = PIND; result[28] = PIND; result[29] = PIND; result[30] = PIND; result[31] = PIND; for(i=2;i<TRANGE;++i) { // Serial.println(result[i], HEX); for(j=0;j<8;++j) { if(portd&(1<<j)) r.t[j] += !(result[i] & (1<<j)); } } } return r; } static int pitches[] = { 523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988, 2*523, 2*554, 2*587, 2*622, 2*659, 2*698, 2*740, 2*784, 2*831, 2*880, 2*932, 2*988, }; // differential pulse trains. The marktospacepercentage controls timbre (and amplitude for small values). // The frequency determines pitch. Use a high impedence driver: 30-100Ohms or a piezo. void beep (unsigned frequencyInHertz, unsigned timeInMilliseconds, unsigned marktospacepercentage) // the sound producing function { int x; static int swap=0; unsigned long delayAmount = 1000000L/frequencyInHertz; unsigned long markdelay = delayAmount*marktospacepercentage/1000l; unsigned long spacedelay = (delayAmount*(1000l-marktospacepercentage))/1000l; int loopTime = (int)((timeInMilliseconds*500l)/(delayAmount)); while(loopTime--) { pinMode(speakerPin, OUTPUT); // sets the speakerPin to be an output pinMode(speakerPinbis, OUTPUT); // sets the other speakerPin to be an output digitalWrite(speakerPin,swap); digitalWrite(speakerPinbis,!swap); delayMicroseconds(markdelay); pinMode(speakerPin, INPUT); // sets the speakerPin to be an output pinMode(speakerPinbis, INPUT); // sets the other speakerPin to be an output delayMicroseconds(spacedelay); } swap = !swap; } void loop () { // read the keys struct tr r = touchsense(0xcffcUL); // sound a short pitch for each touch using the touch value to determine loudness/timbre for(int i = 0; i < 21; i++) { int key =r.t[i]; if(key>0 &&i!=13 && i!=speakerPin && i!=speakerPinbis) { if(debugging) { Serial.print(i); Serial.print(" "); Serial.println(key); } beep(pitches[i]/4,100,key); } } } #include <stdarg.h> void touchsensepins(int l, ...) { va_list argp; unsigned long res = 0; va_start(argp, l); int i = l; do { res |= 1UL <<i; } while((i = va_arg(argp, int))!=-1); touchsense(res); va_end(argp); }
Links:
[1] http://www.arduino.cc/en/Reference/PortManipulation
[2] http://www.adrianfreed.com/taxonomy/term/173
[3] http://www.adrianfreed.com/category/affinity-group/e-textiles