![[AVR] C언어 OOP(Object-Oriented Programming) 구현](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fwh09X%2FbtsFhUFuZ9B%2FPvpUrWdAMsSb60zlOeFvok%2Fimg.png)
[AVR] C언어 OOP(Object-Oriented Programming) 구현AVR/Study2024. 2. 25. 13:48
Table of Contents
| OOP
: Object-Oriented Programming(객체 지향 프로그래밍)
캡슐화 : 각 기능별 코드를 서로 분리, 관련된 코드는 묶음
ex) 출력 파일, 버튼 입력 파일, ... 각 파일별로 캡슐화
추상화 : 하나만 있으면 의미가 없는 구체적인 것들을 모아 의미가 있는 하나의 코드로 만드는 것
ex) DDRA &= ~(1<<7) → 이 단일 코드 하나는 의미가 없지만 이러한 것들이 여러개 모여 Port A : 입력 모드가 됨
- C언어 : Procedural Programming(절차 지향 프로그래밍) → But, OOP스럽게 프로그래밍 하겠다!
- Why?
- 새로운 객체(하드웨어)를 추가했을 때 기능 구현하기 용이 → 각 기능별 코드를 분리해놨기 때문
- 기능에 대한 디버깅 쉬움 → FND 출력이 안된다? FND 출력부에서 디버깅하면 됨
- Why?
OOP Implement Process
1. 객체가 객체를 호출
2. main을 AP 객체로, LED를 driver 객체로 구현
3. AP 객체를 세분화(캡슐화)하여 객체(Button, FND, LCD) Call
- StopWatch라는 부서의 이벤트 처리 담당자, 시간 계산 담당자, 출력 담당자가 있고 각 담당자가 Button, FND, LCD(하드웨어) 등을 Call
Clock Machinde OOP 구현
: 탁상시계 + 스톱워치
1. Listener
: Button의 상태 정보(Push Or Not) Check
- 1.1 사용할 Button driver 초기화
- 1.2 Button Event를 check하고 Mode 변경, Mode state를 Model에 저장
- 1.2.1 AP State(TimeClock, StopWatch 2가지 모드)
- 1.2.2 TimeClock State(Hour:Min, Sec:miliSec 2가지 모드)
- 1.2.3 StopWatch State(Run, Stop, Reset 3가지 모드)
더보기
#include "Listener.h"
/*
[Listener]
: Button 상태 정보 체크
*/
STRCT_button btn_RunStop_stopwatch, btn_Reset_stopwatch, btn_mode, btn_dispMode_timeClock;
/*ㅡㅡㅡ초기화ㅡㅡㅡ*/
void AP_Listener_init()
{
DRIVER_Button_init(&btn_RunStop_stopwatch, &Button_DDR, &Button_PIN, Button_1);
DRIVER_Button_init(&btn_Reset_stopwatch, &Button_DDR, &Button_PIN, Button_2);
DRIVER_Button_init(&btn_dispMode_timeClock, &Button_DDR, &Button_PIN, Button_1);
DRIVER_Button_init(&btn_mode, &Button_DDR, &Button_PIN, Button_4);
}
/*ㅡㅡㅡ버튼 입력 체크 -> Machine 모드 변경 -> Model에 저장ㅡㅡㅡ*/
void AP_Listener_EventCheck()
{
uint8_t state_timeMode = AP_Model_getStateData_MachineMode();
switch(state_timeMode)
{
case TIMECLOCK:
AP_Listener_EventCheck_timeClock();
if (DRIVER_Button_GetState(&btn_mode) == ACT_RELEASED)
{
state_timeMode = STOPWATCH;
AP_Model_setStateData_MachineMode(state_timeMode);
}
break;
case STOPWATCH:
AP_Listener_EventCheck_stopwatch();
if (DRIVER_Button_GetState(&btn_mode) == ACT_RELEASED)
{
state_timeMode = TIMECLOCK;
AP_Model_setStateData_MachineMode(state_timeMode);
}
break;
}
}
/*ㅡㅡㅡ버튼 입력 체크 -> StopWatch 모드 변경 -> Model에 저장ㅡㅡㅡ*/
void AP_Listener_EventCheck_stopwatch()
{
uint8_t State_stopwatch;
State_stopwatch = AP_Model_getStateData_stopwatch();
switch(State_stopwatch)
{
case STOP:
if (DRIVER_Button_GetState(&btn_RunStop_stopwatch) == ACT_PUSHED)
{
State_stopwatch = RUN;
AP_Model_setStateData_stopwatch(State_stopwatch);
}
if (DRIVER_Button_GetState(&btn_Reset_stopwatch) == ACT_PUSHED)
{
State_stopwatch = RESET;
AP_Model_setStateData_stopwatch(State_stopwatch);
}
break;
case RUN:
if (DRIVER_Button_GetState(&btn_RunStop_stopwatch) == ACT_PUSHED)
{
State_stopwatch = STOP;
AP_Model_setStateData_stopwatch(State_stopwatch);
}
break;
case RESET:
State_stopwatch = STOP;
AP_Model_setStateData_stopwatch(State_stopwatch);
break;
}
}
/*ㅡㅡㅡ버튼 입력 체크 -> TimeClock 모드 변경 -> Model에 저장ㅡㅡㅡ*/
void AP_Listener_EventCheck_timeClock()
{
uint8_t State_timeClock;
State_timeClock = AP_Model_getStateData_timeclock_Disp();
switch(State_timeClock)
{
case HOUR_MIN:
if (DRIVER_Button_GetState(&btn_dispMode_timeClock) == ACT_PUSHED)
{
State_timeClock = SEC_miliSEC;
AP_Model_setStateData_timeclock_Disp(State_timeClock);
}
break;
case SEC_miliSEC:
if (DRIVER_Button_GetState(&btn_dispMode_timeClock) == ACT_PUSHED)
{
State_timeClock = HOUR_MIN;
AP_Model_setStateData_timeclock_Disp(State_timeClock);
}
break;
}
}
2. Model
: AP의 어디에서나 접근 가능한 공용 Database
- 2.1 AP State Database(GetterSetter 이용)
- 2.2 ClockMachine State Database(GetterSetter 이용)
- 2.3 StopWatch State Database(GetterSetter 이용)
더보기
#include "Model_State_TimeMode.h"
/*
[Model]
: AP 어디서나 접근 가능한 공용 Database
*/
uint8_t StateData_timeMode;
/*ㅡㅡㅡGetterSetterㅡㅡㅡ*/
uint8_t AP_Model_getStateData_MachineMode()
{
return StateData_timeMode;
}
void AP_Model_setStateData_MachineMode(uint8_t data)
{
StateData_timeMode = data;
}
▲ ClockMachine mode state Model
#include "Model_State_Disp_TimeClock.h"
/*
[Model]
: AP 어디서나 접근 가능한 공용 Database
*/
uint8_t StateData_disp_timeClock;
uint8_t AP_Model_getStateData_timeclock_Disp()
{
return StateData_disp_timeClock;
}
void AP_Model_setStateData_timeclock_Disp(uint8_t data)
{
StateData_disp_timeClock = data;
}
▲ TimeClock mode state Model
#include "Model_State_StopWatch.h"
/*
[Model]
: AP 어디서나 접근 가능한 공용 Database
*/
uint8_t StateData_stopwatch;
/*ㅡㅡㅡGetterSetterㅡㅡㅡ*/
uint8_t AP_Model_getStateData_stopwatch()
{
return StateData_stopwatch;
}
void AP_Model_setStateData_stopwatch(uint8_t data)
{
StateData_stopwatch = data;
}
▲ StopWatch mode state Model
3. Service
: AP 메인 기능 수행
- 3.1 TimeClock Function
- 3.1.1 시간 변수 초기화
- 3.1.2 시간(시, 분, 초) 계산 ← ISR 이용 1ms count
- 3.1.3 계산한 시간을 Presenter로 넘김
- 3.2 StopWatch Function
- 3.2.2 시간 변수 초기화
- 3.2.2 시간(시, 분, 초) 계산 ← ISR 이용 1ms count
- : Model에 저장된 mode State data에 따라 시간 count할지 안할지 결정(RUN 모드일 때만 count)
더보기
#include "Service_TimeClock.h"
/*
[Service]
: AP의 기능을 구현하는 핵심 알고리즘
*/
uint16_t TC_msec;
uint8_t TC_sec; // 60되면 Min+1
uint8_t TC_min; // 60되면 Sec 0, Hour+1
uint8_t TC_hour;
/*ㅡㅡㅡ초기화ㅡㅡㅡ*/
void AP_Service_TimeClock_init()
{
TC_msec = 0;
TC_sec = 10;
TC_min = 17;
TC_hour = 18;
}
/*ㅡㅡㅡTimeClock에 사용할 시간(시,분,초) 계산ㅡㅡㅡ*/
void AP_Service_TimeClock_increase_mSec()
{
TC_msec = (TC_msec+1) % 1000;
if(TC_msec) return;
TC_sec = (TC_sec+1) % 60;
if(TC_sec) return;
TC_min = (TC_min+1) % 60;
if(TC_min) return;
TC_hour = (TC_hour+1) % 24;
}
/*ㅡㅡㅡ계산한 시간(시,분,초)을 다음 단계(Presenter)로 넘김ㅡㅡㅡ*/
void AP_Service_TimeClock_Run()
{
uint8_t State_timeMode;
State_timeMode = AP_Model_getStateData_MachineMode();
if (State_timeMode != TIMECLOCK) return;
AP_Presenter_Disp_TimeClockData(TC_hour, TC_min, TC_sec, TC_msec);
}
▲ TimeClock Service
#include "Service_StopWatch.h"
/*
[Service]
: AP의 기능을 구현하는 핵심 알고리즘
*/
uint16_t SW_msec;
uint8_t SW_sec; // 60되면 Min+1
uint8_t SW_min; // 60되면 Sec 0, Hour+1
uint8_t SW_hour;
/*ㅡㅡㅡ초기화ㅡㅡㅡ*/
void AP_Service_StopWatch_init()
{
SW_msec = 0;
SW_sec = 0;
SW_min = 0;
SW_hour = 0;
}
/*ㅡㅡㅡStopWatch에 사용할 시간(시,분,초) 계산ㅡㅡㅡ
ㅡㅡㅡ + 어떤 모드인지 Model에서 state data 불러옴ㅡㅡㅡ */
void AP_Service_StopWatch_increase_mSec() // CTC Mode interrupt 발생 할 때 마다 실행
{
uint8_t State_stopwatch;
State_stopwatch = AP_Model_getStateData_stopwatch();
if (State_stopwatch == RUN) // RUN 모드 일때만 시간 카운트하고 아니면 함수 빠져나감
{
SW_msec = (SW_msec+1) % 1000; // 0~999
}
else return;
if (SW_msec) return; // 참이면 return -> 거짓(0되면)이면 아래 코드 실행 -> 0 의미 : 1000ms
// 1000ms -> mSec=0 -> 아래 코드 실행(t_Sec+1)
SW_sec = (SW_sec+1) % 60; // 0~59
if (SW_sec) return; // 60초 -> t_Sec=0 -> 아래 코드 실행(t_Min+1)
SW_min = (SW_min+1) % 60;
if (SW_min) return;
SW_hour = (SW_hour+1) % 24; // 0~23
}
/*ㅡㅡㅡ계산한 시간(시,분,초)을 다음 단계(Presenter)로 넘김ㅡㅡㅡ
ㅡㅡㅡ + 어떤 모드인지 Model에서 state data 불러옴ㅡㅡㅡ */
void AP_Service_StopWatch_Run()
{
uint8_t State_timeMode;
State_timeMode = AP_Model_getStateData_MachineMode();
if (State_timeMode != STOPWATCH) return;
uint8_t State_stopwatch;
State_stopwatch = AP_Model_getStateData_stopwatch();
if (State_stopwatch == RESET) // 모드 리셋이면 시간 변수 초기화하고 display
{
SW_msec = 0;
SW_sec = 0;
SW_min = 0;
SW_hour = 0;
}
AP_Presenter_Disp_StopWatchData(SW_hour, SW_min, SW_sec, SW_msec);
}
▲ StopWatch Service
4. Presenter
: Service로부터 받은 시간 data를 LCD,FND에 출력
- 4.1 사용할 LCD, FND driver 초기화
- 4.2 TimeClock data 출력
- 4.3 StopWatch data 출력
- Model에 저장된 mode State data에 따라 [시:분] 출력 or [초:밀리초] FND 출력
- : TimeClock과는 다르게 mode에 따라 시간을 다르게 계산할 필요(Run, 0 초기화, 시간 stop)가 없고 모드별로 시간 data 골라서 출력하면 됨(시간 data : 시, 분, 초, 밀리초 저장)
- Model에 저장된 mode State data에 따라 [시:분] 출력 or [초:밀리초] FND 출력
더보기
#include "Presenter.h"
/*
[Presenter]
: Data를 LCD, FND에 출력
*/
/*ㅡㅡㅡ초기화ㅡㅡㅡ*/
void AP_Presenter_init()
{
DRIVER_LCD_init();
DRIVER_FND_init();
}
/*ㅡㅡㅡService에서 시간 받아서 StopWatch FND, LCD 출력ㅡㅡㅡ*/
void AP_Presenter_Disp_StopWatchData(uint8_t hour, uint8_t min, uint8_t sec, uint16_t msec)
{
if (msec % 7 != 0) return; // 7초에 1번 출력
// FND 출력
uint16_t Data_stopwatch;
Data_stopwatch = (min%10 * 1000) + (sec*10) + (msec/100);
/* t_Min%10 * 1000 : 분 1의 자리로 만들고(%10) FND 1000의 자리에 보내기(*1000)
t_Sec*10 : 초 FND 10의 자리로 보내기 -> 55초 : 0550
mSec/100 % 10 : 550ms : 5 FND 출력 */
DRIVER_FND_SetFndData(Data_stopwatch);
// LCD 출력
char buff[30];
sprintf(buff, "Stop Watch");
DRIVER_LCD_writeString_XY(0, 3, buff);
sprintf(buff, "%02d:%02d:%02d:%02d", hour, min, sec, msec/10);
DRIVER_LCD_writeString_XY(1, 0, buff);
}
/*ㅡㅡㅡService에서 시간 받아서 TimeClock FND, LCD 출력ㅡㅡㅡ
ㅡㅡㅡ + 어떤 모드인지 Model에서 state data 불러옴ㅡㅡㅡ
=> 1. StopWatch : Mode 별로 시간 계산이 달라서(시간 유지, 런, 초기화) Service에서(시간 계산 할 때) Model의 state data 불러옴
2. TimeClock : Mode 별로 어떤걸 출력할지가 달라서(시:분 or 초:밀리초) Presenter에서(출력 할 때) Model의 state data 불러옴
*/
void AP_Presenter_Disp_TimeClockData(uint8_t hour, uint8_t min, uint8_t sec, uint16_t msec)
{
if (msec % 7 != 0) return;
uint16_t Data_timeClock;
uint8_t State_Disp_timeClock = AP_Model_getStateData_timeclock_Disp();
// FND 출력
switch(State_Disp_timeClock)
{
case HOUR_MIN:
if(sec % 4 < 2) DRIVER_FND_colonON(); // 2초에 한번 콜론 ON/OFF
else if(sec % 4 >= 2) DRIVER_FND_colonOFF();
Data_timeClock = (hour*100) + min;
DRIVER_FND_SetFndData(Data_timeClock);
break;
case SEC_miliSEC:
if(sec % 2 < 1) DRIVER_FND_colonON(); // 1초에 한번 콜론 ON/OFF
else if(sec % 2 >= 1) DRIVER_FND_colonOFF();
Data_timeClock = (sec*100) + (msec/10);
DRIVER_FND_SetFndData(Data_timeClock);
break;
}
// LCD 출력
char buff[30];
sprintf(buff, "Time Clock");
DRIVER_LCD_writeString_XY(0, 3, buff);
sprintf(buff, "%02d:%02d:%02d:%02d", hour, min, sec, msec/10);
DRIVER_LCD_writeString_XY(1, 0, buff);
}
5. AP main
: 세분화된 각 AP 기능을 조합하여 하나의 AP로 조립
- 5.1 ISR 설정
- 5.2 각 AP 기능 초기화
- 5.3 ClockMachine 초기 모드 설정
- 5.4 각 AP 기능 동작 호출
더보기
#include "AP_Main.h"
/*
FLOW : Listener(버튼입력) -> Model(모드상태) -> Service(시간계산) -> Presenter(출력) -> main
*/
/*
[AP_Main]
: 세분화 된 각 AP 기능을 조합하여 하나의 AP로 조립(추상화)
*/
ISR(TIMER0_OVF_vect) // Normal mode, 1ms마다 fnd 출력
{
DRIVER_FND_ISR_Process();
TCNT0 = 130;
}
ISR(TIMER2_COMP_vect) // CTC mode, 1ms마다 시간+1
{
AP_Service_StopWatch_increase_mSec();
AP_Service_TimeClock_increase_mSec();
}
void AP_Main_init()
{
AP_Listener_init();
AP_Service_StopWatch_init();
AP_Service_TimeClock_init();
AP_Presenter_init();
TIMER0_init();
TIMER2_init();
sei();
AP_Model_setStateData_MachineMode(TIMECLOCK);
AP_Model_setStateData_stopwatch(STOP);
AP_Model_setStateData_timeclock_Disp(HOUR_MIN);
}
void AP_Main_execute()
{
AP_Listener_EventCheck();
AP_Service_StopWatch_Run();
AP_Service_TimeClock_Run();
}
작동 영상
전체 소스코드
AVR_0223_ClockMachine_OOP.zip
0.14MB
Made by MinSeok KIM
'AVR > Study' 카테고리의 다른 글
[AVR] External Interrupt(외부 인터럽트) & Ultrasonic 거리 측정 (0) | 2024.02.27 |
---|
@민바Minba :: Minba's blog
Let's Be Happy!
도움이 되었으면 좋겠어요 :)