2016년 1월 29일 금요일

아두이노에서 FreeRTOS 사용하기 - 2


이번에는 태스크 간 통신에 관한 내용이다.

두개의 태스크가 동시에 실행되면서 서로간에 데이터를 주고 받는 예제 코드를 만들어 보겠다. 태스크 간 통신을 위해서 Queue를 사용한다.
이전 예제 코드에서 Light 태스크는 측정한 조도 값을 시리얼 포트를 통해 출력했는데, 이번에는 시리얼 포트로 출력하는 대신 측정 값을 Print라는 이름의 태스크로 보낸다. Print 태스크는 데이터가 들어오기를 기다렸다가 들어온 내용을 시리얼 포트로 출력한다.

Print 태스크는 UART를 초기화 한 후 큐에 데이터가 들어오기를 기다리는 무한루프를 돌면서 데이터가 들어오면 그 내용을 읽어 출력한다. Light 태스크는 이전 예제와 같이 무한 루프를 돌면서 조도 값을 측정하여 그 값을 큐에 집어 넣는다.


태스크 간 통신은 queue를 사용한다. Queue는 xQueueCreate() 함수로 만들어 진다.

xQueueHandle xQueueCreate ( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize );

이 함수는 큐에 필요한 메모리 공간(uxQueueLength * uxItemSize)을 할당하고 그에 대한 queue handle(일종의 포인터)를 리턴 해 준다.

큐에 데이터를 집어 넣기 위해서는 xQueueSendToBack() 함수를 사용하고, 큐에서 데이터를 읽어 오기 위해서는 xQueueReceive() 함수를 사용한다. 

portBASE_TYPE xQueueSendToBack ( xQueueHandle xQueue, const void *pvItemToQueue, portTickType xTicksToWait );
portBASE_TYPE xQueueReceive ( xQueueHandle xQueue, void *pvBuffer, portTickType xTicksToWait );

두 함수 모두 첫번째 파라미터는 queue handle(xQueueCreate에서 리턴된 값)이고, 두번째 파라미터는 집어 넣을 아이템(데이터)에 대한 포인터 또는 읽어 올 아이템을 넣을 버퍼의 포인터이다. 두 함수 모두 데이터를 복사하는 동작을 수행한다. 세번째 파라미터는 동작이 완료될 때 까지 기다리는 시간이다. ‘0’으로 설정하면 함수는 아이템을 큐에 쓰거나 큐에서 읽어 오는 동작이 완료되었는가 여부에 관계 없이 바로 리턴한다. 만일 이 값을 portMAX_DELAY로 지정하면 함수는 동작이 수행될 때 까지 계속 블럭된다. 그 이외 값을 넣으면 동작이 수행되지 못하는 경우 지정된 시간만큼 함수가 블럭된다. 

아래 예제에서는 Light 태스크는 큐가 풀인 경우 기다리지 않지만, Print 태스크는 큐가 비어 있는 경우 데이터가 들어올 때 까지 블럭상태로 기다린다.

#include <FreeRTOS_AVR.h>

#define MS(x) ((unsigned long)(x)/portTICK_PERIOD_MS)

QueueHandle_t xQueue;

static void Print(void* arg);
static void Light(void* arg);


static void Print(void* arg) {
  uint16_t light;
  uint16_t sampleCount = 0;

  while (1) {
    if (xQueueReceive(xQueue, &light, portMAX_DELAY)) {
      sampleCount++;
      Serial.print("Sample ");       Serial.print(sampleCount);
      Serial.print(" Light = "); Serial.println(light);
    }
  }
}

static void Light(void* arg) {  
  uint16_t l = 0;
  TickType_t xLastWakeTime;  

  xLastWakeTime = xTaskGetTickCount();  

  while (1) {
    l = analogRead(0);    
    xQueueSendToBack(xQueue, &l, 0);
    vTaskDelayUntil( &xLastWakeTime, ( 2000 / portTICK_PERIOD_MS ) );  
  }
}

void setup() {
  Serial.begin(115200);

  xQueue = xQueueCreate(5, sizeof(uint16_t));

  xTaskCreate(Print, NULL, 200, NULL, 1, NULL);
  xTaskCreate(Light, NULL, 200, NULL, 2, NULL);

  vTaskStartScheduler();     // start scheduler
  while(1);
}

void loop() {
}


댓글 없음:

댓글 쓰기