Archiv verlassen und diese Seite im Standarddesign anzeigen : AT90S2313 - Timer
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
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
Oh, sry.... in Assembler
Wo gibts denn die Tutorials?? bei Google hab ich dann wahrscheinlich die falschen Stichwörter angegeben.
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
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
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?
Woher soll der MC wissen, dass er bei einem Timerinterrupt zu time: springen muss?
Wenn ich das jetzt so spät noch auf die schnelle sehe, ich glaube es ist richtig!
Probier es doch einfach aus! :o)
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
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??
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)
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....
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)
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 ;-)
Hi enoritz!
Funktioniert's?
Ne, hat nicht funktioniert
Schade, ich simuliere es nochmal und dann versuche ich mal den Fehler zu finden!
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.....
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)
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:)
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)
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, 22:20
http://www.mikrocontroller.net/articles/c/Timer_Counter.htm
http://mc-project.de/Pages/timer.html
war wohl nichts.....
mfg pebisoft
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.
@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.
hmmmm, das hilft mir leider auch nicht viel weiter ;)
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, 11: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
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.
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.
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.
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ß.
.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.
danke für deine Mühe. Habs verstanden
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.