Function destroying information

Hi all,

First off, sorry for the long post.

This is my first time posting here and first Arduino project. I have had some experience with Arduino in school projects, but this is the first time I've done something on my own. I am trying to create a "door-knock unlocker" that will unlock a door in response to a preset knock that the user defines. At this point, I am working on storing the knock combination needed to unlock the door. My idea was to store the knocks by time that the occured, find the space between knocks, convert those to ratios (based on the first space) to make it tempo independent and eventually compare those ratios to someone's knock who is trying to get in. Everything works great except for one detail.

When I wrote the functions for the converting the times into spaces and then ratios, I get a weird bug the makes my knock counter go to 0. Basically, I wanted the user to be able to change their secret knock. This means if the knock is shorter than the previous one, I want to write over those extra bits from the old knock with zeros. This works for the getKnockTimes and getKnockDelay functions, but when I use it in getKnockRatios function, it makes my knockCounter variable go to 0, which makes my entire knockDelays and knockRatios arrays be overwritten. It only happens in that ONE for loop, and it happens even if I replace every instance of the knockCounter variable in the getKnockRatios function. Does anyone know why this function's for-loop is affecting that particular variable?

const int ARRAY_LENGTH = 50;

int indicatorPin = 13;
int playbackPin = 12;

int sensorValue;
int button;

float knockTimes[ARRAY_LENGTH];
float knockDelays[ARRAY_LENGTH-1];
float knockRatios[ARRAY_LENGTH-1];

int knocks;
int knockCounter;

int playbackCounter;


void setup() {
  Serial.begin(9600);
  pinMode(indicatorPin, OUTPUT);
  pinMode(playbackPin, OUTPUT);
}

void loop() {
  
  if (buttonPressed()) {
    knocks = getSecretKnock(knockTimes);     // Gets the new knock sequence if button is pressed.
    
    if (knocks >= 1) {                        // Avoid any knocks of 0 length
      knockCounter = knocks;
    }
    
    getKnockDelays(knockTimes, knockDelays, knockCounter);
    getKnockRatios(knockDelays, knockRatios, knockCounter);
  }
  
  Serial.println(knockCounter);

  for (int i = 0; i < 10; i++) {
    Serial.print(knockTimes[i]);
    Serial.print(",");
  }
  Serial.println();
    
  for (int i = 0; i < 10; i++) {
    Serial.print(knockDelays[i]);
    Serial.print(",");
  }
  Serial.println();
  
  for (int i = 0; i < 10; i++) {
    Serial.print(knockRatios[i]);
    Serial.print(",");
  }
  Serial.println();
}

boolean buttonPressed() {
  // Checks to see if button is pressed or not.
  
  int button;
  
  button = analogRead(1);
  
  if (button > 0) {
    return true;
  }
  else {
    return false;
  }
}

int getSecretKnock(float *array) {
  // Detects the knocks and stores them by the time at which they occur.
  // If a previous knock is stored, new one overwrites it.
  // Also returns the number of knocks in the sequence.
  
  int button;               // Is the button for recording knock pressed?
  int sensorValue;          // Piezo sensor value
  int counter = 0;
  
  button = analogRead(1);
  sensorValue = analogRead(0);
  
  while (button > 0) {
    // While the button is pressed, read in values from sensor that are greater than 0.
    
    if (sensorValue > 0) {                 // Lights up indicator LED if knock occurs.
      digitalWrite(indicatorPin, HIGH);
      delay(10);
      digitalWrite(indicatorPin, LOW);
    }
    
    if (sensorValue > 0) {
      if (counter == 0) {                             // First value in knock sequence
        array[counter] = millis();
        counter++;
      }
      else {
        if ((millis()-array[counter-1]) > 100) {      // If the time between previous knock and current
          array[counter] = millis();                  // knock is too short, it is most likely noise and
          counter++;                                  // is ignored as a knock value.
        }
      }
      for (int i = counter; i < ARRAY_LENGTH; i++) { // Overwrites all knock values after the last knock
        array[i] = 0;                                // (in case any left from previous sequence).
      }
    }
    button = analogRead(1);
    sensorValue = analogRead(0);
  }
  return counter;      // Return the number of knocks in sequence for later use.
}

