아두이노 코딩 : 히스테리시스로 아날로그 입력 노이즈 처리
Lucy Archive
Lucy / Facilitate4U
2020. 7. 24. 01:56

아두이노 Hysteresis Arduino아두이노 Hysteresis

Arduino Uno Schmitt trigger and hysteresis

  아두이노로 회로를 꾸미고, 프로그래밍을 할 때, 노이즈 문제는 항상 고려되어야 합니다. 외부 조명 밝기에 따라 내부 조명을 켜고 끄는 프로그래밍을 작성하는 경우, 조명 센서의 값은 항상 노이즈를 포함하고 있기 떄문에 조명을 켜고 끄는 임계점에서는 문제가 발생 할 수 있습니다. 이 때 노이즈를 처리할 수 있는 여러가지 기법들이 있습니다. 본 포스트에서는

아날로그 입력 전압으로 On, Off 제어를 하는 경우 사용 할 수 있는 히스테리시스 적용 방법

에 대해 작성하였습니다.

슈미트트리거와 히스테리시스

우리가 사용하는 모든 신호에는 노이즈가 함께 존재합니다. 아날로그 전압을 1과 0으로 판별하기 위해, 아래와 같이 기준 전압으로 단순하게 HIGH, LOW 를 판단하게 되면 노이즈로 인해 임계점에서 HIGH, LOW 판별이 어려워집니다. 신호는 LOW이기만 노이즈로 인해 HIGH 로 인식 할 수도 있습니다.

HIGH, LOW 단순하게 판단HIGH, LOW 단순하게 판단하는 경우 임계점 부근에서 노이즈로 인한 영향으로 HIGH, LOW 판단이 어려움

위와 같은 현상을 방지하기 위해, 대부분의 디지털 IC의 입력부에는 슈미트트리거 회로가 존재합니다. 슈미트트리거는 HIGH 판정전압, LOW판정 전압이 존재합니다. 단순하게 HIGH 판정 전압, LOW 전압이 존재하는 것은 아니고, 신호가 증가할 때, 감소할 때 적용되는 HIGH 판정 전압 및 LOW 판정 전압이 다르게 적용 됩니다.

슈미트트리거 회로가 적용슈미트트리거 회로가 적용된 회로의 HIGH, LOW 판별

신호가 높아질 때 LOW -> HIGH 로 변경 되는 전압과 신호가 낮아질 때 HIGH -> LOW 로 변경되는 전압이 다른 것을 히스테리시스가 있다고 표현을 할 수 있습니다. 이런 현상으로 동작하는 슈미트트리거 회로는 위 그림과 같이 히스테리시스 기호를 포함하고 있습니다. 


히스테리시스 예제

가변저항을 이용하여, 아날로그 핀의 전압이 2.5V 이상이 되면 HIGH로 판단하고 LED를 ON, 2.5V 이하로 되면 LOW로 인식하고 OFF하는 예제입니다.

예제1 : 2.5V 기준으로 단순하게 HIGH, LOW 를 판단하는 경우의 문제점 확인

예제2 : 2.5V 기준에서 히스테리시스를 적용하여 HIGH 판별 전압을 2.7V, LOW 판별 전압을 2.3V 로 설정


Hardware

준비물

본 예제의 구성품은 아래와 같습니다.

  • Arduino Uno x 1EA
  • DIP Type LED x 1EA
  • DIP Type Resistor x 1 EA (200Ω ~ 1kΩ 권장)
  • Potentionmeter x 1 EA ( 1kΩ 이상 권장 )
  • Bread Board x 1 EA
  • Jumper Wires

회로도 : LED, 저항, 가변저항 연결 방법

회로도 및 연결 사진회로도 및 연결 사진

본 예제의 회로 구성은 아래와 같습니다.

  • A0 : 가변저항 아날로그 입력
  • D11 : digitalPin 출력 포트로 사용
    • HIGH 출력 일 때 LED 켜짐
    • LOW 출력 일 때 LED 꺼짐

예제1 : 히스테리시스 미적용

아날로그 입력 전압 2.5V (디지털 데이터 511) 기준으로 HIGH, LOW를 판별하여 LED를 ON, OFF 하는 예제입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#define ledPin 11 // LED 핀 번호
#define sensor A5 // 가변저항의 전압 입력
 
void setup(){
    pinMode(ledPin, OUTPUT); // LED 핀은 출력 포트로 설정
    pinMode(sensor, INPUT); // 가번저항 연결 핀은 입력 포트로 설정
}
 
void loop(){
    int value = analogRead(sensor);
 
    // 아날로그 전압이 511 (2.5V) 이상,이하 일 경우 각각 LED ON, LED OFF
    if(value >= 511){
        digitalWrite(ledPin, HIGH);
    }
    else
    {
        digitalWrite(ledPin, LOW);
    }
    
}
cs

예제2 : 히스테리시스 적용

