mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Timer funktioniert ab Vorteiler 256 nicht mehr


Autor: Chris G. (chriscrown)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Moin moin erstmal!

Ich mache gerade meine ersten Mikrocontroller-Gehversuche mit einem 
ATMega8 und komme an diesem Timer einfach nicht weiter... Das Programm 
soll eine LED an Port D (Pollin Evaluationsboard) ein- und ausschalten. 
Sobald ich aber den Vorteiler auf 256 oder größer stelle, bleibt die LED 
dunkel. Ich habe es mit dem extern Quarz (16 MHz) und allen internen 
Taktfrequenzen probiert. Man sieht zwar dass die LED flackert, aber eine 
geringere Taktfrequenz bringt nicht ein langsameres Flackern. Wo mache 
ich da einen Denkfehler??

Vielen Dank für Eure Hilfe,
Chris


.include "m8def.inc"

.def temp1 = r16
.def leds = r17
.def z1 = r18

.org 0x0000
  rjmp main          ;Reset Handler

.org OVF0addr
  rjmp timer0_overflow    ;Timer Overflow Handler

main:
  ldi temp1, LOW(RAMEND)    ;Stackpointer initialisieren
  out SPL, temp1
  ldi temp1, HIGH(RAMEND)
  out SPH, temp1

  ldi temp1, 0b01000000    ;Register konfigurieren
  out DDRD, temp1

  ldi leds, 0xFF
  ldi z1, 0

  ldi temp1, 2        ;Vorteiler
  out TCCR0, temp1

  ldi temp1, 1<<TOIE0      ;Timer Interupts erlauben
  out TIMSK, temp1

  sei

loop:
  rjmp loop


timer0_overflow:
  ;inc z1
  ;cpi z1, 10
  ;brne timer0_overflow_end
  rcall invert_leds
timer0_overflow_end:
  reti

invert_leds:
  andi leds, 0b01000000    ;nur LED ansteuern
  out PORTD, leds
  com leds
  ret

Autor: Wolfram Quehl (quehl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich kann keinen direkten Fehler finden. die ANDI Anweisung im Interrupt 
ist hier überflüssig. Aber funktionieren müßte das trotzdem.
Es ist nicht ganz klar, ob die LED dunkel bleibt oder flackert. Aufgrund 
meiner ähnlichen Tests müßte die LED leuchten und nur wenn man genau 
hinsieht, sehe ich ein Flackern. Etwas besser ist es, die andere LED 
auch einzuschalten, damit man den Unterschied sieht. Habe ich aber auch 
nicht gleich gesehen, waren fast gleich hell.

Ich würde einfach weiter programmieren. Manchmal sind die Fehler durch 
eine Umstellung durch eine tlw. Neuprogrammierung weg, ohne daß man 
weiß, woran das liegt.

mfg

Autor: AVRFan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich würde als Erstes mal die obligatorische Sicherung des SREG beim 
Eintritt in die Interruptroutine und Wiederherstellung vor dem Verlassen 
ergänzen.  Wenn man das weglässt, braucht man sich über "seltsame 
Effekte" nicht wundern.

Autor: Chris G. (chriscrown)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Alles klar, das mit dem SREG werde ich gleich mal ausprobieren.

Die andi Maske benutze ich um nur die eine LED zu schalten. Auf dem 
Board ist an Port D nämlich auch ein Piezo Pieper mit angeschlossen und 
der nervt doch ein bißchen bei den Tests... ;-)

Ich werde nachher von Erfolgen oder evtl. Mißerfolgen berichten!

Autor: AVRFan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Noch was eingefallen...

>Sobald ich aber den Vorteiler auf 256 oder größer stelle, bleibt die LED
>dunkel.

Ich hoffe, Du stellst den Vorteiler nicht auf 256, indem Du

  ldi temp1, 256      ;Vorteiler
  out TCCR0, temp1

schreibst.  Dann bleibt der Timer nämlich wirklich stehen! (Klar, warum? 
Wenn nicht, Bescheid sagen)

>Ich werde nachher von Erfolgen oder evtl. Mißerfolgen berichten!

Viel Glück! :-)

Autor: Chris G. (chriscrown)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ähhm, nein...
Soweit bin ich dann doch schon drin im Thema ;-)
ldi temp1, 5        ;Vorteiler 1024
out TCCR0, temp1

Geht aber leider auch mit sichern des SREG nicht...
timer0_overflow:
  in temp1, sreg
  rcall invert_leds
timer0_overflow_end:
  out sreg, temp1
  reti

Oder muss ich da noch mehr machen?? (temp1 wird nicht in invert_leds 
genutzt)

Noch ne kleine Frage am Rande: Warum kann man SREG nicht mit push und 
pop sichern? Ist das 16 Bit??

