Главная > AVR > Еще раз о емкостных сенсорах.

Еще раз о емкостных сенсорах.

07/03/2012

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

Вообще говоря, существует много емкостных методик определения касания. Самый древний подход — определение касания по наводкам от силовой сети, которые всегда присутствуют на теле человека (если он, конечно, не находится в чистом поле). Во вторую группу можно выделить QTouch‘еобразные (основанные на перекачивании в накопительный конденсатор заряда с сенсора и последующем измерении его величины) подходы, отличающиеся алгоритмами обработки, формой датчиков, подходом к фильтрации помех, etc. Посмотреть на реализацию такой системы на коленке, а также почитать подробное описание идеи работы такой системы на русском можно тут. В этой же статье нас будет интересовать третий подход, менее продвинутый, но гораздо более простой относительно второго и надежный относительно первого — непосредственное измерение емкости пластины сенсора. В принципе, и об этом уже писал Elm-Chan. Но попробуем повторить то же самое по-русски и не глядя в чужие исходники.

Для опыта я буду использовать свою макетку с установленной ATmega48, так что пример будет под AVR.

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

Ножка микроконтроллера подтягивается к питанию резистором достаточно большого номинала (1 мегаом), и к ней же подключается площадка сенсора. Оценка емкости производится путем измерения времени заряда площадки до напряжения логической единицы — это возможно, поскольку выводы микроконтроллера обладают пороговыми свойствами, т.е., в регистре PIN будет читаться единица начиная с какого-то определенного уровня (около 1В, немного различается для разных кристаллов). Алгоритм опроса такого сенсора выглядит следующим образом:

1. Настроить ножку на выход;
2. Подать на нее логический ноль, чтобы гарантированно разрядить сенсор перед замером;
3. Настроить ножку на вход;
4. Посчитать, за сколько тактов напряжение на ней достигнет единицы.

Все вышесказанное я воплотил в такой код:

uint8_t pad_chg_time(uint8_t pad_mask)
{
  volatile uint8_t tck=0;

  //Discharging pin
  SNS_DDR|=pad_mask;
  SNS_PORT&=~SNS_PADPIN;
  //Starting pin charge
  SNS_DDR&=~pad_mask;

  while (!(SNS_PIN & pad_mask))
    tck++;

  return tck;
}

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

Но после опроса нам надо решить, нажата кнопка или нет. Очевидный подход — найти количество тактов цикла, соответствующее порогу нажатия, и сравнивать полученное значение с ним. Но такое решение получится нестабильным, потому что порог будет зависеть от силы нажатия на сенсор (рука эластична, с изменением силы нажатия меняется площадь соприкосновения, а, следовательно, и емкость). Потому лучше ввести гитерезис: выбрать значение, ниже которого сенсор гарантированно свободен, и значение, зарегистрировав число выше которого можно точно сказать, что к площадке прикасаются, после чего делать вывод, сравнивая результат опроса с этими двумя значениями. Возможно, звучит громоздко, но, надеюсь, код внесет ясность:

uint8_t pad_touched(void)
{
  static uint8_t prev_state=0;
  uint8_t chg=pad_chg_time(SNS_PADPIN);

  if (chg>SNS_TH_MAX)
    prev_state=1;
  if (chg<SNS_TH_MIN)
    prev_state=0;

  return prev_state;
}

Идея следующая:

1. Опрашиваем сенсор;
2. Если значение выше порога касания — регистрируем касание и запоминаем это.
3. Если значение ниже порога свободного сенсора — регистрируем пустой сенсор и запоминаем это.
4. Выдаем запомненное значение.

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

Вышеприведенные участки кода — фрагменты проекта, который я по-быстрому набросал в AVR Studio + WinAVR.

Ну и пара картинок напоследок.

Сам сенсор (на ножке PD7):

Процесс тестирования:

Рубрики:AVR