PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : AT90S2313 - Timer



enoritz
22.08.2004, 22:07
Hallo,

kann mir jemand sagen wie man die Timer des AT90S2313 benutzen kann?? Ich hab schon in den Datenblättern nachgeschaut, allerdings stand da nur etwas über die Register (TCCR0 und TCNT0). Nur kann ich damit nicht soviel anfangen. Und als ich darunter dann noch was über einen 16Bit-Timer gelesen hab wars ganz vorbei.
Am besten wärs wenn mir jemand mal ne übersicht über die ganze Timergeschichte geben könnte.

MfG
enoritz

sonic
23.08.2004, 00:02
Hallo,

kann mir jemand sagen wie man die Timer des AT90S2313 benutzen kann?? Ich hab schon in den Datenblättern nachgeschaut, allerdings stand da nur etwas über die Register (TCCR0 und TCNT0). Nur kann ich damit nicht soviel anfangen. Und als ich darunter dann noch was über einen 16Bit-Timer gelesen hab wars ganz vorbei.
Am besten wärs wenn mir jemand mal ne übersicht über die ganze Timergeschichte geben könnte.

MfG
enoritz

In welcher Programmiersprache?
Ansonsten gibt's im Internet doch genug Tutorials, oder?

Gruß, Sonic

enoritz
23.08.2004, 09:59
Oh, sry.... in Assembler

Wo gibts denn die Tutorials?? bei Google hab ich dann wahrscheinlich die falschen Stichwörter angegeben.

23.08.2004, 11:38
In welcher Programmiersprache du arbeitest, ist für dein Problem vollkommen belanglos. Solange du nicht weisst, wie ein Timer funktioniert, wirst du ihn auch nicht verwenden können.
Ich empfehle dir, mal die Linkliste auf mikrocontroller.net durchzuarbeiten. Ansonsten kannst du bei Google auch mal nach Christian Schifferle suchen, der hat auch ein gutes AVR-Tutorial geschrieben. Zuletzt kannst du auch noch auf www.mc-project.de schauen, dort steht auch noch ein bischen was zu Timern.

Gruß, Gast

23.08.2004, 15:52
Da er offenbare kein nützlichen Beispiele/Tutorials gefunden hatte, betrachte ich meine Links schon als hilfreich:

http://www.mikrocontroller.net/articles/c/Timer_Counter.htm
http://mc-project.de/Pages/timer.html

Diese Quellen sprengen auch nicht den didaktischen Anspruch und eine umfassende Antwort erübrigt sich eigentlich (Warum das Fahrrad zweimal erfinden?)

Gruß, Gast

enoritz
24.08.2004, 20:12
Hallo,

ich hab mir mal n bisschen was durchgelesen... und würde jetzt gerne wissen ob das so in ordnung ist:




.include "2313def.inc"

.def temp=r16
.def int_per_sec=r17

initTimer:
ldi temp,5 ;CPU-Takt/1024
out TCCR0,temp
ldi temp,2 ;aktivieren des Interrups bei einem
out TIMSK,temp ;Überlauf

ldi int_per_sec,46 ;Anzahl der Interrupts pro Sekunde

;12MHz: 12.000.000/1024=11718,75 --> Bei jedem 11718,75ten Takt
;wird ein Interrupt eingeworfen
;=>11718,75/256(wegen 8Bit TCNT)=45,78 (ca. 46 Interrupts pro Sek.)

sei ;Interrupts global erlauben

endlos: ;Endlosschleife
rjmp endlos

time: ;Aufruf bei jedem Interrupt
dec int_per_sec
brne zurueck ;nach 46 Interrupts (int_per_sec=0) wird
;nicht nach "zurueck" gesprungen

;irgendwas zur vollen sekunde

zurueck:
reti ;rücksprung in die Endlosschleife


Dort müsste doch jetzt eigentlich zu jeder vollen sekunde bei dem Label time (dort wo der Kommentar ist) das ausgeführt werden was ich gerne möchte oder?

24.08.2004, 21:02
Woher soll der MC wissen, dass er bei einem Timerinterrupt zu time: springen muss?

Florian
24.08.2004, 21:06
Wenn ich das jetzt so spät noch auf die schnelle sehe, ich glaube es ist richtig!
Probier es doch einfach aus! :o)

martin
24.08.2004, 22:02
Hallo,

