처음 실행시키면 vIntegerGenerator태스크보다 vStringPrinter태스크의 우선순위가 높기때문에 먼저 실행이 되나 큐가 비어있기때문에 블록 상태가 된다.
따라서 vIntegerGenerator태스크가 실행되지만 vTaskDelayUntil함수를 사용했기 때문에 정해준 값인 200밀리세컨드마다 대기상태에서 벗어나와 작업을 시작할 수 있다.
vIntegerGenerator에서 증가시킨 정수값을 큐에 넣는 것을 5번 반복한 후 인터럽트를 발생시킨다.
인터럽트 서비스 루틴인 vExampleInterruptHandler 함수가 호출된다.
vExampleInterruptHandler에서 정수값을 넣은 큐에서 데이터를 꺼내와서 정수에 대응되는 문자열을 큐에 문자열을 넣는 큐에 넣는다. 정수값을 꺼내오는 큐가 빌때까지 계속 반복한다. 최대 5번 반복하게 된다.
인터럽트 서비스 루틴을 마치고 vIntegerGenerator에서 인터럽트 발생 후 코드를 마저하기전에 큐에서 데이터를 꺼내와 출력하는 vStringPrinter 태스크가 먼저 실행되도록 강제로 컨텍스트 스위치를 시킨다.
vIntegerGenerator보다 우선순위가 더 높기 떄문에 vStringPrinter이 먼저 실행되게 된다.
vStringPrinter 태스크가 실행되는데 큐에 데이터가 있기 때문에 꺼내와서 화면에 출력한다. 5번 문자열을 출력하고 나면 다시 대기상태가 되고 다시 vIntegerGenerator태스크가 실행된다.
- /* FreeRTOS.org includes. */
- #include "FreeRTOS_AVR.h"
- //#include "task.h"
- //#include "queue.h"
- //#include "portasm.h"
- /* Demo includes. */
- #include "basic_io_avr.h"
- //숫자를 증가시켜서 큐에 넣는 함수
- static void vIntegerGenerator( void *pvParameters );
- //큐에서 문자열 데이터를 꺼내와 출력하는 함수
- static void vStringPrinter( void *pvParameters );
- //인터럽트 서비스 루틴
- //중가된 숫자를 이용하여 문자열 데이터를 큐에 넣는다.
- static void vExampleInterruptHandler( void );
- unsigned long ulNext = 0;
- unsigned long ulCount;
- unsigned long ul[ 100 ];
- /*-----------------------------------------------------------*/
- //큐에 접근시 사용될 변수
- QueueHandle_t xIntegerQueue, xStringQueue;
- // pin to generate interrupts
- #if defined(CORE_TEENSY)
- const uint8_t interruptPin = 0;
- #elfif defined(__AVR_ATmega32U4__)
- const uint8_t interruptPin = 3;
- #else // interruptPin
- const uint8_t interruptPin = 2;
- #endif // interruptPin
- void setup( void )
- {
- Serial.begin(9600);
- //10개까지 저장가능한 두 개의 큐를 생성한다. 각각 unsigned long과 char * 타입의 변수를 저장할 수 있음.
- xIntegerQueue = xQueueCreate( 10, sizeof( unsigned long ) );
- xStringQueue = xQueueCreate( 10, sizeof( char * ) );
- if ( xIntegerQueue !=0 && xStringQueue != 0 ) //큐가 성공적으로 생성되었으면
- {
- /* Install the interrupt handler. */
- // _dos_setvect( 0x82, vExampleInterruptHandler );
- //인터럽트핀을 출력으로 설정하고
- pinMode(interruptPin, OUTPUT);
- //인터럽트 서비스 루틴을 지정한다. LOW->HIGH로 핀 전압이 변화시 인터럽트 발생
- attachInterrupt(0, vExampleInterruptHandler, RISING);
- //큐에 값을 넣은 후 인터럽트를 발생시키는 태스크를 우선순위 1로해서 생성한다.
- xTaskCreate( vIntegerGenerator, "IntGen", 200, NULL, 1, NULL );
- //우선순위 2로해서 큐에 있는 데이터를 꺼내어 출력하는 태스크를 생성한다.
- xTaskCreate( vStringPrinter, "String", 200, NULL, 2, NULL );
- //스케줄러를 시작한다.
- vTaskStartScheduler();
- }
- else {}//큐가 성공적으로 생성되지 못함
- //메모리 부족으로 여기에 도달함
- for( ;; );
- // return 0;
- }
- /*-----------------------------------------------------------*/
- static void vIntegerGenerator( void *pvParameters )
- {
- TickType_t xLastExecutionTime;
- unsigned portLONG ulValueToSend = 0;
- int i;
- //vTaskDelayUntil함수에서 사용할 변수를 현재 틱 카운트로 초기화 해준다.
- xLastExecutionTime = xTaskGetTickCount();
- for( ;; )
- {
- //정확히 200밀리세컨드마다 대기상태에서 벗어난다.
- vTaskDelayUntil( &xLastExecutionTime, 200 / portTICK_PERIOD_MS );
- //5번 반복해서 증가된 값을 큐에 넣는다.
- for( i = 0; i < 5; i++ )
- {
- xQueueSendToBack( xIntegerQueue, &ulValueToSend, 0 );
- ulValueToSend++;
- }
- //인터럽트를 발생시킨다.
- vPrintString( "Generator task - About to generate an interrupt.\r\n" );
- digitalWrite(interruptPin, LOW);
- digitalWrite(interruptPin, HIGH);
- //인터업트 처리후 하던일을 마저한다.
- vPrintString( "Generator task - Interrupt generated.\r\n\r\n\r\n" );
- }
- }
- /*-----------------------------------------------------------*/
- static void vStringPrinter( void *pvParameters )
- {
- char *pcString;
- for( ;; )
- {
- //큐에서 문자열을 꺼내온다.
- //portMAX_DELAY를 사용하면 큐에 데이터가 있을때까지 무한히 기다린다.
- xQueueReceive( xStringQueue, &pcString, portMAX_DELAY );
- /* Print out the string received. */
- vPrintString( pcString );
- }
- }
- /*-----------------------------------------------------------*/
- //인터럽트 발생시 호출되어 진다.
- static void vExampleInterruptHandler( void )
- {
- static portBASE_TYPE xHigherPriorityTaskWoken;
- static unsigned long ulReceivedNumber;
- //문자열들을 static const으로 선언해서 interrupt service routine스택에서 할당되지 않도록한다.
- //값이 계속 유지됨.
- static const char *pcStrings[] =
- {
- "String 0\r\n",
- "String 1\r\n",
- "String 2\r\n",
- "String 3\r\n"
- };
- xHigherPriorityTaskWoken = pdFALSE;
- //정수값 넣은 큐가 비어있지 않는 동안 반복한다.
- while( xQueueReceiveFromISR( xIntegerQueue, &ulReceivedNumber, (BaseType_t*)&xHigherPriorityTaskWoken ) != errQUEUE_EMPTY )
- {
- //0~3사이 값으로 변환
- ulReceivedNumber &= 0x03;
- //첫번째 파라메터는 문자열 데이터를 보낼 큐에 대한 핸들
- //두번째 파라메터는 큐에 복사될 데이터에 대한 포인터
- //세번째 파라메터는 큐에 데이터가 들어갔는지 여부를 얻기 위한 변수의 주소를 넣는다.
- xQueueSendToBackFromISR( xStringQueue, &pcStrings[ ulReceivedNumber ], (BaseType_t*)&xHigherPriorityTaskWoken );
- }
- //인터럽트 서비스 루틴을 마치고 vIntegerGenerator에서 인터럽트 발생 후 코드를 마저하기전에 큐에서 데이터를 꺼내와
- //출력하는 vStringPrinter 태스크가 먼저 실행되도록 강제로 컨텍스트 스위치를 시킨다.
- //우선순위가 더 높기떄문에 vStringPrinter이 먼저 실행되게 된다.
- if( xHigherPriorityTaskWoken == pdTRUE ) //데이터가 성공적으로 큐에 보내진 경우
- {
- //강제로 컨텍스트 스위치를 시킨다.
- vPortYield();
- }
- }
- //------------------------------------------------------------------------------
- void loop() {}
'Arduino FreeRTOS' 카테고리의 다른 글
아두이노 freeRTOS 튜토리얼 16 (0) | 2015.01.16 |
---|---|
아두이노 freeRTOS 튜토리얼 15 (0) | 2015.01.16 |
아두이노 freeRTOS 튜토리얼 13 (0) | 2015.01.16 |
아두이노 freeRTOS 튜토리얼 12 (0) | 2015.01.16 |
아두이노 freeRTOS 튜토리얼 11 (0) | 2015.01.16 |
시간날때마다 틈틈이 이것저것 해보며 블로그에 글을 남깁니다.
블로그의 문서는 종종 최신 버전으로 업데이트됩니다.
여유 시간이 날때 진행하는 거라 언제 진행될지는 알 수 없습니다.
영화,책, 생각등을 올리는 블로그도 운영하고 있습니다.
https://freewriting2024.tistory.com
제가 쓴 책도 한번 검토해보세요 ^^
그렇게 천천히 걸으면서도 그렇게 빨리 앞으로 나갈 수 있다는 건.
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!