Atmega8: Assembler schalten von Ausgängen / Led am Ausgang "gedimmt"

OP #4527374
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.
Angehängte Dateien:
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
OP
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
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.
OP
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 !
Gast
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

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 10 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.