Go Down

Topic: Arduino-Keyboard (Read 986 times) previous topic - next topic

Homy

Hallo!

Ich hab folgendes vor: Mit 12 Tastern und einem Piezo-Buzzer möchte ich mir ein kleines 1-Oktav-Keyboard basteln. Mit der Tone-Funktion kann man ja ganz einfach bestimmte Töne erzeugen. Daher dachte ich mir, dass das eigentlich relativ leicht zu coden sein müsste, jetzt habe ich aber ein komisches Problem:

Ich hab die Schaltung für einen Taster auf dem Breadboard augebaut. Schreibe ich den Code für einen einzigen Taster, ist alles in Ordnung. Schreibe ich jedoch den Code für den 2. Taster (siehe auskommentiertes) dazu, verursacht der Piezo-Buzzer mit dem selben ersten Taster einen anderen (viel zu hohen) Ton. D.h. der zusätzliche Code hat irgendwie einen Einfluss auf den Codeteil der davor einwandfrei funktioniert hat. Wie kann das sein? Hat da vielleicht jemand eine Idee? Steh gerade irgendwie aufm Schlauch...:/

Code: [Select]

int speakerPin = 9;
int taster1 = 2;
int taster2 = 3;

void setup() {
pinMode(speakerPin, OUTPUT);
pinMode(taster1, INPUT);
pinMode(taster2, INPUT);
digitalWrite(taster1, HIGH);  // pullup-Widerstände
digitalWrite(taster2, HIGH);

}
void loop() {
  if (digitalRead(taster1) == LOW) {
    tone(speakerPin, 400);
  }
  else {
    noTone(speakerPin);
  }
//    if (digitalRead(taster2) == LOW) {
//    tone(speakerPin, 500);
//  }
//  else {
//    noTone(speakerPin);
//  }
  }

-Holger-

Servus,

Wenn du z.B. den 2. button drückst:
Im ersten if kommst du immer in den else-zweig mit notone, im zweiten if in den tone-teil.
Das schaltet den piezo ganz schnell an und aus und an und aus und ... Naja ;)

Notone willst du nir machen, wenn KEIN Button gedrueckt wird.

uwefed

Für die Erklärung von -Holger- hab ich etwas gebraucht um es zu verstehen.

Jede nicht gedrückte Taste schaltet den Ton sofort wieder aus, weil im else Teil noTone(speakerPin); steht.
Du mußt die Tastaturkontrolle auf Zustandsänderung umschreiben und beim Drücken eines Tasters den Ton einschalten und beim loslassen den Ton ausschalten.

Grüße Uwe

Homy

aaah ja ich verstehe was ihr meint, daran habe ich gar nicht gedacht. Dann wird der Code wohl doch ein kleines bisschen aufwändiger ;)

Vielen Dank euch beiden!

mkl0815

#4
Dec 31, 2012, 12:02 pm Last Edit: Dec 31, 2012, 02:51 pm by mkl0815 Reason: 1
Kleiner Vorschlag, um Deinen Code zu vereinfachen. Du kannst ja Deine 12 Taster an die Pins 2 bis 13 anschliessen, dann bleiben 0 und 1 für die serielle Schnittstelle frei. Zusätzlich würde ich die Taster "LOW-aktiv" verwenden, also mit dem internen PullUp Widerstand, damit sparst Du dir die Widerstände an den Tastern. Die Taster schalten dann das Pin gegen Masse und liefern ein HIGH wenn sie nicht gedrück sind und ein LOW wenn sie gedrückt wurden.

Die Pins 0 bis 7 werden durch den PORTD abgebildet, auf den man direkt zugreifen kann. Ebenso die Pins 8 bis 13, die durch den PORTB abgebildet werden. Siehe http://www.arduino.cc/en/Reference/PortManipulation
mit einem
Code: [Select]

unsigned int input =(( PORTD & 0x3F ) << 8) + ( PORTB & 0xFC );

