main 함수(caller)가 LED 함수(calllee)를 호출한다.
main 함수가 LED 함수의 toggle 기능을 사용한다
= main 함수가 LED 함수에게 toggle 기능을 요청한다
= main 함수가 LED 함수에게 toggle 기능을 명령한다
C++, java 등은 class를 통해 캡슐화
C언어의 경우, 파일을 통해 캡슐화
-> 이름을 붙이는 것은 추상화 = 구체적인 것에 의미를 부여, 특징만을 표현 <-> 구체화
=> 이런 방식으로 프로그래밍을 하는 것이 Object Oriented Programing(OOP)라고 하며, 객체 지향 프로그래밍이라고 불리운다.
-> but, C언어는 상속이 어렵기 떄문에 완전한 객체 지향 프로그램은 아니다
OOP 형식으로 시계와 스톱워치의 스왑을 구현해 보자
구조는 다음과 같다
코드의 동작을 구현한 코드의 구조도는 다음과 같다
main.c
#include <avr/io.h>
#include "ap/apMain.h"
int main(void)
{
apMain_init(); // 초기화를 위한 apMain_init을 호출
while (1)
{
apMain_excute();
}
}
apMain.c
#include "apMain.h"
ISR(TIMER0_OVF_vect)
{
FND_ISR_Process();
TCNT0 = 130;
}
ISR(TIMER2_COMP_vect)
{
StopWatch_incMilisec();
TimeClock_incMilisec();
}
void apMain_init() // 초기화 함수를 모아놓은 apMain_init
{
StopWatch_init();
TimeClock_init();
Listener_init();
Prsenter_init();
Model_setStopWatchStateData(STOP);
Model_setTimeClockDispStateData(HOUR_MIN);
Model_setTimeModeStateData(TIMECLOCK);
TIM0_init();
TIM2_init();
sei();
}
void apMain_excute()
{
Listener_checkEvent();
StopWatch_run();
TimeClock_runState();
}
apMain.h
#ifndef APMAIN_H_
#define APMAIN_H_
#include <avr/io.h>
#include <avr/interrupt.h>
#include "../driver/FND/FND.h"
#include "../periph/TIM/TIM.h"
#include "Listener/Listener.h"
#include "Model/Model_StopWatchState.h"
#include "Model/Model_TimeClockDispState.h"
#include "Model/Model_TimeModeState.h"
#include "Presenter/Presenter.h"
#include "Service/Service_StopWatch.h"
#include "Service/Service_TimeClock.h"
void apMain_init();
void apMain_excute();
#endif /* APMAIN_H_ */
Service_StopWatch.c
#include "Service_StopWatch.h"
static uint16_t milisec;
static uint8_t sec;
static uint8_t min;
static uint8_t hour;
void StopWatch_init()
{
milisec = 0;
sec = 0;
min = 0;
hour = 0;
}
void StopWatch_incMilisec()
{
uint8_t stopWatchState = Model_getStopWatchStateData();
if (stopWatchState == RUN) {
milisec = (milisec + 1) % 1000;
}
else {
return;
}
if (milisec) return;
sec = (sec + 1) % 60;
if (sec) return;
min = (min + 1) % 60;
if (min) return;
hour = (hour + 1) % 24;
}
void StopWatch_run()
{
uint8_t timeModeState = Model_getTimeModeStateData();
if (timeModeState != STOPWATCH) return;
uint8_t stopWatchState = Model_getStopWatchStateData();
if (stopWatchState == RESET) {
milisec = 0;
sec = 0;
min = 0;
hour = 0;
}
Presenter_dispStopWatchData(hour, min, sec, milisec);
}
Service_StopWatch.h
#ifndef SERVICE_STOPWATCH_H_
#define SERVICE_STOPWATCH_H_
#include <avr/io.h>
#include "../Model/Model_StopWatchState.h"
#include "../Model/Model_TimeModeState.h"
#include "../Presenter/Presenter.h"
void StopWatch_init();
void StopWatch_incMilisec();
void StopWatch_run();
#endif /* SERVICE_STOPWATCH_H_ */
Service_TimeClock.c
#include "Service_TimeClock.h"
static uint16_t milisec;
static uint8_t sec;
static uint8_t min;
static uint8_t hour;
void TimeClock_init()
{
milisec = 0;
sec = 0;
min = 0;
hour = 12;
}
void TimeClock_incMilisec()
{
milisec = (milisec+1) % 1000;
if (milisec) return;
sec = (sec+1) % 60;
if (sec) return;
min = (min+1) % 60;
if (min) return;
hour = (hour+1) % 24;
}
void TimeClock_runState()
{
uint8_t timeModeState = Model_getTimeModeStateData();
if (timeModeState != TIMECLOCK) return;
Presenter_dispTimeClock(hour, min, sec, milisec);
}
Service_TimeClock.h
#ifndef SERVICETIMECLOCK_H_
#define SERVICETIMECLOCK_H_
#include <avr/io.h>
#include "../Model/Model_TimeModeState.h"
#include "../Presenter/Presenter.h"
void TimeClock_init();
void TimeClock_incMilisec();
void TimeClock_runState();
#endif /* SERVICETIMECLOCK_H_ */
Presenter.c
#include "Presenter.h"
void Prsenter_init()
{
FND_init();
LCD_init();
}
void Presenter_dispStopWatchData(uint8_t hour, uint8_t min, uint8_t sec, uint16_t milisec)
{
static uint8_t prevMilisec = 0xff;
if ((milisec/10) == prevMilisec) return;
prevMilisec = milisec/10;
uint16_t stopWatchData;
char buff[30];
stopWatchData = (min%10 * 1000) + (sec*10) + (milisec/100%10);
FND_setFndData(stopWatchData);
sprintf(buff, "StopWatch");
LCD_writeStringXY(0, 0, buff);
sprintf(buff, "%02d:%02d:%02d.%02d", hour, min, sec, milisec/10);
LCD_writeStringXY(1, 0, buff);
}
void Presenter_dispTimeClock(uint8_t hour, uint8_t min, uint8_t sec, uint16_t milisec)
{
static uint8_t prevMilisec = 0xff;
if ((milisec/10) == prevMilisec) return;
prevMilisec = milisec/10;
uint8_t timeClockDispState = Model_getTimeClockDispStateData();
uint16_t timeClockData;
char buff[30];
switch(timeClockDispState)
{
case HOUR_MIN :
timeClockData = (hour * 100) + min;
FND_setFndData(timeClockData);
break;
case SEC_MIL :
timeClockData = (sec * 100) + (milisec/10);
FND_setFndData(timeClockData);
break;
}
if ((milisec/10) < 50) {
FND_colonOn();
}
else {
FND_colonOff();
}
sprintf(buff, "TimeClock");
LCD_writeStringXY(0, 0, buff);
sprintf(buff, "%02d:%02d:%02d ", hour, min, sec);
LCD_writeStringXY(1, 0, buff);
}
Presenter.h
#ifndef PRESENTER_H_
#define PRESENTER_H_
#include <avr/io.h>
#include <stdio.h>
#include "../../driver/FND/FND.h"
#include "../../driver/LCD/LCD.h"
#include "../Model/Model_TimeClockDispState.h"
void Prsenter_init();
void Presenter_dispStopWatchData(uint8_t hour, uint8_t min, uint8_t sec, uint16_t milisec);
void Presenter_dispTimeClock(uint8_t hour, uint8_t min, uint8_t sec, uint16_t milisec);
#endif /* PRESENTER_H_ */
Listener.c
#include "Listener.h"
button_t btnRunStop, btnReset, btnMode, btnTimeClockDisp;
void Listener_init()
{
Button_init(&btnRunStop, &DDRA, &PINA, 0);
Button_init(&btnReset, &DDRA, &PINA, 1);
Button_init(&btnMode, &DDRA, &PINA, 3);
Button_init(&btnTimeClockDisp, &DDRA, &PINA, 0);
}
void Listener_checkEvent()
{
uint8_t timeModeState = Model_getTimeModeStateData();
switch (timeModeState)
{
case TIMECLOCK:
Listener_timeClockEvent();
if (Button_getState(&btnMode) == ACT_RELEASED) {
Model_setTimeModeStateData(STOPWATCH);
}
break;
case STOPWATCH:
Listener_stopWatchEvent();
if (Button_getState(&btnMode) == ACT_RELEASED) {
Model_setTimeModeStateData(TIMECLOCK);
}
break;
}
}
void Listener_timeClockEvent()
{
uint8_t timeClockDispState = Model_getTimeClockDispStateData();
switch(timeClockDispState)
{
case HOUR_MIN:
if (Button_getState(&btnTimeClockDisp) == ACT_RELEASED) {
timeClockDispState = SEC_MIL;
Model_setTimeClockDispStateData(timeClockDispState);
}
break;
case SEC_MIL:
if (Button_getState(&btnTimeClockDisp) == ACT_RELEASED) {
timeClockDispState = HOUR_MIN;
Model_setTimeClockDispStateData(timeClockDispState);
}
break;
}
}
void Listener_stopWatchEvent()
{
uint8_t stopWatchState;
stopWatchState = Model_getStopWatchStateData();
switch( stopWatchState )
{
case STOP:
if (Button_getState(&btnRunStop) == ACT_PUSHED) {
stopWatchState = RUN;
Model_setStopWatchStateData(stopWatchState);
}
else if (Button_getState(&btnReset) == ACT_PUSHED) {
stopWatchState = RESET;
Model_setStopWatchStateData(stopWatchState);
}
break;
case RUN:
if (Button_getState(&btnRunStop) == ACT_PUSHED) {
stopWatchState = STOP;
Model_setStopWatchStateData(stopWatchState);
}
break;
case RESET:
stopWatchState = STOP;
Model_setStopWatchStateData(stopWatchState);
break;
}
}
Listener.h
#ifndef LISTENER_H_
#define LISTENER_H_
#include <avr/io.h>
#include "../../driver/Button/Button.h"
#include "../Model/Model_StopWatchState.h"
#include "../Model/Model_TimeClockDispState.h"
#include "../Model/Model_TimeModeState.h"
void Listener_init();
void Listener_checkEvent();
void Listener_stopWatchEvent();
#endif /* LISTENER_H_ */
Model_StopWatchState.c
#include "Model_StopWatchState.h"
uint8_t stopWatchStateData;
uint8_t Model_getStopWatchStateData()
{
return stopWatchStateData;
}
void Model_setStopWatchStateData(uint8_t state)
{
stopWatchStateData = state;
}
Model_StopWatchState.h
#ifndef MODEL_STOPWATCHSTATE_H_
#define MODEL_STOPWATCHSTATE_H_
#include <avr/io.h>
enum {STOP, RUN, RESET};
uint8_t Model_getStopWatchStateData();
void Model_setStopWatchStateData(uint8_t state);
#endif /* MODEL_STOPWATCHSTATE_H_ */
Model_TimeClockDispState.c
#include "Model_TimeClockDispState.h"
uint8_t timeClockDispStateData;
uint8_t Model_getTimeClockDispStateData()
{
return timeClockDispStateData;
}
void Model_setTimeClockDispStateData(uint8_t state)
{
timeClockDispStateData = state;
}
Model_TimeClockDispState.h
#ifndef MODEL_TIMECLOCKDISPSTATE_H_
#define MODEL_TIMECLOCKDISPSTATE_H_
#include <avr/io.h>
enum {HOUR_MIN, SEC_MIL};
uint8_t Model_getTimeClockDispStateData();
void Model_setTimeClockDispStateData(uint8_t state);
#endif /* MODEL_TIMECLOCKDISPSTATE_H_ */
Model_TimeModeState.c
#include "Model_TimeModeState.h"
uint8_t timeModeStateData;
uint8_t Model_getTimeModeStateData()
{
return timeModeStateData;
}
void Model_setTimeModeStateData(uint8_t state)
{
timeModeStateData = state;
}
Model_TimeModeState.h
#ifndef MODEL_TIMEMODESTATE_H_
#define MODEL_TIMEMODESTATE_H_
#include <avr/io.h>
enum {TIMECLOCK, STOPWATCH};
uint8_t Model_getTimeModeStateData();
void Model_setTimeModeStateData(uint8_t state);
#endif /* MODEL_TIMEMODESTATE_H_ */
현재의 Timer의 Mode전환은 시간을 기반으로 전환이 되므로 버튼이 제대로 동작하지 않는 문제가 발생
Presenter.c 에서 문제의 원인을 파악할 수 있었음
=> resource를 아끼기 위해 사용한
static uint8_t prevMilisec = 0xff;
if ((milisec/10) == prevMilisec) return;
prevMilisec = milisec/10;
코드에서 문제가 발생 -> 초기값은 prevMilisec값이 0xff이므로 Stop Watch의 값인 0과 달라, 최초 1번을 실행이 되지만, 이후, STOP상태에서 Mode를 바꿀 경우, Stop Watch 값이 0이므로 prevMilisec와 값이 같기 때문에 return으로 함수문을 빠져나가는 문제가 생긴다.