Paso 7: El código
Este código Lee cuando el imán pasa el sensor y mantiene un promedio de marcha del tiempo entre pedal pasa. Utiliza esta información para calcular las revoluciones por minuto.
Para la salida a los LEDs, utiliza una función para calcular el brillo de cada LED en función del valor de rpm. Esto crea un efecto de decoloración suave entre los LEDs como los valores cambian.
La mejor forma de leer del sensor habría sido con interrupciones, pero me encontré con un problema donde los valores del sensor no eran lo suficientemente altos como para registrarse con el Arduino como señales digitales. Así que tuve que utilizar los valores de los sensores analógicos.
Este no es el código más elegante, pero funciona y está actualmente bloqueado dentro de una caja en mi bici, así que les dejo como es. Sugerencias y cambios son bienvenidos.
#define ARRAY_SIZE 3 //The number of values to keep in the running average #define TIMEOUT 1500 //Max time without input before turning off LEDs #define FADE_INCREMENT .1 //Controls the fading speed--adjust with trial and error #define LED_CONSTANT -20 //Used in the brightness fading equation //RPM targets for each LED: #define RED_1_TARGET 45 #define YELLOW_1_TARGET 68 #define GREEN_TARGET 90 #define YELLOW_2_TARGET 113 #define RED_2_TARGET 135 /**PORT SETUP**/ const int magnetSensor = A7; //Change this for your arduino const int red1 = 12; const int yellow1 = 10; const int green = 9; const int yellow2 = 5; const int red2 = 4; const int ledPin = 11; bool magnetOn = false; bool prevMagOn = false; bool primed = false; bool arrayEmpty = false; float times[ARRAY_SIZE]; //array to hold values for the running average float startTime = millis(); int rpm = 0; bool pedaling = false; int targetR1; int targetY1; int targetG; int targetR2; int targetY2; float r1; float y1; float g; float y2; float r2; //add a new value to the array, moving the rest back one space and removing the oldest void updateTimes(float newValue) { for(int i = 0; i < ARRAY_SIZE-1; i++) { times[i] = times[i+1]; } times[ARRAY_SIZE-1] = newValue; } //returns an average of the values in the array int avgArray(float values[]) { int total = 0; int counted = ARRAY_SIZE; for(int i = 0; i < ARRAY_SIZE; i++) { total = total + values[i]; if(values[i] == 0) counted--; } return(total/counted); } //for debugging void printValues() { for(int i = 0; i < ARRAY_SIZE - 1; i++) { Serial.print(times[i]); Serial.print(", "); } Serial.println(times[ARRAY_SIZE -1]); } //clear the array void clearTimes() { for(int i = 0; i < ARRAY_SIZE; i++) times[i] = 0; } //check if the array is full void checkFullArray() { arrayEmpty = true; for(int i = 0; i < ARRAY_SIZE; i++) { if(times[i] != 0) arrayEmpty = false; } } //use a function to calculate the brightness of a given led based on a target int calculateLED(int target) { if (rpm <= 0) return 0; return int(LED_CONSTANT*abs(target-rpm)+255); } void setup() { pinMode(red1, OUTPUT); pinMode(yellow1, OUTPUT); pinMode(green, OUTPUT); pinMode(yellow2, OUTPUT); pinMode(red2, OUTPUT); Serial.begin(9600); } void loop() { //Read from the hall effect sensor (using analog values, unfortunately) int magnetState = analogRead(magnetSensor); Serial.println(magnetState); if(magnetState > 60) { magnetOn = false; } else { magnetOn = true; } if(!magnetOn && prevMagOn) { primed = true; } //timeout if(millis()-startTime > TIMEOUT) { clearTimes(); pedaling = false; } if(magnetOn && !prevMagOn && primed) { //if magnet passes sensor once float currentTime = millis(); float changeTime = (currentTime - startTime); //record the time since the last pedal startTime = millis(); if(pedaling) //if there has been pedaling since the last timeout updateTimes(changeTime); //add the time to the running average array primed = false; pedaling = true; } //mostly for debugging, this blinks the built-in LED whenever the magnet passes the sensor if(magnetOn) digitalWrite(ledPin, HIGH); else digitalWrite(ledPin, LOW); prevMagOn = magnetOn; checkFullArray(); float gap = avgArray(times); if(arrayEmpty) { rpm = 0; } else rpm = 60000/gap; //turn millisecond gap value into rpm //light the lowest red LED when the first pedal stroke is recorded, since there isn't enough data to calculate rpm if(pedaling && rpm == 0) rpm = 40; /******LED OUTPUT*****/ //calculate values targetR1 = calculateLED(RED_1_TARGET); targetY1 = calculateLED(YELLOW_1_TARGET); targetG = calculateLED(GREEN_TARGET); targetY2 = calculateLED(YELLOW_2_TARGET); targetR2 = calculateLED(RED_2_TARGET); //Normalize negative values to zero (these should really be in an array...) if(targetR1 < 0) targetR1 = 0; if(targetY1 < 0) targetY1 = 0; if(targetG < 0) targetG = 0; if(targetY2 < 0) targetY2 = 0; if(targetR2 < 0) targetR2 = 0; //fade to value if (r1 < targetR1) r1 += FADE_INCREMENT; if (r1 > targetR1) r1 -= FADE_INCREMENT; if (y1 < targetY1) y1 += FADE_INCREMENT; if (y1 > targetY1) y1 -= FADE_INCREMENT; if (g < targetG) g += FADE_INCREMENT; if (g > targetG) g -= FADE_INCREMENT; if (y2 < targetY2) y2 += FADE_INCREMENT; if (y2 > targetY2) y2 -= FADE_INCREMENT; if (r2 < targetR2) r2 += FADE_INCREMENT; if (r2 > targetR2) r2 -= FADE_INCREMENT; //output to LEDs analogWrite(red1, r1); analogWrite(yellow1, y1); analogWrite(green, g); analogWrite(yellow2, y2); analogWrite(red2, r2); }