아두이노의 디지털핀 두 개와 저항 하나로 터치 센서를 구현할 수 있는데 관련 객체를 제공하는 것이 바로 Capacitance Sensing Library 이다.

기본 개념과 구성 회로

정전용량식 터치 센서의 개념도는 아래 그림과 같다.

[그림 1] 정전용량식 터치 센서의 개념도


이 개념도를 보면 두 개의 핀을 사용하는데 하나는 발신 핀(send pin) 이고 다른 하나는 수신 핀(receive pin)이다. 이 두 핀을 저항으로 연결하고 수신 핀에 터치할 도체(foil)를 연결한다. 만약 이 도체를 터치를 하면 수신 핀 단의 정전용량이 틀려지고 발신 핀에서 신호를 보낼 때(즉 발신 핀이 on되었을 때) 수신 핀이 기립 시간(rising time, 발신 핀이 on 된 후 수신핀이 on이 되는데 걸리는 시간 간격)이 변하게 된다. 이 변화를 감지하여 터지가 되었는지 안 되었는지를 판단하는 것이다.

해당 라이브리리 설치와 사용법

 이 기능을 아두이노에서 사용하려면 먼저 라이브러리를 다운로드 받아서 설치해야 한다. 아래와 같은 절차를 따른다.


  1. 소스를 다운로드 받는다.( CapacitiveSensor04.zip )

  2. 압축을 푼 후 그 안의 CapacitiveSensor 폴더를 복사해서 Arduino/libraries/ 폴더에 붙인다.

  3. 아두이노 IDE에서 Sketch>Import Library>CapacitiveSensor 메뉴를 선택한다.


위와 같이 했다면 IDE에 다음과 같이 헤더파일이 인클루드 된다.


#include <CapacitiveSensor.h>


이 라이브러리에서는 CapacitiveSensor라는 클래스가 있는데 이것의 인스턴스는 다음과 같이 초기화 할 수 있다.


CapacitiveSensor CapacitiveSensor(byte sendPin, byte receivePin);

 

여기서 sendPin과 receivePin 은 저항이 연결된 두 개의 디지털 핀을 지정해주면 된다. 이제 이 인스턴스의 메소드(함수)로 다음과 같은 것들이 있다.

long capacitiveSensorRaw(byte samples)


이 함수는 감지된 정전용량 값을 반환이며 반환값은 무단위이다. 입력으로 주어지는 samples 는 (byte형이므로 0-255 사이의 값) 샘플링 횟수를 지정해 주는 것이다. 이 값이 커지면 리턴값의 분해능이 커지는 대신 속도가 느려지게 되므로 적당한 값을 선택해야 한다. 리턴값은 각각의 샘플링에서 얻어진 값을 모두 더한 값이며 평균값이 아니다.


long capacitiveSensor(byte samples)


이 함수 역시 감지된 정전용량 값을 반환이며 반환값은 무단위이다. 앞의 함수와 다른 점은 터치가 안 되었을 때의 값(기본값)을 추적하여 현재 감지된 값에서 그 값을 뺀 다음 반환한다. 따라서 터지가 안 된 상태라면 0에 가까운 작은 값을 반환하고 터치가 되었다면 그것 보다는 큰 숫자를 반환한다.


 기본값(터치가 안 되었을 때의 정전용량 값)은 CS_Autocal_Millis 라는 상수에 저장된 시간 마다 자동으로 조정된다. 초기값은 20000 밀리초 (20초)이다. 이 갱신 시간은 set_CS_Autocal_Millis() 함수를 이용해서 변경할 수 있다.


void set_CS_Autocal_Millis(unsigned long autoCal_millis);


자동 갱신 기능을 끄려면 매우 큰 값(0xFFFFFFFF)으로 지정하면 된다.


 만약 즉시 기본값을 조정하려면 다음 함수를 호출하면 된다.


void reset_CS_AutoCal()


그리고 사용 빈도는 낮지만 다음 함수는 capacitiveSensor()함수나 capacitiveSensorRaw()함수의 타임아웃 시간을 지정해주는 함수도 있다.


void set_CS_Timeout_Millis(unsigned long timeout_millis);


이 함수는 CS_Timeout_Millis 내부 변수를 변경하는 함수인데 초기값은 2000 밀리초(2초)이다. 타임아웃시간이란 발신핀이 on 되었는데도 수신핀이 on이 되지 않을 경우 언제까지 기다려야 하는가를 정하는 것이다. 타임아웃 시간이 지나도 수신핀이 on이 되지 않으면 -2를 반환한다.

저항값의 선택

저항값은 다음과 같은 기준으로 선택한다.

  • 1 MΩ (혹은 이것보다 다소 작은 용량) : 완전히 터치되었을 때에만 반응시키고자 할 때

  • 10 MΩ : 4~6인치 정도 떨어진 곳에서도 반응시킬 때

  • 40 MΩ : 12~24인치 정도 떨어진 곳에서도 반응시킬 때 (도체의 크기에 따라 가변적임)


