ATmaga128_ OOP

JS·2023년 2월 27일
0

ATmega128

목록 보기
5/9

main 함수(caller)가 LED 함수(calllee)를 호출한다.

main 함수가 LED 함수의 toggle 기능을 사용한다
= main 함수가 LED 함수에게 toggle 기능을 요청한다
= main 함수가 LED 함수에게 toggle 기능을 명령한다

C++, java 등은 class를 통해 캡슐화
C언어의 경우, 파일을 통해 캡슐화
-> 이름을 붙이는 것은 추상화 = 구체적인 것에 의미를 부여, 특징만을 표현 <-> 구체화

=> 이런 방식으로 프로그래밍을 하는 것이 Object Oriented Programing(OOP)라고 하며, 객체 지향 프로그래밍이라고 불리운다.
-> but, C언어는 상속이 어렵기 떄문에 완전한 객체 지향 프로그램은 아니다

OOP 형식으로 시계와 스톱워치의 스왑을 구현해 보자

구조는 다음과 같다

코드의 동작을 구현한 코드의 구조도는 다음과 같다

  • Model: 다른 객체에서 사용이 가능한 공유 데이터
    ->
  • Listener: 버튼의 driver에 입력된 값과 각 Model의 값을 요청하여 비교후, 값을 각 Model의 set에 전달
  • Presenter: 값을 LCD와 FND에 출력하기 위해 출력장치의 driver를 요청하여 Model 값에 따라 TimeClock또는 StopWatch의 출력값을 출력장치를 통해 출력하는 역할
  • Service: Model의 값을 요청하여 시, 분, 초를 계산하여 Model로 반환하는 역할, TimeClock과 StopWatch로 나뉘어져 있다.
    코드는 다음과 같다

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으로 함수문을 빠져나가는 문제가 생긴다.

0개의 댓글