Forum: Mikrocontroller und Digitale Elektronik Atmega8: Assembler schalten von Ausgängen / Led am Ausgang "gedimmt"


von Lukas .. (luki93)


Angehängte Dateien:

Lesenswert?

Hallo,


ich beschäftige mich seit kurzem mit dem Assembler programmieren.
Dazu verwende ich einen Atmega8 auf einem Selfmade Experimentierboard 
mit ein paar Ausgängen (PortB zu LEDS), Tastern, Mehrfarbige LED und 
einem Summer.

Als Einstieg habe ich ein Sample verwendet welches eine LED am PortB 
blinken lässt. Hat auch funtkioniert.
Im nächsten schritt wollte ich ein Lauflicht programmieren.
--> Hat auch funktioniert und das lauflicht läuft und läuft :D

ABER:

Mir ist aufgefallen dass das Bit7/Led8 und Bit8/Led6 nicht vollständig 
leuchten.

Hier der Assembler Sourcecode. Die Kommentare stimmten teilweise nicht 
mehr überein und manche Dinge werden noch nicht aufgerufen.
Als Test schalte ich alle LEDs ein.

************************************************************************ 
******
;*
;*  Titel:          LED Blinkprogramm
;*  Autor:          Rüdiger Kluge
;*  Version:        01.01.0003
;*  Build date:     22.12.08
;*  Target:         ATmega8
;*
;*  Zweck:
;*  Eine an PORTB, PB0 angeschlossene LED blinkt
;*  Die Periode des Blinkens kann mit den Variablen
;*      delay_0
;*      delay_1
;*      delay_2
;*  eingestellt werden.
;*
;*********************************************************************** 
*******


;*********************************************************************** 
*******
;* Definitionen
;*********************************************************************** 
*******

.include "m8def.inc"        ; Definitionen für ATmega8
.def temp       = r16       ; temp ist symbolischer Name für Register 16
                            ; wird als temporäre Variable verwendet
.def delay_0    = r17       ; delay_0 ist symbolischer Name für Register 
17
.def delay_1    = r18       ; delay_1 ist symbolischer Name für Register 
18
.def delay_2    = r19       ; delay_2 ist symbolischer Name für Register 
19
.def count    = r20
.equ LED_0      = ~0b00000000


;*********************************************************************** 
*******
;*  Programm Start nach Reset
;*
;*  der Stackpointer wird initialisiert
;*  RAMEND = $045F = 1119 beim ATmega8
;*  Register werden gesetzt
;*********************************************************************** 
*******

RESET:                          ; hier startet der Code nach einem Reset
    ldi     temp,high(RAMEND)    ; $04 wird in Register 16 geladen
    out     SPH,temp             ; SPH, oberes Byte des Stackpointers 
wird $04
    ldi     temp,low(RAMEND)     ; $5F wird in Register 16 geladen
    out     SPL,temp             ; SPL, unteres Byte des Stackpointers 
wird $5F
    out     DDRB,temp           ; setzt alle PINs von PORTB als Ausgang
    ldi     temp,LED_0          ; temp wird 0b00000000



;*********************************************************************** 
*******
;*  Hauptprogramm
;*
;*  eine endlose Schleife
;*********************************************************************** 
*******

MAIN:                           ; hier startet das Hauptprogramm

;   ldi     delay_0, 1          ; delay_0 wird 0
;   ldi     delay_1, 1          ; delay_1 wird 0
;   ldi     delay_2, 4          ; delay_1 wird 0
    out     PORTB,temp          ; PORTB, PIN0 wird gesetzt
;   lsr     temp
;   com      temp
;   cpi      count, 8
;   breq    RESET_REGISTER
;   rcall   SUB_COUNT
;   rcall   SUB_DELAY           ; Verzögerung, Sprung zu Unterprogramm
    rjmp    MAIN                ; springt zurück zu MAIN:


;*********************************************************************** 
********
;* Unterprogramm SUB_DELAY
;*
;* erzeugt eine Verzögerung für das Blinken
;*
;*********************************************************************** 
********

SUB_DELAY:                      ; hier ist der Einsprung ins 
Unterprogramm

                                       ; hier beginnt die innere 
