Сенсорная кнопка из подручных средств

pavelkq
Offline
Зарегистрирован: 23.10.2015

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

int val=0;                      // таймер ёмкости
boolean flag=0;                  // значение кнопки

void setup() {               
  pinMode(13, OUTPUT);      // это выход - светодиод
}
void loop() {
  pinMode(10, OUTPUT);       // устанавливаем ноль принудительно
  pinMode(10, INPUT);        // готовимся считывать значение

  while (digitalRead(10)==LOW){ 
    val++;                    //считаем, за сколько зарядилась ёмкость
  }
  if (val>20 && flag==0) {    // 7-20 величина гистерезиса
    digitalWrite(13,!digitalRead(13));
    flag=1;
    delay(500);
  }
  if (val<7 && flag==1) {  // 7-20 величина гистерезиса
    flag=0;
    delay(500);
  }
  val=0;
}

Пришлось добавить задержку в полсекунды, т.к. весьма ощутим был дребезг (переходные процессы).

Величина ёмкости без касания равнялась примерно 6 тактам. При касании - свыше 20. Знаю, что у раных людей ёмкость может быть разной, поэтому величину гистерезиса можете сами подправить.

В качестве кнопки использовал болт М5 (предположительно будет видна только его шляпка, как кнопка). Провод к болту длинной 50 см., что практически не влияет на измеренную ёмкость (на коротком поводке значения те же).

П.С. Простите, не знал, в каком разделе разместить написать, поэтому здесь.

Tomasina
Tomasina аватар
Offline
Зарегистрирован: 09.03.2013

какой смысл в комбинации строк 8 и 9?

P.S. http://www.pjrc.com/teensy/td_libs_CapacitiveSensor.html

pavelkq
Offline
Зарегистрирован: 23.10.2015

Переводя порт в режим вывода мы переводим его в состояние логического нуля. Потом переводим порт в режим чтения  (не включая подтягивающий резистор) и через резистор идет зарядка "конденсатора" до состояния логической единицы. Именно время заряда и является показателем касания сенсора.

PVl_Soryn
Offline
Зарегистрирован: 31.05.2017

Круто, хочу узнать побольше об этом! Например, почему резистор 2 Mom, почему не 1 Mom или 200 kom? И вообще, зачем он тут?

negavoid
Offline
Зарегистрирован: 09.07.2016

PVl_Soryn пишет:
почему резистор 2 Mom, почему не 1 Mom или 200 kom? И вообще, зачем он тут?

Чтобы регулировать чувствительность. 1 МОм тоже можно. С 200 кОм, скорее всего, перестанет работать как должно. С 10 МОм будет много ложных срабатываний и срабатываний даже с отдалённой рукой, а с 50 МОм, например, будет реагировать даже на проезжающую мимо машину, у которой шины трутся об асфальт и создают статический заряд.

PVl_Soryn
Offline
Зарегистрирован: 31.05.2017

Спасибо за толковое разъяснение, добавлю в важные заметки. А схема для этого скетча --> ?

PVl_Soryn
Offline
Зарегистрирован: 31.05.2017

Только вместо 3 пина на плате - 10 пин, а 2 пин вовсе не подключаем, т. е. используем 3 пина arduino? Во всяком случае я это уже попробовал и всё работает, но мне нужно мнение посвящённого человека, чтоб наверняка...

negavoid
Offline
Зарегистрирован: 09.07.2016

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

#define CAP_PIN 3

int val = 0;             // таймер ёмкости
boolean flag = 0;        // значение кнопки

void setup()
{
  pinMode(13, OUTPUT);   // это выход - светодиод
}

void loop()
{
  pinMode(CAP_PIN, OUTPUT);       // устанавливаем ноль принудительно
  pinMode(CAP_PIN, INPUT);        // готовимся считывать значение

  while (digitalRead(CAP_PIN) == LOW) {
    val++;                        //считаем, за сколько зарядилась ёмкость
  }

  if (val > 20 && flag == 0)      // 7-20 величина гистерезиса
  {
    digitalWrite(13, !digitalRead(13));
    flag = 1;
    delay(500);
  }

  if (val < 7 && flag == 1)       // 7-20 величина гистерезиса
  {
    flag = 0;
    delay(500);
  }

  val = 0;
}

PVl_Soryn
Offline
Зарегистрирован: 31.05.2017

Интересно, схему которую вы нарисовали. немного отличается от той что я испробовал: провод что ведёт к 5 вольтам у меня отсутсвует, т. е. всего я использую 3 провода. Вопрос, как у меня всё работает ?? :))

PVl_Soryn
Offline
Зарегистрирован: 31.05.2017

Аааа, до меня дошло..., без этого 4-го провода не использовать мне резистор.

 

PVl_Soryn
Offline
Зарегистрирован: 31.05.2017