Dir fehlen die Interruptvektoren!
Wie Gast schon erwähnt hat, weiss dein Controller nicht, was er bei einem Timerinterrupt machen soll. Nachdem auch der Stackpointer-Init fehlt, wird das Programm sowieso nicht laufen.

Falls du dafür Hilfe brauchst, schreib nochmal hier rein.
Es ist aber auch in fast allen Bespielprogrammen drin.

Grüsse, Martin

enoritz
25.08.2004, 13:09
Hallo,

hier müsste es so mit dem Stackpointer gehn oder?


.include "2313def.inc"

.def temp=r16
.def int_per_sec=r17

.start:
ldi temp,low(ramend)
out spl,temp

initTimer:
ldi temp,5 ;CPU-Takt/1024
out TCCR0,temp
ldi temp,2 ;aktivieren des Interrups bei einem
out TIMSK,temp ;Überlauf

ldi int_per_sec,46 ;Anzahl der Interrupts pro Sekunde

;12MHz: 12.000.000/1024=11718,75 --> Bei jedem 11718,75ten Takt
;wird ein Interrupt eingeworfen
;=>11718,75/256(wegen 8Bit TCNT)=45,78 (ca. 46 Interrupts pro Sek.)

sei ;Interrupts global erlauben

endlos: ;Endlosschleife
rjmp endlos

time: ;Aufruf bei jedem Interrupt
dec int_per_sec
brne zurueck ;nach 46 Interrupts (int_per_sec=0) wird
;nicht nach "zurueck" gesprungen

;irgendwas zur vollen sekunde

zurueck:
reti ;rücksprung in die Endlosschleife


Das mit dem Interruptvektoren hab ich allerdings nicht verstanden... Wie kann man die setzen??

Florian
25.08.2004, 13:33
Hi @ all! ;o)
War wohl doch gestern etwas müde, das ich das nicht gesehen habe! *lol*



.start:
ldi temp,low(ramend)
out spl,temp

Ich würde vor start: noch den Punkt wegnehmen, das ist ein Label und keine Direktive! ;o)

Außerdem würde ich noch die Interrupttabelle einfügen! :o)

.org 0x000
rjmp start ; Initialisierung / RESET
reti ; IRQ0
reti ; IRQ1
reti ; Timer1 Capture
reti ; Timer1 Compare
reti ; Timer1 Overflow
reti ; Timer0 Overflow
reti ; SPI Complete
reti ; UART Rx
reti ; UART Data empty
reti ; UART Tx
reti ; ADC Conversion Complete
reti ; EEPROM ready
reti ; Analog Comparator

Die musst Du nurnoch wie bei start verändern und das richtige Label hinsetzten!
*edit* Guck mal bei www.mikrocontroller.net im Tutorial! */edit*
Ich habe leider jetzt nicht die zeit um den ganzen Code zu überprfen! :o(
Mal sehn, wenn es noch Probs gibt, kann ich im Notfall noch helfen! :o)

enoritz
25.08.2004, 15:02
Hallo...


Ich würde vor start: noch den Punkt wegnehmen, das ist ein Label und keine Direktive! ;o)


Sry. War nur n Tippfehler

Ich werds jetzt mal auf nem Controller testen... Danke

Edit:
Hmm... Also irgendwie klappt das nicht:

.include "2313def.inc"

.def temp=r16
.def int_per_sec=r17
.def _led=r18

.org 0x000
rjmp start ; Initialisierung / RESET
reti ; IRQ0
reti ; IRQ1
reti ; Timer1 Capture
reti ; Timer1 Compare
reti ; Timer1 Overflow
rjmp Time ; Timer0 Overflow
reti ; SPI Complete
reti ; UART Rx
reti ; UART Data empty
reti ; UART Tx
reti ; ADC Conversion Complete
reti ; EEPROM ready
reti ; Analog Comparator

start:
ldi temp,low(ramend)
out spl,temp
ldi temp,0b11111111
out DDRD,temp
ldi _led,1
rjmp initTimer

initTimer:
ldi temp,5 ;CPU-Takt/1024
out TCCR0,temp
ldi temp,2 ;aktivieren des Interrups bei einem
out TIMSK,temp ;Überlauf

ldi int_per_sec,46 ;Anzahl der Interrupts pro Sekunde

;12MHz: 12.000.000/1024=11718,75 --> Bei jedem 11718,75ten Takt
;wird ein Interrupt eingeworfen
;=>11718,75/256(wegen 8Bit TCNT)=45,78 (ca. 46 Interrupts pro Sek.)

