Forum: Mikrocontroller und Digitale Elektronik drehzahlmesser


von gartler p. (Gast)


Lesenswert?

Guten abend, allerseits

ich bin leider nur elektriker und ein hobbyelektroniker, daher die etwas 
gewagte frage

ich nehme via schmitt trigger kapazitiv über das zündkabel eines kleinen 
2 takt motors das signal ab ab und habe dann sauberes rechtecksignal am 
atmega 644

leider bringe ich das programm selber nicht hin

habe schon einiges versucht, aber so recht will es nicht

gedacht ist ein externer interupt, mit dem ich einen counter raufzählen 
lasse

dann will ich mittels internem interupt ein zeitfenster vorgeben, wo der 
zähler ausgewertet wird

in der while schleife mache ich mehrere if bedingungen rein, also pro 
led 1 bedingung..
Je höher die drehzshl, desto mehr leds sollen leuchten und ab bestimmter 
drehzahl sollen alle blinken

kann mir da wer weiterhelfen mit dem code, den ich in atmel 6.2 
schreibe?

vl mache ich auch einen fehler beim initialisieren der interupts...

beste grüsse

von gvs (Gast)


Lesenswert?

1a) Man kann direkt auf einen Timer/Counter Eingangspin gehen und der 
Counter zählt per Hardware (ohne Interrupt).

1b) Man kann einen Pin-Change Interrupt verwenden um damit einen Zähler 
per Software zu erzeugen.

2) Ohne Quellcode kann dir keiner helfen.

von gartler p. (Gast)


Lesenswert?

So...dann mal den code

im main steht
cli();
DDRA=0xff; DDRC=0xff;
DDRD=0b11110111;
TCCR2B=(1 <<CS22)|(1 <<CS21)|(1 <<CS20);
TCNT2=10;
TIMSK2|=(1 <<TOIE2);
MCUCR=(1 <<ISC11)|(1 <<ISC10);
sei();

In der while stehen nur die bedingungen, wo der zählwert verglichen 
wird, also das hier als beispiel..

If ((cnt> 2)&&(cnt<6))
{
PORTA=0b00000001;
PORTB=0b00000000;
}

Das mit unterschiedlichen werten

dann das zeitfensted als internen interupt

ISR(TIMER2_OFV_vect)
{
flag=1;  // ist bei mir in der main eingebunden mit rücksetzung
cnt=spark;
spark=0;
TCNT2=10;
}

und hier der externe interupt

ISR(INT1_vect)
{
spark++;
}


Der atmega 644 muss eh nen schaden haben, denn nicht alle ports lassen 
5v raus trotz beidseitiger spannungsversorgung


Kann da wer helfen?

von m.n. (Gast)


Lesenswert?

Mit dem Suchbegriff "Drehzahl" in 'Projekte & Code' findet man dies
http://www.mikrocontroller.net/search?query=drehzahl&forums[]=4&max_age=-&sort_by_date=0
Da sollte doch etwas zu finden sein.

von Wolfgang (Gast)


Lesenswert?

gartler p. schrieb:
> So...dann mal den code

Und deine Variablen hast du nicht irgendwo deklariert?

Mir sticht da gerade spark ins Auge. So geht das Programm doch 
nichtmal durch den Compiler.

> Der atmega 644 muss eh nen schaden haben, denn nicht alle ports lassen
> 5v raus trotz beidseitiger spannungsversorgung

 - Wie hast du den angeschlossen?
 - Welche Ports sind betroffen?
 - Wie ist JTAG konfiguriert?

von Thomas W. (wagneth)


Lesenswert?

Wenn der Controller eh einen Schaden hat, brauchst Du einen neuen...

Vielleicht ist dein Vollständiges Programm ja korrekt !? ;)

von gartler p. (Gast)


Lesenswert?

Dependency injections sagen mir leider gar nichts

so sehr will ich gar nicht ins detail gehen

die variablen, wie auch die defines und includes, sind natürlich 
definiert...alles globale variablen

ich habe den prozessor gegen einen atmega 32 getauscht, alle ports gehen 
auch hier nicht, aber es gibt genug andere freie ports

