보통 프로세서가 사용되는 디지털 시스템(아두이노 등)에서는 만약 계통에 특정한 이벤트가 발생했을 경우에는 수행 중인 작업을 중단하고 발생한 이벤트를 처리한 다음, 다시 원래 수행하던 작업으로 되돌아가 계속 처리하게 된다. 이러한 ‘즉시 처리해야 하는 특수한 이벤트의 발생’을 인터럽트라고 한다. 인터럽트가 발생하면 아두이노는 그 이벤트를 처리할 작업들이 수록된 함수를 호출하는데 이 함수를 인터럽트 서비스 루틴 (interrupt service routine, 이하 ISR)이라고 한다.


  • 인터럽트 : 즉시 처리해야 하는 특수한 이벤트의 발생

  • ISR : 인터럽트 서비스 루틴, 인터럽트가 발생했을 때 호출되는 함수


 이 인터럽트는 마이크로프로세서 시스템에서 굉장히 중요한 비중을 차지한다. 비유를 들어서 설명하자면 어떤 전화기가 있는데 전화가 걸려왔는데도 벨소리도 안 나고 진동도 안 된다고 가정해보자. 이 전화기로 꼭 받아야만 하는 중요한 전화가 올 예정이라면 그 사람은 다른 일은 못 하고 몇 초에 한 번씩 전화가 왔나 안 왔나 들어서 확인해 봐야 할 것이다. 하지만 전화가 걸려왔을 때 벨소리가 나거나 진동하는 전화라면 편하게 다른 일을 하고 있다가 전화가 오면 벨소리를 듣고(인터럽트 요구) 전화를 받아 용무를 처리한 후 하던 일을 계속할 것이다.


 터치 버튼을 가지고 부연 설명을 하면 ‘터치되었다’라는 특수한 이벤트를 감지하려면 기본적으로 아두이노가 loop()함수 내에서 항상 이 버튼의 상태를 검사해야 한다. 하지만 이것을 인터럽트로 처리하면 소프트웨어적으로 이 버튼의 상태를 항상 검사할 필요가 없이 다른 일을 할 수가 있는 것이다. 다른 작업을 하고 있다가 ‘버튼이 눌려지면’ 그 즉시 (하드웨어적으로) 인터럽트를 발생하여 하던 일을 멈추고 이를 처리할 ISR을 호출한 뒤 ISR이 끝나면 하던 일을 다시 하면 되는 것이다. 이와 같이 (외장 혹은 내장) 주변기기와 아두이노가 통신을 수행하는데 있어서 아두이노가 주변기기의 상태를 loop()함수에서 상시 검사하지 않고 인터럽트로 처리하면 전체적인 시스템의 운용 효율이 매우 높아지게 된다.


 아두이노 우노의 경우 인터럽트를 처리할 수 있는 핀은 2번과 3번 핀인데 각각 INT0, INT1이라고 부른다. (인터럽트 0번, 인터럽트 1번 이다.)


[표 1] 아두이노 우노의 인터럽트핀


INT0

INT1

핀번호

2번 핀

3번 핀


 좀 더 구체적으로 설명하면 인터럽트라는 것은 이 핀들의 특정한 신호 상태를 의미한다. 예를 들면 신호가 0에서 1로 바뀌는 순간 (또는 그 반대의 경우도) 에 하던 일을 멈추고 연결된 특정한 함수(ISR)를 수행할 수 있다. 신호가 0에서 1로 변하는 순간을 ‘rising edge’ 라고 하고 1에서 0으로 변하는 순간을 ‘falling edge’라고 한다.


ISR을 등록하기 위한 아두이노 함수로 attachInterrup()라는 함수가 있다.


   attachInterrupt( pin, ISR, mode) 함수

  • 인터럽트핀에 처리 함수를 붙이는 일을 수행한다.

  • pin 값은 우노의 경우 0(또는 INT0 ), 1 (또는 INT1) 둘 중 하나이다.

  • 2번 핀의 경우 0을, 3번 핀의 경우 1을 입력해야 한다는 것에 주의해야 한다. 혼동을 피하기 위해서 INT0, INT1 상수를 이용할 것을 권한다.

  • ISR은 인터럽트가 걸렸을 때 호출할 함수의 이름이다.

  • mode 는 RISING / FALLING / CHANGE / LOW 중 하나이다. (아래 표 참조)



RISING

FALLING

CHANGE

LOW

[그림 1] 아두이노에서 사용되는 인터럽트의 종류


 ISR은 입력 인수를 받을 수 없고 출력도 void형이어야 한다. 이 attatchInterrupt() 함수는 통상 setup() 함수 안에서 사용되어 초기에 인터럽트를 설정한다.


아두이노 강좌 전체 목록 (TOP) >>>

C++ 언어 전체 강좌 목록 >>>

c{ard},n{ad015}

Posted by 살레시오