sei ;Interrupts global erlauben

endlos:
ldi temp,0b0001000
out portd,temp ;Endlosschleife
rjmp endlos

led_an:
ldi temp,0b00100011
out PORTD,temp
ldi _led,0
rjmp zurueck
led_aus:
ldi temp,0b00000000
out PORTD,temp
ldi _led,1
rjmp zurueck
time: ;Aufruf bei jedem Interrupt
dec int_per_sec
brne zurueck ;nach 46 Interrupts (int_per_sec=0) wird
;nicht nach "zurueck" gesprungen

;irgendwas zur vollen sekunde
sbrs _led,1
rjmp led_aus
rjmp led_an




zurueck:
reti ;rücksprung in die Endlosschleife

Nunja die LED in der Endlosschleife Leuchtet, aber von Timer her kommt nix....

Florian
26.08.2004, 17:48
Hi enoritz!


rjmp Time ; Timer0 Overflow
Versuchs mal mit nem kleinen time!
Mehr sehe ich jetzt apprupt nicht!

Sag bitte bescheid, ob's klappt! :o)

enoritz
26.08.2004, 21:57
Ich werds mal probieren, kann mir aber irgendwie nicht vorstellen das es was bringt, da das Label "time" ja eigentlich nur eine Adresse repräsentiert, welche im Code-Editor (sowie im Compiler, etc.) als Text (case-insensitive) dargestellt wird.

Ich werds aber trotzdem mal probieren ;-)

Florian
27.08.2004, 12:40
Hi enoritz!
Funktioniert's?

enoritz
27.08.2004, 14:41
Ne, hat nicht funktioniert

Florian
27.08.2004, 14:44
Schade, ich simuliere es nochmal und dann versuche ich mal den Fehler zu finden!

enoritz
27.08.2004, 19:37
Also das müsste irgendwie am Aufruf des Interrupts und somit wahrscheinlich an der initialisierung des Timers liegen.

Wenn ich in die endlosschleife ein Sleep einbaue und auf einen Interrupt warte, wonach dann eine LED angehen soll passiert gar nichts. Eigentlich müsste ein Interrupt den Sleep-Befehl wieder auflösen.

Bei einem Reset-Interrupt z.B. funktionierts.....

Florian
27.08.2004, 20:43
So, der Code funktioniert! :o)
Der Code invertiert an PORTD alle 1Sek. den Zustand der LED's, das heißt sie blinken alle 1Sek.!
Ich hoffe man versteht meine Label-Kommentare! ;o)
Wenn jemand noch Fragen hat, ich stehe zur Verfügung! :o)

Viel Spass! :o)

enoritz
27.08.2004, 21:26
Werd ich mal testen.....

Nur wozu ist der Wert "start" gut?? Da zählt der doch immer nur 244 Takte??

//Edit: Schon in ordnung... hab n bisschen rumgerechnet und habs gerafft O:)

Florian
28.08.2004, 14:07
Werd ich mal testen.....

Nur wozu ist der Wert "start" gut?? Da zählt der doch immer nur 244 Takte??

//Edit: Schon in ordnung... hab n bisschen rumgerechnet und habs gerafft O:)

Hi enoritz!
Freut mich, dass Du den Code verstanden hast! :o)

Viel Spass noch damit! :o)

Lektor
27.09.2005, 20:14
ich starte mal diesen Thread wieder, da ich zu der Interrupttabelle auch eine Frage habe.
Sobald ich nach rjmp reset ein reti stehen habe, funktioniert kein Programm. Sobald da nur rjmp reset steht funktionierts. Warum ist es so, wo liegt der Fehler.
Selbst bei Programmen die keine Interrupts benutzen darf ich keinen reti stehen haben. Also Programme die den Eingang gleich an Ausgang schalten; sprich, das billigste vom billigsten.
Kann den Fehler einfach nicht finden. AVR Studio gibt keinen Fehler aus und ich möchte auch nicht nach jeder kleinen Änderung den uC neu programmieren. Soll ja angeblich auch nicht unbegrenzt oft funktionieren.


.include "m8def.inc"
.def temp = r16

rjmp reset ; Reset Handler
;rjmp interrupt0 ; IRQ0 Handler
;reti ; IRQ1 Handler
;reti ; Timer1 Capture Handler
;reti ; Timer1 compare Handler
;reti ; 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
;reti
;reti
;reti
;reti
;reti

