Ich bin ein absoluter newbie in sachen mikrocontroller und assembler. Ich möchte nun ein ganz einfaches Prog. schreiben, welches zwei led's abwechselnd an PD0 und PD1 blinken lässt. und das ganze mit 1Hz. Das Problem das ich hab ist, dass ich keinen Ahnung hab wie ich den internen Timer meines ATmega8 (4MHz) verwenden kann. Was ich bis jetzt herausgefunden habe ist, dass man irgendwelches Bits setzten muss um einen "Multiplikator" (oder so ähnlich) einzustellen, der dann sagt wie oft der Timer in der sek. zählt. Was ich auch schon herausgefunden hab ist, das ich den Timer1 nehmen muss, weil ein 8bit Timer nicht für so eine "große" Zeitspanne ausreicht. Bei jedem Überlauf des Timers soll dann ein Interrupt ausgelöst werden. Doch wie konfiguriere ich den Timer und starte ihn? welche bits muss ich setzten?? Könnt ihr mir vielleicht einen Link nennen wo das verständlich beschrieben wird? danke
Hallo, Du setzt das Bit für globale Interruptfreigabe, setzt das Bit, damit Timer1 einen Überlauf-Interrupt auslöst, stellst den Vorteiler ein, so das die Quarzfrequenz geteilt durch den Wert des Vorteilers, z.B. 1024, in die Nähe Deiner gewünschten Frequenz kommt. Takt Vorteiler 65535 = Interruptfrequenz. Welche Bits in welchen Registern das genau sind, steht im Datenblatt in den Kapiteln zum Interrupt und zu dem Timer1. Dann kannst Du in der Interruptroutine irgend ein Bit setzen, und dieses im Hauptprogramm abfragen und an den Port weiter geben oder Du schiebst in der Interruptroutine ein Register nach links und gibst dieses im Hauptprogramm am Port aus. Auf der Homepage von Scott-Falk Huehn ist ein Beispiel, wie einen LED blinkt, allerdings ohne Interrupt. oder hier, allerdings nicht für den Mega: www.avr-asm-tutorial.net/avr_de/test4.html Gruß
aus den verschiedensten Seiten hab ich nun folgenden Code gebastelt: .include "m8def.inc" .org 0x000 rjmp start .org 0x08 rjmp overflow ; Timer1 Overflow Handler ;-------------------------------------- start: ;-- stapel initialisieren ldi r16,HIGH(RAMEND) out SPH,r16 ldi r16,LOW(RAMEND) out SPL,r16 ;-- LED's initialisieren: ldi r16,0xFF out DDRB,r16 ldi r16,0x00 out PORTB,r16 ldi r17,0b01010101 sei rcall load_count ;-------------------------------- ;prescaler auf 256 setzen ldi r16,0x04 out TCCR1B,r16 ;-------------------------------- loop: rjmp loop ;-----------------------------------------´ overflow: ;LED's ändern inc r17 out PORTB,r17 rcall load_count reti ;------------------------------------------ load_count: push r16 ;Timer Counter mit 49911 vorladen ldi r16,HIGH(49911) out TCNT1H,r16 ldi r16,LOW(49911) out TCNT1L,r16 pop r16 ret ;------------------------------------------ nur er funzt nicht und ich hab keine ahnung worans liegt. Wenn ich den proz starte tut sich nichts. alle LEDs tot! obwohl die LEDs in der Hauptroutine einmal alle angeschaltet werden! sozusagen als funktionstest! Aber da geht nichts!! Woran könnte das liegen??
Du mußt den Timer1-IRQ noch aktivieren. Nach dem rcall load_count setz mal folgendes ein: "sbi TIMSK,TOIE1" Gruß Andi
sbi im oberen I/O-Bereich?? Ich habe jetzt zwar nicht konkret im Datenblatt nachgeschaut, aber ich denke, dass die Register der Timer im oberen I/O-Bereich liegen. SBI/CBI geht doch aber nur im unteren Bereich, oder?? ...HanneS...
Ups, sorry, habe nur versucht, zu helfen! Sich über andere Leute beschweren aber selber keinen Lösungsvorschlag bringen, das ham ma gern ;-) Habe bei mir gerade nachgesehen und da ist es auch mit out. Aber das hasse ich wirklich am meisten bei den AVR´s. Dies und das geht einfach mit diesem oder jenem Befehl ABER... Ansonsten jibt es nix auszusetzen über die AVR´s. Das nur mal so am Rande. @Ricardo: Dann füge folgendes, am besten lieber doch vor der Marke "loop", ein: ldi r16,0b00000100 out TIMSK,r16 oder ldi r16,1<<TOIE1 out TIMSK,r16 Gruß Andi
Danke für den Tip. Leider muss sonst noch ein Fehler drinen sein! Ich hab den Code nun ein bisschen geändert: .include "m8def.inc" .org 0x000 rjmp start .org 0x08 rjmp overflow ; Timer1 Overflow Handler ;-------------------------------------- start: ;-- stapel initialisieren ldi r16,HIGH(RAMEND) out SPH,r16 ldi r16,LOW(RAMEND) out SPL,r16 ;-- LED's initialisieren: ldi r16,0xFF out DDRB,r16 sei rcall load_count ldi r17,0b01010101 out PORTB,r17 ;-------------------------------- ;prescaler auf 256 setzen ldi r16,0x00000100 out TCCR1B,r16 ;-------------------------------- ;-------------------------------- ;timer_1 overflow interrupt enable ldi r16,0b00000100 out TIMSK,r16 ;-------------------------------- loop: rjmp loop ;-----------------------------------------´ overflow: ;LED's ändern ror r17 out PORTB,r17 rcall load_count reti ;------------------------------------------ load_count: push r16 ;Timer Counter mit 49911 vorladen ldi r16,HIGH(49911) out TCNT1H,r16 ldi r16,LOW(49911) out TCNT1L,r16 pop r16 ret ;------------------------------------------ ich komm einfach nicht drauf woran es liegt! der timer dürfte einfach nicht zu zählen beginnen oder kein interrupt auslösen! Muss ich da noch irgend ein Bit setzen??
Du könntest ja mal zur Sicherheit die Liste für die Interrup-Vektoren verfollständigen: .org 0x000 rjmp start ; Reset-Vektor reti reti reti reti reti reti reti rjmp overflow ; Timer1 Overflow Handler ($008) reti reti reti reti reti reti reti reti reti reti reti Wenn von Haus aus ein IRQ aktiv ist, wird durch ein RETI verhindert, das irgend was unvorhergesehenes passiert und Dein Prog.-Code ist nicht innerhalb der Vektor-Liste. Ansonsten lies Dir im PDF für den ATMega8 ab Seite 44 alles über Interrups durch. http://www.atmel.com/dyn/resources/prod_documents/doc2486.pdf Vielleicht mußt Du noch irgend was wegen dem Bootloader machen, weiß nur nicht was. Aber da hilft nur Büffeln im PDF. Gruß Andi
ich hatte auch schon prob. alle interrupts zu deklarieren! hatte aber nichts gebracht! Habs trotzdem nochmal probiert. Aber kein Erfolg! Naja dann packen wir mal usere Englischkenntnisse aus!
Das studieren des Datenblatts hat mich leider auch nicht wirklich weitergebracht!
Hallo, Du kannst den Timer so konfigurieren, das Du ihn nicht jedesmal neu laden muss (siehe CTC Clear Timer On Compare). Laut Kommentar aktivierst Du den OverFlow Interrupt, verwendest aber einen Compare Match Interrupt. Ich denke Du muesstest Bit 3 (also 0b00001000) nehmen. Gruss Andreas
Hallo Ricardo, du hast einen Fehler in Deiner Prescaler-Routine ;-------------------------------- ;prescaler auf 256 setzen ldi r16,0x00000100 out TCCR1B,r16 ;-------------------------------- du musst ldi r16,0b0000100 eingeben. x bedeutet Hexadezimalwert wird übergeben und der ist mit 00000100 out of range. Vielleicht solltest Du dir AVR-Studio von der Atmel Seite laden und Deine Programme darin simulieren. Habe ich auch mit Deinem Programm gemacht und der Fehler wurde sofort angezeigt. Gruß Jörg
Nochmals ich, falls die LED's abwechselnd blinken sollen würde ich statt ;LED's ändern ror r17 out PORTB,r17 ;LED's ändern com r17 out PORTB,r17 schreiben. Also das 1ner Complement bilden (heißt nur alles was 0 ist wird 1 und umgekehrt). ROR rotiert nach rechts und fügt ganz links das Carry-Bit ein und da Du es beim ersten mal nicht gesetzt hast schiebt er eine 0 ein. Dazu empfiehlt sich das AVR Instruction Manual (auch bei Atmel). Gruß Jörg
Nochmals zum 3., falls Deine Programme später mal zeitkritischer werden, würde ich die load_count-Routine in die Timer1-Overflow-Routine setzen. Der Aufruf der Unterroutine load_count plus dem pusch und pop plus Rücksprung kosten mal eben 11 Taktzyclen. Weiterhin kann es sein, dass es zu Laufzeitfehlern kommt, wenn z.B. die load_count-Routine durch einen anderen Interrupt unterbrochen wird. Gruß Jörg
Hallo Jörg! Wenn eine IRQ-Routine gestartet wurde, wird automatisch das I-Bit in SREG (Global Interrupt Flag) gelöscht, d. h. das während des Ablaufs einer IRQ-Routine keine andere IRQ-Routine gestartet wird. Beim Rücksprung aus einer IRQ-Routine mit RETI wird das I-Bit wieder automatisch gesetzt auch wenn vorher kein Hardware-Call zu einer IRQ-Routine war. Man kann das I-Bit mit SEI innerhalb einer IRQ-Routine wieder setzen wodurch dann ein Interrupt innerhalb einer IRQ-Routine aufgerufen werden darf aber so was sollte man dann mit eigenen Flag-Variablen handlen. Desweiteren kommt es im Normalfall bei einer IRQ-Auslösung während eine IRQ-Routine läuft quasi zu einer zeitlichen verzögerung. Z. B. wird für Timer1 das Flag Timer 1 Overflow Interruptflag gesetzt aber die dazu gehörende IRQ-Routine erst gestartet, wenn die vorher ausgeführte IRQ-Routine mit RETI beendet wurde. Will damit nur sagen, das die Unterroutine load_count welche mit rcall von der IRQ-Routine Timer1_Overflow aufgerufen wurde nicht unterbrochen werden kann da währenddessen das I-Bit gelöscht ist und erst durch RETI wieder gesetzt wird. Gruß Andi
Hallo Andi, stimmt hab ich nicht dran gedacht. Was passiert denn, wenn wärend der Abarbeitung eines Timer 1 Overflow Interrupts ein weiterer Timer 1 Overflow Interrupt auftritt? Gruß Jörg
Wenn der Timer1 einen IRQ auslöst während Timer1 läuft wird so gut wie kein Befehl mehr von dem normal ablaufenden Programm abgearbeitet. Desweiteren stimmt dann die Frequenz nicht mehr für Timer1 und man sollte die Frequenz verringern oder die Routine optimieren bzw. auf weniger Takte bringen. Gruß Andi
hi guck mal auf.. http://paste.phpfi.com/31595 nur als ansatz, da wird eine led immer abwechselnt an / ausgeschaltet
läuft der AVR überhaupt bzw. hast du mit einem kurzem testprogramm mal geschaut ob irgendeine LED überhaupt an (aus) geht?
Danke für alle Tipps! ich hatte eigentlich schon wenige Stunden nach der 1. Antwort gepostet das der Fehler mit dem x schuld war! der thread scheint aber gar nicht auf!?! Wahrscheinlich war irgend ein kleiner Fehler mit er Verbindung zum Server oder sonst was! Danke aber trotzdem für die vielen Antworten und Tips
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.