댓글을 달아 주세요

 초음파 센서 모듈은 초음파를 발생시켜서 물체에 반사되어 돌아오는 시간을 측정해서 물체까리의 거리를 구할 수 있는 장치이다. 다음 그림은 parallax.com 사의 초음파 센서 모듈이다. (저가형 중국산 모듈은 4핀이 달린 것도 있으나 성능이나 사용법은 동일하다.)


전원핀,

GND핀,

출력핀, 세 개로 동작한다.

2cm 부터 3m 범위를 측정할 수 있다.

[그림 1] parallax.com 사의 초음파센서모듈


이 모듈의 사용법은 굉장히 간단하다. 일단 5V, GND 핀을 연결한 후 신호핀은 아두이노의 디지털 핀에 연결한다. 그리고 디지털핀으로 시작 신호(펄스)를 보낸 후 같은 핀에서 되돌아오는 펄스의 폭(시간)을 잰다.



[그림 2] 초음파 모듈의 동작 순서

- 시작 펄스는 5micro-sec 동안 유지해야 한다.

- 응답 펄스는 초음파가 발생한 후 되돌아온 시간 동안 HIGH를 유지한다.


이 응답 펄스의 폭은 장애물과의 거리에 비례하며 초음파가 발생된 후 되돌아올 때 까지의 시간동안 HIGH로 유지된다. 오직 하나의 디지털 핀만을 사용하므로 시작 신호를 보낸 후 바로 핀의 모드를 입력으로 전환해야 한다.  시작 펄스는 5micro-sec 동안 유지해야 한다. 각 단계는 다음과 같다.


  1. 핀을 출력으로 설정한다.

  2. LOW신호를 2micros 동안 유지한다.

  3. HIGH 신호를 5micros동안 유지한다.

  4. LOW로 신호를 내보냄과 동시에 핀을 입력으로 설정한다.

  5. pulseIn() 함수를 이용하여 펄스가 HIGH인 구간 시간을 micros 단위로 받는다.



 초음파 모듈 시간은 초음파를 송신함과 동시에 핀을 HIGH로 올리고 물체에 반사된 초음파를 수신하면 LOW로 내린다. 따라서 핀이 HIGH로 유지되는 경과 시간은 초음파가 나가서 물체에 반사되어 되돌아온 시간인 것이다.


 이 시간을 이용한 계산으로 거리 값을 도출할 수 있는데 다음과 같은 식을 이용한다. 소리는 초당 343m를 이동하므로 1cm를 이동하는데 29.155micro-sec 이 걸린다. 따라서 측정된 시간(마이크로 초 단위)를 58.31 로 나누어야 한다. 2를 곱해주는 것은 측정된 시간이 왕복 시간이기 때문이다.


 이제 이러한 내용을 바탕으로 코딩을 해보자.


#define MS_PER_CM           58.31f
#define ULTRA_SONIC_SENSOR  2

void setup() {
 Serial.begin(9600);
}

void loop() {
 float fDist = measureDist();
 if (fDist < 0) {
   Serial.println("No obstable or no sensor.");
 } else {
   Serial.print("Distance: ");
   Serial.print(fDist);
   Serial.println(" cm");
 }
 delay(100);
}

float measureDist() {
 pinMode(ULTRA_SONIC_SENSOR, OUTPUT); //(1)단계
 digitalWrite(ULTRA_SONIC_SENSOR, LOW); //(2)단계
 delayMicroseconds(2);
 digitalWrite(ULTRA_SONIC_SENSOR, HIGH); //(3)단계
 delayMicroseconds(5);
 digitalWrite(ULTRA_SONIC_SENSOR, LOW); //(4)단계
 pinMode(ULTRA_SONIC_SENSOR, INPUT);

// (5) 단계
 unsigned long ulPulseTime = pulseIn(ULTRA_SONIC_SENSOR, HIGH);
 if (ulPulseTime == 0 )
   return -1.0f;
 else
   return ulPulseTime / MS_PER_CM;
}


위 코드에서 measureDist() 함수를 실행하면 위에서 설명한 각 단계를 거쳐서 거리까지 계산한 float 값을 반환한다. 만약 pulseIn()함수의 반환값이 0이라면 -1.0f 를 반환하여 장애물이 감지되지 않은 것임을 표시한다.


아두이노 강좌 전체 목록 (TOP) >>>

C++ 언어 전체 강좌 목록 >>>

c{ard},n{ad014}

Posted by 살레시오

댓글을 달아 주세요

시리얼 통신 두 번째 예제

 두 번째 예제로 이번에는 PC에서 문자 하나를 받아서 그것이 ‘0’이면 LED를 끄고 ‘1’이면 LED를 켜는 프로그램을 작성해 보자. 이 경우 아두이노는 데이터가 사용자로부터 들어올 때 까지 대기 상태로 있다가 데이터가 읽히면 거기에 맞는 동작을 수행해야 한다.