Bekommst Du einen 16 bit Wert der alle gedrückten Taster repräsentiert. In einem switch() - case Block kannst Du das dann super auswerten.
Was macht die o.g. Zeile:
unsigned int definert eine vorzeichenlose 16bit Zahl
( PORTD & 0x3F ) << 8 ) liest den kompletten PORTD (Pin 8 bis 13) aus und blendet die obersten zwei Bits aus, da die keine Input-Pin Daten enthalten und mit dem "& 0x3F" sicher auf 0 gesetzt werden. Anschliessend wird mittles Bit-Shift der Wert um 8 Bit nach links geschoben.
+ ( PORTB & 0xFC ); hier wird der Port B (Pin 0 bis 7) ausgelesen und durch das & 0xFC die untersten beiden Bits (Pin 0 und 1) ausgeblendet. Dieser Wert wird zum vorherigen Wet addiert, also in den untersten 8 Bit des 16 bit Wertes eingefügt.

Homy

wow ok das muss ich mir erstmal in Ruhe durchlesen und verstehen ;)
danke für den Tip!

mkl0815

Ok, kleine Korrektur. Wenn man schon Vorschläge macht, dann wenigstens korrekt  :smiley-eek:
Die Ports PORTB und PORTD sind die Output-Register und damit für Taster leider kompletter Quark. PINB und PIND sind die passenden Input-Register.
Mit folgendem Programm kann man das Ganze schon mal testen:
Code: [Select]


void setup() {
  Serial.begin(9600);
  //Pin 2 bis 13 als Eingang mit aktiviertem PullUp setzen
  for (int i = 2; i<=13; i++)
     pinMode(i,INPUT_PULLUP);
}

void loop() {
  //Alle Eingänge einlesen
  unsigned int input =(( PINB & B00111111 ) << 8) + ( PIND & B11111100 );
 
  Serial.println(input,BIN);
  delay(100);
}

Bei meinem kleinen Duemilanove Clone habe ich leider das Problem mit dem Pin 13 und der daran angeklemmten LED. Diese zieht anscheinen über ihren Vorwiderstand das Pin bereits gegen Masse, daher ist Pin13 immer LOW. Ist das beim Uno auch so? Ich vermute mal ja.
Ansonsten liefert das Testprogramm die binäre Darstellung der Pins 0 bis 13. Zieht man nun eines der Pins auf Masse, sieht man die entsprechende Veränderung in der Ausgabe.

Falls das Pin 13 auch beim Uno ein Problem ist, kann man stattdessen die Pins 0 und 1 mit verwenden. Allerdings hat man dann keine einfache Debugmöglichkeit mehr, da man die serielle Schnittstelle blockiert. Wenn allerdings keine Datem vom PC empfangen werden müssen, kann man einfach das RX (Pin 0) verwenden und auf Pin 1 (TX) trotzdem Ausgaben an den Rechner senden.

Homy

ich hoffe du bist mir nicht böse, aber ich habs jetzt erstmal auf "herkömmliche" Weise probiert  :smiley-red:
werd mich deinem Lösungsansatz aber aufjeden Fall auch mal widmen, habe mich bisher noch nie mit der seriellen Schnittstelle beschäftigt.

hier mal mein code den ich gebastelt habe; funktioniert für 2 Taster wunderbar und sollte dann eigentlich auch für mehrere funktionieren:

Code: [Select]

int speaker = 9;
int taster[] = {2, 3};
boolean lastState[] = {false, false};
boolean state[] = {false, false};
int frequencies[] = {400, 500};

boolean tasterCheck(int i) {
  if(digitalRead(taster[i]) == LOW) {
    return true;
  }
  else {
    return false;
  }
}

void setup() {
pinMode(speaker, OUTPUT);
   for(int i = 0; i < 2; i++){
  pinMode(taster[i], INPUT);
  digitalWrite(taster[i], HIGH);
  }
}


void loop() {
  for(int i = 0; i < 2; i++){
    state[i] = tasterCheck(i);
    if(state[i] != lastState[i]){
      tone(speaker, frequencies[i]);
    }
  lastState[i] = state[i];
  }
 
  if(state[0] == false && state[1] == false){
    noTone(speaker);
  }   
}


mkl0815

Wieso sollte ich böse sein? Ich wollte nur eine weitere Möglichkeit aufzeigen, wie man an die Daten der gedrückten Tasten kommt, aber niemanden zwingen meine Lösung zu verwenden.  :)
Also alles gut! Das Du das Abfragen in einzelne Funktionen gekapselt hast sorgt doch genau so für aufgeräumten Code und wirklich zeitkritisch ist Deine Anwendung auch nicht.
Prost Neujahr,
Mario.

Go Up