AVR

[전자동 커튼] 제어보드 펌웨어 핵심구문

Posted 2010. 02. 23 Updated 2014. 04. 20 Views 6352 Replies 0
?

단축키

Prev이전 문서

Next다음 문서

ESC닫기

크게 작게 위로 아래로 댓글로 가기 인쇄
  while(1)
 {
  switch( dStatus )
  {
   case STAT_IDLE :   // Standby
   {
    // CSW Reaction
    switch( CSW )
    {
     case CSW_L : 
     {
      ctrlBuzzer(200, 100);
      ctrlLED(LC_G, BL);
      dStatus = STAT_MOVS_L;
     }
     break; 

     case CSW_N : 
     {
     
     }
     break;

     case CSW_R : 
     {
      ctrlBuzzer(200, 100);
      ctrlLED(LC_G, BL);
      dStatus = STAT_MOVS_R;
     }
     break;
    }
   }
   break;

   case STAT_STOP :   // Move Completed
   {
    // CSW Reaction
    switch( CSW )
    {
     case CSW_L : 
     {

     }
     break;

     case CSW_N : 
     {
      ctrlLED(LC_G, ON);
      dStatus = STAT_IDLE;
     }
     break;

     case CSW_R : 
     {

     }
     break;
    }
   }
   break;

   case STAT_MOVS_L :  // Move Start Left
   {
    MDIR(DIR_L);
    clutchFail = ctrlClutch(CLU_E);
    if( clutchFail )
    {
     ctrlBuzzer(500, 100);
     ctrlBuzzer(500, 100);
     ctrlBuzzer(500, 100);

     ctrlLED(LC_Y, BL);
     dStatus = STAT_ERROR;
    }
    else
    {
     dStatus = STAT_MOVI_L;
    }

    // CSW Reaction
    switch( CSW )
    {
     case CSW_L : 
     {
      
     }
     break;

     case CSW_N : 
     {
      dStatus = STAT_MOVE_L;
     }
     break;

     case CSW_R : 
     {
      dStatus = STAT_MOVS_R;
     }
     break;
    }
   }
   break;

   case STAT_MOVS_R :  // Move Start Right
   {
    MDIR(DIR_R);
    clutchFail = ctrlClutch(CLU_E);
    if( clutchFail )
    {
     ctrlBuzzer(500, 100);
     ctrlBuzzer(500, 100);
     ctrlBuzzer(500, 100);

     ctrlLED(LC_Y, BL);
     dStatus = STAT_ERROR;
    }
    else
    {
     dStatus = STAT_MOVI_R;
    }

    // CSW Reaction
    switch( CSW )
    {
     case CSW_L : 
     {
      dStatus = STAT_MOVS_L;
     }
     break;

     case CSW_N : 
     {
      dStatus = STAT_MOVE_R;
     }
     break;

     case CSW_R : 
     {

     }
     break;
    }
   }
   break;

   case STAT_MOVI_L :  // Moving Left
   {
    if( gPosition==GPOS_L )
    {
     dStatus = STAT_MOVE_L;
    }

    // CSW Reaction
    switch( CSW )
    {
     case CSW_L : 
     {

     }
     break;

     case CSW_N : 
     {
      dStatus = STAT_MOVE_L;
     }
     break;

     case CSW_R : 
     {
      dStatus = STAT_MOVS_R;
     }
     break;
    }
   }
   break;

   case STAT_MOVI_R :  // Moving Right
   {
    if( gPosition==GPOS_R )
    {
     dStatus = STAT_MOVE_R;
    }

    // CSW Reaction
    switch( CSW )
    {
     case CSW_L : 
     {
      dStatus = STAT_MOVS_L;
     }
     break;

     case CSW_N : 
     {
      dStatus = STAT_MOVE_R;
     }
     break;

     case CSW_R : 
     {

     }
     break;
    }
   }
   break;

   case STAT_MOVE_L :  // Move End Left
   {
    clutchFail = ctrlClutch(CLU_D);
    MDIR(DIR_S);
    if( clutchFail )
    {
     ctrlBuzzer(500, 100);
     ctrlBuzzer(500, 100);
     ctrlBuzzer(500, 100);

     ctrlLED(LC_Y, BL);
     dStatus = STAT_ERROR;
    }
    else
    {
     ctrlBuzzer(100, 100);
     ctrlBuzzer(100, 100);

     // CSW Reaction
     switch( CSW )
     {
      case CSW_L : 
      {
       dStatus = STAT_STOP;
      }
      break;

      case CSW_N : 
      {
       dStatus = STAT_STOP;
      }
      break;

      case CSW_R : 
      {
       dStatus = STAT_MOVS_R;
      }
      break;
     }   
    }
   }
   break;   case STAT_MOVE_R :  // Move End Right
   {
    clutchFail = ctrlClutch(CLU_D);
    MDIR(DIR_S);
    if( clutchFail )
    {
     ctrlBuzzer(500, 100);
     ctrlBuzzer(500, 100);
     ctrlBuzzer(500, 100);

     ctrlLED(LC_Y, BL);
     dStatus = STAT_ERROR;
    }
    else
    {
     ctrlBuzzer(100, 100);
     ctrlBuzzer(100, 100);

     // CSW Reaction
     switch( CSW )
     {
      case CSW_L : 
      {
       dStatus = STAT_MOVS_L;
      }
      break;

      case CSW_N : 
      {
       dStatus = STAT_STOP;
      }
      break;

      case CSW_R : 
      {
       dStatus = STAT_STOP;
      }
      break;
     }   
    }
   }
   break;

   case STAT_ERROR : // Error
   {
    // Reset
    ((void (*)())0x0000)();
   }
   break;
  }
 }