reset:
ldi temp, LOW(RAMEND) ;LOW-Byte der obersten RAM-Adresse
out SPL, temp
ldi temp, HIGH(RAMEND) ;HIGH-Byte der obersten RAM-Adresse
out SPH, temp

ldi r16, 0xFF
out DDRC, r16 ; Port C output
ldi r17, 0x00
out PORTC, r17 ; Port C LEDs an

;-----------externer Interrupt enablen--------------
ldi r16, 1<<int0
out GICR, r16

ldi r16, 1<<ISC01
out MCUCR, r16

sei ;global interrupt enable
;----------------------------------------------------
main:
loop:
rjmp loop

;----------Interruptprozedur--------------
interrupt0:
com r17
out PORTC, r17
reti
;----------------------------------------

pebisoft
27.09.2005, 21:20
http://www.mikrocontroller.net/articles/c/Timer_Counter.htm
http://mc-project.de/Pages/timer.html

war wohl nichts.....
mfg pebisoft

Lektor
27.09.2005, 21:31
beide links funktionieren leider zur Zeit nicht.

Warum hast du eigentlich 2 Warnungen?

Naja habe erstmal .0rg 0x0000 hinzugefügt. Funktioniert aber immernoch nicht. Die Simulation funktioniert.

recycle
27.09.2005, 23:55
@Lektor


Kann den Fehler einfach nicht finden. AVR Studio gibt keinen Fehler aus und ich möchte auch nicht nach jeder kleinen Änderung den uC neu programmieren. Soll ja angeblich auch nicht unbegrenzt oft funktionieren.

Für den Flash-Rom des ATMega8 ist im Datenblatt eine Haltbarkeit von 10.000 Schreib/Lösch-Zyklen angegeben und ein neuer kostet knapp 3 Euro.
Ich glaube unter dieser Voraussetzung kannst du ruhig auch mal kleinere Änderungen in den Controller schreiben und ausprobieren.

Lektor
28.09.2005, 07:56
hmmmm, das hilft mir leider auch nicht viel weiter ;)

Lektor
28.09.2005, 09:19
so, noch ein Erklärungsversuch



.include "m8def.inc"
.def temp = r16

;.org 0x0000
rjmp reset ; Reset Handler
;reti ; IRQ1 Handler
sei

reset:
ldi temp, LOW(RAMEND) ;LOW-Byte der obersten RAM-Adresse
out SPL, temp
ldi temp, HIGH(RAMEND) ;HIGH-Byte der obersten RAM-Adresse
out SPH, temp

ldi temp, 0xFF
out DDRC, temp

ldi temp, 0x00
out DDRD, temp

test:
in temp, pind
out portc, temp
rjmp test


so funktioniert der Code. Sobald ich aber entweder das .org oder reti dazunehme, funktioniert es nicht mehr. Kann mir nicht erklären woran es liegt. Ist einfach nur unlogisch. Bitte helft mir, denn wenn es schon an so einfachen Dingen scheitert, dann kann ich den uC vergessen.

pebisoft
28.09.2005, 10:52
Warum hast du eigentlich 2 Warnungen?

einige user mögen meine harten äußerungen nicht und reagieren ein bisschen
verweichlicht. obwohl diese user es so verdient haben.
der chef des hauses meint , wenn ich unruhe reinbringe kostet es ein bussgeld. ich kann damit leben mit meinen 57 jahren.
mfg pebisoft

enoritz
28.09.2005, 11:12
RETI holt sich die Adresse vom Stack, von wo aus deine Funktion angesprungen wurde, und springt zu dieser Addresse Zurück. RJMP ist einfach nur ein Sprungbefehl, d.h. es wird keine Addresse mehr auf den Stack gepusht sondern der Program-Counter wird einfach auf einen neuen Wert gesetzt. So entsteht der Fehler beim Reti nach dem Sprung auf Reset. Auf dem Stack steht überhaupt keine Addresse, wo hingesprungen werden kann.

Lektor
28.09.2005, 14:16
wie muß ich den jetzt den Code ändern das es funktioniert? Deine Erklärung hört sich für mich so an als müßte ich die Stackinitialiesung noch vor der Interrupttabelle setzen; das habe ich aber noch nie gesehen. Ich habe ja alles nur aus Tutorials kopiert und diese Interrupttabelle sieht man ja auch praktisch in jedem Programm.
Bin schon langsam am überlegen ob ich nicht auf C umsteige weil mir diese kleinen unerklärlichen Probleme den ganzen Spaß rauben.