예제1의 프로그램에서 히스테리시스를 적용한 코드입니다. 아날로그 입력 전압을 아래의 상태로 구분하여 프로그래밍을 하였습니다.

  • ONINIT : 프로그램 시작시 초기 상태
  • ONHIGH : 아날로그 전압이 HIGH 로 진입 한 경우
  • ONLOW : 아날로그 전압이 LOW 로 진입 한 경우
  • VHIGH : HIGH 판정전압
  • VLOW : LOW 판정전압
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#define ONINIT 0 // 프로그램 초기 상태
#define ONHIGH 1 // 입력 전압이 HIGH 로 진입상 상태
#define ONLOW 2 // 입력 전압이 LOW 로 진입한 상태 
 
#define VHIGH 551 // HIGH 판별 전압을 위해 Margin 40
#define VCENTER 511 // 10 bit 아날로그 입력의 2.5V 값
#define VLOW 471 // LOW 판별 전압을 위해 Margin 40
 
#define ledPin 11 // LED 핀 번호
#define sensor A5 // 가변저항의 전압 입력
 
int iStatus = ONINIT; // 아날로그 입력 전압의 상태를 저장하는 변수
 
void setup(){
    pinMode(ledPin, OUTPUT);
    pinMode(sensor, INPUT);
}
 
void loop(){
    int value = analogRead(sensor);
 
    switch (iStatus) {
        case ONHIGH:
            digitalWrite(ledPin, HIGH);
            if(value < VLOW){
                iStatus = ONLOW;
                digitalWrite(ledPin, LOW);
            }
            break;
        case ONLOW:
            digitalWrite(ledPin, LOW);
            if(value > VHIGH){
                iStatus = ONHIGH;
                digitalWrite(ledPin, HIGH);
            }
            break;
        case ONINIT: // 프로그램 초기 실행시
            if(value > VCENTER)
                iStatus = ONHIGH;
            else
                iStatus = ONLOW;
            break;
    }
}
cs

실행 결과

아래 영상에서 앞 부분은 히스테리시스 미적용으로 임계점 근처에서 깜빡이는 현상을 보여줍니다. 영상의 뒷 부분은 히스테리시스 코드를 적용하여 임계점에서 깜빡임 없이 의도한 대로 코드가 잘 동작하는 것을 보여줍니다.



부록 : 예제2 디버깅 코드 추가

아래 코드는 예제2 에서 디버그 출력을 하기 위한 코드를 추가하였습니다. MsTimer2.h 라이브러리를 사용하여, 1초마다 현재 아날로그 입력 전압 값과 LED의 상태를 출력하도록 코드를 추가하였습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <MsTimer2.h>
 
#define ONINIT 0 // 프로그램 초기 상태
#define ONHIGH 1 // 입력 전압이 HIGH 로 진입상 상태
#define ONLOW 2 // 입력 전압이 LOW 로 진입한 상태 
 
#define VHIGH 551 // HIGH 판별 전압을 위해 Margin 40
#define VCENTER 511 // 10 bit 아날로그 입력의 2.5V 값
#define VLOW 471 // LOW 판별 전압을 위해 Margin 40
 
#define ledPin 11 // LED 핀 번호
#define sensor A5 // 가변저항의 전압 입력
 
int iStatus = ONINIT; // 아날로그 입력 전압의 상태를 저장하는 변수
int value; // 아날로그 입력 전압값 저장
 
void setup(){
    pinMode(ledPin, OUTPUT);
    pinMode(sensor, INPUT);
    MsTimer2::set(1000, debugPrint); // 1초마다 ISR 호출
    MsTimer2::start();
    Serial.begin(9600);
}
 
void loop(){
    value = analogRead(sensor);
 
    switch (iStatus) {
        case ONHIGH:
            digitalWrite(ledPin, HIGH);
            if(value < VLOW){
                iStatus = ONLOW;
                digitalWrite(ledPin, LOW);
            }
            break;
        case ONLOW:
            digitalWrite(ledPin, LOW);
            if(value > VHIGH){
                iStatus = ONHIGH;
                digitalWrite(ledPin, HIGH);
            }
            break;
        case ONINIT:
            if(value > VCENTER)
                iStatus = ONHIGH;
            else
                iStatus = ONLOW;
            break;
    }
}
 
void debugPrint(){ // 1초 간격으로 입력 전압값과 LED 상태를 출력
    Serial.print("The value : ");
    Serial.println(value);
    Serial.print("LED status : ");
    if(iStatus == ONHIGH){
        Serial.println("ONHIGH");
    }
    else
    {
        Serial.println("ONLOW");
    }
}
cs

마무리

본 포스트에서 아날로그 입력 전압으로 HIGH, LOW 등을 판별 하는 경우 적용 할 수 있는 히스테리시스 예시 코드에 대해 작성하였습니다. 본 포스트에서 사용한 아날로그 입력 및 MsTimer2 라이브러리 사용법에 대한 내용이 필요하시면 아래의 관련 포스트를 참고해주세요. 

끝까지 읽어 주셔서 감사합니다.^^

관련포스트

👉 아두이노 아날로그 입출력 관련글 목록 보기

👉 아두이노 타이머 관련글 목록 보기

👉 아두이노 관련글 전체 목록 보기