Forum: Mikrocontroller und Digitale Elektronik Frequenz messen mit ATtiny85


von Michael L. (nightflyer88)


Lesenswert?

Hallo Zusammen

Ich will eine Frequenz mit einem ATtiny85 messen. Der Messeingang ist 
PB4.

Das INT0 Interrupt soll dann einen Timer starten, und so die Frequenz 
ermitteln.

Nun funktioniert nicht einmal das INT0, das interrupt wird dauernd 
ausgelöst, sollte aber nur, wen sich PB4 ändert.


Hier ein kleines Testprogramm in Bascom:


$regfile = "attiny85.dat"
$crystal = 8000000

Open "comb.2:1200,8,n,1" For Output As #1
Print #1 , "Start"

Enable Interrupts
Enable Int0
On Int0 Frequenz_messung

Config Portb.4 = Input
Gimsk = &B01100000
Pcmsk = &B00010000
Mcucr = &B00000001


Do                                    'Hauptprogramm
  Print #1 , "warte..."
  Waitms 1000
Loop


End


Frequenz_messung:
  Gifr = &B01100000
  Print #1 , "INT0"
Return

von M. N. (Gast)


Lesenswert?


von Floh (Gast)


Lesenswert?

Im Interrupt eine Ausgabe auf die Seriell zu machen dauert zu lang, bei 
1200 Baud/s dauert dein "Int0" ca 4,2ms! Inzwischen ist sícher die 
nächste Änderung am Int0 passiert.
Wie willst du da Signale schneller als vielleicht  100 Hz messen?
Besser macht man das so mit einem AVR:
Der AVR zählt eine bestimmte Zeit lang (Torzeit) die Änderungen auf dem 
Eingangspin, elegant lässt sich das z.B. mit dem Timerclockeingang (weiß 
grad nicht ob der tiny85 einen hat) erledigen.
Nach der Torzeit kannst du den Frequenzwert an den PC übertragen und die 
nächste Messung starten.

von M. N. (Gast)


Lesenswert?

Floh schrieb:
> Besser macht man das so mit einem AVR:

Der Tiny85 ist ein AVR.

> Der AVR zählt eine bestimmte Zeit lang (Torzeit)

Wenn schon, dann bitte eine reziproke Messung. Da reicht schon ein 
ATtiny2313.

von Eumel (Gast)


Lesenswert?

M. N. schrieb:
> Der Tiny85 ist ein AVR.

Lesekompetenz 0.

von Mystik (Gast)


Lesenswert?

M. N. schrieb:
> Floh schrieb:
>> Besser macht man das so mit einem AVR:
>
> Der Tiny85 ist ein AVR.
>
>> Der AVR zählt eine bestimmte Zeit lang (Torzeit)
>
> Wenn schon, dann bitte eine reziproke Messung. Da reicht schon ein
> ATtiny2313.

....ich verneige mich vor dir !

von BerndB (Gast)


Lesenswert?

M. N. schrieb:
> Wenn schon, dann bitte eine reziproke Messung. Da reicht schon ein
> ATtiny2313.

2,5x so groß ist 2,5x so gut oder ist wie ist das "Da reicht schon ein
 ATtiny2313" zu verstehen?

von Michael L. (nightflyer88)


Lesenswert?

Das Interrupt sollte mit dem Befehl "Pcmsk = &B00010000" eigentlich nur 
auf PCINT4 ausgelöst werden. Und nicht am Standartpin PCINT0, oder sehe 
ich das falsch ?


Die andere Möglichkeit, anzahl Pulse zählen wäre auch eine Variante.
Ich will eine Frequenz zwischen 1Hz und 3KHz messen.

Wie mache ich das am besten ?

Wie gesagt, der AVR sollte ein tiny85 sein (aus Platz gründen), und der 
Messeingang darf nicht auf PB0 und PB2 liegen, da ich den I2C Bus 
ebenfalls brauche.

von Ulrich (Gast)


Lesenswert?