즉, 저항값이 커지면 감도도 높이지고 반응 속도는 느려진다. 또한 터치부가 노출된 금속판이라면 발신부에서서 on 신호를 발생시키지 못 할 가능성도 있다. 수신핀을 작은 용량의 커패시터 (100 pF ~ 0,01uF) 를 통해서 접지시키면 센서의 안정도를 개선시킬 수 있다.

실제 예제 프로그램

 회로도는 다음과 같다. 아두이노 우노와 1MΩ 저항 하나로 구성한다.

[그림 2] 실험 회로도


다음 프로그램을 실행하면 D3핀 쪽의 리드선을 터치할 때 LED가 켜진다.


#include <CapacitiveSensor.h>
#define LED 13
CapacitiveSensor cs23 = CapacitiveSensor(2,3);
void setup() {
   pinMode(LED, OUTPUT);
   cs23.set_CS_Autocal_Millis(0xFFFFFFFF);
   Serial.begin(9600);
}
void loop() {
   long start = millis();
   long total1 = cs23.capacitiveSensor(30);
   (total1>10) ? digitalWrite(LED, HIGH):digitalWrite(LED, LOW);
}



Posted by 살레시오
,

 다음 예제들은 DFRobot사의 LCD쉴드를 이용하여 실험을 진행하였다.

[그림 2] 실험에 사용된 LCD쉴드와 회로도

회로도를 보면 RS가 8번 핀, RW가 9번핀, 그리고 D4~D7번 핀이 4번에서 7번핀까지로 결선되어 있음을 알 수 있다. 따라서 LiquidCrystal 클래스의 인스턴스는 첫 번째 생성자를 이용하여 다음과 같이 생성하면 된다.

LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

이제 예제들을 작성해 보도록 하겠다.

첫 번째 예제

 첫 번째 예제로 간단한 문자열을 출력하는 프로그램이다.


// 헤더파일을 인클루드 시킨다.
#include <LiquidCrystal.h>
// 회로도를 참조하여 LCD 객체를 생성/초기화시킨다.
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
void setup() {
   // LED의 행수와 열수를 주어 표시를 시작한다.
   lcd.begin(16, 2);
   // LDC에 문자열을 표시한다.
   lcd.print("hello, world!");
}
void loop() {
   // 커서의 위치를 0열, 1행(두 번재 행)으로 설정한다.
   lcd.setCursor(0, 1);
   // 초를 표시한다.
   lcd.print(millis()/1000);
}

두 번째 예제

 LiquidCrystal 라이브러리에는 blink() 와 noBlink() 함수가 있는데 깜박이는 직사각형의 커서를 표시할 것인지 아닌지를 설정하는 함수이다. 다음 예제를 이것을 이용한 것이다.


#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

void setup() {
   lcd.begin(16, 2);
   lcd.print("hello, world!");
}
void loop() {
   lcd.noBlink();
   delay(3000);
   lcd.blink();
   delay(3000);
}

유사한 함수로 cursor() 함수와 noCursor()함수가 있는데 이것은 밑줄 모양의 커서를 표시할 것인가 말 것인가를 설정하는 것이다. 이 경우 밑줄 커서는 깜박이지 않는다.

세 번째 예제

 LiquidCrystal 라이브러리의 공용 멤버함수 중에는 display()함수와 noDisplay()함수가 있다. 함수 명에서 알 수 있듯이 화면에 표시를 할 것인지 말 것인지를 설정하는 것이다.


#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

void setup() {
   lcd.begin(16, 2);
   lcd.print("hello, world!");
}

void loop() {
   lcd.display();
   delay(3000);
   lcd.noDisplay();
   delay(3000);
}


위 예제어서 noDisplay()함수가 실행되면 화면에 표시된 문자열이 사라지지만 그 내용은 내부 메모리에 여전히 남아있다. 따라서 display()함수가 호출되면 되살아나는 것이다. 또한 이 함수들을 이용하면 화면 전체를 깜박이는 효과를 줄 수도 있다.

네 번째 예제

문자열이 표시되는 방향을 바꾸는 함수로 rightToLeft()함수와 leftToRight()함수가 있다. 다음 예제는 이것을 이용한 것이다.


#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
int thisChar = 'a';
void setup() {
   lcd.begin(16, 2);
   lcd.cursor();
}
void loop() {
   // ‘m’ 이 표시되면 방향을 바꾼다.
   if (thisChar == 'm') {
       lcd.rightToLeft();
   }
   // 's'가 표시되면 방향을 다시 바꾼다.
   if (thisChar == 's') {
       lcd.leftToRight();
   }
   // 'z'가 표시된 후 처음 조건으로 다시 리셋한다.
   if (thisChar > 'z') {
       lcd.clear(); // 화면을 지운 후 커서를 처음 자리로
       thisChar = 'a';
   }
   lcd.write(thisChar);
   delay(1000);
   thisChar++;
}


