Watch Dog 보드 ( 아두이노 이용 )

Hardware|2023. 3. 21. 17:05
반응형

최근 Burn-In 장비 프로젝트를 하면서 고객사의 요구사항으로 만들게된 Watch Dog 기능의 보드 입니다. 

제어 소프트웨어와 시리얼 포트를 통해 주기적으로 통신을 유지하다가 원인 불명의 오류등으로 제어 프로그램이 무한루프에 빠지거나 프로그램이 다운되어서 일정시간 동안 통신이 이루어지지 않으면  Watch Dog 보드가 연결된 장비의 전원을 차단하거나 알람을 울려줄 수 있는 용도로 개발 하였습니다. 

 

Watch Dog
Watch Dog 외형

 

* MCU 로는 아두이노 나노를 사용하였고 릴레이 5개 출력을 사용할 수 있도록 되어 있습니다. 

* 릴레이 출력은 NC, NO를 모두 단자대로 연결해 두었기 때문에 용도에 따라 사용할 수 있습니다. 

* Emergency 입력 기능도 사용 가능하도록 설계에는 반영하였는데 펌웨어 상에 코드는 빠져 있습니다. 

* 회로도와 PCB 파일은 KiCAD 를 이용하여 설계 했습니다. 

* 전원은 24V 입니다. 

* 통신은 RS485 통신입니다. 

 

필요하신분들 만들어 사용할 수 있도록 모든 소스를 올려 놓습니다. 

필요하지만 따로 만들기 부담스러우신 분들 댓글로 요청 주시면 소정의 비용으로 제작해 드릴 수도 있습니다. 

Circuit.zip
0.55MB
firmware.zip
0.01MB

반응형

댓글()

아두이노 비트필드(bit field)를 이용한 버튼입력 처리

Software/Arduino|2023. 1. 17. 11:35
반응형

아두이노에 버튼이 여러개 있을 경우 각각의 버튼에 대한 입력을 체크하여 각각의 버튼에 대한 입력 처리만 하게됩니다. 

예를 들어 버튼이 3개가 있다면 3가지 경우의 입력만 처리하게 됩니다.  

 

하지만 적은 수의 버튼으로 좀더 많은 경우의 처리를 하는 방법이 있습니다. 바로 bit field 기능을 이용하면 됩니다. 

비트 필드를 구성하게 되면 두개 이상의 키가 동시에 눌리는 경우도 하나의 입력값으로 인식하여 처리 루틴을 만드는 것이 가능합니다.

만일 버튼이 3개 있다면 최대 7가지의 경우로 조합하여 입력 처리를 할 수 있습니다. 

 

#define U08  unsigned char 

union BUTTON_STATE   // 버튼입력 상태에 대한 비트필드 공용체
{
  U08 State ;
  struct
  {
    int UP_BUTTON    : 1 ;
    int DOWN_BUTTON  : 1 ;
    int LEFT_BUTTON  : 1 ;
    int RIGHT_BUTTON : 1 ;   
    int EMPTY        : 4 ;
  } ;
} ;

const int upButton    = 2;    
const int downButton  = 3;       
const int leftButton  = 4;
const int rightButton = 5;

BUTTON_STATE btn_state ;

void setup()
{
  // initialize the buttons' inputs:
  pinMode(upButton, INPUT);      
  pinMode(downButton, INPUT);      
  pinMode(leftButton, INPUT);      
  pinMode(rightButton, INPUT);     
}

U08 Read_Button()
{
   btn_state.UP_BUTTON    = digitalRead(upButton); 
   btn_state.DOWN_BUTTON  = digitalRead(downButton);
   btn_state.LEFT_BUTTON  = digitalRead(leftButton);
   btn_state.RIGHT_BUTTON = digitalRead(rightButton);

   return btn_state.State ;
}
 
void loop()
{
    U08 Key_State ;

    Key_State = Read_Button() ;

    switch(Key_State)
    {
        case 0x01 : function1() ; break ;  // UP_BUTTON
        case 0x02 : function2() ; break ;  // DOWN_BUTTON
        case 0x04 : function3() ; break ;  // LEFT_BUTTON
        case 0x08 : function4() ; break ;  // RIGHT_BUTTON
        case 0x03 : function5() ; break ;  // UP_BUTTON & DOWN_BUTTON
    }
}
반응형

댓글()

아두이노 시리얼 통신( PC <-> 아두이노 )

Software/Arduino|2023. 1. 17. 10:44
반응형

아두이노와 외부 디바이스 또는 PC 와 RS232 통신을 하기위한 방법을 설명합니다.

제 블로그에서는 가급적 실사용 위주를 중심으로 코드를 올립니다. 큰 틀은 가져가시고 세부적인 부분만 수정하셔도 동작에 지장이 없으실 겁니다. 