Der Tiny2313 ist für eine Frequenzmessung als reziprokzähler deutlich 
besser geeignet - der Tiny85 hat leider keine ICP Funktion, aber 
immerhin mehr Speicher.

Mit dem Tiny85 hat man 2 Möglichkeiten:
1) klassich mit fester Torzeit und zählen der Perioden des Signals
2) als Reziprokzähler mit Interrupt als ICP Ersatz in Software

Bei nur 8 Bit Timern und in Software wird die Genauigkeit beim 
Rezirokzähler nicht so besonders gut, und abhängig vom Aufwand den man 
treibt. An einigen Stellen wäre ASM statt C hilfreich/nötig um trotzdem 
eine sehr gute Auflösung zu erreichen. Trotzdem ist das Verfahren für 
niedriger Frequenzen noch die bessere Wahl. Die maximale mögliche 
Frequenz wird bei rund 100 kHz liegen, in ASM auch etwas mehr.

Das klassische Verfahren ist einfacher, und für höhere Frequenzen 
geeignet, und in einem kleinen Bereich (so ab 50 kHz) ggf. auch genauer. 
Bei niedriger Frequenz fehlt einfach die Auflösung, oder die Torzeit 
müsste lang werden.

Welcher weg passt hängt von der Frequenz, der benötigten Auflösung und 
Geschwindigkeit der Messung ab.

von Michael L. (nightflyer88)


Lesenswert?

Das Projekt wird eine Drehzahlsensor für einen Datenlogger, um die 
Propellerdrehzahl im Modellbau zu messen.

Mit 2 Pulsen pro Umdrehung (Zweiblattpropeller), und einer Torzeit von 
0.5s, ergibt dies eine Auflösung von 60rpm, das wäre gerade noch 
akzeptabel.

Besser wäre eine Messzeit von 0.1s und einer Auflösung von 10rpm.
Bei sehr kleiner Drehzahl (100rpm), ist das natürlich nicht möglich, da 
wäre eine Messzeit von 1s allemal in Ordnung.

von BerndB (Gast)


Lesenswert?

Michael L. schrieb:
> Ich will eine Frequenz zwischen 1Hz und 3KHz messen.

das ist ja nun keine Raketentechnik,
ich würde einen Timer laufen lassen und per Interrupt die Flanken zählen 
und wenn 1 Sekunde um ist und die nächste Flanke kommt den Zählerstand 
nehmen, durch die Zahl der Perioden teilen und so eine Periode berechnen

von Michael L. (nightflyer88)


Lesenswert?

So habe ich mir das auch überlegt...

Nur wie Anfangs beschrieben, funktioniert die Interrupt Geschichte, der 
die Flanke auslösen soll, mit dem Pin PB4 nicht.
Irgendwie wird trotz der Maskierung von INT0 auf PCINT4, der PCINT0 Pin 
ausgewertet. Und dort ist momentan zu Testzwecken die Serielle 
Schnittstelle, und später wird dort der I2C Bus sein.

von MWS (Gast)


Lesenswert?

Michael L. schrieb:
> Irgendwie wird trotz der Maskierung von INT0 auf PCINT4,

Was ist denn das für ein Unsinn ? Da kann nichts ummaskiert werden.

Außerdem triggerst Du mit dem Soft-UART den INT0.
Wie wär's mit ein paar Grundlagen ?

von Michael L. (nightflyer88)


Lesenswert?

Das mit dem UART und INT0 habe ich auch gemerkt.

Im Datenblatt auf Seite 54, im Register PCMSK – Pin Change Mask 
Register, sollte man das INT0 auf einen anderen PIN legen, oder habe ich 
da was falsch verstanden ?

von MWS (Gast)


Lesenswert?

Michael L. schrieb:
> oder habe ich
> da was falsch verstanden ?

Ja.

von Michael L. (nightflyer88)


Lesenswert?

Wo zu dient den das PCMSK – Pin Change Mask Register ?

von Ulrich (Gast)


Lesenswert?

