[TH] ESP-IDF Ep.7 : DAC Output

บทความนี้กล่าวถึงการใช้งาน GPIO ของ ESP32 เพื่อทำหน้าที่นำออกสัญญาณแอนาล็อกผ่านทางโมดูล DAC ขนาด 8 บิตของไมโครคอนโทรลเลอร์ ESP32 โดยทดลองสร้างเป็นกราฟฟันปลา (ดังภาพที่ 7) เพื่อส่งแรงดันดังกล่าวไปยังโมดูลลำโพงดังภาพที่ 1

ภาพที่ 1 การต่อใช้งานประกอบตัวอย่างการใช้งาน DAC

โครงสร้างของโครงงาน

โครงสร้างของโครงงานของ ESP-IDF เป็นดังภาพที่ 2 คือ ในไดเร็กทอรีหรือโฟลเดอร์ของโครงงานจะมีไฟล์ CMakeList.txt และ sdkconfig กับไดเร็กทอรีชื่อ main สำหรับเก็บรหัสต้นฉบับของโครงงาน โดยในไดเร็กทอรีดังกล่าวมีไฟล์ภาษา C และ CMakeLists.txt

ภาพที่ 2 โครงสร้างของโครงงาน

จากโครงสร้างในภาพที่ 2 ต้องสร้างโค้ดของไฟล์ CMakeLists.txt ดังนี้ ซึ่งเนื้อหาในโค้ดได้กำหนดรุ่นขั้นต่ำของโปรแกรม cmake และกำหนดค่าการใช้งานของ cmake เบื้องต้นตามจ้นฉบับที่มากับ ESP-IDF พร้อมทั้งตั้งชื่อโครงงานเป็น ep07

cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(ep07)

สิ่งที่เขียน 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 หลังจากนั้นบันทึกและออกจากการตั้งค่า

ภาพที่ 3 ตั้งค่า Tick rate (Hz)

การใช้ DAC

ไมโครคอนโทรลเลอร์ ESP32 มีวงจรแปลงสัญญาณดิจิทัลเป็นแอนาล็อกเพื่อนำออกให้กับวงจรภายนอก หรือ DAC (Digital to Analog) ที่มีความละเอียด 8 บิต และรองรับการทำงานแบบ DMA (Direct Memory Access) ผ่านทางบัส I2S ซึ่งจะต้องใช้โมดูลภายนอก (และจะกล่าวถึงในบทความในตอนถัด ๆ ไป) ทำให้สามารถปรับค่าแรงดันที่ขา DAC ให้เป็น 0 ถึง 3V3 ได้ด้วยการส่งค่า 0 ถึง 255 ไปยังขานั้น ซึ่งตัว ESP32 เตรียมวงจร DAC ให้ใช้งาน 2 ตัว คือ

  • DAC1 ผ่านทางขา 25
  • DAC2 ผ่านทางขา 26

การใช้งาน DAC จะต้องนำเข้าไฟล์ส่วนหัวดังนี้ เพื่อใช้สำหรับเปิดหรือปิดการทำงานของ I2S

#include <driver/dac.h>

และเรียกใช้งานไฟล์ส่วนหัว dac_common.h สำหรับใช้งานคำสั่งเกี่ยวกับ DAC ของไมโครคอนโทรลเลอร์ ESP32

#include <driver/dac_common.h>

คำสั่ง

การสั่งเปิดหรือปิดการทำงานบัส I2S เพื่อทำการเข้าถึงโมดูลแปลง DAC ภายนอกในแบบ DMA ใช้คำสั่ง dac_i2s_enable() และ dac_i2s_disable() ตามรูปแบบของการใช้งานดังต่อไปนี้

esp_err_t dac_i2s_enable()
esp_err_t dac_i2s_disable()

โดยค่าคืนกลับจากการทำงานของคำสั่ง dac_i2s_enable และ dac_i2s_disable เป็นดังนี้

  • ESP_OK

คำสั่งสำหรับเปิดและปิดการทำงานของ DAC ในช่องสัญญาณที่ระบุมีรูปแบบของการใช้งานดังนี้

dac_output_enable( ช่องสัญญาณนำออก )
dac_output_disable( ช่องสัญญาณนำออก )

ซึ่งค่าช่องสัญญาณนำออกมีค่าเป็นดังนี้

  • DAC_CHANNEL_1 สำหรับขา 25
  • DAC_CHANNEL_2 สำหรับขา 26