#define LED 13
void setup() {
 pinMode(LED, OUTPUT);
 Serial.begin(9600);
}
void loop() {
 if ( Serial.available() ) {
   char command = Serial.read();
   if (command == '0') {
     digitalWrite(LED, LOW);
     Serial.println("LED off.");
   }
   else if (command == '1') {
     digitalWrite(LED, HIGH);
     Serial.println("LED on.");
   }
     else {
     Serial.print("Wrong command :");
     Serial.println(command);
     }
 }
}


이 예제에서는 다음과 같은 함수들이 사용되었다.


   int Serial.available() 함수

  • 전송되어 내부버퍼(64바이트)에 저장된 데이터의 개수를 반환한다.

  • 입력인수는 없다.


   int Serial.read() 함수

  • 전송되어 내부 버퍼(64바이트)에 저장된 데이터 중 가장 첫 번째 데이터(ASCII코드)를 읽어서 반환한다.

  • 이 함수가 수행되면 내부 버퍼의 크기는 하나가 줄어든다.

  • 내부 버퍼가 비었다면 -1을 반환하다.


   int Serial.println() 함수

  • 출력 문자열의 끝에 줄바꿈 기호 ‘\r\n’ 가 자동으로 붙는다는 점 외에는 Serial.print()함수와 동일한 동작을 수행한다.


이 예제에서는 USRT 통신기의 내부 버퍼의 개념을 이해할 필요가 있다. 내부 버퍼란 전송된 데이터가 일시적으로 저장되는 내부 메모리를 말하며 데이터가 전송된 순서대로 저장된다. 아두이노의 내부 버퍼의 크기는 64바이트이다. 전송되어 저장된 데이터를 사용하려면 내부 버퍼에서 이 데이터를 읽어내야 하는데 이때 사용되는 함수가 Serial.read()함수이다. 가장 먼저 전송된 데이터 하나를 읽어낸 후 그 데이터는 버퍼에서 삭제되며, 만약 버퍼가 비었다면 -1을 반환한다. 따라서 버퍼에 읽어낼 데이터가 있는지 없는지를 먼저 검사하는 것이 일반적이고 이때 사용되는 함수가 Serial.available()이다. 이 함수는 버퍼에 저장된 데이터의 개수를 반환하며 따라서 버퍼가 비어있다면 0을 반환한다.


 이런 사항들을 이해하였다면 두 번째 예제를 이해하는데 어려움이 없을 것이다. 데이터가 전송되어 오면 그것을 읽어들여서 ‘1’이면 LED를 켜고, ‘0’이면 끈다. 그 이외의 데이터에 대해서는 잘못된 명령이라는 문자열을 출력한다.


시리얼 통신 세 번째 예제

 세 번째로 11번 핀에 부저가 연결되었다고 가정하고 명령어를 하나 받아서 다음과 같은 동작을 수행하는 예제를 작성해 보도록 하겠다.


       - ‘0’ : LED를 끈다.

       - ‘1’ : LED를 켠다.

       - ‘2’ : 부저를 짧게 한 번 울린다. (삑)

       - ‘3’ : 부저를 짧게 두 번 울린다.(삐삑)

       - 그 외의 명령어들은 잘못된 것이라는 메세지를 출력한다.


이 예제의 경우는 처리해야 될 경우의 수가 많기 때문에 if-else 명령보다는 switch-case 명령이 더 효율적이다.


#define LED 13
#define BUZ 11

void setup() {
 pinMode(LED, OUTPUT);
 pinMode(BUZ, OUTPUT);
 Serial.begin(9600);
}

void loop() {
 if ( Serial.available() ) {
   char command = Serial.read();
   switch(command) {
     case '0':
       digitalWrite(LED, LOW);
       Serial.println("LED off.");
       break;
   case '1' :
     digitalWrite(LED, HIGH);
     Serial.println("LED on.");
     break;
   case '2' :
     digitalWrite(BUZ, HIGH);
     delay(50);
     digitalWrite(BUZ, LOW);
     break;
   case '3' :
     digitalWrite(BUZ, HIGH);
     delay(50);
     digitalWrite(BUZ, LOW);
     delay(50);
     digitalWrite(BUZ, HIGH);
     delay(50);
     digitalWrite(BUZ, LOW);
     break;
   default:
     Serial.print("Wrong command :");
     Serial.println(command);
   }
 }
}


아두이노 강좌 전체 목록 (TOP) >>>

C++ 언어 전체 강좌 목록 >>>

c{ard},n{ad013}

Posted by 살레시오