Beim Propeller werden es eher keine 3 kHz, und wohl auch nicht runter 
bis 1 Hz gehen.
Die Logische Wahl wäre da schon die Messung über eine Zeitmessung 
zwischen 2 gleichen Flanken, z.B. mit int0. Die Genauigkeit wird ggf. 
durch langsamere andere Interrupts gestört, aber die Anforderungen sind 
auch nicht so extem.
Bei der Software UART muss man aber ggf. schon aufpassen, das die nicht 
zu lange Pausen verursacht.

Zur Erweiterung der Auflösung der 8 Bit Timer gibt es 2 Möglichkeiten: 
Zählen der Überläufe in Software, oder man nutzt 2 Timer mit 
unterschiedlichem Vorteiler, etwa so das der eine Timer die 8 unteren 
Bits liefert, und der andere 7 zusätzliche - ohne 1 Bit als Überlapp 
ginge es ggf. mit einem sehr genauen Timing in ASM. Mit 15 oder 16 Bit 
Auflösung für die Zeit sollte man auskommen, denn die Genauigkeit ist 
ohnehin durch die nicht immer konstante Antwortzeit für den Interrupt 
begrenzt. Falls einem wieder Erwarten die Auflösung bei den höheren 
Frequenzen nicht reicht, ließe sich auch die Zeit für mehr als eine 
Periode messen.

von MWS (Gast)


Lesenswert?

Michael L. schrieb:
> Wo zu dient den das PCMSK – Pin Change Mask Register ?

Für eine ganze Reihe PCINT-Pins, meist ein ganzer Port, gibt's jeweils 
nur einen Interruptvektor, der dann eben entsprechend heißt, hier 
PCINT0.

Jeder in PCMSK gesetzte Pin kann dann eben diesen Vektor triggern. 
Rauszubringen welcher es war, ist dann Dein Job.

Der Vektor INT0 und PCINT0 sind aber zwei voneinander getrennte Sachen.

Verwirrend mag sein, dass die Pinchange-Pins auch mit PCINTx bezeichnet 
werden, ähnlich dem Namen des eigentlichen Interruptvektors.

von BerndB (Gast)


Lesenswert?

Michael L. schrieb:
> Pin Change Mask
> Register, sollte man das INT0 auf einen anderen PIN legen, oder habe ich
> da was falsch verstanden ?

pin change Interrupt heißt nicht dass da ein Pin gewechselt wird, 
sondern das ein Pegelwechsel an einem Pin einen Interrupt auslöst

von Michael L. (nightflyer88)


Lesenswert?

Ja genau, wir sind uns einig, die Messung mit einem Interrupt zwischen 
zwei flanken wäre die richtige.

Nun genau da ist mein Problem, das INT0 ist auf PB2, und dort ist zu 
Testzwecken der UART, später brauche ich den HW I2C der auf PB0 und PB2 
liegt. Die Schnittstellen lösen aber immer das INT0 aus.

Nun wollte ich das INT0 auf PB4 umleiten, aber irgendwie geht das mit 
dem PCMSK Register nicht.

von Michael L. (nightflyer88)


Lesenswert?

So könnte es gehen, oder ?


Enable Interrupts
Enable Int0
On Int0 Frequenz_messung

Config Portb.4 = Input
Gimsk = &B01100000
Pcmsk = &B00010000     'PCINT4 Maskieren
Mcucr = &B00000001


Do                       'Hauptprogramm
Loop

End

Frequenz_messung:
  if Gifr.5 = 1 then    'Prüfen ob PCINT4 das Interrupt ausgelöst hat
    Gifr = &B01100000    'PCINT4  reset
    Print #1 , "OK"
  end if
Return

von MWS (Gast)


Lesenswert?

Michael L. schrieb:
> So könnte es gehen, oder ?

Nein. Vergleich die Interruptvektoren, bzw. was ich schrieb.

von M. N. (Gast)


Lesenswert?

BerndB schrieb:
> 2,5x so groß ist 2,5x so gut oder ist wie ist das "Da reicht schon ein
>  ATtiny2313" zu verstehen?

