AVR Touchscreen сенсорный экран на ATmega8
В этой заметке рассмотрим принцип работы с тачскрином (англ. Touchscreen) и подключим его к AVR микроконтроллеру, а точнее к ATmega8. Идея использования тачскрина пришла ко мне, когда я хотел отказаться от использования клавиш в своем проекте метеостанции. Метеостанция выводила данные на графический ЖКИ WG12864A. Поискав в Интернете графические ЖКИ с предустановленной сенсорной панелью я уже расстроился, что таких у нас (г. Киев) не продают, либо их стоимость зашкаливает.
Далее я натолкнулся на сенсорные панели, которые можно прикрепить уже на свой ЖКИ с помощью двухстороннего скотча. Такая штука нашлась, и называется TS12864ARNB, предназначена для индикатора WG12864A. Также нашлись в наличии панельки для WG12864C (немного другие размеры и распиновка чем у WG12864A), называются TS12864CRNA. Купив такую панельку для своего ЖКИ я начал экспериментировать. Вообще TS12864ARNB – резистивная сенсорная панель с 4-х проводным интерфейсом. Рассмотрим принцип ее работы:
Основу тачскрина представляет тонкое стекло, на которое нанесено две тонких резистивных пленки, разделенных между собой шариками изоляторами и с внешней стороны покрытых защитным слоем. Резистивные пленки способны проводить ток и имеют крест-накрест расположенные электроды (X-,X+,Y-,Y+). При прикосновении, проводящие пленочки замыкаются и образуют между собой контакт, при этом точка прикосновения образует простой резистивный делитель:
Благодаря этому координаты прикосновения можно легко вычислить. Для этого нужно с помощью АЦП произвести 2 измерения (но на практике задействуется 4 канала АЦП микроконтроллера). Сперва на заднюю пленку подаем постоянное напряжение, например наши +5В (на вывод X+ подаем 5В, а на вывод Х подключаем к земле). При этом, на каждом горизонтальном участке заднего слоя, ток создает падение напряжение, пропорционально длине участка, которое и нужно нам считать. Щупом послужит передний резистивный слой, электроды которого замыкаются и подаются на вход АЦП. Это будет Х-вая координата нажатия. Аналогично считывается и У координата. Определить нажатие можно подав так: подаем на У- +5В, а все остальные выводы ставим в Hi-Z состояние, появления на них нулевого потенциала будет сигналом того, что произошло прикосновение. Продемонстрируем сказанное, соорудим макет:
Источник тактирования – внутренний RC генератор на 1МГц, резистор R1 – 10 кОм, конденсатор С7 – 0,1мкФ. Светодиод D1 сигнализирует, что на схему подается питание, R2 – 1кОм. Резистор R3 ограничительный, для подсветки ЖКИ, 17 Ом, VR1 – переменный резистор на 10кОм, для регулировки контраста. Заодно подключим к микроконтроллеру графический ЖКИ WG12864A, на котором будем выводить точки с координатами прикосновения, считанными с тачскрина. Получиться некий мини-планшет, на котором можно будет рисовать. Код программы выглядит вот так:
#include <avr/io.h> //Стандартная библиотека ввода/вывода #include "symbol.h" #define DI 0 #define RW 1 #define E 2 #define CS1 3 #define CS2 4 #define RST 5 //Программа формирвоания задержки void pause (unsigned int a) { unsigned int i; for (i=a;i>0;i--); } //ПРограмма передачи в ЖКИ данных void lcd_dat (unsigned char data) { PORTD=data; //Выводим данные PORTB|=_BV(DI); //Говорим дисплею что передаются данные asm("nop"); PORTB|= _BV(E); //Импульс записи asm("nop"); PORTB&=~_BV(E); PORTB&=~_BV(DI); } //ПРограмма передачи в ЖКИ комманды void lcd_com (unsigned char comm) { PORTD=comm; //Выводим команду asm("nop"); PORTB|= _BV(E); // Импульс записи asm("nop"); PORTB&=~ _BV(E); } //Программа установки курсора по координатам void gotoxy (unsigned char x, unsigned char y) { if (x<64) PORTB|=_BV(CS1); //Если x<64 включаем CS1 else { PORTB|=_BV(CS2); //else включаем CS2 x=x-64; } lcd_com(0x40+x); //Выставляем X координату lcd_com(0xb8+y/8); //Выставляем Y координату } //Программа очистки экрана void clear_screen (void) { unsigned char i,j; PORTB|=_BV(CS1)|_BV(CS2); //Включаем оба чипа for (j=0;j<8;j++) { lcd_com(0xb8+j); for (i=0;i<64;i++) lcd_dat(0x00); //Очищаем } } //Программа инициализации графического ЖКИ void wg12864_init(void) { DDRD=0xff; //PD0-7 как выхода PORTD=0x00; PORTB=_BV(RST)|_BV(CS1)|_BV(CS2); //Включаем оба чипа DDRB=_BV(DI)|_BV(RW)|_BV(E)|_BV(CS1)|_BV(CS2)|_BV(RST); //PB0-5 как выхода asm("nop"); lcd_com(0x3f); //Разрешаем отображение lcd_com(0xc0); //Устанавливаем начало отображения lcd_com(0x40); //Ставим X=0 lcd_com(0xb8); //Ставим Y=0 clear_screen(); PORTB&=~(_BV(CS1)|_BV(CS2)); } //ПРограмма прорисовки пикселя на ЖКИ void put_pixel (const unsigned char x, const unsigned char y, const unsigned char color) { unsigned char temp=0; PORTB=_BV(RST); if ( (x>128)||(y>64) ) return; gotoxy (x,y); PORTD=0xff; DDRD=0x00; //PD0-7 как входа PORTB|=(_BV(RW)|_BV(DI)); //Считываем данные pause(1); PORTB|= _BV(E); asm("nop"); PORTB&=~_BV(E); asm("nop"); PORTB|= _BV(E); asm("nop"); temp=PIND; PORTB&=~_BV(E); if (color==1) temp|= _BV(y%8); //Выставляем/снимаем нужный нам бит else temp&=~_BV(y%8); PORTB&=~(_BV(RW)|_BV(DI)); DDRD=0xff; //PD0-7 как выхода asm("nop"); gotoxy(x,y); //Переходим к X,Y lcd_dat(temp); //Записываем данные PORTB=_BV(RST); } int sign (int x) { if (x<0) return -1; if (x>0) return 1; return 0; } int abs (int x) { if (x<0) return -x; else return x; } //Программа прорисовки линии на ЖКИ void line (unsigned char x1,unsigned char y1,unsigned char x2, unsigned char y2,unsigned char color) { int dx,dy,i,sx,sy,check,e,x,y; dx=abs(x1-x2); dy=abs(y1-y2); sx=sign(x2-x1); sy=sign(y2-y1); x=x1; y=y1; check=0; if (dy>dx) { dx=dx+dy; dy=dx-dy; dx=dx-dy; check=1; } e=2*dy - dx; for (i=0;i<=dx;i++) { put_pixel(x,y,color); if (e>=0) { if (check==1) x=x+sx; else y=y+sy; e=e-2*dx; } if (check==1) y=y+sy; else x=x+sx; e=e+2*dy; } } //ПРограмма прорисовки прямоугольника на ЖКИ void rectangle (unsigned char x1,unsigned char y1,unsigned char x2, unsigned char y2,unsigned char color) { line (x1,y1,x2,y1,color); line (x2,y1,x2,y2,color); line (x2,y2,x1,y2,color); line (x1,y2,x1,y1,color); } //Программа вывода текста на ЖКИ void put_char (unsigned char x0, unsigned char y0, unsigned char code, unsigned char mode) { unsigned char i,x,y; x=x0; y=y0; PORTB=_BV(RST)|_BV(CS1); if ( (x>128)||(y>64) ) return; for (i=0;i<6;i++) { if (x>=64) { //Включить CS2 x=x-64; PORTB|=_BV(CS2); PORTB&=~_BV(CS1); } lcd_com(0x40+x); //Перейти X,Y lcd_com(0xb8+y); if (i<=4) { if (mode==1) lcd_dat(~sym[code][i]);//Пишем колонку else lcd_dat (sym[code][i]);//Пишем инвертированную колонку } if (i==5) { if (mode==1) lcd_dat(0xff); //Рисуем разделитель else lcd_dat(0x00); //Рисуем инвертированный разделитель } x=x+1; } } unsigned int getU(void) //Взять результат с АЦП { unsigned int v; v=(ADCL/64+ADCH*4)*5; return v; } //Основная программа int main(void) { //Декларация переменных unsigned long int u=0,x,y,x0,y0; pause(5000); //Пауза для включения ЖКИ wg12864_init(); //Инициализация ЖКИ rectangle(0,0,127,63,1); //Рисуем область отображения ADCSRA=(1<<ADEN)|(1<<ADPS0); //АЦП включен, прескаллер=/1 while(1) { DDRC=0x01; //Ждем нажатия PORTC=0x00; pause(10); ADMUX=(1<<REFS0)|(1<<ADLAR)|(1<<MUX1)|(1<<MUX0); ADCSRA|=(1<<ADSC); while ((ADCSRA&_BV(ADIF))==0x00) //Ждем окончания преобразования ; u=getU(); if (u<10) { //Если было нажатие DDRC=0x0c; //Считываем X координату PORTC=0x08; pause(1); ADMUX=(1<<REFS0)|(1<<ADLAR)|(1<<MUX0); ADCSRA|=(1<<ADSC); while ((ADCSRA&_BV(ADIF))==0x00) // Ждем окончания преобразования ; x=getU(); DDRC=0x03; // Считываем У координату PORTC=0x01; pause(1); ADMUX=(1<<REFS0)|(1<<ADLAR)|(1<<MUX1)|(1<<MUX0); ADCSRA|=(1<<ADSC); while ((ADCSRA&_BV(ADIF))==0x00) // Ждем окончания преобразования ; y=(getU()-495)/(4105/64); //Вычисляем координаты нажатия x=(x-400)/(4265/128); if ((abs(x-x0)<5)&&(abs(y-y0)<5)) put_pixel(x,y,1); //Рисуем пиксел x0=x; y0=y; } } return 1; }
Думаю особо комментировать не нужно. Все словесно описано выше. А функции работы с WG12864A описаны здесь.
Для тех, кто поленился подключить ЖКИ, могу посоветовать выводить данные о прикосновении по UART, убрав все функции работы с WG12864A и добавив в программу такие строчки:
Инициализация UART (перед вечным циклом):
UBRRH = 0x00; //Set bitrate 9600 bit/sec at 4Mhz tick UBRRL = 0x19; UCSRA = 0x00; UCSRB = (1<<TXEN); UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
Также добавить функцию передачи данных по UART:
void USART_transmit(unsigned char data ) { while ( !( UCSRA & (1<<UDRE)) ) ; UDR = data; }
Которой нужно будет поручить передать данные о нажатии:
USART_transmit(x); USART_transmit(y);
Что из этого получилось, можно увидеть на видео:
Я специально не налаживал тачпанель на ЖКИ, потому как видеокамера давала очень плохую картинку и не можно было иметь представления что твориться на экране.
Так просто рисовать каряки и смайлики быстро надоело, захотелось чего-то еще. Сделал сенсорную клавиатуру, на 12 клавиш. Цифры с 0 по 9 + сброс и backspace. И дописал код, который после определения координат нажатия, смотрит, на какую клавишу нажали, и если таковая была, то мигает кнопкой на экране и добавляет введенный символ:
Клавиатурный буфер организован подобно буферу в статье про символьный ЖКИ и матричную клавиатуру. Константа MAX_NUMBER определяет размер буфера, переменная number_count – количество цифр в буфере, а массив data[MAX_NUMBER] – собственно данные. Функция key_pressed (x,y); по заданным координатам, определяет какая клавиша была нажата (или была ли вообще нажата хоть одна) и заносит данные в буфер, а функция write_data (); - выводит содержимое буфера на ЖКИ. В остальном программа идентична предведущей.
#include <avr/io.h> #include "symbol.h" #define DI 0 #define RW 1 #define E 2 #define CS1 3 #define CS2 4 #define RST 5 #define MAX_NUMBER 6 //Максимальное число цифр unsigned char data [MAX_NUMBER]={}; //Буфер клавиатуры unsigned char number_count=0; //Количество цифр в буфере void pause (unsigned int a) { unsigned int i; for (i=a;i>0;i--); } void lcd_dat (unsigned char data) { PORTD=data; //Выводим данные PORTB|=_BV(DI); //Говорим дисплею что передаются данные asm("nop"); PORTB|= _BV(E); //Импульс записи asm("nop"); PORTB&=~_BV(E); PORTB&=~_BV(DI); } void lcd_com (unsigned char comm) { PORTD=comm; //Выводим команду asm("nop"); PORTB|= _BV(E); // Импульс записи asm("nop"); PORTB&=~ _BV(E); } void gotoxy (unsigned char x, unsigned char y) { if (x<64) PORTB|=_BV(CS1); //Если x<64 включаем CS1 else { PORTB|=_BV(CS2); //else включаем CS2 x=x-64; } lcd_com(0x40+x); //Выставляем X координату lcd_com(0xb8+y/8); //Выставляем Y координату } void clear_screen (void) { unsigned char i,j; PORTB|=_BV(CS1)|_BV(CS2); //Включаем оба чипа for (j=0;j<8;j++) { lcd_com(0xb8+j); for (i=0;i<64;i++) lcd_dat(0x00); //Очищаем } } void wg12864_init(void) { DDRD=0xff; //PD0-7 как выхода PORTD=0x00; PORTB=_BV(RST)|_BV(CS1)|_BV(CS2); //Включаем оба чипа DDRB=_BV(DI)|_BV(RW)|_BV(E)|_BV(CS1)|_BV(CS2)|_BV(RST); //PB0-5 как выхода asm("nop"); lcd_com(0x3f); //Разрешаем отображение lcd_com(0xc0); //Устанавливаем начало отображения lcd_com(0x40); //Ставим X=0 lcd_com(0xb8); //Ставим Y=0 clear_screen(); PORTB&=~(_BV(CS1)|_BV(CS2)); } void put_pixel (const unsigned char x, const unsigned char y, const unsigned char color) { unsigned char temp=0; PORTB=_BV(RST); if ( (x>128)||(y>64) ) return; gotoxy (x,y); PORTD=0xff; DDRD=0x00; //PD0-7 как входа PORTB|=(_BV(RW)|_BV(DI)); //Считываем данные pause(1); PORTB|= _BV(E); asm("nop"); PORTB&=~_BV(E); asm("nop"); PORTB|= _BV(E); asm("nop"); temp=PIND; PORTB&=~_BV(E); if (color==1) temp|= _BV(y%8); //Выставляем/снимаем нужный нам бит else temp&=~_BV(y%8); PORTB&=~(_BV(RW)|_BV(DI)); DDRD=0xff; //PD0-7 как выхода asm("nop"); gotoxy(x,y); //Переходим к X,Y lcd_dat(temp); //Записываем данные PORTB=_BV(RST); } int sign (int x) { if (x<0) return -1; if (x>0) return 1; return 0; } int abs (int x) { if (x<0) return -x; else return x; } void line (unsigned char x1,unsigned char y1,unsigned char x2, unsigned char y2,unsigned char color) { int dx,dy,i,sx,sy,check,e,x,y; dx=abs(x1-x2); dy=abs(y1-y2); sx=sign(x2-x1); sy=sign(y2-y1); x=x1; y=y1; check=0; if (dy>dx) { dx=dx+dy; dy=dx-dy; dx=dx-dy; check=1; } e=2*dy - dx; for (i=0;i<=dx;i++) { put_pixel(x,y,color); if (e>=0) { if (check==1) x=x+sx; else y=y+sy; e=e-2*dx; } if (check==1) y=y+sy; else x=x+sx; e=e+2*dy; } } void rectangle (unsigned char x1,unsigned char y1,unsigned char x2, unsigned char y2,unsigned char color) { line (x1,y1,x2,y1,color); line (x2,y1,x2,y2,color); line (x2,y2,x1,y2,color); line (x1,y2,x1,y1,color); } void put_char (unsigned char x0, unsigned char y0, unsigned char code, unsigned char mode) { unsigned char i,x,y; x=x0; y=y0; PORTB=_BV(RST)|_BV(CS1); if ( (x>128)||(y>64) ) return; for (i=0;i<6;i++) { if (x>=64) { //Включить CS2 x=x-64; PORTB|=_BV(CS2); PORTB&=~_BV(CS1); } lcd_com(0x40+x); //Перейти X,Y lcd_com(0xb8+y); if (i<=4) { if (mode==1) lcd_dat(~sym[code][i]);//Пишем колонку else lcd_dat (sym[code][i]);//Пишем инвертированную колонку } if (i==5) { if (mode==1) lcd_dat(0xff); //Рисуем разделитель else lcd_dat(0x00); //Рисуем инвертированный разделитель } x=x+1; } } unsigned int getU(void) //Взять результат с АЦП { unsigned int v; v=(ADCL/64+ADCH*4)*5; return v; } void key_pressed (unsigned char x, unsigned char y) //Вычисление нажатой клавиши { if ( (x>68)&&(y>14)&&(x<76)&&(y<24) ) { rectangle (68,14,76,24,0); pause(10000); rectangle (68,14,76,24,1); if (number_count<MAX_NUMBER){ data[number_count]=0x07; number_count++; } return; } if ( (x>68)&&(y>30)&&(x<76)&&(y<40) ) { rectangle (68,30,76,40,0); pause(10000); rectangle (68,30,76,40,1); if (number_count<MAX_NUMBER){ data[number_count]=0x04; number_count++; } return; } if ( (x>68)&&(y>46)&&(x<76)&&(y<56) ) { rectangle (68,46,76,56,0); pause(10000); rectangle (68,46,76,56,1); if (number_count<MAX_NUMBER){ data[number_count]=0x01; number_count++; } return; } if ( (x>81)&&(y>14)&&(x<89)&&(y<24) ) { rectangle (81,14,89,24,0); pause(10000); rectangle (81,14,89,24,1); if (number_count<MAX_NUMBER){ data[number_count]=0x08; number_count++; } return; } if ( (x>81)&&(y>30)&&(x<89)&&(y<40) ) { rectangle (81,30,89,40,0); pause(10000); rectangle (81,30,89,40,1); if (number_count<MAX_NUMBER){ data[number_count]=0x05; number_count++; } return; } if ( (x>81)&&(y>46)&&(x<89)&&(y<56) ) { rectangle (81,46,89,56,0); pause(10000); rectangle (81,46,89,56,1); if (number_count<MAX_NUMBER){ data[number_count]=0x02; number_count++; } return; } if ( (x>94)&&(y>14)&&(x<102)&&(y<24) ){ rectangle (94,14,102,24,0); pause(10000); rectangle (94,14,102,24,1); if (number_count<MAX_NUMBER){ data[number_count]=0x09; number_count++; } return; } if ( (x>94)&&(y>30)&&(x<102)&&(y<40) ){ rectangle (94,30,102,40,0); pause(10000); rectangle (94,30,102,40,1); if (number_count<MAX_NUMBER){ data[number_count]=0x06; number_count++; } return; } if ( (x>94)&&(y>46)&&(x<102)&&(y<56) ){ rectangle (94,46,102,56,0); pause(10000); rectangle (94,46,102,56,1); if (number_count<MAX_NUMBER){ data[number_count]=0x03; number_count++; } return; } if ( (x>107)&&(y>14)&&(x<115)&&(y<24) ) { rectangle (107,14,115,24,0); pause(10000); rectangle (107,14,115,24,1); number_count=0; return; } if ( (x>107)&&(y>30)&&(x<115)&&(y<40) ) { rectangle (107,30,115,40,0); pause(10000); rectangle (107,30,115,40,1); if (number_count>0) number_count--; return; } if ( (x>107)&&(y>46)&&(x<115)&&(y<56) ) { rectangle (107,46,115,56,0); pause(10000); rectangle (107,46,115,56,1); if (number_count<MAX_NUMBER){ data[number_count]=0x00; number_count++; } return; } } void write_data (void) //Вывод буфера на ЖКИ { unsigned char i; for (i=0;i<number_count;i++) put_char (10+i*6,1,data[i],0); for (i=number_count;i<MAX_NUMBER;i++) put_char (10+i*6,1,0x85,0); } int main(void) { unsigned long int u=0,x,y; pause(5000); //Задержка для включения ЖКИ wg12864_init(); //Инициализация ЖКИ rectangle(0,0,127,63,1); //Рисуем область отображения put_char (70,2,0x07,0); //Рисуем цифры put_char (70,4,0x04,0); put_char (70,6,0x01,0); put_char (83,2,0x08,0); put_char (83,4,0x05,0); put_char (83,6,0x02,0); put_char (96,2,0x09,0); put_char (96,4,0x06,0); put_char (96,6,0x03,0); put_char (109,2,0x0c,0); put_char (109,4,0x0b,0); put_char (109,6,0x00,0); rectangle (68,14,76,24,1); //Рисуем квадратики rectangle (68,30,76,40,1); rectangle (68,46,76,56,1); rectangle (81,14,89,24,1); rectangle (81,30,89,40,1); rectangle (81,46,89,56,1); rectangle (94,14,102,24,1); rectangle (94,30,102,40,1); rectangle (94,46,102,56,1); rectangle (107,14,115,24,1); rectangle (107,30,115,40,1); rectangle (107,46,115,56,1); ADCSRA=(1<<ADEN)|(1<<ADPS0); //АЦП включен, прескаллер=/1 while(1) { DDRC=0x01; //Ждем нажатия PORTC=0x00; pause(10); ADMUX=(1<<REFS0)|(1<<ADLAR)|(1<<MUX1)|(1<<MUX0); ADCSRA|=(1<<ADSC); while ((ADCSRA&_BV(ADIF))==0x00) //Ждем окончания преобразования ; u=getU(); if (u<10) { //Если было нажатие DDRC=0x0c; //Считываем X координату PORTC=0x08; pause(1); ADMUX=(1<<REFS0)|(1<<ADLAR)|(1<<MUX0); ADCSRA|=(1<<ADSC); while ((ADCSRA&_BV(ADIF))==0x00) // Ждем окончания преобразования ; x=getU(); DDRC=0x03; // Считываем У координату PORTC=0x01; pause(1); ADMUX=(1<<REFS0)|(1<<ADLAR)|(1<<MUX1)|(1<<MUX0); ADCSRA|=(1<<ADSC); while ((ADCSRA&_BV(ADIF))==0x00) // Ждем окончания преобразования ; y=(getU()-495)/(4105/64); //Вычисляем координаты нажатия x=(x-400)/(4265/128); DDRC=0x01; //Ждем отжания клавиши PORTC=0x00; pause(10); ADMUX=(1<<REFS0)|(1<<ADLAR)|(1<<MUX1)|(1<<MUX0); while (u<10) { ADCSRA|=(1<<ADSC); while ((ADCSRA&_BV(ADIF))==0x00) // Ждем окончания преобразования ; u=getU(); } key_pressed (x,y); //Определяем какая клавиша нажата write_data (); //Выводим буфен на ЖКИ } } return 1; }
Что получилось из этой затеи можно посмотреть на видео:
Скачать прошивку в виде проекта под AVR studio 4.
Когда-то давно я писал уже статью про тачскрины, ее оригинал можно прочитать вот здесь:
Подключаем touchscreen к AVR-ке
Также англочитающим будет интересно почитать фирменный Atmel'овский аппноут:
AVR341: Four and five-wire Touch Screen Controller
Огромное СПАСИБО !
Если Есть У кого- нибудидь Информация о том данном устройстве и где его можго купить в Киеве, Харькове и т.д. Прошу на почту : Harconen(Sobaka)mail.ru
если автору не сложно, прошу ответить.
В Имраде вроде
В Имраде вроде есть:
жидко-кристалические индикаторы TS320240ARNA# WINSTAR 185.64
жидко-кристалические индикаторы TS320240DRC0# WINSTAR 140.07
жидко-кристалические индикаторы TSX320240ARNB# WINSTAR 95.62
Они побольше будут, т.е. для дисплеев 320х240 точек. Только они наверно под заказ, позвони им, уточни.
агроменное спасибо автору...
агроменное спасибо автору... просто очень большое. искал подобную информацию очень долго. довольно перспективная вещь))
Добрый день! Спасибо за
Добрый день!
Спасибо за статью очень интересно
Мне нужна помощь по поводу кода пытаюсь его переделать под нокию 3310
Пиксили вырисовываются но (проводишь по стачскрину с низу вверх а он какие-то лабиринты вырисовывает да и то только в одной части экрана) уже не знаю где копать
Вот код основного файла если надо весь проект выложу
Мне кажется, что здесь может
Мне кажется, что здесь может быть несколько проблем:
1) Правильно ли у тебя написаны функции работы с дисплеем нокии 3310? Попробуй вывести поочередно точки в центре и по углах дисплея.
2) Снизь частоту МК до 1Мгц, на АЦП на больших частотах может ловить помеху.
Заархивируй проект и закинь
Заархивируй проект и закинь куда-то на хостинг и вставь сюда ссылку.
Надо глянуть весь проект полностью.
Код
http://avrlab.com/upload_files/avr_touchscreen_code2.rar
Вот проект помогли мне более менее разобраться в коде но все ровно не рисует так как на видео у вас в статье а хотелось бы по лучше