Các mô-đun ESP phổ biến cho các chức năng Wi-Fi của chúng như ESP8266, ESP-12E, v.v. Tất cả đều là các mô-đun Vi điều khiển mạnh mẽ với các chức năng Wi-Fi. Có một mô-đun ESP nữa mạnh mẽ và linh hoạt hơn các mô-đun ESP trước đó - tên của nó là ESP32. Nó có kết nối Bluetooth và Wi-Fi và chúng tôi đã giải thích khả năng BLE của ESP32 và sử dụng ESP32 trong nhiều dự án IoT. Nhưng rất ít người biết rằng ESP32 là một vi điều khiển lõi kép.
ESP32 có hai bộ vi xử lý Tensilica Xtensa LX6 32-bit, làm cho nó trở thành bộ vi điều khiển lõi kép (core0 và core1) mạnh mẽ. Nó có sẵn trong hai biến thể lõi đơn và lõi kép. Nhưng biến thể lõi kép phổ biến hơn vì không có sự chênh lệch giá đáng kể.
ESP32 có thể được lập trình bằng Arduino IDE, Espressif IDF, Lua RTOS, v.v. Trong khi lập trình với Arduino IDE, mã chỉ chạy trên Core1 vì Core0 đã được lập trình cho giao tiếp RF. Nhưng đây là hướng dẫn này, chúng tôi sẽ chỉ ra cách sử dụng cả hai lõi của ESP32 để thực hiện hai hoạt động đồng thời. Tại đây, nhiệm vụ đầu tiên sẽ là nhấp nháy đèn LED trên bo mạch và nhiệm vụ thứ hai là lấy dữ liệu nhiệt độ từ cảm biến DHT11.
Đầu tiên chúng ta hãy xem ưu điểm của bộ xử lý đa lõi so với lõi đơn.
Ưu điểm của bộ xử lý đa lõi
- Bộ vi xử lý đa lõi rất hữu ích khi có nhiều hơn 2 tiến trình hoạt động đồng thời.
- Khi công việc được phân phối giữa các lõi khác nhau, tốc độ của nó tăng lên và nhiều quá trình có thể được hoàn thành cùng một lúc.
- Điện năng tiêu thụ có thể được giảm bớt vì khi bất kỳ lõi nào ở chế độ nhàn rỗi hơn nó có thể được sử dụng để tắt các thiết bị ngoại vi không được sử dụng tại thời điểm đó.
- Bộ vi xử lý lõi kép ít phải chuyển đổi giữa các luồng khác nhau hơn so với bộ xử lý lõi đơn vì chúng có thể xử lý hai luồng cùng một lúc thay vì một lần.
ESP32 và FreeRTOS
Bo mạch ESP32 đã được cài đặt phần mềm FreeRTOS trên đó. FreeRTOS là Hệ điều hành thời gian thực mã nguồn mở, rất hữu ích trong đa nhiệm. RTOS giúp quản lý tài nguyên và tối đa hóa hiệu suất hệ thống. FreeRTOS có nhiều hàm API cho các mục đích khác nhau và sử dụng các API này, chúng ta có thể tạo các tác vụ và làm cho chúng chạy trên các lõi khác nhau.
Bạn có thể tìm thấy toàn bộ tài liệu về API FreeRTOS tại đây. Chúng tôi sẽ cố gắng sử dụng một số API trong mã của mình để xây dựng một ứng dụng đa nhiệm chạy trên cả hai lõi.
Tìm ID lõi ESP32
Ở đây chúng tôi sẽ sử dụng Arduino IDE để tải mã lên ESP32. Để biết Core ID mà mã đang chạy, có một hàm API
xPortGetCoreID ()
Hàm này có thể được gọi từ hàm void setup () và void loop () để biết ID lõi mà các hàm này đang chạy.
Bạn có thể kiểm tra API này bằng cách tải lên bản phác thảo bên dưới:
void setup () { Serial.begin (115200); Serial.print ("Hàm setup () chạy trên core:"); Serial.println (xPortGetCoreID ()); } void loop () { Serial.print ("Hàm loop () chạy trên core:"); Serial.println (xPortGetCoreID ()); }
Sau khi tải lên bản phác thảo trên, hãy mở màn hình Serial và bạn sẽ thấy rằng cả hai chức năng đều đang chạy trên core1 như hình dưới đây.
Từ những quan sát trên, có thể kết luận rằng bản phác thảo Arduino mặc định luôn chạy trên core1.
Lập trình lõi kép ESP32
Arduino IDE hỗ trợ FreeRTOS cho ESP32 và API FreeRTOS cho phép chúng tôi tạo các tác vụ có thể chạy độc lập trên cả hai lõi. Nhiệm vụ là đoạn mã thực hiện một số hoạt động trên bảng như nhấp nháy đèn led, gửi nhiệt độ, v.v.
Hàm dưới đây được sử dụng để tạo các tác vụ có thể chạy trên cả hai lõi. Trong hàm này, chúng ta phải đưa ra một số đối số như ưu tiên, id lõi, v.v.
Bây giờ, hãy làm theo các bước dưới đây để tạo tác vụ và chức năng tác vụ.
1. Đầu tiên, tạo các tác vụ trong chức năng thiết lập void . Ở đây chúng ta sẽ tạo hai tác vụ, một tác vụ cho đèn LED nhấp nháy sau mỗi 0,5 giây và một tác vụ khác là đọc nhiệt độ sau mỗi 2 giây.
Hàm xTaskCreatePinnedToCore () nhận 7 đối số:
- Tên hàm để triển khai tác vụ (task1)
- Bất kỳ tên nào được đặt cho nhiệm vụ (“task1”, v.v.)
- Kích thước ngăn xếp được phân bổ cho nhiệm vụ bằng chữ (1 từ = 2byte)
- Tham số đầu vào tác vụ (có thể là NULL)
- Mức độ ưu tiên của nhiệm vụ (0 là mức độ ưu tiên thấp nhất)
- Điều khiển tác vụ (có thể là NULL)
- Id lõi nơi tác vụ sẽ chạy (0 hoặc 1)
Bây giờ, tạo Task1 để nhấp nháy đèn led bằng cách đưa ra tất cả các đối số trong hàm xTaskCreatePinnedToCore ().
xTaskCreatePinnedToCore (Task1code, "Task1", 10000, NULL, 1, NULL, 0);
Tương tự, tạo Task2 cho Task2 và tạo id lõi 1 trong đối số thứ 7.
xTaskCreatePinnedToCore (Task2code, "Task2", 10000, NULL, 1, NULL, 1);
Bạn có thể thay đổi mức độ ưu tiên và kích thước ngăn xếp tùy thuộc vào mức độ phức tạp của nhiệm vụ.
2. Bây giờ, chúng ta sẽ thực hiện Task1code và chức năng Task2code . Các hàm này chứa mã cho tác vụ được yêu cầu. Trong trường hợp của chúng tôi, tác vụ đầu tiên sẽ nhấp nháy đèn LED và tác vụ khác sẽ lấy nhiệt độ. Vì vậy, hãy tạo hai hàm riêng biệt cho mỗi tác vụ bên ngoài hàm thiết lập void.
Chức năng Task1code cho đèn led trên bo mạch nhấp nháy sau 0,5 giây được thực hiện như hình dưới đây.
Void Task1code (void * tham số) { Serial.print ("Task1 chạy trên lõi"); Serial.println (xPortGetCoreID ()); for (;;) {// vòng lặp vô hạn digitalWrite (led, HIGH); chậm trễ (500); digitalWrite (lãnh đạo, LOW); delay (500); } }
Tương tự, thực hiện chức năng Task2code để tìm nạp nhiệt độ.
void Task2code (void * pvParameters) { Serial.print ("Task2 chạy trên lõi"); Serial.println (xPortGetCoreID ()); for (;;) { float t = dht.readTempentic (); Serial.print ("Nhiệt độ:"); Serial.print (t); chậm trễ (2000); } }
3. Ở đây hàm vòng lặp void sẽ vẫn trống. Như chúng ta đã biết rằng chức năng vòng lặp và thiết lập chạy trên core1, vì vậy bạn cũng có thể triển khai tác vụ core1 trong chức năng vòng lặp void .
Bây giờ phần viết mã đã kết thúc, vì vậy chỉ cần tải mã lên bằng Arduino IDE bằng cách chọn bảng ESP32 trong menu Công cụ. Đảm bảo rằng bạn đã kết nối cảm biến DHT11 với chân D13 của ESP32.
Bây giờ kết quả có thể được theo dõi trên Serial Monitor hoặc Arduino IDE như hình dưới đây:
Các ứng dụng phức tạp như hệ thống thời gian thực có thể được xây dựng bằng cách chạy nhiều tác vụ đồng thời bằng cách sử dụng lõi kép của ESP32.
Mã hoàn chỉnh cùng với video Demo được cung cấp bên dưới.