eigenartig, dass der 32er sich nur im intrcosc 8mhz programmieren 
lässt...ich denke aber, dass das programm so funktionieren wird.


was genau stimmt mit der interupt routine nicht?
sobald eine steigende flanke ansteht, wird spark um 1 erhöht....alle 1/4 
sec vom anderen interupt spark eingelesen und wieder auf null gestellt

wenn wer einen schnellem kurzcode für mich hätte, wäre ich dankbar

von gartler p. (Gast)


Lesenswert?

Naja, versuch es doch mal, verständlich und ev mit Code 
rüberzubringen...das wäre durchaus hilfreich

von ich (Gast)


Lesenswert?

gartler p. schrieb:
> Naja, versuch es doch mal, verständlich und ev mit Code
> rüberzubringen...das wäre durchaus hilfreich

Wenn ich dir einen Rat geben darf, das süße Spice-Girl trollt in vielen 
anderen Beiträgen auch nur rum und versucht alle zu beleidigen und Stunk 
zu verbreiten. Einfach ignorieren, ok?

von Wolfgang (Gast)


Lesenswert?

gartler p. schrieb:
> Dependency injections sagen mir leider gar nichts

Und dir fällt auch nichts dazu ein, wie du zumindest eine grobe 
Vorstellung bekommen kannst, was damit gemeint ist?
http://de.wikipedia.org/wiki/Dependency_Injection

> die variablen, wie auch die defines und includes, sind natürlich
> definiert...alles globale variablen

Die Frage ist nicht, ob sie definiert sind, sondern wie.
Ich war nicht davon ausgegangen, dass du nicht kompilierbaren Code auf 
den µC geladen hast - wie auch ;-)

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

spicy meint vermutlich sowas hier:
http://martinfowler.com/articles/injection.html#InversionOfControl, 
wobei ich die Ausdrucksweise (genau wie Martin Fowler) auch verwirrend 
finde. Es hilft dir auch nicht, wenn du mit Fremdworten zugeschaufelt 
wirst, das kann ich gut verstehen.

Der Ansatz an sich ist ja schon richtig. Ein wie auch immer gearteter 
Zähler zählt die Zündimpulse und ein Zeitgeber holt sich den Zählerstand 
und setzt den Zähler zurück.
Aus deinem Codefragment geht aber leider nicht hervor, ob du z.B. die 
Variablen richtig deklariert hast. Variablen, die in ISR verwendet 
werden,sollten bis auf wenige Ausnahmefälle als 'volatile' erklärt 
werden, denn für den Compiler ist eine ISR ein Unterprogramm, das 
nirgends aufgerufen wird (geschieht ja durch ein externes Ereignis) und 
er neigt deswegen dazu, Variablen wegzuoptimieren, wenn sie nicht 
volatile sind. Dadurch entstehen lustige und weniger lustige Effekte.

Um die Hardware des MC besser auszunutzen, ist es ausserdem sinnvoll, 
wie gvs schon vorschlug, die Impulse mit T0 (Counter/Timer 0) oder T1 
(Counter/Timer 1) zu zählen, das geschieht dann vollautomatisch, ohne 
das eine ISR benötigt wird. Dazu konfigurierst du einen Timer als 
Counter mit externem Takt und schliesst die Pulse an T0 oder T1 an. (Pin 
1 oder Pin2 am Mega 644)
Dein Zeitfenster bildest du mit einem anderen Timer. Dieser löst alle 
z.B. 100ms einen Interrupt aus, der den zählenden Counter ausliest und 
zurücksetzt.
Dein Hauptprogramm kann dann mit dem gespeicherten ausgelesenen Wert, 
machen was es will.

gartler p. schrieb:
> ich habe den prozessor gegen einen atmega 32 getauscht, alle ports gehen
> auch hier nicht

Mir klingt das Problem arg nach aktiviertem JTAG Interface. Wenn du mal 
die Fuses anschaust und umprogrammierst, sperre das JTAG und dann sollte 
sich Port C normal verhalten.

: Bearbeitet durch User
von grundschüler (Gast)


Lesenswert?

gartler p. schrieb:
> alle ports gehen
> auch hier nicht

das sind die jtag-Pins auf PortC ->Fusebits

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

