MoonNote

반응형
     

 

 

 

이벤트(Event)란,

프로그래밍에서 이벤트라고 하면 '지정한 조건에서의 특정 기능이 실행'되도록 하는 것입니다. 프로그래밍 언어가 익숙하신 분들은 어렵지 않겠으나 반대로 '굳이 써야하나..?'라고 생각하시는 분들도 계실 수 있는데요. 간단하게 설명하긴 하였지만 이벤트를 사용하지않고 CASE 구조를 가지고 입력이 a이면 b를, c이면 특정 동작을 수행하라와 같이 코드를 작성할 수도 있습니다. (강의를 다녀보면 오히려 많이 배우면 머리아프다거나,,이정도만 알아도 내가 코드를 간단히 작성해서 돌려보는데에는 문제없다고 하시는 분들도 꽤 있더군요..LabVIEW가 배우기 쉬운만큼 간단한 것까지만하려고 하는걸까요. 개인적으로는 아쉬웠습니다..😂)바로 이전 시간에 '스탑 워치' 실습을 해보았던 자료를 예시로 설명하자면 작성해야하는 알고리즘에 맞춰 Flow chart를 그리고 CASE 구조로 기능 구현을 하였던 실습인데요. 해당 튜토리얼 이미지와 이전 시간의 링크를 첨부하오니 잘 기억이 안나시는 분들은 한번 리마인드 부탁 드리겠습니다.

 

Flow chart : Tutorial 16. 스탑 워치
Block Diagram : CASE 구조를 활용한 스탑 워치 기능 구현

 

 

랩뷰(LabVIEW) Tutorial 16 | 스톱워치 기능 만들기

지금까지 다루었던 반복문, 분기문, 시프트 레지스터, 타이밍 함수 등을 이용하여 스톱 워치와 알람 기능을 만들어보도록 하겠습니다. 혹시라도 해당 포스팅을 처음 보시거나 랩뷰를 처음 사용

moonnote.tistory.com

 

 

 LabVIEW는 와이어링 기반의 코드 방식이라고 수차례 말씀 드린 것처럼 CASE 구조를 사용한 위의 코드처럼 실행할 경우, While Loop는 10ms마다 계속 돌아가면서 ¹Reset 버튼 값 확인, ²Start/Stop 값 확인의 순서로 작성된 코드를 실행하게 됩니다. 폴링(Polling) 방식의 프로그램인 것이죠. 차이를 조금이라도 더 이해하시길 바라는 마음으로 서론이 길었는데요..이벤트 구조를 사용한 프로그래밍 기법은 일종의 인터럽트(Interrupt) 방식이라고 할 수 있습니다. 비동기적인 특성을 가진 기능 구현만 설정하면 되는 것이죠. 스탑 워치 기능으로 본다면 아래의 이미지와 같겠네요. Event 타임도 걸 수 있지만 기본 '무한정 기다림' 동작으로 보았을 때 Flow Chart입니다.

 

Event를 사용한 스탑 워치 Flow Chart

 

 

이벤트 구조(Event Structure)

 랩뷰에서 Event 구조는 함수 팔레트 >> 프로그래밍 >> 구조 >> 이벤트 구조를 선택하시면 생성할 수 있습니다. 

랩뷰(LabVIEW) 이벤트 구조

 

블록다이어그램에 생성하는 방법은 다른 구조들과 마찬가지로 드래그하면 되기에 생략하겠습니다. 기본 이벤트 구조는 아래 이미지와 같은 형태이며 구성은 다음 3가지로 이루어집니다. 이 외에도 다이나믹 이벤트, 필터 이벤트 등 내용이 있으나 기본 이벤트 구조에 대해 이해하고나서 다음 튜토리얼에서 다루어보도록 하겠습니다.

 

① 타임 아웃 터미널 : 시간 단위는 ms로 지정된 시간만큼 등록된 이벤트를 기다립니다. 기본 값은 -1로 '무한정 기다림'이란 의미입니다.

② 이벤트 선택자 라벨 : 등록된 이벤트 케이스들을 보기 위해 라벨로 표시해둔 부분입니다. 케이스 구조와 동일하며 양 옆의 화살표로 다른 이벤트 케이스를 볼 수 있습니다.

③ 서브 다이어그램 : 이벤트 케이스 구조의 경계를 말합니다.

④ 이벤트 데이터 노드 : 이벤트 발생시 LabVIEW가 반환하는 데이터를 식별할 수 있는 노드입니다.

 

 

 

이벤트 구조(Event Structure)를 사용한 스탑 워치

이벤트 구조를 사용해서 한번 스탑워치를 만들어보겠습니다. 실습하면서 중간중간 Event 구조의 특성에 대해 추가 설명을 하겠습니다.

 

1. While 루프 생성 : Main 루프용 While문을 블록다이어그램에서 하나 생성합니다.

 