댓글을 달아 주세요

 시리얼 통신(serial communication)은 기기들간 데이터를 주고 받는 방법 중 하나인데 병렬 통신 (parallel communication) 방식에 비해서 통신선의 갯수가 적다는 장점이 있다.  아두이노는 UART (universal asynchronous receiver and transmitter), SPI, I2C 방식의 시리얼 통신을 지원하는데 이중 UART는 주로 아두이노와 PC간의 통신을 하는데 사용된다. 아두이노는 하나 이상의 UART 통신기가 내장되어 있는데  라이브러리와 IDE에 내장된 터미널(terminal, 주고 받는 데이터를 확인할 수 있는 프로그램)을 이용하면 손쉽게 PC와의 통신을  수행할 수 있다.


 아두이노 우노의 경우 0번과 1번핀이 시리얼 통신에 사용된다. 이 핀들은 내부적으로 USB통신을 담당하는 칩과 연결되어서 USB신호로 변환된 후 PC에 전달된다. 반대로 PC에서 보내지는 USB신호는 이 칩에서 시리얼 통신 신호로 변환되어 아두이노의 AVR에 전달된다. 따라서 만약 아두이노가 PC와의 통신을 수행하고 있다면 이 핀들을 다른 용도로 사용하면 안된다. 그리고 통신을 수행할 때에는 TX, RX라고 마킹된 LED가 깜빡인다.  일단 사용자는 아두이노와 PC간에 USB케이블로 연결하면 통신 실습을 할 준비가 끝나게 된다.


  • 시리얼 통신에 사용되는 두 개의 핀(빨간색)과 usb변환 칩(하늘색)

  • 내부적으로 USART 신호는 USB신호로 변환되어 PC에 전송된다.


시리얼 통신 첫 번째 예제

 첫 번째 예제로 아두이노에서 PC로 간단한 데이터를 전송하는 예를 해보도록 하겠다. 단순히 아두이노에게 전원을 인가하면 “I’m ready.” 라는 메세지를 PC에 전송하는 예이다.


void setup() {
 Serial.begin(9600);
 Serial.printl"I'm ready.");
}
void loop() {
}


이 예제를 다운로드 한 후 터미널을 켜고 리셋버튼을 누르면 터미널에 “I’m ready.”라는 문자열이 찍히는 것을 확인할 수 있다. 터미널 실행 버튼을 누르면 아두이노에 자동으로 리셋신호가 걸려서 프로그램이 처음부터 수행된다. 그리고 프로그램 다운로드 중에서는 터미널을 실행시키지 못 한다는 것도 알아두자.



 UART와 관련되 아두이노의 라이브러리는 Serial클래스에 다 모여있다. (자세한 설명을 여기 참조) 일단 이 예제에서 보면 setup()함수내에서 두 개의 함수가 호출되었다.


void Serial.begin(long baud_rate) 함수

  • UART 통신을 초기화 시킨다.

  • 통신 속도(baud rate)를 입력으로 받는다.        

  • 9600, 19200, 57600, 115200 등 여러 baud rate를 지원한다.


long Serial.print(val) 함수

  • 입력값을 ASCII값으로 변환하여 PC쪽으로 출력한다.

  • 전송된 데이터의 바이트 수를 리턴한다. (잘 사용되지 않음)

  • 비동기 통신 방식이므로 데이터가 전송되기 전에 리턴된다.

  • 입력 변수 val은 어떤 데이터 타입도 가능하다. 예를 들면

    • Serial.print(78) gives "78"

    • Serial.print(1.23456) gives "1.23"

    • Serial.print('N') gives "N"

    • Serial.print("Hello world.") gives "Hello world."


  • 두 번째 인수로 출력 형식을 지정할 수 있다. 예를 들면

    • Serial.print(78, BIN) gives "1001110"

    • Serial.print(78, OCT) gives "116"

    • Serial.print(78, DEC) gives "78"

    • Serial.print(78, HEX) gives "4E"

    • Serial.println(1.23456, 0) gives "1"

    • Serial.println(1.23456, 2) gives "1.23"

    • Serial.println(1.23456, 4) gives "1.2346"


첫 번째 예제는 setup() 함수 내에서 UART를 초기화 하고 문자열 하나를 보내는 아주 간단한 예제이다.


아두이노 강좌 전체 목록 (TOP) >>>

C++ 언어 전체 강좌 목록 >>>

c{ard},n{ad012}

Posted by 살레시오

댓글을 달아 주세요

 인체감지센서 모듈은 적외선을 감지하는 센서를 장착하고 있으며 약 6미터 이내의 인간이나 동물의 움직임을 감지할 수 있다. 인체나 동물의 몸과 같이 열을 발산하는 곳에서 발생하는 적외선을 감지하는 원리이다.


<그림 1> 인체 감지 센서 모듈


  • 인체나 동물의 몸체에서 발산되는 열적외선을 감지한다.

  • 둥근 캡은 적외선을 증폭하는 효과가 있다.

  • 약 6m 이내의 인체의 움직임을 감지할 수 있다.

