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

[atmega8][C] multipleksowanie wyświetlaczy 7-seg.

cezar89 06 Sie 2009 23:44 5669 27
REKLAMA
  • #1 6865358
    cezar89
    Poziom 11  
    Witam

    Próbuję zrealizować multipleksowanie wyświetlaczy 7-seg.(dwóch) na atmega8, piszę w C, korzystam z WinAVR, mam wyświetlacze ze wspólną anodą, wykorzystałem tranzystory PNP. Z częstotliwością zegara nic nie kombinowałem więc mega pracuje na 1MHz. Napisałem taki kod:

    #include <avr/io.h>
    #include <avr/interrupt.h>   
            
    /*
    cyfry na wyświetlaczu
    0 0b10000001  129
    1 0b11010111  215
    2 0b01001001  73
    3 0b01000011  67
    4 0b00010111  23
    5 0b00100011  35
    6 0b00100001  33
    7 0b11000111  199
    8 0b00000001  1
    9 0b00000011  3
    */
    
    unsigned int cyfra[10]={129,215,73,67,23,35,33,199,1,3};
    unsigned int i,wysw;
    
    
    int main(void)
    {
    	
    	DDRB=0b11111111;   //port B wyjscia
    	DDRD=0b11111111;   //port D wyjscia
    	TCCR1B=(1 << CS10);   //ustaw timer1 z preskalerem 1
    	TCCR1B=(1 << WGM12);   //ustaw timer1 w tryb CTC
    	OCR1A=10000;   //do ilu liczy timer1;dla uzyskania 100Hz
    	SREG=(1 << 7);   //zezwolenie na przerwania 
    	TIMSK=(1 << OCIE1A);   //zezwolenie na przerwania dla CTC
    	
    	while(1){}
    	
    
    }
    	
    
    
    ISR(TIMER1_COMPA_vect)
    {
    	if(wysw==1)
    	{
    		PORTB=0b11111110;   //wł pierwszy wyświetlacz
    		PORTD=cyfra[1];
    		wysw++;
    	}
    	else
    	{
    		PORTB=0b11111101;   //wł drugi wyświetlacz
    		PORTD=cyfra[2];
    		wysw=1;
    	}
    	
    }


    Po skompilowaniu i wgraniu programu świecą się całe dwa wyświetlacze. Wydaje mi się, że kod jest taki jaki powinien być, chyba, że się mylę.
    Zaobserwowałem jeszcze coś takiego, że jak zamiast
    TCCR1B=(1 << WGM12);   //ustaw timer1 w tryb CTC


    dam

    TCCR1A=(1 << WGM12);   //ustaw timer1 w tryb CTC


    to wtedy niby działa, wyświetla się oczekiwana liczba 12 ale mruga i zmiana częstotliwości wyświetlania(na mniejszą czy większą) nic nie zmienia. No ale patrzę w datasheet to WGM12 jest w TCCR1B.

    Połączenia układu są OK bo jak napiszę jakiś prosty program bez użycia przerwań/timerów to wyświetlacze dobrze działają.

    Widzi ktoś jakiś błąd?
    Z góry dzięki.

    Pozdrawiam

    Przeniosłem z Programowanie początkujący.
    [Dr.Vee]
  • REKLAMA
  • Pomocny post
    #2 6865390
    Demoman
    Poziom 17  
    tak na pierwszy rzut oka:

       TCCR1B=(1 << CS10);   //ustaw timer1 z preskalerem 1
       TCCR1B=(1 << WGM12);   //ustaw timer1 w tryb CTC 

    Taki zapis nie wykona tego czego byś oczekiwał. Używasz operator przypisania =, co powoduje że pierwsza linia jest "pomijana" a w TCCR1B masz wartość (1 << WGM12).
    Użyj operatorów sumy i iloczynu binarnego z przypisaniem (ale mi nazwa wyszła, tak to się nazywa? :P ): &= i |=, czyli w Twoim przypadku:


       TCCR1B |= (1 << CS10);   //ustaw timer1 z preskalerem 1
       TCCR1B |= (1 << WGM12);   //ustaw timer1 w tryb CTC 
  • #3 6865409
    cezar89
    Poziom 11  
    Dzięki działa, ale mógłbyś jakoś jaśniej napisać o co chodzi z tym samym przypisaniem (=), która linijka jest pomijana? to wynika ze standardu języka(nie wydaje mi się) czy coś od strony avr?


    Pozdrawiam
  • #4 6865422
    Demoman
    Poziom 17  
    no z języka.

    =, czyli przypisanie, zastępuje wartość w rejestrze
    natomiast Ty chcesz "dopisać" jedynkę na którymś tam bicie, pozostawiając resztę w spokoju.

    przykład:
    
    r16 = 0b00000000 
    r16 = 1 << 2  ... (A = 0b00000100)
    
    //i teraz Twoja druga linia
    r16 = 1 << 1 ... (A = 0b00000010)
    
    //gdzie powinno być
    r16 |= 1 << 1 ... (A = 0b00000110)
    
  • REKLAMA
  • #5 6865430
    cezar89
    Poziom 11  
    No fakt, dzięki za wyjaśnienie.
  • #6 6865442
    Demoman
    Poziom 17  
    Tak dla świętego spokoju na przyszłość...
    Ja zawsze "wpisując" coś do rejestru zmieniam tylko ten bit o który dokładnie chodzi resztę pozostawiając bez zmiany.

    Zaoszczędza to wiele czasu ;)
  • #7 6868469
    cezar89
    Poziom 11  
    Wzbogaciłem mój program o to żeby odliczał jedną minute(praca jest wyświetlana na dwóch wyśw 7 segm.), oto kod:

    #include <avr/io.h>
    #include <avr/interrupt.h> 
    #include <util/delay.h>  
            
    /*
    cyfry na wyświetlaczu
    0 0b10000001  129
    1 0b11010111  215
    2 0b01001001  73
    3 0b01000011  67
    4 0b00010111  23
    5 0b00100011  35
    6 0b00100001  33
    7 0b11000111  199
    8 0b00000001  1
    9 0b00000011  3
    */
    
    unsigned int cyfra[10]={129,215,73,67,23,35,33,199,1,3};
    volatile unsigned int i,wysw,liczba,dziesiatki,jednosci,licznik;
    
    
    int main(void)
    {
    	
    	DDRB=0b11111111;   //port B wyjscia
    	DDRD=0b11111111;   //port D wyjscia
    	TCCR1B=(1 << CS10 |1 << CS11 | 1<< WGM12);   //ustaw timer1 z preskalerem 64 //ustaw timer1 w tryb CTC
    	TCCR2=(1 << WGM21 | 1 << CS22);   //ustaw timer2 z preskalerem 64; timer2 na CTC
    	OCR2=125;   //timer2, częstotliwość wyświetlaczy 125HZ
    	OCR1A=15625;   //do ilu liczy timer1 dla odmierzenia 1s
    	SREG=(1 << 7);   //zezwolenie na przerwania 
    	TIMSK=(1 << OCIE1A | 1 << OCIE2);   //zezwolenia na przerwania dla CTC
    	
    	while(1){}
    }
    	
    ISR(TIMER1_COMPA_vect)
    {
    	dziesiatki=liczba/10;
    	jednosci=liczba%10;
    	if(liczba==59) liczba=0; else liczba++;
    }
    
    ISR(TIMER2_COMP_vect)
    {
    	if(wysw==1)
    	{
    		PORTB=0b11111110;   //wł pierwszy wyświetlacz
    		PORTD=cyfra[dziesiatki];
    		wysw++;
    	}
    	else
    	{
    		PORTB=0b11111101;   //wł drugi wyświetlacz
    		PORTD=cyfra[jednosci];
    		wysw=1;
    	}
    }


    I mam dwa problemy: odmierzanie czasu trochę się rozjeżdża, na 5min około 0,5s, czy to jest wina tego, że mega pracuje na 1MHz? Druga sprawa dotyczy początku/startu pracy liczenia, najpierw pojawiają się dwa zera czekam ~2s i dopiero liczy, i nie wiem czemu na początku jest taka przerwa, potem jak już się zapętla to takiej sytuacji nie ma.

    Z góry dzięki za jakieś sugestie.

    Pozdrawiam
  • #8 6874895
    rpal
    Poziom 27  
    Mi się wydaje że kolega z każdym dojściem swojego licznika sekund do 59 gubi jedną sekundę porównując ją z 59 a nie 60. Dojście do 59 to jeszcze nie minuta. Przejście przez 60 to jest upływ pełnej minuty.
    Poza tym wydaje mi się że używając przerwania porównania dla timer1 to chyba trzeba podczas obsługi tego przerwania za każdym razem zerować go bo licznik mimo zgłoszenia przerwania dalej sobie liczy i najpierw osiągnie 0 ustawiając bit przepełnienia a potem znowwu dojdzie do ustalonej liczby zgłaszając ponownie przerwanie. Tym sposobem cały myk z wyznaczaniem przerwania raz na 15625 impulsów zegarowych bierze w łeb.:)
  • #9 6874927
    cezar89
    Poziom 11  
    Hmmm wydaje mi się, że nie masz racji, tzn tak, minuta ma 60 sekund ale jak będę porównywał do 60 to za każdym razem gdy licznik liczy od nowa to mam dodatkową 1s i to chyba nie w tym tkwi problem. Jeszcze mnie zastanawia na "przerwa" na początku liczenia.
  • #10 6874973
    rpal
    Poziom 27  
    Jeszcze jedno, ten program główny to w zasadzie nic nie robi poza ustawianiem liczników. Nie lepiej byłoby gdyby przerwanie 1sekundy ustawiało zmienne minut i godzin ,natomiast przerwanie dla LED zajmowało się jedynie wyborem cyfry oraz wpisywaniem jej wartości do portu ? Przeliczenia i zamiana wartości zmiennych odpowiednie segmenty LED to moim zdaniem robota dla programu głównego bo przecież i tak nic innego nie robi.
  • REKLAMA
  • #11 6874978
    cezar89
    Poziom 11  
    rpal napisał:
    Mi się wydaje że kolega z każdym dojściem swojego licznika sekund do 59 gubi jedną sekundę porównując ją z 59 a nie 60. Dojście do 59 to jeszcze nie minuta. Przejście przez 60 to jest upływ pełnej minuty.
    Poza tym wydaje mi się że używając przerwania porównania dla timer1 to chyba trzeba podczas obsługi tego przerwania za każdym razem zerować go bo licznik mimo zgłoszenia przerwania dalej sobie liczy i najpierw osiągnie 0 ustawiając bit przepełnienia a potem znowwu dojdzie do ustalonej liczby zgłaszając ponownie przerwanie. Tym sposobem cały myk z wyznaczaniem przerwania raz na 15625 impulsów zegarowych bierze w łeb.:)


    Ale chyba w trybie CTC licznik sam się zeruje.
  • #12 6875009
    rpal
    Poziom 27  
    No własnie tego nie jestem pewien, aż sięgne do lektury :) Sięgnąłem i przyznaję że popełniłem małego byka. Tak zeruje się :) Odszczekuję co napisałem.
  • #13 6875030
    cezar89
    Poziom 11  
    A masz jakiś pomysł czemu atmega "czeka" na starcie ~2s?
  • #14 6875051
    rpal
    Poziom 27  
    Może musi się rozgrzać ? Kiedy wstajesz z łózka też od razu jesteś na 100% obrotach :) musze pomyśleć czemu tak się dzieje i nie donoś od razu za żarty do admina :)
  • #15 6875064
    cezar89
    Poziom 11  
    rpal napisał:
    Może musi się rozgrzać ? Kiedy wstajesz z łózka też od razu jesteś na 100% obrotach :) musze pomyśleć czemu tak się dzieje i nie donoś od razu za żarty do admina :)


    Swoją drogą dobry żart:D Donosić?? to też chyba był żart:D
  • #16 6875117
    rpal
    Poziom 27  
    Ooj różnie to bywa ludzie w internecie są jacyś drażliwi. Ja bym zrobił tak zainicjuj wstępnie te zmienne jakąś wartością i nie odpalaj przerwania 1-sekundowego. Zobaczysz wtedy czy startuje to od razu czy są jakieś smiecie. Nie mam pomysłu na to ale zastanawia mnei jak to się dzieje że masz zegar który obrazuje minuty i sekundy a z programu wynika że wybierasz na przemian dwa wyświetlacze. Ile mają one cyfr 2 czy 4 ? Bo jesli dwie to coś tutaj jest bez sensu.
  • #17 6875152
    cezar89
    Poziom 11  
    rpal napisał:
    Ooj różnie to bywa ludzie w internecie są jacyś drażliwi. Ja bym zrobił tak zainicjuj wstępnie te zmienne jakąś wartością i nie odpalaj przerwania 1-sekundowego. Zobaczysz wtedy czy startuje to od razu czy są jakieś smiecie. Nie mam pomysłu na to ale zastanawia mnei jak to się dzieje że masz zegar który obrazuje minuty i sekundy a z programu wynika że wybierasz na przemian dwa wyświetlacze. Ile mają one cyfr 2 czy 4 ? Bo jesli dwie to coś tutaj jest bez sensu.


    Jeszcze przed Twoim postem przeniosłem
    dziesiatki=liczba/10;
    jednosci=liczba%10; 

    do maina i o dziwo mega już nie śpi, mam dwa wyświetlacze jedno cyfrowe, po prostu przymierzam się do zrobienia zegarka i na razie skleciłem taki układ, żeby się trochę podszkolić. Wracając do działała, to nadal ten mój "zegar" źle odmierza czas("spieszy się"). Nie mam pojęcia czemu.
  • #18 6875194
    rpal
    Poziom 27  
    Masz czym zmierzyć częstotliwość zegarową. Może Twoje 1 Mhz to wcale nei jest 1 Mhz ? ja bymjeszcze się przyjżał czy przypadkiem liczba którą wpisujesze do licznika jako wartość do porównywania tak samo jak w.w. sekunda nie jest zaniżona o 1 ? myślę że to jest powodem. Tam powinno być chyba 15626 bo dopiero przekroczenie 15625 o jeden będzie równoważne z upływem 1 sekundy przy częstotliwości taktowania 15625Hz. W sumei za pomocą tej wartości możesz stac się zegarmistrzem i dostroić się do prawidłowego czasu.
  • #19 6875230
    cezar89
    Poziom 11  
    Niestety częstotliwości nie mam czym zmierzyć, co do tych 15625 to chyba tyle ma być, chcę otrzymać częstotliwość 1Hz, daje preskaler 64 a 64*15625=1000000. Nie wiem czy dobrze to rozumuje ale chyba to akurat się zgadza.
  • #20 6875245
    rpal
    Poziom 27  
    Nie zawracałbym sobie tym głowy i po prostu preskalerem bym doszlusował do poprawnej wartości czasu. Kiedyś jak robiłem prędkościomierz do samochodu dokonałem obliczeń obwodu koła, dobrałem na podstawie obliczeń, preskaler i osiągnałem róznicę we wskazaniach na poziomie 2-4 km/h. Ponieważ mocno mnei to irytowało, zmieniłem preskaler o niewielką wartość i można powiedzieć że się ręcznie musiałem dostroić. Mierzyłem potem na radarze wskazania i nie miałem jakiś wielkich odchyleń. Może to jest metoda ?
  • #21 6875261
    cezar89
    Poziom 11  
    Jak to preskaler zmieniałeś o niewielką wartość? Z tego co ja wiem w atmedze8 mamy do dyspozycji preskalery: 8,64,256,1024.
  • #22 6875274
    rpal
    Poziom 27  
    Źle się wyraziłem z tym preskalerem miałem na myśli wartość licznika z którą dokonywałem porównania. Liczby różniły się ok 5-10.
  • REKLAMA
  • #23 6875281
    cezar89
    Poziom 11  
    No chyba, że tak. To będę kombinował, może w końcu zadziała.
  • #24 6875315
    rpal
    Poziom 27  
    W tej obsłudze przerwania odpowiedzialnego za wybór zapalanej cyfry lepiej jest się posłużyć przesuwaniem bitów niż operacją dodawania. W końcu dojdziesz do 4 cyfr i wartość aktualnie wybranej cyfry będziesz musiał inaczej wpisywać. Zatem najlepiej stworzyć 4 bajtowy bufor i dokonywać wyboru za pomocą indeksu z tablicy . Natomiast program główny już o to musi zadbać w które miejsce buforu wpakować odpowiednią wartość. Ups. znowu poknociłem dodawanie zostaje ale bufor i wskaźnik zostaje :)
  • #25 6875321
    cezar89
    Poziom 11  
    No fakt, dzięki za sugestie.
  • #26 6875327
    rpal
    Poziom 27  
    czas na sen a nie na pisanie bo bzdury wychodzą.
  • #27 6875330
    cezar89
    Poziom 11  
    Racja :D
  • #28 6875495
    kwesoly
    Poziom 15  
    cezar89 napisał:
    Z częstotliwością zegara nic nie kombinowałem więc mega pracuje na 1MHz

    Zgodnie z datasheetem do ATmegi8 wewnętrzny oscylator ma dokładność +/- 3% a i to pod warunkiem że masz równe 5V i 25*C


    Pisza tam też że można to jeszcze trochę poprawić (dodatkowa kalibracja), ale osiągniesz maks 1% błędu co w przypadku odmierzania czasu raczej nie jest akceptowalne (15minut błędu na dobę).

    Więc raczej nie ma sensu oczekiwać świetnej dokładności przy pomiarze czasu za pomocą wewnętrznego zegara. Możesz to rozwiązać na 3 sposoby z tego co wiem, ale prosiłbym o weryfikacje bardziej doświadczonych:
    1. Zewnętrzny kwarc taktujący uC będzie dokładniejszy, wiec zmniejszysz błąd.
    2. Z datasheetu wynika ze taktując mege jej wewnętrznym zegarem można w użyć wejść XTAL/TOSC wraz z oscylatorem 32768kHz jako źródła sygnału dla asynchronicznego timera.
    3. Można użyć zewnętrznego źródła sygnału zegarowego - jakiś układ zegara czasu rzeczywistego.
REKLAMA