وقتی همزمان چند کار دارید (مثلاً چشمک زدن LED، خواندن سنسور و پاسخ به درخواستهای وب)، نوشتن همه در یک loop() ساده بهسرعت پیچیده میشود. در میکروپایتون این مشکل با uasyncio (کتابخانهٔ async/await) حل میشد؛ در Arduino-ESP32 معادل واقعی و حتی قدرتمندتر آن FreeRTOS است — سیستمعامل بلادرنگی که خودِ هستهٔ Arduino-ESP32 از قبل روی آن سوار شده و اجازه میدهد چند «Task» واقعاً بهصورت زمانبندیشده (نه فقط ظاهری) همزمان اجرا شوند.
ساخت چند Task با xTaskCreate
const int LED_PIN = 2;
void blinkTask(void* parameter) {
pinMode(LED_PIN, OUTPUT);
while (true) {
digitalWrite(LED_PIN, !digitalRead(LED_PIN));
vTaskDelay(500 / portTICK_PERIOD_MS); // معادل await asyncio.sleep_ms(500)
}
}
void sensorTask(void* parameter) {
int counter = 0;
while (true) {
counter++;
Serial.print("خواندن شمارهٔ ");
Serial.println(counter);
vTaskDelay(2000 / portTICK_PERIOD_MS);
}
}
void setup() {
Serial.begin(115200);
// نام Task، اندازهٔ پشته، پارامتر، اولویت، دستهٔ Task
xTaskCreate(blinkTask, "Blink", 2048, NULL, 1, NULL);
xTaskCreate(sensorTask, "Sensor", 2048, NULL, 1, NULL);
}
void loop() {
// خودِ loop() هم در واقع یک Task دیگر از FreeRTOS است؛
// میتواند خالی بماند یا کار سبک دیگری انجام دهد
vTaskDelay(1000 / portTICK_PERIOD_MS);
}نکتهٔ مهم: بهجای delay() معمولی که کل هستهٔ پردازنده را مسدود میکند، در داخل یک Task از vTaskDelay() استفاده میکنیم تا زمانبند FreeRTOS بتواند در همان لحظه Taskهای دیگر را اجرا کند — دقیقاً همان نقشی که await asyncio.sleep() در uasyncio بازی میکرد.
پروژهٔ پایانی: پنل کوچک خانهٔ هوشمند
در این پروژهٔ جمعبندی، مفاهیم فصلهای قبل را ترکیب میکنیم: خواندن سنسور DHT22 (فصل ۳)، نمایش وضعیت روی OLED (فصل ۴)، و اجرای همزمان وظایف با FreeRTOS Tasks.
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <DHT.h>
#define DHT_PIN 15
DHT dht(DHT_PIN, DHT22);
Adafruit_SSD1306 display(128, 64, &Wire, -1);
void readAndDisplayTask(void* parameter) {
while (true) {
float t = dht.readTemperature();
float h = dht.readHumidity();
if (!isnan(t) && !isnan(h)) {
display.clearDisplay();
display.setCursor(0, 10);
display.print("Dama: ");
display.print(t);
display.println("C");
display.setCursor(0, 30);
display.print("Rotoobat: ");
display.print(h);
display.println("%");
display.display();
}
vTaskDelay(2000 / portTICK_PERIOD_MS);
}
}
void setup() {
Wire.begin(21, 22);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
dht.begin();
xTaskCreate(readAndDisplayTask, "ReadDisplay", 4096, NULL, 1, NULL);
}
void loop() {
vTaskDelay(1000 / portTICK_PERIOD_MS);
}برای پروژهٔ پایانی، نمایشگر OLED (I2C روی SDA=21, SCL=22) و سنسور DHT22 (پایهٔ ۱۵) را در یک پروژهٔ خالی Arduino/ESP32 در Wokwi اضافه کنید.
ساخت پروژهٔ خالی Arduino/ESP32 در Wokwi ↗پروژهٔ پایانی: کد بالا را با بخش Wi-Fi/MQTT درس ۱۳ ترکیب کنید تا یک Task سوم (sendToCloudTask) هر ۱۰ ثانیه دادهٔ آخرین اندازهگیری را به بروکر MQTT ارسال کند؛ هر سه Task باید همزمان و بدون توقف یکدیگر اجرا شوند.