Tut mir Leid, ich habe in Eile nur knapp formuliert.
Auf den ATtiny2313 habe ich verwiesen, weil dieser zum einen einen 
16-Bit Timer mit input-capture Funktion und zum anderen auch ein USART 
auf dem Chip hat. Da braucht man nicht viel zu tricksen, um eine gute 
Lösung zu bekommen. Als kleinere Lösung könnte man auch einen 
ATtiny461/861 nehmen.

Der Beitrag, auf den ich ganz oben verwiesen habe, beschreibt ja auch 
schon eine reziproke Messung mit dem ATtiny45/85. Dass nur 4 Stellen 
angezeigt werden, liegt an der Grundschaltung mit 7-Segment LCD und 
daran, dass unbedingt 'float' vermieden werden sollte und die 
Berechnungen als uint32_t stattfinden.
Beim ATtiny85 kann man getrost 'float' rechnen. Das Programm passt 
locker ins FLASH.

Wie man das Ganze in BASIC formuliert, weiß ich allerdings nicht.

von Michael L. (nightflyer88)


Lesenswert?

@MWS habs verstanden, so funktioniert nun die Interruptsache mit PCINT4:


Enable Interrupts                          'Interrupts einschalten
Enable Pcint0
On Pcint0 Frequenz_messung

Gimsk = &B00100000
Pcmsk = &B00010000


Do                                       'Hauptprogramm
  Print #1 , Drehzahl
  Drehzahl = 0
  Waitms 500
Loop

End

Frequenz_messung:
  Incr Drehzahl
Return

von Michael L. (nightflyer88)


Angehängte Dateien:

Lesenswert?

Nun habe ich noch ein anderes Problem. Die HW mit dem Fototransistor ist 
scheisse !

Wenn ich mit der Hand den Fototransistor auf- und abdecke, funktionierts 
einigermassen.

Aber die Drehzahl eines Propellers damit messen, geht nicht !

Ich habe den 10k Widerstand von 0-100k verändert, und zwei Transistoren 
probiert, ohne erfolg.

von MWS (Gast)


Lesenswert?

Du tust Dir selber einen Gefallen, wenn Du das:
1
Gimsk = &B00100000
2
Pcmsk = &B00010000
so schreibst:
1
Gimsk = Bits(PCIE)
2
Pcmsk = Bits(PCINT4)

Michael L. schrieb:
> Nun habe ich noch ein anderes Problem. Die HW mit dem Fototransistor ist
> scheisse !

Bei veränderlicher Umgebungshelligkeit braucht Du irgendeine Regelung, 
um den Arbeitspunkt des Fototransistors jeweils darauf einzustellen. In 
Wirklichkeit hast Du keine Helligkeitsschwankungen Tag/Nacht.

von MWS (Gast)


Lesenswert?


von Michael L. (nightflyer88)


Lesenswert?

Vielen Dank für die Info.

Die Schaltung kenne ich. Habe den Datenlogger von d.meissner ebenfalls 
schon aufgebaut, mit dem Logger von d.meissner mit PIC funktionierts 
auch einwandfrei.

nur wenn ich die Schaltung ohne PIC laufen lasse, und die Freuqenz mit 
dem Multimeter messen will, kommt nichts raus ?!?

von MWS (Gast)


Lesenswert?

Michael L. schrieb:
> nur wenn ich die Schaltung ohne PIC laufen lasse, und die Freuqenz mit
> dem Multimeter messen will, kommt nichts raus ?!?

Die Schaltung dürfte Nadelimpulse erzeugen, mit denen ein MM überfordert 
sein könnte, ein µC jedoch durchaus klarkommt.

von Michael L. (nightflyer88)


Lesenswert?

Also dann probier ich die Schaltung von Sprut an einem AVR aus.

Spurt verwendet da 5V, ich habe aber nur 3.3V, sollte ich die 
Widerstände ändern, oder funktioniert das trotzdem ?

von MWS (Gast)


Lesenswert?

