Czujnik pojemnościowy i Arduino

Wpis w kategorii [ Arduino ]

KlawiaturaCzujniki pojemnościowe (zbliżeniowe) reagują na zbliżanie do ich powierzchni dowolnego materiału. Mnie w chwili obecnej interesuje głównie zastosowanie czujników pojemnościowych jako klawiatury (trochę zmotywowany / zachęcony produktem QTouch Atmela). Materiałem zbliżanym do czujnika będzie więc ludzkie ciało.

Okazuje się, że realizacja prostej klawiatury zbliżeniowej nie wymaga budowania specjalistycznych modułów sterujących. Mało tego, można nawet stworzyć taką klawiaturę z zastosowaniem wyłącznie mikrokontrolera.

Przyjrzyjmy się bliżej dwóm rozwiązaniom.

1. Czujnik pojemnościowy bez dodatkowego sprzętu

Pierwsze rozwiązanie pozwala na wykrycie zbliżenia / dotknięcia na 6 pinach cyfrowych Arduino (piny od 8 do 13). Projekt działa bez jakichkolwiek zewnętrznych elementów (poza drucikiem pełniącym rolę czujnika), jednak zaleca się zastosowanie kondensatora o pojemności 1nF włączonego pomiędzy czujnik a masę, w celu zminimalizowania wpływu zakłóceń sieci energetycznej (50Hz).

Program mierzy pojemność (czas ładowania) na danym pinie. Jeśli czujnik jest niedotknięty funkcja getcap zwraca małą wartość (np. 1), gdy zostanie dotknięty wartość ta wzrasta np. do 5 (wartości trzeba zmierzyć).

Kod

// sensor key
#define KEYPORT PORTB
#define KEYDDR  DDRB
#define KEYPIN  PINB
#define KEY0    PB0        // capture input - digital 8
#define KEY1    PB1        // capture input - digital 9
#define KEY2    PB2        // capture input - digital 10
#define KEY3    PB3        // capture input - digital 11
#define KEY4    PB4        // capture input - digital 12
#define KEY5    PB5        // capture input - digital 13
 
void setup()
{
  Serial.begin(9600);      // connect to the serial port
}
 
// returns capacity on one input pin
// pin must be the bitmask for the pin e.g. (1<<PB0)
char getcap(char pin)
{
  char i = 0;
  KEYDDR &= ~pin;          // input
  KEYPORT |= pin;          // pullup on
  for(i = 0; i < 16; i++)
    if( (KEYPIN & pin) ) break;
  KEYPORT &= ~pin;         // low level
  KEYDDR |= pin;           // discharge
  return i;
}
 
void loop ()
{
  char capval[6];
  char pinval[6] = {1<<KEY0,1<<KEY1,1<<KEY2,1<<KEY3,1<<KEY4,1<<KEY5};
  delay(1000);
  for(char i = 0; i < 6; i++)
  {
    capval[i] = getcap(pinval[i]);
    Serial.print("digital ");
    Serial.print(i+8, DEC);
    Serial.print(": ");
    Serial.println(capval[i], DEC);
  }
  Serial.println("");
}

2. Czujnik dotykowy – wersja bardziej zaawansowana

Biblioteka capSense stanowi bardziej rozbudowaną wersję obsługi czujników pojemnościowych. Do jej działania wymagane są co najmniej dwa piny: jeden pracujący w trybie wyjściowym, generujący sygnał pobudzający i drugi pracujący w trybie wejściowym dokonujący pomiaru. Poza tym niezbędny jest rezystor oraz przewód i fragment folii pełniący rolę czujnika.

Przy maksymalnej czułości (czułość jest regulowana rezystorem), sensor wykrywa zbliżenie już z odległości kilkunastu centymetrów.

Zasada działania

Funkcja capSense przełącza stan na wyjściu send i czeka, aż na wejściu receive pojawi się ten sam stan. Pomiędzy zdarzeniami inkrementowany jest licznik, którego wartość jest zwracana po jej zakończeniu.

Do wejścia receive podłączony jest czujnik (folia podłączona przewodem). Gdy wyjście send zmienia stan, na receive pojawi się on z opóźnieniem wynikającym ze stałej czasowe obwodu RC (nasz rezystor oraz pojemność wejścia i naszej folii).

Funkcje biblioteki

Biblioteka składa się z trzech funkcji zasadniczych i kilku pomocniczych.

CapSense CapSense(byte sendPin, byte receivePin)

Funkcja ta wywołuje instancję CapSense (ważne: istnieje inna funkcja o podobnej nazwie – różnice są tylko w wielkości liter)