제어보드에 올라가는 펌웨어중 핵심구문만을 옮긴 것이다.

부팅 과정에서 각종 장치를 테스트(이라고 해봐야 클러치 테스트)를 수행하고, 이 과정에서 아무 이상이 발견되지 않으면 바로 위와의 무한루프로 진입하게 된다.


이 부분은 상태 기계(State Machine)를 switch-case 구문을 활용한 코딩으로 옮겨놓은 것이다.

PDS(Position Detection Switch)CSW(Control SWitch)의 상태에 따라 각 State를 이동하게 된다.

겨우 스위치 입력 하나 받아서 모터 두 개 제어하는데 무슨 이런 복잡한 구문이 필요하냐고 생각할지도 모르지만, 항상 전원이 인가되어 실생활에 활용되는 장치의 경우 오동작은 곧 화재 등의 재해로 이어질 수 있기 때문에 펌웨어를 제작할때 여러 가지 예외 상황를 고려한 세심한 코딩이 필수적이다.

커튼 제어도 단순하게 말하면 DC모터 정, 역회전만 구현할 수 있으면 충분하다고 할 수 있지만, 사용자의 편의나 안전을 위해 실제로는 여러 가지를 고려하여 펌웨어를 작성해야 하기 때문이다.

 

예를 들어, CSW를 오른쪽(열림)으로 돌려놓은 상태에서 커튼이 오른쪽 끝에 도달한 상황을 가정해보자.

커튼이 오른쪽 끝에 도달하면 오른쪽 PDS를 누르게 되고, 프로세서에서는 이를 감지하고 메인모터의 구동을 정지시킬 수 있다.

단순하게는 오른쪽 PDS가 눌리지 않은 경우에만 메인모터를 작동시키면 되지만, 이렇게 단순 FeedBack방식으로 펌웨어를 구성하면 다소 보기 좋지 않은 문제가 발생할 소지가 있다. (이런 단순한 동작만을 수행하려면 예초부터 프로세서 사용하지 않고 게이트들 조합해서 회로를 구성했을 것이다.)

커튼이 완전히 열린 다음에도 CSW를 원위치 하기 전까지는 오른쪽 PDS 누름 → 클러치 뺌, 메인모터 정지 → 고무벨트의 탄성에 의해 약간 후퇴 → 오른쪽 PDS 빠짐 → 클러치 넣음, 메인모터 작동 → 오른쪽 PDS 누름 → ...

이런 작동, 정지, 작동, 정지 과정이 무한반복되게 될 것이다.

커튼이 완전히 열린 다음에도 메인모터가 계속 회전을 하기 때문에 과열 등의 우려고 있고, 사용자 편의의 측면에서 생각해보더라도 커튼이 완전히 열려 오른쪽 PDS를 한 번 누른 다음에는 작동을 멈추는 것이 좋다.

즉, CSW가 똑같이 오른쪽(열림)에 있더라도 커튼을 열기 전인지, 혹은 열고난 후인지에 따라서 작동 여부를 결정해야 하는 것이다.

이러한 동작을 수행하는데 제격인 프로그램 모델이 바로 상태 기계(State Machine)이다.

다음은 실제 코딩에 들어간 각 State의 의미와, 상호 전환 관계에 대한 설명이다.


STAT_IDLE : 대기

부팅 완료 후 바로 진입하는 State이다.

이 State에서는 CSW의 상태만 지속적으로 확인하며, CSW를 좌측으로 돌린 경우 STAT_MOVS_L(좌측 이동 시작) State로 점프하고,

CSW를 우측으로 돌린 경우 STAT_MOVS_R(우측 이동 시작) State로 점프한다.

 

