บทความนี้กล่าวถึงการตั้งค่า GPIO และการส่งสถานะดิจิทัล 0 หรือ 1 ไปยังพอร์ต โดยเริ่มจากการสั่งให้หลอดแอลอีดีสว่างและดับ โดยเชื่อมต่อกับวงจรแอลอีดีภายนอกบอร์ดดังภาพที่ 1
โครงสร้างของโครงงาน
โครงสร้างของโครงงานของ ESP-IDF เป็นดังภาพที่ 2 คือ ในไดเร็กทอรีหรือโฟลเดอร์ของโครงงานจะมีไฟล์ CMakeList.txt และ sdkconfig กับไดเร็กทอรีชื่อ main สำหรับเก็บรหัสต้นฉบับของโครงงาน โดยในไดเร็กทอรีดังกล่าวมีไฟล์ภาษา C และ CMakeLists.txt
จากโครงสร้างในภาพที่ 2 ต้องสร้างโค้ดของไฟล์ CMakeLists.txt ดังนี้ ซึ่งเนื้อหาในโค้ดได้กำหนดรุ่นขั้นต่ำของโปรแกรม cmake และกำหนดค่าการใช้งานของ cmake เบื้องต้นตามจ้นฉบับที่มากับ ESP-IDF พร้อมทั้งตั้งชื่อโครงงานเป็น ep03
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(ep03)
สิ่งที่เขียน main/CMakeLists.txt เป็นดังงต่อไปนี้ เพื่อกำหนดรายการไฟล์ที่จะต้องคอมไพล์ ซึ่งกำหนดไว้เป็น main.c และกำหนดไดเร็กทอรีที่เก็บไฟล์ส่วนหัวเอาไว้เป็นค่าว่างซึ่งหมายถึงที่เดียวกับ main.c หรือในไดเร็กทอรี main
idf_component_register(SRCS "main.c"
INCLUDE_DIRS "")
เมื่อสร้างโครงสร้างได้เหมือนดังภาพที่ 2 ให้สั่งเลือก target ของระบบเป็น ESP32 ดังนี้
idf.py set-target esp32
ส่วน sdkconfig เกิดจากการเรียกใช้คำสั่งต่อไปนี้ idf.py menuconfig
idf.py menuconfig
จากหน้าจอกำหนดการตั้งค่าให้เข้าไปที่ Component Config –> FreeRTOS และกำหนด Tick rate (Hz) เป็น 1000 ดังภาพที่ 3 หลังจากนั้นบันทึกและออกจากการตั้งค่า
คำสั่ง
การใช้งาน GPIO จะต้องนำเข้าไฟล์ส่วนหัวชื่อ gpio.h ซึ่งอยู่ในโฟลเดอร์ย่อย driver ของ ESP-IDF ซึ่งสามารถนำเข้าดั้วยคำสั่ง include ดังนี้
#include <driver/gpio.h>
การเลือกใช้ขาต้องระบุด้วยคำสั่งต่อไปนี้
gpio_pad_select_gpio( หมายเลขขา )
คำสั่งสำหรับกำหนดหน้าที่การทำงานของขา มีรูปแบบดังนี้ โดยโหมดของขาเป็น GPIO_MODE_INPUT หรือ GPIO_MODE_OUTPUT
gpio_set_direction( หมายเลขขา, โหมดของขา )
การกำหนดสถานะของแรงดันดิจิทัลให้กับขามีรูปแบบของคำสั่งดังนี้
gpio_set_level( หมายเลขขา, ระดับแรงดันดิจิทัล )
สำหรับการหน่วงเวลาจะต้องเรียกใช้ชุดคำสั่งการหน่วงเวลาจาก FreeRTOS ด้วยคำสั่งการหน่วงเวลาต่อไปนี้ โดยการเข้าถึงค่า Tick rate (Hz) ที่กำหนดไว้ในขั้นตอน menuconfig สามารถเรียกได้จากค่าคงที่ชื่อ portTICK_PERIOD_MS
vTaskDelay( ระยะเวลาที่ต้องการหน่วงเวลา )
กรณีที่ต้องการใช้งาน GPIO แบบอื่น ๆ สามารถเข้าไปอ่านบทความต่าง ๆ ดังต่อไปนี้เพิ่มเติม
ตัวอย่างโปรแกรม
วงจรแอลอีดีที่ใช้ในการทดลองครั้งนี้เป้นดังภาพที่ 4 และ 5 อุุปกรณ์ที่ใช้ในการทดลองได้แก่
- บอร์ด esp32
- บอร์ดทดลอง
- แอลอีดี
- ตัวต้านทาน
จากภาพที่ 5 จะพบว่าได้เชื่อมต่อขา GPIO13 เข้ากับขาของแอลอีดีฝั่งที่เป็นส่วนของ Vcc นั่นหมายความว่าถ้าส่งข้อมูลเป็น 1 จะทกให้หลอดติด และถ้าส่งเป็น 0 จะทำให้หลอดดับ ดังตัวอย่างโปรแกรมต่อไปนี้
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <math.h>
#include "driver/gpio.h"
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#define LED_PIN 13 // GPIO13
void app_main(void)
{
printf("Ep.02 GPIO");
gpio_pad_select_gpio(LED_PIN);
gpio_set_direction(LED_PIN, GPIO_MODE_OUTPUT);
while(1) {
gpio_set_level(LED_PIN, 0);
vTaskDelay( 500/portTICK_PERIOD_MS );
gpio_set_level(LED_PIN, 1 );
vTaskDelay( 500/portTICK_PERIOD_MS );
}
}
คอมไพล์และอัพโหลด
ทำการคอมไพล์ด้วยคำสั่งต่อไปนี้จะได้รายงานผลดังภาพที่ 6 และ 7
idf.py build
ขั้นตอนสุดท้ายคือสั่งอัพโหลดลงชิพด้วยคำสั่งต่อไปนี้ และจะได้รายงานการทำงานตามภาพที่ 8 และ 9
idf.py -p /dev/ttyUSB0 flash
จากตัวอย่างโปรแกรมมีผลการทำงานที่หลอดแอลอีดีดังภาพที่ 10 และ 11 สลับกันไป
สำหรับตัวอย่างการสั่งงานกับบอร์ด ESP32-C3 เพื่อให้หลอด LED-RGB ติดสลับกันไป ให้เปลี่ยนโค้ดโปรแกรมเป็นดังนี้ และจะได้ผลลัพธ์ดังภาพที่ 12
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <math.h>
#include "driver/gpio.h"
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#define LED_R_PIN 3
#define LED_G_PIN 4
#define LED_B_PIN 5
void app_main(void)
{
printf("C3 LEDs");
gpio_pad_select_gpio(LED_R_PIN);
gpio_set_direction(LED_R_PIN, GPIO_MODE_OUTPUT);
gpio_pad_select_gpio(LED_G_PIN);
gpio_set_direction(LED_G_PIN, GPIO_MODE_OUTPUT);
gpio_pad_select_gpio(LED_B_PIN);
gpio_set_direction(LED_B_PIN, GPIO_MODE_OUTPUT);
while(1) {
gpio_set_level(LED_R_PIN, 1);
vTaskDelay( 500/portTICK_PERIOD_MS );
gpio_set_level(LED_R_PIN, 0 );
vTaskDelay( 500/portTICK_PERIOD_MS );
gpio_set_level(LED_G_PIN, 1);
vTaskDelay( 500/portTICK_PERIOD_MS );
gpio_set_level(LED_G_PIN, 0 );
vTaskDelay( 500/portTICK_PERIOD_MS );
gpio_set_level(LED_B_PIN, 1);
vTaskDelay( 500/portTICK_PERIOD_MS );
gpio_set_level(LED_B_PIN, 0 );
vTaskDelay( 500/portTICK_PERIOD_MS );
gpio_set_level(LED_R_PIN, 1 );
gpio_set_level(LED_G_PIN, 1 );
gpio_set_level(LED_B_PIN, 0 );
vTaskDelay( 500/portTICK_PERIOD_MS );
gpio_set_level(LED_R_PIN, 0 );
gpio_set_level(LED_G_PIN, 1 );
gpio_set_level(LED_B_PIN, 1 );
vTaskDelay( 500/portTICK_PERIOD_MS );
gpio_set_level(LED_R_PIN, 1 );
gpio_set_level(LED_G_PIN, 0 );
gpio_set_level(LED_B_PIN, 1 );
vTaskDelay( 500/portTICK_PERIOD_MS );
gpio_set_level(LED_R_PIN, 1 );
gpio_set_level(LED_G_PIN, 1 );
gpio_set_level(LED_B_PIN, 1 );
vTaskDelay( 500/portTICK_PERIOD_MS );
gpio_set_level(LED_R_PIN, 0 );
gpio_set_level(LED_G_PIN, 0 );
gpio_set_level(LED_B_PIN, 0 );
vTaskDelay( 500/portTICK_PERIOD_MS );
}
}
สิ่งที่ห้ามลืมคือ ต้องเปลี่ยน target เป็น esp32c3 ด้วยคำสั่งต่อไปนี้ก่อนดำเนินการอัพโหลดโปรแกรม
idf.py set-target esp32c3
สรุป
จากบทความนี้จะพบว่าการเขียนโปรแกรมด้วย ESP-IDF ค่อนข้างมีความซับซ้อนเนื่องจากเครื่องมืออยู่ในรูปแบบโหมดตัวอักษร (แต่ถือว่าสะดวกสำหรับนักพัฒนาที่ใช้ระบบปฏิบัติการลิกนุกซ์) แต่ถ้าพิจารณาขั้นตอนการเขียนโปรแกรมจะมีความสะดวกเพราะสามารถเขียนกำหนดและสั่งงานได้เหมือนกับการเขียนด้วย Arduino แต่คำสั่งนั้นแตกต่างกัน
การกำหนดหรือตั้งค่าไมโครคอนโทรลเลอร์จะต้องไปทำให้ idf.py menuconfig เพื่อตั้งค่าความถี่หรืออื่น ๆ ก่อนเสมอเพื่อให้การทำงานถูกต้องตามที่ต้องการ ซึ่งก่อนเข้า menuconfig ต้องกำหนด target ให้ถูกต้องก่อน ซึ่งได้แก่ esp32 esp32s2 esp32c3 และ esp32s3 โดยในบทความนี้เป็น esp32
สุดท้ายขอให้สนุกกับการเขียนโปรแกรมครับ
ท่านใดต้องการพูดคุยสามารถคอมเมนท์ได้เลยครับ
(C) 2020-2021, โดย อ.ดนัย เจษฎาฐิติกุล/อ.จารุต บุศราทิจ
ปรับปรุงเมื่อ 2021-07-27, 2021-10-01, 2021-12-10