spicy schrieb im Beitrag #3894986:
> Was hat JTAG bitte mit einer fehlerhaften Programmstruktur zu tun?

Tja, wer aus dem Zusammenhang zitiert, findet das verwirrend.
Für dich also nochmal komplett:

Matthias Sch. schrieb:
> gartler p. schrieb:
>> ich habe den prozessor gegen einen atmega 32 getauscht, alle ports gehen
>> auch hier nicht
>
> Mir klingt das Problem arg nach aktiviertem JTAG Interface. Wenn du mal
> die Fuses anschaust und umprogrammierst, sperre das JTAG und dann sollte
> sich Port C normal verhalten.

Jetzt sollte das auch dir klar werden.

von Wolfgang (Gast)


Lesenswert?

Oder kurz:

Wolfgang schrieb:
> - Wie ist JTAG konfiguriert?

spicy schrieb im Beitrag #3894986:
> Was hat JTAG bitte mit einer fehlerhaften Programmstruktur zu tun?

Du scheinst in deiner Programmstrukturwelt vor lauter 
Schlagwortschwurbelei nicht erkannt zu haben, dass es noch mehr Probleme 
gibt.

von gartler p. (Gast)


Lesenswert?

Also, die variablen sind als volatile definiert, also das sollte passen

ich werde nächste woche den signalgenerator anhängen und mal 
durchtesten, ob es funktioniert

die fuses werde ich mir genauer ansehen...es funktionieren im moment 
pc7, pc6, pc1 und pc0....die anderen geben definitiv zu wenig spannung 
raus, man kann gaaaaanz geringes leuchten sehen

Ich habe nun timer 1 fürs zählen aktiviert....

@matthias....wie kann man sich da im detail die interupt routine am 
zähler 1 ersparen? Ich muss doch irgendwie definieren, dass bei z.b 
steigender flanke ein zähler hochzählt

@ich...wer provoziert, muss anderswo n defizit haben, daher reagiere ich 
da nicht so wirklich drauf...
ich suche nur rat und bleibe dabei freundlich

anfänger bin ich ja, ich habe sonst mit mittelspannung zu tun..

von grundschüler (Gast)


Lesenswert?

gartler p. schrieb:
> pc7, pc6, pc1 und pc0

nochmal: pc2..5 sind durch JTAG belegt, die musst du erst in den 
Fusebits freischalten

von Thomas F. (igel)


Lesenswert?

gartler p. schrieb:
> Ich habe nun timer 1 fürs zählen aktiviert....
>
> @matthias....wie kann man sich da im detail die interupt routine am
> zähler 1 ersparen? Ich muss doch irgendwie definieren, dass bei z.b
> steigender flanke ein zähler hochzählt

Ich mische mich mal ein;-) Habe einen Drehzahlmesser wie du ihn 
beschrieben ast in Betrieb. Allerdings in ASM programmiert:

Timer 1 wird als Zähler mit Input Capture Irq gestartet:

    ldi  temp1, 0;Timer1 Counter
    out  TCCR1A, temp1
    ldi  temp1, 1<<ICES1|1<<CS11|1<<CS10
    out  TCCR1B, temp1

    ldi  temp1, 1<<OCIE2|1<<TICIE1 | 1<<TOIE1
    out  TIMSK, temp1


Die Routine für den Timer 1 Capture:


icp1:      ;Drehzahl über Input Capture
;  Frequenz:  172800 Hz
;  600-> 17.280rpm   12000-> 864rpm
    in    savereg, SREG
    push  temp1

    in    T1CaptureL, ICR1L;Counterwerte auslesen

    in   T1CaptureH, ICR1H

    clr   temp1
    out  TCNT1H, temp1  ;Counter auf Null setzen
    out  TCNT1L, temp1

    sbr  Pst_status, 1<<0
               ;Motor-an Flag

    pop    temp1
    out    SREG, savereg

    reti


Weiter gibt es noch eine irq-Routine für den Überlauf von Timer1. Tritt 
dieser Interrupt ein, dann wurde kein Zündimpuls gemessen.


