กลับมากันอีกแล้วครับ สำหรับบทความนี้ เราจะมาแนะนำให้รู้จัก FreeRTOS หนึ่งในความสามารถใหม่ ที่มากับ ESP32 เนื่องจาก CPU ตัวใหม่ใน ESP32 เป็นแบบ Dual Core และ ประสิทธิ์ภาพความเร็วถึง 240 MHz ผมสงสัยว่าเราจะใช้ความสามารถมาได้เต็มที่ได้อย่างไงนะ ปกติ เคยเขียนแต่โปรแกรม หนึ่ง Core ทำมันทุกอย่าง
ทาง Espressif ได้เตรียมตัวเรื่องนี้มาไว้อย่างเดียวเลยที่เดียว เขาได้เละ core sdk เดิม มาเป็น core ใหม่ ที่มาพร้อมกับ FreeRTOS เลย ซึ่งทำให้เราเปิด Task การทำงาน ขนานกันไปได้เลย ซึ่งการเขียนโปรแกรมแบบ FreeRTOS ทำให้ใช้ความสามารถของ ESP32 ได้ดียิ่งขึ้น แต่อาจจะแลกมากับความซับซ้อนของการคิดโปรแกรม
FreeRTOS คือออะไร
FreeRTOS เป็นระบบปฏิบัติการสําหรับอุปกรณ์ Embeded ใช้ได้ในหลากหลายไมโครคอนโทรเลอร์ และยังเป็นโปรเจคโอเพ่นซอร์สอีกด้วย (Open Source) ถูกออกแบบมาให้สามารถใช้งานได้ง่ายและมีขนาดค่อนข้างเล็ก ภายใน เคอร์เนลของระบบประกอบด้วยไฟล์ภาษาซีเพียง 3-4 ไฟล์เท่านั้น รวมทั้งมีตัวอยางการออกแบบและการใช้งานให้ศึกษา ซึ่งใครสนใจ FreeRTOS เป็นอย่างไง ลองหาอ่านในเน็ทจะมีข้อมูลเยอะครับ เนื่องจากมีคนนำไปใช้ในไมโครคอนโทรลเลอร์ตระกูลอื่นก่อนจะมาอยู่บน esp32
โดยรวมสรุปความสามารถเด่นของ FreeRTOS ไว้ดังนี้
- มีโครงสร้างที่เล็กและง่ายต่อการใช้งาน
- การจัดการเวลาต่างๆ สามารถเลือกตั้งค่าได้ ทั้งแบบ Preemptive หรือ Cooperation operation
- ควบคุมทาสก์(Task)และสแต็ก(Stack) ได้ง่าย
ซึ่งทาง Espressif นำ FreeRTOS มาใส่ใน ESP-IDF หรือ ชุดพัฒนาของ ESP32 จึงทำให้ใน arduino esp32 มีความสามารถของ FreeRTOS มาด้วยเลย ซึ่งวิธีใช้ ไม่ได้ยากอะไรครับ ลองดู ตัวอย่างโค๊ดนี้ไปลองกันเลยครับ ใครอยากรู้ลึกๆ FreeRTOS ใช้งานอย่างไง แนะนำให้เข้าไปอ่านที่เวปของ FreeRTOS
สำหรับบอร์ดที่ทางเราใช้เป็น Node32s ครับ ที่ภูมิใจ ไทยทำ และ ตอนนี้มีจำหน่ายแล้ว ที่ Gravitech Thai
ตัวอย่างนี้ ทางผมเปิด 2 Task สำหรับทำไฟกระพริบ ที่ความเร็วไม่เท่ากันครับ
#define BUILDIN_LED 2 #define ledPIN1 23 #define ledPIN2 22 // ---------------------------------------------------------------------------------- void first_task(void *pvParameter){ /* Configure the IOMUX register for pad BLINK_GPIO (some pads are muxed to GPIO on reset already, but some default to other functions and need to be switched to GPIO. Consult the Technical Reference for a list of pads and their default functions.) */ pinMode(ledPIN1,OUTPUT); while(true) { digitalWrite(ledPIN1, HIGH); vTaskDelay(50 / portTICK_RATE_MS); digitalWrite(ledPIN1, LOW); vTaskDelay(50 / portTICK_RATE_MS); } } // ---------------------------------------------------------------------------------- void second_task(void *pvParameter){ /* Configure the IOMUX register for pad BLINK_GPIO (some pads are muxed to GPIO on reset already, but some default to other functions and need to be switched to GPIO. Consult the Technical Reference for a list of pads and their default functions.) */ pinMode(ledPIN2,OUTPUT); while(true) { digitalWrite(ledPIN2, HIGH); vTaskDelay(500 / portTICK_RATE_MS); digitalWrite(ledPIN2, LOW); vTaskDelay(500 / portTICK_RATE_MS); } } void setup() { pinMode(BUILDIN_LED,OUTPUT); // xTaskCreate( pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask) //first thread blinky in 50ms xTaskCreate(&first_task, "first_task", 1024, NULL, 5, NULL); //second thread blinky in 500ms xTaskCreate(&second_task,"second_task",1024, NULL, 5, NULL); } // the loop function runs over and over again forever void loop() { digitalWrite(BUILDIN_LED, HIGH); // turn the LED on (HIGH is the voltage level) delay(250); // wait for a second digitalWrite(BUILDIN_LED, LOW); // turn the LED off by making the voltage LOW delay(250); // wait for a second }
หรือ เข้าไปดูที่ gist