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] Panel dotykowy - jak oprogramować.

garyxppro 26 Sty 2011 21:26 8317 31
REKLAMA
  • #1 9061704
    garyxppro
    Poziom 10  
    Witam Wszystkich zainteresowanych tematem.

    Otóż mam problem od dwóch tygodni męczy mnie pewien problem, a dokładnie zmuszenie ekranu dotykowego do współpracy z ATMega16. Ekran z telefonu HTC Tytn, kupionego na alledrogo za 20zl.

    Ekran dotykowy (rezystancyjny) sprawdziłem omomierzem X+ i X- oraz Y+ i Y- jest ok (reaguje zwiększoną rezystancją na dotyk).
    [ATMEGA16][C] Panel dotykowy - jak oprogramować.

    Panel jest podpięty z ATMegą pod PA1: x-, PA4: x+, PA2: y+ i PA3: y-.

    AVCC podpiety przez kondensator 100nF do masy i dławik 10uH do VCC (zgodnie z dokumentacją Atmela - AVR341: Four and five-wire Touch Screen Controller), GND=GND oraz AREF 100nF.
    [ATMEGA16][C] Panel dotykowy - jak oprogramować.

    Kod przyznam, że zerżnięty z innej stronki ( Link ), gdyż nie programowałem jeszcze przetworników ADC, nie bardzo wiem za bardzo o co tu chodzi.

    Oto kod, który wykorzystuje:

    
    int16_t  l;
    uint16_t  h;
    uint16_t  l1;
    uint16_t  h1;
    
    void	read_x(void)
    {
    	DDRA = 0b00010010; // Output on PA4(5V) and PA1(GND), Input on PA4(ADC)
    	sbi(PORTA, 4); //pull PA4 to 5V
    	cbi(PORTA, 1); //pull PA1 to GND
    	
    	_delay_ms(1);
    	
    	ADMUX = (1 << MUX1);//ADC2
    	ADCSRA = (1 << ADEN)|(1 << ADSC)|(1<<ADPS2)|(1<<ADPS1);
    	
    	while(ADCSRA & (1 << ADSC));
    	l = ADCL;
    	h = ADCH & 0x03;
    	h = h << 8;
    	h = h + l;
    	 
    }
    
    
    void read_y(void)
    {
    	DDRA = 0b00001100; // Output on PC2(5V) and PC3(GND), Input on PA4(ADC)
    	sbi(PORTA, 2); //pull PA2 to 5V
    	cbi(PORTA, 3); //pull PA3 to GND
    	
    	_delay_ms(1);
    	
    	ADMUX = (1 << MUX2);//ADC4
    	ADCSRA = (1 << ADEN)|(1 << ADSC)|(1<<ADPS2)|(1<<ADPS1);
    	
    	while(ADCSRA & (1 << ADSC));
    	l1 = ADCL;
    	h1 = ADCH & 0x03;
    	h1 = h1 << 8;
    	h1  = h1 + l1;
    }
    


    Odczytywane współrzędne przesyłam na RS'a:


    
    	znak = 'A';
    	for (;;)
    	{
    		USART_Transmit( znak );
    		znak = USART_Receive();
    
    		USART_write_text ( "X: " );
    		read_x();
    		USART_write_number( (int)h );
    
    		USART_write_text ( ", Y: " );
    		read_y();
    		USART_write_number( (int)h1 );
    		
    		USART_write_text ( "\r\n" );
    	}
    


    Nie wiem dlaczego, ale za każdym razem otrzymuje 1023 jako wynik X i Y:

    
     X: 1023, Y: 1023
     X: 1023, Y: 1023
    


    W trakcie trwania programu, mogę także zmierzyć miernikiem napięcia np. osi X i zmienia się zależnie od nacisku od 5V do 0V .

    Domyślam się iż jest to błahostka, ale męczę się już dwa tygodnie, próbowałem różnych kodów z różnych stron, w tym avrlib i inne pochodne do obsługi adc (jednak ten, który wybrałem wydaje mi się najbardziej 'czytelny').

    Dodam jeszcze że układ chodzi na kwarcu 8MHz.

    Pozdrawiam Serdecznie

    Poprawiłem tytuł - regulamin p.11.1
    [zumek]
  • REKLAMA
  • #2 9062146
    piotrva
    VIP Zasłużony dla elektroda
    A nie trzeba przypadkiem panelu podpiąć jako dzielnik rezystancyjny?
    Poza tym sprawdź czy wogóle adc działa popijając zamiast panelu potencjometr
  • #3 9062148
    Konto nie istnieje
    Konto nie istnieje  
  • #4 9062695
    garyxppro
    Poziom 10  
    Witam

    Cytat:
    A nie trzeba przypadkiem panelu podpiąć jako dzielnik rezystancyjny?

    Panel dotykowy wg. producenta można bezpośrednio podpiąć pod porty ADC (Atmel) byle na jak najkrótszym kablu (mam około 5cm kabel miedziany podpięty pod nóżki ATMegi16) oraz znalazłem niedawno także stronkę z opisem jak podłączyć oraz źródłami w c, ale na ATmege128 wykorzystujący bibliotekę avrlib, z którą także kilka dni się męczyłem - bez skutku.
    [ATMEGA16][C] Panel dotykowy - jak oprogramować.

    Procesor jest nowy, zresztą na dwóch uC sprawdzałem.

    Cytat:
    Poza tym sprawdź czy w ogóle adc działa podpinając zamiast panelu potencjometr

    Nie mam na chwile obecną chwile żadnego potencjometru, ale jutro się zaopatrzę i przetestuje.

    Cytat:
    PORTC z PORTA się pomieszały

    PORTC to ADC w ATmega168.
    PORTA to ADC w Atmega16.
    PORTF to ADC w ATmega128.
    etc :D

    Analogicznie musiałem zmienić w kodzie tylko porty PORTC na PORTD i DDRC na DDRA.

    Pozdrawiam
  • Pomocny post
    #5 9063197
    ktrot
    Poziom 20  
    Ustaw napięcie referencyjne na AREF:

    ADMUX=(1<<MUX1)|(1<<REFS0)
  • #6 9063513
    Konto nie istnieje
    Poziom 1  
  • #7 9063605
    Konto nie istnieje
    Konto nie istnieje  
  • #8 9063722
    Konto nie istnieje
    Poziom 1  
  • REKLAMA
  • #9 9063910
    Konto nie istnieje
    Konto nie istnieje  
  • #10 9063980
    LordBlick
    VIP Zasłużony dla elektroda
    Przecież tak pisany kod jest niewygodny - wystarczy #define PORT_ADC PORTD i wszędzie dalej posługiwać się PORT_ADC, PORT_ADC-1 dla DDR i PORT_ADC-2 dla PIN. Taka możliwość jest dostępna nawet dla asemblera z AVRStudio, a sporo ludzi się tym nie posługuje, na tym form jeszcze nie spotkałem takiego... ;)
    Co więcej:
    #define DDR(_PORT) (_PORT-1)
    #define PIN(_PORT) (_PORT-2)
    No i potem przykładowo w kodzie:
    DDR(PORT_ADC)=0b01110110;
    Port_keys=PIN(_PORT_KEYBOARD);
  • #11 9065063
    garyxppro
    Poziom 10  
    Witam

    Już działa:D Dziękuje za zainteresowanie tematem. Tak myślałem, że będzie to błahostka.

    Zabrakło mi tylko napięcia referencyjnego:

    Cytat:
    ktrot:
    Ustaw napięcie referencyjne na AREF:

    ADMUX=(1<<MUX1)|(1<<REFS0)

    Dzięki wielkie!

    Tego mi właśnie brakowało: "|(1<<REFS0)".

    Tak teraz wygląda funkcja "read_x".

    void	read_x(void)
    {
    	DDRA = 0b00010010; // Output on PA4(5V) and PA1(GND), Input on PA4(ADC)
    	sbi(PORTA, 4); //pull PA4 to 5V
    	cbi(PORTA, 1); //pull PA1 to GND
    	
    	_delay_ms(1);
    	
    	//ADMUX = (1 << MUX1);//ADC2
    	ADMUX = (1<<MUX1)|(1<<REFS0);
    	ADCSRA = (1 << ADEN)|(1 << ADSC)|(1<<ADPS2)|(1<<ADPS1);
    	
    	while(ADCSRA & (1 << ADSC));
    	l = ADCL;
    	h = ADCH & 0x03;
    	h = h << 8;
    	h = h + l;
    	 
    }


    A tak wyjście z terminala po przejechaniu palcem na panelu:
     X: 452, Y: 871
     X: 552, Y: 935
     X: 627, Y: 941
     X: 618, Y: 939
     X: 628, Y: 927
     X: 637, Y: 911
     X: 623, Y: 885
     X: 643, Y: 875
     X: 641, Y: 859
     X: 654, Y: 843
     X: 668, Y: 839
     X: 685, Y: 855
     X: 550, Y: 783
     X: 1021, Y: 1023
    


    Mam nadzieje, że komuś się przyda powyższa lekcja:) Jeszcze dziś zamieszczę schemat wraz z kompletnym kodem do Atmegi16.

    Pozdrawiam Serdecznie
  • REKLAMA
  • #12 9099341
    pywoo
    Poziom 18  
    Witam. Odświeże trochę temat bo też skorzystałem z wyżej podanego przykładu z tym że na razie wyświetlam x i y na wyświetlaczu graficznym. Kod sprawdzania panela dotykowego mam można powiedzieć że identyczny.
    Nie wiem tylko dlaczego gdy nie dotykam panelu to zwraca mi współrzędne mniej więcej na środku. Przy odczycie podczas dotykania jest ok. Co może być przyczyną ?

    Panel dotykowy ma podłączony w następujący sposób:
    PA1 -> X-
    PA2 -> Y+
    PA3 -> Y-
    PA4 -> X+
    
    void   read_x(void) 
    { 
       DDRA = 0b00010010; // Output on PA0(5V) and PA1(GND), Input on PA0(ADC) 
       sbi(PORTA, 4); //pull PA4 to 5V 
       cbi(PORTA, 1); //pull PA1 to GND 
        
       _delay_ms(1); 
        
       ADMUX = (1 << MUX1)|(1<<REFS0);//ADC2 
       ADCSRA = (1 << ADEN)|(1 << ADSC)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); 
        
       while(ADCSRA & (1 << ADSC)); 
       l = ADCL; 
       h = ADCH & 0x03; 
       h = h << 8; 
       h = h + l; 
        
    } 
    
    
    void read_y(void) 
    { 
       DDRA = 0b00001100; // Output on PA2(5V) and PA3(GND), Input on PA4(ADC) 
       sbi(PORTA, 2); //pull PA2 to 5V 
       cbi(PORTA, 3); //pull PA3 to GND 
        
       _delay_ms(1); 
        
       ADMUX = (1<<MUX2)|(1<<REFS0);//ADC4
       
       ADCSRA = (1 << ADEN)|(1 << ADSC)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); 
        
       while(ADCSRA & (1 << ADSC)); 
       l1 = ADCL; 
       h1 = ADCH & 0x03; 
       h1 = h1 << 8; 
       h1  = h1 + l1; 
    } 
    
    
  • #13 9099472
    garyxppro
    Poziom 10  
    Witam

    Panel jest nowy?

    Może ten panel ma mniejszą rezystancję wewnętrzną niż ten od HTC Tytn, za każdym razem jak włączasz zasilanie musisz wykonać kalibrację obu osi (wg. narożników) i wtedy wyliczasz według odczytanych przy kalibracji wartości, obie wartości osi X i Y.

    Swoją drogą, kiedyś czytałem że niektóre panele mogą dłużej się 'ładować' - dlatego spróbuj użyć "buforowania" - czyli odczytaj kilka wartości i wylicz średnią.

    Albo może ten panel jest uszkodzony lub zużyty...

    Pozdrawiam
  • #14 9099590
    pywoo
    Poziom 18  
    Panel jest nowy. Wcześniej nie był używany. Dostosowany do graficznego LCD 240x128. Mierzyłem rezystancję linii panelu. Między x+ i x- 711ohm między y+ i y- 232ohm. W trakcie pomiaru np między y- i x+ rezystancja pojawia się dopiero po dotknięciu panelu. Więc panel jest sprawny.
    Rozumiem gdyby w czasie gdy nie jest dotykany zwrócił jakieś wartości z po za obszaru dotyku. Uśrednianie nic mi tu nie da bo po prostu otrzymam tylko dokładniejsze współrzędne środkowe.
    ................
    Rzeczywiście panel ma jakiś swój czas ładowania bo gdy zwiększyłem opóźnienie czasowe po zmianie pinów zasilających na 20ms to współrzędne w spoczynku przesunęły się prawie poza obszar wskazań. Niestety razem to już daje opóźnienie 40 ms trochę dużo jak dla mnie.
  • #15 9100180
    Konto nie istnieje
    Poziom 1  
  • REKLAMA
  • #16 9108117
    pywoo
    Poziom 18  
    Super. Dzięki za podpowiedź. Zrobiłem tak i działa :) Teraz musze tylko sobie sformatować współrzędne dobrze i poszukać cos o tym jak kalibrację zrobić. Co prawda panel ma być z założenia obsługiwany tylko palcem ale i tak trzeba by skalibrować jakoś.
  • #17 10218804
    elmielony
    Poziom 2  
    Witam, będę robił podobny projekt. Zastanawiam się nad połączeniem taśmy z panelu dotykowego do płytki. Czy są odpowiednie złącza które można na stałe przylutować do płytki i tylko włożyć taśmę z panelu. Za wszelki informacje dziękuje. Pozdrawiam.
  • #19 10220027
    pywoo
    Poziom 18  
    W moim przypadku złącze było dostarczone razem z panelem dotykowym.
  • #20 10220707
    INTOUCH
    Poziom 30  
    Współżędna "Z" na panelu duwymiarowym. Mozna jeśniej?

    Proszę poprawić post - regulamin pkt.3.1.13 [dzimi]
  • #21 10220747
    Brutus_gsm
    Poziom 25  
    W przypadku paneli dotykowych współrzędna Z określa siłę nacisku.
  • #22 10221148
    INTOUCH
    Poziom 30  
    Z jakich uzyskanych danych z panela można ją wyliczyć?
  • #23 10221163
    Konto nie istnieje
    Poziom 1  
  • #24 10221186
    Brutus_gsm
    Poziom 25  
    Przecież kolega podał gotowy "algorytm" na uzyskanie tej informacji.

    atom1477 napisał:
    Przecież to normalne zachowanie panelu.
    Żeby było dobrze to pomiędzy odczytami osi X i Y trzeba jeszcze odczytywać "współrzędną" Z.
    W zasadzie to od Z trzeba zaczynać i dopiero jak będzie odpowiednia do odczytywać X i Y.
    Odczyt Z:
    X- i X+: Output i na GND
    Y- i Y+: Input i podciąganie do VCC.
    Czekamy kilka ms i odczytujemy wartość ADC z Y- albo Y+.
    Jak bliska VCC to znaczy że panel nie jest dotknięty.
    Jak bliska GND to znaczy że jest dotknięty.
    Gdy mamy blisko GND (czyli panel dotknięty) to dopiero zabieramy się za odczyt osi X i Y.
    Swoją drogą przy odrobinie szczęścia można z tej "współrzędnej" Z zrobić pożytek, na przykład uzależnić od niej grubość rysowanej linii jeżeli ktoś robi jakiegoś Painta na panelu dotykowym.
  • #25 10221662
    mirekk36
    Poziom 42  
    Proponuję też panowie zainteresować się scalaczkami, które zrobią to za was a ich obsługa programowa np po I2C jest prosta i daje dużo więcej możliwości na inne sprawy w programie.

    Przykład na hmm mniej dostępnym scalaku stmpe811 jest np tutaj:

    https://www.elektroda.pl/rtvforum/topic2151096.html

    ale można także użyć dostępnych scalaków z rodziny AR1000 np AR1020, które działają na podobnej zasadzie.

    Jak spróbowałem, to stwierdziłem, że nie ma co się męczyć samemu to ruszać na ADC. Tzn tak dla nauki i sprawdzenia - pewnie że warto, ale już w jakichś swoich projekcikach to na pewno wolałbym taki dedykowany scalaczek użyć.
  • #26 10372454
    elmielony
    Poziom 2  
    Witam. Mam problem ze sprawdzeniem warunku dotknięcia panelu. Oś x i y sczytuje odpowiednio, jednak wykrycie dotyku poprzez z - tak jak wyżej jeden z panów opisał mi nie wychodzi. Nie do końca wiem jaki warunek w C napisać odnośnie tego :
    "Czekamy kilka ms i odczytujemy wartość ADC z Y- albo Y+.
    Jak bliska VCC to znaczy że panel nie jest dotknięty.
    Jak bliska GND to znaczy że jest dotknięty. "

    Czy za GND mam przyjąć 0 a za VCC 5? Dziękuje za podpowiedzi.
  • #27 10373516
    piotrva
    VIP Zasłużony dla elektroda
    Tak, zwykle w układach TTL 0V to GND (odczyt a 10 bit ADC = 0) a 5V to VCC (ADC=1023). U mnie wartość ta oscyluje w okolicach 800-900 (wartość ADC) dla średnio silnego nieprzypadkowego nacisku.
  • #28 10373710
    Konto nie istnieje
    Poziom 1  
  • #29 12165704
    MardukGD
    Poziom 10  
    Przepraszam za odkop, ale mam pytanie. Czy nie można np. podłączyć dwóch z tych pinów touch panelu na stałe do Vcc i użyć do odczytu pozycji X i Y (no i przy okazji Z) tylko dwóch wejść uP (zamiast czterech)?
REKLAMA