{"id":173794,"date":"2025-09-11T13:26:56","date_gmt":"2025-09-11T13:26:56","guid":{"rendered":"https:\/\/randomnerdtutorials.com\/?p=173794"},"modified":"2025-11-20T14:30:01","modified_gmt":"2025-11-20T14:30:01","slug":"esp32-freertos-queues-inter-task-arduino","status":"publish","type":"post","link":"https:\/\/randomnerdtutorials.com\/esp32-freertos-queues-inter-task-arduino\/","title":{"rendered":"ESP32 with FreeRTOS Queues: Inter-Task Communication (Arduino IDE)"},"content":{"rendered":"\n<p>In this guide, you&#8217;ll learn how to use FreeRTOS queues for safe and efficient communication between tasks on the ESP32, using the Arduino IDE. Queues allow you to exchange data between tasks in a safe way. We&#8217;ll cover the basic principles of how queues work and walk you through three practical examples to show how to pass data between tasks.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" fetchpriority=\"high\" decoding=\"async\" width=\"1200\" height=\"675\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/07\/ESP32-FreeRTOS-queues.jpg?resize=1200%2C675&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 with FreeRTOS Queues: Inter-Task Communication (Arduino IDE)\" class=\"wp-image-174099\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/07\/ESP32-FreeRTOS-queues.jpg?w=1920&amp;quality=100&amp;strip=all&amp;ssl=1 1920w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/07\/ESP32-FreeRTOS-queues.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/07\/ESP32-FreeRTOS-queues.jpg?resize=1024%2C576&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/07\/ESP32-FreeRTOS-queues.jpg?resize=768%2C432&amp;quality=100&amp;strip=all&amp;ssl=1 768w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/07\/ESP32-FreeRTOS-queues.jpg?resize=1536%2C864&amp;quality=100&amp;strip=all&amp;ssl=1 1536w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><\/figure><\/div>\n\n\n<p class=\"rntbox rntclgreen\"><strong>New to FreeRTOS? <\/strong>Start with this tutorial: <a href=\"https:\/\/randomnerdtutorials.com\/esp32-freertos-arduino-tasks\/\">ESP32 with FreeRTOS (Arduino IDE)\u2014Getting Started Guide: Creating Tasks<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Table of Contents<\/h2>\n\n\n\n<p>In this tutorial, we&#8217;ll cover the following subjects:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"#freertos-communication-between-tasks\" title=\"\">FreeRTOS Communication Between Tasks<\/a><\/li>\n\n\n\n<li><a href=\"#freertos-queues\" title=\"\">What are FreeRTOS Queues?<\/a><\/li>\n\n\n\n<li><a href=\"#queue-basics\" title=\"\">FreeRTOS Queue Basics<\/a><\/li>\n\n\n\n<li><a href=\"#led-brightness\" title=\"\">Example 1: Using Queues to Control LED Brightness<\/a><\/li>\n\n\n\n<li><a href=\"#three-tasks\" title=\"\">Example 2: FreeRTOS Queues &#8211; Sharing Data Between Three Tasks<\/a><\/li>\n\n\n\n<li><a href=\"#data-structure\" title=\"\">Example 3: Display Sensor Data on a Screen (Sharing a Data Structure)<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"freertos-communication-between-tasks\">FreeRTOS Communication Between Tasks<\/h2>\n\n\n\n<p>In FreeRTOS there are different ways for inter-task communication and synchronization of data between tasks, suited for different purposes.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Queues<\/strong>: allow tasks to send and receive data, like sensor readings, button states, or other data, as we&#8217;ll see in the examples covered in this tutorial. Here we&#8217;ll focus on FreeRTOS queues. <\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Semaphores <\/strong>are like signaling tools in FreeRTOS used to coordinate tasks. They are often used to indicate that an event has occurred or a resource is ready. They don\u2019t carry data, just a count (or flag) to trigger actions after something has happened. We&#8217;ll cover this in a future tutorial.<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Mutexes<\/strong> (mutual exclusions) are used to protect shared resources by allowing only one task to access them at a time. This prevents conflicts in concurrent operations that need to access the same data. Unlike queues, mutexes focus on resource access rather than data transfer. We&#8217;ll cover this in a future tutorial.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"freertos-queues\">What are FreeRTOS Queues?<\/h2>\n\n\n\n<p>FreeRTOS queues are thread-safe data structures that allow tasks to send and receive data for synchronized communication in a multitasking environment.<\/p>\n\n\n\n<p>They ensure that data is passed safely between tasks without conflicts or data loss.<\/p>\n\n\n\n<p>Queues are especially useful when one task needs to send data and another task needs to handle it later, like a sensor task sending readings to a logging task or to be processed to display on a screen. This way, each task can run at its own speed without interfering with the other.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"queue-basics\">FreeRTOS Queue Basics<\/h2>\n\n\n\n<p>Here are some basic concepts about creating and handling queues on your Arduino IDE code for the ESP32:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Creating a Queue<\/h3>\n\n\n\n<p>Use the <span class=\"rnthl rntliteral\">xQueueCreate(size, item_size)<\/span> to create a queue\u2014<span class=\"rnthl rntliteral\">size<\/span> corresponds to the number of items that can be on the queue and <span class=\"rnthl rntliteral\">item_size<\/span> is the bytes size of heap allocated for each item on the queue.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Sending Data to a Queue<\/h3>\n\n\n\n<p>To send data to a queue use the <span class=\"rnthl rntliteral\">xQueueSend()<\/span> to add data to the queue. Or use <span class=\"rnthl rntliteral\">xQueueSendFromISR()<\/span> if sending the data from an ISR (interrupt service routine).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Receive Data from a Queue<\/h3>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">xQueueReceive()<\/span> function reads data from the queue, if available.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"led-brightness\">Example 1: Using Queues to Control LED Brightness<\/h2>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"750\" height=\"422\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/07\/ESP3w-with-an-LED-and-potentiometer.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 with an LED and a Potentiometer\" class=\"wp-image-174088\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/07\/ESP3w-with-an-LED-and-potentiometer.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/07\/ESP3w-with-an-LED-and-potentiometer.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p>In this example, we&#8217;ll create two tasks. One task will send data to a queue. The other task will read data from the queue.<\/p>\n\n\n\n<p>We&#8217;ll control the LED brightness using a potentiometer. This is a basic example, you&#8217;ve probably seen before, to learn about <a href=\"https:\/\/randomnerdtutorials.com\/esp32-adc-analog-read-arduino-ide\/\" title=\"\">analog reading<\/a> and <a href=\"https:\/\/randomnerdtutorials.com\/esp32-pwm-arduino-ide\/\" title=\"\">PWM<\/a>. In this case, we&#8217;ll use that basic example as a starting point to explain queues.<\/p>\n\n\n\n<p>We&#8217;ll create two tasks with the following names:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><span class=\"rnthl rntliteral\">potTask<\/span>: reads the value from the potentiometer and sends it to a queue.<\/li>\n\n\n\n<li><span class=\"rnthl rntliteral\">LEDBrightnessTask<\/span>: checks if there are values to receive from the queue and adjusts the LED brightness accordingly.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Parts Required<\/h3>\n\n\n\n<p>For this project, you need the following parts:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/esp32-dev-board-wi-fi-bluetooth\/\" target=\"_blank\" rel=\"noreferrer noopener\">ESP32 Board<\/a> of your choice&nbsp;\u2013 read&nbsp;<a href=\"https:\/\/makeradvisor.com\/esp32-development-boards-review-comparison\/\" target=\"_blank\" rel=\"noreferrer noopener\">Best ESP32 Development Boards<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/3mm-5mm-leds-kit-storage-box\/\" target=\"_blank\" rel=\"noopener\" title=\"\">LED<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/resistors-kits\/\" target=\"_blank\" rel=\"noopener\" title=\"\">220 Ohm resistor<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/potentiometer-assortment-kit\/\" target=\"_blank\" rel=\"noopener\" title=\"\">Potentiometer<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/mb-102-solderless-breadboard-830-points\/\" target=\"_blank\" rel=\"noreferrer noopener\">Breadboard<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/jumper-wires-kit-120-pieces\/\" target=\"_blank\" rel=\"noreferrer noopener\">Jumper wires<\/a><\/li>\n<\/ul>\n\n\n<p>You can use the preceding links or go directly to <a href=\"https:\/\/makeradvisor.com\/tools\/?utm_source=rnt&utm_medium=post&utm_campaign=post\" target=\"_blank\">MakerAdvisor.com\/tools<\/a> to find all the parts for your projects at the best price!<\/p><p style=\"text-align:center;\"><a href=\"https:\/\/makeradvisor.com\/tools\/?utm_source=rnt&utm_medium=post&utm_campaign=post\" target=\"_blank\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2017\/10\/header-200.png?w=1200&#038;quality=100&#038;strip=all&#038;ssl=1\"><\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Wiring the Circuit<\/h3>\n\n\n\n<p>For this example, wire an LED and a potentiometer to your ESP32 board. We&#8217;re connecting the LED to GPIO 2 and the potentiometer to GPIO 15.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"976\" height=\"708\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/07\/ESP32-connected-to-an-LED-and-potentiometer-edited.png?resize=976%2C708&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Connected to an LED and a potentiometer\" class=\"wp-image-174020\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/07\/ESP32-connected-to-an-LED-and-potentiometer-edited.png?w=976&amp;quality=100&amp;strip=all&amp;ssl=1 976w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/07\/ESP32-connected-to-an-LED-and-potentiometer-edited.png?resize=300%2C218&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/07\/ESP32-connected-to-an-LED-and-potentiometer-edited.png?resize=768%2C557&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 976px) 100vw, 976px\" \/><\/figure><\/div>\n\n\n<h3 class=\"wp-block-heading\">Code &#8211; Control LED Brightness (Queues Basic Example)<\/h3>\n\n\n\n<p>The following code creates two tasks. One reads the values from the potentiometer and sends them to a queue. The other task reads the values from the queue and controls the LED brightness accordingly.<\/p>\n\n\n\n<p>You can copy the following code to the Arduino IDE and upload it to your board.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-c\">\/*\n  Rui Santos &amp; Sara Santos - Random Nerd Tutorials\n  Complete project details at https:\/\/RandomNerdTutorials.com\/esp32-freertos-queues-inter-task-arduino\/\n  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.\n  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n*\/\n#define POT_PIN 15 \n#define LED_PIN 2   \n#define PWM_FREQ 5000\n#define PWM_RESOLUTION 12  \/\/ 12-bit (0\u20134095)\n#define QUEUE_SIZE 5\n\n\/\/ Create an handle for the queue\nQueueHandle_t potQueue = NULL;\n\nvoid potTask(void *parameter) {\n  for (;;) {\n    uint16_t potValue = analogRead(POT_PIN);  \/\/ Read 0\u20134095\n    xQueueSend(potQueue, &amp;potValue, portMAX_DELAY);  \/\/ Send to queue\n    Serial.printf(&quot;potTask: Sent pot value %u\\n&quot;, potValue);\n    vTaskDelay(100 \/ portTICK_PERIOD_MS);  \/\/ 100ms\n  }\n}\n\nvoid LEDBrightnessTask(void *parameter) {\n  for (;;) {\n    uint16_t potValue;\n    if (xQueueReceive(potQueue, &amp;potValue, portMAX_DELAY)) {\n      uint16_t brightness = potValue;\n      ledcWrite(LED_PIN, brightness);\n      Serial.printf(&quot;LEDBrightnessTask: Set brightness %u\\n&quot;, brightness);\n    }\n  }\n}\n\nvoid setup() {\n  Serial.begin(115200);\n\n  \/\/ Setup PWM for LED\n  ledcAttach(LED_PIN, PWM_FREQ, PWM_RESOLUTION);\n\n  \/\/ Create queue (5 items, each uint16_t)\n  potQueue = xQueueCreate(QUEUE_SIZE, sizeof(uint16_t));\n  if (potQueue == NULL) {\n    Serial.println(&quot;Failed to create queue!&quot;);\n    while (1);\n  }\n\n  \/\/ Create tasks\n  xTaskCreatePinnedToCore(\n    potTask,\n    &quot;potTask&quot;,\n    3000,  \/\/ Task stack\n    NULL,\n    1,\n    NULL,\n    1  \/\/ Core 1\n  );\n\n  xTaskCreatePinnedToCore(\n    LEDBrightnessTask,\n    &quot;LEDBrightnessTask&quot;,\n    3000,\n    NULL,\n    1,\n    NULL,\n    1\n  );\n}\n\nvoid loop() {\n  \/\/ Empty\n}\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/ESP32\/FreeRTOS\/Basic_Queue_Example.ino\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How Does the Code Work?<\/h3>\n\n\n\n<p>Let&#8217;s take a look at the code to see how it works.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Define the LED and Potentiometer GPIOs<\/h4>\n\n\n\n<p>First define the GPIO pins for the LED and for the potentiometer.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#define POT_PIN 15\n#define LED_PIN 2   <\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">PWM Properties<\/h4>\n\n\n\n<p>Then, define the PWM frequency and resolution to adjust the LED brightness. We&#8217;re setting 12-bit resolution (the same default resolution for the analog reading).<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#define PWM_FREQ 5000\n#define PWM_RESOLUTION 12  \/\/ 12-bit (0\u20134095)<\/code><\/pre>\n\n\n\n<p>If you&#8217;re new to PWM with the ESP32, check this tutorial to learn more: <a href=\"https:\/\/randomnerdtutorials.com\/esp32-pwm-arduino-ide\/\" title=\"\">ESP32 PWM with Arduino IDE (Analog Output)<\/a>.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">FreeRTOS Queue Size<\/h4>\n\n\n\n<p>Define the size of the FreeRTOS queue. This is the number of items that can the queue can hold. In this case, we&#8217;re setting it to 5.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#define QUEUE_SIZE 5<\/code><\/pre>\n\n\n\n<p>In our case, this is a good estimate because the items sent to the queue will be almost imediately consumed by the other task.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Queue Handle<\/h4>\n\n\n\n<p>Create an handle for the queue. This is how we&#8217;ll refer to our queue throughout our code. We&#8217;ll refer to the queue as <span class=\"rnthl rntliteral\">potQueue<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Create an handle for the queue\nQueueHandle_t potQueue = NULL;<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">potTask Function<\/h4>\n\n\n\n<p>Create a function for the pontentiometer task: <span class=\"rnthl rntliteral\">potTask<\/span>. This is the task that will read from the pontentiometer.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void potTask(void *parameter) {\n  for (;;) {\n    uint16_t potValue = analogRead(POT_PIN);  \/\/ Read 0\u20134095\n    xQueueSend(potQueue, &amp;potValue, portMAX_DELAY);  \/\/ Send to queue\n    Serial.printf(\"potTask: Sent pot value %u\\n\", potValue);\n    vTaskDelay(100 \/ portTICK_PERIOD_MS);  \/\/ 100ms\n  }\n}<\/code><\/pre>\n\n\n\n<p>We start by reading the value from the potentiometer and save it in a <span class=\"rnthl rntliteral\">uint16_t<\/span> type of variable called <span class=\"rnthl rntliteral\">potValue<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>uint16_t potValue = analogRead(POT_PIN);  \/\/ Read 0\u20134095<\/code><\/pre>\n\n\n\n<p>To learn more about reading analog values with the ESP32, check out this tutorial: <a href=\"https:\/\/randomnerdtutorials.com\/esp32-adc-analog-read-arduino-ide\/\">ESP32 ADC \u2013 Read Analog Values with Arduino IDE<\/a>.<\/p>\n\n\n\n<h5 class=\"wp-block-heading\"><strong>Send an Item to the Queue<\/strong><\/h5>\n\n\n\n<p>Then, we&#8217;ll use the <span class=\"rnthl rntliteral\">xQueueSend()<\/span> function to send an item to the queue. We&#8217;re sending the <span class=\"rnthl rntliteral\">potValue<\/span> to the <span class=\"rnthl rntliteral\">potQueue<\/span> as follows.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>xQueueSend(potQueue, &amp;potValue, portMAX_DELAY);  \/\/ Send to queue<\/code><\/pre>\n\n\n\n<p>The last parameter, <span class=\"rnthl rntliteral\">portMAX_DELAY<\/span> means that the task will wait indefinitely until there is space in the queue for this new item. If you don&#8217;t want it to wait, and want to return immmediately, pass <span class=\"rnthl rntliteral\">0<\/span> instead.<\/p>\n\n\n\n<h5 class=\"wp-block-heading\"><strong>vTaskDelay<\/strong><\/h5>\n\n\n\n<p>Then, we wait 100 milliseconds between each reading.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>vTaskDelay(100 \/ portTICK_PERIOD_MS);  \/\/ 100ms<\/code><\/pre>\n\n\n\n<p>In FreeRTOS tasks, we must use the <span class=\"rnthl rntliteral\">vTaskDelay()<\/span> function instead of the usual <span class=\"rnthl rntliteral\">delay()<\/span> arduino function. It accepts as argument the number of ticks to wait. In case of the ESP32, one tick corresponds to 1ms=<span class=\"rnthl rntliteral\">portTICK_PERIOD_MS<\/span>.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">LEDBrightnessTask<\/h4>\n\n\n\n<p>The following lines create the function for the task that controls the LED brightness. It&#8217;s called <span class=\"rnthl rntliteral\">LEDBrightnessTask<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void LEDBrightnessTask(void *parameter) {\n  for (;;) {\n    uint16_t potValue;\n    if (xQueueReceive(potQueue, &amp;potValue, portMAX_DELAY)) {\n      uint16_t brightness = potValue;\n      ledcWrite(LED_PIN, brightness);\n      Serial.printf(\"LEDBrightnessTask: Set brightness %u\\n\", brightness);\n    }\n  }\n}<\/code><\/pre>\n\n\n\n<p>We create a local variable called <span class=\"rnthl rntliteral\">potValue<\/span> that will receive the values in the queue.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>uint16_t potValue;<\/code><\/pre>\n\n\n\n<h5 class=\"wp-block-heading\"><strong>Get Values From the Queue<\/strong><\/h5>\n\n\n\n<p>To get values from the queue we can use the <span class=\"rnthl rntliteral\">xQueueReceive()<\/span> function. Pass the queue handle as an argument, a pointer to the variable where the value should be saved and whether to wait for an item to be available (<span class=\"rnthl rntliteral\">portMAX_DELAY<\/span>) or to return immediately (pass <span class=\"rnthl rntliteral\">0<\/span>).<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>if (xQueueReceive(potQueue, &amp;potValue, portMAX_DELAY)) {<\/code><\/pre>\n\n\n\n<h5 class=\"wp-block-heading\"><strong>Control the LED Brightness<\/strong><\/h5>\n\n\n\n<p>Because we&#8217;re controlling PWM with 12-bit resolution and using the default resolution for PWM (12-bit), the <span class=\"rnthl rntliteral\">brightness<\/span> will the be the same as the <span class=\"rnthl rntliteral\">potValue<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>uint16_t brightness = potValue;<\/code><\/pre>\n\n\n\n<p>Finally, we can use the <span class=\"rnthl rntliteral\">ledcWrite()<\/span> function to adjust the brightness of the LED.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>ledcWrite(LED_PIN, brightness);<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"> setup()<\/h4>\n\n\n\n<p>In the <span class=\"rnthl rntliteral\">setup()<\/span>, initialize the Serial Monitor at a baud rate of 115200.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>Serial.begin(115200);<\/code><\/pre>\n\n\n\n<p>Set up the PWM properties.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>ledcAttach(LED_PIN, PWM_FREQ, PWM_RESOLUTION);<\/code><\/pre>\n\n\n\n<h5 class=\"wp-block-heading\"><strong>Creating the Queue<\/strong><\/h5>\n\n\n\n<p>Create the actual queue using the <span class=\"rnthl rntliteral\">xQueueCreate()<\/span> function. This accepts as argument the queue size and the size of each item in bytes. Since we&#8217;re storing <span class=\"rnthl rntliteral\">uint16_t<\/span> variables, we&#8217;re passing the size of <span class=\"rnthl rntliteral\">uint16_t<\/span>, which is 2 bytes (16 bits).<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Create queue (5 items, each uint16_t)\npotQueue = xQueueCreate(QUEUE_SIZE, sizeof(uint16_t));\nif (potQueue == NULL) {\n  Serial.println(\"Failed to create queue!\");\n  while (1);\n}<\/code><\/pre>\n\n\n\n<h5 class=\"wp-block-heading\"><strong>Creating the Tasks<\/strong><\/h5>\n\n\n\n<p>Then, create the tasks that handle the potentiometer and control the LED brightness. We&#8217;re assigning both tasks to core 1. <\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Create tasks\nxTaskCreatePinnedToCore(\n  potTask,\n  \"potTask\",\n  3000,  \/\/ Task stack\n  NULL,\n  1,\n  NULL,\n  1  \/\/ Core 1\n);\n\nxTaskCreatePinnedToCore(\n  LEDBrightnessTask,\n  \"LEDBrightnessTask\",\n  3000,\n  NULL,\n  1,\n  NULL,\n  1\n);<\/code><\/pre>\n\n\n\n<p>We covered how to create tasks in this previous tutorial: <a href=\"https:\/\/randomnerdtutorials.com\/esp32-freertos-arduino-tasks\/\">ESP32 with FreeRTOS (Arduino IDE) \u2013 Getting Started: Create Tasks<\/a><\/p>\n\n\n\n<h4 class=\"wp-block-heading\">loop()<\/h4>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">loop()<\/span> is empty because FreeRTOS handles the tasks.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void loop() {\n  \/\/ Empty\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Demonstration<\/h3>\n\n\n\n<p>Upload the code to your board. Press the onboard RST button, so that the ESP32 starts running the code.<\/p>\n\n\n\n<p>Then, open the Serial Monitor at a baud rate of 115200. You should get something similar.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"712\" height=\"375\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/07\/ESP32-PWM-pot-FreeRTOS-tasks-serial-monitor.png?resize=712%2C375&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 freertos tasks with queues - demonstration in serial monitor\" class=\"wp-image-174034\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/07\/ESP32-PWM-pot-FreeRTOS-tasks-serial-monitor.png?w=712&amp;quality=100&amp;strip=all&amp;ssl=1 712w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/07\/ESP32-PWM-pot-FreeRTOS-tasks-serial-monitor.png?resize=300%2C158&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 712px) 100vw, 712px\" \/><\/figure><\/div>\n\n\n<p>Rotate the potentiometer and see the LED brightness increase and decrease accordingly.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"422\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/07\/ESP32-control-LED-brightness-with-potentiometer.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Control LED brightness with pontentiometer\" class=\"wp-image-174089\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/07\/ESP32-control-LED-brightness-with-potentiometer.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/07\/ESP32-control-LED-brightness-with-potentiometer.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"three-tasks\">Example 2: FreeRTOS Queues &#8211; Sharing Data Between Three Tasks<\/h2>\n\n\n\n<p>Data can be shared between multiple FreeRTOS tasks. In the previous example, we passed data from one task to another. But we can pass data to as many tasks as we want.<\/p>\n\n\n\n<p>This example is a modification of the previous project, with the addition of a third task. This third task will be responsible for retrieving the potentiometer values from the queue and displaying the values along with a timestamp in the Serial Monitor. I also removed all Serial prints from the other tasks.<\/p>\n\n\n\n<p>This is a simple example that shows how you can use queues to share data between multiple tasks.<\/p>\n\n\n\n<p>If we want multiple tasks to receive the same data, we need to feed two (or more) separate queues with the same values. Then, each task will retrieve the data from its own queue. We need to do this because in FreeRTOS a queue item can only be removed once, meaning only one task can receive each value from a single queue.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Wiring the Circuit<\/h3>\n\n\n\n<p>Keep the same circuit with an LED and a potentiometer from the previous example.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Code: FreeRTOS Queues &#8211; Three Tasks<\/h3>\n\n\n\n<p>Copy the following code to the Arduino IDE.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-c\">\/*\n  Rui Santos &amp; Sara Santos - Random Nerd Tutorials\n  Complete project details at https:\/\/RandomNerdTutorials.com\/esp32-freertos-queues-inter-task-arduino\/\n  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.\n  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n*\/\n#define POT_PIN 15 \n#define LED_PIN 2   \n#define PWM_FREQ 5000\n#define PWM_RESOLUTION 12  \/\/ 12-bit (0\u20134095)\n#define QUEUE_SIZE 5\n\nQueueHandle_t potQueue = NULL;\nQueueHandle_t sMonitorQueue = NULL;\n\nvoid SensorTask(void *parameter) {\n  for (;;) {\n    uint16_t potValue = analogRead(POT_PIN);  \/\/ Read 0\u20134095\n    xQueueSend(potQueue, &amp;potValue, portMAX_DELAY);  \/\/ Send to queue\n    xQueueSend(sMonitorQueue, &amp;potValue, portMAX_DELAY);  \/\/ Send to queue\n    vTaskDelay(300 \/ portTICK_PERIOD_MS);  \/\/ 300ms\n  }\n}\n\nvoid LEDBrightnessTask(void *parameter) {\n  for (;;) {\n    uint16_t potValue;\n    if (xQueueReceive(potQueue, &amp;potValue, portMAX_DELAY)) {\n      uint16_t brightness = potValue;\n      ledcWrite(LED_PIN, brightness);\n    }\n  }\n}\n\nvoid SerialLoggerTask(void *parameter) {\n  for (;;) {\n    uint16_t potValue;\n    if (xQueueReceive(sMonitorQueue, &amp;potValue, portMAX_DELAY)) {\n      Serial.printf(&quot;SerialLoggerTask: Pot value %u at %lu ms\\n&quot;, potValue, millis());\n    }\n  }\n}\n\nvoid setup() {\n  Serial.begin(115200);\n\n  \/\/ Setup PWM for LED\n  ledcAttach(LED_PIN, PWM_FREQ, PWM_RESOLUTION);\n\n  \/\/ Create queue (5 items, each uint16_t)\n  potQueue = xQueueCreate(QUEUE_SIZE, sizeof(uint16_t));\n  if (potQueue == NULL) {\n    Serial.println(&quot;Failed to create queue!&quot;);\n    while (1);\n  }\n\n  \/\/ Create queue (5 items, each uint16_t)\n  sMonitorQueue = xQueueCreate(QUEUE_SIZE, sizeof(uint16_t));\n  if (sMonitorQueue == NULL) {\n    Serial.println(&quot;Failed to create queue!&quot;);\n    while (1);\n  }\n\n  \/\/ Create tasks with one parameter per line\n  xTaskCreatePinnedToCore(\n    SensorTask,             \/\/ Task function\n    &quot;SensorTask&quot;,           \/\/ Task name\n    3000,                   \/\/ Stack size (bytes)\n    NULL,                   \/\/ Task parameters\n    1,                      \/\/ Priority\n    NULL,                   \/\/ Task handle\n    1                       \/\/ Core ID\n  );\n\n  xTaskCreatePinnedToCore(\n    LEDBrightnessTask,      \/\/ Task function\n    &quot;LEDBrightnessTask&quot;,    \/\/ Task name\n    3000,                   \/\/ Stack size (bytes)\n    NULL,                   \/\/ Task parameters\n    1,                      \/\/ Priority\n    NULL,                   \/\/ Task handle\n    1                       \/\/ Core ID\n  );\n\n  xTaskCreatePinnedToCore(\n    SerialLoggerTask,       \/\/ Task function\n    &quot;SerialLoggerTask&quot;,     \/\/ Task name\n    3000,                   \/\/ Stack size (bytes)\n    NULL,                   \/\/ Task parameters\n    1,                      \/\/ Priority\n    NULL,                   \/\/ Task handle\n    1                       \/\/ Core ID\n  );\n}\n\nvoid loop() {\n  \/\/ Empty\n}\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/ESP32\/FreeRTOS\/Queue_with_Three_Tasks.ino\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How Does the Code Work?<\/h3>\n\n\n\n<p>This code is very similar to the previous example, but with an additional queue, and an additional task.<\/p>\n\n\n\n<p>Basically, we create another queue called <span class=\"rnthl rntliteral\">sMonitorQueue<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>QueueHandle_t potQueue = NULL;\nQueueHandle_t sMonitorQueue = NULL;<\/code><\/pre>\n\n\n\n<p>In the <span class=\"rnthl rntliteral\">SensorTask()<\/span>, we fed both queues with the potentiometer values.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>xQueueSend(potQueue, &amp;potValue, portMAX_DELAY);  \/\/ Send to queue\nxQueueSend(sMonitorQueue, &amp;potValue, portMAX_DELAY);  \/\/ Send to queue<\/code><\/pre>\n\n\n\n<p>We add an additional task, the <span class=\"rnthl rntliteral\">SerialLoggerTask()<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void SerialLoggerTask(void *parameter) {\n  for (;;) {\n    uint16_t potValue;\n    if (xQueueReceive(sMonitorQueue, &amp;potValue, portMAX_DELAY)) {\n      Serial.printf(\"SerialLoggerTask: Pot value %u at %lu ms\\n\", potValue, millis());\n    }\n  }\n}<\/code><\/pre>\n\n\n\n<p>This task gets the <span class=\"rnthl rntliteral\">potValue<\/span> from the <span class=\"rnthl rntliteral\">sMonitorQueue<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>if (xQueueReceive(sMonitorQueue, &amp;potValue, portMAX_DELAY)) {<\/code><\/pre>\n\n\n\n<p>And then, displays it in the Serial Monitor along with a timestamp.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>Serial.printf(\"SerialLoggerTask: Pot value %u at %lu ms\\n\", potValue, millis());<\/code><\/pre>\n\n\n\n<p>You also need to create this new task in the <span class=\"rnthl rntliteral\">setup()<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>xTaskCreatePinnedToCore(\n  SerialLoggerTask,       \/\/ Task function\n  \"SerialLoggerTask\",     \/\/ Task name\n  3000,                   \/\/ Stack size (bytes)\n  NULL,                   \/\/ Task parameters\n  1,                      \/\/ Priority\n  NULL,                   \/\/ Task handle\n  1                       \/\/ Core ID\n);<\/code><\/pre>\n\n\n\n<p>And also, the additional queue.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Create queue (5 items, each uint16_t)\n  sMonitorQueue = xQueueCreate(QUEUE_SIZE, sizeof(uint16_t));\n  if (sMonitorQueue== NULL) {\n    Serial.println(\"Failed to create queue!\");\n    while (1);\n  }<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Demonstration<\/h3>\n\n\n\n<p>The result will be similar to the previous example, but now you have the <span class=\"rnthl rntliteral\">SerialLoggerTask<\/span> displaying the values and the timestamp in the Serial Monitor.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"666\" height=\"374\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/07\/ESP32-Three-Tasks-FreeRTOS-Queues-Serial-Monitor.png?resize=666%2C374&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Esp32 with a freertos task that prints data to the Serial Monitor - demonstration\" class=\"wp-image-174037\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/07\/ESP32-Three-Tasks-FreeRTOS-Queues-Serial-Monitor.png?w=666&amp;quality=100&amp;strip=all&amp;ssl=1 666w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/07\/ESP32-Three-Tasks-FreeRTOS-Queues-Serial-Monitor.png?resize=300%2C168&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 666px) 100vw, 666px\" \/><\/figure><\/div>\n\n\n<p>This simple example is to demonstrate that you can pass data to as many tasks as you want with multiple queues.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"data-structure\">Example 3: Display Sensor Data on a Screen (Sharing a Data Structure)<\/h2>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"421\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/07\/ESP32-Display-BME280-Sensor-Readings-OLED-Display-FreeRTOS.jpg?resize=750%2C421&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Display Sensor REadings from a BME280 sensor on an OLED display\" class=\"wp-image-174090\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/07\/ESP32-Display-BME280-Sensor-Readings-OLED-Display-FreeRTOS.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/07\/ESP32-Display-BME280-Sensor-Readings-OLED-Display-FreeRTOS.jpg?resize=300%2C168&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p>In this example, we&#8217;ll display sensor readings from a BME280 on an OLED display using FreeRTOS tasks. The process is divided into two main tasks:<\/p>\n\n\n\n<p><strong>SensorTask<\/strong>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Reads temperature, humidity, and pressure from the BME280 sensor<\/li>\n\n\n\n<li>Sends the sensor data to a queue<\/li>\n<\/ul>\n\n\n\n<p><strong>DisplayTask<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Receives sensor data from the queue<\/li>\n\n\n\n<li>Displays the readings on the OLED screen<\/li>\n<\/ul>\n\n\n\n<p>The aim of this example is to demonstrate how to share a data structure containing multiple variables (temperature, humidity, and pressure) between tasks.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Parts Required<\/h3>\n\n\n\n<p>For this example, you need the following parts:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/esp32-dev-board-wi-fi-bluetooth\/\" target=\"_blank\" rel=\"noreferrer noopener\">ESP32 Board<\/a> of your choice&nbsp;\u2013 read&nbsp;<a href=\"https:\/\/makeradvisor.com\/esp32-development-boards-review-comparison\/\" target=\"_blank\" rel=\"noreferrer noopener\">Best ESP32 Development Boards<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/bme280-sensor-module\/\" target=\"_blank\" rel=\"noopener\" title=\"\">BME280 Sensor<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/oled-display-128x64-0-96-inch\/\" target=\"_blank\" rel=\"noopener\" title=\"\">SSD1306 OLED display<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/mb-102-solderless-breadboard-830-points\/\" target=\"_blank\" rel=\"noreferrer noopener\">Breadboard<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/jumper-wires-kit-120-pieces\/\" target=\"_blank\" rel=\"noreferrer noopener\">Jumper wires<\/a><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Wiring the Circuit<\/h3>\n\n\n\n<p>Wire the BME280 and the OLED display to the ESP32 default I2C pins.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"841\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/07\/ESP32-OLED-BME280_bb.jpg?resize=750%2C841&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 circuit with OLED Display and BME280 connected to the ESP32 default I2C pins\" class=\"wp-image-174100\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/07\/ESP32-OLED-BME280_bb.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/07\/ESP32-OLED-BME280_bb.jpg?resize=268%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 268w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p>You may also like reading: <a href=\"https:\/\/randomnerdtutorials.com\/esp32-i2c-communication-arduino-ide\/\">ESP32 I2C Communication: Set Pins, Multiple Bus Interfaces and Peripherals (Arduino IDE)<\/a>.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>BME280<\/strong><\/td><td><strong>ESP32<\/strong><\/td><\/tr><tr><td>VIN<\/td><td>3V3<\/td><\/tr><tr><td>GND<\/td><td>GND<\/td><\/tr><tr><td>SCL<\/td><td>GPIO 22<\/td><\/tr><tr><td>SDA<\/td><td>GPIO 21<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>OLED Display<\/strong><\/td><td><strong>ESP32<\/strong><\/td><\/tr><tr><td>VIN<\/td><td>3V3<\/td><\/tr><tr><td>GND<\/td><td>GND<\/td><\/tr><tr><td>SCL<\/td><td>GPIO 22<\/td><\/tr><tr><td>SDA<\/td><td>GPIO 21<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Code &#8211; Display Sensor Data on a Screen using FreeRTOS Queues<\/h3>\n\n\n\n<p>Copy the following code to the Arduino IDE.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-c\">\/*\n  Rui Santos &amp; Sara Santos - Random Nerd Tutorials\n  Complete project details at https:\/\/RandomNerdTutorials.com\/esp32-freertos-queues-inter-task-arduino\/\n  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.\n  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n*\/\n#include &lt;Arduino.h&gt;\n#include &lt;Wire.h&gt;\n#include &lt;Adafruit_BME280.h&gt;\n#include &lt;Adafruit_GFX.h&gt;\n#include &lt;Adafruit_SSD1306.h&gt;\n\n#define SCREEN_WIDTH 128\n#define SCREEN_HEIGHT 64\n#define OLED_ADDRESS 0x3C\n\n#define QUEUE_SIZE 5\n\nAdafruit_BME280 bme;\n\nAdafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &amp;Wire, -1);\n\nQueueHandle_t sensorQueue = NULL;\n\ntypedef struct {\n  float temperature;\n  float humidity;\n  float pressure;\n} SensorData;\n\nvoid SensorTask(void *parameter) {\n  if (!bme.begin(0x76)) {\n    Serial.println(&quot;Could not find a valid BME280 sensor, check wiring!&quot;);\n    while (1);\n  }\n  for (;;) {\n    SensorData data;\n    data.temperature = bme.readTemperature();  \n    data.humidity = bme.readHumidity();        \n    data.pressure = bme.readPressure() \/ 100.0F;  \n    xQueueSend(sensorQueue, &amp;data, portMAX_DELAY);\n    Serial.print(&quot;SensorTask: Sent Temp=&quot;);\n    Serial.print(data.temperature, 1);\n    Serial.print(&quot;\u00b0C, Hum=&quot;);\n    Serial.print(data.humidity, 1);\n    Serial.print(&quot;%, Pres=&quot;);\n    Serial.print(data.pressure, 1);\n    Serial.println(&quot;hPa&quot;);\n    vTaskDelay(2000 \/ portTICK_PERIOD_MS);  \/\/ 2s\n  }\n}\n\nvoid DisplayTask(void *parameter) {\n  if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDRESS)) {\n    Serial.println(&quot;OLED init failed!&quot;);\n    while (1);\n  }\n  display.clearDisplay();\n  display.setTextSize(1); \n  display.setTextColor(SSD1306_WHITE);\n\n  for (;;) {\n    SensorData data;\n    if (xQueueReceive(sensorQueue, &amp;data, portMAX_DELAY)) {\n\n      \/\/ Display on OLED\n      display.clearDisplay();\n      display.setCursor(0, 0);\n      display.print(&quot;Temperature: &quot;);\n      display.print(data.temperature, 1);\n      display.print(&quot; &quot;);\n      display.cp437(true);\n      display.write(167);\n      display.println(&quot;C&quot;);\n      display.setCursor(0, 20);\n      display.print(&quot;Humidity: &quot;);\n      display.print(data.humidity, 1);\n      display.println(&quot; %&quot;);\n      display.setCursor(0, 40);\n      display.print(&quot;Pressure: &quot;);\n      display.print(data.pressure, 1);\n      display.println(&quot; hPa&quot;);\n      display.display();\n    }\n  }\n}\n\nvoid setup() {\n  Serial.begin(115200);\n  \n  \/\/ Starts I2C on the board default's  I2C pins\n  Wire.begin();\n\n  \/\/ Create queue\n  sensorQueue = xQueueCreate(QUEUE_SIZE, sizeof(SensorData));\n  if (sensorQueue == NULL) {\n    Serial.println(&quot;Failed to create queue!&quot;);\n    while (1);\n  }\n\n  \/\/ Create tasks\n  xTaskCreatePinnedToCore(\n    SensorTask,             \/\/ Task function\n    &quot;SensorTask&quot;,           \/\/ Task name\n    4000,                   \/\/ Stack size (bytes)\n    NULL,                   \/\/ Task parameters\n    1,                      \/\/ Priority\n    NULL,                   \/\/ Task handle\n    1                       \/\/ Core ID\n  );\n\n  xTaskCreatePinnedToCore(\n    DisplayTask,            \/\/ Task function\n    &quot;DisplayTask&quot;,          \/\/ Task name\n    4000,                   \/\/ Stack size (bytes)\n    NULL,                   \/\/ Task parameters\n    1,                      \/\/ Priority\n    NULL,                   \/\/ Task handle\n    1                       \/\/ Core ID\n  );\n}\n\nvoid loop() {\n  \/\/ Empty\n}\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/ESP32\/FreeRTOS\/Queue_BME280_Data_Structure.ino\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How Does the Code Work?<\/h3>\n\n\n\n<p>At this point, you should be familiar with most of the code.<\/p>\n\n\n\n<p>To send multiple variables to the queue, we create a structure that will contain temperature, humidity, and pressure. We call that type of structure <span class=\"rnthl rntliteral\">SensorData<\/span>.<\/p>\n\n\n\n<p>Alternatively, you can also use JSON objects, but I find structures easier to use for this scenario.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>typedef struct {\n  float temperature;\n  float humidity;\n  float pressure;\n} SensorData;<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">SensorTask<\/span> function is responsible for retrieving the current sensor readings and sending them to the queue. We create a variable called <span class=\"rnthl rntliteral\">data<\/span>, which is a data structure of type <span class=\"rnthl rntliteral\">SensorData<\/span> (the one we created previously).<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>SensorData data;<\/code><\/pre>\n\n\n\n<p>Then, we add values to the <span class=\"rnthl rntliteral\">data<\/span> structure as follows.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>data.temperature = bme.readTemperature();  \ndata.humidity = bme.readHumidity();        \ndata.pressure = bme.readPressure() \/ 100.0F;  <\/code><\/pre>\n\n\n\n<p>Now that we have populated the <span class=\"rnthl rntliteral\">data<\/span> structure with the latest sensor readings, we can send it to the queue, just as we did in the previous examples, using the <span class=\"rnthl rntliteral\">xQueueSend()<\/span> function.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>xQueueSend(sensorQueue, &amp;data, portMAX_DELAY);<\/code><\/pre>\n\n\n\n<p>In the <span class=\"rnthl rntliteral\">DisplayTask<\/span> function, we get the data from the queue and display it on the OLED screen.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void DisplayTask(void *parameter) {\n  if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDRESS)) {\n    Serial.println(\"OLED init failed!\");\n    while (1);\n  }\n  display.clearDisplay();\n  display.setTextSize(1); \n  display.setTextColor(SSD1306_WHITE);\n\n  for (;;) {\n    SensorData data;\n    if (xQueueReceive(sensorQueue, &amp;data, portMAX_DELAY)) {\n\n      \/\/ Display on OLED\n      display.clearDisplay();\n      display.setCursor(0, 0);\n      display.print(\"Temperature: \");\n      display.print(data.temperature, 1);\n      display.print(\" \");\n      display.cp437(true);\n      display.write(167);\n      display.println(\"C\");\n      display.setCursor(0, 20);\n      display.print(\"Humidity: \");\n      display.print(data.humidity, 1);\n      display.println(\" %\");\n      display.setCursor(0, 40);\n      display.print(\"Pressure: \");\n      display.print(data.pressure, 1);\n      display.println(\" hPa\");\n      display.display();\n    }\n  }\n}<\/code><\/pre>\n\n\n\n<p>As in the previous examples, in the <span class=\"rnthl rntliteral\">setup()<\/span>, we create the queue and the tasks, and assign them to an ESP32 core.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void setup() {\n  Serial.begin(115200);\n  \n  \/\/ Starts I2C on the board default's  I2C pins\n  Wire.begin();\n\n  \/\/ Create queue\n  sensorQueue = xQueueCreate(QUEUE_SIZE, sizeof(SensorData));\n  if (sensorQueue == NULL) {\n    Serial.println(\"Failed to create queue!\");\n    while (1);\n  }\n\n  \/\/ Create tasks\n  xTaskCreatePinnedToCore(\n    SensorTask,             \/\/ Task function\n    \"SensorTask\",           \/\/ Task name\n    4000,                   \/\/ Stack size (bytes)\n    NULL,                   \/\/ Task parameters\n    1,                      \/\/ Priority\n    NULL,                   \/\/ Task handle\n    1                       \/\/ Core ID\n  );\n\n  xTaskCreatePinnedToCore(\n    DisplayTask,            \/\/ Task function\n    \"DisplayTask\",          \/\/ Task name\n    4000,                   \/\/ Stack size (bytes)\n    NULL,                   \/\/ Task parameters\n    1,                      \/\/ Priority\n    NULL,                   \/\/ Task handle\n    1                       \/\/ Core ID\n  );\n}<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">loop()<\/span> is empty because FreeRTOS handles the tasks.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void loop() {\n  \/\/ Empty\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Demonstration<\/h3>\n\n\n\n<p>Upload the previous code to your ESP32 board. After uploading, press the onboard RST button so that the board starts running the code.<\/p>\n\n\n\n<p>Open the Serial Monitor at a baud rate of 115200. Every two seconds, it will display updated sensor readings.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"666\" height=\"375\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/07\/ESP32-Sensortask-FreeRTOS-serial-monitor.png?resize=666%2C375&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Sensor Task (FreeRTOS) displayed on the serial monitor every two seconds\" class=\"wp-image-174087\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/07\/ESP32-Sensortask-FreeRTOS-serial-monitor.png?w=666&amp;quality=100&amp;strip=all&amp;ssl=1 666w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/07\/ESP32-Sensortask-FreeRTOS-serial-monitor.png?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 666px) 100vw, 666px\" \/><\/figure><\/div>\n\n\n<p>The screen is updated at the same rate as new readings are sent to the queue.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"421\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/07\/ESP32-Display-Sensor-Readings-OLED-Display.jpg?resize=750%2C421&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Display BME280 Sensor Readings on OLED Display using FreeRTOS queues\" class=\"wp-image-174093\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/07\/ESP32-Display-Sensor-Readings-OLED-Display.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/07\/ESP32-Display-Sensor-Readings-OLED-Display.jpg?resize=300%2C168&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\">Wrapping Up<\/h2>\n\n\n\n<p>In this tutorial, you learned how to use FreeRTOS queues to pass data from one task to the other in a safe way. We&#8217;ve shown you three different examples that demonstrate how easy it is to use queues to communicate between tasks. After understanding those basic examples, the idea is to apply this concept to more complex projects, where accessing variables&#8217; values simultaneously might be critical to the program.<\/p>\n\n\n\n<p>We hope you&#8217;ve found this tutorial useful. We have more tutorials on this FreeRTOS series that you may like:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-freertos-arduino-tasks\/\">ESP32 with FreeRTOS (Arduino IDE)\u2014Getting Started Guide: <strong>Creating Tasks<\/strong><\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-freertos-semaphores-arduino\/\">ESP32 with FreeRTOS: Getting Started with <strong>Semaphores <\/strong>(Arduino IDE)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-freertos-software-timers-interrupts\/\" title=\"\">ESP32 with FreeRTOS: <strong>Software Timers\/Timer Interrupts<\/strong> (Arduino IDE)<\/a><\/li>\n<\/ul>\n\n\n\n<p>Learn more about the ESP32 with our resources:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/learn-esp32-with-arduino-ide\/\" title=\"\">Learn ESP32 with Arduino IDE (eBook)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/projects-esp32\/\" title=\"\">All our ESP32 Projects and Guides<\/a><\/li>\n<\/ul>\n\n\n\n<p>Thanks for reading.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this guide, you&#8217;ll learn how to use FreeRTOS queues for safe and efficient communication between tasks on the ESP32, using the Arduino IDE. Queues allow you to exchange data &#8230; <\/p>\n<p class=\"read-more-container\"><a title=\"ESP32 with FreeRTOS Queues: Inter-Task Communication (Arduino IDE)\" class=\"read-more button\" href=\"https:\/\/randomnerdtutorials.com\/esp32-freertos-queues-inter-task-arduino\/#more-173794\" aria-label=\"Read more about ESP32 with FreeRTOS Queues: Inter-Task Communication (Arduino IDE)\">CONTINUE READING \u00bb<\/a><\/p>\n","protected":false},"author":5,"featured_media":174099,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[276,281,277,299,264],"tags":[],"class_list":["post-173794","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-esp32","category-esp32-project","category-esp32-arduino-ide","category-0-esp32","category-project"],"aioseo_notices":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/07\/ESP32-FreeRTOS-queues.jpg?fit=1920%2C1080&quality=100&strip=all&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/173794","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/comments?post=173794"}],"version-history":[{"count":21,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/173794\/revisions"}],"predecessor-version":[{"id":183531,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/173794\/revisions\/183531"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media\/174099"}],"wp:attachment":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media?parent=173794"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/categories?post=173794"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/tags?post=173794"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}