Forum: Mikrocontroller und Digitale Elektronik Problem mit 16-bit Timer/Counter


von Flo333 (Gast)


Lesenswert?

Hi!

Ich hab folgende Problem:

Ich möchte das an Pin T0 (entspricht PD4) anliegende Rechtecksignal 
zählen. Nach 1000 Impulsen soll PortB "High" geschaltet werden. Dazu hab 
ich den Timer/Counter1 (16-bit) meines 2313 verwendet. Leider 
funktioniert es nicht, PortB bleibt immer auf "Low". Ich vermute das der 
Fehler irgendwo bei der Einrichtung des 16-bit Counters liegt. Hab aber 
bis jetzt noch nichts gefunden.

Wäre total super wenn mir einer von euch weiterhelfen könnte.

Schon mal im Voraus Danke!

MfG Flo


.include "2313def.inc"
.def temp = r16
.equ start = 65536 - 1000
.equ highValue = high(start)
.equ lowValue = low(start)

rjmp reset      ;Reset Handler
reti    ;IRQ0 Handler
reti    ;IRQ1 Handler
reti          ;Timer1 Capture Handler
reti          ;Timer1 Compare Handler
rjmp counter1   ;Timer1 Overflow Handler
reti          ;Timer0 Overflow Handler
reti          ;SPI Transfer Complete Handler
reti          ;UART RX Complete Handler : RXCIE
reti          ;UDR Empty Handler
reti    ;UART TX Complete Handler
reti    ;ADC Conversion Complete Interrupt Handler
reti    ;EEPROM Ready Handler
reti          ;Analog Comparator Handler


reset:

ldi temp, low(RAMEND)  ;set stackpointer
out SPL, temp

ldi temp, 0x00
out DDRD, temp    ;PORTD input
ldi temp, 0xFF
out DDRB, temp    ;PORTB output

ldi temp, 1<<TOIE1   ;1000 0000
out TIMSK, temp          ;timer1 interrupt on
ldi temp, highValue  ;Startwert des Counters Highbyte
out TCNT1H, temp
ldi temp, lowValue
out TCNT1L, temp        ;Startwert des Counters Lowbyte

ldi temp, 0b00000111
out TCCR0, temp    ;Counter +1 bei fallender Flanke an Pin T0

sei      ;interrupts aktiv

main:

  loop:

  rjmp loop


;--------------------------------------------------------------

counter1:

ldi temp, 0xFF
out PORTB, temp

ldi r17, 0
ldi r18, 0
ldi r19, 35

delay:
dec r17
brne delay
dec r18
brne delay
dec r19
brne delay

ldi temp, 0x00
out PORTB, temp

ldi temp, highValue  ;Startwert des Counters Highbyte neu
out TCNT1H, temp
ldi temp, lowValue
out TCNT1L, temp        ;Startwert des Counters Lowbyte neu

reti

von thkaiser (Gast)


Lesenswert?

Du wirfst Timer0 und Timer1 durcheinander. Wenn Du Dich für einen von 
beiden entscheidest, könnte es funktionieren ;-)
Du zählst Impulse an T0, das ist der Eingang des Timer0. Allerdings die 
Interrupt-Routine ist für Timer1.

von crazy horse (Gast)


Lesenswert?

out TCCR0, temp ;Counter +1 bei fallender Flanke an Pin T0

da wird der Fehler liegen, sollte wohl heißen:
out TCCR1B, temp

Ansonsten kann ich nur sagen, das Programm ist ein Graus, verzeihen 
könnte ich dir das nur, wenn du Anfänger bist und dir noch keiner was 
beigebracht hat.

