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

Jak skonfigurować Timer 8051 do zliczania impulsów i zapalania diody?

cristof_w 23 Paź 2007 12:09 10525 58
Najlepsze odpowiedzi

Jak skonfigurować timery 8051 tak, aby jeden zliczał zewnętrzne impulsy przez określony czas, a po zliczeniu dwóch impulsów zapalał diodę?

Ustaw T0 jako licznik impulsów zewnętrznych, a T1 jako timer odmierzający czas, a po zakończeniu okresu 15 s odczytaj stan licznika impulsów, porównaj go z 2 i dopiero wtedy zaświeć diodę [#4406844][#4461605] TMOD=0x15 jest poprawne dla T1 w trybie 1 jako timera i T0 w trybie 1 jako licznika, ale jeśli chcesz tryb 2 dla T0, to dolny nibble powinien odpowiadać temu trybowi; bit GATE ma sens tylko wtedy, gdy chcesz bramkować zliczanie sygnałem INT0 [#4406844] W kodzie masz też błąd krytyczny: `if (TR0=0)` to przypisanie, a nie porównanie, więc powinno być `if (TR0==0)` [#4429112] Nie rób długiego `migaj()` w przerwaniu — ISR powinno tylko ustawić flagę, zatrzymać/uruchomić liczniki albo zliczyć zdarzenie, a samo wyświetlanie/miganie przenieś do `main` [#4452088][#4461605] Dodatkowo nie wpisuj 16-bitowej wartości do samego TH1; trzeba dobrać wartości reload zgodnie z trybem, bo TH1 przechowuje tylko 8 bitów [#4406619] Jeśli impulsy podajesz przyciskiem, uwzględnij też drgania styków, bo mogą fałszywie zwiększać liczbę zliczeń [#4433397]
Wygenerowane przez model językowy.
REKLAMA
  • #1 4406336
    cristof_w
    Poziom 17  
    Posty: 338
    Pomógł: 3
    Ocena: 9
    Witam. Mam nadzieję, że i tym razem uzyskam od Was pomoc.
    Chciałem napisać program do zliczania impulsów, a dokładnie np. zliczanie impulsów w okresie czasu 15 sekund i jak zostaną zliczone dwa impulsy to ma się zapalić dioda. Poniżej przedstawię kod programu, ale najpierw objaśnienia.

    Timer T0 - zlicza impulsy
    Timer T1 - odmierza czas zliczania

    Kwarc 6Mhz, zatem 6Mhz/12 daje 500000 Hz
    Przyjmuje sobie ziarnko odmierzanego czasu jako 10Hz (o,15 sekundy) Zatem: 500000 Hz/50000
    50000 to zapiane w Hex C350
    FFFF - C350 to daje 3CAF te wartości wykrorzystuje w programie.

    Wiem, że trzeba odpowiednio ustawić poszczególne bity w rejestrze TMOD. Tylko nie wiem, gdyż są 4 tryby działania Timerów ( 0,1,2,3), ja wybrałem MODE 1, czy jest to dopowiednie pod moje potrzeby? Jezel i tak, to czy zapis TMOD=0x0D; jest prawidłowy? Nie wiem czy dobrze skonfigurowałem te Timery, prosiłbym o weryfikacje
    osoby, które mogą pomóc. Nie wiem jak zrobić, żeby dioda się zapalała po zlcizeniu tych 2 impulsów. Byłbym wdzięczny za pomoc. Pozdrawiam.

    #include <8051.h>
    #include <stdio.h>
    
    #define SECOND 100
    #define PortLED P1_1
    
    ////////////////////////////////////////////////////////////////////////
    void main(void)//program glowny 
    { 
    	TMOD=0x0D;     		//Ustawienie trybu Timerow 
    	
    	TR1=1;			//Start Timer 1
    	TH1=0x3CAF;		//Wpisanie wartosci do rejestra
    	TL1=0;
    	
    	TH0=0xFE;		//Wpisanie wartosci do rejestra (ma zliczyć 2 impulsy i zasygnalizować to)
    	TL0=0;	
    	TR0=1;			//Start Timer0
    	ET1=1;			//Zgoa na przerwanie od TIMER1
    	EA=1;			//zezwolenie na przerwanie
    	
    	while(1)		//petla
    	{	
    		while(!INT0) {}; //Linia INT0 bramkuej zliczanie		
    		while(INT0) {};
    		TH0=0;		//zerowanie licznikow TH0	
    		TL0=0;		//i TL0 przed pomiarem
    	}
    		
    }
    
    //podprogram przerwania
    void T1_int(void) interrupt 3 using 1
    {	
    	int count=0;
    	TH1=0x3CAF;	//czas do następnego przerwania
    	TL1=0x00;
    	if (++count==SECOND)
    	{
    		count=0;
    		INT0=!PortLED;
    		
    	}
    }
    
  • REKLAMA
  • #2 4406539
    arturt134
    Poziom 27  
    Posty: 792
    Pomógł: 76
    Ocena: 24
    A nie prościej byłoby ustawić timer, żeby odmierzał 15 sekund, a impulsy zliczać przy pomocy przerwania. Każdy impuls zwiększałby licznik impulsów (w przerwaniu). Po odmierzeniu 15 sekund miałbyś przerwanie od timera, w którym odczytywałbyś licznik impulsów i odpowiednio reagował. Po odczytaniu zerowałbyś licznik impulsów. Cały cykl powtarzałby się od początku.

    Wydaje mi się, że taki algorytm byłby prostszy, pod warunkiem że impulsów nie byłoby zbyt dużo, powiedzmy kilka na sekundę.
    Przy większych częstotliwościach, lepiej byłoby zrobić zliczanie impulsów drugim timerem, tak jak proponowałeś.
  • #3 4406605
    cristof_w
    Poziom 17  
    Posty: 338
    Pomógł: 3
    Ocena: 9
    Docelowo ma być ok. 100 impulsów na sekundę, zatem takie rozwiązanie odpadłoby. Sprawdziłem ten programik, kompiluje się, a po wgraniu do procka...otrzymuje to, ze podłączona dioda świcie/gaśnie naprzemiennie. Byłbym wdzięczny za podpowiedź jak udoskonalić/ przrobić program tak, żeby np. po dwóch impulsach zapaliła się dioda. Proszę o porady/wskazówki/pomoc.
    Pozdrawiam.
  • #4 4406619
    romsik
    Poziom 15  
    Posty: 116
    Pomógł: 5
    Ocena: 8
    tryby pracy układu czasowolicznikowego:
    0. licznik 13 bitowy 8th+ 5tl (nie pamiętam czy starsze,czy młodsze)
    1. tryb 16 bitowy 8th +8tl
    2. tryb 8 bitowy tl po przepełnieniu wpisuje wartość z th
    3. dwa liczniki 8 bitowe th0 i tl0 sterowane za pomocą bitów sterujących odpowiednio t1 i t0

    jeśli chodzi o bramkowanie to możesz to zrobić ustalając GATE =1 (to jest bit słowa tmod, ale ono nie jest adresowane bitowo) - poszukaj o układzie czasowo licznikowym to na pewno znajdziesz cos lepszego graficznie :)
    i jeszcze jedno C się dopiero uczę więc niezbyt dokładnie przeanalizowałem program ale wpisujesz do 8 bitowego th1 wartość 16 bitową (kompilator nie ostrzega?)
    Cytat:

    TH1=0x3CAF; //Wpisanie wartosci do rejestra


    jeśli coś jeszcze chcesz wiedziec o t0 i t1 to pisz powodzenia pozdrawiam
  • #5 4406659
    cristof_w
    Poziom 17  
    Posty: 338
    Pomógł: 3
    Ocena: 9
    Dzięki za pomoc. Oczywiście są jeszcze rzeczy, które chciałbym wiedzieć, chętnie zapytam i się dowiem.

    Znam te 4 tryby działania Timerów, wybrałem właśnie tryb 1.
    Wiem, że: TMOD ustawia tryby pracy Timerów 1 i 2. Cztery młodsze bity ustawiają timer0, cztery strasze ustawiają Timer 1.
    Z tym programem to wzorowałem się na literaturze i np. nie wiem:
    jak rozszyfrować zapis TMOD=0x0D; a także zapis TMOD = TMOD | 0x10; ? Dlaczego właśnie jest tak?
    Czy ten kawałek kodu oznacza, że nastąpi przepełnienie po szczytaniu dwóch impulsów? TH0=0xFE; TL0=0;
    Noi chciałbym wiedzieć jak zrealizowac programowo, żeby np. zapalił diodę po szczytaniu 2 impulsów?

    A co do Twojego pytania. Nie, kompilator nie niekrzyczy, pojemność Timera to 65536, więc nie ma problemu.
    Pozdrawiam.
  • Pomocny post
    #6 4406844
    romsik
    Poziom 15  
    Posty: 116
    Pomógł: 5
    Ocena: 8
    no dobra tmod skałda się z dwóch czwórek następujących bitów:
    GATE,C/T,M1,M0
    m1 i mo ustalają tryb które znasz.
    C/T określa funcję c/t=1 Counter czyli zlicza impulsy doprowadzone do wejścia T(0lub1 w zalezności który licznik) c/t=0 timer zlicza cykle maszynowe (właściwie to powinno być C/ (negacja) T, tylko nie wiem jak to napisać) :) :(
    Gate - bramkowanie zliczania gate=1 licznik liczy jeżeli tr=1 i int=1; gate=0 licznik liczy jezeli tr=1;
    tmod=0x0d oznacza, że :
    licznik t1:
    gate=0; wystarczy, że tr=1 żeby liczył
    c/t=0 zlicza wewnętrzne impulsy
    m1=0
    mo=0 tryb 0
    licznik t0:
    gate=1 -zliczanie zależy od int1
    c/t=1 zlicza zewnętrzne impulsy doprowadzone do t0
    m1=0;
    m0=1 tryb 1

    Cytat:
    Czy ten kawałek kodu oznacza, że nastąpi przepełnienie po szczytaniu dwóch impulsów? TH0=0xFE; TL0=0;

    i tak i nie - to zależy od trybu
    w trybach od 0 do 2 nie w trybie 3 tak
    16 bitowy licznik to składa się z 2 części 8 bitowych tho- starsza część i tlo młodsza część żeby zwiększyć o 1 tho to przepełnić sie musi tlo, a Ty do niego wpisujesz 0 jeśli chcesz liczyć do 2 to nalepiej wykorzystac tryb 2 wpisując do th fe
    Cytat:
    Noi chciałbym wiedzieć jak zrealizowac programowo, żeby np. zapalił diodę po szczytaniu 2 impulsów?


    przepełnienie licznika jest sygnalizowane ustawieniem bitu TF w słowie TCON i tu masz 2 wyjści albo na bieżąco spawdzasz stan tego bitu i jesli jest ustawiony to go kasujesz i robisz co trzeba; albo 2 wyjscie robisz to w przerwaniu od tego licznika (tu nie musisz kasowac TF)

    Cytat:
    TMOD = TMOD | 0x10;


    co do tego to jakaś funcja logiczna C na słowie TMOD i wartości 0x10 ; wynik umieszczony w TMOD ale co to za funckja to nie pamiętam bo niestey za mało używam :(
    Cytat:
    pojemność Timera to 65536, więc nie ma problemu.


    zgoda ale jak pisałem cały licznik ma taką pojemność, a Ty do jego połowki wpisujesz wartość 16 bitową :)
    uff
    coś jeszcze?
    napisz jak poszło
  • REKLAMA
  • #7 4406989
    cristof_w
    Poziom 17  
    Posty: 338
    Pomógł: 3
    Ocena: 9
    Więc tak...
    Zrozumiałem jak interpetować zapi TMOD=... Ok.
    Z tego co piszesz, to ustawiłem teraz Timer0 w trybie 2, po to , żeby nastąpiło przepełnienie i, żeby mógł pozostać zapis:
    TH0=0xFE;TL0=0;
    Skoro Timer0 jest w trybie 2 to teraz napisałem, że TMOD=0x0E; (00001110).
    Teraz tylko pozostał problem z sygnalizacja diody po tych dwóch impulsach...Napisałeś, że jest to sygnalizowane przepełnieniem bitu TF w słowie TCON. Z tego co wiem, to w rejestrze TCON znajdują się po dwa bity sterujące dla każdego timera TRx i TFx i flaga przepełnienia ustawiona jest automatycznie na 1 w momencie przekroczenia zakresu tegoż Timera. Jednakże brakuje mnie wiedzy jak to zrealizowac programowo Będzie to w funkcji main w pętli while? Czy się mylę?

    Co do tych połówek -bitowych Timerów, to dla pewności teraz zmieniłem te czasy na inne, i np.wstawiłem wartość TH1 = 0x87;
    Ale spotkałem się z czymś takim, że wstawiają właśnie 0x87 jako 0x87FF, co jest 34815, natomiast 3CAF daje 15535. Tym się sugerując wstawiałem, ale chwuilowo to pomińmy. Nakieeuj mnie programowo, jak możesz, jak zrobić to wyświetlenie po zczytaniu tych dwóch impulsów.
    Pozdrawiam.

    A tak obenie wygląda program:
    #include <8051.h>
    #include <stdio.h>
    
    #define PortLED  P2_5
    #define SECOND 100    //1sek to 20 przerwan od Timer
    
    void main(void)
    {	
    
    	TMOD=0x0E;
    	
    	TH0=0xFE;		
    	TL0=0;	
    	TR0=1;
    	
    	TH1 = 0x87;
    	TL1 = 0;
    	TR1 = 1;
    	ET1 = 1;
    	EA = 1;
    
    	while(1) {
    		
    		TH0=0;		//zerowanie licznikow TH0	
    		TL0=0;		//i TL0 przed pomiarem
    	
    		};
    	}
    void T1_int(void) interrupt 3 using 1 
    	{
    	static data unsigned char count=0;
    	TH1 =0x87;
    	TL1 =0;
    
    	if (++count ==SECOND)
    		{
    		count =0;
    		INT0=PortLED=!PortLED;
    		}
    	}
  • #8 4407172
    romsik
    Poziom 15  
    Posty: 116
    Pomógł: 5
    Ocena: 8
    gdyby tak jeszcze jakiś schemat to byłoby prościej ale na razie to:
    Cytat:

    Z tego co piszesz, to ustawiłem teraz Timer0 w trybie 2, po to , żeby nastąpiło przepełnienie i, żeby mógł pozostać zapis:
    TH0=0xFE;TL0=0;

    to jjest nie całkiem dobrze bo zlicz TL0, aTh0 przechowuje wartość jaką należy wpisać po przepełnieniu nalepij byłoby:
    TH0=0xFE
    TL0=0xFE
    Cytat:

    TMOD=0x0E; (00001110).

    ok T0 jest w trybie 2 ale po co gate=1 (pierwsza jedynka) stad pytanie o schemat

    Cytat:
    tego co wiem, to w rejestrze TCON znajdują się po dwa bity sterujące dla każdego timera TRx i TFx i flaga przepełnienia ustawiona jest automatycznie na 1 w momencie przekroczenia zakresu tegoż Timera. Jednakże brakuje mnie wiedzy jak to zrealizowac programowo Będzie to w funkcji main w


    dobrze wiesz x=0 lub 1 odpowiednio dla każdego licznika TRx=1 włącza zliczanie TFx sygnalizuje przepełnienie (przepełnienie i przekroczenie zakresu to chyba nie to samo) ustawienie TF (piszę w skrócie bez x bo dla obu jest tak samo) może powodowac przerwanie jeżeli go włączysz.
    no to chyba teorię mamy z głowy (prawie)
    co do konkretnego roziązania programowego to przychyliłbym sie do propozycji kolegi arturt134
    Twój program w funkcji main tylko w kółko zeruje licznik T0 i nic więcej, a odmirzanie czasu (jeśli jest dobre) w przerwaniu nie sprawdza nic co sie dzieje w T0 i jeszcze jedno jeśli ten czas ma być dokładnie odmirzany to to całkiem nie działa, bo gubisz kilka cykli maszynowych na przyjecie przerwania i wpis nowej wartości; trzeba w asemblerze wstawic coć takiego:
    ORL TL1,#wartość jaką trzeba wpisać do tl1
    MOV TH1, # wartość jaką trzeba wpisac do th1
    jeszcze co do propozycji kolegi arurt134 to Twoje 100 impulsów nie powinno byc zbyt duzo . przemyśl sprawę jeszcze raz i zacznij najlepiej od początku ja ze swojej strony chetnie pomogę ale w C nie jestem mocny jak pisałem
    na rzie ode mnie tyle pozdawiam rs

    dzięki za punkty :)) :))
  • #9 4407294
    cristof_w
    Poziom 17  
    Posty: 338
    Pomógł: 3
    Ocena: 9
    Dzięki za odpowiedź.
    Co d oschematu to nierysowałem gdyż są tam tylko następujące rzeczy:
    -procek AT9S52
    -sygnał zewnętrzny podaje na wejście timera T0, to jest na P3_4
    -diodę sygnalizacyjną podłączam na P2_5. To wszystko.
    Póki co narazie chcę pozostać przy takim rozwiązaniu, jakie jest, tzn. zliczanie impulsów za pomocą drugiego Timera. Sęk w tym, że nie wiem jak to teraz dalje dokończyć. Brakuje mnie jeszcze wiedzy i umiejętności w C...dlatego mam nadzieję, że ktoś z Was pomoże.
    Narazie czasy nie są istotne (super dokładność), chodzi tylko oto, żeby zadziałało.
    Czy w funkcji main powinienem na początku dodać coś w postaci:
    while(TH0=0x00) {PortLED=0;}; jako srawdzenie co się dzieje w TO ?
    Pozdrawiam.
  • #10 4408917
    as124
    Poziom 14  
    Posty: 145
    Ocena: 15
    A dlaczego nie zastosować sposobu arturt134? Odmierzasz 15 sekund i sprawdzasz ile jest impulsów (wywołanych przerwaniem). Problem ich dużej ilości rozwiążesz jeśli w przerwaniu ilość impulsów będzie zliczane w paru bajtach zamiast w jednym; np. od 0 do 100 w bajcie A po dodaniu impulsu sprawdzasz czy jest sto jeśli jest to A=0 a inkrementujesz bajt B. Dla 2 bajtów masz 25500 impulsów jeśli tego mało to możesz zrobić 255x255 albo jeszcze razy 255 używając bajtu C.
  • REKLAMA
  • #11 4408980
    arturt134
    Poziom 27  
    Posty: 792
    Pomógł: 76
    Ocena: 24
    Oczywiście, że można zrobić licznik impulsów o długości 16 bitów.
    O zliczaniu małej ilości impu8lsów mówiłem tylko dlatego, że ten procek pewnie robi coś jeszcze oprócz zliczania impulsów. Jeżeli ich częstotliwość jest zbyt duża, to jedno przerwanie jest zgłaszane za drugim, no i kontroler nie może robić nic więcej tylko obsługiwać te przerwania.
    Przepraszam, że nie napisałem tego dostatecznie jasno.

    Reasumując, możesz zawsze zliczać impulsy, pod warunkiem, że licznik posiada odpowiednią długość i procesor ma dość czasu, żeby obsłużyć wszystkie nadchodzące przerwania no i oczywiście wykonywać program główny.
  • REKLAMA
  • #12 4409064
    cristof_w
    Poziom 17  
    Posty: 338
    Pomógł: 3
    Ocena: 9
    Witam. Dzięki za odzew.
    Zacząłem poruszać się tym tropem i chciałbym to skończyć w ten sposób, czyli T0- zlicza impulsy, T1-odmierza czas. I teraz jest taki pomysł.
    Rejestry T0 to TH0, TL0, W tej chwili T0 jest ustawiony w tryb pracy 2. Jednakże myślałem o czymś takim:
    T0 ustawić w tryb pracy 1
    TH0 i TL0 - wartości początkowe ustawić na zero.
    W przerwaniu pozostawić odmierzanie czasu przez T1, natomiast dopisać funkcję, że:
    TH0=a;
    if (a==2) PortLED2=0;

    Czy to jest dobry tok myślenia?
    Bo na logikę, Timer T0 zlicza impulsy, wtedy jego rejsetr powinien się zwiększać (napisałem, że TH0, aczkolwiek nie mam pewnosci czy nie bedzie to TL0). I gdy zliczy dwa impulsy w zadanym przez Timer1 czasie, to zapala diode.
    Jeżeli jest to prawidłowy tok myślenia to prosze o dalsze porady. Powinienem tan zapis umiescic w while w main?
    while(1) {
    		TH0=a;
    		if (a==2) PortLED2=0; }

    Pozdrawiam i proszę o dalsze wskazóki.
  • #13 4409263
    arturt134
    Poziom 27  
    Posty: 792
    Pomógł: 76
    Ocena: 24
    Przypisanie masz w drugą stronę. Powinno być chyba a=TH0.
    No i powinieneś go gdzieś zerować.

    Nie bardzo rozumiem jakie powinno być działanie programu. Czy dioda ma się zapalić po stwierdzeniu 2 impulsów w cigu 15 sekund i palić się do końca świata? Czy może ma się zapalić i palić do końca 15 sekundowego cyklu? A może jeszcze inaczej? Spróbuj opisać działanie programu trochę dokładniej.

    Jeżeli wystarczy stwierdzić, że w ciągu 15 sekund wystąpiły dwa impulsy, to polecam jednak moją metodę z wykrywaniem impulsów w przerwaniu. Po stwierdzeniu że otrzymałeś 2 impulsy, przerwanie po prostu wyłączasz. Odblokowujesz je po upływie cyklu 15 sekundowego, zerując licznik impulsów (jego wartość będzie równa 2).
  • #14 4409364
    cristof_w
    Poziom 17  
    Posty: 338
    Pomógł: 3
    Ocena: 9
    Póki co narazie chce pozostać przy tej metodzie.
    Timer mierzy czas np. 15 sekund, w tym czasie T0 zlicza, nastepuje pomiar.Po skonczeniu pomiru dioda ma gasnąć, kolejny pomiar, zliczone dwa impulsy, dioda się zapala, gaśnie po upływie końca zliczania Timera1, i tak w kółko. Wiem,ze to dziwne, ale poprostuchce sobie sprawdzić jak to wszystko działa. W przyszlości to ma byc zliczanie obrotów(impulsow) od silnika DC, powidzmy coś na wzór obrotoierza, ale to później. Mam nadzieje, że Ci wyjaśniłem o co mnie chodzi.
    Pozdrawiam.
  • #15 4409419
    arturt134
    Poziom 27  
    Posty: 792
    Pomógł: 76
    Ocena: 24
    Teraz już wszystko jasne.
    Jeżeli się upierasz przy uzyciu timera do zliczania impulsów to OK. Musisz tylko się zabezpieczyć przed przepełnieniem. Zastanów się co się stanie, jeżeli w ciągu jednego cyklu pomiarowego (15 sekund) przyjdzie więcej impulsów niż timer jest w stanie zmieścić w swoim liczniku, np. wskutek zakłóceń.
  • #16 4410837
    cristof_w
    Poziom 17  
    Posty: 338
    Pomógł: 3
    Ocena: 9
    To dobrze, że już wszystko wyjaśniliśmy w pewnych kwestiach.
    Przerobiłem troszke program, ustawiłem Timery w odpowiednie tryby, jednakże prgoram nie działa. Może wiecie czego brakuje w tym kodzie , ewentualnie co jest nie tak?Może zerowanie Timerów jest źle zrobione? Po przejściu dwóch impulsów dioda się niezapala.
    Kod poniżej. Pozdrawiam.
    #define PortLED  P2_5 
    #define PortLED2  P2_4 
    #define SECOND 200    //1sek to 20 przerwan od Timer 
    
    void main(void) 
    {    
    
       TMOD=0x06; 
        
       TH0=0;       
       TL0=0;    
       TR0=1; 
        
       TH1 = 0x87; 
       TL1 = 0; 
       TR1 = 1; 
       ET1 = 1; 
       EA = 1; 
    
       while(1) { 
           
       	int a;
       	a=TH0;
       	if (a==2) PortLED2=0;
          TH0=0;      //zerowanie licznikow TH0    
          TL0=0;      //i TL0 przed pomiarem 
        
          }; 
       } 
    void T1_int(void) interrupt 3 using 1 
       { 
       static data unsigned char count=0; 
       TH1 =0x87; 
       TL1 =0; 
    
       if (++count ==SECOND) 
          { 
          count =0; 
          PortLED=!PortLED; 
          } 
       }
  • #17 4412498
    arturt134
    Poziom 27  
    Posty: 792
    Pomógł: 76
    Ocena: 24
    Zerowanie timera powinno być zrobione tak:
    if (a==2)
    {
    PortLED2=0;
    TH0=0; //zerowanie licznikow TH0
    TL0=0; //i TL0 przed pomiarem
    }

    W twoim kodzie timer był zawsze zerowany, niezaleznie od tego czy dwa impulsy wystąpiły, czy nie. No i nie wiem, czy powinienes sprawdzać TH0 czy TL0. Sprawdź, który z tych rejetrów zawiera młodszy bajt wyniku, bo to niego powinieneś odczytywać.
  • #18 4413565
    cristof_w
    Poziom 17  
    Posty: 338
    Pomógł: 3
    Ocena: 9
    Witam.
    Ten kawałek programu wygląda następująco:
     while(1) { 
            
          int a; 
          a=TL0; 
          if (a==2) 
    		{ 
    			PortLED2=0; 
    			TH0=0; //zerowanie licznikow TH0 
    			TL0=0; //i TL0 przed pomiarem 
    		} 
    
        
        	   }


    Więc tak.
    Rzeczywiście zmieniłem i przypisałem obecnie a=TL0; .
    Program zadziałał, owszem. Jednakże cos jest nie tak i nie mogę do tego dojść. Próbowałem dla kilku wartości zmiennej a, ale dioda cały czas zapala się po jednym impulsie (nieważne jaką wartość ma zmienna a).
    W czym może tkwić problem?
    Co więcej, po przerwaniu dioda PortLED2 cały czas się świeci, niegaśnie, też nie wiem dlaczego. Jakieś sugestie?
    Pozdrawiam.
    Edit:
    Chodzi oto, żeby uzyskać nastepujący efekt:
    Zliczanie impulsów podczas odmierzenia czasu, następnie przerwanie (i w tym momencie, czyli w trakcie trwania przerwania, żeby tutaj nastąpiło wyświetlenie ilości zliczonych impulsów, czyli zapalenie PortLED2).
  • #19 4415750
    arturt134
    Poziom 27  
    Posty: 792
    Pomógł: 76
    Ocena: 24
    Przypisanie: PortLED=!PortLED miało pewnie służyć do zgaszenia diody. W ten sposób możesz też ją zapalać (jeżeli jest zgaszona, to zmiana stanu na przeciwny spowoduje jej zapalenie).
    Lepiej byłoby przypisać jawnie stan wysoki (bo takim stanem ją chyba gasisz), zamiast zmieniać go na przeciwny.

    Poza tym uruchamianie kodu ja bym przeprowadził dwuetapowo. W pierwszym etapie sprawdziłbym jak działa timer odmierzający 15 sekund, na przykład każąc mu zmieniać stan diody po upływie każdego okresu (na przeciwny). Na czas uruchamiania tego timera resztę kodu bym zaremował.
    Dopiero po stwierdzeniu, że timer 1 sekundowy działa dobrze, zabrałbym się za resztę programu.
  • #20 4416131
    cristof_w
    Poziom 17  
    Posty: 338
    Pomógł: 3
    Ocena: 9
    Więc tak...
    Poprawiłem zliczanie w Timer1, gdyż rzeczywiście było błędne.
    Z kolegą Artur źle się znowu zrozumielismy w jednej rzeczy. Dioda PortLED służy tylko jako sygnalizacja pracy Timera!, tak żebym mógł sprawdzić czy działa poprawnie. Teraz już działa poprawnie.
    Docelowo ma być tak, że mierzy okres 1s, jednakże dla testów ustawiłem w tej chwili ok 10s, tak abym mógł fizycznie zdążyć z podawaniem impulsów na wejście Timer0.
    Program uruchomiłem dwuetapowo, tak jak radziłeś. Wnioskuję, że problem leży przy Timer0, albo coś źle w funkcji while, albo źle go skonfigurowałem.
    obecnie jest tak, że Timer1 jest ustawiony w tryb 1 i Timer0 jest ustawiony w tryb 1. Czyli mam następujacy zapis:
    TMOD=0x15; patrząc na to co kolega wcześniej napisał to jest to:

    Timer1 | Timer0
    G|C/T|M1|M0 |G|C/T|M1|M0 czyli mam, że:
    0001 0101

    T1 ma liczyć czas, T0 ma zliczać impulsy podawane na T0. I teraz chcę mieć pewność czy dobrze to skonfigurowałem? Może problem leży tutaj? Może tutaj pokręciłem właśnie coś?

    Dalej. Program w obecnej chwili działa tak, że po wykryciu impulsu na wejściu T0 zapala diode PortLED2.
    Moim celem jest aby program działał w następujący sposób:
    T1 liczy czas, w tym czasie są podawane impulsy (czyli przyszłosciowo w trakcie 1s), natomiast w drugiej sekundzie ma być wyświetlany wynik, i tak w kółko. Teraz dioda PortLED2 niegaśnie po zapaleniu i zapala się już w trakcie zliczania po otrzymaniu jednego impulsu na T0.
    Mam nadzieję, że już wszystko jasno objaśniłem. Jakieś pomysły jeszcze?
    Byłbym zainteresowany.
    Pozdrawiam i pod spodem obecny kod programu.
    #define PortLED  P2_4 
    #define PortLED2  P2_5 
    #define SECOND 160   //Ok 10 sekund
    
    void main(void) 
    {    
    
       TMOD=0x15; 
           
       TR0=1; 
       TH1 = 0x87; 
       TL1 = 0; 
       TR1 = 1; 
       ET1 = 1; 
       EA = 1; 
      
       TH0=0;
       TL0=0;
       while(1) 
       {
       int a;
       a=TL0;
       if (a==2) 
          { 
             PortLED2=0; 
             TH0=0; //zerowanie licznikow TH0 
             TL0=0; //i TL0 przed pomiarem 
          }
       }
    } 
    void T1_int(void) interrupt 3 using 1 
       { 
       static data unsigned char count=0; 
       TH1 =0x87; 
       TL1 =0; 
    
       if (++count==SECOND) 
          { 
          count =0; 
          PortLED=!PortLED; 
          }
       }
  • #21 4416308
    McRancor
    VIP Zasłużony dla elektroda
    Posty: 5326
    Pomógł: 479
    Ocena: 123
    Temat poprawiłem :arrow: regulamin
  • #22 4416573
    romsik
    Poziom 15  
    Posty: 116
    Pomógł: 5
    Ocena: 8
    liczniki wygądają na dobrze ustawione;
    led2 powinien migać niezależnie od wszystkiego i na moje oko w ten program ma sszanse tak działac ,ale jesli sprawdziłbyś to jeszcze raz dla pewności to byloby dobrze (w main pusta pętla);

    teraz istotne pytanie : Jak podajesz impulsy na t0?, jeśli to jest przełącznik to drgają styki i licznik liczy więcej niż Ci się wydaje

    i kolejna sprawa w Twoim programie oba liczniki liczą niezależnie a chyba powinno byś tak :
    1 Pomiar t0 liczy
    2 Wyświetlanie t0 nie liczy, wyswietlasz jego zawartość , zerujesz i idziesz do pkt 1

    a t1 liczy cały czas żeby określać czy pomiar czy wyswietlanie

    moja propozycja jest taka: na końcu programu obsługi t1 negujesz tr0; a w funkcji main najpierw sprawdzasz stan tr0 jeśli jest 1 to nie robisz nic , bo liczy, jesli jest 0 to możesz wyświetlić wynik (tu dygresja jak bedziesz to robił przy pmocy 1 diody? chyba coś więcej tam będzie) i wyzerować go, a potem czekać, aż program od t1 znowu ustawi TR0 nie zmieniając stanu wyswietlanego wyniku

    to jest tylko moja propozycja może mozna zrobic lepiej

    powodzenia 73

    aha przez weekend jestem offline
  • #23 4416891
    cristof_w
    Poziom 17  
    Posty: 338
    Pomógł: 3
    Ocena: 9
    Witaj.
    Sprawdzę to o czym piszesz. Co do wyświetlania wyniku, będzie tam LCD, ale to później. Narazie interesuje mnie tylko to czy działa włąśnie ten program, czy liczniki są dobrze poustawiane. Dlatego dla testu chcę wyświetlić na jednej diodzie zliczenie np. 2 impulsów. Nie mogę tylko zrozumieć jednej kwestii, którą napisałeś
    "led2 powinien migać niezależnie od wszystkiego i na moje oko w ten program ma sszanse tak działac ,ale jesli sprawdziłbyś to jeszcze raz dla pewności to byloby dobrze (w main pusta pętla);"
    Nie mtoę tego rozszyfrować o co Ci chodzi tutaj? :)
    Pozdrawiam.
  • #24 4425548
    romsik
    Poziom 15  
    Posty: 116
    Pomógł: 5
    Ocena: 8
    chodzi mi o odmierzanie czasu powinno działać niezależnie tzn w main masz tylko ustawienia wstępne tzn tmod i włączenie timera , a potem pusta pętla i obsługa przerwania od czasu to powinno powodować miganie diody led2
  • #25 4425550
    cristof_w
    Poziom 17  
    Posty: 338
    Pomógł: 3
    Ocena: 9
    Więc tak.
    Witam.

    Na końcu T1 zanegowałem zatem TR0 : TR0=!TR0; Dało to tyle, że rzeczywiście T0 nie zlicza już cały czas, tylko jesto to tak:
    Liczy, przerwanie (nieliczy i tutaj ma być wyświetlany wynik), liczy i tak w kółko.
    Jednakże nie wyświetla mnie wyniku wtedy gdy nieliczy (czyli na czas trwania przerwania). Źle pozmieniałem w main? A wygląda to tak:
    while(1)
    {
    int a;
    a=TL0;

    if (a==2)
    {
    if (TR0=0) {
    PortLED2=0;
    TH0=0; //zerowanie licznikow TH0
    TL0=0; //i TL0 przed pomiarem
    }
    }
    }
    Probowalem na różne sposoby, może powinno to wyglądać inaczej?
    Pozdrawiam.

    Dodano po 29 [minuty]:

    Edit: Sprawdziłem to miganie diody LED2, niestety od czasu do czasu ona nie mruga, tak jak piszesz (no chyba, że są to bardzo długie odstepy czasu, teraz mam nastawy przerwanie co ok. 10 sekund).
  • #26 4425756
    romsik
    Poziom 15  
    Posty: 116
    Pomógł: 5
    Ocena: 8
    być może znalazłem bląd
    polega on na tym, że w w przerwaniu deklarujesz zmienną count i od razu przypisujesz jej wartość
    pytania są 2:
    czy przypadkiem przy kazdym zgłoszeniu przerwania zmienna nie jest zerowana?
    czy ta zmienna ( a dokładnie komórka pamięci która przechowuje tą zmienną ) nie jest modyfikowana w innym fragmencie programu?
    najprawdopodobniej nie ale spróbuj zadeklarować ten licznik jako zmienną globalną i sprawdź jak działa, bo tylko to budzi moje wątpliwości reszta przerwania powinna działać dobrze
  • #27 4425921
    cristof_w
    Poziom 17  
    Posty: 338
    Pomógł: 3
    Ocena: 9
    Niestety...niepomogło, deklaracja jako zmienna globalna niemiała żadnego wpływu na program.
    Poprostu nie chce działać...pomysły się mnie też kończą.
  • #28 4426043
    romsik
    Poziom 15  
    Posty: 116
    Pomógł: 5
    Ocena: 8
    a pokaż kod
  • #29 4426247
    cristof_w
    Poziom 17  
    Posty: 338
    Pomógł: 3
    Ocena: 9
    #include <8051.h> 
    #include <stdio.h> 
    
    #define PortLED  P2_4 
    #define PortLED2  P2_5 
    #define SECOND 160   //Ok 10 sekund
    static data unsigned char count=0; //bez przyrownania do 0 tez
    //sprawdzalem
    void main(void) 
    {    
    
       TMOD=0x15; 
           
       TR0=1; 
    
       TH1 = 0x87; 
       TL1 = 0; 
    
       TR1 = 1; 
    
       ET1 = 1; 
       EA = 1; 
      
       TH0=0;
       TL0=0;
    
       while(1) 
       {
       int a;
       a=TL0;
      
       if (a==2) 
          { 
          	if (TR0=0) { 
    
             PortLED2=0; 
             TH0=0; //zerowanie licznikow TH0 
             TL0=0;             }//i TL0 przed pomiarem      		  
          }       	
       }
    } 
    void T1_int(void) interrupt 3 using 1 
       { 
       //static data unsigned char count=0; 
       TH1 =0x87; 
       TL1 =0; 
    
       if (++count==SECOND) 
          { 
          count =0; 
          PortLED=!PortLED; 
          TR0=!TR0;//zmiana T0 liczy
          }
       }


    Dodano po 1 [minuty]:

    Zastanawiam się jeszcze nad kwestią przyrównywania a do TH0 jako integer, czy niepowinno być podawane w systemie 0x01 zamiast a =1.
  • #30 4426303
    romsik
    Poziom 15  
    Posty: 116
    Pomógł: 5
    Ocena: 8
    #include <8051.h>
    #include <stdio.h>
    
    #define PortLED  P2_4
    #define PortLED2  P2_5
    #define SECOND 160   //Ok 10 sekund
    static data unsigned char count=0; //bez przyrownania do 0 tez
    //sprawdzalem
    void main(void)
    {   
    
       TMOD=0x15;
           
       TR0=1;
    
       TH1 = 0x87;
       TL1 = 0;
    
       TR1 = 1;
    
       ET1 = 1;
       EA = 1;
     
       TH0=0;
       TL0=0;
    
       while(1)
     { }
    }
     void T1_int(void) interrupt 3 using 1
       {
       //static data unsigned char count=0;
       TH1 =0x87;
       TL1 =0;
    
       if (++count==SECOND)
          {
          count =0;
          PortLED=!PortLED;
          TR0=!TR0;//zmiana T0 liczy
          }
       }


    a coś takiego sprawdzałeś ?
    to jest tylko obsługa przerwania od T1 , jak to nie działa to nie wiem
    pozdrawiam i życzę powodzenia

    tu co ok 10sekund powinien zmieniać sie stan diody i nic więcej

