사용자 도구

사이트 도구

English

cublocapp:an41002:index

AN41002 - 타임루프 프로그래밍 기법 소개

타임루프 프로그래밍 기법은 제가 아주 오래전부터 자주 이용해오던 프로그래밍 기법중 하나입니다. 아마 이미 알고 계신분도 있을겁니다. (타임루프 프로그래밍 기법이라는 이름은 제가 생각해낸 이름입니다.)

여러분이 일반적으로 C언어로 프로그래밍을 짜다보면, 반복적으로 처리해야될 일이 있을때 아래 처럼 루프를 구성하게 됩니다.

while (1) {
    proc_rtn1();
    proc_rtn2(); 
    }

while(1) 문으로 이 루프를 감싸게되면, 처리상황에 따라서 루프실행간격이 일정하지 않게됩니다.

이 루프가 항상 일정한 시간간격으로 실행되게 하는것이 "타임 루프" 프로그래밍의 핵심입니다. 과연 이렇게해서 무슨 이득이 있을까요?

바로 시간관리를 할 수 있다는 장점이 생기게 됩니다.


설명을 위해 다음과 같은 프로그램을 작성해보도록 하겠습니다.

포트0에 입력이 들어오면 포트10을 On하고, 포트1에 입력이 들어오면 포트11을 On한다.

아주 단순한 프로그램입니다. 아래처럼 작성해 보았습니다.

#include "moacon500.h"
int mainTm=0;
 
void processA(void);
void processB(void);
 
void cmain(void)
{
 portInit(1,0); // 1번 블록을 출력상태로 만듭니다.
 
 while(1) { // 무한루프
 processA();
 processB();
  }
}
 
void processA(void)
{
 if (portIn(0) == 1)
  portOn(10);
 else
  portOff(10);
}
 
void processB(void)
{
 if (portIn(1) == 1)
  portOn(11);
 else
  portOff(11);
}

이 상황에서 아래 그림처럼, 입력조건이 잠깐 들어와도 출력은 1초동안 On 상태를 유지하도록 프로그램해보겠습니다.

초보자라면 이런식으로 딜레이가 들어간 프로그램을 생각하셨겠죠?

portOn(10); Delay(1000); PortOff(10);

이렇게 한다면 delay하는 1초동안 다른 입력을 못받게 됩니다. 그럼 어떻게 할까요?


본격적으로 설명 드리기에 앞서, 모아콘에서 타이머 이벤트를 사용하는 방법부터 알아보겠습니다.

모아콘에서 아래 프로그램을 실행시키면 0.1초마다 타이머 이벤트가 실행됩니다.

#include "moacon500.h"
int mainTm=0;
void cmain(void)
{
  portInit(1,0); // 1번 블록을 출력상태로 만듭니다.
  startTimerEvent(100); // 타이머 이벤트의 시작
  while(1) { // 무한루프
      }
}
 
// 0.1초마다 이곳으로 옵니다.
void timerEvent(void)
{
  mainTm++;
  printf("mainTm value is %d \r\n",mainTm); 
}

위 프로그램을 실행시키면 모아콘 스튜디오의 디버그창에 0.1초 마다 증가되는 숫자를 보실 수 있습니다.


이제 "타임 루프 프로그래밍 기법"이 들어간 소스를 보여드리겠습니다.

프로세스를 입력과 출력으로 나누고, processInput 에서는 입력이 들어오면 timerA 또는 timerB만 건드립니다. 출력프로세스인 processOutput에선 timerA, timerB가 0이 아닐 경우에만 해당 출력을 On시킵니다.

timerA, timerB는 0.1초마다 감소되는 타이머입니다. 0 이될때까지 감소시킵니다.

#include "moacon500.h"
int mainTm=0;
int timerA=0;
int timerB=0;
 
void cmain(void)
{
 portInit(1,0); // 1번 블록을 출력상태로 만듭니다.
 startTimerEvent(100); // 타이머 이벤트의 시작
 
 while(1) { }  // 무한루프, 여기서 남는시간을 소비  
}
 
void processInput(void)        //   입력 처리
{
 if (portIn(0) == 1) timerA = 10;
 if (portIn(1) == 1) timerB = 10;
}
 
void processOutput(void)       // 출력처리
{
 if (timerA > 0)
  portOn(10);
 else
  portOff(10);
 
 if (timerB > 0)
  portOn(11);
 else
  portOff(11);
}
 
void timer(void)          // 메인타이머 처리
{
 mainTm++;
 if (timerA > 0) timerA--;
 if (timerB > 0) timerB--;
}
 
// 0.1초마다 이곳으로 옵니다.
 
void timerEvent(void)    // 메인루틴
{
 timer();
 processInput();
 processOutput();
}
 

이렇게하면, 입력이 들어온뒤 입력이 꺼지더라도, 1초간은 출력을 On 상태로 유지하게 됩니다.

공장자동화 분야에서 입력조건이 잠깐 살아도, 어느정도 출력을 유지해주어야 하는일은 매우 빈번하게 나오는 상황입니다. 이 골격을 유지하면서, 아무리 입력조건과 출력조건이 복잡해진다고 해도, 정확히 타이밍을 지켜가면서 출력이 나옵니다. 1초간 출력을 유지하는 사이에 들어오는 신호를 놓치는 일도 없습니다.

저는 지금도 상당수의 프로그램을 이 기법으로 짜고 있습니다. 이 기법의 장점은 노이즈에도 강한 프로그램이 된다는 것입니다. 모든 입력조건을 0.1초마다 반복적으로 검사를하고 처리를 하니까, 노이즈가 잠깐들어와서 잘못된 출력결과가 나온다 하더라도, 0.1초 뒤에는 다시 정상적인 출력이 나가게 됩니다.

"타임루프 프로그래밍"을 위해서는 2가지의 중요한 규칙을 지켜주어야 합니다.

1. 함수의 처리시간이 기준시간을 초과해선 안됩니다. 0.1초안에 모든처리가 끝나야합니다.

2. 함수내부에서 프로세싱을 잡아두면 안됩니다.

이게 무슨 말이냐면, 함수안에 delay 같은 시간을 끄는 함수나, while (1)같은 무한루프가 있어서는 안된다는 것입니다.

MOACON 어플리케이션 노트

cublocapp/an41002/index.txt · 마지막으로 수정됨: 2017/10/17 17:10 저자 Comfile Technology