Forum: Mikrocontroller und Digitale Elektronik Frequenzmessung


von Asm (Gast)


Lesenswert?

Hallo,

mein Code soll mit 2Mhz Quarz und ATmega8 eine Frequenz von 1-100 Hz 
Messen.
Dabei wird bei ankommen einer positiven Flanke an INT0 ein timer mit 
1024erPS gestartet.
Bei der nächsten Flanke wird dann der Timer gestoppt.
Das ergebnis wird jeweils bei aufruf der ISR auf Port B gegeben und ich 
schaus mir mit LEDs an.

Leider funktioniert das ganze nicht.
Hier mal der Code:
.include "m8def.inc"

.def temp = r16
.def temp1=r17
.def temp3=r18
.org 0x0000
        rjmp    main
.org INT0addr
        rjmp int0_handler
.org OVF0addr
        reti
main:

     ldi     temp, LOW(RAMEND)     ; Stackpointer initialisieren
        out     SPL, temp
        ldi     temp, HIGH(RAMEND)
        out     SPH, temp
        ldi temp, 0b00000011  ; INT0, rising edge
        out MCUCR, temp

        ldi     temp, 0 << TOIE0
        out     TIMSK, temp
        ldi     temp, 0b00000000
        out     TCCR0, temp

    ldi temp, 0x00
    out TCNT0, temp


ldi temp,0xFF      ;Ausgang konfigurieren
out DDRB, temp

ldi temp,0x00   ; Eingang konfigurieren
out DDRD, temp


ldi temp, 0b01000000  ; INT0 aktivieren!
out GICR, temp


ldi temp, 0b00000000 ;Hier Temp mit 1024erPS laden
ldi temp3,0b00000101 ;Hier einmal festgelegt!



sei ;Generelle Interruptfreigabe!
loop:

rjmp loop

int0_handler:   ldi temp1, TCNT0
             out PORTB, temp1

               eor temp, temp3
         out TCCR0, temp
   reti



Eigentlich ein einfaches Programm.

Danke!

von Asm (Gast)


Lesenswert?

Und keiner ne Ahnung?

von Gast (Gast)


Lesenswert?

Doch, sicherlich. Nur wie Du es machen willst, wird es keinem hier 
gefallenen.
Einfach und elegant ist es, T1 mit hoher Taktfrequenz laufen zu lassen 
und die Periodendauer des Eingangssignals mit dem InputCaptureRegister 
ICR1 zu messen. Dazu muß Dein Signal an ICP1 anliegen, und Überläufe von 
T1 müssen mit ausgewertet werden.
Das Thema ist hier schon öfter ausführlich besprochen worden: suchen und 
finden.

von Asm (Gast)


Lesenswert?

Hmm naja, ich will aber nicht mehr als 100Hz messen....Dafür so ein 
Aufwand?

von Gast (Gast)


Lesenswert?

Gerade weil Du nur 100Hz messen willst, ist ICP1 ideal.
Dein Programm ist sicherlich sehr kurz, aber es funktioniert ja auch 
nicht ;-)

von Asm (Gast)


Lesenswert?

Ja das stimmt ;)


Aber ich dachte mir, mit 2Mhz Quarz währe es dann ideal mit 1024er PS 
sowas zu machen....


Es ist ja nichts großartiges.
Positive Flanke, Zählstart, positive Flanke, Zählstopp.

Das wars ja schon ;)

von ASM (Gast)


Lesenswert?

>ldi temp, 0b00000000 ;Hier Temp mit 1024erPS laden
>ldi temp3,0b00000101 ;Hier einmal festgelegt!

Was soll das? Du musst es schon noch in ein Register schreiben, damit es 
eine Auswirkung hat

von Asm (Gast)


Lesenswert?

? Ja habe ich doch auch gemacht!

In der ISR des INT0 wird jeweils 0x00 oder ebenhalt 0x05 gesschrieben.
Damit wird dann der timer jeweils gestartet und gestoppt!!

von ASM (Gast)


Lesenswert?

Starten und stoppen allein bringt afaik nichts, du musst ihn auch mal 
auf null setzten oder die Differenz zwischen neuem und altem Timerwert 
ausgeben,

von Asm (Gast)


Lesenswert?

Also meinst du:

Timer Starten, Stoppen.

Timer Wert auslesen.
Timer Wert ausgeben.
Timer auf 0 Setzen.

Von Vorn.


?

von ASM (Gast)


Lesenswert?

Nein, ich wuerde den Timer nie stoppen sondern so (wenn du es ohne ICP 
machen willst):

Hauptprogramm:
   Timer mit prescaler 1024 starten
   sei()

   Endlosschleife()

*******

Interrupt:
   temp = Timer
   Timer = 0
   PortB = temp
reti

von Asm (Gast)


Lesenswert?

Hmm jo...


Also meine Lösung kann ja nur "datenmüll" ausgeben...
Denn wenn immer in Endlosschleife der Timer Wert ausgegeben wert, 
welcher sich ständig und schnell ändert, kanns nicht funktionieren ;)

Also erst Zeit messen und ENDWERT, nach Stoppen des Timers, ausgeben.

von ASM (Gast)


Lesenswert?

Wie gesagt, den Timer musst du nicht stoppen, sondern nur auf 0 setzen, 
dann sollte es klappen. Ist mein "Programm" oben nicht verstaendlich?

