본문 바로가기

아두이노우노 R4

포모도로 기법과 아두이노로 실제 만드는 방법

반응형

 

포모도로 기법(Pomodoro Technique)은 시간 관리 방법으로, 1980년대 프란체스코 치릴로(Francesco Cirillo)가 개발했습니다.

 

이 기법은 집중력을 높이고 생산성을 향상시키기 위해 작업을 25분 단위(1 포모도로)로 나누고, 각 구간 후 5분 휴식을 취하는 방식입니다. 4개의 포모도로를 완료하면 15~30분 긴 휴식을 갖습니다.

 

타이머(전통적으로 토마토 모양 타이머 사용)를 활용해 시간을 엄격히 관리하며, 방해 요소를 최소화하는 데 초점을 둡니다. "포모도로"는 이탈리아어로 토마토를 뜻합니다. 

 

 

회로도

 

 

 

사용자 설정 상수

 

 

 

전체 코드

 

// 3차 버전 : https://wokwi.com/projects/424093001412009985

/*
//01 ~ 03 개별 코드를 통합 코드 작성
// 코드리뷰에 따른 개선
매직 넘버 제거
중복 코드 합침
밀리초 계산 명확화
디스플레이 포맷팅 함수 분리
*/

#include <Arduino.h>
#include <TM1637.h>

// -------------- LED 핀번호 및 변수 선언 --------------
const int WORK_LED_PIN = 11;
const int BREAK_LED_PIN = 10;

// -------------- 부저 핀번호 및 변수 선언 --------------
const int BUZZER_PIN = 9;
const int BUZZER_FREQUENCY = 1000;
const int BUZZER_DURATION = 1000;

// -------------- 4자리 7세그먼트 LED 핀번호 및 변수 , 객체 선언 --------------
const int CLK_PIN = 2; // 변수명 수정 (7로 시작하는 변수명은 문법 오류)
const int DIO_PIN = 3; // 변수명 수정
TM1637 segment(CLK_PIN, DIO_PIN);

// -------------- 디버그 모드 설정 --------------
const bool DEBUG_MODE = false;

// -------------- 작업, 휴식간 상태머신 변수 선언 --------------
bool isBreakTime = false;
unsigned long previousTime = 0;

// const int workMinutes = 25;
// const int breakMinutes = 5;

// -------------- 시간 상수 선언( 사용자 시간 설정 부분 ) --------------
const unsigned long ONE_SECOND_MS = 1000;
const unsigned long ONE_MINUTE_MS = 60 * ONE_SECOND_MS;

unsigned long setWorkingTime = 25 * ONE_MINUTE_MS; // 25분으로 설정
unsigned long setBreakTime = 5 * ONE_MINUTE_MS;    // 5분 휴식 시간

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

    pinMode(WORK_LED_PIN, OUTPUT);
    pinMode(BREAK_LED_PIN, OUTPUT);
    pinMode(BUZZER_PIN, OUTPUT);

    segment.init();
    segment.set(BRIGHT_TYPICAL);

    digitalWrite(WORK_LED_PIN, LOW);
    digitalWrite(BREAK_LED_PIN, LOW);
}

void loop()
{
    handleTimer(isBreakTime);
}

void handleTimer(bool isBreak)
{
    unsigned long currentTime = millis();

    // millis() 오버플로우 처리
    if (currentTime < previousTime)
    {
        previousTime = 0;
    }

    unsigned long elapsedTime = currentTime - previousTime;
    unsigned long targetTime = isBreak ? setBreakTime : setWorkingTime;

    digitalWrite(WORK_LED_PIN, !isBreak);
    digitalWrite(BREAK_LED_PIN, isBreak);

    handle7SegmentDisplay();

    if (elapsedTime >= targetTime)
    {
        isBreakTime = !isBreakTime;
        previousTime = currentTime;
        Serial.println(isBreakTime ? "작업 완료! 휴식 시간 시작" : "휴식 완료! 작업 시간 시작");
        tone(BUZZER_PIN, BUZZER_FREQUENCY, BUZZER_DURATION);
    }
}

void handle7SegmentDisplay()
{
    int minute = 0;
    int second = 0;
    unsigned long remainTime = 0;
    unsigned long totalTime;

    if (!isBreakTime)
    {
        totalTime = setWorkingTime;
        remainTime = setWorkingTime - (millis() - previousTime);
    }
    else
    {
        totalTime = setBreakTime;
        remainTime = setBreakTime - (millis() - previousTime);
    }

    // 시간이 음수값으로 가지 않도록
    if (remainTime < 0)
    {
        remainTime = 0;
    }

    minute = remainTime / ONE_SECOND_MS / 60;
    second = (remainTime / ONE_SECOND_MS) % 60;

    if (DEBUG_MODE)
    {
        Serial.print("남은 시간: ");
        Serial.print(minute);
        Serial.print(":");
        Serial.println(second);
    }

    if (totalTime >= ONE_MINUTE_MS)
    {
        // 특별한 경우 처리 제거 - 일반 계산 사용
        // 기존 조건문 삭제: if (!isBreakTime && (setWorkingTime == 25 * ONE_MINUTE_MS))

        // 분:초 형식으로 표시
        displayMinutesAndSeconds(minute, second);
    }
    else
    {
        // 초 단위로만 표시
        displayOnlySeconds(second);
    }
}

/**
 * 분:초 형식으로 7세그먼트에 시간 표시
 * @param minute 표시할 분
 * @param second 표시할 초
 */
void displayMinutesAndSeconds(int minute, int second)
{
    displayTwoDigits(0, minute); // 앞 두 자리에 분 표시
    displayTwoDigits(2, second); // 뒤 두 자리에 초 표시
}

/**
 * 초만 7세그먼트에 표시 (앞 두 자리는 00)
 * @param second 표시할 초
 */
void displayOnlySeconds(int second)
{
    segment.display(0, 0);
    segment.display(1, 0);
    displayTwoDigits(2, second); // 뒤 두 자리에만 초 표시
}

/**
 * 두 자리 숫자를 7세그먼트에 표시 (한 자리면 앞에 0 추가)
 * @param startPos 시작 위치 (0-3)
 * @param value 표시할 값 (0-99)
 */
void displayTwoDigits(int startPos, int value)
{
    if (value < 10)
    {
        segment.display(startPos, 0);
        segment.display(startPos + 1, value);
    }
    else
    {
        segment.display(startPos, value / 10);
        segment.display(startPos + 1, value % 10);
    }
}

 

 

 

 

 

 

참고 자료는 이곳에서 전체를 보실 수 있습니다.

 

 

https://youtube.com/shorts/ybCPCdGkfR8?si=TRL5WjcPE2Vmtzod

 

 

반응형

더욱 좋은 정보를 제공하겠습니다.~ ^^