ESP 模塊因其 Wi-Fi 功能而廣受歡迎,例如ESP8266、ESP-12E等。這些都是具有 Wi-Fi 功能的強大微控制器模塊。還有一個 ESP 模塊,它比以前的 ESP 模塊更強大、更通用——它的名字是ESP32。它具有藍牙和 Wi-Fi 連接,我們已經解釋了 ESP32 的 BLE 功能,并在許多物聯網項目中使用了 ESP32 。但很少有人知道ESP32 是雙核微控制器。
ESP32具有兩個 32 位 Tensilica Xtensa LX6 微處理器,這使其成為功能強大的雙核(core0 和 core1)微控制器。它有單核和雙核兩種變體。但雙核版本更受歡迎,因為沒有明顯的價格差異。
ESP32 可以使用 Arduino IDE、Espressif IDF、Lua RTOS 等進行編程。使用 Arduino IDE 進行編程時,代碼只能在 Core1 上運行,因為 Core0 已經針對射頻通信進行了編程。但這是本教程,我們將展示如何使用 ESP32的兩個內核同時執行兩個操作。這里的第一個任務是閃爍板載 LED,第二個任務是從 DHT11 傳感器獲取溫度數據。
讓我們首先看看多核處理器相對于單核的優勢。
多核處理器的優勢
當有兩個以上的進程同時工作時,多核處理器很有用。
由于工作分布在不同的內核之間,它的速度會提高,并且可以同時完成多個進程。
可以降低功耗,因為當任何內核處于空閑模式時,它都可以用來關閉當時未使用的外圍設備。
雙核處理器必須比單核處理器更少地在不同線程之間切換,因為它們可以一次處理兩個而不是一次處理一個。
ESP32 和 FreeRTOS
ESP32 板上已經安裝了 FreeRTOS 固件。FreeRTOS 是一個開源實時操作系統,在多任務處理中非常有用。RTOS 有助于管理資源和最大化系統性能。FreeRTOS 有許多用于不同目的的 API 函數,使用這些 API,我們可以創建任務并使它們在不同的內核上運行。
可以在此處找到 FreeRTOS API 的完整文檔。我們將嘗試在代碼中使用一些 API 來構建將在兩個內核上運行的多任務應用程序。
查找 ESP32 內核 ID
在這里,我們將使用Arduino IDE 將代碼上傳到 ESP32中。要知道運行代碼的Core ID,有一個API函數
xPortGetCoreID()
可以從void setup()和void loop()函數調用此函數,以了解運行這些函數的核心 ID。
您可以通過上傳以下草圖來測試此 API:
無效設置() { Serial.begin(115200); Serial.print("setup() 函數在核心上運行:"); Serial.println(xPortGetCoreID()); } void loop() { Serial.print("loop() 函數在核心上運行:"); Serial.println(xPortGetCoreID()); }
上傳上面的草圖后,打開串口監視器,你會發現這兩個功能都在 core1 上運行,如下圖所示。
從以上觀察可以得出結論,默認的 Arduino 草圖始終在 core1 上運行。
ESP32 雙核編程
Arduino IDE 支持 ESP32 的 FreeRTOS,FreeRTOS API 允許我們創建可以在兩個內核上獨立運行的任務。任務是在板上執行一些操作的代碼,例如閃爍的 LED、發送溫度等。
以下函數用于創建可以在兩個內核上運行的任務。在這個函數中,我們必須給出一些參數,比如優先級、核心 ID 等。
現在,按照以下步驟創建任務和任務功能。
1.首先在void setup函數中創建任務。在這里,我們將創建兩個任務,一個用于每 0.5 秒后閃爍 LED,另一個任務是每 2 秒后獲取溫度讀數。
xTaskCreatePinnedToCore() 函數有 7 個參數:
實現任務的函數名(task1)
任務的任何名稱(“task1”等)
以字為單位分配給任務的堆棧大小(1 個字=2 字節)
任務輸入參數(可以為NULL)
任務的優先級(0為最低優先級)
任務句柄(可以為 NULL)
任務將運行的核心 ID(0 或 1)
現在,通過在 xTaskCreatePinnedToCore() 函數中提供所有參數來創建用于閃爍 LED 的 Task1 。
xTaskCreatePinnedToCore(Task1code, "Task1", 10000, NULL, 1, NULL, 0);
同樣,為 Task2創建 Task2并在第 7個參數中設置 core id 1。
xTaskCreatePinnedToCore(Task2code, "Task2", 10000, NULL, 1, NULL, 1);
您可以根據任務的復雜性更改優先級和堆棧大小。
2. 現在,我們將實現Task1code和Task2code函數。這些函數包含所需任務的代碼。在我們的例子中,第一個任務將閃爍 LED,另一個任務將獲取溫度。因此,在 void setup 函數之外為每個任務創建兩個單獨的函數。
Task1code功能實現了 0.5 秒后閃爍板載 LED,如下所示。
void Task1code( void * parameter) { Serial.print("Task1 在核心上運行"); Serial.println(xPortGetCoreID()); for(;;) {//無限循環 digitalWrite(led, HIGH); 延遲(500); digitalWrite(led, LOW); 延遲(500); } }
同樣,實現獲取溫度的Task2code函數。
void Task2code( void * pvParameters ){ Serial.print("Task2 在核心上運行"); Serial.println(xPortGetCoreID()); for(;;){ 浮動 t = dht.readTemperature(); Serial.print("溫度:"); 序列號.print(t); 延遲(2000); } }
3. 這里的void 循環函數將保持為空。我們已經知道循環和設置函數在 core1 上運行,因此您也可以在void 循環函數中實現 core1 任務。
現在編碼部分已經結束,所以只需在工具菜單中選擇 ESP32 板,使用 Arduino IDE 上傳代碼。確保您已將 DHT11 傳感器連接到 ESP32 的引腳 D13。
現在可以在 Serial Monitor 或 Arduino IDE 上監控結果,如下所示:
通過使用 ESP32 的雙核同時運行多個任務,可以構建像實時系統這樣的復雜應用。
#include "DHT.h"
#define DHTPIN 13
#define DHTTYPE DHT11
const int led = 2;
DHT dht(DHTPIN, DHTTYPE);
無效設置() {
Serial.begin(115200);
pinMode(LED,輸出);
dht.begin();
xTaskCreatePinnedToCore(Task1code, "Task1", 10000, NULL, 1, NULL, 1);
延遲(500);
xTaskCreatePinnedToCore(Task1code, "Task1", 10000, NULL, 1, NULL, 0);
延遲(500);
}
void Task1code( void * pvParameters ){
Serial.print("Task1 在核心上運行");
Serial.println(xPortGetCoreID());
for(;;){
digitalWrite(led, HIGH);
延遲(300);
數字寫入(領導,低);
延遲(300);
}
}
void Task2code( void * pvParameters ){
Serial.print("Task2 在核心上運行");
Serial.println(xPortGetCoreID());
for(;;){
浮動 h = dht.readHumidity();
浮動 t = dht.readTemperature();
浮動 f = dht.readTemperature(true);
Serial.print("溫度:");
序列號.print(t);
Serial.print(" *C \n ");
if (isnan(h) || isnan(t) || isnan(f)) {
Serial.println("讀取 DHT 傳感器失敗!");
返回;
}
延遲(2000);
}
}
無效循環() {
}
-
微控制器
+關注
關注
48文章
7571瀏覽量
151631 -
編程
+關注
關注
88文章
3628瀏覽量
93814 -
Arduino
+關注
關注
188文章
6472瀏覽量
187346 -
ESP32
+關注
關注
18文章
971瀏覽量
17366
發布評論請先 登錄
相關推薦
評論