Hier nochmal die Routine dazu: In der Pchg_isr werden alle Pegelwechsel innerhalb einer Timerperiode gesammelt und das jeweilige Bit in "Changed_pins_sum" gesetzt. Eine 1 bedeutet hierbei, dass sich dieses Bit verändert hat, nicht jedoch, dass sein Pegel 1 ist...! In der Timer_Isr wird der letze PINB-Status nach "Deb_pinb" transferiert, wobei das Byte in "Changed_pins_sum" die Maske liefert, für jene Bits (die gekippten) die beim Übertrag nach "Deb_pinb" ausgelassen werden. Kurz: 'Wd_isr' ist eine Transferroutine von Byte A nach Byte C, wobei das Bitmuster im Masken-Byte B (hier das "Changed_pins_sum") bestimmt, welche Bits im Zielbyte unverändert bleiben sollen. Die gesamte Routine sollte somit geeignet sein, abhängig vom Timerintervall, eine reproduzierbare Grenzfrequenz zu realisieren, indem sie die präzise erfassten Flankenwechsel die in kürzerer Periode als Tim_int eintreffen, nicht weiterleitet. Die Codelaufzeit in Zusammenhang mit dem Systemtakt muss dabei natürlich mit einbezogen werden. '****************************************** . Last_pins_state = Pinb . . Do . Loop . . '********************* Pchg_isr: 1 Changed_pins = Last_pins_state Xor Pinb 2 Last_pins_state = Pinb 3 Changed_pins_sum = Changed_pins_sum Or Changed_pins Return '******************** Wd_isr: 4 If Changed_pins_sum = 0 Then 5 Deb_pinb = Last_pins_state 6 Else 7 Deb_pinb = Deb_pinb And Changed_pins_sum 8 Changed_pins_sum = Changed_pins_sum Xor &HFF 9 Changed_pins_sum = Changed_pins_sum And Last_pins_state 10 Deb_pinb = Deb_pinb Or Changed_pins_sum 11 Changed_pins_sum = 0 12 End If Return ' bei 8,9 u.10 wird "Changed_pins_sum" nur noch als Temp-Variable 'mißbraucht' bzw. 'recycled', ohne inhaltlichen Bezug zu ihrem anfänglichen Namen. Mike
Was mich noch interessieren würde: Kann man diese Art der Maskierung (Protektion der Zielbits mittels Maske) mit anderen Operationen schneller, und/oder kürzer realisieren..?
Michael Schurr schrieb: > Was mich noch interessieren würde: > > Kann man diese Art der Maskierung (Protektion der Zielbits mittels > Maske) mit anderen Operationen schneller, und/oder kürzer realisieren..? Nein. Ok. In BASCOM vielleicht nicht, aber ein C-Compiler macht aus deinem Code 2 Ladeinstruktionen 2 And 1 XOR 1 Or 1 Speicherinstruktion alles in allem 7 Taktzyklen, wovon 3 nicht optimierbar sind (Laden und Speichern) Was willst du da noch groß optimieren? Du optimierst an der falschen Stelle. Ob der Timer Interrupt jetzt 0.5 Promille oder 0.5001 Promille der Rechenzeit braucht, ist sowas von Wurscht. Wenn dieser Unterschied in deinem Progamm einen Unterschied macht, dann hast du ganz andere Probleme. Sorg lieber dafür, dass deine Tastendruck-Auswertung ordentlich benutzbar wird. Da hast du mehr davon. Denn bis jetzt hast du ja nur einen Tastenzustand aber noch keine Erkennung eines einzelnen Tastendrucks.
Man muß auch berücksichtigen, daß jeder Interrupt ein Prolog/Epilog Gedöns braucht. Beim AVR-GCC gehen dafür allein gerne mal 30..40 Zyklen drauf. Wenn also der ICP-Interrupt keinen großen Vorteil bringt, kostet er trotzdem zusätzlich.
Hi Kh, nein das ist jetzt nicht akut relevant. Wollte nur generell von der Profiseite her wissen, ob es da elegantere und schnellere Lösungen gibt. Und generell will man schon immer Zeit und Platz von vornherein sparen. Nachher ist es immer etwas mühselig, wenn es klemmt. Vor allem sind knappe und sporadische Timingprobleme nicht Debugger's Lieblingshobby... ;-)
Michael Schurr schrieb: > Und generell will man schon immer Zeit und Platz von vornherein sparen. Ja das kenn ich. Ich sitz auch an so einem Programm an dem ein einzelner 15 Jahre lang jegliche softwaretechnische Sorgfalt hat missen lassen und gnadenlos optimiert hat - Funktionsaufrufe kosten ja auch so viiieel Zeit. Das Ergebnis vom Lied: Er ist nicht mehr in der Firma und 5 Mann arbeiten seit ca 2 Jahren daran, wenigstens die gröbsten Softwaresünden und schlimmsten Bugs auszumerzen. Während nebenbei auch noch die Weiterentwicklung laufen soll. Aber Hauptsache das Programm ist schnell .... manchmal sind die Ergebnisse zwar, sagen wir mal, kreativ aber die sind dafür dann auch schnell da. Das Hauptaugenmerk eines Profis liegt auf wartbarem Code! Und nicht auf der Optimierung des letzten Taktzykluses. "Schnell genug" ist völlig ausreichend. Mehr braucht es nicht.
Hab die Routine nochmal optimiert, so daß jetzt auch bei Mehrfachprellen innerhalb des aktuellen Timerintervalls nur ein einziger Pchg-Int pro Eingang auftritt. Eine weitere Optimierung (Code in Klammern) ist noch dadurch möglich, daß bei statischen (ruhigen) Eingängen, auch noch der Timer_Int deaktiviert wird, falls dieser nicht auch von anderen Routinen genutzt wird. Die ganze Debounce-Routine ist somit bei ruhigen Eingängen total inaktiv und verbraucht keinerlei Zeit durch Prüfroutinen und Ints mit Push/Pop-Sequenzen. Sie wird nur bei einem neuerlichen Pegelwechsel für einen(!) Durchlauf aktiviert. Das bedeutet maximale Treffsicherheit bei Erkennung von Prell-, oder Störimpulsen, bei maximaler Zeiteffizienz. Die hier oft credomässig postulierte Behauptung, daß Pchg-Int bei der Tastenentprellung nichts zu suchen hat, ist so gesehen nicht überzeugend. Die Vorteile überwiegen bei Weitem, wenn es richtig umgesetzt ist. Selbst die Int-Aufrufe und die beanspruchte Gesamtzeit, liegen mit der jetzigen Implementierung hinter denen, die bei einer ununterbrochenen, zyklischen Pollingaktivität auch ohne jegliche Tastenaktivität verbraten werden. .... 'Init: . . Pcmsk=&b00010111 'Pchg_Int_Maske Pcmsk_copy = Pcmsk Last_pins_state = Pinb 'Main: . do ... loop . 'ISRs: '********************* Pchg_isr: (Set WDIE => WDTimer_Int enablen) Changed_pins = Last_pins_state XOR Pinb Last_pins_state = Pinb Changed_pins_sum = Changed_pins_sum OR Changed_pins Stable_pins = Changed_pins_sum XOR &HFF Pcmsk = Pcmsk AND Stable_pins Return '***************** Wd_isr: If Changed_pins_sum = 0 Then Deb_pinb = Last_pins_state (Reset WDIE => WDTimer_Int disablen) Else Deb_pinb = Deb_pinb AND Changed_pins_sum Stable_pins = Stable_pins AND Last_pins_state Deb_pinb = Deb_pinb OR Stable_pins Changed_pins_sum = 0 End If Pcmsk = Pcmsk_copy Return
Michael Schurr schrieb: > bei maximaler Zeiteffizienz. Ich glaube nicht, daß jemand das als wirklichen Vorteil sieht, wenn beim nicht Drücken die CPU-Last um 0,01% geringer ist, gegenüber der Timermethode. Auf jeden Fall ist es nicht merkbar. Auch braucht fast jede Anwendung einen Timer, um zeitliche Abläufe (RTC, Multiplex, Blinken usw.) zu realisieren. Der Timerinterrupt läuft also eh immer und kann nicht gestoppt werden. Effizienz ist nicht das Maximum eines Parameters, sondern das Optimum aller Parameter.
Moin moin... Peter Dannegger schrieb: > Ich glaube nicht, daß jemand das als wirklichen Vorteil sieht, wenn beim > nicht Drücken die CPU-Last um 0,01% geringer ist, gegenüber der > Timermethode. Es geht doch hier ja gar nicht um den Kontrast zur Timermethode, sondern um die Gegenüberstellung der Int_getriggerten Eventmethode einerseits, zur stichprobenartig arbeitenden Pollingmethode andererseits. Letztere muss auch im eventlosen Zustand ständige Abfragen und Vergleichsoperationen ausführen, um überhaupt weiteren Handlungbedarf zu erkennen. Ausserdem kann das zyklische Polling generell, wie z.B. auch die Audiodigitalisierung, nur solche Dynamiken sicher detektieren, die unterhalb der halben Pollingfrequenz liegen. Eine Routine, die zufällig x-mal denselben Pegel detektieren und als "statisch" erklären kann, während das Signal ausserhalb der Stichproben quasi Narrenfreiheit besitzt, ist ja nicht als mathematisch/logisch eindeutige Methode und damit als verlässlich zu bezeichnen. Aber genau das will man doch bei jeder Art der sauberen Programmierung erreichen, daß das Prozedurverhalten eindeutige und vor allem reproduzierbare(...) Ergebnisse generiert. Das ist auch im Hinblick auf Wartbarkeit und Verwendbarkeit als Modul, ein starkes Argument. Ich sehe Zuverlässigkeit und Reproduzierbarkeit eines detektierten Zustandes, als eines der prioritären Prinzipien an und damit auch als Code-Effizienz im übergeordneten Sinne. Vor allem kann Code der reproduzierbar verlässlichen Output liefert, auf andere Einsatzgebiete portiert werden, gerade wenn es dort auch auf kompromisslose Zuverlässigkeit ankommt. Der wirklich effizienzgewinnende Teil der letzten Änderung, ist ja die Begrenzung des Pchg_int auf das erste Ereignis. Das bewirkt, daß z.B. auch stark prellende Kontakte nur einen einzigen Int samt push/pop-Overhead pro Timerzyklus erzeugen. Die 'ruhigen', stabilen Eingangskonstellationen verbrauchen, wie gehabt, nach dem zweiten Timerzyklus ohnehin gar keine Prozesszeit mehr. Ob nun der Timerinterrupt mit seinen 0,01% dazu auch noch wegfällt oder nicht, habe ich ja auch nur als Option in Klammern dargestellt, die man noch reinnehmen kann um damit eine 'puristisch reine', eventgetriggerte Prozedur zu erreichen, die ohne akuten Event garnicht mehr in Erscheinung tritt.
Michael Schurr schrieb: > Eine Routine, die zufällig x-mal denselben Pegel detektieren und als > "statisch" erklären kann, während das Signal ausserhalb der Stichproben > quasi Narrenfreiheit besitzt, ist ja nicht als mathematisch/logisch > eindeutige Methode und damit als verlässlich zu bezeichnen. Doch kann man denn das hängt ausschließlich von den Rahmenbedingungen ab. Indirekt ewähntest du schon das Nyquist Theorem das exakt diese Grenze mathematisch formuliert. Alle externen Eregnisse die unterhalb dieser Grenze ablaufen können auch mit einem Sampling das oberhalb dieser Grenze liegt eindeutig sauber erfasst werden. Die Notwendigkeit für ein Ereignisbasiertes System entfällt bzw. es stellen sich die gleichen Verhältnisse dazu bei einem Sampling ein. So bleibt also nur das Argument des Aufwandes, des Resourcenverbrauches. Und da sieht es eben so aus das für Tasterabfragen wirklich nur eine Verbesserung von Subprozentpunkten den Unterschied machen.
Michael Schurr schrieb: > Der wirklich effizienzgewinnende Teil der letzten Änderung, ist ja die > Begrenzung des Pchg_int auf das erste Ereignis. Das bewirkt, daß z.B. > auch stark prellende Kontakte nur einen einzigen Int samt > push/pop-Overhead pro Timerzyklus erzeugen. Die 'ruhigen', stabilen > Eingangskonstellationen verbrauchen, wie gehabt, nach dem zweiten > Timerzyklus ohnehin gar keine Prozesszeit mehr. Exkat dieser Teil deiner Argumentation kann man auch als negativ bewerten. Wir wissen das ein gültiges Tasterereignis im Frequenzbereich < 100Hz liegt. Wir wissen auch das Störungen teilweise im Frequenzbereich weit oberhalb von x kHz liegen können. Zudem wissen wir das der PinChange mit Clock_CPU/4 maximaler Frequenz arbeiten kann. Das hochfrequente Prellen des Tasters wird also dazu führen das überproportional viele Resourcen in der PinChange ISR verschwendet werden die keinerlei zielführende Resultate bringen werden. Benutzt man einen Timer mit einer Frequenz von zB. 200Hz dann reduziert man also auf Grund des Nyquist Theorems diese hochfrequenten Störungen und damit den unnützen Verbrauch von Rechenzeit. Gleichzeitigt bleiben aber die erreichbare Genauigkeit beider Verfahren erhalten, beide Verfahren sind also zur Erreichung des Zieles identisch exakt.
Denoch gibt es Anwendungsfälle bei denen deine PinChange Methode überlegen ist. Wenn man zb. einen Timestamp mit viel höherer Auflösung als die 100Hz Auslöserate des Tasters diesem Event zuordnen muß. Dann müsste man mit der Timer Methode diesen Timer mit wensentlich höherer Frequenz laufen lassen. Und ab einem gewissen BreakEven Point wird die PinChange Methode die Timer Polling/Sampling Methode outperformen.
Hagen Re schrieb: > Das > hochfrequente Prellen des Tasters wird also dazu führen das > überproportional viele Resourcen in der PinChange ISR verschwendet > werden Nein, wird es nicht, wie sich aus meinem Text (und auch aus dem Code) ersehen lässt. Da du meine Texte und die Funktion des Codes offensichtlich nicht zur Grundlage deiner Überlegungen nimmst, können wir auf weitere Spekulationen dieser Art und unfundierte Behauptungen verzichten... Wenn ich statt neue Wege und Tatsachen zu analysieren, lieber Glaubensdinge und Dogmen erörtern möchte, gehe ich in einschlägige Foren... ;-)
Um es nochmal anders zu betrachten: Die Timer Methode impliziert einen digitalen Filter auf Grund des Abtasttheorems (Nyquist). Diesen Filter hat man inklusive ohne zusätzliche Resourcen. Die PinChange Methode benötigt die Resource PinChange ISR und ebenso einen Timer oder zus. softwarebasierte Filter um die gleiche Effektivität zu erreichen. Der Rsourcenverbrauch ist also höher da man nicht nur die CPU Zeit als Resource betrachten darf sondern auch die benutzten Features der CPU. Dazu kommt als Resource noch der Hirnschmalz den man investieren muß und die erreichbare Stabilität aus Sicht des Zieles und der Vermeidung von Störungen. Im Falle einer einfachen Tasterabfrage meine ich das die Timermethode die simpelste und gleichermaßen effektivste Methode ist, weil sie nach folgenden Regeln arbeitet: - keep it simple - programmiere das Nötige mit dem minimalsten Aufwand - benutzte aus zwei Methoden diejenige die die geringste Komplexität hat
Michael Schurr schrieb: > Wenn ich statt neue Wege und Tatsachen zu analysieren, Glaubst du wirklich, einen neuen Ansatz gefunden zu haben, der die Tastenabfrage jetzt revolutionär besser macht? Das Thema Tastenabfrage, auf den ersten Blick logischerweise, über Interrupts zu machen, taucht hier wöchentlich auf. Einfach nur langweilig. mfg.
Michael Schurr schrieb: > Nein, wird es nicht, wie sich aus meinem Text (und auch aus dem Code) > ersehen lässt. > > Da du meine Texte und die Funktion des Codes offensichtlich nicht zur > Grundlage deiner Überlegungen nimmst, können wir auf weitere > Spekulationen dieser Art und unfundierte Behauptungen verzichten... Ich habe deine Argumentation sehr genau gelesen und möchte hier auf deinen Hinweis auch eingehen. Wenn das Prellen so schnell ist das es die Ausführungszeit der PinChange ISR überholt, also die Hardware Grenze von CPU_Clock/4 überschreitet (was immerhin auf AVRs ca. 2Mhz sind) dann filtert quasi die Hardware für dich. Wenn das Prellen langsammer ist aber immer noch schneller als die Ausführungszeiten deiner PinChange ISR dann führt dies dazu das sofort nach Abarbeitung dieser ISR diese ISR wiederum aufgerufen wird. Denn das Interruptflag wird erneut gesetzt. Angenommen deine PinChange ISR kann nur mit maximal 100KHz arbeiten und der Taster prellt für 10ms mit 500kHz, dann würde deine PinChange ISR die komplette CPU Zeit für diese 10ms verbrauchen. Das kann mit einer Timer ISR nicht passieren da diese eben nur mit 5ms Interval arbeitet. Und dieses Verhalten wird durch den Entwickler provoziert ohne jeglichen Gewinn, denn das Ziel lautete: ein Taster der max. mit 100Hz betätigt werden kann soll so ausgelesen werden das man keine der 100Hz Betätigungen vermisst. Und da besagt das Nyquist Theorem ganz klar: lasse den Timer mit 200Hz laufen um dieses Ziel mathmeatisch beweisbar erreichen zu können. Das Problem mit der PinChange ISR ist es also das sie gerade auf jedes Ereignis des Tasters sofort reagiert obwohl dies kontraproduktiv sein muß. Wir wissen das mit 100Hz ein Tasterevent kommt und davor aber x'male mit >> 100Hz ein Prellen. Wir sind am Tasterevent interessiert und nicht am Prellen. Wir möchten die Resourcen schonen und nur auf das reagieren was relevant ist. Die PinChange Methode kann also nicht das leisten was die Timer Methode in diesem Fall leistet. Timer Methode benötigt einen langsammen Timer der oft sowieso schon benutzt wird. PinChange benötigt den PinChange und entweder einen Timer zusätzlich oder eine aufwnedigere Softwarefilterung. Beide leisten am Ende das gleiche. Der Verbrauch an vorhandenen Resourcen ist also bei der PinChange Methode höher. Gleiches gilt für die Komplexität der Verfahren.
Michael Schurr schrieb: > Da du meine Texte und die Funktion des Codes offensichtlich nicht zur > Grundlage deiner Überlegungen nimmst Vielleicht ging es ihm nur so wie mir, ich verstehe nicht, wie Dein Code entprellen soll. Er enthält ja auch keinerlei Kommentare. Wie ich das verstehe, wird beim ersten Pin-Change Interrupt der Pin-Zustand eingelesen und weitere Interrupts für diesen Pin gesperrt. Und nach einer Wartezeit wird dann der gespeicherte Zustand übernommen und Pin-Change wieder freigegeben. Der Pin kann zwischenzeitlich wieder eine völlig anderen Zustand haben, es kann auch nur ne Störnadel gewesen sein. Das entspricht also in der Funktion dem Klassiker: Externer Interrupt + Delay. P.S.: Den PinB im Pin-Change-Interrupt zweimal einzulesen, heißt nicht, daß diese Werte auch identisch sind. Externe Ereignisse sind asynchron. Da sollte man also eine Zwischenvariable benutzen.
Peter Dannegger schrieb: > Michael Schurr schrieb: >> Da du meine Texte und die Funktion des Codes offensichtlich nicht zur >> Grundlage deiner Überlegungen nimmst > > Vielleicht ging es ihm nur so wie mir, ich verstehe nicht, wie Dein Code > entprellen soll. Er enthält ja auch keinerlei Kommentare. Nein so ging es mir eigentlich nicht. Ich braucht nicht seinen Code zu verstehen um zu meinen Schlußfolgerungen zu kommen. Es gibt mehrere Wege: 1. er benutzt nur den PinChange: Vorteil: nur eine Resource benutzt, identisch zur Timer Methode. Nachteil: bekommt dann Probleme mit dem Prellen und muß per Sofwtare aufwendig filtern. 2. er benutzt den PinChange als Intialzünder, deaktiviert diese ISR und benutzt dazu einen Timer: Vorteil: statt nun mit 200Hz Abtastrate arbeiten zu müssen wie bei der Timer Methode hat er diese Abtastfrequenz auf 100Hz reduziert. Die Timermethode muß also minimal doppelt so häufig nachschauen wie seine Methode. Da aber Software für seine PinChange ISR + Timer ISR programmiert werden muß verbraucht er doppelt soviele Resourcen in diesem Bereich. Nachteil: er benutzt 2 Hardware Resourcen statt eine wie bei der Timer Methode. Egal wie man es also dreht und wendet: die PinChange Methode ist ineffektiver, sowohl beim Resourcenverbrauch wie auch bei der Komplexität, wenn man die selbe Zielsetzung annimmt. Ich sehe da nur einen Denkfehler: das Unverständis zum Abtasttheorem.
Peter Dannegger schrieb: > P.S.: > Den PinB im Pin-Change-Interrupt zweimal einzulesen, heißt nicht, daß > diese Werte auch identisch sind. Externe Ereignisse sind asynchron. > Da sollte man also eine Zwischenvariable benutzen. Und das sind dann die versteckten Probleme die die Sache eben komplexer machen im Vergleich zur simplen Sampling Methode nach Nyquist = Timer Methode.
Wenn es um die Probleme deim Abtasten von anaolgen Werten per ADC geht (Nyquist) ist das Verständnis der Entwickler vorhanden. Die Frage die sich nun stellt ist warum manche Entwickler dieses Wissen nicht anwenden können auf andere Probleme. Und eine Tasterabfrage ist so ein Problem. Oder ist es wirklich sinnvoll einen analogen Wert am ADC so abzutasten das wenn sich dieser Wert ändert sofort eine ansynchrone Abarbeitung per "ADC_Change-ISR" anzustoßen und das dann auf den Zeitbereich per zusätzlichen Filterungen (Timer, Delays etc.pp) wieder zu linearisieren ?
Thomas Eckmann schrieb: > Glaubst du wirklich, einen neuen Ansatz gefunden zu haben, der die > Tastenabfrage jetzt revolutionär besser macht? > Das Thema Tastenabfrage, auf den ersten Blick logischerweise, über > Interrupts zu machen, taucht hier wöchentlich auf. > Einfach nur langweilig. ...tsts... auf Beiträge die mich langweilen gehe ich in der Regel erst gar nicht ein... von daher: Danke, für die Mühe... ;-) Ich habe das Thema "Tastenabfrage mit Interrupts" eben nicht nur mit dem ersten Blick euphorisiert, sondern seine Nachteile, die auftreten wenn man den Pchg-Int unreflektiert benutzt, gesehen und dann ausgeschaltet. Daß es mich "revolutionär" dünkt, hast du stichelig ins Feld geworfen... wirst wohl emotionalen Grund dazu haben... '*************** @ Hagen... Alles Argumente, die nicht wirklich greifen im vorliegenden Fall. Während das Polling ständig am werkeln ist, wacht meine Routine nur bei einem realen PChg-Event auf und benötigt genau max. 1 PChg-Int pro Zeitfenster und instabilem Eingang. Und die Pchg-Routine ist nun wirklich minimalistisch und präzise zugleich. Ich brauche keine 100Hz Abtastfrequenz, welche die ganze Zeit pollt, testet und prüft... ich brauche den 100Hz Takt Pchg-getriggert genau 2 mal um einen Change abzuarbeiten, danach ist Ruhe. Auch dann, wenn der unruhige Pin innerhalb dieser Periode noch x-mal weiterbounct! Es scheint hier mehr um das Dogma: "Entprellung und Interrupt ist Resourcenverschwendung und generell tabu..!!" zu gehen, ohne sich damit zu befassen, dass es mit der richtigen Implementierung nur Vorteile bringt. Und zwar in sachen Präzision, wie auch Timing. Nur verstehn muss halt, was hier gemacht wurde und wie der Code arbeitet. Sonst bleiben die meisten 'Kritiken' einfach nur Unkenrufe. Auch Peter D.s Image als Board-Koryphäe und seine unbestritten enormen Fach-Fähigkeiten, werden durch eine Alternativlösung keineswegs in Frage gestellt. Aber es bedeutet auch nicht zwingend, dass von solcher Seite deswegen stets nur die ultimativen Non-plus-Ultra-Lösungen kommen, die als unantastbar, unverbesserbar, oder gar alternativlos zu respektieren sind. Hier scheint es mir diesbezüglich viele "eifrige Jünger" zu geben, die meinen, ihren Guru beschützen zu müssen, statt unvoreingenommen und offen fü anderes zu sein. Stichhaltige Gegenargumente, die das codetechnische Verhalten obiger Routine richtig erfassen, habe ich hier jedenfalls noch keine gesehen. Von den Bugs im Anfangsstadium und der diesbezüglich berechtigten, konstruktiven Kritik mal abgesehen. Nein, ich halte mich weder für einen Revoluzzer, noch für einen Entdecker einer "grossen" Sache. Einen gewissen Perfektionismus mit einfachen Mitteln zu Realisieren, macht mir einfach Spass... wenn's dann endlich funzt. Das bedeutet für mich dann Effizienz. Mike
Michael Schurr schrieb: > @ Hagen... > > Alles Argumente, die nicht wirklich greifen im vorliegenden Fall. Ok dann liefere ich dir eines: Implementiere deine Methode mit 4 Tastern + 4 andere Signalleitung die den PinChange zwingend benötigen. 1. du wirst Probleme bekommen einen AVR so mit PinChange zu programmieren das du innerhalb der PinChange ISR, die ja für den ganzen Port gilt, zu erkennen welcher Pin nun einen PinChange ausgelösst hat. 2. du wirst Probleme bekommen bei 4 Tastern das nachfolgende Timer Timing einzuhalten, der Aufwand steigt proportional da du ja nun für jedes Event einen eigenen Timerwert pflegen musst. Du hast dann zwei Möglichkeiten: defakto 4 Timer zu benutzten oder einen Timer mit festem aber nun viel höherem Interval als 100Hz um 4 Zähler für die Events programmieren zu können. Gerade letzteres führt zur Frage: warum dann nicht gleich mit nur einem Timer sampeln ? der dann sogar wieder langsammer laufen kann = 200Hz. Bei der Timer Methode tastet man alle 4 Taster im gleichen Interval ab, also synchron zueinander innerhalb einer einzigen Routine und sogar Variablen. Ich habe da so eine Design-Regel in meiner Arbeit als Entwickler: wenn eine gewählte Methode ohne Probleme höherwertige Probleme genauso gut erschlagen kann dann ist diese Methode besser als eine andere Methode die dann erst richtig Probleme verursacht. Und ausgehend von einem Taster auf zB. 4 Taster ist es eben so das die Timer Sampling Methode enorm einfach anzupassen ist und mit gleicher Effektivität nun ein komplexeres Problem lösen kann. Über das Abtasttheorem und dessen Konsequenzen müssen wir ja nicht mehr diskutieren. Wir wissen ja das die Sampling Methode nur doppelt so oft aufgerufen werden muß wie das zu erwartende Ereignis auftreten kann. Wenn dieses Theorem nicht verletzt wurde dann unterscheiden sich beide Methoden von der Zielsetzung nicht mehr. Dh. die Exaktheit und Genauigkeit ist die gleiche bei beiden Verfahren. Du musst also uns beweisen das deine Methode einen entscheidenden Vorteil gegenüber der Timer Methode hat. Und da sehe ich eben keine logisch vernünftigen Argumente deinerseits. Ich entwickele mein Wissen also nicht nur ausgehend von einem konkreten gegenwätigen Problem sondern immer in Hinblick darauf das sich ähnliche Probleme auch in Zukunft stellen werden. Somit verfolge ich immer auch das Ziel eine Problemlösung wiederverwenden zu können. Mike, ich diskutiere hier mit dir nur aus einem Grund heraus: nicht weil ich deine Sichtweise diskreditieren möchte noch deine Ideen herabsetzen möchte, sondern um dir meine Sichtweise und die logischen Gründe dafür näher zu bringen. Letzendlich sehe ich in deinen Argumenten exakt die Denkfehler die ich damals als Anfänger gemacht habe. PS: ich rede hier immer von Effektivität und nicht Effizienz und das aus gutem Grund. Denn es geht hier nicht nur um die Betrachtung welche Resourcen wir im AVR haben und verbrauchen sondern auch um den Effekt den die eigenen Entwicklungsarbeit für uns hat. Und da meine ich eben das die Sampling Methode per Timer die höhere Effektivität hat.
Michael Schurr schrieb: > Stichhaltige Gegenargumente, die das codetechnische Verhalten obiger > Routine richtig erfassen, habe ich hier jedenfalls noch keine gesehen. > Von den Bugs im Anfangsstadium und der diesbezüglich berechtigten, > konstruktiven Kritik mal abgesehen. Ich habe keine, wie du so schön schreibst, stichhaltigen Gegenargumente zu deinem Sourcecode. Es gibt auch keine da du sauber entwickelt hast. Man kann es so machen. Mein Gegenargument ist das du am Thema der Zielstzung vorbei entwickelt hast und es einfacher geht bei gleicher Exaktheit der Resultate und annähernd vergleichbarer CPU Auslastung. Die anderen Resourcen die deine Methode benötigt disqualifiziert sie aber zur Sampling Methode. Die Einsetzbarkeit auf nur ein spezielles Problem im Vergleich zur Erweiterbarkeit der Sampling Methode disqualifiziert sie ebenfalls. Ich weiß das du das anders siehst ;)
Wie man es macht, hängt doch davon ab, wieviele Taster/Schalter zu verarbeiten sind und wie schnell reagiert werden muß. Bei einer Tastenmatrix reichen zum einen die Eingänge des Controllers nicht aus, und zum anderen ist für die Dekodierung sowieso einige Zeit nötig, während der aber keine Interrupts blockiert werden müssen. Da gibt es keine Alternative zur zyklischen Abfrage in einer Timer-ISR. Hier ist PCINT auf verlorenem Posten. PCINT bietet sich bei einem oder nur wenigen Tastern an, oder wenn auf Impulse von z. B. Reedrelais' schnell reagiert werden soll. Dabei ist eine Filterung mit ext. RC-Glied einem 'Software-Filter' vorzuziehen, da der integrierte Impuls nicht mehr zwischen GND und VCC wackelt, sondern um ein Maß, was deutlich unter der Hysterese eines Eingangs (beim AVR) liegt. Eine RC-Filterung schützt den Eingang zudem vor zu schneller Interruptfolge und in gewissen Rahmen auch vor ext. Überspannung, wenn der Taster räumlich entfernt angeordnet ist. Anfang der Woche hatte ich dazu etwas in der Codesammlung geschrieben und auch den Kurvenverlauf für einen typischen Eingabetaster (Digitast) gezeigt. "EIN-AUS mit Taster per Interrupt"
hm gerade auch bei Reedrelais würde ich eher das Sampling benutzen. Es gillt in jedem fall das das Prellen höherfrequenter ist als das eigentliche Eregnis. Ergo muß man nur die Samplingfrequenz korrekt anpassen und filtert so ohne externen Aufwand und ohne weiteren internen Aufwand automatisch. Nur wenn wir einen Timestamp dem Event zuordnen müssen der selber eine viel größere Auflösung hat als die Auslösegeschwindigkeit des Ereignises muß man ereignisbasiert arbeiten. Nur wenn wie in Echtzeit, auch eine Definitionssache, darauf reagieren müssen lohnt sich ereignisbasiert zu arbeiten. Nur wenn die Synchronität bei der Auswertung mehrer Ereignisse kontraproduktiv wird, also die Asynchronität zwischen den Ereignissen für uns wichtig ist, müssen wir ereignisbasiert arbeiten. Und wenn wir mal konsequent zu Ende denken dann gilt: wir arbeiten in einer CPU immer nach dem Sampling Verfahren denn auch die CPU arbeitet nur Taktbasiert, ergo beträgt die maximale Samplingfrequenz aller Ereignisse auf die die CPU reagieren kann auch nur die der Taktfrequenz der CPU.
Hagen Re schrieb: > 1. du wirst Probleme bekommen einen AVR so mit PinChange zu > programmieren das du innerhalb der PinChange ISR, die ja für den ganzen > Port gilt, zu erkennen welcher Pin nun einen PinChange ausgelösst hat. Nein, werde ich nicht, weil genau diese differenzierte Erkennung in der PChg-Isr ohnehin gemacht wird und zudem nur jene Eingange als Auslöser in Frage kommen, die im PMSK aktiviert sind.. Ich brauch nur das Changed_Pins Byte auswerten... das enthält genau jenen Eingang als eine "1", der den Int getriggert hat. Alle andern sind Zero. Hagen Re schrieb: > 2. du wirst Probleme bekommen bei 4 Tastern das nachfolgende Timer > Timing einzuhalten, der Aufwand steigt proportional da du ja nun für > jedes Event einen eigenen Timerwert pflegen musst. Auch das ist grottenfalsch... :-) In der PChg_Isr werden alle (per PCMSK aktivierten) Bits in der Breite des gesamten Ports per Ver-ODER-ung gesammelt und dann mit dem Timer_Int als Bytewert in einem Rutsch und mit Hilfe von Bitmanipulationen, gemeinsam ausgewertet und prozessiert. Nix "4 Timerwerte pflegen" und son Zeug...! Alle Change-Events parallel 'sammeln', byteweise verarbeiten, das Ausgangsbyte mit den "ruhigen" Bits updaten und jene Bits die sich verändert haben, beobachten, bis sie innerhalb einer Timerperiode unverändert waren... dann auch diese im Ausgangsbyte updaten... fertig. Hagen Re schrieb: > nicht weil > ich deine Sichtweise diskreditieren möchte noch deine Ideen herabsetzen > möchte, sondern um dir meine Sichtweise und die logischen Gründe dafür > näher zu bringen. Sorry, aber sowohl deine Sichtweise, als auch deine "logischen Gründe" sind in Bezug auf meine Routine total unlogisch und unzutreffend... Wenn du nun bitte eine argumentative Denkpause anfügen könntest, anstatt ohne wirkliche Kenntnis des Codeablaufen munter weiter ins Blaue zu spekulieren, wäre ich dir sehr verbunden... ohne sich wirklich Mühe zu machen etwas zu verstehen, geht es nämlich vom sachlichen Kritikanspruch schnell in Richtung Diskreditierung. Und das steht dir ja ferne... ;-) Mike
Michael Schurr schrieb: > In der PChg_Isr werden alle (per PCMSK aktivierten) Bits in der Breite > des gesamten Ports per Ver-ODER-ung gesammelt und dann mit dem Timer_Int > als Bytewert in einem Rutsch und mit Hilfe von Bitmanipulationen, > gemeinsam ausgewertet und prozessiert. Nix "4 Timerwerte pflegen" und > son Zeug...! > > Alle Change-Events parallel 'sammeln', byteweise verarbeiten, das > Ausgangsbyte mit den "ruhigen" Bits updaten und jene Bits die sich > verändert haben, beobachten, bis sie innerhalb einer Timerperiode > unverändert waren... dann auch diese im Ausgangsbyte updaten... fertig. Na da haben wirs doch ! 1. du wertest mit dem gleichen Timer Interval alle PinChange's aus. Das Argument das du gezielt auf einen Taster umgehend reagieren kannst gilt also nicht mehr da du nur noch in einem festen Interval auf mehrere Changes reagieren kannst. Somit ist dies identisch zum Abtasten. 2. du kannst nicht innerhalb der PinChange ISR herausfinden welcher maskierte Pin die ISR ausgelöst hat. Das geht nicht weil der AVR dafür keine Hardware Unterstützung anbietet. Die einzige Möglichkeit ist es den Pinzustand auszulesen und mit einem zwischengespeicherten zu vergleichen. Dies muß in Relation zur nachfolgenden Timer Auswertung in einer separaten Variablen erfolgen. Beim Sampling entfällt diese Variable. 3. du verbrauchst zwei Resourcen: PinChange und Timer. Der einzige Vorteil aus Sicht der CPU Zeit den ich sehe ist das deine Methode nur dann aktiv wird wenn Taster gedrückt/losgelassen werden. Dies ist unbestritten ein Vorteil aus Sicht der CPU Zeitauslastung wenn man es in absoluten Zahlen fast. Aber, lohnt sich diese Komplexität, dieser Resourcenverbrauch an 2 HW-Resourcen + FLASH Speicher für den komplexeren Code in Relation zu den ca. 20 Opcodes die alle 200Hz in einer Timer Routine beim Sampling benötigt werden ? Ich denke nicht. Alle anderen propagierten Vorteile: wie Exaktheit, Komplexität usw. habe ich oben schon widerlegt.
Hagen Re schrieb: > Ergo muß man nur die Samplingfrequenz korrekt > anpassen und filtert so ohne externen Aufwand und ohne weiteren internen > Aufwand automatisch. Na da spendiere ich meiner Schaltung doch lieber 10k + 10nF als Filter, als mit 1-10kHz Dauerlauf auf Verdacht abzutasten. Je kleiner das Reedrelais, umso schneller kann es schalten.
Michael Schurr schrieb: > beobachten, bis sie innerhalb einer Timerperiode > unverändert waren... Ooops...das ist natürlich selbstgemachter Humbug... die Changed_Pins brauchen natürlich nicht "beobachtet" zu werden, sondern werden automatisch upgedatet, sobald sie eine Timerperiode lang stabil waren...
Michael Schurr schrieb: > sobald sie eine Timerperiode lang stabil waren... Dies ist die entscheidende Passage: das Abtasttheorem besagt exakt das Gleiche wenn man mit doppelter Frequenz zur Eventfrequenz abtastet. Du machst also im Extremfall folgendes: Alle 100Hz kommt ein PinChange und mit einem 200Hz Timer tastest du nochmal ein zweites mal ab. Die Sampling Mehtode macht folgendes: Alle 200Hz taste ab und vergleiche mit dem vorherigen Zustand = 100Hz. In beiden Fällen kommt exakt das Gleiche heraus. Nur wenn der Taster nicht mehr alle 100Hz gedrückt wird ändert sich zugunsten deiner Methode der Verauch an CPU Zeit. Wird der Taster schneller als 100Hz gedrückt machen beide Methoden einen Fehler. Stellt sich nun die Frage: welche Mehtode ist insgesamt effektiver ? Die Timer Methode: - simpel - ausbaufähig - weniger HW-Resourcen - geringere Komplexität - dadurch weniger fehlerträchtig Die PCINT Methode: - weniger Rechenleistung wenn sich nichts am Taster verändert Alle 200Hz werden 20 OpCodes beim Sampling benötigt. Bei 8MHz Takt sind dies 0,05% der Rechenleistung. Das wars mit den Vorteilen.
Mike, du musst es doch mal so betrachten. Dein Ziel hier deine Methode vorzustellen, und damit der Nutzwert für die Leute die ihn anwenden wollen, besteht doch darin sie in ein weiterführendes Projekt einzubauen. Damit muß letzendlich die Betrachtungsweise der Effizienz zu einer Betrachtungsweise der Effektivität werden. Denn nur deinen Sourcecode als einzigem Bestandteil eines Programmes zu betrachten ist widersinnig. Denn erstens erledigt sich dann das Thema Effizenz da man ausreichend Resourcen zur Verfügung hat. Zweitens ist eine solche Effizienzbewertung im Vergleich zu anderen Methoden hinfällig. Ergo: stellt sich die Frage mit welchen Minimal-Mitteln kann das Ziel erreicht werden da man ja annehmen muß das die Resourcen in einer größeren Anwendung immer knapper werden, oder eben bestimmte Resourcen eh schon vorhanden und benutzt werden (wie eben ein Timer). Gleichermaßen muß man dann hinterfragen welche Seiteneffekte wird es haben wenn ich bestimmt Resourcen blockiere für die spätere Anwendung. So jedenfalls ist meine Sicht auf diesen Thread und daraus resultiert auch meine Wertung. Gruß Hagen
Hagen Re schrieb: > Wird der Taster schneller als 100Hz gedrückt machen beide Methoden einen > Fehler. Das muß nicht so sein. Durch schnelles Anschlagen eines Tasters wird ein kurzer Impuls erzeugt, der per PCINT schnell und zuverlässig erkannt wird: siehe Bild. Nach ca. 2ms ist der Kontakt erkannt und nach ca. 4ms wieder auf Ruhepegel. Soll sich jeder selber sein Urteil bilden.
Hagen Re schrieb: > Du machst also im Extremfall folgendes: > Alle 100Hz kommt ein PinChange und mit einem 200Hz Timer tastest du > nochmal ein zweites mal ab. Hallo "Mr. Abtasttheorem", ...selten sowas von lernresistent und daneben bei einer "Analyse" gelesen.. Daß der PChg_int nur auslöst, wenn auch ein solcher Event auftritt, ist dir aber schon klar? Daß er nur 1mal gebraucht wird und daher der entsprechende Eingangspin für den Rest des laufenden Timerintervalls aus dem PChg ausmaskiert wird, ist dir auch klar? Nein, sicher nicht... war nur rhetorisch. Da kommt eben nicht dasselbe raus, schon alleine dewegen, weil der PChg-Int jeden(!) kurzen Flankenwechsel erfasst, während das Pollen nur zufällig im Nebel stochert, um einen Pegelwert zu erfassen. Wenn da wenige µs voerher oder nachher ein Flankenwechsel war, merkt die Pollingroutine nix davon und gibt stattdessen ein falsches "stabil" Argument weiter. Dein (uni??)theoretischer Firlefanz liefert nur dann korrekte Schlüsse, wenn er richtig eingesetzt wird... und das wird er von dir ganz offensichtlich nicht! Hagen Re schrieb: > Nur wenn der Taster nicht mehr alle 100Hz gedrückt wird ändert sich > zugunsten deiner Methode der Verauch an CPU Zeit. Ah ja... du meinst wohl, nur wenn man Taster langsamer als mit 100Hz betätigt, hat meine Methode Vorteile... oh DAS ist aber ein gaaanz schlimmes Manko...!!! Wo doch jeder Old Dadderhand locker mit 150Hz auf den Tasten was reinhackt. Haha, klasse! Im Übrigen ist 100Hz eine Frequenzangabe und keine Zeitangabe. Man kann einen Taster evtl. mit Hz bezittern, oder man kann kann alle 10ms einen Taster drücken. Aber nicht alle 100Hz einen Taster drücken... Und zu deinem letzten Post: Da wird garnix blockiert an Resourcen. Die schon vorhandene Auswertung, welche Taste den Interrupt generiert hat, ist sogar nützlich für andere Rotinen, die diese Info ebenfalls benötigen! Das Argument "Resourcenblockierung" ist auch nur Hot_Air! Bist du jetzt eigentlich bald fertig mit deiner nichtdiskreditierenden Diskreditierungsorgie...? Das hat ja schon was Fanatisches an sich, Dein missionarischer Eifer des Madigmachens... ;-) ****** Hagen Re schrieb: > Denn erstens erledigt sich dann das Thema Effizenz da man > ausreichend Resourcen zur Verfügung hat. Ach, und wozu überhaupt noch was Effizientes proggen, wenn es doch Resourcen im Überfluss gibt...? Hagen Re schrieb: > Gleichermaßen muß man > dann hinterfragen welche Seiteneffekte wird es haben wenn ich bestimmt > Resourcen blockiere für die spätere Anwendung. Hauptsache gekontert, auch wenn er sich selbst diametral widerspricht in einem einzigen Absatz... ...schizo..? Oder merkst du einfach nix mehr, auf deinem Mießmuscheltrip? Ich wünsche dir gute Besserung... dieser, wenigstens psychologisch interessante, Disput bringt mir keine neuen Erkenntnisse mehr, ausser daß ich da subjektiv eine subtile Art von Neid bei dir und deinen endlosen, hohlen Kontra-Argumenten erspüre. Mach doch mal was Kreatives, statt hier so verbissen erfolglos den Marcel Reich-Ranicki der µC-Progger zu imitieren... :-)) Ich jedenfalls geh jetzt raus an die Sonne...
Michael Schurr schrieb: > Ich jedenfalls geh jetzt raus an die Sonne... Na endlich mal was Vernünftiges. Da kannst du dann über Vorwiderstände ohne Leuchtdioden nachdenken. Auch so ein beliebtes Vollpfostenthema, daß niemanden wirklich interessiert. mfg.
M. N. schrieb: > Hagen Re schrieb: >> Wird der Taster schneller als 100Hz gedrückt machen beide Methoden einen >> Fehler. > > Das muß nicht so sein. Durch schnelles Anschlagen eines Tasters wird ein > kurzer Impuls erzeugt, der per PCINT schnell und zuverlässig erkannt > wird: siehe Bild. > Nach ca. 2ms ist der Kontakt erkannt und nach ca. 4ms wieder auf > Ruhepegel. Soll sich jeder selber sein Urteil bilden. Und was bringt das ? So hast du nämlich einen Störimpuls zuverlässig detektiert und nicht das Betätigen wie gewünscht zuverlässig erkannt. Also kommt der Timer nach dem PCINT ins Spiel der dann 50ms später erneut den Taster abfragt und nur wenn dann der Taster immer noch betätigt ist wird ein Tasterevent erzeugt. In deinem Falle also kein Tasterereignis aber ein unnötiger PCINT.
Michael Schurr schrieb: > Hallo "Mr. Abtasttheorem", ...selten sowas von lernresistent und daneben > bei einer "Analyse" gelesen.. Daß der PChg_int nur auslöst, wenn auch > ein solcher Event auftritt, ist dir aber schon klar? Daß er nur 1mal > gebraucht wird und daher der entsprechende Eingangspin für den Rest des > laufenden Timerintervalls aus dem PChg ausmaskiert wird, ist dir auch > klar? > Nein, sicher nicht... war nur rhetorisch. Doch das ist mir klar und habe ich auch so schon in den vorherigen Positing analysiert für dich. Egal, letztendlich habe ich nur noch eine Bemerkung zu machen: ist dir mal aufgefallen welche Rethorik du an den Tag legst ?
Hagen Re schrieb: > Und was bringt das ? So hast du nämlich einen Störimpuls zuverlässig > detektiert und nicht das Betätigen wie gewünscht zuverlässig erkannt. > > Also kommt der Timer nach dem PCINT ins Spiel der dann 50ms später > erneut den Taster abfragt und nur wenn dann der Taster immer noch > betätigt ist wird ein Tasterevent erzeugt. In deinem Falle also kein > Tasterereignis aber ein unnötiger PCINT. Das ist kein Störimpuls und einen Timer verwende ich auch nicht. Bei genauer Lektüre hätte es Dir klar sein sollen. Aber was soll ich hier gegen Windmühlen antreten?
M. N. schrieb: > Hagen Re schrieb: >> Und was bringt das ? So hast du nämlich einen Störimpuls zuverlässig >> detektiert und nicht das Betätigen wie gewünscht zuverlässig erkannt. >> >> Also kommt der Timer nach dem PCINT ins Spiel der dann 50ms später >> erneut den Taster abfragt und nur wenn dann der Taster immer noch >> betätigt ist wird ein Tasterevent erzeugt. In deinem Falle also kein >> Tasterereignis aber ein unnötiger PCINT. > > Das ist kein Störimpuls und einen Timer verwende ich auch nicht. Bei > genauer Lektüre hätte es Dir klar sein sollen. > Aber was soll ich hier gegen Windmühlen antreten? Mit anderen Worten möchtest du einen 2ms langen Tastendruck detektieren ? Nachfolgend deine Lektüre: >Hagen Re schrieb: >> Wird der Taster schneller als 100Hz gedrückt machen beide Methoden einen >> Fehler. >Das muß nicht so sein. Durch schnelles Anschlagen eines Tasters wird ein >kurzer Impuls erzeugt, der per PCINT schnell und zuverlässig erkannt >wird: siehe Bild. >Nach ca. 2ms ist der Kontakt erkannt und nach ca. 4ms wieder auf >Ruhepegel. Soll sich jeder selber sein Urteil bilden. Ich bezog mich darauf das der Taster minimal 10ms gedrückt sein muß, und alles was drunter ist ist ein Störimpuls. Vielleicht wird dir jetzt meine Aussage klarer.
Peter Dannegger schrieb: > Vielleicht ging es ihm nur so wie mir, ich verstehe nicht, wie Dein Code > entprellen soll. Er enthält ja auch keinerlei Kommentare. > > Wie ich das verstehe, wird beim ersten Pin-Change Interrupt der > Pin-Zustand eingelesen und weitere Interrupts für diesen Pin gesperrt. > > Und nach einer Wartezeit wird dann der gespeicherte Zustand übernommen > und Pin-Change wieder freigegeben. Der Pin kann zwischenzeitlich wieder > eine völlig anderen Zustand haben, es kann auch nur ne Störnadel gewesen > sein. Peter, Du hast recht. In der Wd_isr muss natürlich stehen: If Changed_pins_sum = 0 Then Deb_pinb = PINB anstatt: Deb_pinb = Last_Pins_state Else . . Hab ich in der obigen Aktualisierung falsch übernommen und ist mir nicht aufgefallen. Das wirkt sich sonst genau in diesem besonderen Fall aus, wenn es ein einzelner Spike bzw. ein Burst war, der den ersten Flankenwechsel im Endeffekt wieder annuliert UND wenn gleichzeitig im darauffolgenden Timerinterval kein aktualisierender PChg-Event auftritt. Bei einem Changed_pin_sum = 0 im Timer-Int ist jedoch garantiert, daß es innerhalb des gesamten vorangegangenen Timerzeitfensters, keinen Change-Event am Eingangsport gegeben hat. Somit ist in diesem Fall das gesamte PINB stabil und gültig und kann ins Ausgangsbyte kopiert werden.. Brilliant beobachtet, danke !
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.