👉 Timer 인터럽트?
코드에서 진행중인 작업과 상관없이 특정한 시간 간격으로 작업을 수행 할 수 있다.
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 실행
#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=함수명
(참고링크)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에서 가장 중요하다(논블로킹 처리가 가장 좋다)