전원과 신호를 전달하는 세 핀을 가지고 있고 5V 전원을 받아서 인체가 감지되면 신호선은 약 3.3V 전압을 띠게된다. 따라서 신호선을 아두이노의 디지털 핀에 연결하면 쉽게 인체감지 여부를 알 수 있게 된다.


 또한 인체가 감지되었을 때 high 신호를 유지하는 시간을 설정하는 조절기가 내장되어 있어서 이 시간을 0,3초~18초 사이로 조절할 수 있다. 이 조절 기능을 이용하면 인체가 감지되었을 때 점등되는 시스템을 아주 간단하게 구현할 수 있다. 모델에 따라서 열적쇠선 센서의 감도를 조절하는 조절기가 내장된 경우도 있다.


 고휘도LED가 5번 핀에 연결되어 있고 인체 감지 센서 모듈의 신호선이 A0핀에 연결되어 있다고 가정하자. 이 예제에서는 아날로그 핀을 디지털 핀으로 사용하는 예제이다. 전술한 바와 같이 디지털 핀의 숫자가 모자랄 경우에는 아날로그 핀을 디지털 핀으로 사용할 수 있다.


#define HLED 5
void setup() {
   pinMode(A0, INPUT);
   pinMode(HLED, OUTPUT);
}
void loop() {
   digitalWrite(HLED, digitalRead(A0) );
   delay(100);
}


이 예제를 실행해 보면서 인체가 감지되는 거리 범위와 고휘도LED가 켜지는 시간을 조절하여 보자.


아두이노 강좌 전체 목록 (TOP) >>>

C++ 언어 전체 강좌 목록 >>>

c{ard},n{ad011}

Posted by 살레시오

댓글을 달아 주세요

 택스위치(tact switch)는 기계적인 접점을 가지는 스위치로서 누르면 접점이 닫히고 누르지 않은 상태에서는 접점이 열려있는 소자이다.

[그림 1] 택(tact) 스위치

택스위치는 다리가 2개인 것과 4개인 것이 있다. (왜 궂이 다리가 4개가 필요할까 의아하겠지만 스위치 배열 회로를 꾸밀때 유용하다.)


 다음과 같이 아두이노의 디지털핀과 연결하여 접점의 상태를 읽을 수 있다. 일단 2번 핀에 스위치의 한 쪽 다리를 연결하고 GND에 다른 쪽 다리를 연결해야 한다.


[그림 2] 택스위치 결선도

아두이노 우노는 2번 핀이 INT0 이고 3번 핀이 INT1 으로서 외부 인터럽트를 사용할 수 있다.


 이렇게 회로가 구성되었다면 pinMode() 함수를 이용하여 스위치가 연결된 핀을 입력으로 설정해야 하는데 다음과 같이 두 가지 방법이 있다.


pinMode(2, INPUT ) ;     // 2번 핀을 입력으로 설정
pinMode(2, INPUT_PULLUP);// 2번 핀을 입력 + 내부 풀업 저항 연결


첫 번째 방법은 단순히 2번 핀을 입력으로 설정하는 것이다. 두 번째 방법은 2번 핀을 입력으로 설정한 후 내부 풀업(pull-up)저항까지 연결하도록 하는 것이다.


 기계적인 스위치를 핀에 연결할 때는 보통 내부 풀업저항을 연결해서 사용한다. [그림 2]의 회로 동작은 간단하다. 내부에 풀업 저항이 연결되어 있으므로 안 눌렸다면 2번 핀으로 HIGH신호가 나오고, 눌렸다면 LOW 신호가 나온다. 따라서 이 디지털 신호를 읽으면 택스위치가 눌렸는지 아닌지를 판별할 수 있다.


  • 스위치가 눌렸다면 LOW 신호

  • 스위치가 안 눌렸다면 HIGH 신호


이 핀값을 읽을 때는 digitalRead()함수를 사용하면 된다.


digitalRead(2); // 2번 핀의 값을 읽는다


예를 들어서 이 값을 변수에 저장할 수도 있다.


byte bySwitchIn = digitalRead(2);


 첫 예제로 버튼을 누르고 있으면 내장된 LED가 켜지는 간단한 기능을 구현해 보자. 누르고 있는 동안에만 켜져 있고 누르지 않고 있다면 꺼지도록 하는 것이다.


#define SW 2
void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(SW, INPUT_PULLUP); // 내부 풀업 저항을 연결한다.
}
void loop() {
 digitalWrite(LED_BUILTIN, !digitalRead(SW));
}


여기서 digitalRead()함수 앞에 논리 not (!) 연산자가 붙어있다. 이렇게 해서 스위치가 누르면 digitalRead() 은 0값이 나오는데  !digitalRead() 은 1이 되어 LED에 불이 켜지게 된다.


아두이노 강좌 전체 목록 (TOP) >>>

C++ 언어 전체 강좌 목록 >>>