Podsumowanie tematu

✨ Dyskusja dotyczy konfiguracji timerów mikrokontrolera 8051 (konkretnie modelu AT9S52) do zliczania impulsów na wejściu T0 oraz odmierzania czasu za pomocą timera T1, z celem zapalenia diody po zliczeniu określonej liczby impulsów (np. dwóch) w czasie 15 sekund. Użytkownik stosuje kwarc 6 MHz, co daje częstotliwość taktowania 500 kHz po podziale przez 12. Timer T0 ma działać jako licznik impulsów zewnętrznych (C/T=1), a Timer T1 jako timer odmierzający czas (C/T=0) w trybie 1 (16-bitowym). Wartości rejestrów TMOD, TH0, TL0, TH1, TL1 są ustawiane zgodnie z obliczeniami, jednak pojawiają się problemy z poprawnym odczytem i zerowaniem liczników oraz z obsługą przerwań. Dyskutowano o interpretacji bitów TMOD, roli bitów TRx i TFx w rejestrze TCON, oraz o konieczności zabezpieczenia przed przepełnieniem licznika. Proponowano implementację zliczania impulsów w przerwaniu, a odmierzanie czasu w przerwaniu timera T1, z wyłączaniem licznika impulsów podczas wyświetlania wyniku. Problemy techniczne obejmowały błędne przypisania w warunkach (np. użycie operatora przypisania zamiast porównania), nieprawidłowe zerowanie timerów, drgania styków przy podawaniu impulsów z przycisku, oraz nieprawidłowe działanie funkcji migania diodą w pętli głównej i w przerwaniu. Użytkownik testował program w symulatorze, gdzie zauważył zapętlenia w kodzie asemblerowym odpowiadającym fragmentom programu w C. Wskazano, że długotrwałe operacje (np. miganie diodą) nie powinny być wykonywane w przerwaniu, a obsługa powinna być rozdzielona między przerwania i pętlę główną. Ostatecznie zaproponowano poprawki w logice sterowania timerami i obsługi przerwań, jednak użytkownik nadal boryka się z problemami w działaniu programu. Dyskusja zawierała także sugestie dotyczące użycia symulatorów i nauki asemblera dla lepszego zrozumienia działania timerów 8051.
Wygenerowane przez model językowy.
REKLAMA