ESP模块因其Wi-Fi功能而广受欢迎,例如ESP8266,ESP-12E等。这些都是具有Wi-Fi功能的强大微控制器模块。还有一个ESP模块,它比以前的ESP模块更强大,更通用-其名称为ESP32。它具有蓝牙和Wi-Fi连接,我们已经介绍了ESP32的BLE功能,并在许多物联网项目中使用了ESP32。但是很少有人知道ESP32是双核微控制器。
ESP32有两个32位Tensilica Xtensa LX6微处理器,这使其成为功能强大的双核(core0和core1)微控制器。有单核和双核两种版本。但是双核版本更受欢迎,因为它们之间没有明显的价格差异。
可以使用Arduino IDE,Espressif IDF,Lua RTOS等对ESP32进行编程。使用Arduino IDE进行编程时,由于Core0已针对RF通信进行了编程,因此代码仅在Core1上运行。但是在本教程中,我们将展示如何使用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:
void setup(){ Serial.begin(115200); 在核心上运行的Serial.print(“ setup()函数:”); Serial.println(xPortGetCoreID()); } void loop(){ Serial.print(“ loop()function on core:”); Serial.println(xPortGetCoreID()); }
上传完上述草图后,打开“串行”监视器,您会发现两个功能都在core1上运行,如下所示。
从以上观察结果可以得出结论,默认的Arduino草图始终在core1上运行。
ESP32双核编程
Arduino IDE支持ESP32的FreeRTOS,而FreeRTOS API允许我们创建可以在两个内核上独立运行的任务。任务是一段在板上执行某些操作的代码,例如LED闪烁,发送温度等。
以下函数用于创建可以在两个内核上运行的任务。在此函数中,我们必须提供一些参数,例如优先级,核心ID等。
现在,按照以下步骤创建任务和任务功能。
1.首先,在 空白设置 功能中创建任务。在这里,我们将创建两个任务,一个任务是每0.5秒闪烁一次LED,另一任务是每2秒获取一次温度读数。
xTaskCreatePinnedToCore()函数采用7个参数:
- 实现任务的函数名称(task1)
- 赋予任务的任何名称(“ task1”等)
- 分配给任务的堆栈大小,以字为单位(1个字= 2字节)
- 任务输入参数(可以为NULL)
- 任务的优先级(0是最低优先级)
- 任务句柄(可以为NULL)
- 任务将运行的核心ID(0或1)
现在,通过在xTaskCreatePinnedToCore()函数中提供所有参数来创建Task1,以使指示灯闪烁。
xTaskCreatePinnedToCore(Task1code,“ Task1”,10000,NULL,1,NULL,0);
同样,为Task2创建Task2并在第7个参数中使核心ID为1 。
xTaskCreatePinnedToCore(Task2code,“ Task2”,10000,NULL,1,NULL,1);
您可以根据任务的复杂性更改优先级和堆栈大小。
2.现在,我们将实现 Task1code 和 Task2code 函数。这些功能包含所需任务的代码。在我们的情况下,第一个任务将使LED闪烁,另一个任务将获取温度。因此,在void设置功能之外,为每个任务设置两个单独的功能。
如下图所示,实现了 Task1code 功能, 该 功能在0.5秒后使板上LED闪烁。
无效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(;;){ float t = dht.readTemperature(); Serial.print(“ Temperature:”); Serial.print(t); delay(2000); } }
3.这里 空循环 功能将保持为空。我们已经知道 loop 和 setup 函数在core1上运行,因此您也可以在 void loop 函数中实现core1任务。
现在编码部分已经结束,因此只需在“工具”菜单中选择ESP32板,就可以使用Arduino IDE上传代码。确保已将DHT11传感器连接到ESP32的D13引脚。
现在,可以在串行监视器或Arduino IDE上监视结果,如下所示:
可以通过使用ESP32的双核同时运行多个任务来构建诸如实时系统之类的复杂应用程序。
以下是完整的代码以及演示视频。