von Asm (Gast)


Lesenswert?

Ja doch schon.
Bis auf die Tatsache, dass der Timer Wert nur jedes zweite mal 
reinkopiert werden soll.
Denn sonst hat man einmal 0 und einmal den Wert.

von ASM (Gast)


Lesenswert?

Nein, du kannst bei jeder steigenden Flanke den Timerwert auslesen, nach 
dem auslesen wieder auf 0 setzten. Es gibt so genau einen falschen Wert, 
und der entsteht dann, wenn der Interrupt zum ersten Mal ausgefuehrt 
wird nach einem Reset. Danach stimmt es mit dieser Methode immer. Nix 
mit Timer anhalten...!

von Asm (Gast)


Lesenswert?

Oki,

bin gerade nicht daheim und kanns nich probieren.

Nachher schau ich mal ob es funzt..

von Asm (Gast)


Lesenswert?

Hmm Funktioniert leider nicht :(

Ich starte den Timer.

Der uC Bleibt dann in einer endlosschleife und mach nichts.
Bei Positiver Flanke wird in der ISR der Timer Wert gesichert, der Timer 
auf null gesetzt und der timer wert aufs port geschrieben.


Lustigerweise kommt bei mir dann immer raus:
0bxxx10011 (Also das, was aufs port c geschrieben wird).
Das verändert sich auch nicht :(

von Vorname N. (logout-name)


Lesenswert?

Zeig nochmal das Programm

von Asm (Gast)


Lesenswert?

So jetzt läufts, erst nicht aber nun doch ;)

Merke:
TCNT0 wir nicht mit ldi in ein arbeitsregister kopiert sondern mit in!

hinterdieohrenschreib

von Asm (Gast)


Lesenswert?

So funktioniert es glaube ich ;)

.include "m8def.inc"

.def temp = r16
.def temp1=r17
.def temp3=r18


.org 0x0000
        rjmp    main

.org INT0addr
        rjmp int0_handler
.org OVF0addr
        reti

main:

     ldi     temp, LOW(RAMEND)     ; Stackpointer initialisieren
        out     SPL, temp
        ldi     temp, HIGH(RAMEND)
        out     SPH, temp

;******************************
; INTERRUPTs  konfigurieren


      ldi temp, 0b00000011  ; INT0, rising edge generates interrupt 
request
        out MCUCR, temp

    ldi     temp, 0 << TOIE0     ; Bei überlauf von Timer0 KEIN 
Interrupt
        out     TIMSK, temp

;******************************
;    T I M E R 0 konfigurieren

      ldi     temp, 0b00000000     ; Timer für den Anfang ausschalten!
        out     TCCR0, temp

    ldi temp, 0x00
    out TCNT0, temp
;*****************************
;Ports
ldi temp,0xFF      ;Ausgang konfigurieren
out DDRC, temp

ldi temp,0x00   ; Eingang konfigurieren
out DDRD, temp

ldi temp, 0xFF
out PORTD, temp
ldi temp, 0b01000000  ; INT0 aktivieren!
out GICR, temp
ldi temp, 0b00000000
ldi temp3,0b00000101 ;Hier einmal festgelegt!
sei ;Generelle Interruptfreigabe!
 out TCCR0, temp3 ;Timer Starten!


loop:
rjmp loop

int0_handler:
in temp1, TCNT0
out PORTC, temp1
  ldi temp, 0x00
out TCNT0, temp
         reti

von Kachel-Heinz (Gast)


Lesenswert?

- Im ext. Interrupt eine Zählvariable hochzählen.

- Mit Timer einen Sekundentakt erzeugen. Darin die Zählvariable zur
  Ausgabe kopieren und danach löschen.

Oder

- Einen Timer/Counter als asynchronen Zähler über den externen
  Zähleingang (T0 oder T1) benutzen und damit die Impulse zählen.

- Mit anderem Timer einen Sekundentakt erzeugen, in dem den ersten
  Timer/counter auslesen und löschen.

Oder (wenn nicht die Frequenz, sondern die Periodendauer gewünscht wird)

- Timer1 frei laufen lassen.

- Signal an ICP1-Eingang legen.

- Bei ICP-Interrupt ICR1H:ICR1L auslesen und Differenz zum Wert der
  letzten Messung bilden, dann den neuen Wert für die nächste Messung
  merken. Timer dabei nicht löschen. Vorteil: Man kann nebenher noch
  die beiden Compare-Interrupts des Timer1 benutzen, um z.B. eine
  7-Segment-Anzeige zu multiplexen.

- Messwert (Differenz neu minus alt) entspricht der Periodendauer. Soll
  die Frequenz gemessen werden, dann ist er umzurechnen (f=1/t). Da der
  AVR aber kein Hardware-Div hat, wird das eine kleine Fleißarbeit.

KH

von Asm (Gast)


Lesenswert?

So um verwirrungen zu vermeiden habe ich jetzt mal nen mega32...
Denn beim mega8 ist das port c ja "abgehackt".

Klappt sehr gut und ich habe eine frequenzabweichung von "nur" einem 
Herz.
Wohlgemerkt mit selbstgebautem Funktionsgenerator, der noch ein etwas zu 
schnelles quarz drinne hat...


Danke nochmal für alle tipps.
Ich werde mich, zwecks genauigkeit, noch mit der ICP Methode und 16bit 
arithmetik befassen...

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.