c{ard},n{ad010}


Posted by 살레시오

댓글을 달아 주세요

 여기에서는 터치센서를 이용하여 디지털 입력 값을 받는 실험을 진행해보도록 하겠다. 시중에서 구할 수 있는 터치센서 모듈의 외형은 다음 그림과 같다.


[그림 1]  터치센서 모듈


터치센서의 금속판을 터치할 때 출력 신호가 바뀐다. 즉, 터치시에 HIGH를 아닐 때는 LOW 신호를 내보낸다.


 이 모듈은 선이 세 가닥이 있다. 두 가닥은 전원선이고 나머지 하나는 신호선이다. 이 신호선을 아두이노의 디지털 핀에 연결하면 되는데 예를 들어서 3번 핀에 연결한다면 다음과 같다.

[그림 2] 터치센서 모듈을 우노의 3번 핀에 에 연결한 모양


 이 모듈의 동작은 간단하다. 터치가 안 되어 있다면 신호선으로 LOW 신호가 나오고 터치가 되었다면 HIGH 신호가 나온다. 따라서 이 디지털 신호를 읽으면 터치 패널에 터치가 되었는지 아닌 지를 판별할 수 있다.


 단순하게 터치가 된 상태라면 LED가 켜진 상태를 유지하고 아니라면 LED도 꺼진 상태를 유지하는 매우 간단한 프로그램을 작성해 보도록 하겠다.


#define TS 3 // 터치센서에 연결된 핀 번호
void setup() {
   pinMode(LED_BUILTIN, OUTPUT);
   pinMode(TS, INPUT);
}
void loop() {
   int iTouched = digitalRead(TS);
   digitalWrite(LED_BUILTIN, iTouched);
}


이것을 더 간단하게 줄이면 다음과 같이 iTouched 변수를 생략할 수 있다.


#define TS 3 // 터치센서에 연결된 핀 번호
void setup() {
   pinMode(LED_BUILTIN, OUTPUT);
   pinMode(TS, INPUT);
}
void loop() {
   digitalWrite(LED_BUILTIN, digitalRead(TS));
}


이 프로그램이 실행되면 터치 상태를 계속 읽어들여서 터치되었다면 LED를 켠다.


아두이노 강좌 전체 목록 (TOP) >>>

C++ 언어 전체 강좌 목록 >>>

c{ard},n{ad009}


Posted by 살레시오

댓글을 달아 주세요

 이번에는 부저(buzzer)를 이용한 실험을 해 보겠다. 부저는 소리를 내는 부품으로서 소리 파형을 만들어서 인가하여야 하는 것과 그냥 전압을 걸면 소리가 나는 두 가지 종류가 있으나 실험의 편의상 후자를 택해서 진행한다.


[그림 1] 부저의 외형


부저는 극성이 있으며 조금 긴 다리가 (+)극이고 짧은 쪽은 (-)이다. 극성에 맞게 전압을 걸면 삐~~ 하는 소리가 발생한다. 아두이노 우노의 11번 핀에 부저의 (+)를 꽂으면 (-)핀은 GND에 들어맞게 되어 있다.


[그리 2] 아두이노의 11번 핀에 부저의 (+)를, GND핀에 (-)를 연결했다.


이렇게 연결했다면 부저를 울리는 것은 LED를 동작시키는 것과 똑같다. 단순히 1초 간격으로 삑삑 거리는 프로그램은 다음과 같이 하면 된다.


#define BUZ 11

void setup() {
    pinMode(BUZ, OUTPUT);
}
void loop() {
    digitalWrite(BUZ, HIGH); // 부저가 울리기 시작한다.
    delay(50);
    digitalWrite(BUZ, LOW); // 부저가 멈춘다
    delay(950);
}


이 예제에서는 부저가 울리는 시간을 50ms로 설정했으므로 짧은 시간 동안 ‘삑’하는 소리가 날 것이다. loop()함수 안에 있으므로 이것이 1초 간격으로 반복된다.


 두 번째 예제로 13번 핀에 물려 있는 LED와 조합해서 동작하도록 해보자. LED는 0.5초마다 한 번씩 켜지고 부저는 1초 마다 한 번씩 울리게 해서 마치 타이머처럼 동작하도록 하는 예제이다.


#define LED 13

#define BUZ 11

void setup() {
    pinMode(LED, OUTPUT);
    pinMode(BUZ, OUTPUT);
}
void loop() {
    digitalWrite(LED, HIGH);
    digitalWrite(BUZ, HIGH);
    delay(50);
    digitalWrite(BUZ, LOW);
    delay(200);
    digitalWrite(LED, LOW);
    delay(250);
    digitalWrite(LED, HIGH);
    delay(250);
    digitalWrite(LED, LOW);
    delay(250);
}



Posted by 살레시오