สำหรับการนำออกสัญญาณแอนาล็อกจะต้องส่งข้อมูลเป็นค่าในช่วง 0 ถึง 255 เพื่อใช้แทนค่าแรงดันในช่วง 0 ถึง 3V3 ด้วยคำสั่ง dac_output_voltage() ดังรูปแบบต่อไปนี้

dac_output_voltage( หมายเลขช่องสัญญาณ, ค่านำออก )

กรณีที่ต้องการใช้งาน GPIO แบบอื่น ๆ สามารถเข้าไปอ่านบทความต่าง ๆ ดังต่อไปนี้เพิ่มเติม

  1. นำออกข้อมูลสัญญาณดิจิทัล
  2. นำเข้าสัญญาณดิจิทัล
  3. นำเข้าสัญญาณแอนาล็อก
  4. นำออกสัญญาณแอนาล็อก (ตอน 2)

ตัวอย่างโปรแกรม

วงจรแอลอีดีที่ใช้ในการทดลองครั้งนี้เป็นดังภาพที่ 5 อุปกรณ์ที่ใช้ในการทดลองได้แก่

  1. บอร์ด esp32
  2. บอร์ดทดลอง
  3. โมดูลลำโพง
    1. ทรานซิสเตอร์
    2. ตัวต้านทาน 2 ตัว
    3. บัซเซอร์
ภาพที่ 5 วงจรเชื่อมต่อโมดูลบัซเซอร์

ตัวอย่างโปรแกรมสำหรับส่งค่า 0 ถึง 255 ไปยังขา 25 และเมื่อค่าที่เพิ่มขึ้นมีค่ามากกว่า 255 ให้เปลี่ยนค่าเป็น 0 และวนรอบต่อไปนั้นมีโค้ดเป็นดังต่อไปนี้

#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 wave1() {
  int dValue=0;
  printf("Start wave1 ...");
  dac_output_enable( pinDAC );
  while (true) {
    dac_output_voltage( pinDAC, dValue++ );
    vTaskDelay( 10/portTICK_PERIOD_MS );
    if (dValue > 255) {
        break;
    }
  }
  dac_output_disable( pinDAC );
  printf("done.\n");
}

void app_main(void)
{  
  printf("Ep.07 DAC\n"); 
  dac_i2s_enable();
  dac_i2s_disable();

  while(1) {
    wave1();
    vTaskDelay( 10/portTICK_PERIOD_MS );
  }
}

คอมไพล์และอัพโหลด

ทำการคอมไพล์ หลังจากนั้น flash ลงชิพ และเข้าโปรแกรม Serial Monitor สั่งงานดังนี้

idf.py -p /dev/ttyUSB0 build flash monitor

ตัวอย่างผลลัพธ์ของโปรแกรมเป็นดังภาพที่ 6 และกราฟที่แสดงผลด้วยออสซิโลสโคปเป็นดังภาพที่ 7

ภาพที่ 6 ผลลัพธ์จากโปรแกรม ep7
ภาพที่ 7 กราฟผลลัพธ์ของโปรแกรมตัวอย่าง

สรุป

จากบทความนี้จะพบว่า การนำเข้าสัญญาณแอนาล็อกนั้น มีขั้นตอน 3 ขั้นตอน คือ

  1. เปิดการทำงานของ DAC1 หรือ DAC2 ด้วยคำสั่ง dac_output_enable()
  2. นำออกข้อมูลด้วยคำสั่ง dac_output_voltage()
  3. ปิดการทำงานของ DAC1 หรือ DAC2 ด้วยคำสั่ง dac_output_disable()

แต่อย่างไรก็ดี บทความนี้ได้ข้ามเรื่องของการใช้งาน I2S (พวกเรายังไม่มีโมดูล I2S ใช้งานในขณะที่เขียนบทความน่ะครับ) และชุดคำสั่งเกี่ยวกับการสร้างสัญญาณคลื่น cosine ที่ไลบรารีเตรียมไว้ให้ ซึ่งจะนำมาเขียนถึงในบทความถัด ๆ ไป สุดท้ายขอให้สนุกกับการเขียนโปรแกรมครับ

ท่านใดต้องการพูดคุยสามารถคอมเมนท์ได้เลยครับ

แหล่งอ้างอิง

  1. ESP-IDF : DAC

(C) 2020-2021, โดย อ.ดนัย เจษฎาฐิติกุล/อ.จารุต บุศราทิจ
ปรับปรุงเมื่อ 2021-10-11, 2021-12-25