Hallo, für ein Projekt brauche ich eine Möglichkeit, mit einem ATtiny25 Impulslängen zu messen. Es sollen dabei 3 Zustände erkannt werden: 1. Der Impuls ist kürzer als 1,5 ms 2. Der Impuls ist zwischen 1,5 ms und 4,5 ms und 3. Der Impuls ist länger als 4,5 ms. Bei diesen Zuständen sollen dann verschiedene Vorgänge ausgeführt werden. In meiner Schaltung ist ein Taster an PB0 angeschlossen, PB1, PB3 und PB4 sind Ausgänge und PB2 ist nicht belegt. Der uC ist mit 1 MHz getaktet. Da ich erst vor kurzen mit der Mikrocontrollerprogrammierung angefangen habe, weiß ich jedoch nicht, wie ich diese Impulsmessung realisieren kann. Das Programm möchte ich in C schreiben. Was bei den Zuständen passieren soll, kann ich selbst schreiben, bei der Impulsmessung brauche ich aber Hilfe. Könnte einer von euch mir vieleicht einen Beispielcode geben, der diese Impulsmessung durchführt? Ich bedanke mich schonmal im Voraus für die Antworten. MfG Marcus
Ergänzung: Bei den Längen meine ich 0,15s und 0,45s. Durch diese Impulsmessung soll Morsecode vom Taster eingelesen werden. MfG Marcus
Marcus W. schrieb: > Da ich erst vor kurzen mit der Mikrocontrollerprogrammierung angefangen > habe, weiß ich jedoch nicht, wie ich diese Impulsmessung realisieren > kann. Hallo Marcus, zuerst willkommen im Forum! Impulslängenmessungen würden viele hier vermutlich über einen Timer realisieren. Da der ATtiny25 8-Bit-Timer besitzt, würde ich einen solchen Timer ständig laufen lassen und über zwei Register (zusammen dann 16 bit) Millisekunden (oder 10-Millisekunden-Schritte) zählen. Das wäre meine "Uhr", anhand derer ich die Impulslängen berechnen würde. Ach, halt, die Impulse würde ich - wie die Sache mit dem Timer - ebenfalls per Interrupt behandeln, und zwar per INT0. INT0 ist fest dem PB2 zugeordnet. Das Ganze ist aber so komplex, dass du dir zuerst das Datenblatt genau durchsehen solltest. Es gibt auch Tutorials hier in der Community, z.B. dieses: http://www.mikrocontroller.net/articles/AVR-Tutorial:_Timer Nebenbei: Für deinen Zweck scheint auch der billige ATtiny13A zu reichen. Zusätzlich könnte es sich lohnen, den Mikrocontroller mit 128 kHz (reicht für deinen Zweck) zu takten, dann braucht er sehr viel weniger Strom.
Marcus W. schrieb: > Da ich erst vor kurzen mit der Mikrocontrollerprogrammierung angefangen > habe, weiß ich jedoch nicht, wie ich diese Impulsmessung realisieren > kann. Obwohl Marcus W. natürlich mit seinen Ausführungen recht hat, möchte ich gern darauf hinweisen dass es immer (besonders als Anfänger) besser wäre einen z.B. Atmega88 zu nehmen. Da hat man mehr Anschlüsse und vorallem auch einen Seriellport. Da kann man sich dann immer mal Statusinformationen ausgeben lassen. Ich selbst bin bestimmt schon seit 3-4 jahren mit Atmels unterwegs und ich mache die Entwicklung immer auf nem Mega88. Wenn es dann rund läuft passe ich die Ports an und flasche das dann in die Tiny 25/45/85. Gruss Klaus
Markus W. schrieb: > Ach, halt, die Impulse würde ich - wie die Sache mit dem Timer - > ebenfalls per Interrupt behandeln, und zwar per INT0. INT0 ist fest dem > PB2 zugeordnet. Damit wären wir auch schon beim Thema Entprellen. Beim direkten Auswerten eines Taster per Interrupt gibt es wegen des Tastenprellens bei jedem Schalten einen ganzen Haufen von Interruptereignissen, die man filtern muß, bevor man damit irgendetwas sinnvoll steuern kann. Beitrag "Tasten entprellen - Bulletproof"
Sowie ich eine Delay Funktion zum Entprellen nutze taugt sie meiner Meinung nichts... Ingo
Auch wenn Dir noch weitere kluge Köpfe andere Controller vorschlagen, bleib bei Deinem Tiny25. Als erstes solltest Du einen Timer so programmieren, dass er ca. jede 10ms einen Überlauf erzeugt. Ist der zu messende Impuls aktiv, wird eine Variable mit jedem Überlauf hochgezählt, bis der Impuls wieder vorbei ist. Die Anzahl der gemessenen Überläufe steht in der Variable und kann ausgewertet werden. Anschließend wird sie wieder auf 0 gesetzt und auf den nächsten Impuls gewartet. Bei der Auswertung muß beachtet werden, dass die Überläufe nicht genau alle 10ms erfolgen, sondern vielleicht alle 8 oder 12 ms. Das hängt von der Einstellung der Timerregister ab (Vorteiler + Timer). All diese Abläufe können zunächst ohne Interrupt erledigt werden. Falls ein Taster entprellt werden muß, kann dies zunächst per RC-Glied passieren. So kommst Du erst einmal zu einem Erfolgserlebnis. Anschließend könntest Du die Timerüberläufe per Interrupt erfassen und den ext. Impuls per Software entprellen - wenn dies überhaupt notwendig ist.
Das wäre die Light Version. Wenn du es richtig machen willst, startest einen Timer bei steigender Flanke und stoppst ihn wieder bei der nächsten steigenden Flanke, dann wertest du den Zählerstand aus. Ingo
Marcus W. schrieb: > Durch diese Impulsmessung soll Morsecode vom Taster eingelesen werden. Dann schau Dir mal die Entprellung mit Repeatfunktion an. Die Zeiten paßt man entsprechend an, fertig. Peter
Marcus W. schrieb: > Bei den Längen meine ich 0,15s und 0,45s. Du willst also Impulse von etwa 150 ms und 450 ms auseinander halten. Marcus W. schrieb: > Durch diese Impulsmessung soll Morsecode vom Taster eingelesen werden. Ich denke mal, dass Du dann auch die Impulspausen messen solltest, damit Du die Trennung zwischen den Zeichen (1 bis 5 Impulse pro Zeichen) erkennen kannst. Und da die Morsetaste ein mechanischer (prellender) Schalter ist, muss auch noch eine gute Entprellung realisiert werden. Das ist alles in allem nicht unbedingt ein Anfängerprojekt... Um das 8-bittig realisieren zu können, muss eine zeitliche Auflösung gewählt werden, die die längste zu erwartende Impulsdauer noch mit einem Byte abbilden kann. Dabei halte ich 4 ms für akzeptabel, das ermöglicht ohne Übertrag Impulslängen bis 1,02 Sekunden. Bei 1,0 MHz Taktfrequenz muss der Timer also alle 4000 Takte einen Interrupt auslösen, wobei das nicht unbedingt ein Überlauf-Interrupt sein muss, denn die Compare-Interrupts sind dazu viel besser geeignet. Bei Nutzung des Timer1 stehen die Vorteiler in 1:2-Stufen zur Verfügung, bei Timer0 nur in 1:8 bzw. 1:4-Stufen. Mit Timer1 und Vorteiler 1:16 braucht der Timer einen Zählumfang von 250 für 4 ms Interrupt-Takt. Man wähle also den CTC-Modus und setze das OC-Register auf 249, also Endwert-1. Somit klappert der Timer1 im Hintergrund von 0 bis 249, bei 250 ist er wieder 0 und löst den Interrupt aus. In diesem Interrupt (alle 4 ms) wird nun die modifizierte Vierfach-Entprellung (Dannegger-Algorithmus) aufgerufen und dabei separat die (entprellte!) H- und L-Flanke detektiert und per separate Merker bzw. Flags dem Hauptprogramm mitgeteilt. Weiterhin zählt diese ISR ein Zählregister hoch, das die (bereits erwähnte) innere Uhr darstellt. Das Hauptprogramm fragt nun die Merker ab. Bei jedem Impulsbeginn wird der Zählerstand des Zählregisters als "Impulsbeginn" gesichert. Desweiteren wird von einer Kopie des Zählerstandes der (auch gesicherte) Termin des letzten Impulsendes subtrahiert und daraus die Länge der Impulspause ermittelt. Ist diese größer als die vereinbarte Zeichentrennung, dann wird aus den im Puffer gesammelten Bits ein Zeichen generiert, in den Textpuffer geschrieben und der Zeichen-Puffer gelöscht. Bei jedem Impulsende wird das Zählregister kopiert, als "Impulsende" gesichert, der Termin des Impulsbeginnd davon subtrahiert und das Ergebnis (Impulsdauer) mit den Referenzwerten (im 4ms-Raster) verglichen. Das Ergebnis des Vergleiches (kein Zeichen, Punkt, Strich, ungültige Überlänge) wird bei Gültigkeit in den Zeichen-Puffer geschrieben, bei Ungültigkeit wird der Zeichen-Puffer geleert und ein (vereinbartes) Error-Zeichen in den Textpuffer geschrieben. Die Mainloop prüft weiterhin den Textpuffer auf Inhalt, parst diesen und entfernt beim Erkennen von vereinbarten Schlüsselworten diese aus dem Textpuffer und löst die vereinbarte Handlung aus. Sollten im Programm noch weitere zeitabhängige Dinge (Blinker, Zeitmessungen) nötig werden, so können diese aus einem weiteren Zählregister abgeleitet werden, das in der Timer-ISR hochgezählt wird. Marcus W. schrieb: > Das Programm möchte ich in C schreiben. Ja, dann schreib'... In ASM oder notfalls auch Bascom könnte ich Dir helfend zur Seite stehen, in C halte ich mich mangels Kompetenz aber raus. ...
Peter Dannegger schrieb: > Dann schau Dir mal die Entprellung mit Repeatfunktion an. Die Zeiten > paßt man entsprechend an, fertig. Dachte ich auch zuerst, er muss aber auch die Pausen messen, um die Bits der Zeichen trennen zu können. ...
Hannes Lux schrieb: > Das ist alles in allem nicht unbedingt ein Anfängerprojekt... Weil jeder die Anforderungen des Vorredners erhöht und damit nur weitere Hürden aufbaut! Zur Entprellung: Hier reicht ein 100nF Kondensator des Eingangspins gegen 0V. Davor liegt ein 100k Widerstand in Reihe, der die Impulse des Tasters bekommt. Geschickterweise schaltet der Taster gegen 0V; daher wird noch ein Pullup-Widerstand 10k nach VCC gelegt. Fertig! Timer: Bei 1MHz Prozessortakt nimmt man für T1 einen Vorteiler von 32. Ein Überlauf findet demnach alle 32 x 256 Takte statt. Das sind rund 12,21ms. Zählt man die Überläufe bis 12, entspricht dies ca. 0,144s. Das ist die untere Grenze; die obere liegt Faktor drei höher bei 37. Der Timer wird gestartet, indem der Vorteiler eingeschaltet, T1 auf 0 gesetzt und das Overflow-Flag gelöscht wird. Ebenfalls fertig!
Willi schrieb: > Zur Entprellung: > Hier reicht ein 100nF Kondensator des Eingangspins gegen 0V. Immer wieder lustig, wie krampfhaft versucht wird, an falscher Stelle Code zu sparen. Wenn eh der Timer benutzt wird, warum dann nicht damit gleich entprellen? Sind <1% CPU-Last wirklich zu hoch? Peter
Hannes Lux schrieb: > Dachte ich auch zuerst, er muss aber auch die Pausen messen, um die Bits > der Zeichen trennen zu können. Davon hat er aber nichts gesagt. Vielleicht soll das ja nur ne Zugangsgkontrolle sein und keine Schreibmaschine. Peter
Im Hobbybereich zählt nicht immer 100% richtiges Handeln, Hauptsache es funktioniert irgendwie. Daher 100nF +100k, schon spart man sich das softwareseitige Entprellen. Bei ein paar Million Geräten sind die 2 Ct für den R und C natürlich schon sehr teuer... Ingo
Es geht aber auch noch einfacher... Auch wenn es deutlich weniger elegant ist, kann man als Anfänger auch erst mal ohne Interrupts alles in der Hauptschleife machen. Per delay alle 20 ms Eingang abfragen, das entprellt quasi von selbst, und einfach zählen, wie viele dieser 'Ticks' das Ding an war, weniger oder mehr als 15. Wie es noch besser geht, kann man dann ja hier in den anderen Posts nachlesen.
Da die bei dem Projekt die Zeiten sowas von unkritisch sind, braucht man sich um die Entprellung (bis ~10ms) keine Sorgen machen, wenn die Taster maximal alle 20 ms ausgelesen werden. Vorteiler des Timers auf ~20ms einstellen. Im Overflow-Interrupt: eine globale oder statische variable hochzählen und bei einer Flanke Zeit messen: ZeitIn20ms = VariableBeiFallenderFlanke-VariableBeiSteigenderFlanke volatile uint8_t NeueAnZeitVorhanden=0; volatile uint8_t NeueAusZeitVorhanden=0; volatile uint8_t Zeit=0; ISR( ovrflow_für_meinen_avr ) { static uin8_t Counter = 0; static uin8_t OldCounter = 0; static uint8_t myOldTaster = !(PIN_X & (1<<MY_PIN)); uint8_t myTaster = !(PIN_X & (1<<MY_PIN)); if( myTaster && !myOldTaster ) //Steigende Flanke { Zeit = counter - OldCounter; NeueAnZeitVorhanden = 1; OldCounter = counter; } else if( !myTaster && myOldTaster ) //Steigende Flanke { Zeit = counter - OldCounter; NeueAusZeitVorhanden = 1; OldCounter = counter; } counter++; } ... main .. for(;;) { if( NeueAnZeitVorhanden ) { MachWasMitNeuemTastenDruck( Zeit ); NeueAnZeitVorhanden=0; } if( NeueAusZeitVorhanden ) { MachWasMitNeuerPause( Zeit ); NeueAusZeitVorhanden=0; } ... } ... }
Peter Dannegger schrieb: > Immer wieder lustig, wie krampfhaft versucht wird, an falscher Stelle > Code zu sparen. Wer hat denn vom Codesparen geredet? Mir geht es darum, einem Anfänger einen gangbaren Weg ohne zuviel Frust aufzuzeigen. Irgendwelche 'genialen' Entprellcodeschnipsel sind hier nicht angesagt. Derzeit ist nicht einmal klar, ob überhaupt ein prellender Impuls vorliegt. Schon vor über 40 Jahren gab es Morsetasten, die automatisch kurze und lange Impulse generierten: rechts-links und in der Mitte war Ruhe.
Ingo schrieb: > Daher 100nF +100k, schon spart man sich das > softwareseitige Entprellen. Genau das ist der Punkt, man spart damit garnichts. Wenn man eh den Timer oder ein Delay benutzt, dann fällt das Entprellen quasi mit ab. Wenn Du eh Bier einkaufen gehst, kannst Du auch Deiner Frau Blumen mitbringen. Es ist kein Mehraufwand. Peter
Doch, du sparst dir das softwareseitige Entprellen, hast du wohl überlesen. Ingo
Ingo schrieb: > Doch, du sparst dir das softwareseitige Entprellen, hast du wohl > überlesen. Und, was bringt dir das? Softwareseitiges Entprellen ist pipifax. Ganz besonders in dem Fall, in dem er sowieso die Zeiten messen muss. Pulse kleiner als 10ms werden einfach ignoriert, da sie Prellpulse sind. PeDas Lösung kann man nehmen, muss man aber nicht. Ums Bestimmen der zeitlichen Länge kommt man nicht herum, bei der Auswertung von Morsezeichen. Hat man das erst mal im Griff, dann ist softwareseitiges Entprellen nur noch eine Zugabe.
Um das Problem mal ganz destruktiv zu lösen: Die Suche nach "pulsweite" in der Codesammlung bringt eine fertige Lösung, die schön viel Code erzeugt und auch einen ATmega88 braucht, wie es einigen Leuten so richtig gefällt: Beitrag "Stoppuhr – Geschwindigkeit – Pulsweite mit Atmega88" Nimmt man dann noch einen Hallsensor, erübrigt sich die Diskussion um eine Entprellung. Das Problem ist schnell gelöst und der TO hat nichts dazugelernt :-(
Willi schrieb: > Das Problem ist schnell gelöst und der TO hat nichts dazugelernt Das ist doch aber trendy, oder? ...
Für den TE ist es offensichtlich nicht alles pipifax, sonst hätte er sich mit seinem Problem nicht geoutet, dass er noch Anfänger ist... Aber bitte, wenn ihr der Meinung seit die Kondensatoren und Widerstände sein die schlechtere Lösung, nur zu... Man kann's sich auch als Anfänger schwerer machen als es ist. Ingo
Ingo schrieb: > Aber bitte, wenn ihr der Meinung seit die Kondensatoren und Widerstände > sein die schlechtere Lösung, nur zu... Man kann's sich auch als Anfänger > schwerer machen als es ist. Man kann auch einem Anfänger einreden, das das Problem schwer sei. Er misst Pulszeiten an einem Eingangspin. Anstatt if( Zeit < 0.3 Sekunde ) war ein Punkt else war ein Strich schreibt er einfach if( Zeit > 20 Millisekunden ) if( Zeit < 0.3 Sekunden ) war ein Punkt else war ein Strich fertig ist eine für seine zwecke ausreichende Entprellung. Was ist daran jetzt nicht pipifax? Vielleicht einfach mal im Vorfeld überlegen, wie das Programm so in etwa aussehen könnte? Wenn er sowieso die Pulslänge messen muss, wobei es genügt, diese ungefähr festzustellen, kann man genauso gut eindeutig zu kurze Pulse einfach ausfiltern. Ich frage mich wie er wohl die Morsezeichen dekodieren will, wenn das jetzt schon ein 'Problem' darstellt.
Ingo schrieb: > Doch, du sparst dir das softwareseitige Entprellen, hast du wohl > überlesen. Nein, Du sparst nichts. Zeit, die man bei der Projektüberlegung spart, ist vergeudete Zeit. Man braucht hinterher dann ein Vielfaches bei der Implementierung und Debugging. Dagegen ist es sehr zeitsparend, schrittweise vorzugehen und nicht Schritte zu überspringen. Also erstmal eine Entprellung zu verstehen und zu implementieren. Dann ist der Schritt zur lang/kurz-Erkennung nur noch minimal. Peter
Peter Dannegger schrieb: > Dagegen ist es sehr zeitsparend, schrittweise vorzugehen und nicht > Schritte zu überspringen. Na dann sollte sich der TO den C-Compiler noch selber schreiben; das ist ein sehr wichtiger Schritt: "Man braucht hinterher dann nur einen Bruchteil bei der Implementierung und beim Debugging."
Willi schrieb: > Derzeit ist nicht einmal klar, ob überhaupt ein prellender Impuls > vorliegt. Schon vor über 40 Jahren gab es Morsetasten, die automatisch > kurze und lange Impulse generierten: rechts-links und in der Mitte war > Ruhe. Und du meinst, dass die dort verwendeten Kontakte nicht geprellt haben? Es macht einen Unterschied, ob man damit einen Sender steuert, dem das Prellen ziemlich egal ist, da zur Bandbreitenbegrenzung die Flanken sowieso verschliffen werden oder ob eine Digitalmimik auf jede Flanke reagiert.
Willi schrieb: > Peter Dannegger schrieb: >> Dagegen ist es sehr zeitsparend, schrittweise vorzugehen und nicht >> Schritte zu überspringen. > > Na dann sollte sich der TO den C-Compiler noch selber schreiben; das ist > ein sehr wichtiger Schritt: Das hingegen hat keiner behauptet, dass das sinnvoll ist. Fallt doch bitte nicht von einem extrem ins andere.
Werner schrieb: > Und du meinst, dass die dort verwendeten Kontakte nicht geprellt haben? Die Impulse wurden von einem Multivibrator erzeugt. Die Gebergeschwindigkeit mußte man vorab auf sein eigenes Tempo einstellen. Die Geber waren sehr gewöhnungsbedürftig, aber die Leute, die damit umgehen konnten, haben damit "Musik" gemacht :-) Karl Heinz Buchegger schrieb: > Fallt doch bitte nicht von einem extrem ins andere. Manchmal ist es eben doch ärgerlich, wenn einem Anfänger nur Knüppel zwischen die Beine geworfen werden. Meine Meinung, die Sache einfach zu halten, habe ich weiter oben ja beschrieben.
So, mal ganz einfach, aber nicht getestet:
1 | void main() { |
2 | int oncount=0; |
3 | while(1) { |
4 | if (tastegedrueckt) { |
5 | oncount++; |
6 | }else{ |
7 | if (oncount) { //Taste wurde gerade eben losgelassen! |
8 | if (oncount>15) langerdruck(); //lange gedrückt; >15*20ms=300ms |
9 | else kurzerdruck(); //kürzer gedrückt |
10 | }
|
11 | oncount=0; //zurücksetzen |
12 | }
|
13 | _delay_ms(20); //alle 20ms nachsehen |
14 | }//while(1) |
15 | }//main |
Todo: tastegedrückt, langerdruck(), kurzerdruck() implementieren, evtl. oncount-Überlauf verhindern Nachteil: keine Nebenläufigkeit, d.h. das Programm ist nur damit beschäftigt und kann während des Wartens nichts sonst machen. Wenn langerdruck() und kurzerdruck() lange dauern, wird währenddessen der Taster ignoriert.
Willi schrieb: > Manchmal ist es eben doch ärgerlich, wenn einem Anfänger nur Knüppel > zwischen die Beine geworfen werden. Wie kommst Du darauf? Der TO hat sich nirgends in dieser Richtung geäußert. Er kann doch fragen, wenn er irgendwo Probleme hat. Er muß die Probleme einfach nur benennen und nicht wischiwaschi "geht nicht". Es steht natürlich jedem frei, die Fehler zu wiederholen, die vor ihm schon 1000 andere gemacht haben. Ich halte das aber für reine Zeitverschwendung. Ich habe auch mal so angefangen, Spaghetticode aneinander zu kleistern, bis ich nicht mehr durchsehe und nichts mehr läuft. Und dann habe ich gemerkt, man kann die Aufgaben aufteilen und in Unterfunktionen kapseln. Und schon geht alles viel besser und läßt sich auch besser verstehen. Seither nehme ich erstmal Papier und Bleistift und male mir das Programmkonzept grob auf. Peter
Und wie Du sollte man diese Erfahrungen am besten selbst machen.
Hallo, erstmal Danke für die vielen Ideen und Tipps! Am Sonntag hatte ich leider keine Zeit mehr, hier nochmal nachzugucken. Ich werde dann jetzt versuchen, das mit dem Timer und einem Interrupt zu lösen. Wenn ich was habe, poste ich mal den Code. Marcus
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.