댓글을 달아 주세요

  1. yhbum6@naver.com 2016.09.27 17:56  댓글주소  수정/삭제  댓글쓰기

    좋은 강좌 감사합니다 질문을 해도 둴까요?

    님은 명령어를 전부다 외우시나요 아니면 인터넷으로 검색으로 찾으시나요?

  2. 살레시오 2016.10.06 08:55 신고  댓글주소  수정/삭제  댓글쓰기

    많이 사용하는 것들은 자연스레 외워지고 기억안나면 API를 봅니다. 보통 개발자들이 그럴 것 같습니다.

 아두이노 우노에는 실습용 LED가 실장되어 있는데 이것은 13번 핀과 연결되어 있다. 아래 그림과 같이 아두이노마크 근처에 위치하고 있다.(빨간 원 안)


[그림 1] 아두이노 우노의 내장 LED


이것을 이용하여 깜박이는 예제는 아두이노 IDE에 미리 탑재되어서 제공되는데 다음과 같이 예제파일을 선택하여 읽어들일 수 있다.


[그림 2] Blink 예제 읽어들이기


소스코드는 다음과 같다. (주석문은 삭제하였다.)


int led = 13;
void setup() {
   pinMode(led, OUTPUT);
}
void loop() {
   // turn the LED on (HIGH is the voltage level)
   digitalWrite(led, HIGH);
   delay(1000); // wait for a second

   // turn the LED off by making the voltage LOW

   digitalWrite(led, LOW);
   delay(1000); // wait for a second
}


이 예제의 구조를 살펴보면 먼저 눈에 띄는 것이 있는데 setup() 함수와 loop() 함수이다. 이 두 함수는 아두이노 프로그램의 전체적인 구조를 잡아주는 역할을 한다.


    ⁎ setup() 함수

       • 아두이노 프로그램이 실행될 때 맨 처음에 단 한 번 호출되어 수행된다.

       • 따라서 여기에 각종 장치를 초기화하거나 초기값을 설정하는 코드가 오게 된다.


    ⁎ loop() 함수

        • setup()함수 실행 후 수행되면 계속 반복 수행된다.

        • 아두이노에 연결된 장치들을 구동시키는 코드가 위치한다.


setup()함수 내에서 pinMode()함수를 사용하는데 이 함수는 핀을 입력(INPUT) 혹은 출력(OUTPUT)으로 사용할 지를 설정하는 함수이다. 첫 번째 인자로 핀의 번호가 두 번째 인자로 INPUT, 혹은 OUTPUT이라는 상수를 넘겨주면 된다. pinMode(led, OUTPUT) 은 led(13번)을 출력(OUTPUT)으로 사용하겠다고 설정하는 것이다.


   ⁎ pinMode(pinNumber, INPUT/OUTPUT) 함수

       • pinNumber 핀을 입력(INPUT) 혹은 출력(OUTPUT)으로 사용할 지를 지정한다.

       • pinNumber는 우노의 경우 0,1,2, … 13, A0, A1, ...A6 중 하나이다.


loop()함수에서는 digitalWrite()함수를 사용했는데 이 함수는 핀으로 출력값을 내보내는 작업을 수행한다. 첫 번째 인자로 핀 번호를 받고 두 번째 인자로 HIGH 혹은 LOW 상수를 받는다. digitalWrite(led, HIGH) 명령은 led 핀에 HIGH 신호를 내보내므로 LED가 켜지게 된다. 반대로 digitalWrite(led, LOW) 명령은 led 핀에 LOW 신호를 내보내므로 LED가 꺼지게 된다.


    ⁎ digitalWrite(pinNumber, HIGH/LOW) 함수

         • pinNumber 핀이 출력일 경우에 사용한다.

         • 1값을 내보낼지 (HIGH) 0값을 내보낼지(LOW)를 지정한다.


delay()함수는 입력된 시간만큼 아무 일도 안하고 멈춰있는 동작을 수행한다. delay(1000)은 1000ms 동안 지연시키는 것이다. 입력받는 숫자는 ms 단위이다.


    ⁎ delay(time) 함수

         • time ms 만큼 지연 (아무런 일도 안 하고 멈춰있음)한다.


이 함수의 입력 인자가 밀리세컨드(ms) 단위임을 유의해야 한다.


아두이노 강좌 전체 목록 (TOP) >>>

C++ 언어 전체 강좌 목록 >>>

c{ard},n{ad007}

Posted by 살레시오