T1OVL:    ;Timer 1 Overflow: -> Kein Zündimpuls
    in    savereg, SREG
    push  temp1

    cbr  Pst_status, 1<<0  ;Motor-aus Flag

    clr temp1
    sts drehzahl, temp1
    sts drehzahl+1, temp1

    pop    temp1
    out    SREG, savereg

    reti


Ich hoffe dir mit diesem Beispiel helfen zu können.
PS. Mein Controller ist ein Mega322 mit 11,059 MHz.

: Bearbeitet durch User
von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

gartler p. schrieb:
> @matthias....wie kann man sich da im detail die interupt routine am
> zähler 1 ersparen? Ich muss doch irgendwie definieren, dass bei z.b
> steigender flanke ein zähler hochzählt

Als erstes solltest du dein Impulssignal auch an T0 oder T1 
anschliessen, das sind die externen Counter Eingänge für Timer 0 resp. 
Timer 1.
Nimm dir das Datenblatt des Mega644 (oder Mega32, das können beide) und 
konfiguriere nun den Timer auf 'externen Clock'. Beim Timer 0 im Mega 
644 ist das ' External clock source on T0 pin. Clock on rising edge.', 
also
1
TCCR0B = (1 << CS02) | (1 << CS01) | (1 << CS00);
Der Timer wird nun mit jeder steigenden Flanke am Eingang T0 um 1 
hochgezählt, und zwar ohne, das du softwaremässig irgendwas machen 
musst.
Du musst lediglich darauf achten, das es ein 8-bit Timer ist, der nach 
256 Takten überläuft, also fragst du ihn vorher ab.
Timer 1 konfiguriert du auf regelmässigen Überlauf in bekannten 
Intervallen, am besten im CTC Modus, damit kannst du dir z.B. genau 
100ms oder 500ms aussuchen. In dessen ISR liest du TCNT0 aus, setzt es 
auf 0 zurück und speicherst den ausgelesenen Wert als Zündungen pro 
Zeitintervall. Du bist also mit einer einzigen ISR fertig und hast die 
gewünschte Drehzahl, die du nur nach auf z.B. Umdrehungen pro Minute 
skalieren musst.

Edit: igel z.B. verfolgt noch einen anderen Ansatz. Natürlich könntest 
du auch den Abstand ziwschen zwei Impulsen messen, dafür bietet sich der 
ICP Modus an, das ist es was Thomas hier macht.

: Bearbeitet durch User
von m.n. (Gast)


Lesenswert?

Eine Drehzahlmessung für einen Benzin-Motor muß in der Regel mit 
niedrigen Frequenzen klarkommen. Eine Leelaufdrehzahl von 900 Upm 
entspricht 15 Hz. Hier ist eine Zählung der Eingangsimpulse in einem 
festen Zeitraster eine schlechte Lösung. Bei gewünschten drei 
Anzeigewerten/s (Torzeit 1/3 s) ergeben sich Meßwerte für die Frequenz 
von 4, 5, oder 6 und umgerechnet 720, 900 oder 1080 Upm. Eine stark 
wackelnde Anzeige mit erheblichem Fehler wäre das Ergenbis.

Erheblich besser ist es, die Zeit zu messen, die zwischen zwei Impulsen 
liegt. Bei 900 Upm beträgt die Zeit zwischen den Impulsen rund 66,7 ms 
bei einer recht hohen Auflösung im <= µs-Bereich.
Das Meßverfahren nennt sich 'reziproke Frequenzmessung' und liefert 
beste Ergebnisse gerade bei drehzahltypischen Frequenzen.

Das kleinst Beispielprogramm, was ich als Demo habe, ist ein 
Frequenz-Spannungswandler, der schon auf einm ATtiny44 läuft und auf 
einem ATmega644 erst recht. 
http://www.mino-elektronik.de/fmeter/fm_software.htm#bsp11
Versuche, den Code zu verstehen.
Sobald eine Anzeige hinzukommen soll, wird der Code umfangreicher: 
http://www.mino-elektronik.de/7-Segment-Variationen/LCD.htm#lcd3

