mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Blinklicht in Assembler


Autor: Ricardo Herrklotz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Chris (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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ß

Autor: Ricardo Herrklotz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke ich werd mir das mal anschauen

Autor: Ricardo Herrklotz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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??

Autor: Andi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du mußt den Timer1-IRQ noch aktivieren.
Nach dem rcall load_count setz mal folgendes ein:
"sbi TIMSK,TOIE1"

Gruß
Andi

Autor: ...HanneS... (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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...

Autor: Tobi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
sbi/cbi geht bis 0x20, timsk ist an 0x39

Autor: Andi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Ricardo Herrklotz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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??

Autor: Andi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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/...

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

Autor: Ricardo Herrklotz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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!

Autor: Ricardo Herrklotz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das studieren des Datenblatts hat mich leider auch nicht wirklich
weitergebracht!

Autor: Andreas Hesse (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Jörg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Jörg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Jörg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Andi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Jörg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Andi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Jens (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hi

guck mal auf..


http://paste.phpfi.com/31595


nur als ansatz, da wird eine led immer abwechselnt an / ausgeschaltet

Autor: Denis Gérard (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
läuft der AVR überhaupt bzw. hast du mit einem kurzem testprogramm
mal geschaut ob irgendeine LED überhaupt an (aus) geht?

Autor: Ricardo Herrklotz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.