// Alex Leone // October 2008 #define TOUCH_PIN 6 #define TOUCH_LOW ((PIND & _BV(TOUCH_PIN)) == 0) #define OPEN_PIN 5 #define OPEN_LOW ((PIND & _BV(OPEN_PIN)) == 0) #define TOUCH_BUFFER_SIZE 12 #define TOUCH_TIMEOUT 3000 #define MAX_PATTERN_ERROR 100000 #define SERVO_ENABLE 8 #define ZERO_DEG 710 #define FULL_DEG 3000 #define OPEN_DELAY 5000 uint8_t handled = 0; int16_t touchBuffer[TOUCH_BUFFER_SIZE]; uint8_t touchBufferSize = 0; uint32_t lastTouchMillis = 0; int16_t pattern[TOUCH_BUFFER_SIZE] = { 0, 1000, 1000, 500, 500, 1000, 250, 250, 250, 250, 250, 250, }; #define TOUCH_BUFFER_TEMPO_MULTI 100 uint32_t touchBufferSum = 0; void setUpTouchBuffer() { touchBufferSum = 0; for (uint8_t i = 1; i < TOUCH_BUFFER_SIZE; i++) { touchBufferSum += pattern[i]; } } void open_door() { start_servo(); delay(OPEN_DELAY); stop_servo(); } void start_servo() { TCCR1B |= _BV(CS11); // start timer w/ div 8 prescaler digitalWrite(13, HIGH); digitalWrite(SERVO_ENABLE, HIGH); delay(1000); OCR1B = FULL_DEG; } void stop_servo() { OCR1B = ZERO_DEG; delay(1000); digitalWrite(SERVO_ENABLE, LOW); digitalWrite(13, LOW); TCCR1B &= ~_BV(CS11); } void addToBuffer() { uint32_t now = millis(); if (touchBufferSize < TOUCH_BUFFER_SIZE) { touchBuffer[touchBufferSize++] = now - lastTouchMillis; if (touchBufferSize == TOUCH_BUFFER_SIZE) { checkBuffer(); } } lastTouchMillis = now; } void clearBuffer() { touchBufferSize = 0; Serial.println("Cleared Buffer"); Serial.println(); } uint8_t checkBuffer() { sendBuffer(); // check pattern uint32_t sum = 0; for (uint8_t i = 1; i < TOUCH_BUFFER_SIZE; i++) { sum += touchBuffer[i]; } Serial.print("sum: "); Serial.println(sum, DEC); Serial.print("pattern sum: "); Serial.println(touchBufferSum, DEC); uint32_t multi = (touchBufferSum * TOUCH_BUFFER_TEMPO_MULTI) / sum; Serial.print("multi: "); Serial.println(multi, DEC); uint32_t error = 0; for (uint8_t i = 1; i < TOUCH_BUFFER_SIZE; i++) { Serial.print((uint32_t)touchBuffer[i] * multi / TOUCH_BUFFER_TEMPO_MULTI, DEC); Serial.print(' '); int32_t d = pattern[i] - (uint32_t)touchBuffer[i] * multi / TOUCH_BUFFER_TEMPO_MULTI; error += d * d; } Serial.println(); Serial.print("error :"); Serial.println(error, DEC); if (error < MAX_PATTERN_ERROR) { Serial.println("open sesame"); open_door(); } clearBuffer(); } void reset() { Serial.println("reset"); handled = 0; digitalWrite(13, LOW); } void sendBuffer() { for (uint8_t i = 1; i < touchBufferSize; i++) { Serial.print(touchBuffer[i], DEC); Serial.print(' '); } Serial.println(); } void setup() { Serial.begin(9600); pinMode(13, OUTPUT); DDRD &= ~(_BV(TOUCH_PIN) | _BV(OPEN_PIN)); // configure pin as input PORTD |= (_BV(TOUCH_PIN) | _BV(OPEN_PIN)); // enable the pull-up resistor touchBufferSize = 0; setUpTouchBuffer(); reset(); pinMode(10, OUTPUT); pinMode(13, OUTPUT); pinMode(SERVO_ENABLE, OUTPUT); digitalWrite(SERVO_ENABLE, LOW); TCCR1A = _BV(COM1B1); // clear OC1B on up-count, set on down-count TCCR1B = _BV(WGM13); // Phase and frequency correct mode, ICR1 is TOP ICR1 = 20000; OCR1B = ZERO_DEG; delay(5000); } void loop() { if (TOUCH_LOW) { if (handled == 0) { Serial.println("low"); digitalWrite(13, HIGH); addToBuffer(); handled = 1; delay(50); } } else if (handled) { addToBuffer(); reset(); } else if (touchBufferSize) { uint32_t m = millis(); if (m < lastTouchMillis || m - lastTouchMillis > TOUCH_TIMEOUT) { lastTouchMillis = m; clearBuffer(); } } if (OPEN_LOW) { open_door(); clearBuffer(); } }