Eine allgemeine Beschreibung des Meßverfahrens findest Du hier: 
http://www.mino-elektronik.de/fmeter/fmeter.htm

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Um dir also alle Möglichkeiten offenzuhalten, solltest du also das 
Zündsignal auch noch auf Pin 20 (ICP) routen. Dann kannnst du mit allen 
Ansätzen ausprobieren. Achte nur darauf, das du in der Initialisierung 
der Ports alle diese Pins als Inputs konfigurierst.

: Bearbeitet durch User
von gartler p. (Gast)


Lesenswert?

Vielen dank

werde mich morgen damit beschäftigen...der lösungsansatzvon matthias ist 
gut zu verstehen..danke

von gartler p. (Gast)


Lesenswert?

Hier nochmal päde...
Hab mein altes programm getestet...es ging zwar, allerdings falsch, 
ungefähr 40% daneben

versuchte es dann so:

DDRA=0XFF;
DDRC=0XF8; //(INSGESAMT 13 LEDS direkt angesteuert, soll gehen mit 
11mA/led)
DDRD=0b11111011;
cli();
TCCR0=(1 <<CS02)|(1 <<CS01)|(1 <<CS00); //timer0 auf steigende flanke
TCNT=0;

TIMSK=(1 <<TOIE1); //ich nehme den overflow-modus des timer1 mit preload
TCNT1=59;

MCUCR=(1 <<ISC01)|(1 <<ISC00);
GICR=(1 <<INT0);

sei();


Dann das main mit while programm...abfrage der werte und die 
if-bedingungen

und der interupt sieht so aus

ISR(TIMER1_OVF_vect)
{
flag=1; //wird im main abgefragt und nach den bedinungen auf 0 gesetzt
cnt=TCNT0;
TCNT0=0;
TCNT1=59;
}

LEIDER FUNKTIONIERT DAS PROGRAMM NUN NICHT MEHR....WAS HAB ICH DA 
VERGESSEN?

von Thomas F. (igel)


Lesenswert?

gartler p. schrieb:
> WAS HAB ICH DA VERGESSEN?

Kein Grund gleich rumzubrüllen.
Poste doch mal dein gesamtes Programm. Aus den beiden Schnipseln kann 
man nichts rauslesen. Welche Aufgabe haben jetzt Timer0 und Timer1? Und 
hängt der Zündimpuls nun am INT0 oder ICP1 oder was? Was ist TCNT?

von gartler p. (Gast)


Lesenswert?

? Hab zwar das programm wieder hinbekommen, aber eben ungenau bei 
niedrigen frequenzen...vor allem flippt die anzeige...sieht nicht gut 
aus

würde gern die reziproke messung vornehmen, kann mit der theorie was 
anfangen, das war es auch schon..

will da nicht zu viel zeit damit vergeueden und bitte euch, mir vl den 
start zu ermöglichen, da es eben massiv an praxis mangelt.

Also ich benötige die voreinstellungen für die counter, so ganz blick 
ich nicht durch

ich werde max. 20000rpm messen wollen, bei etwa 15 leds im wichtigen 
drehzahlbereich

ich muss also einen timer auf ctc modus bauen? Sozusagen als 
referenzfrequenz

dann einen counter, der diesen ctc timer startet und bei z.b. 2. 
flankenänderung stopt und ausliest,  zu guter letzt resettet, richtig. ?

das signal will ich via pin 20, also icp auswerten lassen

PLEASE HELP

von gartler p. (Gast)


Lesenswert?

Thomas Forster schrieb:
> gartler p. schrieb:
> WAS HAB ICH DA VERGESSEN?
>
> Kein Grund gleich rumzubrüllen.
> Poste doch mal dein gesamtes Programm. Aus den beiden Schnipseln kann
> man nichts rauslesen. Welche Aufgabe haben jetzt Timer0 und Timer1? Und
> hängt der Zündimpuls nun am INT0 oder ICP1 oder was? Was ist TCNT?

Ich brüll nicht rum, sorry....feststelltaste ist nur hängengeblieben 
..ggg

mein programm ist nicht gut geeignet, weil bei niedrigen drehzahlen 
einfach nur schrott rauskommt, also reziprok...aber da ist momentan die 
umsetzungsgabe nicht da

von Mickey M. (Gast)


Lesenswert?

