타이머 사용

문주은·2020년 12월 31일
0

메디컬IOT

목록 보기
6/13

👉 Timer 인터럽트?
코드에서 진행중인 작업과 상관없이 특정한 시간 간격으로 작업을 수행 할 수 있다.

1. Timer 사용(Uno)

IDE에서 스케치> 라이브러리 추가하기> 라이브러리 매니저> TimerOne 설치
TimerOne : 인터럽트 서비스 루틴을 주기적으로 실행시키는 것, 사용시 Timer1로 사용

#define LED_PIN LED_BUILTIN
#define LED_OFF 0
#define LED_ON 1
#define LED_BLINK 2

#include <TimerOne.h>
bool onVal = HIGH;
bool offVal = LOW;
int mode; // 0:off, 1:on, 2:blink
int onMil = 3000;
int offMil = 500;

volatile bool blinkOn;
volatile unsigned long nextMil;

void ledISR() {
  if (mode == LED_BLINK) {
    if(blinkOn && millis() > nextMil) {
      digitalWrite(LED_PIN,offVal);
      blinkOn = false;
      nextMil = millis() + offMil;
    }
    else if(!blinkOn && millis() > nextMil) {
      digitalWrite(LED_PIN,onVal);
      blinkOn = true;
      nextMil = millis() + onMil;
    }
  }
}

void setup() {
  Serial.begin(115200);
  Serial.println();
  
  Timer1.initialize(10000); // 10밀리초
  Timer1.attachInterrupt(ledISR);
  pinMode(LED_PIN,OUTPUT);
}

👉initialize(10000) : 실행주기 지정 → 10ms 마다 loop() 반복하여 인터럽트를 발생
👉Timer.attachInterrupt() : 구동시킬 프로그램을 지정. 호출할 콜백 함수 ledISR 실행

2. Timer 사용(ESP8266)

#define LED_PIN LED_BUILTIN
#define LED_OFF 0
#define LED_ON 1
#define LED_BLINK 2

#include<Ticker.h>
Ticker tickerLed;
bool onVal = LOW;
bool offVal = HIGH;
int mode; //0:off, 1:on, 2:blink
int onMil = 3000;
int offMil = 500;

volatile bool blinkOn;
volatile unsigned long nextMil;

void ICACHE_RAM_ATTR ledISR(){
  if(mode == LED_BLINK){
    if(blinkOn && millis() > nextMil){
      digitalWrite(LED_PIN,offVal);
      blinkOn = false;
      nextMil = millis() + offMil;  
    }
    else if(!blinkOn && millis() > nextMil){
      digitalWrite(LED_PIN,onVal);
      blinkOn = true;
      nextMil = millis() + onMil;
    }  
  }
}
void setup() {
  Serial.begin(115200);
  Serial.println();
  tickerLed.attach_ms(10,ledISR);
  pinMode(LED_PIN, OUTPUT);
}

void loop() {
  while(Serial.available()) {
    char c = Serial.read();
    if (c == 'm') { 
      int val = Serial.parseInt();
      switch (val) {
        case 0 : mode = LED_OFF;
                 digitalWrite(LED_PIN,offVal);
                 Serial.println("mode=LED_OFF");
                 break;
        case 1 : mode = LED_ON;
                 digitalWrite(LED_PIN,onVal);
                 Serial.println("mode=LED_ON");
                 break;
        case 2 : mode = LED_BLINK;
                 digitalWrite(LED_PIN,onVal);                 
                 blinkOn = true;nextMil;
                 nextMil = millis() + onMil;
                 Serial.println("mode=LED_BLINK");
                 break;
        default: Serial.println("mode ERROR!!");
                 continue;
      }
    }
  }
}

👉void ICACHE_RAM_ATTR : ISR 함수를 램에 상주하도록 한다.
👉volatile : 매 순간 RAM에서 값을 읽어와 계산을 한다. 즉, volatile을 붙여야 인터럽트로 바뀐 값을 인식
👉tickerLed.attach_ms(10,ledISR) : initialize()와 같은 역할(실행 주기)로 인수1=sec, 인수2=함수명

3.Simple Timer(Uno,ESP계열 모두 사용가능)

(참고링크)https://github.com/jfturcot/SimpleTimer> DownloadZip
IDE에서 스케치> zip 추가하기> SimpleTimer-master.zip

#include <SimpleTimer.h>
SimpleTimer timerCnt;	//객체(오브젝트) timerCnt 생성
unsigned long loopCnt;
void timerCntFunc(){
  Serial.println(loopCnt);
  loopCnt = 0;
}
void setup() {
  Serial.begin(115200);
  Serial.println();
  timerCnt.setInterval(1000,timerCntFunc);
}

void loop() {
  timerCnt.run()
  loopCnt++;
}

👉setInterval(milli-sec,func) : milli-sec 간격마다 func을 실행
👉오브젝트.run() : 메소드가 실행될 때 조건이 충족되면 setup()에서 지정한 함수가 실행

주변 장치를 인식, 데이터 전송 및 가져오기 위해선 블로킹 코드가 없어야한다. 블로킹 되는 주 원인은 dealy or 함수의 내용의 길이이다. 이것을 방지하기 위해 인터럽트 함수를 사용하거나 millis 함수를 사용하여 일정시간 동안 여러개의 장치를 주기적으로 실행하기 위한 것이 IOT에서 가장 중요하다(논블로킹 처리가 가장 좋다)

profile
Data Engineer

0개의 댓글