하기의 코드는 실제 개발 제품에 사용했던 것으로 PC가 Master 이고 아두이노가 Slave 인 구성에서의 코드입니다. 

아두이노가 Master 가 되는 상황에서 다른 디바이스를 제어할 경우는 코드 구성이 좀 틀립니다. 

또한 하기 코드의 프로토콜에는 별도의 오류 체크를 포함하지 않았지만 통신 오류를 줄이기 위해 Check Sum 이나 CRC 등의 오류 체크를 포함할 수도 있습니다. 

#define     STX             0x02
#define     ETX             0x03
#define     BUFFER_MAX      20              // 수신버퍼 최대 용량 

const int COMM_CTRL        = 3 ;			// MAX485 RX/TX Control

volatile int Comm_Index = 0 ;					// Receive buffer Index Pointer 
volatile boolean stringComplete = false ;   	// 수신 데이타가 다 들어왔는지 확인한다.
volatile boolean serial_start = false ;

char Receive_Buffer[BUFFER_MAX] ;
char Send_Buffer[7] = {STX, 0x30, 0x31, 'I', 'O', 'K', ETX} ;	            // Serial 송신 버퍼

//--------------------------------------------------------------------------------
void setup() 
{
    Serial.begin(9600);         // set serial communication (9600 bps)

    pinMode(COMM_CTRL, OUTPUT) ;  // RS485 통신의 경우 송,수신 전환 단자제어 
    digitalWrite(COMM_CTRL, LOW);    
}
//--------------------------------------------------------------------------------
void loop() 
{
    if(stringComplete == true)      // 통신 패킷이 모두 들어왔다. 
    {
        if(Receive_Buffer[1] == 0x30 && Receive_Buffer[2] == 0x31)    // 자신의 데이타가 맞다. 
        {
            switch(Receive_Buffer[3])   // 수신된 명령어???
            {
                case 'I' : Initialize() ;       // initialize  
                           break ;                            
                case 'P' : function1() ;
                           break ;
                case 'R' : function2() ;
                           break ;
                case 'T' : function3() ;
                           break ;
                case 'S' : function4() ;
                           break ;                           
                default  : Error() ;
                           break ;
            }
            
            Send_Action_Result() ;   // 수신에 대한 응답 메시지 송신
        }
        memset(Receive_Buffer, 0x00, sizeof(Receive_Buffer)) ;  // 수신 버퍼 Clear 
        stringComplete = false ;   // 시리얼 입력에 대한 작업이 종료 되었다. 
    }
}
//--------------------------------------------------------------------------------
void Send_Action_Result(void)
{
  /****************************************
    function : 시리얼 포트로 수신결과에 대한 응답을 보낸다.
  ****************************************/
    int count ;

    digitalWrite(COMM_CTRL, HIGH)  ;    // RS485 통신칩의 송/수신 컨트롤 단자 제어용입니다. 
                                        // 경우에 따라 없을 수도 있습니다. 
    for (count = 0 ; count < 7 ; count++)
    {
        Serial.write(Send_Buffer[count]) ;    // 송신 버퍼의 내용을 시리얼로 전송합니다.
    }

    delay(10) ;		// RS485 통신의 경우 이걸 해 주어야만 컨트롤 단자가 LOW 로 떨어지지 않는다.

    digitalWrite(COMM_CTRL, LOW)  ;
}
//------------------------------------------------------------------------------------
void function1() {} 
void function2() {} 
void function3() {} 
void function4() {} 
//------------------------------------------------------------------------------------
void Error(void)
{
    Send_Buffer[3] = 'N' ;    // NAK 반송  
    Send_Buffer[4] = 'A' ;    
    Send_Buffer[5] = 'K' ;
}
//-------------------------------------------------------------------------------- 
void Initialize(void)
{
    /* 명령어 수행 루틴 작성 */

    Send_Buffer[3] = 'I' ;    // 반송 명령어 
    Send_Buffer[4] = 'O' ;    // OK : 명령을 정상적으로 수행했다. 
    Send_Buffer[5] = 'K' ;
}
//-------------------------------------------------------------------------------- 
void serialEvent()   // 시리얼 포트의 입력 인터럽트 
{
    if (stringComplete == false)
    {
        char inChar = (char)Serial.read() ;

        if (inChar == STX && serial_start == false)      // 시리얼 포트로 데이타가 들어오기 시작 
        {
            serial_start = true ;
            Comm_Index = 0 ;
        }

        Receive_Buffer[Comm_Index] = inChar ;

        if (Receive_Buffer[Comm_Index] == ETX)          // 시리얼 포트로 데이타가 모두 들어왔다.        
        {
            stringComplete = true ;
            serial_start = false ;
        }

        Comm_Index ++ ;

        if (Comm_Index >= BUFFER_MAX) Comm_Index = 0 ;
    }
}
//--------------------------------------------------------------------------------

 

반응형

댓글()