Разработка сенсорной клавиатуры для своих устройств

    В данной статье я опишу процесс разработки сенсорной клавиатуры, которую можно использовать в своих девайсах. Такую клавиатуру нетрудно собрать, т.к. в ней отсутствуют механические части, а отсутствие механической обратной связи компенсируется изяществом использования.

    В процессе разработки одного проекта мне потребовалась удобная клавиатура на 8 кнопок. Я решил прибегнуть к известному подходу – реализовать емкостные сенсоры.
    Физическую теорию я уже описал в своей статье про девайс-сувенир, которой чувствовал, когда его берут в руку (http://habrahabr.ru/blogs/DIY/111627/)
    Принцип остается совершенно тем же самым, единственное отличие в реализации – используются не два вывода микроконтроллера а один.
    Для начала, видео того, к чему мы будем стремиться:



    Шаг 1: Схемотехника



    Схемотехника сенсоров слегка изменилась, в связи с тем, что необходимо использовать только одну ногу микроконтроллера на сенсор, а не две. Впрочем, если вам не жалко лишних ног, то можно все оставить по-старому.

    image

    Порядок опроса сенсора будет слегка отличаться. Изначально на пин PD0 подан лог. 0.
    Таким образом, ток течет от источника питания через мегаомный резистор и втекает в пин. Если сенсор был заряжен, то ток с него также будет стекать в пин PD0.

    В момент опроса мы переключаем пин с выхода на вход (подтяжки отключены!). В этот момент, пин переходит в высокоимпедансное состояние, с сопротивлением порядка нескольких десятков(а то и сотен) МОМ. Ток в направлении пина практически прекращает течь, и начинает течь в сторону сенсора. Как только сенсор зарядится до напряжения свыше уровня лог. 1, данный вход микроконтроллера покажет единицу.
    Измерив время, которое прошло с момента перевода PD0 в высокоимпедансное состояние до появления на нем лог 1, можно сделать вывод об изменении емкости сенсора, а значит, отловить момент прикосновения.

    Конструктивно сенсор представляет собой прямоугольную контактную площадку 10х10 мм, но на самом деле форма его практически ничем не ограничивается, можно делать круги, змейки, делить их на сегменты и сектора — в общем ввод информации в любом виде.

    Ниже представлена фотография законченной печатной платы. Плата заказная, но изготовить такую в домашних условиях также не составляет труда. При использовании макетных плат в роли сенсора может выступать кусочек фольгированного стеклотекстолита, приклеенный поверх платы.

    image

    Над каждым сенсором расположен SMD диод для индикации нажатия.
    Управляется все это микроконтроллером ATMega88, заведенном на частоте 20 МГц.
    Таким образом, выход с этой клавиатуры можно сделать любой, какой вам будет нужен и какой потянет мега. В моем случае был удобен SPI (я прошивал и тестил не отключая от программатора, да и в устройстве уже была задействована эта шина), но вы может использовать встроенный в мегу наравне с SPI UART, I2C, или воспользоваться программной реализацией USB от ObjDev. Да, собственно, можно и аппаратной, типа FTDI преобразователя USB->UART.

    Итоговая схема (скриншот из Altium) представлена ниже.

    image

    Опять-таки, ничего сложного, ничего лишнего – мега, тактирующая ее цепь, пара сглаживающих питание кондеров, разъем для программирования/подключении, 8 диодов и 8 сенсоров.

    Что интересно: расстояние, на котором сенсор может почувствовать руку зависит от разрядности таймера, его частоты, а также сопротивления, через которое подключен сенсор. Объясняется это просто – более быстрый таймер сможет засечь более мелкие интервалы времени, а при отсутствии гальванического контакта с сенсором время зарядки существенно снижается. 20 МГц меги и ее 16-разрядного таймера хватает на то чтобы уверенно обнаруживать прикосновение через слой пластика (плексигласа) около 1 мм.
    Можно слегка разогнать мегу и немного увеличить сопротивление, но лучше этим не увлекаться – стабильность работы разогнанной меги не гарантируется, а слишком большое сопротивление может сравнять ток заряда с током утечки, что сделает сенсор вечно неактивным.
    Как бы то ни было, нормального режима работы вполне хватит для прикрытия сенсоров тонким кусочком пластика. Идеальным бы был вариант с напылением токопроводящего покрытия на стекло, но у меня не было особой возможности поэкспериментировать в этом направлении.

    Дальше нас ждет код.

    Шаг 2: Код



    В принципе все уже описано выше, но для некоторой ясности приведу код проекта.

    #include <avr/interrupt.h>
    #include <avr/io.h>
    
    unsigned char KBD_STATUS=0x00, TMP_STATUS=0x00; //Текущий статус клавиатуры и переменная, куда запишем новый статус
    
    unsigned short SensorTimes[8]={0,0,0,0,0,0,0,0}; //Времена откликов сенсоров
    unsigned short SensorHI[8]={0,0,0,0,0,0,0,0},      //Для ускорения вычислений - заранее посчитанные 
    			   SensorLO[8]={0,0,0,0,0,0,0,0};  //верхний и нижний пороги
    void CheckSensors();
    unsigned short SensToLED[8]={8,16,32,1,4,2,1,2};  //Доп. массив, т.к. диоды висят на рандомных ногах)
    ISR(TIMER0_OVF_vect)
    {
    		CheckSensors(); //Проверяем сенсоры
    		for(unsigned short i=0;i<8;i++)
    		{
    			if(KBD_STATUS&(1<<i)==0)         //Зажигаем диоды. Проект старый, сейчас я бы так не написал
    				if(i==3||i==7)
    					PORTB|=SensToLED[i];  //Но править уже не буду. Куча ифов из за того что диоды
    				else
    					PORTC|=SensToLED[i]; //висят на разных портах и рандомных пинах.
    			else
    				if(i==3||i==7)
    					PORTB|=SensToLED[i];
    				else
    					PORTC&=~SensToLED[i];
    		}
    }
    
    ISR(SPI_STC_vect)  //Это прерывание вызывается если нас опросили по SPI
    {
       	SPDR=KBD_STATUS; //Отправим им текущий статус!
    }
    
    void InitSPIMode3()  //Настройка SPI
    {
    	DDRB= 0b00010011;  
    	PORTB=0b00000011;
    
    	SPCR= 0b11001100;
    	SPSR=0x00;
    }
    
    void Calibrate()  //Калибруем все сенсоры по очереди
    {
    unsigned char i=1,k=0;
    	while(i!=0)
    	{
    		TCNT1=0x0000;
    		TCCR1B=0x01;
    		DDRD = ~i;
    		while((PIND&i)==0);
    		TCCR1B=0x00;
    		DDRD|=i;
    		SensorTimes[k]=TCNT1;
    		SensorHI[k]=SensorTimes[k]+70;
    		SensorLO[k]=SensorTimes[k]+20;
    		k++;
    		i<<=1;
    	}
    }
    
    void CheckSensors()  //Проверяем все сенсоры по очереди
    {
    unsigned char i=1,k=0;
    	TMP_STATUS=KBD_STATUS;
    	TCNT1=0x0000;
    	TCCR1B=0x01;
    	DDRD = 0b11111110;
    	while(i!=0)
    	{
    		TCNT1=0x0000;
    		TCCR1B=0x01;
    		DDRD = ~i;
    		while((PIND&i)==0);
    		TCCR1B=0x00;
    		DDRD|=i;
    		if(TCNT1>SensorHI[k])   //Гистерезис, чтобы не дрыгалось при граничном значении емкости
    			TMP_STATUS|=i;
    		else if(TCNT1<=SensorLO[k])
    			TMP_STATUS&=~i;
    		k++;
    		i<<=1;
    	}
    	KBD_STATUS=TMP_STATUS;
    }
    int main()
    {
    DDRD=0xFF;
    PORTD=0x00;
    
    PORTC=0xFF;
    DDRC=0xFF;
    
    TCCR0=0b00000101;
    TCNT0=0x00;
    
    TCCR1A=0x00;
    TCCR1B=0x00;
    TCNT1H=0x00;
    TCNT1L=0x00;
    ICR1H=0x00;
    ICR1L=0x00;
    OCR1AH=0x00;
    OCR1AL=0x00;
    OCR1BH=0x00;
    OCR1BL=0x00;
    
    ASSR=0x00;
    TCCR2=0x00;
    TCNT2=0x00;
    OCR2=0x00;
    
    MCUCR=0x00;
    TIMSK=0x01;
    ACSR=0x80;
    SFIOR=0x00;
    InitSPIMode3();
    
    for(int i=0;i<1024;i++) //Просто чтобы не калиброваться сразу как подадут питание
    	CheckSensors();  // подрыгаем сенсорами)
    KBD_STATUS=0x00;
    TMP_STATUS=0x00;
    Calibrate();                  //Калибруемся
    sei();
    while(1);
    }
    
    Поделиться публикацией
    Комментарии 50
      +12
      Dude, you're on the jazzz :))
        0
        А печатка откель такая? как-то связаны с производством?
          +4
          Нет, совершенно никак не связан, но решили с друзьями-разработчиками попробовать заказать платы на троих (сообразили на троих, ага =) ), т.к. у нас на тот момент накопилось несколько проектов.
          Собрали все наши разводки, объединили в одну заготовку и отдали в компанию ТеПро.
          В результате получил довольно много плат (двусторонние, с маской и металлизацией) за 5+ тысяч рублей на троих. Приемлемо, но дороговато. Хотя результаты и время выполнения заказа очень порадовали.

          Сейчас большинство плат я делаю сам) Не такого качества, конечно, но для макетов вполне хватает.
            0
            Да, цены кусаются. В свое время хотел сделать устройство на заводской печатке, но цена расстроила.
              0
              Кусаются, поэтому надо платы заказывать на двоих-троих.
              На одну заготовку все кидать, желательно — много мелких. Тогда будет более-менее нормально по цене.
                0
                А заказывать у рекламщиков у кого есть лазеры дорого?
                  0
                  А каким образом рекламщики смогут помочь с изготовлением плат? Промышленно делать платы имеет смысл когда нужна металлизация отверстий ну, или хотябы, маска с шелкографией.
                    0
                    У рекламщиков нужно заказывать не «лазеры», а трафареты с самоклейки.
                    0.2мм дороги нарезают идеально. Подумываю о приобретении плоттера для нарезки винилов. Есть довольно точные модели, в пределах 0.03мм, но для мелких форматов.
                    Вообще чем больше максимальный формат, тем хуже. У самых больших, для А1 и более, разброс 0.2-0.3мм что абсолютно не подходит для даных задач.
                    С другой стороны процесс перевода вырезаного на монтажную плёнку довольно трудоёмок.
                    Метализация и лакировка решаются в домашних условиях химическими путями.
                    Правда это довольно дорогое удовольствие. В основном обхожусь гальванизацией и зелёным цапон-лаком. Ну и естественно не стоит забывать о ЛУТе который в правильных руках даёт дороги в 0.1-0.2 мм
                      +1
                      А еще не стоит забывать о стеклотекстолите с уже нанесенным фоторезистом. Кусок двустороннего текстолита с СПФ стоит 90 рублей, одностороннего — 80. Дает отличные результаты.
                    0
                    Я работал с этими ребятами (вышеупомянутое ТеПро). Штучное изготовление примерно так и стоит у всех. Но здесь плюс — расположены они в Москве. Причем большую часть цены составляет именно подготовка производства. Т.е. примерно никакой разницы между 1 и 2 одинаковыми платами.
                    Удобно все платки объединить в одну плату — так получится дешевле. А разделить можно и гильотиной, или же заказать у них фрезеровку (цена этого какая то смешная, но есть тонкости).
                    Еще можно отказаться от паяльной маски — немного подешевле будет.
                    Ну а если заказывать 100 и больше штук — то тут Китай правит балом. Как то так.
                    0
                    Производителей плат для мелкосерийного производства или прототипирования можно здесь:
                    www.elart.narod.ru/pcb.htm — россия
                    electronix.ru/forum/index.php?showtopic=44306 — украина
                    projects.org.ua/forum/viewtopic.php?t=315 — ураина
                    Украина две ссылки, потому что сам отсюда ;)
                    У некоторых из них такая платка размером 40*90 обошлась бы в 20 грн примерно за одну штуку или по 14 грн за 10 шт (примерно 80 и 60 руб соответственно)
                    Качество, возможно чуть похуже, чем на фото.
                  0
                  А если хочется вставить девайс в корпус — что-то изменится? Как сенсор реагировать будет?
                    0
                    Смотря как вставить. если толщина стенки корпуса 1мм и меньше, проблем не будет, пробьет через стенку. Но чем ближе сенсоры к пальцу, тем лучше, так что в корпусе я бы прорезал окошечко, и вставил туда тонкий пластик.
                    0
                    Альтиум юзаете, а УГО компонентов не по ГОСТ. Не порядок! )
                      +2
                      Ненавижу наши ГОСТы. Зарубежные куда более дружественные, ИМХО.
                      А почему альтиум вдруг обязывает к нашим ГОСТам, это же не КОМПАС)
                        0
                        Хотите любИте, хотите — ненавидьте, но я, как человек, который уже натрахался со стандартами, в принципе, могу сказать, что система в целом так уж неплоха, хоть и не идеальна. Есть куда более кривые реализации, ну и в целом у нас в стране стандартизация в упадке. А что творится с техническими регламентами — так и вообще жесть.

                        Так что (если делаете что-то не только для себя) старайтесь хоть более-менее придерживаться стандартов, хотите — ГОСТ, хотите — ISO, работать с чьей-нибудь документацией или проектом, оформленным как захотелось автору, в большинстве случаев, удобно только автору, а вот разбираться что и как и почему — сомнительное удовольствие.
                          +7
                          Уважаемый, когда я черчу схему в НИИ, я черчу ее так чтобы было удобно работать с ней остальным. Когда я черчу схему для себя, я черчу ее так, как удобно мне, и рисовать новые библиотеки с УГО, когда с альтиумом идет тонна готовых я не собираюсь.

                          И, кстати сказать, что же тут не по ISO?
                            0
                            А я и не говорю, что тут что-то не по ISO, я просто призываю соблюдать стандарты.
                              0
                              Shirixae, глюк какой-то, на почту ваш ответ пришел, а здесь не отображается (по крайней мере у меня).

                              >А я и не говорю, что тут что-то не по ISO, я просто призываю соблюдать стандарты.

                              Разумеется, как инженеры мы все понимаем что стандарты обязательны) Более того, как бы я не относился к нашим ГОСТам, схемы обязывают сдавать в них, так что приходится чертить)
                              Я просто говорю, что если бы была возможность выбирать, я бы предпочел зарубежный стандарт на Э3 нашему.
                            0
                            Вот-вот, он вообще ни к чему не обязывает, т.к. фирма австралийская =)
                          0
                          А есть схемки, что бы число «кнопок» было 14-16?
                            +2
                            Хм, ну что вам мешает взять и дополнить эту схему? Ведь главное принцип.
                            Учитывая что все сенсоры тут опрашиваются по очереди, можно вообще повесить все на одну ногу и мультиплексировать.
                            0
                            Отличная статья.
                            Есть опыт эксплуатации? Хорошая устойчивость к статике/наводкам в бытовом применении? У меня у монитора envision емкостная клавиатура под пластик спрятана, стильно, но пожалел уже — иногда не срабатывает, зараза.
                              0
                              Опыт в эксплуатации есть, но т.к. она юзается в портативном девайсе, возможности проверить реальную устойчивость к наводкам и прочему особо не было. Про девайс потом, возможно, напишу отдельную статью.

                              Если так подумать, то наводки ей особо не страшны, она измеряет изменение емкости, врядли наводкой удастся настолько изменить емкость, как это сделает прикосновение. А насчет статики — если под пластиком спрятать, то тоже не должно помешать)
                              Я пробовал ее использовать через тонкий пластик, меньше 1 мм должна справится нормально.

                              Самый лучший вариант, это продумать технологию по нанесению токопроводящего материала тонким слоем на стекло. Ну или на тот же пластик. Тогда результаты будут на порядок лучше. Возможно, стоит поглядеть в сторону токопроводящих красок…
                                0
                                Да, единственное что наводка может сделать — переключить раньше времени пин в лог. 1.
                                Но это значит что у нее должна быть довольно здоровая амплитуда, и переключение раньше времени будет сигнализировать что сенсор неактивен — но врядли эта наведенная помеха будет присутствовать там постоянно, значит, при следующем же опросе сенсоров результаты вновь будут валидными, а это доли секунды.
                              0
                              Какая отличная экономия!
                              Вместо www.atmel.com/products/touchsoftware/qtouchsuite.asp?family_id=702 набор кондеров и резисторов, вместо программатора, наверняка КТ315 и два стабилитрона… :)
                              Осталось применить что-то вроде KiCAD для начертания схемы и будет полное OpenSource решение :)
                                0
                                Зря иронизируете, на момент разработки этой клавиатуры Атмел свой QTouch не выпустил еще, насколько мне известно.
                                Я просто рассказал об одном из возможных решений, весьма простом и дешевом.
                                Вместо программатора у меня лично собранная Проттоссовская железка на лично разведенной под нее плате.
                                А вы большой поклонник дорогих решений?)
                                  0
                                  Наоборот я поклонник всего открытого, это была не ирония.
                                  Собственно, возможно, даже и использую у себя такую штуку вместо кнопок. Мнится мне, что весьма удобно получится…
                                  А ссылку на железку-программатор можно?
                              0
                              А может кто-то подсказать как сделать клавиатуру с бОльшим количеством сенсоров? Например повторить стандартную клавиатуру.
                                0
                                Да также. Или воспользовавшись пресловутой QTouch библой от атмела.
                                Только ног нужно побольше) Впрочем, это все решается несколькими дополнительными микросхемами из стандартной логики.
                                0
                                В новых микроконтроллерах Microchip добавили некий Capacitive Sensing Module. Иногда бывает необходимо разгрузить ядро.
                                  0
                                  Да, аппаратная поддержка это дело хорошее)
                                  Впрочем, это же клавиатура, ее основная задача — работать с сенсорами, поэтому не думаю, что стоит разгружать ее ядро)
                                  В моем устройстве она подключена по SPI, как раз затем чтобы разгрузить ядро центрального вычислителя — он просто периодически запрашивает байты от клавиатуры, и все.
                                    0
                                    Эх, я б так жил).
                                    В крупносерийном производстве — вешать отдельный контроллер для обработки (8-ми) сенсоров есть непозволительная роскошь.
                                      0
                                      Смотря что производят… Иногда это пренебрежимо мало по сравнению с усложнением схематики или удорожением компонентов.

                                      Так, стоп-стоп. А это не программный-ли модуль? Судя по тому что у них на сайте, это очередная библа типа QTouch. Если это так, то разгрузить ядро не удастся)
                                        0
                                        Нет, конечно же не программный. Здесь поподробнее. И, кстати, проще схемотехника ;).
                                          0
                                          Интересно…
                                          Жаль, что в АВР подобного нет, я к ним как-то больше привык.
                                          У PIC есть отличная ниша, не занятая АВРами, это 16битные микроконтроллеры и DSP, меньше монструозных ДСПшек от всяких TI, но все же полноценные DSP, поэтому для недорогой 16битной обработки сигнала в любом случае приходится от AVR отказываться.
                                          Но для 8битных решений мне ближе AVR.
                                            0
                                            Не буду спорить, это — предпочтения каждого, но новые PIC'и радуют потреблением и скоростью: PIC16 — 32MHz и PIC18 — 64MHz на встроенном RС генераторе. По-моему, не так плохо) А насчет PIC24 или dsPIC, возможно для таких задач имеет смысл присмотреться к Cortex-M3.
                                              0
                                              Неплохо)
                                              А как с точностью? Частота не скачет? У единственной аврки, у которой встроен PLL для работы на 16.5 мгц без генератора, говорят, неважная…
                                              Вообще, к пикам мне стоит присмотреться повнимательнее, у них есть некоторые удачные решения, которых нет у АВР.

                                              А насчет Cortex-M3… Просто бывают задачи, для которых 8 бит АВР/ПИК мало, а 32бит арм ядра — много)
                                                0
                                                Смотря что подразумевается под «скачет». Насколько я помню, 2-3% во всем температурном диапазоне от -40 до +125 (это естественно, поскольку речь идет об R и C). Хоть в PIC'ах и есть регистр для калибровки частоты «на лету», в случае если необходима точность, я бы предпочел кварц + PLL.
                                                  0
                                                  Ну вот у АВР вроде как аж целых 5 процентов.
                                                  Кварц всяко надежнее, да…
                                                    0
                                                    Если там PLL (а скорей всего) то под конец этого уножателя частота будет плавать очень сильно.
                                                0
                                                А чем же вам не подходит AT42QT2160 или AT42QT1070 для сенсорной панели?
                                                Если уж QTouch так QTouch… очень привлекательная штука.
                                                Очень хороший датчик приближения пальцев, срабатывает не при косании а при приблежении, порог включения регулируемый.
                                                Для массового производства дорого, а для любительской панели с гравированого оргстекла и светодиодной подсветкой очень кстати.
                                                Более-менее ДСПшки есть в avr32,
                                                правда не знаю на сколько они дешевле агалогов MICROCHIPа
                                                Но уже второй месяц играюсь с at32uc3b,
                                                который успешно заменил ARMы в некоторых проэктах
                                                Что-то тут приподняли планку над PICами.
                                                Вообще PICи для студента — дорого.
                                                К тому же довольно медленно, avr был всегда быстрее.
                                      0
                                      Ох… Шикарно. Если сделать панель поменьше, то выйдет довольно таки стилный девайс. Пожалуй попробую переделать свой кодовый замок под такую клаву…
                                        0
                                        Ух ты… :)
                                        Сделаю подарок племяннику, как раз День Рождение скоро у него.
                                          0
                                          Скажите, а проблема «дребезга контактов» на такой клаве проявляется? %) Не, ну понятно, что никаких контактов тут и в помине нет, но все же. И насколько она может быть чувствительна в плане повторных нажатий?
                                            0
                                            Кратко: вполне юзабельно. Спасибо автору за идею.

                                            Собрал небольшую платку для теста, все же на практике куда легче посмотреть на возможности.

                                            Если все хорошо расчитать — никаких проблем быть не должно. Емкость сенсора замеряется вполне стабильно, для увеличения точности можно либо повысить тактовую частоту, либо увеличить сопротивление подтяжки.
                                            Останется только подкорректировать пороги включения\выключения в зависимости от условий использования. При низком пороге спокойно определяется прикосновение с обратной стороны текстолита, при высоком — необходимо прикасаться к самому сенсору.
                                            Частоту опроса можно выбрать любую, лишь бы хватило на зарядку каждого сенсора.
                                            С ложными нажатиями проблем быть не должно.

                                            Из минусов — калибровка. Если она будет производиться во время прикосновения к сенсору — ничего хорошего не выйдет. Впрочем, решить эту проблему не сложно.
                                              0
                                              Спасибо за развернутый ответ! А насколько сказываются на качество срабатывания например мокрые руки? Ну или вообще влажность самой клавиатуры
                                                0
                                                На определение приближения — никак не сказываются. Но если намочить поверхность после калибровки — конечно емкость повысится и сможет превысить порог отключения. От влажного пальца при высокой чувствительности это может быть пара секунд задержки выключения, пока вода не испарится. Капля воды вполне сопоставима с прикосновением, потому для использования в дождь данный вариант явно не подойдет.
                                            0
                                            Уже который раз пытаюсь собрать сенсор на таком же принципе, только на PIC'ах…
                                            Не хочет работать =(
                                            Может знает кто в чём может быть загвоздка?
                                            Калибровка не проходит — контроллер уходит в цикл на while:
                                            void CallibrateButtons(void) {
                                            TRISB &= 0b11111000;  // порт на выход
                                            LATB  &= 0b11111000;  // в порт ноль
                                            idle_millisec = 2; OSCCON = OSCCON_START_STATE; SLEEP(); // Ждём пока стечёт заряд
                                            microsec = 0;                // Счётчик микросекунд, инкементируется таймером
                                            TMR0H = TIMER0_H; TMR0L = TIMER0_L; // Установка таймера на прерывание каждые 5с
                                            TMR0ON = 1;                                         // Включили таймер
                                            TRISB |= 0b00000111;                           // Порт на вход
                                            while ( RB0 == 0 ) { __delay_us(1); };     // Висиииим =(
                                            TMR0ON = 0;
                                            button_1_open_time = microsec + 10; }


                                            На всякий случай: резистор 1.3 МОм, конденсатор 27 пФ.

                                            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                            Самое читаемое