{"id":1141,"date":"2020-07-15T02:20:00","date_gmt":"2020-07-15T02:20:00","guid":{"rendered":"http:\/\/visiorob.com.br\/?p=1141"},"modified":"2022-09-04T14:13:30","modified_gmt":"2022-09-04T14:13:30","slug":"primeiros-passos-com-o-freertos-no-arduino","status":"publish","type":"post","link":"https:\/\/visiorob.com.br\/index.php\/2020\/07\/15\/primeiros-passos-com-o-freertos-no-arduino\/","title":{"rendered":"Primeiros passos com o FreeRTOS no Arduino"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Conceitos iniciais<\/h2>\n\n\n\n<p>O FreeRTOS \u00e9 atualmente um dos sistemas operacionais de tempo real mais utilizados no universo de sistemas embarcados, isso se deve tanto ao fato de seu c\u00f3digo ser aberto (open source) como tamb\u00e9m pela possibilidade de ser utilizado em in\u00fameros microcontroladores diferentes. Atualmente existem vers\u00f5es do sistema operacional para mais de 35 fam\u00edlias de processadores, incluindo a linha Atmel AVR, que conta com o microcontrolador ATMega328, presente no Arduino UNO, que ser\u00e1 utilizado para execu\u00e7\u00e3o de nossos testes neste artigo.<\/p>\n\n\n\n<p>Por ser um sistema operacional preemptivo, ou seja, capaz de interromper temporariamente uma tarefa sem a coopera\u00e7\u00e3o da mesma a fim de retoma-la posteriormente, o FreeRTOS permite criar um ambiente multitasking. Sendo assim, cada tarefa tem o direito de fazer uso do processador por um determinado per\u00edodo de tempo, denominado quantum, quando este tempo se esgota a tarefa seguinte toma o controle do processador. Ao se fechar o ciclo e retornar para a primeira tarefa, ela \u00e9 executada exatamente do ponto onde parou anteriormente.<\/p>\n\n\n\n<p>A ordem em que as tarefas s\u00e3o executadas est\u00e1 atrelada \u00e0 prioridade dada a ela no programa. No FreeRTOS a prioridade da tarefa e definida por seu valor num\u00e9rico, tendo a de n\u00famero 0 a menor prioridade. Geralmente definine-se um n\u00edvel prioridade diferente para cada tarefa, por\u00e9m, pode ser necess\u00e1rio um cuidado especial para que certas tarefas n\u00e3o fiquem eternamente esperando sua vez de utilizar o processador, o que pode acontecer com tarefas que dependam de inputs.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Programando com FreeRTOS<\/h2>\n\n\n\n<p>Inicialmente, na IDE do Arduino v\u00e1 no menu Ferramentas &gt; Gerenciar bibliotecas busque e instale a vers\u00e3o mais recente da biblioteca FreeRTOS by Richard Barry.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Cria\u00e7\u00e3o de tarefas (Tasks)<\/h3>\n\n\n\n<p>Deve-se declarar de maneira global as tarefas presentes no projeto, elas devem seguir o seguinte formato:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ Declara\u00e7\u00e3o das tarefas\n\nvoid Tarefa1(void *pvParameters);\nvoid Tarefa2(void *pvParameters);\n.\n.\n.\nvoid TarefaN(void *pvParameters);<\/pre>\n\n\n\n<p>\u00c9 importante ressaltar que esta fun\u00e7\u00e3o deve ter,&nbsp;obrigatoriamente, tipo de retorno como void e par\u00e2metro \u00fanico do tipo ponteiro para void, dessa forma, pode-se passar qualquer tipo de par\u00e2metros para a tarefa, bastando a tarefa, quando em execu\u00e7\u00e3o, fazer o casting para o tipo desejado.<\/p>\n\n\n\n<p>Para criar efetivamente as tarefas devemos utilizar o comando <strong>xTaskCreate<\/strong>. Essa \u00e9 uma fun\u00e7\u00e3o disponibilizada pelo FreeRTOS que conta com diversos par\u00e2metros, como se pode observar no prot\u00f3tipo a seguir:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ Cria\u00e7\u00e3o de tarefas\n  \nxTaskCreate(\n     Tarefa1        \/\/ -Tarefa a ser configurada\n     , \"Tarefa 01\"  \/\/ -Nome (para facilitar o debug)\n     , 128          \/\/ -Stack (em words) reservada para essa fun\u00e7\u00e3o\n     , NULL         \/\/ -Par\u00e2metros passados para a tarefa\n     , 2            \/\/ -Prioridade\n     , NULL         \/\/ -Handle para a tarefa. Este par\u00e2metro \u00e9 opcional,          \n     );             \/\/  desde que voc\u00ea n\u00e3o precise suspender e reiniciar \n                    \/\/  a tarefa durante o tempo de execu\u00e7\u00e3o da tarefa.\n     <\/pre>\n\n\n\n<p>Como visto acima, um dos par\u00e2metros para a cria\u00e7\u00e3o de tarefas \u00e9 o tamanho da stack, ou seja, a quantidade de mem\u00f3ria RAM que a task ter\u00e1 a sua disposi\u00e7\u00e3o. Mas como saber a quantidade que ser\u00e1 suficiente e necess\u00e1ria?<\/p>\n\n\n\n<p>Uma das maneiras mais eficazes de fazer isso \u00e9 atrav\u00e9s do monitoramento do <strong>High Water Mark<\/strong>, que \u00e9 um mecanismo que registra o m\u00e1ximo de mem\u00f3ria utilizada pela task at\u00e9 o momento. O procedimento para realizar esse monitoramento se d\u00e1 da seguinte forma: Inicialmete reserve uma quantidade que estime ser suficiente para aquela tarefa, um &#8220;chute&#8221; pra cima mesmo; Em seguida, fa\u00e7a com que o high water mark seja enviado de tempos em tempos para o monitor serial, vale ressaltar que o valor que ser\u00e1 exibido diz respeito a quantidade da mem\u00f3ria reservada para a task que N\u00c3O foi utlizada por ela; Ap\u00f3s um tempo de opera\u00e7\u00e3o voc\u00ea poder\u00e1 redimensionar a stack conforme a necessidade. \u00c9 sempre recomendado reservar 10% a mais da mem\u00f3ria que foi visualizada nos testes. <\/p>\n\n\n\n<p>Em termos de c\u00f3digo, o valor do high water mark deve ser armazenado numa vari\u00e1vel do tipo UBaseType_t, como visto abaixo:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>UBaseType_t HighWaterMark;<\/code><\/pre>\n\n\n\n<p>Dentro das tarefas, a leitura se d\u00e1 da seguinte forma:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/* Obt\u00e9m o High Water Mark da task atual.\n   Lembre-se: tal informa\u00e7\u00e3o \u00e9 obtida em words! *\/\nHighWaterMark = uxTaskGetStackHighWaterMark( NULL );\nSerial.print(\"High water mark (words) da task atual: \");\nSerial.println(HighWaterMark);<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Praticando o uso de tasks<\/h4>\n\n\n\n<p>Como um exemplo inicial costruiremos duas tarefas simples que ser\u00e3o executadas em paralelo. As tarefas consistem em fazer dois led&#8217;s piscar em frequ\u00eancias distintas.<\/p>\n\n\n\n<p>O circuito para esse projeto conta com apenas dois led&#8217;s conectados \u00e0s portas digitais 12 e 13 do arduino, al\u00e9m de dois resistores limitadores de corrente de 220 ohms.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/visiorob.com.br\/wp-content\/uploads\/2020\/07\/Fantabulous-Jaiks-1024x423.png\" alt=\"\" class=\"wp-image-1198\" width=\"879\" height=\"362\" srcset=\"https:\/\/visiorob.com.br\/wp-content\/uploads\/2020\/07\/Fantabulous-Jaiks-1024x423.png 1024w, https:\/\/visiorob.com.br\/wp-content\/uploads\/2020\/07\/Fantabulous-Jaiks-300x124.png 300w, https:\/\/visiorob.com.br\/wp-content\/uploads\/2020\/07\/Fantabulous-Jaiks-768x317.png 768w, https:\/\/visiorob.com.br\/wp-content\/uploads\/2020\/07\/Fantabulous-Jaiks.png 1366w\" sizes=\"auto, (max-width: 879px) 100vw, 879px\" \/><figcaption>Circuito para o blink de led&#8217;s<\/figcaption><\/figure>\n<\/div>\n\n\n<p>O c\u00f3digo fonte para esse projeto \u00e9 demonstrado e comentado abaixo:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ Inclus\u00e3o da biblioteca FreeRTOS\n\n#include &lt;Arduino_FreeRTOS.h>\n\n\/\/ Defines\n\n#define led01 13         \/\/ led 1 conectado no pino 13\n#define led02 12         \/\/ led 2 conectado no pino 12\n#define tempo_led01 1000 \/\/ 1 segundo\n#define tempo_led02 500  \/\/ 0,5 segundo\n\n\/\/ Declara\u00e7\u00e3o das tarefas\n\nvoid TaskBlink01(void *pvParameters);\nvoid TaskBlink02(void *pvParameters);\n\nvoid setup() {\n\n  pinMode(led01, OUTPUT); \/\/ Led 1 como sa\u00edda\n  pinMode(led02, OUTPUT); \/\/ Led 2 como sa\u00edda \n\n\/\/ Cria\u00e7\u00e3o das tarefas\n  \n  xTaskCreate(\n   TaskBlink01\n    , \"Blink 01\"   \/\/ Nome (para facilitar o debug)\n    , 128          \/\/ Tamanho da stack reservada para essa fun\u00e7\u00e3o\n    , NULL         \/\/ Par\u00e2metros passados para a tarefa\n    , 2            \/\/ Prioridade\n    , NULL         \/\/ Handle da tarefa\n    );\n\n   xTaskCreate(\n    TaskBlink02\n    , \"Blink 02\"   \/\/ Nome (para facilitar o debug)\n    , 128          \/\/ Tamanho da stack reservada para essa fun\u00e7\u00e3o\n    , NULL         \/\/ Par\u00e2metros passados para a tarefa\n    , 1            \/\/ Prioridade\n    , NULL         \/\/ Handle da tarefa\n    );\n}\n\nvoid loop() {\n \n  \/\/ Vazio, tudo \u00e9 executado nas tarefas\n  \n}\n\n\/\/ Tarefas:\n\nvoid TaskBlink01(void *pvParameters){\n\n  (void) pvParameters;\n  \n\/\/ Loop infinito                       \n  while(1){\n    digitalWrite(led01, HIGH);                    \/\/ Acende o led\n    vTaskDelay(tempo_led01 \/ portTICK_PERIOD_MS); \/\/ Tempo aceso\n    digitalWrite(led01, LOW);                     \/\/ Apaga o led\n    vTaskDelay(tempo_led01 \/ portTICK_PERIOD_MS); \/\/ Tempo apagado\n    } \/\/ Fim do loop infinito\n  } \n\n  void TaskBlink02(void *pvParameters){\n\n  (void) pvParameters;\n  \n\/\/ Loop infinito\n  while(1){\n    digitalWrite(led02, HIGH);                    \/\/ Acende o led\n    vTaskDelay(tempo_led02 \/ portTICK_PERIOD_MS); \/\/ Tempo aceso\n    digitalWrite(led02, LOW);                     \/\/ Apaga o led\n    vTaskDelay(tempo_led02 \/ portTICK_PERIOD_MS); \/\/ Tempo apagado\n    } \/\/ Fim do loop infinito\n  }\n<\/pre>\n\n\n\n<p>Note que n\u00e3o devemos utilizar a fun\u00e7\u00e3o <em>delay()<\/em>, nativa da biblioteca do arduino, ja que ela deixaria o processador inativo para todas as tarefas. Ao inv\u00e9s dela utilizamos a fun\u00e7\u00e3o <em>vTaskDelay(),<\/em> ela informa que apenas a tarefa atual entrar\u00e1 em delay, liberando o processador para ser utilizado por outras tarefas. Como argumentos a fun\u00e7\u00e3o <em>vTaskDelay() <\/em>recebe o n\u00famero de ticks do processador que a tarefa dever\u00e1 ficar inativa, mas para facilitar podemos utilizar o tempo em milissegundos seguido da constante \/portTICK_PERIOD_MS assim como foi utilizado no nosso c\u00f3digo.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Cria\u00e7\u00e3o de sem\u00e1foros<\/h3>\n\n\n\n<p>O sistema de sem\u00e1foros \u00e9 um recurso disponibilizado pelo FreeRTOS para que haja um controle no acesso aos recursos do sistema (como a porta serial, por exmplo), evitando que duas tarefas tentem fazer o uso dele ao mesmo tempo,  o que corromperia dados e comprometeria o funcionamento no sistema.<\/p>\n\n\n\n<p>O FreeRTOS oferece outros tipos de sem\u00e1foros, por\u00e9m iremos nos concentrar no sem\u00e1foro do tipo MUTEX (Mutual Exclusion &#8211; Exclus\u00e3o M\u00fatua). Um sem\u00e1foro deste tipo tem por objetivo restringir o acesso \u00e0 um recurso do sistema, permitindo que apenas uma tarefa fa\u00e7a uso de tal recurso at\u00e9 que ela &#8220;libere&#8221; ele.<\/p>\n\n\n\n<p>Para fazer uso de um sem\u00e1foro, inicialmente \u00e9 preciso declarar de maneira global seu handle, da seguinte maneira:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SemaphoreHandle_t xSemaforo_teste;<\/code><\/pre>\n\n\n\n<p>Em seguida \u00e9 necess\u00e1rio criar o sem\u00e1foro em si que, no nosso caso, \u00e9 do tipo MUTEX<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>xSemaforo_teste = xSemaphoreCreateMutex();<\/code><\/pre>\n\n\n\n<p>O ciclo de funcionamento do sem\u00e1foro MUTEX se d\u00e1 da seguinte forma:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Determinada tarefa tenta obter o controle do sem\u00e1foro, atrav\u00e9s da fun\u00e7\u00e3o <strong>xSemaphoreTake<\/strong>.<\/li><li>Se conseguir, ou seja, se o recurso n\u00e3o estiver sendo utilizado por nenhuma outra tarefa, ela executa normalmente.<\/li><li>Finalizado o uso dos recursos que dependiam do sem\u00e1foro, o sem\u00e1foro \u00e9 liberado, com o uso da fun\u00e7\u00e3o&nbsp;<strong>xSemaphoreGive<\/strong>.<\/li><li>Sendo assim, o recurso protegido pelo sem\u00e1foro pode ser utilizado por outra tarefa.<\/li><\/ul>\n\n\n\n<p>Um ponto a se atentar \u00e9 que as fun\u00e7\u00f5es xSemaphoreTake e xSemaphoreGive possuem um par\u00e2metro muito importante chamado xTicksToWait. Ele especifica quantos&nbsp;<strong>ticks do processador<\/strong>&nbsp;deve-se aguardar na tentativa de se obter ou liberar um sem\u00e1foro. Este tempo pode ser infinito, se atribu\u00eddo a este par\u00e2metro a macro portMAX_DELAY. Veja no exemplo a seguir:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>xSemaphoreTake(xSemaforo_teste, portMAX_DELAY );<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Praticando o uso de sem\u00e1foros<\/h4>\n\n\n\n<p>Para exemplificar o uso de sem\u00e1foros podemos aprimorar o c\u00f3digo visto anteriormente, adicionando o sem\u00e1foro para realizar o controle de acesso ao monitor serial, que ser\u00e1 utilizado para monitorar o High Water Mark das tarefas. Acompanhe no c\u00f3digo fonte abaixo<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ Inclus\u00e3o das biblioteca FreeRTOS\n\n#include &lt;Arduino_FreeRTOS.h>\n#include &lt;task.h>\n#include &lt;semphr.h>\n\n\/\/ Defines\n\n#define led01 13         \/\/ led 1 conectado no pino 13\n#define led02 12         \/\/ led 2 conectado no pino 12\n#define tempo_led01 1000 \/\/ 1 segundo\n#define tempo_led02 500  \/\/ 0,5 segundo\n\n\/\/ Declara\u00e7\u00e3o das tarefas\n\nvoid TaskBlink01(void *pvParameters);\nvoid TaskBlink02(void *pvParameters);\n\n\/\/ Declara\u00e7\u00e3o do handle do sem\u00e1foro\n\nSemaphoreHandle_t SemaforoSerial;\n\nvoid setup() {\n\n  pinMode(led01, OUTPUT); \/\/ Led 1 como sa\u00edda\n  pinMode(led02, OUTPUT); \/\/ Led 2 como sa\u00edda \n  Serial.begin(9600); \/\/ Inicialiaza o serial\n\n\/\/ Cria\u00e7\u00e3o do sem\u00e1foro\n\n   SemaforoSerial = xSemaphoreCreateMutex();\n\n\/\/ Configura\u00e7\u00e3o das tarefas\n  \n  xTaskCreate(\n   TaskBlink01\n    , \"Blink 01\"   \/\/ Nome (para facilitar o debug)\n    , 128          \/\/ Tamanho da stack reservada para essa fun\u00e7\u00e3o\n    , NULL         \/\/ Par\u00e2metros passados para a tarefa\n    , 2            \/\/ Prioridade\n    , NULL         \/\/ Handle da tarefa\n    );\n\n   xTaskCreate(\n    TaskBlink02\n    , \"Blink 02\"   \/\/ Nome (para facilitar o debug)\n    , 128          \/\/ Tamanho da stack reservada para essa fun\u00e7\u00e3o\n    , NULL         \/\/ Par\u00e2metros passados para a tarefa\n    , 2            \/\/ Prioridade\n    , NULL         \/\/ Handle da tarefa\n    );\n}\n\nvoid loop() {\n \n  \/\/ Vazio, tudo \u00e9 executado nas tarefas\n  \n}\n\n\/\/ Tarefas:\n\nvoid TaskBlink01(void *pvParameters){\n\n  (void) pvParameters;\n  \n  UBaseType_t HighWaterMark01;\n  int contador01=0;\n                         \n  while(1){\n    digitalWrite(led01, HIGH);                    \/\/ Acende o led\n    vTaskDelay(tempo_led01 \/ portTICK_PERIOD_MS); \/\/ Tempo aceso\n    digitalWrite(led01, LOW);                     \/\/ Apaga o led\n    vTaskDelay(tempo_led01 \/ portTICK_PERIOD_MS); \/\/ Tempo apagado\n    contador01++;\n    \n    \/\/ Imprime o High Water Mark a cada 6 segundos\n   \n    if(contador01 == 3){\n      contador01=0;\n      xSemaphoreTake(SemaforoSerial,portMAX_DELAY);\/\/Solicita o sem\u00e1foro\n      HighWaterMark01 = uxTaskGetStackHighWaterMark(NULL);\n      Serial.print(\"High Water Mark (em words) da Tarefa 1: \");\n      Serial.println(HighWaterMark01);\n      xSemaphoreGive(SemaforoSerial); \/\/ Libera o sem\u00e1foro\n      }\n    } \n  }\n\n  void TaskBlink02(void *pvParameters){\n\n  (void) pvParameters;\n  \n  UBaseType_t HighWaterMark02;\n  int contador02=0;\n  \n  while(1){\n    \n    digitalWrite(led02, LOW);                     \/\/ Apaga o led\n    vTaskDelay(tempo_led02 \/ portTICK_PERIOD_MS); \/\/ Tempo aceso\n    digitalWrite(led02, HIGH);                    \/\/ Acende o led\n    vTaskDelay(tempo_led02 \/ portTICK_PERIOD_MS); \/\/ Tempo apagado\n    contador02++;\n    \n    \/\/ Imprime o High Water Mark a cada 6 segundos\n    \n    if(contador02 == 6){\n      contador02=0;\n      xSemaphoreTake(SemaforoSerial,portMAX_DELAY);\/\/Solicita o sem\u00e1foro\n      HighWaterMark02 = uxTaskGetStackHighWaterMark(NULL);\n      Serial.print(\"High Water Mark (em words) da Tarefa 2: \");\n      Serial.println(HighWaterMark02);\n      xSemaphoreGive(SemaforoSerial); \/\/ Libera o sem\u00e1foro\n      }\n    } \n  }<\/pre>\n\n\n\n<p>Ap\u00f3s algum tempo de execu\u00e7\u00e3o do c\u00f3digo podemos observar a seguinte sa\u00edda no monitor serial:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"417\" height=\"414\" src=\"https:\/\/visiorob.com.br\/wp-content\/uploads\/2020\/07\/HWM-1.png\" alt=\"\" class=\"wp-image-1220\" srcset=\"https:\/\/visiorob.com.br\/wp-content\/uploads\/2020\/07\/HWM-1.png 417w, https:\/\/visiorob.com.br\/wp-content\/uploads\/2020\/07\/HWM-1-300x298.png 300w, https:\/\/visiorob.com.br\/wp-content\/uploads\/2020\/07\/HWM-1-150x150.png 150w\" sizes=\"auto, (max-width: 417px) 100vw, 417px\" \/><figcaption>High Water Mark das tarefas<\/figcaption><\/figure>\n<\/div>\n\n\n<p>Conforme dito anteriormente, o n\u00famero impresso diz respeito ao n\u00famero de words que n\u00e3o foi utilizado pela tarefa. Como reservamos 128 words para ambas as tarefas, podemos facilmente deduzir que a tarefa 1 utiliza 63 words, j\u00e1 a tarefa 2 utiliza 82 words.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Cria\u00e7\u00e3o de filas (Queues)<\/h3>\n\n\n\n<p>Filas (ou queues, em ingl\u00eas) \u00e9 o m\u00e9todo utilizado pelo FreeRTOS para realizar a comunica\u00e7\u00e3o entre as tarefas para que nao haja o uso de vari\u00e1veis globais como interface de comunica\u00e7\u00e3o. O m\u00e9todo de escrita e leitura das filas obedece ao sistema FIFO (First Input First Output), ou seja, o primeiro dado a ser escrito \u00e9 tamb\u00e9m o primeiro a ser lido.<\/p>\n\n\n\n<p>Uma fila pode ser declarada da seguinte forma:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>QueueHandle_t xQueue_Teste;<\/code><\/pre>\n\n\n\n<p>Para iniciar uma fila, \u00e9 necess\u00e1rio fazer o seguinte:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>xQueue_Teste = xQueueCreate( NUMERO_ITENS_FILA, TAMANHO_DE_CADA_ITEM );<\/code><\/pre>\n\n\n\n<p>Onde:<\/p>\n\n\n\n<p><strong>NUMERO_ITENS_FILA<\/strong>:&nbsp;quantidade total de itens que voc\u00ea deseja que sua fila possua.<\/p>\n\n\n\n<p><strong>TAMANHO_DE_CADA_ITEM<\/strong>:&nbsp;tamanho&nbsp;(em bytes)&nbsp;de cada item da fila.<br>Por exemplo, se cada item de sua fila for um n\u00famero inteiro, este campo dever\u00e1 ser igual a sizeof(int).<\/p>\n\n\n\n<p>\u00c9 importante ressaltar que, embora extremamente \u00fateis e necess\u00e1rias, as filas ocupam uma quantidade consider\u00e1vel de mem\u00f3ria RAM, portanto use-as com cuidado.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Formas de escrever\/ler dados de uma fila:<\/h4>\n\n\n\n<p>Existem diversas formas de adicionar elementos em uma fila, segue abaixo alguns deles:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>xQueueSend:&nbsp;<\/strong>adiciona elemento a uma fila. Esta fun\u00e7\u00e3o&nbsp;<strong>n\u00e3o<\/strong>&nbsp;deve ser utilizada dentro do tratamento de uma interrup\u00e7\u00e3o (ou dentro de callbacks).<\/li><li><strong>xQueueSendFromISR:<\/strong>&nbsp;adiciona elemento a uma fila. Esta fun\u00e7\u00e3o&nbsp;<strong>deve ser somente usada<\/strong>&nbsp;dentro do tratamento de uma interrup\u00e7\u00e3o ou callbacks.<\/li><li><strong>xQueueOverwrite:<\/strong>&nbsp;sobrescreve o primeiro elemento de uma fila. Essa fun\u00e7\u00e3o \u00e9 especialmente \u00fatil quando se utiliza uma fila de um \u00fanico elemento, onde somente o valor mais recente (\u00faltima leitura de um sensor, por exemplo) \u00e9 que importa ser mantido. Tipicamente, as filas que usam esse tipo de inser\u00e7\u00e3o s\u00e3o filas de um \u00fanico item.<br>Esta fun\u00e7\u00e3o&nbsp;<strong>n\u00e3o<\/strong>&nbsp;deve ser utilizada dentro do tratamento de uma interrup\u00e7\u00e3o.<\/li><li><strong>xQueueOverwriteFromISR:<\/strong>&nbsp;an\u00e1logo ao anterior, por\u00e9m deve&nbsp;ser usada&nbsp;<strong>somente dentro de um tratamento de interrup\u00e7\u00e3o<\/strong>.<\/li><\/ul>\n\n\n\n<p>Exemplo de escrita de dados em uma fila:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>xQueueOverwrite(HANDLE_DA_FILA, &amp;DADO_A_SER_ESCRITO);<\/code><\/pre>\n\n\n\n<p>J\u00e1 para ler\/remover arquivos de uma fila, algumas das fun\u00e7\u00f5es dispon\u00edveis s\u00e3o:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>xQueueReceive:<\/strong>&nbsp;l\u00ea&nbsp;um elemento da fila. Esta fun\u00e7\u00e3o&nbsp;<strong>n\u00e3o<\/strong>&nbsp;deve ser utilizada dentro do tratamento de uma interrup\u00e7\u00e3o (ou dentro de callbacks).<\/li><li><strong>xQueueReceiveFromISR:<\/strong>&nbsp;l\u00ea&nbsp;um elemento da fila. Esta fun\u00e7\u00e3o&nbsp;<strong>somente deve ser utilizada<\/strong>&nbsp;dentro do tratamento de uma interrup\u00e7\u00e3o (ou dentro de callbacks).<\/li><li><strong>xQueuePeek:<\/strong>&nbsp;faz a leitura do elemento da fila, por\u00e9m, sem retir\u00e1-lo dela. Isso \u00e9 \u00fatil quando a tarefa deseja verificar se a informa\u00e7\u00e3o na fila deve ou n\u00e3o ser tratada por ela, sem alterar nada da fila para isso. Em analogia livre, \u00e9 como&nbsp;\u201cdar uma espiadinha\u201d no item a ser lido\/removido da fila.<br>Esta fun\u00e7\u00e3o&nbsp;<strong>n\u00e3o<\/strong>&nbsp;deve ser utilizada dentro do tratamento de uma interrup\u00e7\u00e3o (ou dentro de callbacks).<\/li><li><strong>xQueuePeekFromISR:&nbsp;<\/strong>an\u00e1logo ao anterior, ou seja,&nbsp;faz a leitura o elemento da fila, por\u00e9m sem retir\u00e1-lo dela, por\u00e9m&nbsp;<strong>somente deve ser utilizada<\/strong>&nbsp;dentro do tratamento de uma interrup\u00e7\u00e3o (ou dentro de callbacks).<br><\/li><\/ul>\n\n\n\n<p>C\u00f3digo exemplo para leitura em filas:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>xQueueReceive(HANDLE_DA_FILA, &amp;VARIAVEL_DESTINO, TEMPO_MAXIMO);<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Praticando o uso de filas<\/h4>\n\n\n\n<p>Para ilustrar o conceito e o funcionamento das filas, podemos elaborar um projeto que realiza a leitura de um teclado matricial e utiliza uma fila para enviar o caracter correspondente a tecla que foi pressionada para ser impresso no monitor serial, al\u00e9m disso, para refor\u00e7ar o conceito de multitarefa, teremos novamente a tarefa respons\u00e1vel pelo blink do led, j\u00e1 vista nos exemplos anteriores. Para tal projeto ser\u00e1 necess\u00e1rio a montagem do seguinte circuito:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/visiorob.com.br\/wp-content\/uploads\/2020\/07\/Fantabulous-Jaiks-1-1.png\" alt=\"\" class=\"wp-image-1226\" width=\"695\" height=\"510\" srcset=\"https:\/\/visiorob.com.br\/wp-content\/uploads\/2020\/07\/Fantabulous-Jaiks-1-1.png 764w, https:\/\/visiorob.com.br\/wp-content\/uploads\/2020\/07\/Fantabulous-Jaiks-1-1-300x220.png 300w, https:\/\/visiorob.com.br\/wp-content\/uploads\/2020\/07\/Fantabulous-Jaiks-1-1-80x60.png 80w\" sizes=\"auto, (max-width: 695px) 100vw, 695px\" \/><figcaption>Circuito para leitura do teclado matricial<\/figcaption><\/figure>\n<\/div>\n\n\n<p>O software a ser embarcado no arduino \u00e9 exibido abaixo:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#include &lt;Arduino_FreeRTOS.h>\n#include &lt;task.h>\n#include &lt;queue.h>\n\n\/\/ Mapeamento de hardware\n\n#define coluna1 6\n#define coluna2 7\n#define coluna3 8\n#define coluna4 9\n#define linha1 2\n#define linha2 3\n#define linha3 4\n#define linha4 5\n\n#define led 13\n#define tempo_led 1000  \n\n\/\/ Declara\u00e7\u00e3o das tarefas\n\nvoid TaskTeclado(void *pvParameters);\nvoid TaskBlink(void *pvParameters);\nvoid TaskImprime(void *pvParameters);\n\n\/\/ Declara\u00e7\u00e3o do handle da tarefa\n\nTaskHandle_t HandleTeclado;\n\n\/\/ Declara\u00e7\u00e3o da fila (queue)\n\nQueueHandle_t QueueImprime; \n\nvoid setup() {\n\n  pinMode(led, OUTPUT); \/\/ Led como sa\u00edda digital\n\n  Serial.begin(9600); \/\/ Inicializa o monitor serial\n  \n\/\/ Linhas como entradas (Utilizando resistores de Pull-Up interno)\n  \n  pinMode(linha1, INPUT_PULLUP);\n  pinMode(linha2, INPUT_PULLUP);\n  pinMode(linha3, INPUT_PULLUP);\n  pinMode(linha4, INPUT_PULLUP);\n    \n\n\/\/ Colunas como sa\u00eddas\n\n  pinMode(coluna1, OUTPUT);\n  pinMode(coluna2, OUTPUT);\n  pinMode(coluna3, OUTPUT);\n  pinMode(coluna4, OUTPUT);\n\n\/\/ Configura\u00e7\u00e3o das tarefas\n\n xTaskCreate(\n    TaskTeclado\n    , \"Varredura do teclado\" \/\/ Nome\n    , 128                    \/\/ Tamanho da Stack\n    , NULL                   \/\/ Par\u00e2metros passados\n    , 1                      \/\/ Prioridade\n    , &amp;HandleTeclado         \/\/ Handle da tarefa\n    );\n\n  xTaskCreate(\n   TaskBlink\n    , \"Blink led\"  \/\/ Nome (para facilitar o debug)\n    , 128          \/\/ Tamanho da stack reservada para essa fun\u00e7\u00e3o\n    , NULL         \/\/ Par\u00e2metros passados para a tarefa\n    , 2            \/\/ Prioridade\n    , NULL         \/\/ Handle da tarefa\n    );\n\n  xTaskCreate(\n    TaskImprime\n    , \"Imprime\"   \/\/ Nome\n    , 128         \/\/ Stack\n    , NULL        \/\/ Par\u00e2metros\n    , 3           \/\/ Prioridade\n    , NULL        \/\/ Handle\n    );\n\n  \/\/ Cria\u00e7\u00e3o da fila de 1 elemento\n  \/\/ do tamanho de uma variavel tipo char\n  \n  QueueImprime = xQueueCreate(1, sizeof(char));\n    \n}\n\nvoid loop() {\n  \n  \/\/ put your main code here, to run repeatedly:\n\n}\n\n\/\/ Tarefas\n\nvoid TaskTeclado(void *pvParameters){\n\n    (void)pvParameters;\n    \n    int coluna;\n    char tecla;\n    \n    while(1){\n\n    \/\/ Varredura do teclado matricial:\n    \/\/ alterna entre as colunas e testa as linhas para\n    \/\/ saber qual tecla foi pressionada\n    \n      for(coluna = coluna1; coluna &lt;= coluna4; coluna++){\n        digitalWrite(coluna1, HIGH);\n        digitalWrite(coluna2, HIGH);\n        digitalWrite(coluna3, HIGH);\n        digitalWrite(coluna4, HIGH);\n        digitalWrite(coluna, LOW);\n\n        if(!digitalRead(linha1)){\n          if(coluna == coluna1) tecla = '1';\n          else if(coluna == coluna2) tecla = '2';\n          else if(coluna == coluna3) tecla = '3';\n          else if(coluna == coluna4) tecla = 'A';\n          xQueueOverwrite(QueueImprime, &amp;tecla);  \/\/ Escreve na fila\n          vTaskSuspend(NULL);                     \/\/ Suspende a tarefa \n          while(!digitalRead(linha1));\/\/ Mant\u00e9m a tarefa nesse ponto at\u00e9\n          }                           \/\/ que a tecla seja solta\n          \n        if(!digitalRead(linha2)){\n          if(coluna == coluna1) tecla = '4';\n          else if(coluna == coluna2 ) tecla = '5';\n          else if (coluna == coluna3) tecla = '6';\n          else if(coluna == coluna4) tecla = 'B';\n          xQueueOverwrite(QueueImprime, &amp;tecla);  \/\/ Escreve na fila\n          vTaskSuspend(NULL);                     \/\/ Suspende a tarefa \n          while(!digitalRead(linha2));\/\/ Mant\u00e9m a tarefa nesse ponto at\u00e9\n          }                           \/\/ que a tecla seja solta\n          \n        if(!digitalRead(linha3)){\n          if(coluna == coluna1) tecla = '7';\n          else if(coluna == coluna2) tecla = '8';\n          else if(coluna == coluna3) tecla = '9';\n          else if(coluna == coluna4) tecla = 'C';\n          xQueueOverwrite(QueueImprime, &amp;tecla);  \/\/ Escreve na fila\n          vTaskSuspend(NULL);                     \/\/ Suspende a tarefa \n          while(!digitalRead(linha3));\/\/ Mant\u00e9m a tarefa nesse ponto at\u00e9\n          }                           \/\/ que a tecla seja solta\n          \n        if(!digitalRead(linha4)){\n          if(coluna == coluna1) tecla = '*';\n          else if(coluna == coluna2) tecla = '0';\n          else if(coluna == coluna3) tecla = '#';\n          else if(coluna == coluna4) tecla = 'D';\n          xQueueOverwrite(QueueImprime, &amp;tecla);  \/\/ Escreve na fila\n          vTaskSuspend(NULL);                     \/\/ Suspende a tarefa \n          while(!digitalRead(linha4));\/\/ Mant\u00e9m a tarefa nesse ponto at\u00e9\n          }                           \/\/ que a tecla seja solta\n        }\n      }\n    }\n\nvoid TaskBlink(void *pvParameters){\n\n  (void)pvParameters;\n\n  while(1){\n    digitalWrite(led, HIGH); \/\/ Acende o led\n    vTaskDelay(tempo_led \/ portTICK_PERIOD_MS); \/\/ Tempo aceso\n    digitalWrite(led, LOW); \/\/ Apaga o led\n    vTaskDelay(tempo_led \/ portTICK_PERIOD_MS); \/\/ Tempo apagado\n    } \n  }\n\nvoid TaskImprime(void *pvParameters){\n\n  (void)pvParameters;\n  char teclaRecebida;\n \n  while(1){\n    \n    \/\/ Aguarda at\u00e9 que haja algo na fila\n    \/\/ quando houver, armaneza na vari\u00e1vel teclaRecebida\n    \n    xQueueReceive(QueueImprime, &amp;teclaRecebida, portMAX_DELAY);\n    vTaskDelay(200\/portTICK_PERIOD_MS); \/\/ delay anti bouncing\n    Serial.print(teclaRecebida); \/\/ Imprime a tecla pressionada\n    vTaskResume(HandleTeclado);  \/\/ Retoma a leitura do teclado\n    }\n  }<\/pre>\n\n\n\n<p>Podemos comprovar o funcionamento da nossa fila ao se observar o monitor serial ap\u00f3s um pequeno teste:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/visiorob.com.br\/wp-content\/uploads\/2020\/07\/Anota\u00e7\u00e3o-2020-07-14-152440.png\" alt=\"\" class=\"wp-image-1237\" width=\"634\" height=\"272\" srcset=\"https:\/\/visiorob.com.br\/wp-content\/uploads\/2020\/07\/Anota\u00e7\u00e3o-2020-07-14-152440.png 978w, https:\/\/visiorob.com.br\/wp-content\/uploads\/2020\/07\/Anota\u00e7\u00e3o-2020-07-14-152440-300x129.png 300w, https:\/\/visiorob.com.br\/wp-content\/uploads\/2020\/07\/Anota\u00e7\u00e3o-2020-07-14-152440-768x330.png 768w\" sizes=\"auto, (max-width: 634px) 100vw, 634px\" \/><figcaption>Impress\u00e3o dos dados do teclado<\/figcaption><\/figure>\n<\/div>\n\n\n<h2 class=\"wp-block-heading\">Conclus\u00e3o<\/h2>\n\n\n\n<p>Com este artigo conseguimos, atrav\u00e9s de exemplos simples, dar uma base  dos principais conceitos do FreeRTOS, bem como o uso de tarefas, filas e sem\u00e1foros. Atrav\u00e9s disso torna-se poss\u00edvel o desenvolvimento de projetos cada vez mais complexos e desafiadores, para isso tamb\u00e9m \u00e9 altamente recomendado o acesso ao site oficial do FreeRTOS (<a href=\"https:\/\/www.freertos.org\/\">www.freertos.org<\/a>). Bons estudos!<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Refer\u00eancias<\/h4>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"https:\/\/www.embarcados.com.br\/rtos-para-iniciantes-com-arduino-e-freertos\/\">https:\/\/www.embarcados.com.br\/rtos-para-iniciantes-com-arduino-e-freertos\/<\/a><\/li><li><a href=\"https:\/\/www.filipeflop.com\/blog\/freertos-para-arduino\/\">https:\/\/www.filipeflop.com\/blog\/freertos-para-arduino\/<\/a><\/li><li><a href=\"https:\/\/www.filipeflop.com\/blog\/fila-com-freertos\/\">https:\/\/www.filipeflop.com\/blog\/fila-com-freertos\/<\/a><\/li><li><a href=\"https:\/\/www.filipeflop.com\/blog\/semaforo-no-freertos\/\">https:\/\/www.filipeflop.com\/blog\/semaforo-no-freertos\/<\/a><\/li><li><a href=\"https:\/\/www.freertos.org\/\">www.freertos.org<\/a><\/li><\/ul>\n","protected":false},"excerpt":{"rendered":"<div class=\"mh-excerpt\"><p>Introdu\u00e7\u00e3o aos principais conceitos para a programa\u00e7\u00e3o utilizando o sistema operacional de tempo real FreeRTOS, contando com exemplos de projetos e c\u00f3digos.<\/p>\n<\/div>","protected":false},"author":22,"featured_media":1247,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[12,42],"tags":[45],"class_list":["post-1141","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-microprocessadores","category-programacao","tag-freertos"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/visiorob.com.br\/index.php\/wp-json\/wp\/v2\/posts\/1141","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/visiorob.com.br\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/visiorob.com.br\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/visiorob.com.br\/index.php\/wp-json\/wp\/v2\/users\/22"}],"replies":[{"embeddable":true,"href":"https:\/\/visiorob.com.br\/index.php\/wp-json\/wp\/v2\/comments?post=1141"}],"version-history":[{"count":79,"href":"https:\/\/visiorob.com.br\/index.php\/wp-json\/wp\/v2\/posts\/1141\/revisions"}],"predecessor-version":[{"id":1433,"href":"https:\/\/visiorob.com.br\/index.php\/wp-json\/wp\/v2\/posts\/1141\/revisions\/1433"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/visiorob.com.br\/index.php\/wp-json\/wp\/v2\/media\/1247"}],"wp:attachment":[{"href":"https:\/\/visiorob.com.br\/index.php\/wp-json\/wp\/v2\/media?parent=1141"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/visiorob.com.br\/index.php\/wp-json\/wp\/v2\/categories?post=1141"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/visiorob.com.br\/index.php\/wp-json\/wp\/v2\/tags?post=1141"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}