บทความนี้กล่าวถึงการใช้งาน GPIO ของ ESP32 เพื่อทำหน้าที่นำออกสัญญาณแอนาล็อกผ่านทางโมดูล DAC ขนาด 8 บิตของไมโครคอนโทรลเลอร์ ESP32 ต่อจากคราวที่แล้ว โดยในบทความนี้เป็นการใช้การสร้างคลื่นแบบ Cosine เพื่อนำออกสัญญาณแอนาล็อกของไมโครคอนโทรลเลอร์ผ่านลำโพง และแสดงให้เห็นรูปของคลื่นที่ได้จากจอแสดงผลของออสซิโลสโคป ส่วนบอร์ดทดลองยังคงใช้ตามภาพที่ 1
โครงสร้างของโครงงาน
โครงสร้างของโครงงานของ ESP-IDF เป็นดังภาพที่ 2 คือ ในไดเร็กทอรีหรือโฟลเดอร์ของโครงงานจะมีไฟล์ CMakeList.txt และ sdkconfig กับไดเร็กทอรีชื่อ main สำหรับเก็บรหัสต้นฉบับของโครงงาน โดยในไดเร็กทอรีดังกล่าวมีไฟล์ภาษา C และ CMakeLists.txt
จากโครงสร้างในภาพที่ 2 ต้องสร้างโค้ดของไฟล์ CMakeLists.txt ดังนี้ ซึ่งเนื้อหาในโค้ดได้กำหนดรุ่นขั้นต่ำของโปรแกรม cmake และกำหนดค่าการใช้งานของ cmake เบื้องต้นตามจ้นฉบับที่มากับ ESP-IDF พร้อมทั้งตั้งชื่อโครงงานเป็น ep08
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(ep08)
สิ่งที่เขียน 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 หลังจากนั้นบันทึกและออกจากการตั้งค่า
ที่มักจะลืมกันคือตั้งค่าขนาดความจุของหน่วยความจำรอม (Flash size) ดังภาพที่ 4 ให้ตรงกับขนาดที่ติดตั้งบนบอร์ด จากเสนู Serial flasher config ซึ่งในบทความใช้เป็น 4MB หลังจากนั้นกด S และ Q เพื่อบันทึกและออกจากการตั้งค่า
การใช้รูปคลื่น cosine
ในชุดไลบรารี DAC ของไมโครคอนโทรลเลอร์ ESP32 มีชุดคำสั่งเกี่ยวกับการเปิด/ปิดการสร้างคลื่นแบบโคไซน์ (cosine) ออกทางช่องสัญญาณ 1 และ 2 โดยต้องกำหนดคุณลักษณะของคลื่นในโครงสร้างข้อมูลประเภท dac_cw_config_t ดังมีรายละเอีดยต่อไปนี้
struct dac_cw_config_t {
dac_channel_t en_ch;
dac_cw_scale_t scale;
dac_cw_phase_t phase;
uint32_t freq;
uint8_t offset;
};
โดยแต่ละคุณสมบัติเป็นดังนี้
- en_ch เป็นหมายเลขช่องสัญญาณที่เปิดการทำงานการสร้างคลื่นแบบโคไซน์ โดยช่องสัญญาณได้แก่
- DAC_CHANNEL_1 ซึ่งเป็นขา 25 ของ ESP32 และขา 17 ของ ESP32-S2
- DAC_CHANNEL_2 ซึ่งเป็นขา 26 ของ ESP32 และขา 18 ของ ESP32-S2
- scale เป็นค่าความสูงของคลื่น (amplitude) ซึ่งกำหนดได้ 4 ระดับ คือ
- DAC_CW_SCALE_1 ให้ลูกคลื่นมีความสูงปกติ
- DAC_CW_SCALE_2 ให้ลูกคลื่นมีความสูง 1/2 ของขนาดปกติ
- DAC_CW_SCALE_4 ให้ลูกคลื่นมีความสูง 1/4 ของขนาดปกติ
- DAC_CW_SCALE_8 ให้ลูกคลื่นมีความสูง 1/8 ของขนาดปกติ
- phase เป็นค่าการเลื่อนเฟสของคลื่น ซึ่งกำหนดได้ 2 ลักษณะ คือ
- DAC_CW_PHASE_0 ให้เริ่มจากเฟส 0 องศา
- DAC_CW_PHASE_180 ให้เริ่มจากเฟส 180 องศา
- freq เป็นค่าความถี่ของคลื่อนซึ่งมีค่าอยู่ในช่วง 130Hz ~ 55,000Hz ซึ่งค่าสูงสุดที่กำหนดได้คือ 100KHz แต่คลื่นความถี่สูงเป็นช่วงที่หูของมนุษย์ไม่ได้ยิน
- offset สำหรับกำหนดระดับค่าแรงดันไฟฟ้ากระแสตรงที่นำออกมาในรูปแบบของคลื่นโคไซน์ ซึ่งต้องกำหนดค่าอยู่ในช่วง -128 ~127 แต่ที่ต้องพึงระวังคือ การใส่ค่าที่ไม่สมเหตุสมผลจะส่งผลต่อช่วงค่าความสูงของคลื่น
การใช้งาน DAC จะต้องนำเข้าไฟล์ส่วนหัวดังนี้ เพื่อใช้สำหรับเปิดหรือปิดการทำงานของ I2S
#include <driver/dac.h>
และเรียกใช้งานไฟล์ส่วนหัว dac_common.h สำหรับใช้งานคำสั่งเกี่ยวกับ DAC ของไมโครคอนโทรลเลอร์ ESP32
#include <driver/dac_common.h>
สำหรับค่าของช่องสัญญาณถูกกำหนดไว้ในไฟล์ส่วนหัวที่ชื่อ dac_channel.h
คำสั่ง
การสั่งเปิดหรือปิดการทำงานของการสร้างคลื่นโคไซน์ทำได้ด้วยการเรียกใช้คำสั่ง dac_cw_generator_enable() และ dac_cw_generactor_disable() ดังรูปแบบการใช้ต่อไปนี้
esp_err_t dac_cw_generator_enable()
esp_err_t dac_cw_generator_disable()
โดยค่าคืนกลับจากการทำงานของคำสั่ง dac_cw_generator_enable และ dac_cw_generator_disable เป็นดังนี้
- ESP_OK
และคำสั่งสำหรับตั้งค่าการทำงานของการสร้างคลื่นโคไซน์มีรูปแบบการใช้งานดังนี้
esp_err_t dac_cw_generator_config( &ตัวแปรที่เก็บการตั้งค่า )
โดยค่าคืนกลับจากการทำงานของคำสั่ง dac_cw_generator_enable และ dac_cw_generator_disable เป็นดังนี้
- ESP_OK สำหรับการตั้งค่าสำเร็จลุล่วง
- ESP_ERR_INVALID_ARG สำหรับการตั้งค่าผิดพลาด
กรณีที่ต้องการใช้งาน GPIO แบบอื่น ๆ สามารถเข้าไปอ่านบทความต่าง ๆ ดังต่อไปนี้เพิ่มเติม
ตัวอย่างโปรแกรม
วงจรแอลอีดีที่ใช้ในการทดลองครั้งนี้เป็นดังภาพที่ 5 อุปกรณ์ที่ใช้ในการทดลองได้แก่
- บอร์ด esp32
- บอร์ดทดลอง
- โมดูลลำโพง
- ทรานซิสเตอร์
- ตัวต้านทาน 2 ตัว
- บัซเซอร์
ตัวอย่างโปรแกรมสร้างคลื่นความถี่ 262Hz ซึ่งเป็นค่าความถี่ของเสียงตัว C ของเปียโนเป็นเวลา 2 วินาที เขียนโค้ดได้ดังนี้
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <math.h>
#include <sdkconfig.h>
#include <driver/gpio.h>
#include <driver/dac.h>
#include <driver/dac_common.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#define pinDAC DAC_CHANNEL_2
void app_main(void)
{
dac_cw_config_t cwCfg;
cwCfg.en_ch = pinDAC;
cwCfg.scale = DAC_CW_SCALE_1;
cwCfg.phase = DAC_CW_PHASE_180;
cwCfg.freq = 262; // 262Hz
cwCfg.offset = 127;
printf("Ep.08 DAC\n");
dac_i2s_enable();
dac_i2s_disable();
if (dac_cw_generator_config(&cwCfg) == ESP_OK) {
printf("Start cosine-wave generator ...");
dac_cw_generator_enable();
dac_output_enable( pinDAC );
vTaskDelay( 2000/portTICK_PERIOD_MS ); // 2 seconds
dac_cw_generator_disable();
dac_output_disable( pinDAC );
printf("done.\n");
} else {
printf("Error : ESP_ERR_INVALID_ARG!\n");
}
while (1) {
vTaskDelay( 10/portTICK_PERIOD_MS );
}
}
กรณีที่ต้องสร้างความถี่เสียงอื่น ๆ สามารถเปลี่ยนค่าความถี่ได้ดังนี้ (ที่มา ammmusic)
- โด ใช้ค่าความถี่ 262Hz
- เร ใช้ค่าความถี่ 294Hz
- มี ใช้ค่าความถี่ 330Hz
- ฟา ใช้ค่าความถี่ 349Hz
- ซอล ใช้ค่าความถี่ 370Hz
- ลา ใช้ค่าความถี่ 440Hz
- ที ใช้ค่าความถี่ 495Hz
คอมไพล์และอัพโหลด
ทำการคอมไพล์ หลังจากนั้น flash ลงชิพ และเข้าโปรแกรม Serial Monitor สั่งงานดังนี้
idf.py -p /dev/ttyUSB0 build flash monitor
ตัวอย่างผลลัพธ์ของโปรแกรมเป็นดังภาพที่ 6 และกราฟที่แสดงผลด้วยออสซิโลสโคปเป็นดังภาพที่ 7
จากภาพที่ 7 จะพบว่ายอดของคลื่นนั้นไม่สมบูรณ์ จึงลองเปลี่ยนการตั้งค่าใหม่เป็นดังนี้ และได้ผลลัพธ์ของลูกคลื่นเป็นดังภาพที่ 8
cwCfg.en_ch = pinDAC;
cwCfg.scale = DAC_CW_SCALE_2;
cwCfg.phase = DAC_CW_PHASE_0;
cwCfg.freq = 262; // 262Hz
cwCfg.offset = 48;
สรุป
จากบทความนี้จะพบว่า การนำออกสัญญาณแอนาล็อกนั้น มีขั้นตอน 3 ขั้นตอน คือ
- ตั้งค่าด้วย dac_cw_generator_config()
- เปิดการทำงานด้วยคำสั่ง dac_cw_generator_enable()
- ปิดการทำงานด้วยคำสั่ง dac_cw_generator_disable()
แต่อย่างไรก็ดี ลักษณะของลูกคลื่นนั้นมีผลต่อคุณภาพของเสียง ดังนั้น ควรตรวจสอบการตั้งค่าและลักษณะของคลื่นที่ได้ประกอบด้วยเสมอเพื่อไม่ให้เกิดการได้ค่าที่ไม่ถูกต้องดังภาพที่ 7 และสุดท้ายขอให้สนุกกับการเขียนโปรแกรมครับ
ท่านใดต้องการพูดคุยสามารถคอมเมนท์ได้เลยครับ
แหล่งอ้างอิง
(C) 2020-2021, โดย อ.ดนัย เจษฎาฐิติกุล/อ.จารุต บุศราทิจ
ปรับปรุงเมื่อ 2021-10-12, 2021-12-26