Hallo, ich bin dabei einen (Ersatz-)Controller für mein MIDI Keyboard zu basteln. Der Prototyp auf einem Breadboard und mit einem Arduino uno r3 hat 1A geklappt, alle Tasten wurden richtig erkannt und die zugehörigen MIDI Daten korrekt ausgegeben. Nun habe ich zwecks Umsetzung des Projekts die Schaltung auf eine Streifenrasterplatine übertragen (und auch alles ggf richtig durchtrennt) und verwende einen Teensy++2 (weil der mehr IO Ports hat und deutlich günstiger als ein Arduino MEGA und noch dazu kompakter ist). Soweit so gut, nur leider "spinnen" die Tasten nun, halte ich eine Taste gedrückt wird sie, scheinbar zufällig, immerwieder neu ausgelöst (MIDI Note On und Note Off werden korrekt gesendet - nur halt sinnlos, weil ich halte die Taste ja gedrückt), seltsamerweise werden teilweise auch benachbarte Tasten und eher selten weiter entfernte Tasten ausgelöst. Für mein Empfinden scheint der Pegel bei gedrückter Tastete nicht gut gehalten zu werden oder die Leitungen stören sich irgendwie gegenseitig. Habe aber leider kein Ozioloskop zum nachsehen :(. Einen Softwarefehler kann ich eigentlich ausschließen, da ich lediglich die Portnummern geändert habe und sonst den gleichen Code verwende wie mit dem Ardino, wo ich nie solche Probleme hatte. Wo kann ich nun am Besten mit der Fehlersuche anfangen? Ich bin etwas ratlos ... die Lötstellen sehn eigentlich alle gut aus und durchgemessen habe ich das ganze auch schon ohne etwas auffälliges zu finden. Meine Vermutung ist momentan, dass der Teensy vielleicht etwas empfindlicher auf Umwelteinflüsse reagiert? Was könnte ich dagegen tun? ist das überhaupt realistisch bei 5V? Im angehängten Schaltplan ist der interessante Teil rot umrahmt. Dort befindet sich das Shiftregister, das die 8x20 Matrix für die Klaviatur (2 Buttons pro Taste) treibt und die 20 PullDown Widerstände sowie der Teensy (die 2x20 Pins in der Mitte). EDIT: UPS da ist noch ein kleiner Fehler im Schaltplan .. "in Echt" sind die PullDown Widerstände natürlich alle an GND angeschlossen, habe gerade noch mal nach gesehen. ... wäre ja auch zu schön, wenn die Antwort so einfach wäre ;) schon mal danke im Voraus, Andreas
Ich vermisse im gesamten Plan die Entkoppelkondensatoren. Zu deinen Gunsten hoffe ich, das da welche eingebaut sind (am besten an jedem IC ein 100nF). CMOS reagiert zwar recht gutmütig, erzeugt aber Umschaltspitzen, die unbedingt abgefedert werden sollten. Ebenso an den Midi-Out Buchsen, da schadet auch ein etwas dickerer Elko im 10-100µF Bereich sicher nicht. Übersprechen zwischen den Leitungen ist ausgeschlossen? Dem Tennsy schadet es mit sicherheit auch nicht, wenn seine Versorgung nochmal extra entkoppelt wird.
Hallo Matthias, ich muss zu meiner Schande gestehen, dass ich Kondensatoren zur Zeit noch so ein wenig "ausblende" (das ist auch mein erstes größeres Projekt und ich komme eher aus der Informatik als aus der E-Technik ;) ). Alle Kondensatoren die ich verwendet habe sind auch auf dem Schaltplan - d.h. ganze 3 Stück, die sind alle jweils vor den Shiftregistern (bei zweien davon, einer für 2 Register, da diese hintereinander geschaltet sind) und haben 1µF. Das ist auch das einzige Bauteil, was ich (neben dem Teensy) gegenüber dem Breadboard Prototypen ausgetaucht habe. Dort hatte ich 10nF Keramikkondensatoren und nun auf der Platine habe ich 1µF Elkos. Die sind auch eigentlich nur dort, da ich es mal so in einem Tutorial zu ShiftRegistern gelernt habe - aber nach kurzen googlen hab ich den Sinn der Entkoppelkondensatoren erkannt ;) d.h. ich sollte auch jeweils vor die Vcc und GND Pins der ShiftRegister und Multiplexer einen Kondensator 100nF packen - verstehe ich das richtig? und die aktuell schon eingebauten entkoppeln so mit das Latch-Siganal für die Register? Zum Übersprechen, also ausschließen kann ich das nicht (mangelns Wissens, wie ich es sicher überprüfen kann). Lediglich das Flachbandkabel für die Treiber der 8x20 Matrix käme da doch in Frage oder? - das waren auf dem Breadboard nur einzelne Kabel. Allerdings kommen die Signale ja auch via Flachbandkabel ... Erklärung zum Bild: Untern in der Mitte, der Teensy++ 2, links und rechts davon, jeweils 8 + 8 und 12 + 8 Anschlüsse für die 8x20 Matrix (aufgeteilt auf 2 Hälften des Keyboards. Die PullDown Widerstände sind, etwas schwer zu erkennen, zwecks Platzersparnis als Widerstandsnetzwerke ausgelegt.
Andreas H. schrieb: > d.h. ich sollte auch jeweils vor die Vcc und GND Pins der ShiftRegister > und Multiplexer einen Kondensator 100nF packen - verstehe ich das > richtig? Ja, bitte. Damit werden sich schon einige Probleme von alleine lösen. Rund um den Teensy auch, also an Vcc und Gnd. Andreas H. schrieb: > Allerdings > kommen die Signale ja auch via Flachbandkabel Gerade Flachbandkabel sind beste Kandidaten für Übersprechen und über längere Strecken recht gute Koppelkondensatoren, wenn nicht zwischen jedem Signal ein GND zwischengelegt ist. Vermeiden kannst du das nur mit entsprechend niederohmigen Signalen oder eben durch abwechselnde Signal-GND-Signal-GND Belegung. So ist das z.B. bei IDE-UDMA Kabeln auch gelöst.
Okay, das mit den Kondensatoren werde ich tun. Nochmal zum Flachbandkabel. Sind diese 10cm die ich da verwende schon zu viel? ich würde ja eher denken nein - zumal ja beim Treiber maximal eine der 8 Leitungen aktiv ist (also +5V). Und der original Controller (der leider hinüber ist) hatte ja dieselben Flachbandkabel von der Klaviatur kommend (die sind so ca 50cm lang). Aber vermutlich werden die Kondensatoren helfen, dass würde auch das eine oder andere merkwürdige Verhalten beim Lesen der analogen Werte für die Potis erklären :D Ich berichte wenn es Neues gibt - danke so weit schon mal!
Andreas H. schrieb: > nur leider "spinnen" die Tasten nun Wenn die Entprellsoftware ordentlich funktioniert, darf das nicht auftreten. Gegebenenfalls von 2-fach auf 3- oder 4-fach Abtastung erhöhen. Allerdings ist der 595 ein Problem. Wenn man mehrere Tasten drückt, können dessen Ausgänge kurzgeschlossen werden. Daher mit jedem Ausgang noch eine Diode in Reihe. Es sei denn, in der Tastatur sind schon Dioden integriert.
@Peter Nein entprellen ist hier (leider/glücklicherweise) kein Problem, Dioden sind ebenfalls schon in der Klaviatur integriert. Das sind auch keine richtigen "Taster" ich weiß nicht wie die Teile heißen, solche leitenden Gumminoppen die auf das PCB drücken und einen Kontakt herstellen. Davon jeweils 2 pro Taste, man muss die Zeitdifferenz zwischen den beiden Kontakten je Taste messen um ermitteln zu können, wie "stark" die Taste gedrückt wurde - es geht hier ja nicht um ein Spielzeug Keyboard ohne Anschlagsempfindlichkeit ;) Und am Prototypen klappte es ja auch einwandfrei ohne Entprellung - allerdings hatte ich da immer nur die einzelnen Komponenten des Controllers geteste und nicht alle auf einmal, weshalb sich das mit dem entkoppeln sehr vielversprechend anhört - nur leider muss ich noch warten bis die Kondensatoren da sind ... so viele hatte ich davon nicht.
Andreas H. schrieb: > allerdings hatte ich da immer nur die einzelnen Komponenten des > Controllers geteste und nicht alle auf einmal Also hast Du doch die SW geändert und nicht nur die Pinzuweisungen. Teste doch erstmal das gleiche Programm, wie von Arduino. Andreas H. schrieb: > man muss die Zeitdifferenz zwischen den beiden > Kontakten je Taste messen Welchen Meßbereich brauchst Du denn dafür? Es kann sein, daß der AVR damit schon voll ausgelastet ist und keine weiteren Tasks mehr kann.
@Peter: Das habe ich bereits getan, ich hab das alte Programm vom Prototyp-arduino genommen und lediglich die PIN nummern angepasst (und auch im "richtigen" Programm ist das Auslesen der anderen Komponenten zur zeit auskommentiert). Der Messbereich liegt etwa bei 1,5 bis 300ms, das klappt also ganz gut, ich habe auch schon beim Prototyp testweise delays von mehreren ms eingearbeitet um das Auslesen andere Komponenten zu simulieren - hat alles trotzdem super geklappt ;) Die Tasten der Klaviatur werden dabei auch deutlich häufiger ausgelesen als die anderen Komponenten. Außerdem hätte ich ja dann eher das problem, dass die Tasten nicht ausgelöst werden, als dass sie zuoft ausgelöst werden, oder? (und vorallem wie liese sich damit erkären, das andere Tasten (die ich gar nicht berühre) auslösen?). Was ich noch mal Testen werde ist den Arduino an die eingelöteten ICs anzuschließen, um zu sehen ob er dort die gleichen Probleme wie der Teensy hat (wenn alles nicht auf dem Breadboard sondern auf der Platine steckt).
Also, ich habe gerade mal den Arduino anstelle des Teensy an die Platine angeschlossen und dort auch Probleme - allerdings nicht die selben, wärend der Teensy die Noten wild wiederholt hat neigt der Arduino eher dazu gar nicht zu reagieren sondern lösst nur sehr selten aus. Andersherum habe ich nun auch mal den Teensy an den Breadboard Prototypen angeschlossen. Dort hat nach anpassen der Pins wieder alles geklappt wie es soll. Mir ist aber auch aufgefallen, dass der Teensy deutlich empfindlicher auf Umgebungseinflüsse reagiert, den Arduino kann ich im Betrieb berühren wo ich will und alles klappt einwandfrei, wenn ich dem Teensy allerdings zu nahe komme werden auch wieder wild Noten ausgelöst (wenn ich die entsprechenden Pinlötstellen berühre) - demnach sind die Entkoppelungskondensatoren wohl die richtige Lösung. Wenn sie eingebaut sind werde ich mich nochmal melden und berichten oder weiter fragen ;).
So die Kondensatoren sind nun da und die nötige Zeit auch ;) Aber bevor ich nachher "doppelt" Löten muss, hier nun mal wie ich die ICs bestücken würde. Ist das so ok? Im Anhang hab ichs mal exemplarisch für den 4051 und 595 gezeichnet. Wie sieht es mit dem MR und OE vom 595 aus - das ist ja keine Versorgungsspannung an den Pins, demnach sind dort auch keine Entstör/Abblockkondensatoren nötig oder? Ansonsten müssen die Kondensatoren ja physikalisch möglichst nah an die Pins und es darf keine "Schleichwege" am Kondensator vorbei geben. Muss ich sonst noch auf etwas achten? Danke schon mal!
Andreas H. schrieb: > Ist das so ok? Es schadet sicher nicht, zwei Entkoppelkondensatoren pro IC zu setzen, aber nötig ist es auch nicht. Einer pro IC ist durchaus ok, wenn du sie nahe am IC plazieren kannst. Wichtig ist auch, das die Versorgungsleitungen keine superdünnen Drähtchen sind, sondern ruhig ein wenig stärker ausgelegt sein sollten, als reine Signalleitungen. Sehe für die Schaltung auch noch dicht am Teensy einen Platz für einen mittleren (gepolten) Elko der 10µF-100µF Klasse über der Betriebsspannung vor. Wenn der Teensy so eine 'Dreckschleuder' ist, schadet es nicht, seine Störimpulse vom Rest der Schaltung fernzuhalten.
Soo .. also ich habe jetzt die ICs mit je 2 Kondensatoren (100nF) bestückt (das war in den meisten Fällen einfacher als nur einen zu nehmen.) Der Teensy hat einen 100µF Elko bekommen. gebracht hat es aber leider nur bedingt etwas. Einige Tasten (hauptsächlich die am weitesten vom Anschlusskabel entfernten) funktionieren jetzt fehlerfrei (allerdings erkenne ich noch kein zuverlässiges Muster, normalerweise verhielten sich die Tasten in 8er Blöcken immer gleich (beim spinnen), aber diesmal sind die Oberen 26 ok - also 2 "zu viel". Das Flachbandkabel des Treibers zur 2. Wannenbuchse habe ich probeweise auch mal entfernt - das brachte aber keine Änderung. Was wäre denn kein "superdünnes" Drätchen? - ich habe bisher für alles AWG 26/28 verwendet, die Flachbandkabel sind AWG 30/32. Ansonsten hätte ich noch Klingeldraht. Nachher update ich noch mal den Schaltplan und das Foto - aber vielleicht gibts ja auch jetzt schon weitere Verbesserungsvorschläge :)
Mit den Dioden in der Tastaturverharfung und dem Flachbandkabel bist du natürlich nicht so auf der pegelsicheren Seite. Deswegen kann es durchaus hilfreich sein, zusätzlich zu den internen Pullups des AVR auch externe, recht niederohmige hinzuzufügen, so in der Gegend von 3k3 bis 10k, evtl. direkt an den Ports des Teensy. Gut geeignet sind sogen. Widerstandsmatrizen wo z.B. 8 oder 10 Widerstände des gleichen Typs schon mit einem gemeinsamen Pol herausgeführt werden. Auf der Punktrasterplatte wird dir nichts anderes übrigbleiben, als die von unten an den IC Sockel zu löten, aber einen Versuch ist es mit Sicherheit wert. Flachbandkabel sind nun mal sehr gute Koppelkondensatoren und führen schnell zu Übersprechen. Andreas H. schrieb: > Was wäre denn kein "superdünnes" Drätchen? Das bezog sich auf die Betriebsspannungsleitungen. Auf meinen Punktrasterprojekten nehme ich z.B. starren Kupferdraht mit ca. 0,5 mm für Masse und Vcc und die Signalleitungen mache ich mit CuL 0,15mm Fädeldraht.
Hmm, ich verwende schon Wiederstandsmatrizen mit 10k ;) ... das sind allerdings Pulldowns, vor den lesenden Pins des Teensys ... ich werd mal versuchen, ob ich durchs Tauschen der Litzen durch Draht an den Versorgungsleitungen etwas verbesser kann. Anbei der aktuelle Schaltplan und ein aktuelles Foto (die Klinkenbuchsen sind übrigens noch nicht angeschlossen - nur als Info) Kann es vielleicht auch sein, dass sich irgendwo ein ungewünschter Schwingkreis gebildet hat? Auf dem defekten Originalboard (das ich allerdings keineswegs 1:1 nachbaue, sind auch noch ein paar Induktivitäten drauf), habe davon auch mal ein Bild angehängt ... allerdings wurde da schon hier und dort ein Teil recyclet ;)
Also das Austauschen der Litzen durch Drähte (bei den Versorgungsleitungen) hat leider nichts gebracht, kein Unterschied zu davor, noch immer die gleichen Probleme.
Andreas H. schrieb: > sind auch noch ein paar > Induktivitäten drauf Das ist am DC Eingang eine stromkompensierte Drossel und das Teil um U19 scheint ein kleiner Schaltregler mit Speicherdrossel zu sein. Bist du dir denn mit deiner Stromversorgung sicher? Liefert die eine saubere Speisespannung? Hast du ein Oszi in Reichweite? Denn so langsam wirst du eines brauchen. An den Tasten mit den meisten Störungen könnte es sich auch bemerkbar machen, wenn du die Flachbandkabel auseinandertrennst.
Hmm einen Oszi könnte ich aller frühstens Dienstag nutzen - allerdings kann ich den nicht mitnehmen und ich wollte ungern mit einer ausgebauten 76er Klaviatur Busfahren :D da könnte ich nur schauen, wie sich das Board an sich verhält. Was würde ich denn da am besten so alles überprüfen? ... Also momentan kommt die Stromversorgungen noch über USB (also über die Buchse des Teensys, die sollte ja eigentlich ganz ok sein. Irgendwie wundert es mich doch sehr, dass das auf dem Breadboard so gut funktioniert hat - hätte nie gedacht, dass sich die ICs gegenseitig so stören können ... So ich habe noch ein bisschen nachgemessen / ausprobiert (dabei habe ich die Pins jeweils DIREKT mit einem Jumperkabel verbunden - also hier können auch keine Störungen aus dem langen Flachbandkabel zur Klaviatur aufgetreten sein) ... und zwar welche Kanäle probleme machen und welche nicht, dazu das Bild im Anhang. Die grünen Kanäle klappen wunderbar, die gelben nur in verbindung mit Treiber[0] sonst Störungen und die blauen haben immer Störungen. Übereinanderliegende Pärchen sind jeweils für eine Taste (da ja pro Taste 2 Taster existieren - also habe ich jeweils einen Treiberpin und ein Pärchen zum Testen verbunden). In der Mitte wäre natürlich der Teensy, den hab ich nur der Übersichthalber weggelassen. Die Treiberpins kommen von dem 1. Shiftregister links des Teensys, wobei Treiber[0] = Q0 Das Flachbandkabel das die Treiberpins verbindet kann es nicht gewesen sein, das habe ich jetzt auseinandergetrennt.
Andreas H. schrieb: > Was würde ich denn da am besten so alles > überprüfen? Wenn du die Klaviatur nicht mitnehmen kannst, bleibt dir nur, die Multiplexsignale und die Rückleitung mal roh zu prüfen, d.h., ob auf den Rückleitungen die Mux Signale liegen per Übersprechen. Andreas H. schrieb: > Die grünen Kanäle klappen wunderbar, die gelben nur in verbindung mit > Treiber[0] sonst Störungen und die blauen haben immer Störungen. Es ist also ein gewisses System drin. Du könntest jetzt versuchsweise mal die Multiplex Rate senken und/oder die Tastenauswertung so verändern, das öfter auf Plausibilität ('ist die Taste auch wirklich gedrückt') geprüft wird. Andreas H. schrieb: > ... Also momentan kommt die Stromversorgungen noch über USB (also über > die Buchse des Teensys, die sollte ja eigentlich ganz ok sein Aaarghh - der Teensy verseucht damit die Restschaltung. Ich bin mir auch wirklich nicht sicher, ob der Kleine die harten Impulse der Mux Treiber und Analogschalter über das Board glätten kann. Probier auch mal, den Teensy nicht aus dem Rechner zu speisen, sondern nur über einen Hub mit Netzteil, der vom Rechner getrennt ist. USB Versorgungen sind oft mit Rechnerpulsen verseucht. Andreas H. schrieb: > Hmm einen Oszi könnte ich aller frühstens Dienstag nutzen Wenn du auch zukünftig komplexere Projekte bauen willst, kann ich dir nur empfehlen, auf eines zu sparen. Du wirst es nicht bereuen und ein gutes (kann auch analog sein) Oszi wird dich viele Jahre begleiten. Ein gebrauchtes 2-Kanal von Hameg o.ä. kostet nicht viel beim Netzauktionshaus und ist extrem hilfreich. Ich prophezeie dir, das du mit einem Oszi schon längst wüsstest, wo der Hase im Gewürz liegt.
Matthias Sch. schrieb: > Es ist also ein gewisses System drin. Du könntest jetzt versuchsweise > mal die Multiplex Rate senken und/oder die Tastenauswertung so > verändern, das öfter auf Plausibilität ('ist die Taste auch wirklich > gedrückt') geprüft wird. also ich habe jetzt mal in den Multiplex Loop ein delay von 50µs pro Schleifendurchlauf eingefügt - und jetzt wirds interessant - alles was an der rechten Buchse angeschlossen ist (die oberen 4 Oktaven) klappt einwandfrei (außer dem zulangen Delay natürlich). Alles was links angeschlosse ist hat aber Störsignale, auch die 2 Pins, die vorher (ohne Delay) richtig funktioniert haben. Ab etwa 35µs kommen die Störungen dann auch auf den oberen Oktaven wieder. Auf den Unteren bleiben die Störungen selbst bei 3ms noch erhalten, jedoch werden sie deutlich langsamer (bzw der Abstand zwischen 2 falsch ausgelösten Noten wird größer). Allerdings sind die Störungen nicht (immer) regelmäßig sondern eher zufällig - also es ist nicht so, dass sie in einer festen Frequenz auftreten. Das mit der Plausabilitätsprüfung ist so eine sache, bei MIDI wird ja ein Signal gesendet, wenn die Taste gedrückt wird und eines wenn sie wieder losgelassen wird - zwischen drin wird nichts gesendet. Außerdem in der Frequenz wie die Fehlauslösungen auftretten glaube ich nicht, dass man das softwaremäßig lösen oder auch nur mildern kann. Ohne das Delay erzeugen die Fehlauslösungen ja fast schon einen eigenen Ton durch die hohe Frequenz des Auftretens - ähnlich wie die Selbstoszilation bei Filtern - und es wir ja auch nicht weniger mit der Zeit sondern bleibt konstant (aber zufällig - also keine feste Frequenz). ... ich werds dann jetzt wohl mal mit nem Oszi versuchen - ich habe ja mittlerweile herausgefunden, dass ich die Störungen auch ohne Klaviatur hab, was den Transport ja enorm erleichtert :) An der Stromversorgung lag es übrigens nicht, habe den Teensy über ein USB-Netzteil von ner Digicam angeschlossen, das hatte aber keinerlei erkennbare Auswirkungen.
So jetzt hab ich ein Oszi (OWON SDS7102) zur Verfügung das ich auch mit nehmen konnte. Ich habe erstmal hier und dort etwas herumgemessen und bis auf eine Sache eigentlich nichts gefunden was mich verwundert hätte (wobei ich zuvor aber auch noch nie mit einem Oszi gearbeitet hab und folglich auch nicht weiß, was man vielleicht sonst noch so messen könnte, also Vorschläge sind willkommen ;) ). Kommen wir zu der einen Sache (siehe dazu Screenshot). Kanal 1 entspricht dem Q7, Kanal 2 dem Q0 des Shiftregisters der 8x20 Matrix, also dem Treiber. Die links zu sehenden Pulse sind wie erwartet: gleich lang und direkt aufeinander foglend. Bei der 2. Serie erkennt man aber deutlich, dass der Puls auf Q7 etwa doppelt so lang ist wie er sein sollte. Vorallem irritiert mich dieses Verhalten, weil das ja der Treiber ist, der eigentlich nur sturr in eine Schleife nach einander ein Bit durchs Register schiebt (bzw. je 8 Bits, aber die 1 ist immer eins weiter). Das Phanomän beschränkt sich auch ausschließlich auf Q7 alle anderen Pulse haben immer die richtige Länge (soweit ich das beurteilen kann). Das Auftreten schein mir auch zufällig zu seien. Einzige regelmäßigkeit, es scheint nie 2 dieser langen Pulse direkt hintereinander zukommen, es ist offensichtlich immer mindestens ein "richtiger" dazwischen. Und der Fehler tritt nur auf, wenn ein Treiber Pin mit einem Pärchen der "blauen" Pins (auf der Abbildung vom Post 15.06.2013 22:37) verbunden ist. Verbinde ich ein "grünes" Pärchen, nur einen Pin oder gar keinen Pin habe ich den Fehler nicht. Die eigentlich Störung (mehrfaches Auslösen einer MIDI Note) kann ich mir damit allerdings auch noch nicht erklären, da die nachfolgenden Pulse ja verschoben sind, somit kann ja nicht falsch sondern nur "später" ausgelesen werden, was ja eigentlich kein Problem sein sollte.
Noch ein Update, der Data Pin des Shiftregisters zeigt ein ähnliches Verhalten wie Q7. Im Screenshot Kanal 1 der Data Pin, Kanal 2 der Q7.
Ich kenne deine Software nicht, aber irgendwann muss ja der MC auch was anderes machen, als Pulse für die Schieberegister zu produzieren. Lass als Hilfe mal in der Multiplexroutine noch einen Ausgang des MC mittoggeln, damit du weisst, wann die Routine aktiv ist und leg dir diesen Puls auf einen Oszi Kanal. Einen Kurzschluss in der Klaviatur oder im Anschlusskabel kannst du grundsätzlich ausschliessen? Sieht mir allerdings auch nicht so aus, sonst würden die Pegel anders verlaufen.
Andreas H. schrieb: > ... das sind allerdings Pulldowns, vor den lesenden Pins des Teensys ... hm... dann hast du aber die internen Pullups abgeschaltet, oder? gruß Christopher
Christopher B. schrieb: > Andreas H. schrieb: >> ... das sind allerdings Pulldowns, vor den lesenden Pins des Teensys ... > > hm... dann hast du aber die internen Pullups abgeschaltet, oder? > > gruß > Christopher Ich formulier es mal so: ich habe sie nicht eingeschaltet. Aber da ich ja im Moment das ganze noch mit dem Arduino Framework programmiert habe sollten die Pullups aus sein, wenn sie nicht explizit angeschaltet sind.
Ok, gut. Aber deine Schalter schalten schon auf HIGH, oder? Muss man ja erstmal ausschließen.
@Christopher: Was genau meinst du mit "schalten auf HIGH"? das sind Taster (schließend), die stellen ja nur eine Verbindung her. Also über den Treiber wird ein HIGH gesendet, wenn der Taster dann entsprechend geschlossen ist kann ich dann ja ein HIGH lesen (deshalb auch PullDowns). Die Taster ansich funktionieren ja auch, mit dem Prototypen auf dem Breadboard und nemm Arduino hat das ja alles super geklappt. Nur seit das ganze (mit allen Komponenten (weitere Shiftregister und Multiplexer für Analoge Signale (Potis))) auf der Streifenrasterplatine sitzt und ich den Teensy benutze gibt es Probleme. Die Software ist bis auf die Pin Nummern auch gleich geblieben. Und zur Zeit sind auch alle weitern Komponenten auskommentiert. Matthias Sch. schrieb: > Ich kenne deine Software nicht, aber irgendwann muss ja der MC auch was > anderes machen, als Pulse für die Schieberegister zu produzieren. Lass > als Hilfe mal in der Multiplexroutine noch einen Ausgang des MC > mittoggeln, damit du weisst, wann die Routine aktiv ist und leg dir > diesen Puls auf einen Oszi Kanal. Das stimmt, wobei das einzige was er sonst noch macht ist das MIDI via UART zu senden (ich hab mir auch mal den TX Pin zusammen mit Q7 angeschaut, da erkenne ich keinen Zusammenhang zwischen dem Senden und den längern Blöcken auf Q7). Die andere Messung hab ich mal in den Anhang gepackt eine Flanke bei Kanal 2 bedeutet, dass dort der Treiber wieder bei Q0 anfängt. Sonst ist da auch nichts drin in dem (main) Loop. hier mal der Quellcode (Anmerkung: debug ist false):
1 | boolean debug = false; |
2 | |
3 | const byte testPin = 31; |
4 | boolean test = false; |
5 | |
6 | /* shift registers */
|
7 | const byte clk = 4; |
8 | const byte data = 1; |
9 | const byte latch_LED = 0; |
10 | const byte latch_Buttons = 26; |
11 | const byte latch_Keys = 27; |
12 | |
13 | /* buttons */
|
14 | const byte buttons0 = 39; |
15 | const byte buttons1 = 38; |
16 | const byte buttons2 = 5; |
17 | |
18 | /* lower keys */
|
19 | const byte keys0 = 25; |
20 | ...
|
21 | const byte keys7 = 18; |
22 | |
23 | /* upper keys */
|
24 | const byte keys8 = 17; |
25 | ...
|
26 | const byte keys19 = 6; |
27 | |
28 | boolean keysRow0 = 0; |
29 | ...
|
30 | boolean keysRow19 = 0; |
31 | |
32 | /* multiplexer */
|
33 | const byte muxSel0 = 45; |
34 | const byte muxSel1 = 44; |
35 | const byte muxSel2 = 43; |
36 | const byte mux0 = A4; |
37 | const byte mux1 = A3; |
38 | const byte mux2 = A2; |
39 | |
40 | const byte shiftBits[] = {B00000001, |
41 | B00000010, |
42 | B00000100, |
43 | B00001000, |
44 | B00010000, |
45 | B00100000, |
46 | B01000000, |
47 | B10000000}; |
48 | |
49 | const byte digits[] = {SEG7_0, SEG7_1, SEG7_2, SEG7_3, SEG7_4, SEG7_5, SEG7_6, SEG7_7, SEG7_8, SEG7_9}; |
50 | |
51 | const byte keyToMidi[10][8] = { |
52 | /* 0 */ {24, 23, 22, 21, 0, 0, 0, 0}, // A0 to C1 // 0 = not available on keyboard |
53 | ...
|
54 | /* 9 */ {96, 95, 94, 93, 92, 91, 90, 89} // F6 to C7 |
55 | };
|
56 | |
57 | boolean keyPressed[8][10]; // nessesary for sending NoteOff |
58 | boolean keyInWatchList[8][10]; |
59 | unsigned long keyFirstButtonTime[8][10]; |
60 | |
61 | // sends NoteOn
|
62 | void MIDINoteOn(byte note, byte chan, byte velo) { |
63 | Serial1.write(0x90 | chan); // note on |
64 | Serial1.write(note); // note value |
65 | Serial1.write(velo); // velo |
66 | }
|
67 | |
68 | // sends NoteOff
|
69 | void MIDINoteOff(byte note, byte chan) { |
70 | Serial1.write(0x80 | chan); // note off |
71 | Serial1.write(note); // note value |
72 | Serial1.write((byte) 0); // velo |
73 | }
|
74 | |
75 | inline void processFirstButton(byte col, byte row){ |
76 | keyFirstButtonTime[col][row] = micros(); |
77 | keyInWatchList[col][row] = true; |
78 | }
|
79 | |
80 | inline void processSecondButton(byte col, byte row){ |
81 | // calculate velocity
|
82 | unsigned long timeDiff = micros() - keyFirstButtonTime[col][row]; |
83 | char velo = 847e-10 * timeDiff * timeDiff - 678e-5 * timeDiff + 136; |
84 | |
85 | if (velo < 1) { |
86 | velo = 1; |
87 | }
|
88 | if (velo > 127) { |
89 | velo = 127; |
90 | }
|
91 | |
92 | if (debug) { |
93 | Serial.print("Velocity Time: "); |
94 | Serial.print(timeDiff); |
95 | Serial.print("us Velo: "); |
96 | Serial.println(velo); |
97 | }
|
98 | |
99 | // send MIDI Note On
|
100 | MIDINoteOn(keyToMidi[row][col], 0, velo); |
101 | //MIDI.sendNoteOn(keyToMidi[row][col], 0, velo);
|
102 | |
103 | // mark key as pressed
|
104 | keyPressed[col][row] = true; |
105 | |
106 | // remove button from watch list
|
107 | keyInWatchList[col][row] = false; |
108 | }
|
109 | |
110 | // drives the 8x8(7) matrix for the LEDs and 7Segments
|
111 | void driveLEDs(byte v1, byte v2){ |
112 | digitalWrite(latch_LED, LOW); |
113 | shiftOut(data, clk, LSBFIRST, v2); |
114 | shiftOut(data, clk, LSBFIRST, v1); |
115 | digitalWrite(latch_LED, HIGH); |
116 | }
|
117 | |
118 | // drives the 8x3 matrix for the buttons
|
119 | void driveButtons(byte value){ |
120 | digitalWrite(latch_Buttons, LOW); |
121 | shiftOut(data, clk, MSBFIRST, value); |
122 | digitalWrite(latch_Buttons, HIGH); |
123 | }
|
124 | |
125 | // drives the 8x20 matrix for the keys
|
126 | void driveKeys(byte value){ |
127 | digitalWrite(latch_Keys, LOW); |
128 | shiftOut(data, clk, MSBFIRST, value); |
129 | digitalWrite(latch_Keys, HIGH); |
130 | }
|
131 | |
132 | // reads the values from the 3 4051-Mulitplexers
|
133 | void readMuxes(){ |
134 | if (debug) { |
135 | Serial.println("muxes:"); |
136 | |
137 | for(byte i = 0; i < 8; i++){ |
138 | Serial.print("("); |
139 | if (i & B100) { |
140 | Serial.print(1); |
141 | digitalWrite(muxSel2, HIGH); |
142 | } else { |
143 | Serial.print(0); |
144 | digitalWrite(muxSel2, LOW); |
145 | }
|
146 | if (i & B010) { |
147 | Serial.print(1); |
148 | digitalWrite(muxSel1, HIGH); |
149 | } else { |
150 | Serial.print(0); |
151 | digitalWrite(muxSel1, LOW); |
152 | }
|
153 | if (i & B001) { |
154 | Serial.print(1); |
155 | digitalWrite(muxSel0, HIGH); |
156 | } else { |
157 | Serial.print(0); |
158 | digitalWrite(muxSel0, LOW); |
159 | }
|
160 | Serial.print(") "); |
161 | Serial.print(i); |
162 | Serial.print("mux0: "); |
163 | |
164 | Serial.print(analogRead(mux0) >> 2); |
165 | Serial.print(" mux1: "); |
166 | Serial.print(analogRead(mux1) >> 2); |
167 | Serial.print(" mux2: "); |
168 | Serial.println(analogRead(mux2) >> 2); |
169 | }
|
170 | }
|
171 | }
|
172 | |
173 | void setup() { |
174 | pinMode(testPin, OUTPUT); |
175 | |
176 | // shift registers
|
177 | pinMode(clk, OUTPUT); |
178 | pinMode(data, OUTPUT); |
179 | pinMode(latch_LED, OUTPUT); |
180 | pinMode(latch_Buttons, OUTPUT); |
181 | pinMode(latch_Keys, OUTPUT); // <-- für die Klaviatur |
182 | |
183 | // lower keys
|
184 | pinMode(keys0, INPUT); |
185 | ...
|
186 | pinMode(keys7, INPUT); |
187 | |
188 | // upper keys
|
189 | pinMode(keys8, INPUT); |
190 | ...
|
191 | pinMode(keys19, INPUT); |
192 | |
193 | // buttons
|
194 | pinMode(buttons0, INPUT); |
195 | pinMode(buttons1, INPUT); |
196 | pinMode(buttons2, INPUT); |
197 | |
198 | // multiplexers
|
199 | pinMode(muxSel0, OUTPUT); |
200 | pinMode(muxSel1, OUTPUT); |
201 | pinMode(muxSel2, OUTPUT); |
202 | pinMode(mux0, INPUT); |
203 | pinMode(mux1, INPUT); |
204 | pinMode(mux2, INPUT); |
205 | |
206 | Serial.begin(9600); // <-- nur fürs debuging, ist aber deaktiviert (ist der Serial Port der über USB gesendet wird) |
207 | |
208 | Serial1.begin(31250); // <-- der Hardware Serial Port (der die RX, TX Pins ansteuert), hier wird das MIDI gesendet |
209 | }
|
210 | |
211 | |
212 | void loop() { |
213 | if (test) { // setzt die Testflanke |
214 | digitalWrite(testPin, HIGH); |
215 | test = false; |
216 | } else { |
217 | digitalWrite(testPin, LOW); |
218 | test = true; |
219 | }
|
220 | |
221 | // keys
|
222 | for (byte testCol = 0; testCol < 8; testCol++) { |
223 | driveKeys(shiftBits[testCol]); |
224 | |
225 | // odd = 2nd buttons; even = 1st buttons
|
226 | keysRow0 = digitalRead(keys0); |
227 | keysRow1 = digitalRead(keys1); |
228 | ...
|
229 | keysRow18 = digitalRead(keys18); |
230 | keysRow19 = digitalRead(keys19); |
231 | |
232 | if (debug || 0) { // debug ist false |
233 | Serial.print(keysRow0); |
234 | ...
|
235 | Serial.println(keysRow19); |
236 | }
|
237 | |
238 | // process 2nd buttons if the key is not yet pressed and they are in the watch list
|
239 | if (!keyPressed[testCol][0] && keyInWatchList[testCol][0] && keysRow1){ |
240 | processSecondButton(testCol, 0); |
241 | }
|
242 | |
243 | ...
|
244 | |
245 | if (!keyPressed[testCol][9] && keyInWatchList[testCol][9] && keysRow19){ |
246 | processSecondButton(testCol, 9); |
247 | }
|
248 | |
249 | // process 1st buttons
|
250 | if (keysRow0) { |
251 | if (!keyPressed[testCol][0] && !keyInWatchList[testCol][0]) { // key is not yet pressed and not in watch list |
252 | processFirstButton(testCol, 0); |
253 | }
|
254 | } else { |
255 | if (keyPressed[testCol][0]) { // key was pressed |
256 | MIDINoteOff(keyToMidi[0][testCol], 0); // send MIDI Note Off |
257 | keyPressed[testCol][0] = false; // mark key as not pressed |
258 | }
|
259 | }
|
260 | |
261 | ...
|
262 | |
263 | if (keysRow18) { |
264 | if (!keyPressed[testCol][9] && !keyInWatchList[testCol][9]) { // key is not yet pressed and not in watch list |
265 | processFirstButton(testCol, 9); |
266 | }
|
267 | } else { |
268 | if (keyPressed[testCol][9]) { // key was pressed |
269 | MIDINoteOff(keyToMidi[9][testCol], 0); // send MIDI Note Off |
270 | keyPressed[testCol][9] = false; // mark key as not pressed |
271 | }
|
272 | }
|
273 | }
|
274 | |
275 | //delay(4);
|
276 | |
277 | if (debug || 0) { |
278 | Serial.println("-----"); |
279 | delay(10); |
280 | }
|
281 | |
282 | // LEDs
|
283 | if (debug) { |
284 | for (byte i = 0; i < 3; i++){ |
285 | if (i == 0) driveLEDs(B00000001, digits[1]); |
286 | if (i == 1) driveLEDs(B00000010, digits[2]); |
287 | if (i == 2) driveLEDs(B00000100, digits[3]); |
288 | }
|
289 | }
|
290 | |
291 | // buttons
|
292 | if (debug) { |
293 | Serial.println("Buttons:"); |
294 | for (byte testCol = 0; testCol < 8; testCol++) { |
295 | driveButtons(shiftBits[testCol]); |
296 | |
297 | boolean btnRow0 = digitalRead(buttons0); |
298 | boolean btnRow1 = digitalRead(buttons1); |
299 | boolean btnRow2 = digitalRead(buttons2); |
300 | |
301 | Serial.print(testCol); |
302 | Serial.print(": "); |
303 | Serial.print(btnRow0); |
304 | Serial.print(btnRow1); |
305 | Serial.println(btnRow2); |
306 | }
|
307 | delay(100); |
308 | }
|
309 | |
310 | // knobs, faders etc.
|
311 | if (debug) { |
312 | readMuxes(); |
313 | }
|
314 | |
315 | }
|
Ich denke eigentlich, dass der Code klappen sollte (mit dem Arduino tat er das ja ;) ) Kurz noch zur Idee, damit du nicht den ganzen Code lesen musst ;): jede Taste der Klaviatur besteht aus 2 Tastern. Wird Taster 1 gedrückt, speichere ich die Taste in der "watchList" und ich speichere den Zeitpunkt zu dem das geschah. Wird Taster 2 gedrückt, vermerke ich das die tastet nun "pressed" ist, messe den Abstand zum Druck von Taster 1, berechne die Velocity und sende das MIDI Note On Wird Taster 1 nicht mehr gedrückt, aber die Taste ist noch als "pressed" markiert sende ich MIDI Note Off und setzte für die Taste wieder alles zurück. > Einen Kurzschluss in der Klaviatur oder im Anschlusskabel kannst du > grundsätzlich ausschliessen? Sieht mir allerdings auch nicht so aus, > sonst würden die Pegel anders verlaufen. Ja kann ich ausschließen - das Kabel ist in einwandfreiem Zustand und an der Klaviatur noch "vom Werk" angelötet, die selbst angelöteten Buchsen auf dem Board haben auch definitiv keinen Kurzschluss.
Ich habe gerade meine Pulse in den +5V wieder gefunden (Kanal 1 = Q7, Kanal 2 = +5V), die Differenz zwischen den maximalen und minimalen Pegeln liegt bei etwa 70 bis 50 mV. Ist das (zu) viel? Mir fehlt für solche Größen noch etwas das Gespühr, mein Bauchgefühl sagt mir aber, dass das zu wenig zum "Stören" ist...
Andreas H. schrieb: > mein Bauchgefühl sagt mir aber, > dass das zu wenig zum "Stören" ist... Naja, Gefühl ist hier so 'ne Sache, Störungen sind Störungen und ohne is' immer besser :-) Gerade die CMOS ICs sehen sowas gerne mal als gültiges Signal. Die Sache mit den dicken Masseleitungen hast du ja hoffentlich gemacht, und das ist es recht einfach, noch ein paar 'strategische' Entkoppelkondensatoren über die Schaltung zu verteilen. Andreas H. schrieb: > if (debug || 0) { > Serial.println("-----"); Das Konstrukt muss dir mir mal erklären 'If debug OR null' - m.E. ist 0 immer wahr. Nur für Tests? Andreas H. schrieb: > for (byte testCol = 0; testCol < 8; testCol++) { > driveButtons(shiftBits[testCol]); > // Sächelchen weggelassen > Serial.print(btnRow1); > Serial.println(btnRow2); > } > delay(100); Hier ist klar, das er in shiftBits[7] länger drin bleibt als in allen anderen Zuständen. Du könntest dein shiftBits Array mal um Zustand Nummer 8 erweitern, indem alle Matrix Ausgänge auf 0 stehen. In diesem Zustand verlässt du dann die Scan Routine. Generell ist die Arduino Library von der Verarbeitungszeit nicht optimal. digitalWrite() ist zwar sehr universell angelegt, braucht aber extrem lange im Vergleich zum direkten Port schreiben. Es kann nicht schaden, früher oder später mal auf richtiges C umzusteigen.
Matthias Sch. schrieb: > Andreas H. schrieb: >> mein Bauchgefühl sagt mir aber, >> dass das zu wenig zum "Stören" ist... > > Naja, Gefühl ist hier so 'ne Sache, Störungen sind Störungen und ohne > is' immer besser :-) Gerade die CMOS ICs sehen sowas gerne mal als > gültiges Signal. > Die Sache mit den dicken Masseleitungen hast du ja hoffentlich gemacht, > und das ist es recht einfach, noch ein paar 'strategische' > Entkoppelkondensatoren über die Schaltung zu verteilen. ja, die dickeren Leitungen zur Stromversorgung habe ich angebracht. Wo wären den solche "strategischen" Kondensatoren angebracht. Vor Abzweigungen? Und eher "kleine" (bis 100nF) oder "große" (mehr als 100nF)? > Andreas H. schrieb: >> if (debug || 0) { >> Serial.println("-----"); > Das Konstrukt muss dir mir mal erklären 'If debug OR null' - m.E. ist 0 > immer wahr. Nur für Tests? \* räusper * - ja das war nur zu Testzwecken, ich wollte nicht, debug auf 1 setzten weil das zu viel (unnötigen) Output gegeben hätte und hab dann kurzer Hand ein "OR 1" dahinter gehängt (aber 0 (als Zahl) ist immer falsch, es ist ja nicht NULL (als unbekannter Wert)) ;) > Andreas H. schrieb: >> for (byte testCol = 0; testCol < 8; testCol++) { >> driveButtons(shiftBits[testCol]); >> // Sächelchen weggelassen >> Serial.print(btnRow1); >> Serial.println(btnRow2); >> } >> delay(100); > > Hier ist klar, das er in shiftBits[7] länger drin bleibt als in allen > anderen Zuständen. Du könntest dein shiftBits Array mal um Zustand > Nummer 8 erweitern, indem alle Matrix Ausgänge auf 0 stehen. In diesem > Zustand verlässt du dann die Scan Routine. Ja, aber zur Zeit debug ja false, d.h. dieser Code wird nie ausgeführt, aber klar, das würde dann zu einem längern Zustand führen. Ist so ein Matrixeintrag mit B00000000 denn zu empfehlen? - sprich stört es, wenn dort ein HIGH "liegen bleibt"? > Generell ist die Arduino Library von der Verarbeitungszeit nicht > optimal. digitalWrite() ist zwar sehr universell angelegt, braucht aber > extrem lange im Vergleich zum direkten Port schreiben. Es kann nicht > schaden, früher oder später mal auf richtiges C umzusteigen. Ja, das habe ich auch noch vor, der Teensy eignet sich auch gut für C Programmierung, aber den Prototypen hatte ich halt mit dem Arduino gemacht, weil grad nix anderes da war und ich wollt ja erst mal nur einen "Proove of Concept", wofür die Arduino Library ja gut geeignet ist - zwecks Übersichtlichkeit :). Ich muss dir zwischen drin auch schon mal Danke sagen ;) - so lang wie der Thread mittlerweile schon geworden ist will ich nicht mehr bis zum hoffentlich baldigem Ende warten :D
Andreas H. schrieb: > ja, die dickeren Leitungen zur Stromversorgung habe ich angebracht. Wo > wären den solche "strategischen" Kondensatoren angebracht. Vor > Abzweigungen? Und eher "kleine" (bis 100nF) oder "große" (mehr als > 100nF)? Schau dir einfach nochmal den originalen Controller an. Eine ähnliche Strategie ist vermutlich gar nicht dumm. Also eine saubere Stromversorgung und dann die grösseren Verbraucher mit Elko und Kerko entkoppeln (den Teensy und die Treiber, die den Strom liefern). Kleinere Kerkos dann an den kleineren Teilen. Übrigens sind auch CMOS Analogschalter nicht unendlich schnell und 'kleben' nach dem Umschalten auf einen anderen Kanal noch kurz auf dem alten. Verhindern könntest du das mit dem Sperren und Freigeben des 'Enable' Eingangs oder durch leicht längeres Warten, bevor du den Schalter dann einliest. Lass dir doch mittels deines Test Ausgangs mal den Zeitpunkt anzeigen, wo du wirklich den Tastenwert einliest und vergleiche die kritischen Tasten mit den unkritischen. Eine andere Strategie wäre noch, die Matrixroutine so zu ändern, das du beim Verlassen der Schleife schon mal die nächste Spalte und Zeile voreinstellst und beim Eintritt zuerst diesen Wert liest. Das ganze wäre mit einer Timer ISR gut zu machen, die Timerperiode ist dann direkt die 'Settle' Zeit deiner Matrix. Andreas H. schrieb: > Ich muss dir zwischen drin auch schon mal Danke sagen ;) Hehehe, da nich' für :-)
Matthias Sch. schrieb: > Übrigens sind auch CMOS Analogschalter nicht unendlich schnell und > 'kleben' nach dem Umschalten auf einen anderen Kanal noch kurz auf dem > alten. Verhindern könntest du das mit dem Sperren und Freigeben des > 'Enable' Eingangs oder durch leicht längeres Warten, bevor du den > Schalter dann einliest. Lass dir doch mittels deines Test Ausgangs mal > den Zeitpunkt anzeigen, wo du wirklich den Tastenwert einliest und > vergleiche die kritischen Tasten mit den unkritischen. Das war es!!! :) - wärend ich keysRow0 und keysRow1 ausgelesen hab war der Treiber noch gar nicht auf HIGH. Warum das jetzt alles so dermaßen durcheinander gebracht hat weiß ich noch nicht genau, aber durch ein kleines Delay von 16µs ist jetzt alles im Lot und die Tasten funktionieren einwandfrei :) - zum Glück hab ich noch nicht angefangen die Kondensatoren zu verlöten, das hätte an einigen Stellen ein echt unschönes Platinenlayout gegeben :D. Das mit dem Enable Pin werde ich auch noch mal testen. Bei meiner Anwendung sind Delays ja eigentlich eher ein Tabu :D Man hat das lange gedauert und soo eine einfach Lösung .. na gut, ich hab viel gelernt dabei! Also noch mal vielen Dank für die Tipps!
1 | ...
|
2 | void loop() { |
3 | // keys
|
4 | for (byte testCol = 0; testCol < 8; testCol++) { |
5 | driveKeys(shiftBits[testCol]); |
6 | delayMicroseconds(16); |
7 | |
8 | // odd = 2nd buttons; even = 1st buttons
|
9 | keysRow0 = digitalRead(keys0); |
10 | keysRow1 = digitalRead(keys1); |
11 | ...
|
Andreas H. schrieb.
1 | if (velo > 127) { |
2 | velo = 127; |
3 | }
|
Dir ist schon klar, dass der Code nix tut?! Ein char kann keinen Wert größer 127 haben. Wundert mich, dass Dein Compiler Dich nicht gewarnt hat. Geht das tatsächlich erst bei einem Delay von 16µs? Meines Erachtens sollten 1 bis 2µs fett reichen.
Deltor schrieb: > Geht das tatsächlich erst bei einem Delay von 16µs? > Meines Erachtens sollten 1 bis 2µs fett reichen. Das ist sehr knapp. Ein 4051/52/53 Analogschalter hat lt. Datenblatt eine Verzögerung von max. 1µs vom Setzen des Schalters bis zum Durchschalten. Das gilt bei 5V. Je höher die Versorgungsspannung ist, desto 'munterer' wird er, bei 10V sinds nur noch 360ns und bei 15V dann 240ns.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.