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

[Attiny2313][C] Matryca klawiszy na 74hc165

codeking 25 Wrz 2010 12:50 2380 9
  • #1 8548490
    codeking
    Poziom 11  
    Proszę o pomoc z uruchomieniem układu:
    [Attiny2313][C] Matryca klawiszy na 74hc165

    Rezystory dałem 1k, kwarc 11.0592MHz (nie ma go na schemacie), do scalaków dodałem kondensatory filtrujące 100nF.

    Testuje to kodem:
    
    
    // pominięty został kod obsługi USART
    
    #define DS_PORT    PORTD
    #define DS_PIN     4
    #define PL_PORT PORTD
    #define PL_PIN  3
    #define CL_PORT PORTD
    #define CL_PIN  5
     
    #define DS_low()  DS_PORT &= ~_BV(DS_PIN)
    #define DS_high() DS_PORT |= _BV(DS_PIN)
    #define PL_low()  PL_PORT &= ~_BV(PL_PIN)
    #define PL_high() PL_PORT |= _BV(PL_PIN)
    #define CL_low()  CL_PORT &= ~_BV(CL_PIN)
    #define CL_high() CL_PORT |= _BV(CL_PIN)
    
    int main(void)
    {	
    	// 5 - PL
    	// 3 - CL
    	// 4 - D
    
    	DDRB = 0xff;
    	PORTB = 0x00;
    
    	DDRD = _BV(5) | _BV(3);
    	PORTD = 0x00;
    	
    	// właczenie RS232
    	USART_Init();
    
    	unsigned char i = 0;	
    	unsigned char old = 0;
    	unsigned char data = 0;
    
    	while (1)
    	{
    		// PL 0->1
    		PL_low();
    		PL_high();
    
    		data = 0;
    		for (i = 0; i < 8; i++)
    		{
    			// CL 1
    			CL_high();
    
    			if ((PINB & _BV(0)))
    			{
    				data |= 1 << i;
    			}
    
    			// CL 0
    			CL_low();
    			
    		}
    
    		if (old != data)
    		{
    			RS_Send(data);
    			old = data;
    		}
    
    
    		RS_Send(0x55);
    
    		for (i = 0; i < 100; i++)
    		{
    			_delay_ms(10);
    		}
    	}
    }
    


    W wyniku nie dostaję nic poza kontrolnym bajtem 0x55 (przycisk przytrzymuje dłużej niż sekundę więc zmiany powinny być widoczne). Dodawałem opóźnienia przy zmianie PL i CL - bez zmian. Czy schemat jest błędny i/lub kod ?
  • #2 8549605
    Andrzej__S
    Poziom 28  
    codeking napisał:

    
       while (1) 
       { 
          // PL 0->1 
          PL_low(); 
          PL_high(); 
    
          data = 0; 
          for (i = 0; i < 8; i++) 
          { 
             // CL 1 
             CL_high(); 
    
             if ((PINB & _BV(0))) 
             { 
                data |= 1 << i; 
             } 
    
             // CL 0 
             CL_low(); 
              
          } 
    
          if (old != data) 
          { 
             RS_Send(data); 
             old = data; 
          } 
    
    
          RS_Send(0x55); 
    
          for (i = 0; i < 100; i++) 
          { 
             _delay_ms(10); 
          } 
       }
    


    Czegoś nie rozumiem. Najpierw zatrzaskujesz dane w rejestrze: PL_low(); PL_high();. Później w pętli przesuwasz te dane na wyjście Q7 połączone z wejściem procesora PD4.

    Nie rozumiem dlaczego pętla ma być wykonywana tylko 8 razy, skoro do odczytania masz 16 bitów (2 układy 74LS165 połączone w szereg).

    Nie wiem, dlaczego odczytujesz dane z PINB: if ((PINB & _BV(0))), skoro dane są na wejściu PD4. Nic dziwnego, że zmienna data jest zawsze równa 0.

    Nie wiem, dlaczego na wszystkich pinach portu B masz cały czas stan niski. Chyba, że multipleksowanie jest w dalszych planach :)
  • #3 8549875
    codeking
    Poziom 11  
    Ten kod to jakaś pomyłka :)

    Multipliksowanie będzie ale narazie chciałem sprawdzić czy to działa. Poprawiłem kod:
    
    
    #define DS_PORT PORTD
    #define DS_PIN  4
    #define PL_PORT PORTD
    #define PL_PIN  3
    #define CL_PORT PORTD
    #define CL_PIN  5
     
    #define DS_low()  DS_PORT &= ~_BV(DS_PIN)
    #define DS_high() DS_PORT |= _BV(DS_PIN)
    #define PL_low()  PL_PORT &= ~_BV(PL_PIN)
    #define PL_high() PL_PORT |= _BV(PL_PIN)
    #define CL_low()  CL_PORT &= ~_BV(CL_PIN)
    #define CL_high() CL_PORT |= _BV(CL_PIN)
    
    int main(void)
    {	
    	// 5 - PL
    	// 3 - CL
    	// 4 - D
    
            DDRB = 0xff;
            PORTB = 0x00; 
    
    	DDRD = 0x00;
    	
    	PL_PORT |= _BV(PL_PIN);
    	CL_PORT |= _BV(CL_PIN);
    
    	PORTD = 0x00;
    	
    	// włączenie RS232
    	USART_Init();
    
    	unsigned char i = 0;	
    	unsigned char old = 0;
    	unsigned char old2 = 0;
    	unsigned char data = 0;
    	unsigned char data2 = 0;
    
    	while (1)
    	{
    		// PL 0->1
    		PL_low();
    		PL_high();
    
    		data = 0;
    		data2 = 0;
    		for (i = 0; i < 16; i++)
    		{
    			// CL 1
    			CL_high();
    
    			if ((PIND & _BV(DS_PIN)))
    			{
    				if (i < 8)
    				{
    					data |= 1 << i;
    				}
    				else
    				{
    					data2 |= 1 << (i - 8);
    				}
    			}
    
    			// CL 0
    			CL_low();
    		}
    
    		if (old != data)
    		{
    			RS_Send(data);
    			old = data;
    		}
    
    		if (old2 != data2)
    		{
    			RS_Send(data2);
    			old2 = data2;
    		}
    
    		RS_Send(0x55);
    
    		for (i = 0; i < 100; i++)
    		{
    			_delay_ms(10);
    		}
    	}
    }
    


    Ale w dalszym ciągu nie działa.

    Wcześniej bawiłem się 74hc595 i działał bez problemu (zapalanie diod).
  • #4 8549959
    Andrzej__S
    Poziom 28  
    Przedtem miałeś:
    
       DDRD = _BV(5) | _BV(3); 
       PORTD = 0x00;
    

    Dlaczego zmieniłeś na:
    
       DDRD = 0x00;
    

    To akurat raczej było dobrze :)

    Tak na marginesie, możesz zadeklarować zmienne data oraz old jako uint16_t zamiast dwóch zmiennych unsigned char i nie trzeba będzie rozgraniczać w pętli if(i<8) itd. To nie błąd, ale będzie prościej napisane. Później możesz to sobie rozbić na:
    
             RS_Send( (char)data );
             RS_Send( (char)(data>>8) );
    
  • #5 8551297
    codeking
    Poziom 11  
    Kolejne poprawki (DDRD i uint16_t):
    
    #define DS_PORT PORTD
    #define DS_PIN  4
    #define PL_PORT PORTD
    #define PL_PIN  3
    #define CL_PORT PORTD
    #define CL_PIN  5
     
    #define DS_low()  DS_PORT &= ~_BV(DS_PIN)
    #define DS_high() DS_PORT |= _BV(DS_PIN)
    #define PL_low()  PL_PORT &= ~_BV(PL_PIN)
    #define PL_high() PL_PORT |= _BV(PL_PIN)
    #define CL_low()  CL_PORT &= ~_BV(CL_PIN)
    #define CL_high() CL_PORT |= _BV(CL_PIN)
    
    int main(void)
    {	
    	// 5 - PL
    	// 3 - CL
    	// 4 - D
    	
    	DDRD = _BV(PL_PIN) | _BV(CL_PIN);
    	PORTD = 0x00;
    	
    	// właczenie RS232
    	USART_Init();
    
    	unsigned char i = 0;	
    
    	uint16_t old = 0;
    	uint16_t data = old;
    
    	while (1)
    	{
    		// PL 0->1
    		PL_low();
    		PL_high();
    
    		data = 0;
    		for (i = 0; i < 16; i++)
    		{
    			// CL 1
    			CL_high();
    
    			if ((PIND & _BV(DS_PIN)))
    			{
    				data |= 1 << i;
    			}
    
    			// CL 0
    			CL_low();
    		}
    
    		if (old != data)
    		{
    			RS_Send((char)data);
    			RS_Send((char)(data >> 8));
    			old = data;
    		}
    
    		RS_Send(0x55);
    
    		for (i = 0; i < 100; i++)
    		{
    			_delay_ms(10);
    		}
    	}
    }
    
    


    W dalszym ciągu brak reakcji, gdy zacznę dotykać ścieżek paluchami to zaczyna wysyłać FF FF a później 00 00. Dodanie _delay_ms(1) po każdej funkcji _low() i _high() powoduje losowe dane przy dotykaniu paluchami. Natomiast zero reakcji na przytrzymanie przycisku. Czy schemat jest poprawny ? Nie brakuje w nim czegoś (kondensatory 100nF dałem przy każdym scalaku przy samym VCC) ?
  • #6 8551451
    rpal
    Poziom 27  
    czemu taki dziwny sposób obsługi klawiszy ?
  • #7 8551488
    Andrzej__S
    Poziom 28  
    codeking napisał:

    ... gdy zacznę dotykać ścieżek paluchami to zaczyna wysyłać FF FF...

    To może zrób z tego panel dotykowy :)

    A tak na poważnie. Właściwie taka właśnie wartość (0xFFFF) powinna być cały czas, dopóki nie naciśniesz jakiegoś klawisza. Dopiero naciśnięcie klawisza powinno spowodować pojawienie się stanu niskiego na danej linii, zakładając że spadek napięcia na diodzie i styku będzie mniejszy od 0,8V.
    Proponuję zmierzyć na wejściu układu 74LS165, jakie masz napięcie na danej linii przed i po wciśnięciu przycisku. Dobrze byłoby sprawdzić wszystkie połączenia i wykluczyć ewentualne zwarcia.

    codeking napisał:

    Dodanie _delay_ms(1) po każdej funkcji _low() i _high() powoduje losowe dane...

    Pojemność przewodów i ścieżek może spowodować, że narastanie zboczy będzie dosyć wolne, w związku z czym trzeba będzie dać jakieś opóźnienia, szczególnie podczas multipleksowania. Teraz jednak w układzie testowy, kiedy na wszystkich kolumnach masz zera i przycisk jest przez dłuższy czas wciśnięty, za którymś razem powinno go odczytać prawidłowo.
  • #8 8551535
    codeking
    Poziom 11  
    rpal napisał:
    czemu taki dziwny sposób obsługi klawiszy ?

    To ma być dodatkowa "klawiatura" do PC odpowiedno obsłużona dodatkowym oprogramowaniem.

    Andrzej__S, z tego co piszesz, to układ nie będzie zbyt "przyjazny" (odporny na zakłócenia) i podpinanie przycisków na dłuższych przewodach (ok. 50cm) odpada. W takim wypadku będę musiał z niego zrezygnować i zrobić to na jednej Atmedze16 bez dodatkowych scalaków.
  • #9 8551631
    Andrzej__S
    Poziom 28  
    codeking napisał:

    ... układ nie będzie zbyt "przyjazny" (odporny na zakłócenia) i podpinanie przycisków na dłuższych przewodach (ok. 50cm) odpada.

    Mógłbyś dać mikrokontroler bezpośrednio przy klawiaturze, a dane do komputera i tak wysyłasz przez RS232, z tego co zauważyłem. Pozostanie Ci tylko pojemność ścieżek. Jak nie będą zbyt gęsto, to powinno być OK. Problem w tym, że musiałbyś to jakoś zasilić osobnym przewodem.

    codeking napisał:

    W takim wypadku będę musiał z niego zrezygnować i zrobić to na jednej Atmedze16 bez dodatkowych scalaków.

    Obawiam się, że to nie rozwiąże problemów związanych z pojemnością 50-centymetrowego kabla. Owszem, odczyt równoległy jest na pewno szybszy od szeregowego, jednak czy będzie bardziej odporny na zakłócenia, tego nie jestem pewien.
  • #10 8551649
    rpal
    Poziom 27  
    Osobiście nie widzę problemu, nie lepiej użyć zwykłej matrycowej klawiatury i te dane słać po RS232 ? Jak PCB będzie pod klawiaturą matrycową to długości sciezek będą minimalne a rsr232 bedzie wysyłał swoje kody na odległości rzędu wielu metrów. Bardzo się namęczysz robiąc to tak jak robisz tylko czy w ogole warto.
REKLAMA