long capSenseRaw(byte samples)

Funkcja capSenseRaw wymaga jednego parametru (samples), zwraca natomiast pojemność bezwzględną w wewnętrznych jednostkach. Parametr samples może zostać wykorzystany do zwiększenia rozdzielczości zwracanego wyniku. Dzieje się to jednak kosztem zmniejszenia wydajności. Zwracana wartość nie jest uśredniana w funkcji ilości próbek, zwracana jest wprost zawartość licznika.

Funkcja capSenseRaw zwróci wartość -2 jeśli czas pomiaru przekroczy wartość CS_Timeout_Millis. Wartość domyślna CS_Timeout_Millis wynosi 2000 milisekund (2 sekundy).

long capSense(byte samples)

Funkcja capSense wymaga jednego parametru (samples), zwraca natomiast pojemność dodaną w wewnętrznych jednostkach. capSense monitoruje najmniejszą pojemność (pojemność bazową) i odejmuje jej wartość od wielkości zmierzonej.

Pojemność bazowa jest wyliczana (kalibrowana) w odstępach czasowych wyznaczonych przez CS_Autocal_Millis. Wartość domyślna to 200000 milisekundy (20 sekund). Re-kalibracja może być wyłączona poprzez ustawienie CS_Autocal_Millis na dużą wartość (funkcją set_CS_AutocaL_Millis()).

void set_CS_Timeout_Millis(unsigned long timeout_millis);

Funkcja set_CS_Timeout_Millis ustawia wartość zmiennej CS_Timeout_Millis, która określa czas po jakim nastąpi timeout, jeśli wejście receive (czujnik) nie przełączy się na ten sam stan co wyjście send. Timeout jest konieczny ponieważ pętla, w której następuje inkrementowanie licznika może zawiesić działanie programu. Wartość domyślna CS_Timeout_Millis wynosi 2000 (2 sekundy).

void reset_CS_AutoCal()

Funkcja reset_CS_AutoCal służy do wymuszenia natychmiastowej kalibracji funkcji capSense.

void set_CS_AutocaL_Millis(unsigned long autoCal_millis)

Funkcja set_CS_AutocaL_Millis(unsigned long autoCal_millis) służy do ustawienia odstępu czasu w jakim mają się wykonywać re-kalibracje. Istnieje możliwość całkowitego wyłączenia re-kalibracji wywołując funkcję set_CS_AutocaL_Millis z parametrem 0xFFFFFFFF.

Jak dobrać wartość rezystora?

Poniżej przedstawione zostały pewne zasady dobierania wartości rezystora. Dla pewności jednak należy wykonać eksperyment z daną sztuką.

  • użyj rezystora o wartości 1 M do zastosowań, gdzie zadziałanie czujnika ma się odbywać poprzez jego dotknięcie.
  • z rezystorem o wartości 10 M czujnik zacznie reagować, już gdy obiekt znajdzie się w odległości 10-15 centymetrów.
  • z rezystorem o wartości 40 M czujnik zacznie reagować, już gdy obiekt znajdzie się w odległości 30-60 centymetrów.
  • zwiększanie czułości (proporcjonalnie do wartości rezystora) powoduje zmniejszenie szybkości działania czujnika.
  • eksperyment z małym kondensatorem (100 pF – 0.01 uF) włączonym między sensor a masę układu, wykazał zwiększenie stabilność czujnika.

Czujniki mogą być zbudowane z wykorzystaniem jednego wyjścia send oraz kilku rezystorów i wejść receive. Przecież wystarczy jedno źródło pobudzenia. Zobacz zresztą na przykładowy kod (przy końcu artykułu).

Uziemienie i znane problemy

Uziemienie płytki duino jest bardzo ważne dla aplikacji z czujnikami pojemnościowymi. Płytka musi mieć jakieś uziemienie, nawet jeśli kiepskie np. przewód podłączony do kaloryfera.

Czujniki pojemnościowe wykazują pewne problemy, gdy płytka podłączona jest do laptopa odłączonego od zasilania sieciowego. Zbliżenie ręki do laptopa zmienia odczytywaną wartość – laptop staje się czujnikiem.

Rozwiązaniem tego problemu może być podłączenie laptopa do sieci zasilającej. Inne rozwiązanie to uziemienie płytki Arduino.

Suwak pojemnościowy

Autor biblioteki twierdzi, że udało mu się uruchomić suwak pojemnościowy z zastosowaniem tylko dwóch pinów mikrokontrolera. Autor odsyła przy tym do dokumentacji Quantum Scrollwheel – nie mogłem jej nigdzie znaleźć.

