본문 바로가기
💻 Microprocessor/캡스톤 챌린지

[5주차] (Timer Counter Interrupt) Capston Challenge

by GroovyArea 2022. 10. 9.

문제 2-1

  • LED, Buzzer 사용 
  • 2초 간격으로 교대로 점멸
  • 스위치가 눌릴 경우 Buzzer 동작
  • delay() 를 사용해서 코드 작성

 

문제 이해

  • 문제 그대로 코드를 작성

 

코드

int switch_state;
int int_sw = 2;
int LED1 = 22;
int LED2 = 24;
int BUZZER = 8;
int LED1_state = HIGH;
int LED2_state = LOW;

void setup() {
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(BUZZER, OUTPUT);
}

void loop() {
  flush();

  switch_state = digitalRead(2);
  if (switch_state == HIGH) {
    digitalWrite(BUZZER, HIGH);
  } else {
    digitalWrite(BUZZER, LOW);
  }
}

void flush() {
  if (LED1_state == HIGH) {
    digitalWrite(LED1, LED1_state);
    delay(2000);
  } else if (LED1_state == LOW) {
    digitalWrite(LED1, LED1_state);
    delay(2000);
  }

  if (LED2_state == HIGH) {
    digitalWrite(LED2, LED2_state);
    delay(2000);
  } else if (LED2_state == LOW) {
    digitalWrite(LED2, LED2_state);
    delay(2000);
  }

  LED1_state = !LED1_state;
  LED2_state = !LED2_state;
}

 

 

문제 2-2, 2-3

  • 2-2
    • MsTimer2 인터럽트 이용
  • 2-3
    • TimerOne 인터럽트 이용

 

문제 이해

  • 각 타이머 인터럽트를 이용하자

 

코드

#include <TimerOne.h>
#include <MsTimer2.h>

int switch_state;
int int_sw = 2;
int LED1 = 22;
int LED2 = 24;
int BUZZER = 8;
int LED1_state = HIGH;
int LED2_state = LOW;

void setup() {
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(BUZZER, OUTPUT);
  MsTimer2::set(2000, flush);
  MsTimer2::start();
}

void loop() {
  switch_state = digitalRead(2);
  if (switch_state == HIGH) {
    digitalWrite(BUZZER, HIGH);
  } else {
    digitalWrite(BUZZER, LOW);
  }
}

void flush() {
  if (LED1_state == HIGH) {
    digitalWrite(LED1, LED1_state);
  } else if (LED1_state == LOW) {
    digitalWrite(LED1, LED1_state);
  }

  if (LED2_state == HIGH) {
    digitalWrite(LED2, LED2_state);
  } else if (LED2_state == LOW) {
    digitalWrite(LED2, LED2_state);
  }

  LED1_state = !LED1_state;
  LED2_state = !LED2_state;
}

 

#include <TimerOne.h>

#include <MsTimer2.h>

#include <LiquidCrystal.h>

// LiquidCrystal lcd(42, 43, 44, 45, 46, 47);

int switch_state;
int int_sw = 2;
int LED1 = 22;
int LED2 = 24;
int BUZZER = 8;
int LED1_state = HIGH;
int LED2_state = LOW;

void setup() {
  // put your setup code here, to run once:

  // lcd.begin(16, 2);
  // lcd.print("hello!");
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(BUZZER, OUTPUT);
  Timer1.initialize(2000000); // 2초
  Timer1.attachInterrupt(flush);
}

void loop() {
  // put your main code here, to run repeatedly:
  // lcd.setCursor(0, 1);
  // lcd.print(millis() / 1000);
  switch_state = digitalRead(2);
  if (switch_state == HIGH) {
    digitalWrite(BUZZER, HIGH);
  } else {
    digitalWrite(BUZZER, LOW);
  }
}

void flush() {
  if (LED1_state == HIGH) {
    digitalWrite(LED1, LED1_state);
  } else if (LED1_state == LOW) {
    digitalWrite(LED1, LED1_state);
  }

  if (LED2_state == HIGH) {
    digitalWrite(LED2, LED2_state);
  } else if (LED2_state == LOW) {
    digitalWrite(LED2, LED2_state);
  }

  LED1_state = !LED1_state;
  LED2_state = !LED2_state;
}

 

 

