logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

obsługa wyświetlacza 7-segmentowego atmega8

kamil1cos7 20 Paź 2011 23:48 2182 6
REKLAMA
  • #1 10048946
    kamil1cos7
    Poziom 14  
    Cześć, napisałem taką obsługę wyświetlacza siedmiosegmentowego z przerwaniem od timer0
    i mam mały problem... Otóż, na wyświetlaczu pojawiają się albo trzy najstarsze cyfry a na cyfrze jedności jest nie wiadomo co, albo świeci się poprawnie cyfra jedności a pozostałe są zgaszone... i tak na zmianę co jakiś czas:P Mogli byście rzucić okiem na ten kod... Bo nie mogę sam dojść co jest źle;/
    .include "m8def.inc"
    .dseg
    .org 0x60
    mod0:      .BYTE 1
    mod1:      .BYTE 1
    mod2:      .BYTE 1
    mod3:      .BYTE 1
    wys_mod:   .BYTE 1
    
    .cseg
    .org 0x00
    rjmp start
    .org 0x09
    rjmp timer0
    .org 0x0A
    
    start:
    ldi r16, 15
    out DDRD, r16      ;cztery piny portu D jako wyjścia, ANODY
    
    ldi r16, 255
    out DDRB, r16      ;cały port B jako wyjścia, KATODY
    
    ldi r16, 127
    out SPL, r16         ;ustawiam wskaźnik stosu na 127
    
    ldi r16, 3
    out TCCR0, r16      ;ustawiam prescaler przez 64
    
    ldi r16, 1
    out TIMSK, r16         ; zezwolenie na przerwanie od timera0
    
    ldi r16, 177
    out TCNT0, r16         ;licznik timera0 aby zlicza do 78=(255-177)
    
    ldi r16, 0b00000001
    sts wys_mod, r16
    
    sei                 
    
    main:
    ldi r16, 48
    sts mod0, r16
    ldi r16, 36
    sts mod1, r16
    ldi r16, 120
    sts mod2, r16
    ldi r16, 16
    sts mod3, r16
    rjmp main
    
    timer0:
    ldi r16, 160
    out TCNT0, r16
    lds r17, wys_mod
    out PORTD, r17
    
    sbic PIND, 0
    lds r16, mod0
    sbic PIND, 1
    lds r16, mod1
    sbic PIND, 2
    lds r16, mod2
    sbic PIND, 3
    lds r16, mod3
    
    out PORTB, r16
    
    lsl r17
    sbic PIND, 3
    ldi r17, 1
    sts wys_mod, r17
    
    reti
  • REKLAMA
  • #2 10049242
    jarekz_2
    Poziom 16  
    Podprogram obsługi przerwania używa rejestru r16 zmieniając jego zawartość sprzed wystąpienia przerwania. Z punktu widzenia programu głównego zawartość r16 nagle „ni stąd ni zowąd“ się zmienia. To samo dzieje się z rejestrem stanu SREG (aczkolwiek akurat nie jest przyczyną błędu). W podprogramie „timer0“ koniecznie dodaj rozkazy:
    - na początku: zachowaj stany używanych rejestrów (r16 i SREG) na stosie:
    push r16 ;zachowaj r16
    in r16,SREG ;\
    push r16 ;/ zachowaj SREG
    - na końcu: odtwórz stany używanych rejestrów:
    pop r16 ;\
    out SREG,r16 ;/ odtwórz SREG
    pop r16 ;odtwórz r16
    Tego typu sekwencje rozkazów są na ogół NIEZBĘDNE w podprogramach obsługi przerwań!
    Inny sposób - ja często go stosuję - to zarezerwować część rejestrów TYLKO na potrzeby programu głównego, a część TYLKO dla podprogramów obsługi przerwań.
  • REKLAMA
  • #3 10049540
    kamil1cos7
    Poziom 14  
    Wielkie dzięki za wyczerpującą odpowiedź;)

    Dodano po 20 [minuty]:

    hmmm, użyłem oddzielnych rejestrów dla obsługi przerwań i dla programu głównego ale problem jest identyczny...
    .include "m8def.inc"
    .dseg
    .org 0x60
    mod0:      .BYTE 1
    mod1:      .BYTE 1
    mod2:      .BYTE 1
    mod3:      .BYTE 1
    wys_mod:   .BYTE 1
    
    .cseg
    .org 0x00
    rjmp start
    .org 0x09
    rjmp timer0
    .org 0x0A
    
    start:
    ldi r16, 15
    out DDRD, r16      ;cztery wyjścia portu D jako wyjścia, ANODY
    
    ldi r16, 255
    out DDRB, r16      ;cały port B jako wyjścia, KATODY
    
    ldi r16, 127
    out SPL, r16         ;ustawiam wskaźnik stosu na 127
    
    ldi r16, 3
    out TCCR0, r16      ;ustawiam prescaler przez 64
    
    ldi r16, 1
    out TIMSK, r16         ; zezwolenie na przerwanie od timera0
    
    ldi r16, 180
    out TCNT0, r16         
    
    ldi r16, 0b00000001
    sts wys_mod, r16
    
    sei               
    
    main:
    ldi r16, 18
    sts mod0, r16
    ldi r16, 36
    sts mod1, r16
    ldi r16, 120
    sts mod2, r16
    ldi r16, 0
    sts mod3, r16
    rjmp main
    
    timer0:
    ldi r18, 180
    out TCNT0, r18
    lds r17, wys_mod
    out PORTD, r17
    
    sbic PIND, 0
    lds r18, mod0
    sbic PIND, 1
    lds r18, mod1
    sbic PIND, 2
    lds r18, mod2
    sbic PIND, 3
    lds r18, mod3
    
    out PORTB, r18
    
    lsl r17
    sbic PIND, 4
    ldi r17, 1
    sts wys_mod, r17
    
    reti
    


    Dodano po 9 [minuty]:

    Zmieniłem także na drugi sposób i też bez zmian...
    
    timer0:
    push r16
    in r16, SREG
    push r16
    
    ldi r16, 180
    out TCNT0, r16
    lds r17, wys_mod
    out PORTD, r17
    
    sbic PIND, 0
    lds r16, mod0
    sbic PIND, 1
    lds r16, mod1
    sbic PIND, 2
    lds r16, mod2
    sbic PIND, 3
    lds r16, mod3
    
    out PORTB, r16
    
    lsl r17
    sbic PIND, 4
    ldi r17, 1
    sts wys_mod, r17
    
    pop r16
    out SREG, r16
    pop r16
    reti
    
  • REKLAMA
  • #4 10050572
    Andrzej__S
    Poziom 28  
    kamil1cos7 napisał:

    Zmieniłem także na drugi sposób i też bez zmian...


    Niemniej ten zabieg był konieczny. Nawet jeśli to w tej chwili być może nie ma większego znaczenia, to przecież program docelowo będzie zawierał jakieś instrukcje warunkowe i arytmetyczne, więc odłożenie na stos SREG jest niezbędne.

    Podobnie jest ze stosem. Kiedy stos rośnie, wskaźnik do stosu (SPH:SPL) maleje, czyli stos "zmierza" w stronę danych, i po dopisaniu jakichś procedur wywoływanych np, instrukcją RCALL lub dołożeniu innych przerwań może się na te dane nakładać (bo masz stos "niebezpiecznie" blisko danych). Jakie będą tego konsekwencje, możesz się chyba domyślić. Proponuję więc do wskaźnika stosu (SP) załadować adres końca RAM (RAMEND).

    Co do głównego problemu, proponowałbym dodać kilka instrukcji NOP (dwie lub trzy powinny wystarczyć) w obsłudze przerwania 'timer0' pomiędzy
    Kod: text
    Zaloguj się, aby zobaczyć kod

    lub zamiast instrukcji sbic PIND, 0 użyć sbrc r17, 0.
    Dlaczego? Spróbuj domyślić się sam.
  • #5 10051204
    kamil1cos7
    Poziom 14  
    Nie sądziłem że, tyle dobrych rad się tutaj dowiem;) Nie mam nic przeciwko następnym związanym z asemblerem;)
    Ale jest mały kłopot, program wygląda jak poniżej i zmiana w działaniu jest taka że, teraz zapalona jest cały czas pierwsza cyfra(tzn jedności), a pozostałe zgaszone... hmm, na to wygląda że, nie dochodzi do instrukcji przesunięcia w rejestrze r17 w którym przechowuje anody wyświetlacza... (instrukcje nop są w kodzie dwie ale próbowałem oczywiście więcej),a i dodam że, jestem początkujący w asemblerze... Ta instrukcja sbrc opuszcza następną instrukcje przy spełnieniu warunku czy może działa innaczej??
    .include "m8def.inc"
    .dseg
    .org 0x60
    mod0:      .BYTE 1
    mod1:      .BYTE 1
    mod2:      .BYTE 1
    mod3:      .BYTE 1
    wys_mod:   .BYTE 1
    
    .cseg
    .org 0x00
    rjmp start
    .org 0x09
    rjmp timer0
    .org 0x0A
    
    start:
    ldi r16, 15
    out DDRD, r16      ;cztery wyjścia portu D jako wyjścia, ANODY
    
    ldi r16, 255
    out DDRB, r16      ;cały port B jako wyjścia, KATODY
    
    ldi r16, RAMEND
    out SPL, r16         ;ładuje jako wskaźnik stosu adres konca RAM
    
    ldi r16, 3
    out TCCR0, r16      ;ustawiam prescaler przez 64
    
    ldi r16, 1
    out TIMSK, r16         ; zezwolenie na przerwanie od timera0
    
    ldi r16, 180
    out TCNT0, r16        
    
    ldi r16, 0b00000001
    sts wys_mod, r16
    
    sei        
    
    
    main:
    ldi r16, 2
    sts mod0, r16
    ldi r16, 36
    sts mod1, r16
    ldi r16, 120
    sts mod2, r16
    ldi r16, 0
    sts mod3, r16
    rjmp main
    
    timer0:
    push r16
    in r16, SREG
    push r16
    
    ldi r16, 180
    out TCNT0, r16
    lds r17, wys_mod
    out PORTD, r17
    nop
    nop
    nop
    sbrc r17, 0
    lds r16, mod0
    sbrc r17, 1
    lds r16, mod1
    sbrc r17, 2
    lds r16, mod2
    sbrc r17, 3
    lds r16, mod3
    
    out PORTB, r16
    
    lsl r17
    nop
    nop
    sbic PIND, 4
    ldi r17, 1
    sts wys_mod, r17
    
    pop r16
    out SREG, r16
    pop r16
    reti
  • #6 10051385
    Andrzej__S
    Poziom 28  
    SBRC robi to samo co SBIC, tylko operuje na rejestrze, a nie na porcie I/O.

    Jak zmieniłeś na SBRC, to nie musisz dawać tych NOP.

    kamil1cos7 napisał:

    Ale jest mały kłopot, program wygląda jak poniżej i zmiana w działaniu jest taka że, teraz zapalona jest cały czas pierwsza cyfra(tzn jedności), a pozostałe zgaszone... hmm, na to wygląda że, nie dochodzi do instrukcji przesunięcia w rejestrze r17 w którym przechowuje anody wyświetlacza..


    Tylko dlaczego zmieniłeś 3 na 4 w obsłudze przerwania:
    Kod: text
    Zaloguj się, aby zobaczyć kod

    W pierwszym poście miałeś 3, i gdyby tak zostało, to pewnie by działało :)
  • REKLAMA
  • #7 10052886
    kamil1cos7
    Poziom 14  
    Poprawiłem, ale kurde nadal jest to samo...
    timer0:
    push r16
    in r16, SREG
    push r16
    
    ldi r16, 180
    out TCNT0, r16
    lds r17, wys_mod
    out PORTD, r17
    
    
    sbrc r17, 0
    lds r16, mod0
    sbrc r17, 1
    lds r16, mod1
    sbrc r17, 2
    lds r16, mod2
    sbrc r17, 3
    lds r16, mod3
    
    out PORTB, r16
    
    lsl r17
    
    sbrc r17, 4
    ldi r17, 1
    sts wys_mod, r17
    
    pop r16
    out SREG, r16
    pop r16
    reti


    Dodano po 42 [minuty]:

    Panowie teraz się pojawia pytanie, bo jeśli testowo skleiłem taki oto kod, to wszystko śmiga jak należy...
    timer0:
    push r16
    in r16, SREG
    push r16
    
    ldi r16, 180
    out TCNT0, r16
    lds r17, wys_mod
    out PORTD, r17
    
    
    sbrc r17,    0
    ldi r16,     2
    sbrc r17,    1
    ldi r16,    120
    sbrc r17,    2
    ldi r16,     2
    sbrc r17,    3
    ldi r16,    120
    
    out PORTB, r16
    
    lsl r17
    
    sbrc r17, 4
    ldi r17, 1
    sts wys_mod, r17
    
    pop r16
    out SREG, r16
    pop r16
    reti


    Dodano po 1 [godziny] 33 [minuty]:

    Dobra już działa;)
    Dzięki wszystkim za pomoc;)
REKLAMA