void setup() {
  pinMode(2, OUTPUT);    добавил вот эту строку, теперь всё работает, как я понимаю, через резистор 1 Мом.

negavoid
Offline
Зарегистрирован: 09.07.2016

PVl_Soryn пишет:

Интересно, схему которую вы нарисовали. немного отличается от той что я испробовал: провод что ведёт к 5 вольтам у меня отсутсвует, т. е. всего я использую 3 провода. Вопрос, как у меня всё работает ?? :))

Таким образом оно работало в качестве детектора электромагнитного поля - в комнате много полей, от компьютера, от розеток, лампочек. Если подключить один выход резистора к земле, а второй (с медной платой - антенной) к аналоговому входу, можно замерять и более слабые поля, ну а так - напряжение на пальце превышало 1 или сколько там вольт, вот цифровой вход и включался.

DontsovS
Offline
Зарегистрирован: 08.03.2017

Спасибо! Хорошая статья в качестве отправной точки.

у меня есть только парочка вопросов и предложений.

1) можно попробовать в setup (или вообще в отдельной функции) подсчитать количество тактов до зарядки "конденсатора". получится самонастраивающаяся система. Тогда и верхнюю границу можно будет взять не за определенное число (в данном случае 20), а как найденное значение в setup плюс дельта.

2) можно ли использовать для настройки чувствительности не только разные резисторы, но и ШИМ? Соответственно резистор подключать не к +5в, а к пину, который поддерживает ШИМ.

3) как себя такая кнопка будет вести в машине, если периодически ездить около высоковольтных линий электропередач?

pavelkq
Offline
Зарегистрирован: 23.10.2015

Признаться, я, всё же, купил у китайцев готовые сенсорные кнопки, но сильно в них разочаровался. Почему-то они часто самопроизвольно срабатывают, хотя я применял разные методы устранить помехи. Думаю, что с самодельной кнопкой больше возможности по настройке чувствительности (в китайских такой настройки вообще нет, она настраивается автоматически). 

По вашим вопросам. Разумеется, идея добавить автоподсчёт в сетап хорошая! Если реализуете, присылайте сюда.

Думаю, что ШИМ использовать можно, но не очень целесообразно, ибо просто его жалко. А если применить еще и самонастройку в сетапе, то даже погрешность в номиналах деталей уже не будет влиять на время срабатывания. 

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

rush
rush аватар
Offline
Зарегистрирован: 21.05.2019

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

#define CAP_PIN 3

int val = 0;             // таймер ёмкости
boolean flag = 0;        // значение кнопки
int r=0;
void setup()
{
  Serial.begin(9600);
 pinMode(13, OUTPUT); // Объявляем пин реле как выход
  digitalWrite(13, LOW); // Выключаем реле - посылаем высокий сигнал
}

void loop()
{
  val = 0; 
  
    pinMode(3, OUTPUT);      
  pinMode(3, INPUT); // устанавливаем ноль принудительно
        // готовимся считывать значение

  while (digitalRead(CAP_PIN) == LOW) {//считаем, за сколько зарядилась ёмкость
    val++;  
    val--;
  Serial.println(val); 
  }
  digitalWrite(13, HIGH);
  delay(300);
   digitalWrite(13, LOW); 

  val = 0;
}

 ​ 

ua6em
ua6em аватар
Онлайн
Зарегистрирован: 17.08.2016

rush пишет:

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

#define CAP_PIN 3

int val = 0;             // таймер ёмкости
boolean flag = 0;        // значение кнопки
int r=0;
void setup()
{
  Serial.begin(9600);
 pinMode(13, OUTPUT); // Объявляем пин реле как выход
  digitalWrite(13, LOW); // Выключаем реле - посылаем высокий сигнал
}

void loop()
{
  val = 0; 
  
    pinMode(3, OUTPUT);      
  pinMode(3, INPUT); // устанавливаем ноль принудительно
        // готовимся считывать значение

  while (digitalRead(CAP_PIN) == LOW) {//считаем, за сколько зарядилась ёмкость
    val++;  
    val--;
  Serial.println(val); 
  }
  digitalWrite(13, HIGH);
  delay(300);
   digitalWrite(13, LOW); 

  val = 0;
}

 ​ 

что это было?

astwo
Offline
Зарегистрирован: 10.07.2019

ua6em пишет:

что это было?

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

rush
rush аватар
Offline
Зарегистрирован: 21.05.2019

rush
rush аватар
Offline
Зарегистрирован: 21.05.2019

хотел повторить эту схему только не знаю какой сигнал там измеряется, думаю что кнопка срабатывает от ёмкости человека, там на схеме видна от пружины до резистора 550кОм и напрямую в МС, если бы получилось повторить  было бы круто

rush
rush аватар
Offline
Зарегистрирован: 21.05.2019

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