void getKnockDelays(float *knockArray, float *delayArray, int knockCounter) {
  // Takes the n length knock array and turns it into a (n-1) length delay array.
  // This is the delay between each successive knock. It will be used to compare
  // to the input knock when trying to unlock.
  
  for (int i = 0; i < knockCounter-1; i++) {              // The first knock delay is knock0 - knock1. The second is
    delayArray[i] = knockArray[i+1] - knockArray[i];      // knock2 - knock1 and so on in this manner.
  }
  for (int j = knockCounter-1; j < ARRAY_LENGTH; j++) {   // Remove any extra delays from previous knock.
    delayArray[j] = 0;
  }
  Serial.println(knockCounter);
}

void getKnockRatios(float *delayArray, float *ratioArray, int knockCounter) {
  // Finds the ratio of the knocks relative to the first delay.
  // This allows the knock sequence to be tempo independent.
  
  for (int i = 0; i < knockCounter-1; i++) {
    ratioArray[i] = delayArray[i] / delayArray[0];
  }
//  for (int j = knockCounter-1; j < ARRAY_LENGTH; j++) {   // Remove any extra delays from previous knock. THIS IS WHERE THE PROBLEM IS.
//    ratioArray[j] = 0;
//  }
  Serial.println(knockCounter);
}

As an example of what happens when it runs, with the for loop commented out I get something like this on the Serial for a 3 knock sequence:
3 (check knockCounter variable in getKnockDelays function)
3 (check knockCounter variable in getKnockRatios function)
3 (check knockCounter after all functions have been called)
200, 400, 600 (knock times)
200, 200 (knock spacing)
1, 1 (knock ratio relative to first spacing)
repeat

With for loop uncommented and used in any way:
3
3
0 (problem starts here)
200, 400, 600
200, 200
1, 1
0
0
0
200, 400, 600
0, 0
0, 0
etc.

You are running off the end of your array:

const int ARRAY_LENGTH = 50;

float knockTimes[ARRAY_LENGTH];
float knockDelays[ARRAY_LENGTH-1];  
float knockRatios[ARRAY_LENGTH-1];  // Elements 0-48
int knocks;
int knockCounter;

void getKnockRatios(float *delayArray, float *ratioArray, int knockCounter) {
  // Finds the ratio of the knocks relative to the first delay.
  // This allows the knock sequence to be tempo independent.
  
  for (int i = 0; i < knockCounter-1; i++) {
    ratioArray[i] = delayArray[i] / delayArray[0];
  }
//  for (int j = knockCounter-1; j < ARRAY_LENGTH; j++) {   // Remove any extra delays from previous knock. THIS IS WHERE THE PROBLEM IS.
//    ratioArray[j] = 0;   ///////  When j reaches 49 (ARRAY_LENGTH-1) this overwrites your counts
//  }

Doh! Thanks so much! I hate it when I miss simple things like that. So to be clear, when it ran over the array length, it just happened to be the address for knockCounter that was overwritten? I'm going to try and fix this really quick in the meantime and make sure it works now.

EDIT: It works perfectly now.

  int button;               // Is the button for recording knock pressed?
  button = analogRead(1);

Lousy name for the variable aside, it appears that you have a digital switch connected to an analog pin. Why?

          array[counter] = millis();                  // knock is too short, it is most likely noise and

Why are you storing the unsigned long returned by millis() in a float?

    delayArray[i] = knockArray[i+1] - knockArray[i];      // knock2 - knock1 and so on in this manner.

Why is the difference between two (what should be unsigned long) times stored in a float? Are you expecting differences of 3.7 milliseconds?

Lousy name for the variable aside, it appears that you have a digital switch connected to an analog pin. Why?

Just learning circuits and electronics in general, so I will change it over to a digital pin.

As for the variable types, this was an oversight on my part. I had misread millis() as being float.