아두이노 우노로 여러개의 루프문을 사용해보기 / ezTask / 편법 / 꿀팁

안녕하세요 메카솔루션입니다.


이번에는 아두이노에서 2개의 루프문을 사용해보기라는 주제로 글을 올렸는데 약간의 편법으로 완벽하지는 않지만 그럴싸하게 구현하는 방법을 알아보고자 합니다.


pick_manager-4... 아두이노가 루프문이 2개? 


네 물론 2개의 루프문을 쓸 수는 없습니다.


 


네 역시.. 안됩니다... 하지만 정말 말 그대로 두 개의 루프를 돌리는 것처럼 사용을 할 수는 있습니다.

그걸 어떻게 하냐고요? 우선 명령어가 실행된다는 개념을 이해해 보도록 하겠습니다.


명령어가 컴파일러(소스 코드를 기계코드로 변경하는 장치)를 통해 기계 코드로 변환 되면 하나의 명령어가 작은 원시 명령어로 나뉘고 이것이 하나하나 차례로 실행이 됩니다. 하지만 이는 우리가 관리할 수 없지만 하나하나 차례로 실행이 된다는 점은 동일합니다. 

이 부분은 어느 정도 감이 잡히시죠? LED를 끄고 키는 것도 위의 함수가 먼저 동작하고 아래의 함수가 이어서 동작이 되듯이 말입니다.

그렇다면 두 개의 서로 다른 역할을 하는 루프를 어떻게 하나로 묶을 수 있을까요? (LED를 깜빡이고 버저의 음악을 제어하는)을 같이 돌릴 수 있다면 어떤 것이 좋을까요? 저는 한가지 편법을 떠 올려 보았습니다.


두 가지 명령을 번갈아서 실행하는 것이지요



위의 그림처럼 말입니다.


pick_manager-28올~ 말은 그럴싸한데.. 이 녀석 워낙 허당이라 믿어도 되나? 


자 그렇다면 명령어의 순서를 섞기 위해서는 어떻게 하면 좋을까요? 저는 함수를 '배열'에 섞고자 합니다.



네 그렇습니다. 함수를 배열로 만들어서 다시 꺼내 쓸 수 있는 것이지요. 그리고 물론 그 함수를 변수 제어를 이용해서 꺼낼 수도 있는 것입니다.  다만 조금씩 제약사항이 있어 이를 조금 유의해야 합니다. 예를 들어 지역변수를 사용하지 못한다는 것 등과 이미 for이나 while로 묶인 것은 다시 중간중간을 끊어둘 수가 없다는 점이겠네요. 그래도 약간의 실마리가 잡혔으니 한번 여러 개의 루프문을 사용하는 것을 시도해 보도록 하겠습니다.


우선 ezTask 라이브러리를 다운로드하고 설치해주세요(millis 기반의 흐름 제어에 도움을 줍니다);


https://github.com/keepworking/ezTask


위 링크에서 바로 다운로드가 가능합니다.


그렇다면 소스 코드를 보면서 자세히 알아보도록 하겠습니다.


#include <ezTask.h>


#define LENGTH(x) sizeof(x)/sizeof(x[0]); //배열속 값들의 갯수를 구합니다.


int a = 0;

void Task1_Runner();

ezTask Task1(0, Task1_Runner);


void (*Task1_func[])(void) {

  []() {Serial.print("TASK1 a : "); 

        Serial.println(a);          },//중간에 짤리면 안되는 부분은 하나의 중괄호로 묶어주세요

  []() {a++;                         },

  []() {Task1.Cycle = 1000;          },//delay(1000); 함수는 이렇게 사용해주세요

  []() {Task1.Cycle = 0;             } //딜레이 후다시 사이클을 0으로 초기화 시켜줍니다.

};


void Task1_Runner(){

  static int idx=0;

  Task1_func[idx]();//배열의 함수를 실행

  idx++;

  idx%=LENGTH(Task1_func);

}


int b = 0;

void Task2_Runner();

ezTask Task2(0, Task2_Runner);


void (*Task2_func[])(void) {

  []() {Serial.print("TASK2 b : ");

        Serial.println(b);          },//중간에 짤리면 안되는 부분은 하나의 중괄호로 묶어주세요

  []() {b++;                         },

  []() {Task2.Cycle = 3000;          },//delay(1000); 함수는 이렇게 사용해주세요

  []() {Task2.Cycle = 0;             } //다시 사이클을 0으로 초기화 시켜줍니다.

};


void Task2_Runner(){

  static int idx=0;

  Task2_func[idx]();

  idx++;

  idx%=LENGTH(Task2_func);

}


void setup() {

  // put your setup code here, to run once:

  Serial.begin(9600);

  while (!Serial) {};

}


void loop() {

  Task1.run();//Task1의 명령을 돌립니다.

  Task2.run();//Task2의 명령을 돌립니다.

}


이렇게 소스 코드를 작성해 주면 Task 속의 함수들이 번갈아 실행됩니다. Runner 함수는 현재 자신에 저장된 변숫값에 맞는 배열의 함수를 실행해주고 ezTask 라이브러리는 배열 속 함수의 딜레이로 인해 다른 배열의 함수 실행에 영향이 가지 않도록 소스 코드를 작성 시켜 보았습니다.



혹시 두 가지 처리를 약간이나마 동시에 처리하고 싶으시다면 위의 방법을 사용해보는 건 어떨까요?


질문이나 의견 덧글로 달아주시면 감사하겠습니다.


감사합니다.


출처 : 메카솔루션  www.mechasolution.com




메카리워즈 Image Map


모바일 버전으로 보기