2. 이벤트 구조 생성 : While문 안에 Event 구조를 하나 생성합니다.

 

(#추가 설명) 정지 버튼 생성 후 VI 실행 : 2번까지 실습을 마치고 While문 조건 터미널에 정지 버튼을 생성해서 VI를 실행해보겠습니다.

Event 구조가 사용된 While문에서의 정지 버튼 생성

(#실행 화면) 실행해보면 정지 버튼이 제대로 작동하지 않습니다. 이벤트 구조를 처음 사용하면 한번쯤은 실수하는 경우인데요. 이벤트 구조의 타임 아웃 설정이 따로 되어있지 않아 '-1 = 무한정 기다림'으로 되어있어 while문 안의 이벤트 구조에서 멈춰있기에 실행 후 정지 버튼의 값을 읽을 수가 없는 것이죠. 실습해보신 분들이 계시다면 'Ctrl+.'키 또는 툴 바에서 강제 종료 버튼을 눌러서 VI를 멈춰주시면 되겠습니다.

정지 버튼 동작 안함 예시

 

3. 2번의 (#추가 설명)과 같은 사유로 정지 버튼 역시 이벤트 케이스로 등록하는 것이 좋습니다. 이벤트 케이스에서 우클릭 >> 이벤트 케이스 추가... 메뉴를 누르고 프런트 패널에 있는 객체(컨트롤 또는 인디케이터) 리스트 중에서 정지 버튼의 "값 변경" 이벤트로 선택 후 [확인] 버튼을 눌러줍니다. 이렇게 되면 정지 버튼에 대한 이벤트가 등록된 것을 확인하실 수 있으실 겁니다.

'이벤트 추가...' 메뉴 선택 후 정지 버튼에 대한 "값 변경" 이벤트 설정 화면

정지 버튼에 대한 이벤트 케이스가 생성되었다면 케이스 내에서 불리언 참(True) 상수를 통해서 조건 터미널과 와이어링 시켜줍니다. 앞으로 이벤트 구조를 사용하게 된다면 반드시 정지 기능에 대해서도 이벤트를 생성해주시면 되겠습니다.

정지 버튼 이벤트에 대한 코드

4.  'Tutorial 16. 스탑 워치 기능 만들기'에서 실습했던 것처럼 UI를 꾸며줍니다. 프런트 패널에 Reset 버튼, Start/Stop 버튼, 타이머 인디케이터를 다음과 같이 생성해주시면 되겠습니다. 타이머 인디케이터는 일반 숫자형 인디케이터 배정도(DBL) 타입인데 프로퍼티 항목에서 디스플레이 포맷만 %<%H:%M:%S%2u>t로 바꿔준 것이니 혹여 궁금증을 가지신 분들은 참고하시면 되겠습니다. 완성된 UI는 아래 이미지와 같습니다.

스탑 워치 User Interface(UI)

 

5. Reset 버튼에 대한 이벤트를 생성합니다. 생성 방법은 앞에서 설명하였으니 생략하오니 헷갈리시는 분들은 3번 내용 참고 부탁드립니다.

Reset 버튼 이벤트 생성

 

6. While 루프에서 Shift Register를 하나 생성하고 Reset 버튼 이벤트 케이스에 경과 시간 체크를 위한 [Tick 카운트]와 디스플레이를 위한 타이머 값을 0로 다시 초기화 시켜주는 코드를 아래와 같이 만듭니다. (Tutorial 16에서 만들었던 기능들)

Reset 버튼 코드 구현

 

7. 마찬가지로 Start/Stop 버튼에 대한 이벤트를 생성합니다. 해당 이벤트 케이스에서는 이벤트 노드의 새 값에서 나오는 불리언 데이터를 기준으로 "참이면? Start 기능", "거짓이면? Stop 기능"이 구현되어야하기에 CASE구조를 하나 더 사용하여 줍니다. 이벤트 노드는 경계에 마우스 커서를 올려다 놓으시면 드래그를 통해 내가 원하는 항목만 보이게끔 할 수 있으니 참고하도록 합니다. 작성된 코드는 아래와 같은 이미지입니다.

Start/Stop 버튼 이벤트 생성 및 CASE 구조 추가

 

8. 시프트 레지스터에 저장된 값을 유지하기 위해서 각각의 이벤트 케이스에서 입력 레지스터와 출력 레지스터쪽을 와이어링시켜 모두 연결시켜줍니다. Start/Stop 이벤트 케이스를 제외한 나머지 이벤트 케이스에서의 와이어링 참고 이미지입니다.

각 이벤트 케이스에서의 와이어링 참고 이미지

 

9. Start/Stop 이벤트 케이스 안의 CASE 구조에서 다음과 같이 코드를 작성해줍니다. (Tutorial 16에서 만들었던 기능들)

CASE 구조 참/거짓 값에 대한 코드

 

10. 이제 코드 작성이 끝났으므로 VI를 실행(Ctrl+R)시켜 봅니다. 제일 처음 설명드렸던 Flow Chart에서 Start 버튼을 누르면? 시간이 카운팅되어야하는데 카운팅 되지 않는 현상이 발생할겁니다. 실행 이미지와 Flow Chart에서 표시한 부분을 참고하시기 쉽게 다시 정리해서 첨부드리겠습니다.

Start/Stop시 타이머 카운팅되지 않는 현상
이벤트 구조 사용시 Flow Chart에서 문제가 되는 부분

 

(#추가 설명) 이런 현상이 나타나는 이유는 바로 타임 아웃 때문인데요. 이벤트가 발생할 때 1번만 While 루프가 실행이 되는데 Start를 누른 시점 이후에는 Stop을 누르기 전까지 계속 타이머가 카운팅 되어야하는데 이벤트 구조는 타임 아웃 설정이 따로 없으므로 무한정 기다리게 되기 때문에 모순이 생기는 것이죠. 위의 이미지를 보면 ¹최초 Start 버튼을 누를 때, 시간 값이 갑자기 증가하는 현상, ²Start 이후 경과 시간이 카운팅되지 않는 현상이 발생하는 것을 확인할 수 있습니다.

 

(#추가 설명) 해결법으로는 ¹Start 이벤트 최초 발생시 시간 값 리셋 후 시간 카운팅, ²이벤트 구조 타임 아웃을 설정하여 주기적으로 타임 아웃 이벤트를 발생시켜서 While문을 실행주면 됩니다.

 

(#추가 설명) 지금처럼 프로그램 조건에 따라서 while루프를 계속 돌려야하는 경우 타임 아웃을 설정하여 루프를 계속 실행시켜주어야합니다. 이벤트 구조에서 '타임 아웃' 케이스가 반드시 필요한 이유라고도 할 수 있는데, 이벤트 구조 생성시 '타임 아웃' 케이스가 기본적으로 생성되는 이유는 이러한 타임 아웃 설정에서 발생할 수 있는 에러에 대한 경우의 수를 줄이고자 반드시 들어가는 것이므로 사용하지 않더라도 케이스를 삭제하지 않도록 주의합니다. LabVIEW 이벤트 구조에서 '타임 아웃' 케이스가 없으면 실행이 안되게 막아둔 이유도 이와 같은 이유에서입니다.

 

11. 해결법으로 소개드렸던 내용을 토대로 코드를 조금 수정해보겠습니다. 먼저 타임 아웃에 10ms 설정을 합니다.

이벤트 케이스 타임 아웃 10ms 설정

 

12. Start/Stop 내에 작성하였던 CASE 구조 코드는 시간을 카운팅 하는 코드입니다. 이를 타임 아웃 이벤트 케이스 안쪽으로 옮겨줍니다. 그리고 Start/Stop 이벤트는 이벤트 노드에서 나오는 "새 값"을 통해 모드만 판별하도록 합니다. 해당 값을 Shift Register로 넘겨주도록 하고 나머지 이벤트 케이스에서는 입출력 레지스터를 연결하여 와이어링에 저장된 값을 유지하도록 하겠습니다. 마지막으로 Start/Stop 이벤트에서는 디스플레이 타이머 값과 경과 시간 Tick 값을 다음과 같이 리셋시켜줍니다.

수정된 Start/Stop 이벤트 케이스
수정된 타임 아웃 이벤트 케이스

 

13. 수정된 코드를 실행해보면 정상 작동하는 것을 확인할 수 있습니다.

이벤트 구조 기반 스탑 워치

 

이벤트 구조에 대한 특성과 주의점을 설명하다보니 내용이 생각보다 길어졌네요. 이벤트 구조를 사용할 때 알아야할 중요한 내용들이니 이해가 되실 때까지 스터디를 해보시는 것을 권장드립니다. 어떤 구조를 사용하느냐는 코드 작성자 마음이긴하지만 상황에 따라서 이벤트 구조가 더 편리하고 케이스 구조가 더 간단할 경우가 있으니 모두 알아두시는 것이 좋습니다.(예 : 버튼 100개에 대한 각각의 기능 구현에서 이를 CASE 구조로만 짜게되면 코드가 커지고 굉장히 보기가 불편할 것입니다.) 이상으로 LabVIEW 이벤트 구조 기본 내용에 대한 포스팅을 마치도록 하겠습니다.

 

 

 

 

 

 

 

 

※ 이 글이 도움이 되었다면 "구독"과 "🤍공감" 버튼을 클릭해주세요. 클릭 한번이 글 쓰는데 큰 힘이 됩니다.

공유하기

facebook twitter kakaoTalk kakaostory naver band