Schleife
dec     delay_0             ; delay_0 = delay_0 - 1
brne    SUB_DELAY           ; wird ausgeführt, solange delay_0 nicht 0 
ist
                                ; hier beginnt die innere Schleife
dec     delay_1             ; delay_0 = delay_0 - 1
brne    SUB_DELAY           ; wird ausgeführt, solange delay_0 nicht 0 
ist
                                ; hier beginnt die innere Schleife

dec     delay_2             ; delay_0 = delay_0 - 1
brne    SUB_DELAY           ; wird ausgeführt, solange delay_0 nicht 0 
ist
                                ; hier beginnt die innere Schleife


    ret                         ; Sprung zurück ins Hauptprogramm zur
                                ; Instruktion nach
                                ; rcall SUB_DELAY, also rjmp

SUB_COUNT:

inc    count

ret


RESET_REGISTER:

ldi   temp, LED_0
out    PORTB,temp
ldi   count, 0

rjmp MAIN
***********************************************************************

Könnt ihr mir bitte helfen was ich falsch mache ?
Auch auf meinem zweiten Board tritt der selbe Fall auf.

DANKE !!
Grüße
Luki


Foto ist angehängt.

: Bearbeitet durch User
von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

DDRB ist falsh initialisiert.Tausche mal die 2 Zeilen nach der 
Stackpointer-Init.

von Michael U. (amiga)


Lesenswert?

Hallo,

wird $5F
    out     DDRB,temp           ; setzt alle PINs von PORTB als Ausgang
    ldi     temp,LED_0          ; temp wird 0b00000000

was bringt Dich auf die Idee, daß $5F ALLE Pins auf Ausgabg schaltet?
Bei sind bei 0b00111111 nur Pb0...PB5 Ausgang und Pb6+7 beliben Eingang.
Da schaltest Du also nur den internen PullUp (irgendwas um 30k) ein- und 
aus, logisch, daß die LEDs mit solche einem großen Vorwiderstand nur 
glimmen.

Da solltest Du also temp schon mit $FF laden...

Gruß aus Berlin
Michael

von Lukas .. (luki93)


Lesenswert?

Hallo!

Vielen dank für die schnelle Hilfe !! Hab nicht damit gerechnet so 
schnell eine Antwort zu bekommen.
Ich habe jetzt den DDRB nicht mit $5F sondern mit $FF also wie von Knut 
vorgeschalgen die Zeilen nach der Stackpointer Initialisierung 
vertauscht.
--> Folglich wird DDRB mit $FF initialisiert.


Zum Thema Stackpointer-Init bin ich mir auch nicht sicher warum ich das 
benötige. Ich greife ja nicht auf dem Stack zu.
Kann mir das jemand erklären oder weiß jemand wo ich das nachlesen kann 
?



Vielen Dank nochmals für die schnelle Hilfe !! :)


Gruß
Luki

von Thomas E. (picalic)


Lesenswert?

Lukas A. schrieb:
> Zum Thema Stackpointer-Init bin ich mir auch nicht sicher warum ich das
> benötige. Ich greife ja nicht auf dem Stack zu.

Sobald Du Unterprogramme aufrufst (call, rcall, später evtl. auch 
Interrupt Service Routinen), verwendet der Controller automatisch den 
Stack. Dort legt er die Rücksprung-Adresse ab.

: Bearbeitet durch User
von Lukas .. (luki93)


Lesenswert?

Alles klar ! Vielen dank !
Und ich dachte dass macht der Atmega selbst wenn man Unterprogrammer 
oder ISR aufruft. Nur wenn ich selbst auf den Stack zugreife muss ich 
diesen Decklarieren.
Leider war meine Vermutung falsch !


Danke nochmals !

von spess53 (Gast)


Lesenswert?

Hi

>Und ich dachte dass macht der Atmega selbst wenn man Unterprogrammer
>oder ISR aufruft.

Das ist richtig.

>Nur wenn ich selbst auf den Stack zugreife muss ich
>diesen Decklarieren.

Da bleiben außer push und pop nicht viel übrig. Ansonsten hast du, außer 
der Stackinitialisierung, nichts mit dem Stack zu tun. Und selbst das 
wird bei neueren AVR automatisch erledigt.

MfG Spess

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.