댓글을 달아 주세요

 디지털 입출력 포트(digital I/O port, 혹은 그냥 포트)는 디지털 신호를 출력하거나 입력받을 수 있는 통로(물리적으로는 핀)이다. 디지털 신호는 0과 1 두 가지 상태만을 표현하므로 포트를 통해서 0 또는 1신호를 내보내거나 입력받을 수 있다. 아두이노 우노에는 13개의 디지털핀이 있는데 이것들이 포트에 해당된다.


 앞으로의 설명을 위해서 약간의 전기회로 지식이 필요하다. 먼저 전압(voltage)과 전류(current)의 개념을 설명하면 다음과 같다. 마트에서 흔히 살 수 있는 AA나 AAA사이즈 건전지 하나의 '전압'은 1.5V (V는 Volt 볼트, 전압의 단위) 라는 것은 알고 있을 것이다. 이 의미는 음극과 양극의 '전위차'가 1.5V라는 의미이며 일단 '전압은 전류를 흘릴 수 있는 힘' 정도로 이해하면 된다. 이 전위차가 있는 두 부분을 도선으로 연결하면 전자가 도선을 따라서 흐르게 되는데 이 전자의 흐름이 전류이다. 전자는 음극에서 양극으로 흐른다. 전압(또는 전위차)이 높을 수록 전자가 더 많이 흐르고 전류값도 높아진다. 전자의 흐름인 전류의 단위는 암페어(Ampere, A로 표시함)이다. 전류는 '양전하의 흐름'이다.


  • 전류(단위는 암페어, A) : 양전하의 흐름

  • 전압(단위는 볼트, V) : 전류를 흘릴 수 있는 힘



위 그림을 보면 건전지의 +극과 -극을 저항 $R$로 연결하였다. (왼쪽은 건전지와 저항의 모양을 그대로 그렸고 오른쪽은 이것을 기호로 표시한 것이다.) 이 경우 전류가 도선을 따라 흐르게 되는데 전지의 전압을 $v$, 저항을 $R$이라고 하면 전류의 크기는 $\frac{v}{R}$로 계산된다. 이것을 오옴의 법칙이라고 한다. 저항의 단위는 오옴(ohm)이다. '저항은 전류의 흐름을 제한하는 역할을 하는 소자'이다.


  • 저항(단위는 오옴 Ω) : 전류의 흐름을 제한하는 역할을 하는 소자

  • 오옴의 법칙 : $v = i R$


 디지털 시스템의 디지털 신호는 '전압'으로 표현된다. 신호 0(LOW)은 0V (GND, 그라운드라고 읽는다)가 사용되고 1신호는 주로 5V, 3.3V 혹은 1.8V이다. 아두이노의 경우 동작 전압이 대부분 5V이므로 신호 1 (HIGH) 은 전압으로 5V가 되는 것이다.


포트를 이용한 출력 내보내기


 포트를 출력으로 사용하는 경우는 스위치를 생각하면 간단히 이해할 수 있다. 건전지와 연결된 전구사이에 스위치가 있는 간단한 실험장치를 생각해 보면 된다. 스위치를 손가락으로 눌러서 연결(on 되었다고 한다)되면 전구에 전압이 걸려서 켜질 것이고 손가락을 떼면 (off되었다고 한다.) 전구가 꺼지게 된다.



포트는 이와 같이 핀에 연결된 회로에 전압을 인가하거나(1, HIGH 신호) 인가하지 않을 (0, LOW 신호) 수 있는 스위치의 역할을 하는데 아두이노의 경우 이 스위치를 프로그램을 통해서 on시키거나 off시킬 수 있다. 사용자가 원하는 타이밍, 주기, 속도를 가지고 스위치를 켰다 끌 수 있는 것이다. 따라서 손으로 스위치를 조작하는 것과는 비교할 수 없는 정밀도와 속도로 개폐를 제어할 수 있다.


포트를 이용한 입력신호 받기


 입력의 경우에는 출력과 반대로 이 물리적인 핀과 연결된 부분의 전압이 0V(LOW)이냐 혹은 5V이냐(HIGH)를 읽어들이는 기능을 한다. 보통 디지털 입력 실험을 할 때 처음으로 접하는 부품이 택스위치 회로인데 택스위치가 눌려졌는지 혹은 떼어졌는지를 포트의 입력 기능으로 판별할 수 있다.


 위 그림 (a)에서 화살표 표시된 곳의 전압은 5V인데 저항에 전류가 흐르지 않아 저항 양단에 전위차가 발생하지 않기 때문이다. 반면에 (b)를 보면 화살표 된 곳의 전압은 0V인데 GND와 직결되어 있기 때문이다.


 이제 (c) 그림을 보면 스위치를 안 눌렸을 때 (a)와 같고 스위치를 누르면 (b)그림과 같다는 것을 알 수 있다. 따라서 스위치를 눌렀을 때와 안 눌렸을 때의 전압값이 달라지므로 포트에서 이 전압값을 읽어 들여서 스위치의 상태를 검출할 수 있다. 여기에선 사용된 저항 $R$을 '풀업(pull-up) 저항'이라고 한다.


아두이노 강좌 전체 목록 (TOP) >>>

C++ 언어 전체 강좌 목록 >>>

c{ard},n{ad006}

Posted by 살레시오

댓글을 달아 주세요