Michael L. schrieb:
> Spurt verwendet da 5V, ich habe aber nur 3.3V, sollte ich die
> Widerstände ändern, oder funktioniert das trotzdem ?

Könnt' genauso mit 3,3V gehen, Widerstände würde ich so lassen.

von Michael L. (nightflyer88)


Angehängte Dateien:

Lesenswert?

Super !! Habe nun die Schaltung wie im Anhang aufgebaut, und die HW 
funktioniert einwandfrei !!

Jetzt noch was anderes:
Der PCINT4 erkennt ja nur wenn sich der Pegel ändert, und nicht ob eine 
steigende Flanke ansteht. Wenn sich das Propellerblatt am Fototransistor 
vorbei bewegt, wird das Interrupt zweimal aufgerufen. Ich will bis 
80000rpm messen können, könnte dies zu Problemen führen, wenn der high 
Pegel nur sehr kurz ist ?

von MWS (Gast)


Lesenswert?

Die steigende Flanke erkennt man beim PCINT daran, dass der Pin beim 
Eintritt in die ISR High ist. Vorausgesetzt natürlich, der Puls dauert 
lang genug von Auslösung bis Pinabfrage. Ausgelöst wird die ISR 
natürlich trotzdem immer zweimal, nur verlässt man sie bei Low-Pegel 
sofort wieder.

Michael L. schrieb:
> wenn der high Pegel nur sehr kurz ist ?

Auch das dürfte keine Schwierigkeit sein. Wie viele Takte ein Impuls 
mindestens dauern muss, um erkannt zu werden, ist im Datenblatt zu 
finden.

von Michael L. (nightflyer88)


Lesenswert?

So habe an der SW weiter gearbeitet, das Resultat ist aber noch nicht in 
Ordnung.

Wenn ich den Fototransistor zu einer Leuchtstofflampe mit 50Hz halte, 
ergibt dies ein Werte von ca. 77, Jedoch schwankt der Wert ziemlich 
stark (+/-10).

Nun die Frage ob ich so auf dem richtigen Weg bin ? Oder gibt es 
SW-Technisch bessere Lösungen ? evtl ASM ?



Config Timer1 = Timer , Prescale = 256

Enable Interrupts
Enable Timer1
Enable Pcint0
On Pcint0 Frequenz_messung
On Ovf1 Timer1ueberlauf

Gimsk = &B00100000
Pcmsk = &B00010000

Do 
'Hauptprogramm
  Print #1 , Drehzahl
  Waitms 500
Loop


End

Timer1ueberlauf:
  Incr Timer_ovf
  If Timer_ovf = 255 Then
    Drehzahl = 0
  End If
Return


Frequenz_messung:
  Incr Pulse
  If Pulse = 1 Then
    Timer_ovf = 0
    Timer1 = 0
    Enable Timer1
  End If
  If Pulse = 8 Then
    Disable Timer1
    Drehzahl = Timer_ovf
    Shift Timer_ovf , Left , 8
    Drehzahl = Drehzahl + Timer1
    Pulse = 0
    Timer_ovf = 0
    Enable Timer1
  End If
Return

von Michael Schurr (Gast)


Lesenswert?

Hi,

Michael L. schrieb:

>    Shift Timer_ovf , Left , 8
>     Drehzahl = Drehzahl + Timer1
>     Pulse = 0
>     Timer_ovf = 0

Wozu ist die erste Zeile gut, wenn in der 4.Zeile Timer_ovf auf 0 
gesetzt wird und dazwischen nix mit Timer_ovf gemacht wird?

von Michael L. (nightflyer88)


Lesenswert?

Oh ja das sollte so heissen:

    Drehzahl = Timer_ovf
    Shift Drehzahl, Left , 8
    Drehzahl = Drehzahl + Timer1
    Pulse = 0
    Timer_ovf = 0

Da ich nur einen 8bit timer habe, habe ich diesen per SW auf 16bit 
erweitert.
Timer_ovf sind anzahl Überläufe von timer1.

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.