STAT_MOVS_L : 좌측 이동 시작

왼쪽으로 이동 명령이 떨어진 경우 최초로 진입하는 State이다.

이 State에서는 메인모터를 작동시키고, 클러치를 넣는 동작을 수행한다. 클러치 제어구문이 시간 지연(Delay) 방식으로 작성되었기 때문에 클러치 작동중에는 키 입력을 받지 않는다.

CSW가 좌측에 계속 있는 경우 STAT_MOVI_L(좌측 이동 중) State로 점프하고, CSW가 클러치 조작 도중 중립으로 옮겨진 경우(즉, 스위치를 왼쪽으로 옮겼다가 바로 중립으로 되돌린 경우) STAT_MOVE_L(좌측 이동 완료) State로 점프하며,

CSW가 우측으로 옮겨진 경우 STAT_MOVS_R(우측 이동 시작) State로 점프한다.

 

STAT_MOVS_R : 우측 이동 시작

오른쪽으로 이동 명령이 떨어진 경우 최초로 진입하는 State이다.

이 State에서는 메인모터를 작동시키고, 클러치를 넣는 동작을 수행한다. 클러치 제어구문이 시간 지연(Delay) 방식으로 작성되었기 때문에 클러치 작동중에는 키 입력을 받지 않는다.

CSW가 좌측으로 옮겨진 경우 STAT_MOVS_L(좌측 이동 시작) State로 점프한다. 

CSW가 클러치 조작 도중 중립으로 옮겨진 경우(즉, 스위치를 오른쪽으로 옮겼다가 바로 중립으로 되돌린 경우) STAT_MOVE_R(우측 이동 완료) State로 점프하며, CSW가 우측에 계속 있는 경우 STAT_MOVI_R(우측 이동 중) State로 점프하고,

 

STAT_MOVI_L : 좌측 이동 중

이 State에서는 좌측 PDS의 상태를 지속적으로 확인하고, 좌측 PDS가 눌려진 경우 STAT_MOVE_L(좌측 이동 완료) State로 점프한다.

CSW가 중립으로 옮겨진 경우(즉, 중간에 작동 정지 명령을 내린 경우) STAT_MOVE_L(좌측 이동 완료) State로 점프하고, CSW가 우측으로 옮겨진 경우 STAT_MOVS_R(우측 이동 시작) State로 점프한다.

 

STAT_MOVI_R : 우측 이동 중

이 State에서는 우측 PDS의 상태를 지속적으로 확인하고, 우측 PDS가 눌려진 경우 STAT_MOVE_R(우측 이동 완료) State로 점프한다.

CSW가 좌측으로 옮겨진 경우 STAT_MOVS_L(좌측 이동 시작) State로 점프하고, CSW가 중립으로 옮겨진 경우(즉, 중간에 작동 정지 명령을 내린 경우) STAT_MOVE_R(우측 이동 완료) State로 점프한다.

 

STAT_MOVE_L : 좌측 이동 완료

이 State에서는 클러치를 빼고, 메인 모터를 정지시켜 커튼의 이동을 중단시킨다.

CSW가 좌측에 계속 있거나, 중립으로 옮겨진 경우 STAT_STOP(정지 완료) State로 점프하고, CSW가 우측으로 옮겨진 경우 STAT_MOVS_R(우측 이동 시작) State로 점프한다.

 

STAT_MOVE_R : 우측 이동 완료

이 State에서는 클러치를 빼고, 메인 모터를 정지시켜 커튼의 이동을 중단시킨다.

CSW가 좌측으로 옮겨진 경우 STAT_MOVS_L(좌측 이동 시작) State로 점프하고, CSW가 우측에 계속 있거나, 중립으로 옮겨진 경우 STAT_STOP(정지 완료) State로 점프한다.

 

STAT_STOP : 정지 완료

이동 완료 후 CSW가 원위치로 돌아가기 전까지 이 State에 머물게 된다.

지속적으로 CSW의 상태만을 확인하며, CSW가 중립 위치로 옮겨진 경우 STAT_IDLE(대기) State로 점프한다.

 

STAT_ERROR : 오류(클러치 제어 실패) 발생

클러치 제어 구문이 있는 State에서 클러치 제어 실패가 발생한 경우 다음 순간 무조건 이 State로 점프하여 MCU를 소프트웨어 리셋하고 부팅과정부터 다시 시작한다.

부팅 과정에서 클러치 테스트를 실시하기 때문에 다시 한 번 클러치 점검을 하며, 만약 이 과정에서도 클러치 제어 실패가 발생할 경우 클러치 수동제어모드로 전환된다.


TAG •