Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

Asembler 89c2051, int0, Led

ekspert100 20 Lip 2006 21:15 1902 10
  • #1 20 Lip 2006 21:15
    ekspert100
    Poziom 16  

    Witam !!!
    pytanie dotyczy w zasadzie szkieletu programu w .asm
    chcę dokonywać pomiaru i wyświetlać jego wynik na led7seg
    czy zasadne jest wyswietlanie wyniku pomiaru jako część
    główna programu,
    a pomiar wykonywany przy zgłoszeniu przerwania

    prosze o opinie i uwagi, pozdrawiam....

    0 10
  • #2 20 Lip 2006 21:31
    vedy1
    Poziom 15  

    Witam!!
    Fajnie by było żebyś napisał ile razy ma trwać przerwanie (m.in od tego zależy czybkośc używanego procka) i na jakim wyświetlaczu chcesz wyświetlać.
    Ale zazwyczaj tak się robi jak napisałeś a po przerwaniu liczysz czy ci starczy czasu na wyświetlenie.

    Pozdrawiam

    0
  • #3 20 Lip 2006 21:49
    maciek_slon
    Poziom 29  

    a może by tak jakiś zatrzask przetrzymujący dla każdego segmentu aktualnie wyświetlaną liczbę? i wtedy zmieniałbyś wyświetlany znak tylko po przerwaniu.

    0
  • #4 21 Lip 2006 12:26
    ekspert100
    Poziom 16  

    wyswietlacz led7seg sterowany cd4543 podłączony do 89c2051
    p1.4-A
    p1.5-B
    p1.6-C
    p1.7-D

    p1.0-CYFRA1
    p1.1-CYFRA2
    p1.2-CYFRA3

    0
  • Pomocny post
    #5 21 Lip 2006 13:09
    Dyrek
    Poziom 16  

    Ja w tego typu wyświetlanie zaprzęgam któryś licznik przepełniający się 100 do 200 razy na sekundę (w zależności od ilości segmentów) i tam przy każdym przepełnieniu aktywuje kolejny segment wyświetlając na niego daną ze zdefiniowanego wcześniej rejestru. Tak więc po dokonaniu pomiaru aktualizujesz tylko odpowiednie rejestry z których dane są wyświetlane w przerwaniu od licznika.

    0
  • Pomocny post
    #6 21 Lip 2006 18:46
    eskwadrat
    Poziom 11  

    Jak chcesz miec porzadek w programie i jesli procesor ma robić tylko tyle ile musi to :

    po 1. Powinienes zdefiniowac w RAM bufor wartosci MIERZONEJ

    po 2. j/w dodatkowo bufor wartosci WYSWIETLANEJ (wyswietlacza)

    po 3. W przerwaniu (timera) powinna znalezc sie JEDYNIE obsluga wyswietlania poszczególnych cyfr (pozycji) z bufora WYSWIETLANIA - dotyczy to tylko wyswietlacza mulsipleksowanego oczywiscie

    po 4. Konwersja wartości mieszonej na wyświetlaną i ładowanie jej do
    bufora WYSWIETLANIA powinno odbywac się w petli głownej ale tylko
    jesli wartosc zmierzona jest różna od wartości zmierzonej poprzednio

    po 5. Samo wywołanie pomiaru wartości do zmierzenia najlepiej umieścic w petli głównej programu, i robić to tak czesto jak ci to jest potrzebne. Z twojego opisu rozumiem, ze wartośc ta bedzie jedynie wyświetlana, więc w takim przypadku wystarcza pomiary 2 do 4 razy na sek. (podobnie jak w multimetrach).

    po 6. Jesli bedziesz robil jak napisalem w pkt.5 to w przerwaniu timera musisz tez umiescic jakis dodatkowy licznik (bajt) albo wykorzystać jakąś inną istniejąca zmienną ktora bedzie ci "taktowała" te ćwiartki lub połóki sekund.

    po 7. Jesli po pomiarze masz możliwośc wygenerowania przerwania (bo np. przetwornik generuje przerwanie) to jedyne co powinienes zrobic w obsłudze takiego przerwania, to zapisać wartośc zmierzoną do bufora wartośc MIERZONEJ i ewentualnie przygotować przetwornik do kolejnego pomiaru, chociaż to ostatnie możesz zrobić w opisanym pkt.5 tuż przed wykonaniem pomiaru.

    Chodzi o to żeby procesy wyświetlania i pomiarowy "chodziły" niezależnie. Wtedy procek się tym nie zmęczy "pustym" wyświetlaniem tej samej wartości a i całośc będzie wyglądać czytelnie i przejrzyście. Jak powiedziałem jedyne co powinno łączyć te dwa procesy to moment opisany w pkt.4

    Pozdr :D

    0
  • #7 24 Lip 2006 21:45
    ekspert100
    Poziom 16  

    Witam

    Bardzo sensowne jest to co napisał eskwadrat, bo tu mam już napisany
    programik który robi pomiar ale wartość tego pomiary odrazu wyrzuca
    na port co mozna definiować jako formę wyswietlania wartości jednak w realu to za mało wiec spróbuję sie zastosować do w/w uwag

    pozdrawiam !!!

    KOD:

    $MOD51 ;istotne dla kompilatora asm51 @@@@@

    ; jesli p3.4 w stanie L to wejscie --[____________]--
    ; jesli p3.5 w stanie L to offset -\__/-
    ; jesli p3.7 w kontrolka

    sed EQU 30H ; deklaracje komórek zmienne "set"
    des EQU 32H ; deklaracje komórek zmienne "des"
    jed EQU 34H ; deklaracje komórek zmienne "jed"

    RB0R0 EQU 44H ; deklaracje komórek zmienne 7seg "jed"
    RB0R1 EQU 46H ; deklaracje komórek zmienne 7seg "des"
    RB0R2 EQU 48H ; deklaracje komórek zmienne 7seg "set"


    sek EQU 50H ; deklaracje komórek zmienne "sek"
    ms EQU 52H ; deklaracje komórek zmienne "10ms"


    org 0000h ; etykieta początek programu "pierwszy raz"
    sjmp pre_start

    org 000Bh ;skok jak pojawi sie przerwanie od t0
    sjmp przerwanie


    pre_start:

    mov sek,#0 ; zeruj zmienna sek ( liczba sekund )
    mov ms,#0 ; zeruj zmienna ms ( liczba milisekund )
    mov p1,#0 ; gasimy wszystkie ledy
    ;mov sed,#0 ; zeruj zmienna sek
    ;mov des,#0 ; zeruj zmienna des
    ;mov jed,#0 ; zeruj zmienna jed


    ; set Konfiguracja t0 ---------------------------------#

    mov tmod,#00000001b ; timer 0 w tryb drugi ( 16 bit ) jako czasomierz M0
    ;mov tcon,#00000001b ; ustawienie Timerów IT0 -\__

    mov th0,#0D8h ; zaladowanie licznika th
    mov tl0,#0EFh ; zaladowanie licznika tl
    mov IE,#10000010b ; uaktywniamy przerwanie EA + ET0 od t0
    setb tr0 ; i na koniec start licznika w TCON


    prog_glowny: ; program główny
    setb p3.5 ; klawisz 0
    jb p3.5,prog_glowny ; jesli p3.5 w stanie H to skocz do
    mov sek,#0 ; zeruj zmienna sek ( liczba sekund )
    ;mov p1,sek ; wyzeruj także port p1
    cpl p3.7 ; neguj także port p3.7
    sjmp prog_glowny ;skocz do


    przerwanie: ; set Konfiguracja t0 ---------------------------------#

    mov th0,#0D8h ; zaladowanie licznika th
    mov tl0,#0EFh ; zaladowanie licznika tl
    push psw ;psw na stos
    push acc ;acc na stos


    licz:

    inc ms ;+1 zmienna 10ms
    mov a,ms ;zmienna do a
    cjne a,#100,koniec_t0 ;jesli A rozne od 100 to skok
    mov ms,#0 ;zerowanie ms
    setb p3.4 ;lub clr sym ustaw p3.4 w stan wysoki H "wej imp"+++++

    jb p3.4, koniec_t0 ;jak p3.4 w stanie H to skok do
    inc sek ;+1 sek dla L
    mov a,sek
    swap a


    mov p1,a ;przepisz zmienna na port p1
    cpl p3.7



    koniec_t0: ;koniec przerwania
    pop acc ;zdejmij ze stosu acc
    pop psw ;zdejmij ze stosu psw
    reti
    end

    0
  • Pomocny post
    #8 25 Lip 2006 02:12
    eskwadrat
    Poziom 11  

    Kilka pytań i spraw, ktore być mogą okazać się pomocne:

    Z wartości przeładowania T0 (D8EF) i faktu że przerwanie chodzi 100 razy/sek domyślam sie ze używasz kwarcu 12MHz . Jednak jesli ma to byc równo 100Hz to zauważ że podana u ciebie wartosć początkowa jest za mała o 1, bo powinno byc:

    T0pocz = FFFFh - (Fxtal / 12 / Fto) + 1 = D8F0h (a nie D8EFh)

    gdzie:
    Fxtal = 12000000 (12MHz)
    Fto = 100 (czestotliwosc przerwania T0)

    Jesli zapomnisz o tej "+1" na koncu rownania to jesli zrobisz na tym zegarek to bedzie sie on poźnił. Zauważ przecież, że przerwanie od timera wywoływane jest kiedy wartośc licznika T0 zmienia się z FFFF na 0, a nie kiedy licznik osiąga FFFFh.

    I jeszcze jedna pomocna sprawa. Jesli w przyszłości zaplanujesz używać przerwania timera do odmierzania czasu (np. do realizacji zegarka albo stopera, gdzie jest wazna doklaność) to warto dobrac tak kwarc aby wartosc przeladowania licznika TL0 była równa 0. Powód jest następujący. W przerwaniu T0 użyłeś następujących instrukcji przeładowania licznika T0:

    mov th0,#0D8h ; zaladowanie licznika th
    mov tl0,#0EFh ; zaladowanie licznika tl

    Wszystko niby jest ok, ale zwróć uwagę, że zanim wykonana zostanie pierwsza z w/w instrukcja, licznik T0 timera nie będzie już miał wartości zerowej, bo upłynie nieco czasu od wykonania ostatniej instrukcji w petli głownej do przyjęcia przerwania, w trakcie którego licznik T0 "zliczy" juz coś. Czas ten może być jeszcze dłuższy, jesli w programie używasz przerwania o wyższym priorytecie niż T0, np. przerwań zewnętrznych.

    Wtedy w najgorszym przypadku możesz "spoźnić się" z przeładowaniem licznika T0 nawet o kilkaset cyklów zegarowych procesora w zależności od czasu trwania obsługi przerwania o wyższym od T0 priorytecie. Wtedy twoje przerwanie "zegarowe" przeładowane w w/w sposób spowoduje że twój zegar będzie się stale późnił, bo przeładowanie nastąpi w momencie kiedy licznik T0 zliczy już jakąś wartośc od momentu jego przeładowania.

    Zauważ, że jeśli dobierzesz wartośc kwarcu w taki sposób że wartoścć przeładowania będzie miała młodszy bajt = 0 (np. dla TL0), to możesz się "spóźnić" z przeładowaniem w przerwaniu nawet o ponad 250 zliczeń T0, gdyż w przerwaniu będzies musiał wtedy wykonać tylko jedną instrukcję:

    mov th0,#0D8h ; zaladowanie licznika th

    TL0 nie wymaga już korekty, gdyż po pierwsze obliczona wartość jest równa 0, a po drugie timer TL0 już "zliczył coś" i przeładowanie nie uwzględni tego faktu a jedynie go "zaśmieci".

    W literaturze często podaje się inny sposób na w/w problem poprzez zastosowanie zamiast instrukcji "mov" instrukcji "orl", np.:

    orl tl0,#0D8h ; zaladowanie licznika tl

    ale zauważ że będzie to poprawne tylko jeśli "zdążysz" z przeładowaniem z 15-tu pierwszych taktach licznika (timera) T0. Podobnie sprawa wygląda z licznikiem T1. Dlatego zawsze jeśli tylko się da należy stosować zasadę nie przełądowywania wartości TL0. Wtedy wszelkie niedokładności pracy twojego zegarka/stopera będziesz mógł "zwalić" jedynie na zastosowany kwarc. :idea:

    I tak dla twojego przykładu, kiedy chcesz aby przerwanie chodziło 100 razy/sek, najlepiej nadaje się kwarc 11,0592MHz, bowiem wtedy wartość początkowa przeładowania timera T0 (przy założeniu że fT0 = 100Hz) będzie równa:

    T0pocz = FFFFh - (11059200 / 12 / 100 ) + 1 = DC00h

    wtedy w przerwaniu T0 wystarczy instrukcja:

    mov th0,#0DCh ; zaladowanie licznika th

    Mam też dodatkowe pytania dot. podanego listingu:

    - do czego podpięte sa P3.4 i P3.7 (bo P3.5 jak widzę to zewn.klawisz) ?
    - z jakiego powodu uzyłeś 4543 ? (czy dlatego że mimałeś displeje z wspólną katodą, czy z jakiegoś innego ?)
    - czy ten program działa u ciebie ?

    Pozdrawiam :D

    0
  • #9 25 Lip 2006 17:12
    ekspert100
    Poziom 16  

    Witam !!!

    - P3.4 - kolektor tranzystora NPN
    - P3.7 - kontrolka led
    - P3.5 - klawisz zerowania komórki
    - z jakiego powodu uzyłeś 4543 ?
    - chciałem opanować ten temat na początek

    - ten program działa u mnie prawidłowo na symulacji programowej
    i w układzie równiez .

    - jeszcze sory za pytanie -jakim programem najwygodniej pisać czy rysować aloogarytm(logika prog)

    Pozdrawiam

    0
  • Pomocny post
    #10 25 Lip 2006 18:15
    eskwadrat
    Poziom 11  

    Witaj,
    W moich ostatnich pytaniach bardziej chodziło mi o to - jaką "funkcję" w układzie pełnią P3.4 i P3.7, a nie do czego są podłączone. Choć oczywiście i ta ostatnia informacja też jest pomocna w ocenie i pomocy dot. twojego układu.

    Na początku wątku napisałeś też że:
    > chcę dokonywać pomiaru i wyświetlać jego wynik na led7seg

    Czy możesz powiedzieć co i jak "mierzysz" oraz w jaki sposób odczytujesz ten wynik pomiaru ? Albo jak masz zamiar to robić :?:
    Bo w treści programu nie bardzo to widać.

    Co do programu to mam watpliwosci czy bedzie on poprawnie realizowal twoje zadanie w rzeczywistosci, bo dzialal bedzie na pewno. Kilka spraw dot. wyswietlania wyniku na 4543 podpietym do P1:

    - liczysz SEK w kodzie binarnym (czyli cyfry do 16-tu) i masz zamiar wysłać młodsze 4 bity SEK na piny DCBA ukladu 4543. Czy wiesz, ze na displeju nie zobaczysz nic po cyfrze 9 ? cyfry 10-15 (A-F) w tym dekoderze nie są wyświetlane w ogóle. Czy w ogóle chcesz liczyć i wyświetlać sekundy w kodzie szesnastkowym czy dziesiętnie ? Jesli szesnastkowo, to masz zły dekoder (o ile dekoder 4543 jest w ogole potrzebny), jesli dziesiętnie to liczenie SEK jest niestety błędne.

    - 4 starsze bity zmiennej SEK po prostu wysyłasz także na port P1 na piny które sa podpięte do sygnałów "CYFRA1, 2 i 3". Rozumiem że miałeś na mysli multipleksowanie wyniku i że twój displej ma mieć 3 pozycje. Czy tak :?: Jesli tak, to wyświetlacz nie będzie wyświetlał wyniku poprawnie, bo wpisywane na piny CYFRA1,2 i 3 stany logiczne nie będą poprawne, będą to po prostu wartości odpowiadające aktualnej wartości zmiennej sekund a dokładnie jej 4 starszych bitów. Zauważ np. że kiedy licznik sekund dojdzie do 112 (0111000 binarnie), to twój wyświetlacz pokaże wartośc "000", bo wszystkie 3 pozycje będą aktywne (zapalone) a na wejściach DCBA dekodera bedzie zero. Po prostu zabrakło w programie multipleksowania.

    Ogólnie można powiedzieć, że twój 3-pozycyjny displej będzie wyświetlał podczas liczenia sekund tę samą cyfrę w danym momencie ale na różnych jego pozycjach i to tylko jeśli licznik SEK będzie w zakresie <16...127> oraz <144...255>. Zastanów się dlaczego :?:

    Chyba nie o to chodzi w projekcie. Napisz do ilu chcesz liczyć i jak. Jeśli dziesiętnie na pojedynczym bajcie (sekund) to zauważ, że wystarczą ci 2 pozycje wyświetlacza, bo przy liczeniu w kodzie BCD (dziesiętnym) w jednym bajcie zmieścisz liczby z zakresu 0-99.

    Jesli zaś chcesz liczyc binarnie (zakres ba bajcie 0-255) to faktycznie trzeba 3 pozycje displeja, ale wtedy bedziesz musial napisac funkcje konwersji liczby binarnej (2-pozycyjnej) na dziesietna (3-pozycyjna). Oczywiscie nie jest to trudne, ale czy o to ci chodzi ? Daj, znać o co w projekcie chodzi a pomoge ci poprawić twój program. Pozdrawiam :D

    0
  • #11 25 Lip 2006 18:29
    ekspert100
    Poziom 16  

    kod:

    $MOD51 ;istotne dla kompilatora asm51 @@@@@

    ; jesli p3.4 w stanie L to wejscie --[____________]--
    ; jesli p3.5 w stanie L to offset -\__/-
    ; jesli p3.7 w kontrolka

    sed EQU 30H ; deklaracje komórek zmienne "set"
    des EQU 32H ; deklaracje komórek zmienne "des"
    jed EQU 34H ; deklaracje komórek zmienne "jed"

    RB0R0 EQU 44H ; deklaracje komórek zmienne 7seg "jed"
    RB0R1 EQU 46H ; deklaracje komórek zmienne 7seg "des"
    RB0R2 EQU 48H ; deklaracje komórek zmienne 7seg "set"


    sek EQU 50H ; deklaracje komórek zmienne "sek"
    ms EQU 52H ; deklaracje komórek zmienne "10ms"


    org 0000h ; etykieta początek programu "pierwszy raz"
    sjmp pre_start

    org 000Bh ;skok jak pojawi sie przerwanie od t0
    sjmp przerwanie


    pre_start:

    mov sek,#0 ; zeruj zmienna sek ( liczba sekund )
    mov ms,#0 ; zeruj zmienna ms ( liczba milisekund )
    mov p1,#0 ; gasimy wszystkie ledy
    ;mov sed,#0 ; zeruj zmienna sek
    ;mov des,#0 ; zeruj zmienna des
    ;mov jed,#0 ; zeruj zmienna jed




    przerwanie: ; set Konfiguracja t0 ---------------------------------#

    mov tmod,#00000001b ; timer 0 w tryb drugi ( 16 bit ) jako czasomierz M0
    mov tcon,#00000001b ; ustawienie Timerów IT0 -\__

    mov th0,#0D8h ; zaladowanie licznika th
    mov tl0,#0EFh ; zaladowanie licznika tl
    push psw ;psw na stos
    push acc ;acc na stos

    mov IE,#10000010b ; uaktywniamy przerwanie EA + ET0 od t0
    setb tr0 ; i na koniec start licznika w TCON


    licz:

    inc ms ;+1 zmienna 10ms
    mov a,ms ;zmienna do a
    cjne a,#100,koniec_t0 ;jesli A rozne od 100 to skok
    mov ms,#0 ;zerowanie ms
    setb p3.4 ;ustaw p3.0 w stan wysoki H "wej imp"+++++

    jb p3.4, koniec_t0 ;jak p3.4 w stanie H to skok do
    inc sek ;+1 sek dla L
    ;mov p2,sek ;przepisz zmienna na port p1
    cpl p3.7
    clr a
    clr c





    bindec: ;Zamień cyfry bin na dec --------------------------------#

    mov a,sek
    mov b,#100
    div ab
    mov sed,a

    mov a,b
    mov b,#10
    div ab
    mov des,a
    mov jed,b
    clr a
    clr c

    BCDSEG: ;Zamień cyfry na odpowiadające im kody BCD--------------#

    MOV A , sed
    LCALL KOD7
    MOV RB0R2 , A


    MOV A , des
    LCALL KOD7
    MOV RB0R1 , A


    MOV A , jed
    LCALL KOD7
    MOV RB0R0 , A


    koniec_t0: ;koniec przerwania
    pop acc ;zdejmij ze stosu acc
    pop psw ;zdejmij ze stosu psw




    reti ; instrukcja zakończ przerwanie bo pujdzie w "maliny"


    prog_glowny: ; program główny
    setb p3.5 ; klawisz 0
    jb p3.5,bindec ; jesli p3.5 w stanie H to skocz do
    mov sek,#0 ; zeruj zmienna sek ( liczba sekund )
    ;mov p1,sek ; wyzeruj także port p1
    cpl p3.7 ; neguj także port p3.7
    clr a
    clr c

    sjmp prog_glowny ;skocz do



    WYSWART:
    ;-----------------------------------------------#
    ;Cyfry są w komórkach RB0R0, RB0R1, RB0R2,

    MOV P1 , RB0R0 ;1 JED
    CLR P1.2
    MOV B , #30
    DJNZ B , $
    SETB P1.2
    MOV P1 , RB0R1 ;2 DES
    CLR P1.1
    MOV B , #30
    DJNZ B , $
    SETB P1.1
    MOV P1 , RB0R2 ;3 SED
    CLR P1.0
    MOV B , #30
    DJNZ B , $
    SETB P1.0


    AJMP WYSWART

    KOD7:
    ANL A,#0FH ;tabela kodów 0..15
    INC A ;pomiń rozkaz RET
    MOVC A,@A+PC ;pobierz kod
    RET

    KOD7SEG: ;Zadeklarowana tablica z kodami dla 74HCT4543

    ;ORGANIZACJA PINÓW NA 89C2051
    ;P1.4-A ;PINY 0123=1 LOG
    ;P1.5-B
    ;P1.6-C
    ;P1.7-D


    ;ORG PIN P0. 76543210
    DB 00FH ;kod znaku 0 ;00001111;015
    DB 01FH ;kod znaku 1 ;00011111;031
    DB 02FH ;kod znaku 2 ;00101111;047
    DB 03FH ;kod znaku 3 ;00111111;063
    DB 04FH ;kod znaku 4 ;01001111;079
    DB 05FH ;kod znaku 5 ;01011111;095
    DB 06FH ;kod znaku 6 ;01101111;111
    DB 07FH ;kod znaku 7 ;01111111;127
    DB 08FH ;kod znaku 8 ;10001111;143
    DB 09FH ;kod znaku 9 ;10011111;159

    end

    Tablica znaków jest ok natomiast nie bardzo moge sobie poradzić
    ze sklejeniem tego w całość.ale program się blokuje.

    Dodano po 7 [minuty]:

    Witam !!!

    Układ ma mierzyć czas wysterowania tranzystora t1= P3.4
    wynik pomiaru do komórki sek ,
    zamiana bin na dec
    każda cyfra do swojej komórki
    i na 4543 i na wyświelacz
    stan niski na porcie p1.0;p1.1;p1.2 jest stanem atywnym
    dla poszczególnych cyfr.

    0