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.

Jak zmodyfikować ten program?

Marek Glogowski 21 Mar 2012 16:24 1554 6
  • #1 21 Mar 2012 16:24
    Marek Glogowski
    Poziom 7  

    MOV TMOD, #02H;
    MOV TH0, #0FAH;
    MOV TL0, #0E8H;
    CPL P1.0;
    SETB TR0;
    CZEKAJ_OVF1:
    JNB TF0, CZEKAJ_OVF1;
    CPL P1.0;
    MOV TH0, #0E8H;
    CLR TF0;
    CZEKAJ_OVF2:
    JNB TF0, CZEKAJ_OVF2;
    CPL P1.0;
    MOV TH0, #0FAH;
    CLR TF0;
    JMP CZEKAJ_OVF1;

    Jestem studentem i potrzebuje pomocy z powyższym programem. Przedstawia on generację przebiegu PWM o okresie 30 mikro sekund i współczynniku wypełnienia 20% na P1.0 z wykorzystaniem timer0 w trybie odpytywania programowego.
    Problem jest taki że czas przez w którym dioda ma być zapalona i zgaszone nie zgadzają mi się z założonymi przez zadanie czasami. czas zgaszenia 6 mikrosekund jest wydłużony o 1 mikro sekundę a czas zapalenia 24 mikrosekundy jest wydłużony o 3 mikro sekundy. Starałem sie zmieniac wartości ze wzgledu na to że każda wykonywana instrukcja wykonywana jest w pewnym czasie który generuje straty, ale nie pomogło. Jeszce jedno pytanie.... czym różni się tryb odpytywania programowego od trybu przerwań? Bardzo proszę o pomoc i jak najszybszą odpowiedź. Pozdrawiam

    0 6
  • #2 21 Mar 2012 16:48
    tehaceole

    Poziom 28  

    "Odpytywanie programowe" w Twoim konkretnym przypadku to typowy przykład programowania liniowego, w którym przetwarzanie wykonywania dalszych instrukcji blokowane jest na czas spełnienia jakiegoś warunku. Zauważ, że

    Kod: C
    Zaloguj się, aby zobaczyć kod

    oraz
    Kod: C
    Zaloguj się, aby zobaczyć kod

    powodują skok do "samych siebie" tak długo, jak flaga przerwania od przepełnienia timera zostaje wyzerowana. Po wystąpieniu przepełnienia flaga ta jest ustawiana, program przechodzi dalej, zmieniasz stan portu na przeciwny, ładujesz timer nową wartością opóźnienia, zerujesz flagę i znów czekasz aż wystąpi kolejne przepełnienie timera ustawiające flagę. I tak cały czas w kółko :)
    Gdybyś zastosował przerwanie od przepełnienia timera, to:
    - flaga byłaby kasowana automatycznie po wyjściu z procedury przerwania instrukcją reti
    - program główny nie byłby blokowany oczekiwaniem na wystąpienie flagi przepełnienia
    W Twoim przypadku wprowadzenie dalszych instrukcji obsługujących coś innego całkowicie zniszczy "działanie" tego dziwoląga poprzez wprowadzenie dodatkowych opóźnień potrzebnych na wykonanie kolejnych instrukcji.
    Jaką częstotliwością masz taktowany procesor? Jaki to typ procesora?
    Sądząc po założeniach projektowych (częstotliwość PWM) celem ćwiczenia było właśnie zauważenie wpływu czasu wykonywania poszczególnych instrukcji na działanie programu.

    Czy rejestr roboczy licznika jest 16-to bitowy? TH0 i TL0 na to właśnie wskazują. Na początku programu ładujesz rejestr wartościami
    Kod: C
    Zaloguj się, aby zobaczyć kod

    a później aktualizujesz już tylko jego starszą część:
    Kod: C
    Zaloguj się, aby zobaczyć kod

    Kod: C
    Zaloguj się, aby zobaczyć kod

    IMHO uparcie ładujesz rejestr 8-io bitowy (połowka rejestru Tx0) wartościami 16-to bitowymi. Nawet jeżeli się mylę co do typu rejestru (i okaże się, że jest to rejestr 32 bitowy) to i tak w dalszym ciągu w swoim programie ładujesz tylko jego starszą część.

    0
  • #3 21 Mar 2012 20:28
    Marek Glogowski
    Poziom 7  

    MOV TMOD, #02H;
    MOV TH0, #0FAH;
    NOP;
    CPL P1.0;
    MOV TL0, #0EBH;
    SETB TR0;
    CZEKAJ_OVF1:
    JNB TF0, CZEKAJ_OVF1;
    CPL P1.0;
    MOV TH0, #0E8H;
    CLR TF0;
    CZEKAJ_OVF2:
    JNB TF0, CZEKAJ_OVF2;
    CPL P1.0;
    MOV TH0, #0FAH;
    MOV TL0, #0ECH;
    CLR TF0;
    JMP CZEKAJ_OVF1;


    Poprawiłem program. Ogólnym zadaniem programu ma być gaszenie diody przez 6 mkro sekund i zapalanie jej przez 24 mikrosekundy. Zadanie każe mi zrobić ten program w trybie odpytywania programowego. Mikrokontroler 8051 częstotliwość taktowania 12MHz. Sprawa jest taka, że ten program ściągnąłem jako gortowy i szerze mówiąc nie mam pojęci jaką funkcę w tym programie spęłnia ustawianie wartości TH0. po poprawieniu tego programu w ten sposób jak powyżej czas zapalenia i gaszenia diody jest zgodny z założeniami. W ciągu 30 mikrosekund dioda jest zgaszone przez 6 miktrosekund a zapalona przez 24 mikrosekundy. Program działa poprawie ale sam do końca nie wiem w jaki konkretnie sposób. Wg. mnie program powinien działać bez ustalania wartości TH0 jeddnak gdy usówam jego wartości program przestaje działać jak nalezy.

    Bardzo dziękuję za odpowiedź na moje poprzednie pytanie i bardzo prosze o pomoc w kolejnym.

    Pozdrawiam.

    0
  • #4 22 Mar 2012 07:38
    tehaceole

    Poziom 28  

    Ostatni raz '51 (konkretnie at89c2051) programowałem jakieś 7 lat temu i nie pamiętam już nazw rejestrów itp. Twój program działa tak:

    Marek Glogowski napisał:

    MOV TMOD, #02H; //ustawiasz timer w odpowiedni typ pracy
    MOV TH0, #0FAH; //ladujesz starsza czesz rejestru timera wartoscią początkową
    NOP; //nie robisz nic
    CPL P1.0; //zmieniasz stan pinu na przeciwny
    MOV TL0, #0EBH; // ladujesz mlodszą czesz rejestru timera wartoscią początkową
    SETB TR0; //uruchamiasz timer
    CZEKAJ_OVF1: //etykieta
    JNB TF0, CZEKAJ_OVF1; //"skaczesz" w tym miejscu "sam do siebie" tak długo jak bit flagi przepełnienia timera jest wyzerowany, jezeli ustawi sie na 1 to idziesz dalej
    CPL P1.0; //zmieniasz stan bitu na przeciwny
    MOV TH0, #0E8H; // ladujesz starsza czesc rejestru timera wartoscią początkową
    CLR TF0; //zerujesz flagę przepełnienia
    CZEKAJ_OVF2: //etykieta
    JNB TF0, CZEKAJ_OVF2; //"skaczesz" w tym miejscu "sam do siebie" tak długo jak bit flagi przepełnienia timera jest wyzerowany, jezeli ustawi sie na 1 to idziesz dalej
    CPL P1.0; //zmieniasz stan bitu na przeciwny
    MOV TH0, #0FAH; // ladujesz starsza czesc rejestru timera wartoscią początkową
    MOV TL0, #0ECH; // ladujesz mlodsza czesc rejestru timera wartoscią początkową
    CLR TF0; //zerujesz flagę przepełnienia
    JMP CZEKAJ_OVF1; //skaczesz znow na poczatek programu


    Timer zlicza od 0 do 65535 (o ile dobrze pamiętam to zliczanie jest właśnie w górę). Wartość 65535 * czas trwania jednego cyklu = maksymalne opóźnienie jakie można zrealizować na nim sprzętowo. Jeżeli do rejestru roboczego wpisujesz jakąś wartość początkową np 0xFFF0 to timer zlicza od tej wartości w górę (w tym przypadku co 16 cykli wystąpi przepełnienie). Nie pamiętam już czy po przepelnieniu rejestr był zerowany, czy pozostawał z wartością max. Nie zmienia to faktu, że każdorazowo musisz go załadować na nowo oczekiwaną przez Ciebie wartością opóźnienia, inaczej program nie będzie działać prawidłowo (co sam już dostrzegłeś :) ).
    Wydaje mi się, że cały czas uparcie źle wpisujesz wartości początkowe do tych rejestrów:
    - masz rejestr 8io bitowy
    - wpiszujesz do niego wartość 16to bitową
    otrzymujesz w rejestrze tylko jej "młodszą" część czyli np. zamiast 0xFFAA w rejestrze będziesz miał 0xAA. Zamiast:
    Kod: C
    Zaloguj się, aby zobaczyć kod

    otrzymasz w TH0 wartość 0xAH a w TL0 wartość 0xCH
    Przypomnij mi się wieczorem na PW to podeślę Ci kod z działającym PWM w oparciu o przerwania napisany dla AT89C2051, po drobnej kosmetyce będzie działać tak samo jak Twój. Przynajmniej zobaczysz jak powinno się te rejestry obsługiwać.

    0
  • #5 23 Mar 2012 07:16
    tehaceole

    Poziom 28  

    Kod: C
    Zaloguj się, aby zobaczyć kod

    To jest kod o którym wspominałem. Teraz, z perspektywy czasu, napisałbym go zupełnie inaczej - powyższy "kwiatek" jest bardzo nieoptymalny. Ale działał. Przy czym nie innteresowała mnie wtedy zbytnio częstotliwość PWM - skupiłem się na uzyskaniu efektu płynnego rozjaśniania / przyciemniania diod. Współczynnik wypełnienia przekazywany jest do przerwania przez rejestr R3, rejestrami roboczymi są R1 i R2, których wartości wyznaczane są z użyciem akumulatora. Zauważ, że na koniec obsługi przerwania ładuję rejestry timera 1 (ten użyłem) wartościami startowymi. Przyjrzyj się, w jaki sposób to robię. Literka "d" na końcu ładowanych wartości oznacza, że wartość podaję w systemie dziesiętnym. Rejestry są 8-io bitowe, zatem wartość FA00 w Hex w prowadzam poprzez rozbicie jej na 2 części: FA - 250 dziesiętnie, 00 - 0 dziesiętnie.
    Przyjrzyj się także sposobowi w jaki wykonuję "skok do samego siebie":
    - zamiast tak jak Ty
    Code:
    JNB TF0, CZEKAJ_OVF1; 

    - robię to tak:
    Code:
    djnz   r2,$

    czyli w Twoim przypadku byłoby to:
    Code:
    JNB TF0,$

    0
  • #6 26 Mar 2012 11:49
    Marek Glogowski
    Poziom 7  

    Dziękję Panu bardzo za pomoc. Przydało się i okazało się że zaliczyłem:) pozdrawiam

    0
  • #7 26 Mar 2012 12:09
    tehaceole

    Poziom 28  

    Cieszę się, że mogłem pomóc :) Na "pana" to trzeba mieć wygląd i pieniądze, jak mawiał mój ś.p. znajomy. Proponowałbym Ci zgłębić tajniki programowania - gwarantuję, że bardzo szybko można złapać bakcyla na tym punkcie :) Sam teraz chwytam się na tym, że pewne sposoby myślenia wyrobione dzięki programowaniu używam w życiu codziennym :) Powodzenia przy kolejnych zaliczeniach!

    0