다섯 번째 예제

 이번에는 터미널에 입력한 문자를 LCD에 표시하는 프로그램을 작성해 보자.

#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
void setup() {
   lcd.begin(16, 2);
   Serial.begin(9600);
}
void loop() {
   // 문자가 전송되면
   if (Serial.available()) {
       // 전체 문자열이 들어올 때까지 잠시 기다린다.
       delay(100);
       lcd.clear();
       // 전송된 모든 문자를 표시한다.
       while (Serial.available() > 0) {
           lcd.write(Serial.read());
       }
   }
}


여섯 번째 예제

 화면의 내용을 스크롤(scroll)하는 예제이다.


#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
void setup() {
   lcd.begin(16, 2);
   lcd.print("hello, world!");
   delay(1000);
}
void loop() {
   // 왼쪽으로 스크롤
   for (int cnt = 0; cnt < 13; cnt++) {
       lcd.scrollDisplayLeft();
       delay(150);
   }
   // 오른쪽으로 스크롤
   for (int cnt = 0; cnt < 29; cnt++) {
       lcd.scrollDisplayRight();
       delay(150);
   }
   // 다시 왼쪽으로 스크롤하여 제자리로
   for (int cnt = 0; cnt < 16; cnt++) {
       lcd.scrollDisplayLeft();
       delay(150);
   }
   delay(1000);
}


이 예제에서는 scrollDisplayLeft() 함수와 scrollDisplayRight() 함수를 이용하여 수동으로 이동시켰다. 반면 autoScroll()함수를 사용하면 문자가 표시되기 전에 왼쪽으로 자동으로 이동이 된다.




Posted by 살레시오
,

 가전제품이나 전자 장치에서 간단한 정보를 표시하는데 많이 사용되는 것이 바로 액정 표시기 (liquid crystal display, LCD)이다. 크게 문자만을 표시할 수 있는 문자형과 선이나 도형 등 그래픽을 그릴 수 있는 그래픽형으로 나뉜다.

[그림 1] LCD 장치의 예

아두이노의 LiquidCrystal 라이브러리는 텍스트 액정(liquid crystal) 표시장치를 구동하기 위한 라이브러리이다. 이 라이브러리를 이용하기 위해서는 다음과 같이 프로그램 서두에 해당 헤더파일을 인클루드시켜야 한다.


#include <LiquidCrystal.h>

이 헤더파일에는 LiquidCrystal 이라는 클래스가 정의되어 있으며 다음과 같은 공용(public) 멤버함수들이 정의되어 있어서 쉽게 사용할 수 있다.

  • 생성자 : LCD 모듈과 아두이노의 연결 방식에 따라서 생성자를 사용하면 된다. 다음과 같은 네 가지 함수가 오버로드되어 있다.

       ❶ LiquidCrystal(rs, enable, d4, d5, d6, d7)

       ❷ LiquidCrystal(rs, rw, enable, d4, d5, d6, d7)

       ❸ LiquidCrystal(rs, enable, d0, d1, d2, d3, d4, d5, d6, d7)

       ❹ LiquidCrystal(rs, rw, enable, d0, d1, d2, d3, d4, d5, d6, d7)

보통은 핀수를 가장 적게 차지하는 ❶번 방식이 많이 사용된다.  멤버함수는 다음과 같다.


[표 1] LiquidCrystal 클래스의 멤버 함수들

멤버 함수

기능

void begin(row, col)

LCD를 초기화 한다.

void clear()

화면을 지운 후 커서를 처음 자리로 옮긴다.

void home()

화면은 그대로 나둔채로 처서만 (0,0)자리로 옮긴다.

setCursor(col, row)

커서를 (col, row)자리로 옮긴다.

byte write(data)

한 문자를 출력한다.

print(data, BASE)

문자열이나 변수 값을 출력한다.

createChar()

사용자 (그림)문자를 생성한다. (8개까지 가능함)

void cursor()

(밑줄)커서를 표시한다.

void noCursor()

커서를 표시하지 않는다

void blink()

깜박이는 커서를 표시한다.

void noBlink()

커서를 표시하지 않는다.

void display()

내용을 표시한다.

void noDisplay()

내용을 표시하지 않는다.(메모리에 내용은 남아 있음)

scrollDisplayLeft()

표시된 내용을 왼쪽으로 한 칸 이동한다.(회전)

scrollDisplayRight()

표시된 내용을 오른쪽으로 한 칸 이동한다.(회전)

void autoscroll()

기존 내용을 좌로 이동시킨 후 현재 내용을 표시.

noAutoscroll()


void leftToRight()

문자 표시 방향을 왼쪽에서 오른쪽으로 설정한다.

void rightToLeft()

문자 표시 방향을 오른쪽에서 왼쪽으로 설정한다.

여기서 write()함수는 입력을 아스키(ASCII)값으로 받으며 print()함수는 문자열이나 상수(변수)값을 받는 것에 유의하자.



Posted by 살레시오
,