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

[ATmega16][C] Multipleksacja i przyciski

Dugi89 17 Sty 2009 19:19 1828 6
REKLAMA
  • #1 6013510
    Dugi89
    Poziom 10  
    Witam wszystkich użytkowników. Od pewnego czasu śledzę tematy dotyczące mikrokontrolerów, ponieważ postanowiłem zacząć naukę ich obsługi. Na początek przerobiłem sobie kilka „zadan” z diodkami i przyciskami. Teraz zająłem sie wyswietlaczem led 7 segmentowym. Czytalem o multi pleksacji i mam nadzieje ze dobrze to zrozumialem (jesli nie prosze o wskazowki). Po udanym wyświetlaniu liczyby na 2 wyswietlaczach. -Postanowilem zrobic program ktory po nacisnieciu jednego switcha zmienia cyferke na jednym z wyswietlaczy, nacisniecie drugiego switcha zmienia literke na drugim wyswietlaczu.
    Oto kod:

    #include<avr/io.h>
    #define F_CPU 16000000UL
    #include<util/delay.h>
    
    int main(void){
     DDRB=0xff; //port B jako wyjscie
     DDRC=0xff; //port c jako wysjcie
     DDRA=0x00; //port A jako wejscie
     int i=0,j=0;
     unsigned char LED[10] = {0b11000000,0b11111001,0b10100100,0b10110000,
     0b10011001,0b10010010,0b10000010,0b11111000,0b10000000,0b10011000 };
     PORTC=0b11111100;  
     PORTB=LED[0];                 //wyswietlenie dwóch  zer i odczekanie 500 ms
     _delay_ms(500);
     for(;;){
     PORTC= 0b11111110;   
     PORTB=LED[j];             
     _delay_ms(4);
     PORTC=0b11111101;     // rozumiana przezemnie multipleksacja (tu wyswietla liczby z
     PORTB=LED[i];              //tabeli zalezne od zmiennych i ,j 
     _delay_ms(4);
    
     if(bit_is_clear(PINA,PD0)){
       i++;}
     if(bit_is_clear(PINA,PD1)){    //sprawdza czy ktorys przycisk jest wcisniety jesli tak 
      j++;}                                         //zwieksza zmienna i lub j o 1
    
     if(i==10){
      i=0;}                      //jesli i lub j =10 zaczyna liczyc od nowa
     if(j==10){
      j=0;}
    }
    }
    

    I teraz moj problem mysle ze to moze byc zwiazane z drganiami stykow lub zlym czasem ?. Po przycisniecu przycisku cyferka na danym wyswietlaczu zmienia sie niestety przeskakuje o kilka cyf . Przyjąlem ze to przez drgania stykow jednka nie dam rady uzyc tej metody : sprawdz odzcekaj sprawdz, poniewaz zwiekszy mi sie czas miedzy wyswietlaniem na danym segmencie. Bardzo prosze o nakierowanie mnie do rozwiazania tego problemu bo niestety nie moge sobie z nim poradzic sam.
  • REKLAMA
  • #2 6013564
    kubus_puchatek
    Poziom 18  
    Przyczyna Jest prostsza. po wykryci wciśnięcia przycisku należy odczekać 10ms i podjąć decyzję a kilka przeskoków jest spowodowanych tym, że nie dałeś opóźnienia:

    if(bit_is_clear(PINA,PD0)){
    i++;
    delay (200);}
    if(bit_is_clear(PINA,PD1)){ //sprawdza czy ktorys przycisk jest wcisniety jesli tak
    j++;
    delay(200);} //zwieksza zmienna i lub j o
    1

    oczywiście ten delay jest w milisekundach.
  • REKLAMA
  • #3 6013690
    Dugi89
    Poziom 10  
    Tak to rozumiem ze trzeba dac to opoznienie tylko ze gdy je wpisze multipleksacja nie dziala juz poprawnie. wyswietlacze migotaja z taka czestotliwoscia ze oko to widzi
  • REKLAMA
  • #4 6013739
    BoskiDialer
    Poziom 34  
    Ekstra opóźnienia nie trzeba - już jest 8ms z multipleksacji. Problemem są warunki - nie sprawdzają, czy przycisk został naciśnięty od poprzedniego sprawdzenia, tylko sprawdzają czy teraz przycisk jest naciśnięty - trzymasz przycisk pewnie dłużej niż 8ms, warunek jest spełniony, zmienna jest zwiększana co 8ms. Kod (nie tylko warunek) poprawić jest łatwo wykorzystując dwie dodatkowe zmienne - na poprzedni i aktualny stan wejść. Warunek musi wtedy sprawdzić, czy poprzednio przycisk był puszczony a teraz jest naciśnięty.
  • #5 6015296
    Dugi89
    Poziom 10  
    Witam i dziekuje za odpowiedzi. POprawilem moj kod nie jestem pewnien czy tak jak mial to na mysli Boski Dialer, ale chodzi trosze opornie ale chodzi. postaram sie to jakos dopracowac zeby bylo plynniejsze ale musze nad tym dluzej pomyslec .
    I mam jesce prosbe do Boski Dialer jesli to nie o takie rozwiazanie chodzilo rozwin swoja mysl zebym mogl to zrozumiec lepiej.
    Poprawiony kod :

    #include<avr/io.h>
    #define F_CPU 16000000UL
    #include<util/delay.h>
    
    int main(void){
     DDRB=0xff; //port B jako wyjscie
     DDRC=0xff; //port c jako wysjcie
     DDRA=0x00; //port A jako wejscie
     int i=0,j=0, a=0, b=0;                [b]   //dodalem dwie zmienne a b[/b]
     unsigned char LED[10] = {0b11000000,0b11111001,0b10100100,0b10110000,
     0b10011001,0b10010010,0b10000010,0b11111000,0b10000000,0b10011000 };
     PORTC=0b11111100; 
     PORTB=LED[0];                 //wyswietlenie dwóch  zer i odczekanie 500 ms
     _delay_ms(500);
     for(;;){
     PORTC= 0b11111110;   
     PORTB=LED[j];             
     _delay_ms(4);
     PORTC=0b11111101;     // rozumiana przezemnie multipleksacja (tu wyswietla liczby z
     PORTB=LED[i];              //tabeli zalezne od zmiennych i ,j
     _delay_ms(4);
    
     if(bit_is_clear(PINA,PD0) && a==0){     [b]    // teraz sprawdza jesce ile             cyli  przeszlo a gdy jest 0 lub 10 to dopiero wtedy reaguje na przycisk. rozne warosci licznikow aby nie pokryly sie[/b]
       i++;}
     if(bit_is_clear(PINA,PD1) && b==10){    //sprawdza czy ktorys przycisk jest wcisniety jesli tak
      j++;}                                         //zwieksza zmienna i lub j o 1
    
     if(i==10){
      i=0;}                      //jesli i lub j =10 zaczyna liczyc od nowa
     if(j==10){
      j=0;}
    a++;
    b++;
    if(a==180 || b==190) 
                                   [b]//jesli licznik dojdzie do odpowiedniej liczby  zeruje sie. wartosci wprawdzalem doswiadczalnie i troche mnie zastanawia dlaczego dopiero przy tak duzej wartosci dziala poprawnie. to wychodzi przerwa okolo 1400 ms.
    {[/b]
    a=0;
    b=0;        
    }
    
    }
    }
  • REKLAMA
  • Pomocny post
    #6 6018821
    BoskiDialer
    Poziom 34  
    Teraz kod sprawdza przycisk co około 1,4s, a więc musisz trzymać przycisk tak długo. Nie chodzi mi o sprawdzanie co jakiś czas, tylko o wykrycie samego faktu, że na wejściu nastąpiła zmiana stanu z 1 na 0:
    	//....
    	unsigned char pina_laststate = PINA;
    	
    	for(;;){ 
    		PORTC= 0b11111110;    
    		PORTB=LED[j];              
    		_delay_ms(4); 
    		PORTC=0b11111101;     // rozumiana przezemnie multipleksacja (tu wyswietla liczby z 
    		PORTB=LED[i];              //tabeli zalezne od zmiennych i ,j 
    		_delay_ms(4);
    		
    		// pobranie aktualnego stanu wejść
    		unsigned char pina_currstate = PINA;
    		// wyliczenie które bity zmieniły się z 1 na 0 (wcześniej było 1, teraz jest 0)
    		unsigned char pina_1to0 = pina_laststate & ~pina_currstate;
    		// zachowanie aktualnego stanu dla następnego sprawdzenia
    		pina_laststate = pina_currstate;
    
    		// jeśli PA0: 1->0, zwiększ zmienną i (ograniczenie zakresu wartości do 0..9)
    		if(bit_is_set(pina_1to0, PA0))
    		{
    			i++;
    			if(i >= 10)
    				i = 0;
    		}
    		// podobnie dla PA1, tyle że zmienna j
    		if(bit_is_set(pina_1to0, PA1))
    		{
    			j++;
    			if(j >= 10)
    				j = 0;
    		}
    	}
  • #7 6021129
    Dugi89
    Poziom 10  
    Dziękuje za odpowiedz teraz wsyztsko rozumiem
REKLAMA