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
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"
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
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 :-(
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.
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
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