Go Down

Topic: Metronom/BPM Counter - grundsätzliches Vorgehen? (Read 2 times) previous topic - next topic

Joghurt


@Joghurt: Deine Code produziert leider nur eine durchgehend leuchtende LED 13...

Mist. :(


und diesen Befehl verstehe ich nicht:
Code: [Select]
digitalWrite(LED, millis()-tick<blinkLength);
Was macht der Vergleichsoperator <blinkLength an dieser Stelle? Ist das ein C spezifischer Trick?

Naja, da kommt entweder "true" oder "false" raus, je nachdem ob du innerhalb der ersten blinkLength Millisekunden eines Zyklus bist oder nicht. Ich war der wohl irrigen Annahme, dass "true" gleich "HIGH" wäre und "false" gleich "LOW", aber dem ist wohl nicht so...?

Probier mal
Code: [Select]
digitalWrite(LED, millis()-tick<blinkLength ? HIGH : LOW);

Helmuth

Hallo Forum, hier der vorläufige Stand der Dinge:

Code: [Select]
//
// First Arduino Project by Pitt Tesla 2012
//
// BPM counter and metronome for triggering a DMX console with an audio input
// for precise light to sound show
//
// In gratitude for the LCD library and examples.
//
// ...tested with Arduino Uno v3 and DFRobot LCD Shield
//

#include <LiquidCrystal.h>

LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // Configuration of DFRobot LCD Shield

int lcd_key        = 0;    // for button reading
int adc_key_in     = 0;    // for button reading
long x             = 0;    // later used to compare with millis()
long y             = 0;    // used to measure TAP time
int tap_counter    = 0;    // counts the TAPs
int tap_max        = 4;    // number of TAPs used for calculation
float BPM          = 0;    // to display beats/minute
int time           = 500;  // ms between impulses = 120 BPM
int SCHRITT        = 10;   // UP/DOWN steps
int schritt        = 1;    // UP/DOWN steps fine
int shift          = 33;   // delay of LED flash (displays latency of my DMX chain) for better control)
int LEDpin         = 2;    // LED flash
int AUDIOpin       = 3;    // PWM output with 10k to AUDIO in
int frequency      = 500;  // Audio signal that seems to be easy to detect
int BUTTONpin      = 0;    // Buttons switching resistors from 5V to A0
int flashon        = 10;   // LED flash time
int wait_after_key = 150;  // for debouncing & key autorepeat
int BACKLIGHTpin   = 10;   // why dont´t use the backlight for flashing?!
int backlight      = 50;   // brightness to give a good contrast for flashing
int range          = 0;    // switches for rough and fine tuning

#define buttonSTART 0
#define buttonUP    1
#define buttonDOWN  2
#define buttonRANGE 3
#define buttonTAP   4
#define buttonNONE  5

int read_LCD_buttons()      // reads the LCD shield buttons
{
  adc_key_in = analogRead(BUTTONpin);     
  if (adc_key_in > 1000) {
    return buttonNONE;
  }
  if (adc_key_in < 50)   {
    return buttonSTART;
  }
  if (adc_key_in < 195)  {
    return buttonUP;
  }
  if (adc_key_in < 380)  {
    return buttonDOWN;
  }
  if (adc_key_in < 555)  {
    return buttonRANGE;
  }
  if (adc_key_in < 790)  {
    return buttonTAP;
  } 
  return buttonNONE; 
}

void ledACTION () {
  digitalWrite(LEDpin, HIGH);
  delay(flashon);
  digitalWrite(LEDpin, LOW);
}

void impulseACTION() {
  x = millis();
  tone(AUDIOpin, frequency, 5);          // send audio impulse
  analogWrite(BACKLIGHTpin, 255);        // flash backlight in "realtime"
  delay(flashon);
  analogWrite(BACKLIGHTpin, backlight);
  delay(shift-flashon);
  ledACTION();                           // flash external LED synchronized to latency of DMX processing
}

void setup()
{
//  Serial.begin(9600);                  // just for debugging...
  lcd.begin(16, 2);                      // init LCD
  lcd.setCursor(0,0);
  lcd.print(" /  Range   ");
  lcd.setCursor(2,0);
  lcd.print(tap_max);
  lcd.setCursor(0,1);
  lcd.print("   ms        BPM");
  pinMode(LEDpin, OUTPUT);               // init pins
  pinMode(AUDIOpin, OUTPUT);
  pinMode(BACKLIGHTpin, OUTPUT);
  analogWrite(BACKLIGHTpin, backlight);  // adjust brightness
}

void loop()
{
  float BPM = ((float)1000/(float)time) * (float)60;  //calculate BPM
  lcd.setCursor(0,1);           
  lcd.print(time);             // ms between impulses
  lcd.setCursor(6,1);           
  lcd.print(BPM);              // impulses/minute
  lcd.setCursor(13,0);           
  lcd.print(millis()/60000);   // power on time in minutes
  lcd.setCursor(0,0);           
  lcd.print(tap_counter);      // count of taps
  lcd.setCursor(10,0);           
  lcd.print(range);            // big or small steps to adjust

  lcd_key = read_LCD_buttons();
  if (millis() - x > time) {   
    impulseACTION();
  }

  switch (lcd_key)              // in order to pressed button do something         
  {
  case buttonSTART:             // to start an impulse immediately
    {                         
      impulseACTION;
      break;
    }
  case buttonRANGE:             // select range of adjustion
    {
      range = range + 1;
      if (range == 2) {
        range = 0;
      }
      delay(wait_after_key);
      break;
    }
  case buttonUP:
    {
      if (range == 0) {          // big step up
        time = time - SCHRITT;
      }
      else {                     // small step up
        time = time - schritt;
      }
      delay(wait_after_key);
      break;
    }
  case buttonDOWN:
    {
       if (range == 0) {     
        time = time + SCHRITT;
      }
      else {
        time = time + schritt;
      }
      delay(wait_after_key);
      break;
    }
  case buttonTAP:                // for synchronizing speed to music
    {
      tap_counter = tap_counter + 1;

      if (tap_counter == 1) {
        y = millis();
      }
      if (tap_counter == tap_max) {
        time = (millis() - y) / (tap_max - 1);
        tap_counter = 0;
        impulseACTION();
      }
      delay(wait_after_key);
      break;
    }
  case buttonNONE:
    {
      break;
    }
  }
}


Bin soweit zufrieden, das Gerät macht, was es soll und die Synchronisation zu Musik gelingt schnell.
Einfach mittels buttonTAP Tempo vorgeben und dann nur noch feinjustieren.

Ich werde morgen noch die zeitliche Auflösung durch zählen von Microsekunden verbessern.

Was noch nicht optimal ist, ist die Funktion von buttonSTART: warum trotz Aufruf von impulseACTION nicht immer sofort ein Blitz ausgegeben wird, verstehe ich nicht.
Ist momentan mehr eine Gefühlssache, den Startpunkt richtig zu erwischen.

Jeder Hinweis dazu und auch grundsätzliche Kritik am ersten Code seit vielen Jahren ist ausdrücklich erwünscht und willkommen!

Beste Grüße

Helmuth





Udo Klein

Quote

@Udo Klein: Tolle Sachen baust Du da, danke für die Links. Als ich Deine Landelicher für den Quadrocopter gesehen habe, musste ich spontan an den LM3914 denken (Dot/Bar Display Driver, kaskadierbar), Datenblatt hier: http://www.ti.com/lit/ds/symlink/lm3914.pdf


Danke für die Blumen. Nur wieso kommt jeder auf die "naheliegende" Idee irgendwelche Chips zu kaskadieren und keiner merkt, dass ein Arduino alleine das ohne weiteres könnte? Es gibt ja nur sehr wenige verschiedene Zustände und die könnte ich direkt treiben. Nur habe ich eben ziemliche viele Arduinos und Blinkenlight Shields sowieso da. Der Punkt ist nur zu zeigen, dass man einen Ausgabepin trotzudem noch gleichzeitig für Eingaben benutzen kann wenn man es geschickt anstellt.
Check out my experiments http://blog.blinkenlight.net

Helmuth

Hi Udo,

wie gesagt, es kam mir einfach in den Sinn.

Quote
Nur wieso kommt jeder auf die "naheliegende" Idee irgendwelche Chips zu kaskadieren und keiner merkt, dass ein Arduino alleine das ohne weiteres könnte?


Also ich kam auf die Idee, weil ich mit "irgendwelchen Chips" mehr Erfahrung habe, als mit den Möglichkeiten des Arduino. Und für Landelicht und Knight Rider Effekt reicht ja eine Dot Anzeige. Habe nicht behauptet, das sei besser oder sonstwas.

Und wenn man auf einem Sack voll "ziemliche viele Arduinos und Blinkenlight Shields" sitzt, kann man natürlich auf andere Ideen kommen.  :)

Quote
...wenn man es geschickt anstellt...


Ja, da wird wohl noch ein bisschen Zeit verstreichen, bis ich Deinen Code komplett verstehe...und mich dann auch geschickt anstellen kann...

Beste Grüße

Helmuth




Udo Klein

Quote

Und wenn man auf einem Sack voll "ziemliche viele Arduinos und Blinkenlight Shields" sitzt, kann man natürlich auf andere Ideen kommen.  smiley


Eben. Der limitierende Faktor sind die Arduinos. Ich glaube im Moment habe ich ~9 Stück. Bei den Shields hingegen sitze ich ja direkt an der Quelle ;)
Check out my experiments http://blog.blinkenlight.net

Go Up