hallo, ich versuche gerade über polling zu zählen wie oft ein signal an einem port anliegt! wenn ein signal zum beispiel an portb0 anliegt müsste doch pinb 1 sein oder irre ich mich da? gruß
wie kann ich denn da die genauigkeit raufschrauben? wenn das gleiche signal über eine gewisse zeit reinkommt schwankt der zählerstand enorm! woran liegt das und wie kann man das beheben?? gruß
Dann scheinst du, alles mögliche zu zählen, nur nicht dein Signal. Hast du vielleicht an deinem Port einen Taster der ordentlich prellt? Oder empfängst du andere Störsignale?
Wenn Du zählen willst, dann musst Du die Signalflanken zählen. Ich vermute mal, dass Du gar nicht wartest, bis Dein Signaleingang wieder auf null ist und deshalb jeden High-Pegel ein paar tausend mal erfasst...
also ich zähl den counter folgendermaßen hoch: cbi(DDRB, 0); sbi(PORTB,0); char neu = PINB; if ( neu != alt) { if ( !(neu & 1) ) counter++; } alt = neu; sbi(DDRB,0); geht das so?
Konfigurier den Port am Beginn des Programms und ändere den dan nicht mehr. Wenn du den Pullup dazuschaltest, kannst du abhängig davon wie die äussere Beschaltung aussieht ein paar Schwingungen oder durch ein RC-Glied eine Verzögerung kriegen. Wie auch immer: Wenn das Pgm hochfährt -> Ports und Pullups konfigurieren. In der Interrupt-Funktion wertest du dann nur mehr die Ereignisse aus und lässt die Konfiguration in Ruhe. Zum Rest: Im Prinzip kannst du das so machen. Ich wuerde es allerdings so schreiben: char neu = PINB & 0x01; /* Uebergang von 0 nach 1 ? Ja: Zaehlen */ if( ( alt == 0 ) && ( neu != 0 ) ) counter++; alt = neu; Ich finde das kommt besser zum Ausdruck, welches Ereignis die Zählung auslöst. Ist aber Geschmackssache.
[Verwirrungstiften] Oder gleich so: if( ( alt == 0 ) && ( neu != 0 ) && alt = neu ) counter++; Damit spart man sich eine Zeile ;-) [/Verwirrungstiften]
Am Ende sollte er glaub' ich sowieso besser einen Timerinterrupt implementieren und in diesem seine Tasten abfragen und entprellen. Beispielcode für sowas gibt's reichlich.
@ulrich [Verwirrungstiften] Oder gleich so: if( ( alt == 0 ) && ( neu != 0 ) && alt = neu ) counter++; Damit spart man sich eine Zeile ;-) [/Verwirrungstiften wobei alt = neu immer 1 ergibt
Ist ja auch so gedacht, halte ich persönlich aber für schlechten Programmierstil, da unübersichtlich und nur schwer zu durchschauen.
@Ulrich Abgesehen vom offensichtlichen Tippfehler. Wenn schon, dann: if( ( alt != neu ) && ( alt == 0 ) && ( neu != 0 ) ) counter++; Viel Spass beim rausknobeln warum. Tip: Es hat was mit der 'Short-Cut-Evaluation' zu tun (Sorry, ich kenn das deutsche Wort dafür nicht).
@Ulrich [Mit der flachen Hand auf die Stirn klatschen] Jetzt hab ich erst verstanden worauf du hinaus willst :-) Solche Schweinereien hab ich mir schon vor Jahren abgewöhnt :-)
ich kann die ports aber von anfang an nicht konfigurieren und so lassen weil das lcd alle ports belegt! ich muss sie also anschalten, gucken und zählen und wieder abschalten! oder gibt es da doch eine elegantere lösung? vielleicht die ports bei dem display deaktivieren?! gruß
if( ( alt == 0 ) && ( neu != 0 ) && alt = neu ) funktioniert auch nicht sonderlich. Es wird versucht dem lvalue (alt == 0) && (neu != 0) && alt den Wert von neu zuzuweisen (Der = Operator hat hier die geringste Priorität). Dazu müßte man den Ausdruck alt = neu in Klammern setzen. Dann würde das logische && von links nach rechts ausgewertet und die Zuweisung alt = neu nur erfolgen, wenn zuvor alt == 0 und neu != 0 logisch richtig waren. Damit spart man sich nicht nur eine Zeile ein, sondern erzeugt auch ein ganz anderes Verhalten.
> ich kann die ports aber von anfang an nicht konfigurieren Dann machs wenigstens so: Port konfigurieren Timer initialisieren Interrupts starten und innerhalb der Interrupt Routine wertest du nur mehr den Pin-Zustand aus. Aber lass um Gottes Willen während der kompletten eigentlichen Messung die Portkonfiguration in Ruhe. > und so lassen weil das lcd alle ports belegt! Keine gute Idee.
Reden wir jetzt aneinander vorbei? Was hat das eine mit dem anderen zu tun, ausser das das LCD Port-Pins belegt und du aber einen Pin als Eingang zum Abfragen brauchst. Du hast dir doch einen Timer aufgesetzt, der in regelmaessigen Zeitabständen einen Interrupt ausloest. Vom Auftreten eines Interrupts bis zum Auftreten des nächsten Interrupts zählst du mit wieviele 0-1 Übergänge an besagtem Eingangspin auftreten.
nein ich zähle nicht mit dem timer! ich zähle in der mainloop! in dem timer sende ich die daten an das lcd!
Damit ich das richtig sehe: Den Timer, mit dem du eine stabile Zeitbasis hinkriegen könntest, nimmst du um damit Daten auf ein LCD zu schaufeln. Auf der anderen Seite benutzt du dort wo du eigentlich ein genaues Timing brauchen würdest eine Wald und Wiesen Schleife, die durch jeden dahergelaufenen Interrupt ab und an mal unterbrochen werden kann. Und da wunderst du dich, dass die Zählerstände schwanken?
aha, und woher hast du die zeitbasis in der mainloop? die kann doch unterbrochen werden durch interrupts und während dieser zeit wird dein zählregister nicht mehr inkrementiert... mit nem timer hast du ne stabile zeitachse (zB alle 1ms gibts 1 interrupt und 1 counter++)
Vielleicht hab ich dich auch nur falsch verstanden. Die Struktur sollte so aussehen: In der Mainloop detektierst du ständig, ob am Eingang ein 0-1 Übergang erkennbar ist. Im Timer-Interrupt (der regelmässig aufgerufen wird), wird der Zaehlerstand ausgewertet und wieder auf 0 gesetzt. Natuerlich sollte die Timer-Interrupt-Funktion nicht allzu lange dauern. Auf keinen Fall darf sie laenger als ein kompletter 0-1-0 Übergang sein. Die Ausgabe auf das LCD ist also nicht so toll da drinnen. Die wuerde ich da komplett rausschmeissen. main wuerde dann in etwa so aussehen (Achtung: Pseudo Code der so ähnlich wie C aussieht). init_lcd() while( 1 ) if( mode == 0 ) { counter = 0; mode = 1; Konfiguriere Eingang zum Aufnehmen der Pulse; starte_timer(); } if( mode == 2 ) { // mode ist vom Timer Interrupt auf 2 // gestellt worden, damit wird signalisiert // das eine bestimmte Zeiteinheit abgelaufen // ist. stoppe_timer(); mode = 0; Konfiguriere Eingang wieder zurueck; counter auswerten und anzeigen; } if( mode == 1 ) { // mode == 1 bedeutet dass zur Zeit gemessen // wird. neu = .... .... if( .... counter++; alt = neu; } } Und die Timer-Overflow Funktion hat nur noch eine Aufgabe: Die globale Variable mode von 1 auf 2 zu setzen um der main-loop anzuzeigen, dass die Zeit abgelaufen ist.
Oops. Jetzt hab ich im letzten Posting während des Schreibens 2 Ideen zu einer einzigen vermanscht. Ich würde es so machen, wie im 2.-ten Teil beschrieben. Wenn du Frequenzen misst, dann ist die Zeitbasis der Messung eines der wichtigsten Dinger. Ob das LCD nach 10 ms oder 11 ms upgedatet wird, interessiert keine S.. .
ich habe aber keine schwankungen mehr! der zähler in der mainloop läuft stabil! alle eine sekunde kommt ab und zu mal eine schwankung von 1! aber das ist akzeptabel! das senden im timer funktioniert auch problemlos! danke für eure hilfe!
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.