gartler p. schrieb:
> mein programm ist nicht gut geeignet, weil bei niedrigen drehzahlen
> einfach nur schrott rauskommt, also reziprok...aber da ist momentan die
> umsetzungsgabe nicht da

Hast du keine Großbuchstaben? Es nervt, sowas dahingerotztes lesen zu 
müssen.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

gartler p. schrieb:
> DDRA=0XFF;
> DDRC=0XF8; //(INSGESAMT 13 LEDS direkt angesteuert, soll gehen mit
> 11mA/led)
> DDRD=0b11111011;
> cli();
> TCCR0=(1 <<CS02)|(1 <<CS01)|(1 <<CS00); //timer0 auf steigende flanke
> TCNT=0;
>
> TIMSK=(1 <<TOIE1); //ich nehme den overflow-modus des timer1 mit preload
> TCNT1=59;
>
> MCUCR=(1 <<ISC01)|(1 <<ISC00);
> GICR=(1 <<INT0);
>
> sei();

Ich seh da nirgends eine Initialisierung des Timers 1 (Zeittor). Du 
gibst seinen IRQ frei und füllst seinen Counter, aber er wird nie 
gestartet.
1
  TCNT=0;
Das soll bestimmt TCNT0 sein, oder? Ich wundere mich nur, das dein 
Compiler sowas zulässt, ohne über undefinierte Sachen zu jammern.

von gartler p. (Gast)


Lesenswert?

Oh...doch, hab die zeile nur vergessen einzufügen

von m.n. (Gast)


Lesenswert?

gartler p. schrieb:
> mein programm ist nicht gut geeignet, weil bei niedrigen drehzahlen
> einfach nur schrott rauskommt, also reziprok...aber da ist momentan die
> umsetzungsgabe nicht da

Das hatte ich ja schon angekündigt ;-)

Ich habe Dir ein paar Links gegeben, die Du aufmerksam lesen solltest, 
da sie nicht zu geschwätzig sind. Diese Arbeit kann Dir keiner abnehmen!
Wenn Fragen offen bleiben, frag ganz konkret nach.
Ach, ich habe noch eine etwas einfachere Beschreibung, wie ich hoffe: 
http://www.mino-elektronik.de/Archiv/Elektronik25_1984.pdf

von Thomas F. (igel)


Lesenswert?

gartler p. schrieb:
> Hab zwar das programm wieder hinbekommen, aber eben ungenau bei
> niedrigen frequenzen...vor allem flippt die anzeige...sieht nicht gut
> aus

Wie ungenau und was heißt flippen?
Ein kleiner Zweitakter mit Vergaser schwankt in der Drehzahl ständig um 
locker mal 100 rpm. Das hat mein Drehzahlmesser auch. Um die Anzeige zu 
beruhigen errechne ich einen gleitenden Mittelwert über vier Zündungen 
(glaub ich jedenfalls, ist schon lange her).

> ich muss also einen timer auf ctc modus bauen?
> Sozusagen als referenzfrequenz

Also arbeitest du nun mit Timer-Capture. Dann also Timer1, da der 16-Bit 
breit ist. Das ist keine Referenz, sondern einfach der Zeitzähler, 
wieviel Zählimpulse zwischen den Zündungen auftreten. Niedrige Drehzahl 
-> lange Zeit -> hoher Zählerwert im ICR1.
Achtung, der Zählwert steht im ICR1, nicht in TCNT1. Der 
Input-Capture-Mode von Timer1 bewirkt, dass bei einem Impuls am ICP-Pin 
der aktuelle Wert aus dem Zählregister in das ICR1-Register geschrieben 
wird. Du mustt diesen Wert dann nur noch auslesen.

> dann einen counter, der diesen ctc timer startet und bei z.b. 2.
> flankenänderung stopt und ausliest, zu guter letzt resettet, richtig?

Ein zweiter Counter ist für die eigentliche Drehzahlerfassung gar nicht 
nötig. Das macht alles schon T1 im Input-Capture-Mode.

Ein kleines Beispiel in C:
http://www.mikrocontroller.net/attachment/highlight/20833

von gartler p. (Gast)


Lesenswert?

Ich habs 2 mal sorgfältig gelesen

konkrete fragen dazu lauten