folgende grobe Fehler:
1. das sreg sollte in einer ISR immer gesichert werden, das sollte in 
Fleisch und Blut übergehen
2. delays dieser Größenordnung haben in Unterruptprogrammen nichts zu 
suchen
3. Wenn du wirklich korrekt zählen willst, sollte das TCNT1-Register als 
erstes in der ISR nachgeladen werden.
4. Register sollten schon Namen bekommen, lange Fehlersuche ist sonst 
bei etwas komplexeren Programmen vorprogrammiert
5. wenn Register nicht ausdrücklich nur für eine ISR reserviert sind, 
auf dem Stack sichern. Programme wachsen im Lauf der Zeit, solche 
(erstmal funktionierenden) Nachlässigkeiten rächen sich später.

von Flo333 (Gast)


Lesenswert?

Guten Morgen!

Danke für die Antworten!

Werds dann gleich mal so ausprobieren.

@ crazy horse

ja ich bin leider noch ziemlicher Anfänger

1. das sreg sollte in einer ISR immer gesichert werden, das sollte in 
Fleisch und Blut übergehen
---> Danke für den Tip, wusste ich nicht
2. delays dieser Größenordnung haben in Unterruptprogrammen nichts zu 
suchen
---> Das war nur zum Test, sonst seh ich an meinen LED´s ja nichts
3. Wenn du wirklich korrekt zählen willst, sollte das TCNT1-Register als 
erstes in der ISR nachgeladen werden.
---> Nochmals Danke, ist ja eigentlich auch logisch
4. Register sollten schon Namen bekommen, lange Fehlersuche ist sonst 
bei etwas komplexeren Programmen vorprogrammiert
---> wie gesagt, die Delay war nur kurz zusammengeschustert
5. wenn Register nicht ausdrücklich nur für eine ISR reserviert sind, 
auf dem Stack sichern. Programme wachsen im Lauf der Zeit, solche 
(erstmal funktionierenden) Nachlässigkeiten rächen sich später.
---> Werds mir merken!

MfG

Flo

von crazy horse (Gast)


Lesenswert?

counter1:
in sreg_bak, sreg
push temp
ldi temp, highValue ;Startwert des Counters Highbyte neu
out TCNT1H, temp
ldi temp, lowValue
out TCNT1L, temp ;Startwert des Counters Lowbyte neu
set      ;T=1
bld flags, t1_ready
pop temp
out  sreg, sreg_bak
reti

für das Register sreg_bak benutzt ich i.a. R1, wenn du keine Interrupts 
verschachtelst, kannst du das Register für verschiedene ISR benutzen
.def sreg_bak R1
.def flags R2
.equ t1_ready=0 ;bit0 von R2

Im Hauptprogramm kannst du dann den Zustand von t1_rady abfragen, ist es 
gesetzt, werden die entsprechenden Aktionen ausgeführt (Port setzen, 
delay, Port rücksetzen.
Es spielt zwar in deinem Programm keine Rolle, wird aber in komplexeren 
Programmen wichtig.
also:
- sreg sichern
- alle benutzten Register sichern
- ISR-Laufzeit kurz wie möglich halten
Das ist natürlich kein unumstößliches Muss, wenn mans beherrscht oder 
besondere Umstände es erfordern, kann man davon abweichen, aber als 
Grundregel ist es nicht schlecht.

Man kann das sreg auch auf dem Stack sichern:
push temp
in temp, sreg
push temp
.
pop temp
out sreg, temp
pop temp
reti
Das empfiehlt sich bei verschachtelten ISRs (die fast immer vermeidbar 
sind)

von Flo333 (Gast)


Lesenswert?

Ich bin´s nochmal!

Leider funktioniert das Programm immer noch nicht!

Hab das "TCCRO, temp" gegen "TCCR1B, temp" ausgetauscht.

Hat jemand vielleicht irgendein Beispielprogramm zum 16-Bit Timer / 
Counter?

MfG

Flo

von crazy horse (Gast)


Lesenswert?

Tja, und nun solltest du deine Impulse auch an den T1-EIngang legen 
(PD5), willst ja mit dem Timer1 zählen.

von Flo333 (Gast)


Lesenswert?

Ganz dumm bin ich auch nicht! :-)

Das hab ich gemacht, funktioniert aber trotzdem nicht. :-(

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.