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


von Chris G. (chriscrown)


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


1
.include "m8def.inc"
2
3
.def temp1 = r16
4
.def leds = r17
5
.def z1 = r18
6
7
.org 0x0000
8
  rjmp main          ;Reset Handler
9
10
.org OVF0addr
11
  rjmp timer0_overflow    ;Timer Overflow Handler
12
13
main:
14
  ldi temp1, LOW(RAMEND)    ;Stackpointer initialisieren
15
  out SPL, temp1
16
  ldi temp1, HIGH(RAMEND)
17
  out SPH, temp1
18
19
  ldi temp1, 0b01000000    ;Register konfigurieren
20
  out DDRD, temp1
21
22
  ldi leds, 0xFF
23
  ldi z1, 0
24
25
  ldi temp1, 2        ;Vorteiler
26
  out TCCR0, temp1
27
28
  ldi temp1, 1<<TOIE0      ;Timer Interupts erlauben
29
  out TIMSK, temp1
30
31
  sei
32
33
loop:
34
  rjmp loop
35
36
37
timer0_overflow:
38
  ;inc z1
39
  ;cpi z1, 10
40
  ;brne timer0_overflow_end
41
  rcall invert_leds
42
timer0_overflow_end:
43
  reti
44
45
invert_leds:
46
  andi leds, 0b01000000    ;nur LED ansteuern
47
  out PORTD, leds
48
  com leds
49
  ret

von Wolfram Q. (quehl)


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

von AVRFan (Gast)


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.

von Chris G. (chriscrown)


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!

von AVRFan (Gast)


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! :-)

von Chris G. (chriscrown)


Lesenswert?

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

Geht aber leider auch mit sichern des SREG nicht...
1
timer0_overflow:
2
  in temp1, sreg
3
  rcall invert_leds
4
timer0_overflow_end:
5
  out sreg, temp1
6
  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...

von Johannes M. (johnny-m)


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.
1
in r16, SREG
2
push r16
3
;....ISR
4
pop r16
5
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.

von Chris G. (chriscrown)


Lesenswert?

Okay, das hätten wir schon mal geklärt.

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

von AVRFan (Gast)


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.
1
timer0_overflow:
2
    push t
3
    in t, SREG
4
    push t
5
6
    rcall invert_leds
7
8
timer0_overflow_end:
9
    pop t 
10
    out SREG, t
11
    pop t
12
13
    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

von Chris G. (chriscrown)


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.

von Chris G. (chriscrown)


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.

von AVRFan (Gast)


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:
1
SwitchLED:
2
   inc c                   ; wird permanent hochgezählt (...254, 255, 0, 1, 2...)
3
4
   bst c, 4                ; Bit Nr. 4 von c ins T-Flag kopieren 
5
6
   clr ledstate
7
   bld ledstate, LEDPIN    ; T-Flag ins LEDPIN-ste Bit von ledstate schreiben
8
   out PORTD, ledstate     ; LED schalten
9
10
   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:
1
SwitchLED:
2
   inc c                  ; wird permanent hochgezählt (...254, 255, 0, 1, 2...)
3
4
   mov ledstate, c
5
   andi ledstate, ...     ; nervige Piepser ausmaskieren 
6
   out PORTD, ledstate    ; alle an Port D angeschlosenen LEDs blinken lassen
7
8
   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.

von Chris G. (chriscrown)


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.

von AVRFan (Gast)


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?

von Chris G. (chriscrown)


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!

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
Noch kein Account? Hier anmelden.