enoritz
28.09.2005, 18:18
Du springst am besten von der Reset in die Loop-Routine (Oder jede andere, von wo aus der Code weiterlaufen soll). Dort wird dann dein ganzer Code ausgeführt.

Das Problem bei deinem Code ist ja(obwohl es auch eigentlich kein Problem ist), dass du in der Reset-Routine den Stack neu initalisierst und deine ganzen Einstellungen zurücksetzt (Was bei einem Hardware-Reset ja auch durchaus gewünscht ist), allerdings den "normalen" Programmfluss durcheinander bringt, falls per Software ausgeführt.

Das reti-Statement ist deswegen absolut fehl am Platze.

Lektor
28.09.2005, 18:56
wenn aber die Stackinitialisierung übersprungen wird, wie soll dann der Stack initialisiert werden? Dann läuft das Programm ständig in der "test" Schleife und der Stack und der DDR wurde nicht eingerichtet.
Poste mal bitte ein funktionierendes Beispiel. Das würde mir sehr helfen. Kann der uC vielleicht kaputt sein? Kann mir nicht vorstellen das alle Tutorials falsch sind und wenn ihr keinen Fehler findet, dann..... Weiss einfach nicht mehr weiter. Es raubt einem echt den Spaß.

enoritz
28.09.2005, 19:35
.include "m8def.inc"
.def temp = r16

rjmp reset ; Reset Handler
;rjmp interrupt0 ; IRQ0 Handler
;andere Interrupt-Vektoren
;reti

;----------Interruptprozedur--------------
interrupt0:
com r17
out PORTC, r17
reti
;----------------------------------------

reset:
ldi temp, LOW(RAMEND) ;LOW-Byte der obersten RAM-Adresse
out SPL, temp
ldi temp, HIGH(RAMEND) ;HIGH-Byte der obersten RAM-Adresse
out SPH, temp

ldi r16, 0xFF
out DDRC, r16 ; Port C output
ldi r17, 0x00
out PORTC, r17 ; Port C LEDs an

;-----------externer Interrupt enablen--------------
ldi r16, 1<<int0
out GICR, r16

ldi r16, 1<<ISC01
out MCUCR, r16

sei ;global interrupt enable
rjmp main ;<----
;----------------------------------------------------
main:
loop:
rjmp loop


Also erstmal ein wenig zu der RJMP-Instruction. Der ganze Befehl verbraucht 2 Byte Speicher. 1Byte für den Befehl, 1 Byte für den Parameter k also die Addresse die angesprungen werden soll. Deswegen solltest du die Interrupt-Vektoren mit einem RJMP-Statement auf ein Label festsetzen, welches unmittelbar unter der Vektoren-Tabelle steht. (Das hat eigentlich nur Geschwindigkeitsrelevante Gründe - der JMP-Befehl nimmt ein Wort als Parameter) Deswegen hab ich die Routine für den externen Interrupt mal direkt unter die Tabelle geschrieben.

Das einzige, was ich sonst noch geändert habe, ist das Einfügen eines RJMP-Befehls auf das Main-Label.

So hier mal eine Erklärung zum Thema Interrupts:
Der Reset-Handler wird immer dann ausgeführt, wenn ein Hardware-Reset am Controller selbst bzw. am Reset-Pin durchgeführt wird. Das gilt quasi als Reset des Controllers, was durch einen Abfall der Spannungsversorgung passiert sein könnte, oder eben durch das gewollte betätigen eines Schalters. Über den Interrupt-Vektor wird die Reset-Routine aufgerufen, der Stack und und der Port initialisiert. Anschließend wir dann via rjmp main, die Main-Routine aufgerufen, dort fängt dein Programmfluss an.

Der Mikrocontroller kann eingentlich nicht kaputt sein. Versuchs mal so wie oben. Es kann daran liegen, das es nicht funktioniert hat, dass direkt nach dem Reset in die interrupt0-Routine weitergeganen wurde, wo dann per reti der saubere Ablauf zerhackt wurde.

;andere Interrupt-Vektoren
Hier müssen noch die anderen Interrupt-Vektoren eingefügt werden, die habe ich vorhin entfernt.

Falls es nicht klappt, dann machs nocheinmal so wie vorher ohne das interrupt0 label.

Lektor
28.09.2005, 20:06
danke für deine Mühe. Habs verstanden