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

Pobieranie danych z tablicy a program w asm

elektrokuba 18 Maj 2010 10:20 3031 23
  • #1 8089349
    elektrokuba
    Poziom 12  
    Witam
    Mam nadzieje że ktoś mi wytłumaczy gdzie tkwi problem i jak go rozwiązać gdyż sam na moim etapie znajomości AVR nie moge sobie poradzić.
    Uczę się asm i chcę napisac program do wyświetlania cyfr 0-9 na wyświetlaczu 7 segmentowym, cyfry mają się zmieniać po naciśnięciu przycisku +/-. Szkopuł tkwi w tym że nie wiem dlaczego w pozycji 0 po naciśnięciu - na wyświetlaczu pojawiają się jakieś hieroglify zamiast cyfry 9. Gdy wartość na wyświetlaczu jest różna od zera to po naciśnięciu - zachowanie jest prawidłowe. Domyślam się że problem tkwi w tablicy znaków zdefiniowanej na dole programu i w sposobie odwołania się do niej i detekcji zera ale nie wiem jak to zrobić żeby było dobrze. Będę bardzo wdzięczny za pomoc.
    Poniżej zamieszczam program.

    .include "2313def.inc"
    #define acc r16
    .cseg
    .org 0x00
    
    ldi acc, 0b11111111 ; załaduj do r16 liczbę 255 (0xff)
    out DDRB, acc ; wpisanie do DDRB samych jedynek
    ; powoduje ustawienie pinów jako wyjście
    out PORTB, acc
    ldi acc, 0b1111100 ;
    out DDRD, acc ; piny D0 i D1 są ustawione jako wejścia
    ; pozostałe jako wyjścia
    ldi acc, 0b1110111
    out PORTD, acc ; włączony pierwszy wyświetlacz, wejścia
    ; podciągnięte do zasilania
    
    
    ldi acc, 127 ;
    out SPL, acc ; ustawienie wskaˇnika stosu na 127
    
    start:
    ldi ZH, high(znaki << 1) ; załadowanie do rejestru Z adresu
    ldi ZL, low(znaki << 1) ; tablicy z kodami znaków
    
    sprawdz_klawisze:
    
    lpm ; załaduj do r0 bajt z pamięci programu
    mov r17, r0 ; przenieś zawartość r0 do r16
    cpi r17, 0 ; sprawdˇ, czy równe zero
    breq start ; jeśli tak, skocz na początek programu
    
    sbis PIND, 0 ; jeśli pin D0 = 1, to pomiń następną instrukcję
    adiw ZH:ZL, 1
    sbis pind, 1 ; jeśli pin D1 = 1, to pomiń następną instrukcję
    sbiw ZH:ZL, 1
    out portb, r0
    ldi acc, 150
    rcall waitms
    rjmp sprawdz_klawisze ; skocz do początku sprawdzania klawiszy
    
    waitms:
    mov r22, acc ; ustaw czas opóˇnienia
    ; powtórz n razy pętlę L,
    ; co da opóˇnienie ok. n * 1 ms
    L:
    ; powtórz 10 razy pętlę L0,
    ; co da opóˇnienie ok 1ms
    ldi r21, 10
    L0:
    ; powtórz 100 razy pętlę L1,
    ; co da opóˇnienie ok. 100 us
    ldi r20, 100
    L1:
    nop ; 1 cykl
    dec r20 ; 1 cykl
    brne l1 ; 2 cykle
    ; koniec pętli L1
    dec r21
    brne l0
    ; koniec pętli L0
    dec r22
    brne L
    ; koniec pętli L
    ret
    
    ; Tablica z kodami znaków
    znaki: .db 192,249,164,176,153,146,130,248,128,144,0
  • #2 8089831
    korrus666
    Poziom 40  
    Popełniasz błąd logiczny. Porównujesz zawartość tablicy do zera a przecież wyświetlane zero nie ma w tablicy wpisanej wartości zero a 192 jak sądzę. Możesz dopisać sobie na początku tablicy 0 i wtedy zadziała ale będziesz musiał przesunąć wskaźnik w starcie o jedną pozycję żeby wyświetlać o drugiego elementu w tablicy.
  • #3 8091177
    xantros
    Poziom 11  
    A poza tym wrzuć kod programu w znaczniki [ code ] bo zaraz któryś z bossów upomni się o to ;)
  • #4 8091739
    elektrokuba
    Poziom 12  
    Code poprawiony ;) - dzięki.

    A co do sugestii to chyba nie o to chodzi porównuje z zerem po to aby przy liczeniu w górę po dojściu do 9 "resetował" się i liczył znowu od zera po naciśnięciu kolejny raz plusa. Jeżeli porówam do 192 to dochodzi mi do 8 i wraca na zero. Samo liczenie w górę przebiega poprawnie odejmowanie przy wartości różnej od zera też, problem powstaje gdy jest zero (wartość 192) i nacisnę minus wtedy chyba wychodzi jakoś poza tablice bo odejmuje dalej stałą jeden a powinien się "przewinąć" na drugi koniec tablicy i z tamtąd zabrać daną.

    Miałem taki pomysł aby naciśnięcie plusa/minusa ustawiało bit jakiegoś rejestru i na podstawie tego bitu pamiętał by jaki przycisk był ostatnio wciśnięty i przy przejściu przez zero ładował by odpowiednie tablice danych i trzeba by było drugą w odwrotnej kolejności zrobić. Ale nie mam pomysłu jak to wykonać. Cały czas mi to nie działa. Jeszcze jakieś pomysły?
  • #5 8091764
    tadzik85
    Poziom 38  
    zmieniaj zawartość pewnego rejestru z zakresie 0-9 przyciskami (tu łatwo zrobić warunki początku i końca)
    do Z wstaw adres tablicy
    wyświetlaj daną z pod Z+rejestr
  • #6 8092089
    elektrokuba
    Poziom 12  
    A możesz wstawić kawałek kodu jak to ma wyglądać bo nie bardzo sobie to moge wyobrazić.
  • #7 8092091
    Dexter77
    Poziom 28  
    W definicji .db musi byc parzysta liczba bajtow. Kompilator nie wyrzuca Ci warninga/errora? Ty masz 11...
  • #8 8092162
    elektrokuba
    Poziom 12  
    Wyrzuca warning ale nic sobie z niego nie robiąc program kompiluje i chodzi w uC.
  • #9 8092185
    tadzik85
    Poziom 38  
    elektrokuba napisał:
    A możesz wstawić kawałek kodu jak to ma wyglądać bo nie bardzo sobie to moge wyobrazić.


    Sorki pomyliło mi się z '51 chodziło o rejestr Z np. post poprawiłem

    nie znam na tyle asemblera by ci gotowca napisać ale algorytm powinien być ci zrozumiały.
  • #10 8092251
    elektrokuba
    Poziom 12  
    Nie rozumiem tego:
    "wyświetlaj daną z pod Z+rejestr"
    tzn rozumie ale nie wiem jak to wykonać. Powiedz chociaż z jakich komend skorzystać to coś poszukam i pomyślę.
  • #11 8092440
    tadzik85
    Poziom 38  
    z pod adresu (Z+rejestr)
  • #12 8092465
    grysek
    Poziom 19  
    Poprostu, dodajesz do adresu tablicy tak jakby indeks liczby którą chcesz wyświetlić. Ten indeks będzie osobnym rejestrem czy też komórką w RAM-ie, a w rejestrze Z bedziesz miał adres pierwszego elementu w tej tablicy i teraz jak bedziesz chciał wyświetlić cyfrę 4 to wpiszesz sobie do rejestru indeks liczbę 4 i dodasz tylko do adresu tablicy (czyli Z + index).

    Co to ułatwia? Przede wszystkim mozesz sobie ułatwić samo zwiększanie i zmienjszanie bo użyjesz tylko inc i dec dla tegro rejestru indeks. I dodasz sobie warunek ze jesli zawartość bedzie równa 10 to rejestr jest czyszczony. No i też ułatwi Ci to jeśli byś chciał rozbudować program np o wyświetlanie np temperatury z czujnika bo mozesz wyswietlić dowolną cyfrę w każdym momencie a nie tylko pokolei 1,2,3.. itd :P

    Pozdrawiam
  • #14 8093488
    elektrokuba
    Poziom 12  
    Już rozumie! Dziękuję za wytłumaczenie. Nie wiedziałem nawet że tak można to rozwiązać. Sprawdziłem wasz pomysł i działa program cały jeszcze nie powstał ale wiem już którędy podążać.
    Jeszcze raz wielkie dzięki.
  • #15 8096087
    elektrokuba
    Poziom 12  
    Uwaga chwale się!
    Program działa jak należy bardzo wam dziękuję za pomoc i do napisania znowu bo pewnie się bede jeszcze odzywał.
    Trochę się z tym napałowałem bo pomysłów miałem 10 na sekunde ale w końcu sie udało a teraz jest banan od ucha do ucha :)
    Poniżej przesyłam program dla takich jak ja którzy próbują się uczyć asm i nie mogą znaleźć ambitniejszych pomocy w necie.

    .include "2313def.inc"
    #define acc r16
    .cseg
    .org 0x00
    
    ldi acc, 0b11111111 ; załaduj do r16 liczbę 255 (0xff)
    out DDRB, acc ; wpisanie do DDRB samych jedynek
    ; powoduje ustawienie pinów jako wyjście
    out PORTB, acc
    ldi acc, 0b1111100 ;
    out DDRD, acc ; piny D0 i D1 są ustawione jako wejścia
    ; pozostałe jako wyjścia
    ldi acc, 0b1110111
    out PORTD, acc ; włączony pierwszy wyświetlacz, wejścia
    ; podciągnięte do zasilania
    
    
    ldi acc, 127 ;
    out SPL, acc ; ustawienie wskaˇnika stosu na 127
    
    ldi r17, 0 ; zerowanie r17
    
    startp: ; start petli gdy liczymy w gore (przycisk+)
    ldi r16, 0 
    rjmp petla
    
    startm: ; start petli gdy liczymy w dol (przycisk-)
    ldi r16, 10
    rjmp petla
    
    petla:
    ldi ZH, high(znaki<<1) ; ladowanie tablicy
    ldi ZL, low(znaki<<1)
    sbis PIND, 0 ; gdy przycisk (+) jest set to pomiń następną
    inc r16 ; zwieksz r16
    
    sbis pind, 1 ; gdy przycisk (-) jest set to pomiń następną
    dec r16 ; zmniejsz r16
    
    cpi r16, 11 ; porownaj do 11
    breq startp ; jak rowne skacz do startp
    
    cpi r16, 255 ; porownaj do 255
    breq startm ; jak rowne to skacz do startm
    
    add ZL, r16 ; sumuj zl i r16
    add ZH, r17 ; sumuj zh i r17
    lpm ; laduj do r0
    mov r18, r0 ; kopiuj r0 do r18
    
    out portb, r18 ; wywal r18 na wyswietlacz
    
    ldi r19, 150 ; laduj dlugosc opoznienia do r19
    rcall waitms ; wywolaj opoznienie
    
    rjmp petla ; powrot do petla
    
    
    waitms:
    mov r22, r19 ; ustaw czas opóˇnienia
    ; powtórz n razy pętlę L,
    ; co da opóˇnienie ok. n * 1 ms
    L:
    ; powtórz 10 razy pętlę L0,
    ; co da opóˇnienie ok 1ms
    ldi r21, 10
    L0:
    ; powtórz 100 razy pętlę L1,
    ; co da opóˇnienie ok. 100 us
    ldi r20, 100
    L1:
    nop ; 1 cykl
    dec r20 ; 1 cykl
    brne l1 ; 2 cykle
    ; koniec pętli L1
    dec r21
    brne l0
    ; koniec pętli L0
    dec r22
    brne L
    ; koniec pętli L
    ret
    
    ; Tablica z kodami znaków
    znaki: .db 192,249,164,176,153,146,130,248,128,144,192
    


    Teraz pora na kolejny stopień w nauce...
  • #16 8096157
    Dexter77
    Poziom 28  
    
    add ZL, r16
    add ZH, r17
    lpm
    mov r18, r0 
    

    Ten kawalek jest bledny, powinienes uzyc adc ZH,r17. To ze Ci dziala to akurat przypadek ze tablica miesci sie w granicach 256 bajtow. Druga sprawa to niepotrzebnie robisz lpm a potem mov. Mozesz to zrobic w jednej instrukcji tak jak pisalem wczesniej lpm r18,Z.

    Druga sprawa to piszesz chaotycznie i Twoj kod jest nieczytelny. Uzywaj wciec, nazywaj jakos rejestry zeby wiedziec do czego sluzy rejestr, zmienna, stala...
  • #17 8096352
    elektrokuba
    Poziom 12  
    W attiny2313 chyba nie można w taki sposób:
    lpm r18,Z
    Wywala taki błąd przy kompilacji:
    error: lpm r18, z: Unsupported instruction on AT90S2313

    A co do reszty uwag przyjmuje je na klate. Na swoje usprawiedliwienie mam jedynie to ze to dopiero trzeci program napisany w całości przeze mnie - więc raczkuje jeszcze w temacie.
    Ale bede miał je na uwadze.
  • #18 8096417
    Dexter77
    Poziom 28  
    Ach faktycznie, to staruszek 2313. No to ok, ja sie zagalopowalem. Nie zmienia to faktu ze blad z add ZH jest. Jesli dopiszesz kawalek kodu i tablica zmieni polozenie to mozesz sie zdziwic ;) Domyslasz sie dlaczego?
  • #19 8096678
    elektrokuba
    Poziom 12  
    Na temat adc wiem tyle co z książki wyczytałem czyli, ze dodaje 1 do wartości gdy znacznik przeniesienia C jest ustawiony. Ale jeszcze nie spotkałem się z tym w realnym programie więc nie bardzo wiem z czym to ugryźć. Jak masz czas i chęć to jakoś łopatologicznie wytłumaczyć to chętnie się dowiem kolejnej nowej rzeczy.
  • #20 8096736
    Dexter77
    Poziom 28  
    No wlasnie. Chodzi o ten znacznik. Gdy pierwszy element tablicy wypadnie zalozmy pod adresem 250 a Ty zechcesz pobrac 8 element to bedzie on pod adresem 258. Dodajac do ZL 8 spowodujesz ze rejestr ten przepelni sie i bedzie mial wartosc 0x02h. Zostanie ustawiony znacznik C ze rejestr sie przepelnil. Jezeli dokonasz normalnego dodawania instrukcja add starsza polowke adresu (czyli ZH) to tak naprawde nie zmienisz jego wartosci gdyz w r17 masz 0. wobec tego pelny adres 16 bitowy bedzie wygladal 0x0002h czyli pobierzesz jakis bajt spod adresu 2 zamist 258. Natomiast jezeli uwzglednisz znacznik C i go dodasz to do ZH dodasz 1 i caly adres po zlozeniu bedzie wygladal 0x0102h czyli spodziewane 258.

    Sa to podstawy arytmetyki 16 bitowej przy opercjach na danych 8 bitowych. Musisz wtedy zwracac uwage na znacznik C i tak naprawde nawet na 8 bitowym uC mozesz dokonywac operacji nawet 64 bitowych i jakichkolwiek innych. Bedzie to tylko bardziej pamieciozerne i bardziej czasochlonne.
  • #21 8096810
    elektrokuba
    Poziom 12  
    Wydaje mi się ze rozumie o co Ci chodzi :) Nie wygląda mi to na skomplikowane sprawy więc pewnie za niedługo i na tym będę się skupiał.
    Tylko jeszcze jedno może banalne pytanie ale:
    jak dodać znacznik? Gdzie on jest i co jeszcze można z nim zrobić. Wyczytałem ze tych znaczników w uC jest kilka odpowiedzialnych za różne rzeczy wiem jak je ustawiać i kasować ale dodawać?

    A propos lpm r18,Z to za niedługo planuje się poćwiczyć na ATMEGA16 więc sprawdzę to co mówisz.
  • #22 8096883
    Dexter77
    Poziom 28  
    Znacznik C automatycznie uwzglednia i dodaje wlasnie instrukcja adc (add with carry) Jezeli C=1 (poprzednia instrukcja wywolala przepelnienie) to jest to dodawane jezeli C=0 (nie bylo przepelnienia) to nic nie jest dodawane. W AVR jest kilka znacznikow i sa instrukcje ktore je wykorzystuja. Najbardziej chyba korzysta sie ze znacznika N (zero) i np. instrukcje breq, brne, tst z niego korzystaja. Ale to juz zaglebianie sie w szczegoly konstrukcji rdzenia, na tym etapie to tylko by Ci namieszalo w glowie :)
  • #23 8097159
    elektrokuba
    Poziom 12  
    OK. Bardzo Ci dziękuje za wyjaśnienia i poświęcony czas.
  • #24 8396908
    elektrokuba
    Poziom 12  
    Witam ponownie Szanowne grono.
    Miałem krótką przerwę ale znowu mam trochę wolnego i wracam do zabaw z asm z nową ulepszoną płytką testową i od razu pojawiają się nowe pytania. Kto mi może w jasny sposób wytłumaczyć bądź podać BARDZO łopatologicznego linka do obsługi adc? Chcę zacząć od czegoś prostego i potem się dopiero wgłębiać. Na początek może w zależności od położenia potencjometru niech mi się różne diody na portach PB pojawiają. A może ktoś ma gdzieś taki program zachomikowany. Będę bardzo wdzięczny.
    Aha i zmieniłem procka na M16.
    Pozdrawiam
    Kuba
REKLAMA