Dla suwaka kod wygląda następująco

CapSense Left32  = CapSense(3, 2); // wire from pin 2 to left side of resistor ladder
CapSense Right23 = CapSense(2, 3); // wire from pin 3 to right side of resistor ladder

W takiej konfiguracji piny na zmianę pełnią rolę nadajnika i odbiornika.

Gdy palec przesuwa się od jednego pinu do drugiego, funkcja capSenseRaw zwraca zmieniające się wartości, których suma w przybliżeniu jest stała.

Komunikaty o błędach

Funkcje capSense oraz capSenseRaw zwrócą wartość -1 przy wybraniu złego pinu do obsługi czujnika (autor dodaje jednak, że błąd ten nie jest obecnie sygnalizowany poprawnie).

Funkcje capSense oraz capSenseRaw zwrócą wartość -2 jeśli czas ich wykonania przekroczył określoną wartość CS_Timeout_Millis (domyślnie są to 2 sekundy). Sytuacja taka ma miejsce najczęściej, gdy rezystor został podłączony do złego pinu, lub nie został podłączony w ogóle (może się np. odłączyć podczas działania układu). Wystąpi również, gdy czujnik został zwarty do masy lub dodatniego potencjału zasilania.

Instalacja

  • pobierz CapacitiveSense003.zip
  • rozpakuj i przenieś do katalogu Arduino/hardware/libraries/
  • aby dodać capSense do nowego projektu wybierz Sketch->Import Library->CapSense.

Przykładowy kod

#include <CapSense.h>
 
/*
 * CapitiveSense Library Demo Sketch
 * Paul Badger 2008
 * Uses a high value resistor e.g. 10M between send pin and receive pin
 * Resistor effects sensitivity, experiment with values, 50K - 50M. Larger resistor values yield larger sensor values.
 * Receive pin is the sensor pin - try different amounts of foil/metal on this pin
 * Best results are obtained if sensor foil and wire is covered with an insulator such as paper or plastic sheet
 */
 
 
CapSense   cs_4_2 = CapSense(4,2);        // 10M resistor between pins 4 & 2, pin 2 is sensor pin, add wire, foil
CapSense   cs_4_5 = CapSense(4,5);        // 10M resistor between pins 4 & 6, pin 6 is sensor pin, add wire, foil
CapSense   cs_4_8 = CapSense(4,8);        // 10M resistor between pins 4 & 8, pin 8 is sensor pin, add wire, foil
 
void setup()                    
{
 
   cs_4_2.set_CS_AutocaL_Millis(0xFFFFFFFF);     // turn off autocalibrate on channel 1 - just as an example
   Serial.begin(9600);
 
}
 
void loop()                    
{
    long start = millis();
    long total1 =  cs_4_2.capSense(30);
    long total2 =  cs_4_5.capSense(30);
    long total3 =  cs_4_8.capSense(30);
 
    Serial.print(millis() - start);        // check on performance in milliseconds
    Serial.print("\t");                    // tab character for debug windown spacing
 
    Serial.print(total1);                  // print sensor output 1
    Serial.print("\t");
    Serial.print(total2);                  // print sensor output 2
    Serial.print("\t");
    Serial.println(total3);                // print sensor output 3
 
    delay(10);                             // arbitrary delay to limit data to serial port 
}

Podsumowanie

Przedstawione metody nie są idealne, ale prostota ich zastosowania i minimalne wymagania sptrzętowe (elementy dodatkowe) sprawiają, że znajdą nie jedno zastosowanie w naszych konstrukcjach.

Jeśli stworzysz coś na ich podstawie, daj znać w komentarzach do tego wpisu. Napisz też jeśli korzystasz z innej metody na stworzenie klawiatury zbliżeniowej.

Oceń ten wpis:
1 gwiazdka2 gwiazdki3 gwiazdki4 gwiazdki5 gwiazdek (głosów: 2, średnia ocen: 3,00)
Loading ... Loading ...
Wyświetleń: 5 026

Podobne artykuły

Możesz śledzić komentarze do tego wpisu poprzez kanał RSS 2.0. Możesz także dodać własny komentarz, lub trackback z własnej strony WWW.

2 komentarzy do “Czujnik pojemnościowy i Arduino”

  • Mariusz (2 czerwca, 2010, 13:48)

    Witam, a jak powinno wyglądać połączenie z folią i rezystorem (wersja 2), można dostać jakiś schemacik?

  • michal (2 czerwca, 2010, 19:24)

    Połączenie jest bardzo proste. Poniżej ilustracja poglądowa:

    CapSense

Dodaj komentarz