Viele Grüße


PS: Noch was: Ich will mit dem Programm kein PWM oder sowas machen, 
sondern einfach die LED langsam blinken lassen. Ich hatte auch noch ein 
zusätzlichen Zähler eingebaut, um die Frequenz noch weiter 
herunterzubringen, hat aber auch nicht richtig geklappt. Falls ihr also 
noch irgendwelche kreativen Anregungen in der Richtung habt, wäre ich 
sehr dankbar...

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Chris G. wrote:
> Noch ne kleine Frage am Rande: Warum kann man SREG nicht mit push und
> pop sichern? Ist das 16 Bit??
Nein, es ist ein I/O-Register, und die kann man nicht direkt pushen und 
poppen. Das geht nur mit Rechenregistern. Wenn Du im Programm Zeit hast, 
kannst Du z.B.
in r16, SREG
push r16
;....ISR
pop r16
out SREG, r16
schreiben. Sind pro ISR zwei Taktzyklen mehr, als wenn man es im 
Rechenregister lässt. Wenn das Register (kann auch jedes andere sein, 
muss nicht r16 sein) eh nicht in der ISR genutzt wird, dann kann man den 
Inhalt auch drinlassen.

Autor: Chris G. (chriscrown)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Okay, das hätten wir schon mal geklärt.

Jetzt muss nur noch der Rest mit dem Timer klappen...

Autor: AVRFan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>  ldi temp1, 5        ;Vorteiler 1024
>  out TCCR0, temp1

Jepp.  Eine besonders lesefreundliche Variante sieht übrigens so aus:

>  ldi temp1, 1<<CS02 | 0<<CS01 | 1<<CS00        ;Vorteiler 1024
>  out TCCR0, temp1

>Geht aber leider auch mit sichern des SREG nicht...

Hmmmm.....

>timer0_overflow:
>  in temp1, sreg
>  rcall invert_leds
>timer0_overflow_end:
>  out sreg, temp1
>  reti
>
>Oder muss ich da noch mehr machen?? (temp1 wird nicht in invert_leds
>genutzt)

Nein, das ist genau so OK, unter einer Bedingung: temp1 darf nirgendwo 
sonst im Programm benutzt werden (ausgenommen der Initialisierungsteil - 
logisch).

>Noch ne kleine Frage am Rande: Warum kann man SREG nicht mit push und
>pop sichern? Ist das 16 Bit??

Du kannst das SREG problemlos mit push und pop sichern, und so wird es 
auch am häufigsten bewerkstelligt.
timer0_overflow:
    push t
    in t, SREG
    push t

    rcall invert_leds

timer0_overflow_end:
    pop t 
    out SREG, t
    pop t

    reti
Hier kann das Register t beliebig im restlichen Programm verwendet 
werden.  Der Preis dafür ist eine etwas weniger schnelle 
Interruptroutine.

Das SREG ist 8 Bit breit.

8 MHz Systemtakt und Vorteiler 1024 macht eine Timer-Tickfrequenz von 
7812.5 Hz.  Overflow nach jedem 256. Tick resultiert zu einer 
LED-Blinkfrequenz von ca. 30.5 Hz.  Das ist nicht gerade eine langsames 
Blinken; man dürfte es eher als unruhiges Flackern wahrnehmen.  Tipp: 
Zähl einfach stupide irgendein Register in der ISR hoch, und gib nicht 
dessen Bit 0, sondern z. B. Bit 4 auf die LED.  Dann hast Du auf 
simpelste Weise einen weiteren "Software"-Frequenzteiler von 16 drin, 
und die LED sollte "augenfreundlich" blinken.

Gruß zurück

Autor: Chris G. (chriscrown)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das mit den 30Hz bei 8 MHz Systemtakt hatte ich mir auch schon 
ausgerechnet, deswegen hab ich den internen Takt mit 1 MHz benutzt, 
sollte also so knapp 4 Hz ergeben. Wie gesagt, SOLLTE ES, tut es aber 
nicht...

Oder gibts da irgendein Problem mit dem internen Takt?? Es kommt erstmal 
auf Genauigkeit nicht an. Ich hätte sonst noch einen externen 16 MHz 
Quarz auf dem Board im Angebot.

Hierzu:

> Tipp:
> Zähl einfach stupide irgendein Register in der ISR hoch, und gib nicht
> dessen Bit 0, sondern z. B. Bit 4 auf die LED.  Dann hast Du auf
> simpelste Weise einen weiteren "Software"-Frequenzteiler von 16 drin,
> und die LED sollte "augenfreundlich" blinken.

...hab ich noch ne kleine Frage:

Heißt das, dass ich doch ein Register nehmen soll, aber eben das Bit 4 
auf die LED ausgeben soll?? Kapier ich noch nicht ganz fürchte ich...
Ich hab jetzt einfach immer einen Zähler gemacht und dann mit cpi auf 
einen Wert geprüft und mit brne dann die Verzweigung realisiert.

Autor: Chris G. (chriscrown)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Yeah, es funktioniert!!

Ich hab nochmal ne Runde mit den Fuse-Bits "rumgespielt" und dazu das 
Datenblatt des Mega8 gewälzt und bin zu folgender Einstellung gelangt:

CKOPT  = 0
CKSEL3 = 1
CKSEL2 = 0
CKSEL1 = 1
CKSEL0 = 1
SUT1   = 1
SUT0   = 1

Somit sollte ich den externen Quarz mit 16 MHz nutzen können. Mit einer 
einfachen Zählschleife kann ich nun die LED schön langsam ein- und 
ausschalten. :-)

Aber warum das mit dem internen Takt nicht hingehauen hat verstehe ich 
immer noch nicht ganz. Vielleicht kann ja hier noch jemand für 
Aufklärung sorgen.

Autor: AVRFan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Heißt das, dass ich doch ein Register nehmen soll, aber eben das Bit 4
>auf die LED ausgeben soll??

Ja, zum Beispiel so:
SwitchLED:
   inc c                   ; wird permanent hochgezählt (...254, 255, 0, 1, 2...)

   bst c, 4                ; Bit Nr. 4 von c ins T-Flag kopieren 

   clr ledstate
   bld ledstate, LEDPIN    ; T-Flag ins LEDPIN-ste Bit von ledstate schreiben
   out PORTD, ledstate     ; LED schalten

   ret

Das ergibt eine Frequenzteilung (ISR-Durchlauffrequenz zu 
LED-Blinkfrequenz) von 2^4 = 16.  Wenn Du aus der 4 eine 5 machst, hast 
Du eine Teilung von 2^5 = 32 usw.  Du kannst so die Blinkgeschwindigkeit 
der LED in Faktor-2-Schritten einstellen.

Alternativ kannst Du auch direkt c auf den Port D ausgeben:
SwitchLED:
   inc c                  ; wird permanent hochgezählt (...254, 255, 0, 1, 2...)

   mov ledstate, c
   andi ledstate, ...     ; nervige Piepser ausmaskieren 
   out PORTD, ledstate    ; alle an Port D angeschlosenen LEDs blinken lassen

   ret 

>Ich hab jetzt einfach immer einen Zähler gemacht und dann mit cpi auf
>einen Wert geprüft und mit brne dann die Verzweigung realisiert.

So geht es natürlich auch, und hat den Vorteil, jede beliebige Teilung, 
d. h. auch z. B. 5, 19, 27 zu ermöglichen.

>Yeah, es funktioniert!!

Glückwunsch! g

>Ich hab nochmal ne Runde mit den Fuse-Bits "rumgespielt"

Uahhhhh... ;-) Beim "Rumspielen" mit den Fuse-Bits sollte man stets 
vorsichtig sein, weil man mit bestimmten Einstellungen beispielsweise 
den Reset-Pin zu einem IO-Pin umfunktionieren kann.  Dann kann man den 
Controller aber auch nicht mehr per ISP neu programmieren!  Wenn Du dann 
kein Board zur Hand hast, das High-Voltage-Parallel-Programming 
unterstützt (wie etwa das STK500), stehst Du erst mal dumm da.  Deshalb 
ist es ratsam, die Fuse-Bits wie ein rohes Ei zu behandeln, und sie erst 
zu beschreiben wenn man sicher sein kann, genau zu wissen was man tut.

Autor: Chris G. (chriscrown)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich bin ganz vorsichtig mit den Fuses, versprochen... Hab auch nur an 
den Takteinstellungen rumgestellt, und auch nur wenn ich mir 100%ig 
sicher war.

Warum das aber alles mit dem internen Takt nicht geklappt hat weiß ich 
immer noch nicht.

Autor: AVRFan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Warum das aber alles mit dem internen Takt nicht geklappt hat weiß ich
>immer noch nicht.

Komische Sache... Also meine Wahl für "1 MHz internal R/C oscillator" 
wäre diese:

CKOPT  = 0
CKSEL3 = 0
CKSEL2 = 0
CKSEL1 = 0
CKSEL0 = 1
SUT1   = 0
SUT0   = 0

Pins XTAL1 und XTAL2 offen lassen.

Läufts bei Dir damit?

Autor: Chris G. (chriscrown)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So, bin endlich zum Ausprobieren gekommen und: ES GEHT!!
Ich hatte vorher nie etwas mit den SUT Bits gemacht, daran lags wohl...

Vielen Dank soweit!

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.