Go Down

Topic: Door opener that senses taps on a microphone (Read 725 times) previous topic - next topic



I am trying to build up a door opener that compares a predefined rhythm to the rhythm you tap on the microphone outside the house in order to open the door if the sequence was correct.
All of that shall be running on an Attiny 45 and I think the in- and output pins suffice for what I plan to do (at least I do not expect to need more pins than I have yet).

Basically, ringing on the outside triggers an Interrupt funtion which then launches a tap recognition function which records what you tap. This function is a loop and not based on interrupts, that is why it might be faulty at that point.

Furthermore, that sequence is normalized. Every entry is divided by the highest entry and multiplied with 100, then rounded to the absolute value and stored again.

Now there are two functions meant to determine the deviations between the recorded rhythm and the reference. In case the differences are within the predefined bounds, a long beep is played on a piezo speaker (and the door is opened of course).

The program i have written does not work as intended, here is the code: Comments are mostly german, i hope it is still posible to understand.

The problem is the following: The reference rhythm contains three 100s which hints at four taps (the values indicate the pauses between two taps) equally distanced with regard to time.

The program does not recognize my correct rhythm. While writing I think of the pulldown resistor that I forgot to install, might this be a problem (i guess so)? I do not exactly tap at the moment, I have a button connecting the input pin to VCC when pressed (The button is debounced with 50ms, see below).

Additionally the program pretends to have recognized a correct rhythm after 4 loops of the "loop" function and does so for any following loop (thus plays the 5 second beep). Why does it do so?

Thank you in advance,

Code: [Select]
//                          +-\/-+
//Reset:  (Ain0 (D 5) PB5) 1|    |8  Vcc
//         Ain3 (D 3) PB3  2|    |7  PB2 (D 2)  Ain1
//         Ain2 (D 4) PB4  3|    |6  PB1 (D 1) pwm1
//                    GND  4|    |5  PB0 (D 0) pwm0
//                          +----+

#define doorOpener 0  // Türöffner
#define beepPin 1    // Summer
#define ringerPin 2  // Pin 2 for digital read!
#define tapPin 3  // Pin 3 for analog read!
#define adjustPin 2  // UNUSED.....Pin 2 for analog read!

#define delayAfterRing 5000  // milliseconds: delay nach klingeln
#define maxRhythmLength 5000  // milliseconds: dauer des refRhythms
#define tapDebounceDelay 50  // milliseconds: "debounce" vom Mikrofon
#define maxTaps 10  // mehr taps werden nicht erkannt.
#define tapForceThresold 30  // 30/1023 Aussteuerung des analogsensors

#define maxAvgOff 15 // Percentage
#define maxOff 20

int lastMillis= -5000;  // Zwischenspeicher für millis
int refRhythm[maxTaps];  // Referenz refRhythm
int recRhythm[maxTaps];  // aufgenommenes refRhythm
int tapCount;  // Anzahl Signale

// --------------- /var

void setup () {
  pinMode(ringerPin, INPUT);
  pinMode(beepPin, OUTPUT);
  pinMode(tapPin, INPUT);
  pinMode(doorOpener, OUTPUT);
  attachInterrupt(0,ringDetect,RISING);  // Wenn geklingelt wird, soll der Interrupt geschehen
  beep(200);  // Statusbeep
  int refRhythm[] = {
    100,100,100,0,0,0,0,0,0,0  };

void loop () {
  ringDetect ();

void ringDetect () {
  if (millis()-lastMillis >= delayAfterRing) {  // Nur alle x Millisekunden einen neuen Interrupt aufnehmen
    lastMillis = millis();  // und den vergleichswert sichern
    if (avgPercOff(refRhythm,recRhythm,tapCount) <= maxAvgOff && maxPercOff(refRhythm,recRhythm,tapCount) <= maxOff) {  // Wenn Toleranzen eingehalten, Tür öffnen

      for(int i=0;i<=maxTaps-1;i++) {
        recRhythm[i] = 0;



void define_refRhythm () {  // UNUSED
  tap_detect (tapPin);

void tap_detect (int inputPin) {
  tapCount = 0;  // Taps nach jedem Klingeln zurücksetzen!
  int tapTime;  // absoluter Zeitpunkt eines Signals
  int tapForce;  // Pegel zum Vergleich/Störungsbeseitigung
  int last_tap = 0;


  while(millis()-lastMillis <= maxRhythmLength) {  // solange die max refRhythm dauer noch nicht um ist:
    tapForce = analogRead(inputPin);  // pin lesen
    if(tapForce >= tapForceThresold   &&   millis()-last_tap >= tapDebounceDelay   &&   tapCount <= maxTaps) {  // wenn tap stark genug; debounce bedingung; tap limit
      if(tapCount == 0) {
        tapTime = millis();  // erster tap: startzeitpunkt
      else {
        recRhythm[tapCount-1] = millis()-tapTime;  // Zeitdifferenzen auftragen
        tapTime = millis();
      last_tap = millis();

void normalizeTimes(int refRhythm[]) {  // normiert ein beliebiges refRhythm auf den Höchsten Wert, dieser wird zu 100 gesetzt, anschließend runden
  int compareValue;
  compareValue = refRhythm[0];

  for (int i=1; i<=maxTaps-1; i++) {
    if(refRhythm[i] > compareValue) {
      compareValue = refRhythm[i];

  compareValue /= 100;

  for (int k=0; k<=maxTaps-1; k++) {
    refRhythm[k] = (int)(refRhythm[k]/compareValue);

int avgPercOff (int reference[], int comp[], int felder) {  // durchschnittliche prozentuale Abweichung
  int abw = 0;
  for (int i=0; i<=felder-1; i++) {
    abw += diffProz(reference[i], comp[i]);
  return (int) abw/felder+0.5;

int maxPercOff (int reference[], int comp[], int felder) {  // maximale prozentuale Abweichung
  int abw = diffProz(reference[0], comp[0]);
  for (int i=1; i<=felder-1; i++) {
    int abwTemp = diffProz(reference[i], comp[i]);
    if (abwTemp > abw) {
      abw = abwTemp;
  return abw;

int diffProz (int ref, int comp) {  // Berechnet prozentuale Abweichung und rundet ganzzahlig
  int abw = (int) 0.5+100*(ref-comp)/ref;
  return abs(abw);

void beep(int dauer) {


Code: [Select]
  int refRhythm[] = {
    100,100,100,0,0,0,0,0,0,0  };

This local variable in setup() is useless. It goes out of scope immediately.
The art of getting good answers lies in asking good questions.

Go Up