1.) Wie aktiviere ich mit der ersten flanke den referenztimer?
2.) Selbe Frage mit "wie stoppe ich den"
3.) Allgemeines Wirrwarr mit der anfänglichen konfiguration der register

ich weiss, worum es geht, kann es nicht umsetzen...und falls ich es 
nicht hinbekomme, werd ich es einfach lassen und widme mich wieder 
nützlicheren dingen, kein thema

bedanke mich aber trotzdem für die infos und tipps....habe leider keine 
zeit mich da ewig damit zu beschäftigen

kurzum, ein einfacher code der isr und anfänglichen einstellungen wären 
für mich einfacher..

von m.n. (Gast)


Lesenswert?

gartler p. schrieb:
> 1.) Wie aktiviere ich mit der ersten flanke den referenztimer?
> 2.) Selbe Frage mit "wie stoppe ich den"


Mit 'init_timer()' wird Timer1 gestartet und nie wieder gestoppt!
Mit jedem input-capture wird der Zeitpunkt erfaßt und die Anzahl der 
gemessenen Impulse erhöht.
Auch die Anzahl wird nie wieder gelöscht, sondern wie bei der Zeit die 
Differenz zwischen den Werten (neuer_wert - alter_wert) verwendet. In 
'main()' wird das entsprechend ausgewertet.

> 3.) Allgemeines Wirrwarr mit der anfänglichen konfiguration der register

Das ist doch hinreichend kommentiert?

gartler p. schrieb:
> kurzum, ein einfacher code der isr und anfänglichen einstellungen wären
> für mich einfacher..

Den habe ich Dir gegeben. Die Programme sind mit AVR-Studio 4.19 
erstellt und sollten auch unverändert auf 6.x laufen.

von Thomas F. (igel)


Lesenswert?

Mal vorneweg (vereinfacht ohne Überlauf):

Die Zündfrequenz des Motors liegt grob zwischen 8Hz (800 U/min, 0.125s) 
und 350 Hz (21000 U/min). Gehen wir mal davon aus, dein uC läuft mit 
1MHz (hast du bisher verschwiegen). TimerCounter1 geht bis 65535. TC1 
soll innerhalb der 0.125s (800 U/min) nicht überlaufen. Man braucht also 
einen Prescaler für TC1. Bei Prescaler 8 zählt TC1 mit 125 kHz. Bei 8Hz 
Zündfrequenz ergibt das 125000/8=15625 Counts im Zähler. Das ist kleiner 
als 65535, Prescaler 8 passt also mal...

Timer1 wird also initialisiert:
TCCR1A = 0
TCCR1B = 1<<ICES1 | 1<<CS11

TIMSK = 1<<TICIE1 | 1<<TOIE1


> 1.) Wie aktiviere ich mit der ersten flanke den referenztimer?

Das ist soeben geschehen. Die Flanke ist hier erst mal wurscht.

> 2.) Selbe Frage mit "wie stoppe ich den"

Wie m.n. schreibt: Nie mehr. Der läuft immer weiter.
Tritt am ICP1-Pin die oben initialisierte steigende Flanke auf, dann 
kopiert TimerCounter1 automatisch den aktuellen Counterwert in das 
16-Bit breite InputCaptureRegister1 und löst den ICP1-Interrupt aus.

ISR( TIMER1_CAPT_vect )
{
    Time = ICR1;
    TCNT1 = 0;
    flag=1; //wird im main abgefragt
}

Die Interrupt-Routine liest nun  das ICR1 aus und legt den Wert in der 
Variablen Time ab. Das muss sein, da bei der nächsten Flanke das ICR1 ja 
neu beschrieben wird.
Der Counter wird noch schnell auf Null gesetzt, dann muss man nicht mit 
einem Überlauf über 65535 rumrechnen.
Im Hauptprogramm kann man nun anhand von 'flag' den aktuellen Zeitwert 
in eine Drehzahl umrechnen und sonst was damit anstellen.

von gartler p. (Gast)


Lesenswert?

Liebe leute

herzlichen dank....das hat geholfen...hab das programm von m.n. kapiert, 
nachdem die weiteren kommentare danach gekommen sind