문제 3

  • 디바운스 회로 설계
  • Falling 1번  :
    • 초음파 센서 LCD에 거리 디스플레이
    • 타이머 인터럽트 사용 2행에 디스플레이, 1초마다 LED 점멸
  • Falling 3번 :
    • 실시간 LCD에 거리 디스플레이
    • 20센티미터 미만 LED 계속 HIGH
    • 20센티미터 초과 타이머 인터럽트 사용 1초마다 점멸
  • Rising 5번 : 
    • 초음파 센서 LCD에 거리 디스플레이
    • 20센티미터 미만 타이머 인터럽트 사용 1초마다 LED 점멸
    • 그 이외 LED HIGH, LCD 2행에 경고 문자 출력

 

문제 이해

  • 하나의 핀으로 폴링과 라이징 엣지를 동시에 검출할 수 없다
    • 폴링이 끝나면 인터럽트를 초기화 하는 수 밖에.
  • 타이머 인터럽트는 마지막에 세팅된 함수만 실행한다.
    • stop()을 호출할 것.

 

코드

#include <TimerOne.h>

#include <MsTimer2.h>

#include <LiquidCrystal.h>

LiquidCrystal lcd(42, 43, 44, 45, 46, 47);

int switch_state;
int LED = 22;
int TRIGGER = 12;
int ECHO = 13;
int LED_state = HIGH;
int LCD_state = HIGH;

const byte interruptPin = 2;
volatile int fallingCount = 0;
volatile int risingCount = 0;
volatile long cm;  // 거리를 전역적으로 사용하기

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(LED, OUTPUT);
  pinMode(ECHO, INPUT);
  pinMode(TRIGGER, OUTPUT);

  noInterrupts();
  interrupts();
  attachInterrupt(digitalPinToInterrupt(interruptPin), fallingAct, FALLING);  // Falling 부터 진행

  lcd.begin(16, 2);
}

void loop() {  // 항상 초음파 거리는 lcd에 디스플레이
  // put your main code here, to run repeatedly:
  cm = getDistanceOfCm();
  lcd.setCursor(0, 0);
  lcd.print(cm);
}

// 첫번째 Falling edge 시 동작 함수
void countOneAct() {
  lcd.setCursor(0, 1);
  lcd.print(millis() / 1000);

  flushLed();
}

// lcd 점멸
void countFiveAct() {
  if (LCD_state == HIGH) {
    lcd.setCursor(0, 1);
    lcd.print("Warning!!");
  } else if (LCD_state == LOW) {
    lcd.clear();
  }

  LCD_state = !LCD_state;
}

// led 점멸
void flushLed() {
  digitalWrite(LED, LED_state);
  LED_state = !LED_state;
}

// 초음파센서 작동 및 cm 변환 함수
long getDistanceOfCm() {
  digitalWrite(TRIGGER, LOW);  // 출력 깨끗히!
  delayMicroseconds(2);

  digitalWrite(TRIGGER, HIGH);  // 출력 시작
  delayMicroseconds(10);

  digitalWrite(TRIGGER, LOW);  // 출력 종료

  long duration = pulseIn(ECHO, HIGH);  // 에코가 트리거가 HIGH 였을 시간을 저장
  return (duration / 2) / 29.1;         // cm로 변환하여 반환
}

//Falling edge Interrupt Service Routine
void fallingAct() {

  fallingCount++;  // Falling count 1 증가

  if (fallingCount == 1) {
    MsTimer2::set(1000, countOneAct);
    MsTimer2::start();
  }

  if (fallingCount == 3) {
    lcd.clear();

    if (cm < 20) {
      MsTimer2::stop();
      digitalWrite(LED, HIGH);
    } else {
      MsTimer2::set(1000, flushLed);
      MsTimer2::start();
    }
  }

  if (fallingCount > 3) {
    MsTimer2::stop();
    noInterrupts();  // Rising Edge를 검출해야 하므로 인터럽트 종료
    interrupts();
    attachInterrupt(digitalPinToInterrupt(interruptPin), risingAct, RISING);
  }
}

void risingAct() {
  risingCount++;

  if (risingCount == 5) {
    lcd.clear();

    if (cm < 20) {
      MsTimer2::stop();
      MsTimer2::set(1000, flushLed);
      MsTimer2::start();
    } else {
      MsTimer2::stop();
      digitalWrite(LED, HIGH);
      MsTimer2::set(2000, countFiveAct);
      MsTimer2::start();
    }
  }
}

 

 

반응형