ich musste nur noch frequenz und prescaling anpassen, funktioniert 
wunderbar
mit dem frequenzgenerator überprüft

tooooop...danke

demnächst mal die dazu gebaute schaltung mit dem schmitt trigger testen 
und das zündsignal kapazitiv abnehmen...

mir will immer noch nicht in den kopf, dass man 1 timer 2 mal 
beschreiben kann, einmal im capture modus, einmal im overflow, nehme das 
aber einmal hin

von Thomas F. (igel)


Lesenswert?

Schön wenns jetzt geht.

Zu meiner obigen Interrupt-Routine noch der Vollständigkeit halber, 
falls das mal jemand lesen sollte.

ISR( TIMER1_CAPT_vect )
{
    Time = ICR1;
    TCNT1 = 0;
    flag=1; //wird im main abgefragt
}


Werden mehrere Interrupts verwendet, kann es mit diesem Code zu 
Messfehlern kommen: Ist bei steigender Flanke am ICP noch ein anderer 
IRQ aktiv, wird TIMER1_CAPT_vect verzögert aufgerufen. Bis dahin hat 
TCNT1 natürlich etwas weitergezählt und wird nun verspätet auf Null 
gesetzt. Um diesen Fehler auszugleichen muss es richtiger heißen:
   TCNT1 = TCNT1 - Time

von m.n. (Gast)


Lesenswert?

Thomas Forster schrieb:
> Bis dahin hat
> TCNT1 natürlich etwas weitergezählt und wird nun verspätet auf Null
> gesetzt. Um diesen Fehler auszugleichen

... darf man den Timer nicht löschen, sondern immer nur das 
capture-Register auslesen! Zum einen ist die ISR immer zu spät und der 
Timer ist für andere Verwendund 'kaputt'.
Ich verweise noch einmal auf 
http://www.mino-elektronik.de/fmeter/fm_software.htm#bsp11, wo mit 
Timer1 ein 10-Bit DAC (mit PWM), ein Millisekunden-Timer und die 
eigentliche Frequenzmessung inkl. ISR für die Überläufe erledigt werden: 
insgesamt 4 x ISR.
Ein Löschen/Verändern des Timers würde diese Möglichkeiten zunichte 
machen.

Ebenso ungeschickt ist es, die Überläufe zu löschen oder, wie an anderer 
Stelle gesehen, das TOV1-Bit außerhalb der entsprechenden ISR zu 
löschen. Die ISR-Routine ist damit für nichts anderes mehr zu 
gebrauchen.

von Thomas F. (igel)


Lesenswert?

m.n. schrieb:
> Ich verweise noch einmal auf
> http://www.mino-elektronik.de/fmeter/fm_software.htm#bsp11

Für deinen und wohl viele andere Anwendungsfälle ist das natürlich der 
bessere Weg. Da ich lediglich einen Drehzahlmesser für Ottomotoren 
gebastelt habe, kann ich hier vereinfachen und nutze den Timer1Overflow 
dann als Abbruchkriterium/Erkennung Motor aus.

von gartler p. (Gast)


Lesenswert?

Noch eine abschliessende frage:

Würde einer der anwesenden hier insgesamt 13 LEDs an die ports hängen 
ohne treiber?

Die leds kommen mit vorwiderstand 220 ohm und brauchen dann etwa 22mA

9 können permanent leuchten, ab 10 leds gibts blinken von allen
also 13x blinken mit etwa 30% zeit an, rest aus

40mA pro pin werden zwar nicht überschritten, aber beim 32er in pdip 
ausführung steht nicht dezitiert drauf, wieviel belastung gesamt drauf 
sein darf

ein input wird noch angeschlosseb, sonst nix

was meint ihr?

von gartler p. (Gast)


Lesenswert?

Uhhhh.entdeckt...da muss ein treiber ran

von npn (Gast)


Lesenswert?

Die Frage ist, ob du wirklich die 22mA brauchst. Meist reich auch ein 
wesentlich kleinerer Strom, um eine LED hell genug leuchten zu lassen. 
Probiere es einfach aus. Vielleicht kommst du ja auch mit beispielsweise 
5mA hin...

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
Noch kein Account? Hier anmelden.