[TH] ESP-IDF Ep.6 : ADC Input

บทความนี้กล่าวถึงการใช้งาน GPIO ของ ESP32 เพื่อทำหน้าที่เป็นการนำเข้าสัญญาณแอนาล็อก โดยใช้วงจรการนำเข้าแรงดันจากการปรับค่าด้วยตัวต้านทานแบบปรับค่าได้ดังภาพที่ 1 ดังนั้น ในบทความนี้เราจะได้รู้จักการใช้คำสั่งเกี่ยวกับ ADC ของไมโครคอนโทรลเลอร์ ESP32 และการตั้งค่าเกี่ยวกับการปรับแต่งค่าของ ADC ใน menuconfig

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

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

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

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

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

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

สิ่งที่เขียน 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)

การตั้งค่าเกี่ยวกับ ADC ให้เข้าไปที่ Component config และเลือก ADC-Calibration ตรวจสอบว่าได้เลือก (*) ทั้ง 3 ตัวเลือกหรือไม่ดังภาพที่ 4 หลังจากนั้นกด S เพื่อบันทึก และ Q เพื่อออกจากหน้าจอตั้งค่า

ESP-IDF menuconfig/ADC-Calibration
ภาพที่ 4 การตั้งค่า ADC-Calibration

การใช้ ADC

ไมโครคอนโทรลเลอร์ ESP32 มีวงจรแปลงแรงดัน 3V3 ให้เป็นค่าดิจิทัลที่มีความละเอียด 12 บิต ทำให้สามารถแปลงค่าจาก 0 ถึง 3v3 ได้เป็น 0 ถึง 4095 หรือ 4096 ระดับ และมีภาค ADC จำนวน 2 ช่องสัญญาญ เรียกว่า ADC1 และ ADC2 โดยที่

  • ADC1 มีจำนวน 8 ช่องสัญญาณผ่านทางขา 32, 33, 34, 35, 36, 37, 38 และ 39
  • ADC2 มีจำนวน 10 ช่องสัญญาณผ่านทางขา 0, 2, 4, 12, 13, 14, 15, 25, 26 และ 27

แต่เมื่อผู้เขียนโปรแกรมใช้งานภาค WiFi จะส่งผลให้ ADC2 ของขาที่ระบุนี้ใช้งานไม่ได้ เนื่องจากถูกใช้ภาค ADC2 ในการแปลงสัญญาณของวงจร WiFi แต่ขาในภาค ADC2 ยังคงทำงานแบบดิจิทัล หรือทำ DAC (ขา 25, 26 และ 27) ได้ ดังนั้น ในบทความนี้ขึงเน้นที่การใช้งาน ADC1 เป็นหลัก

ในบอร์ด ESP32 DevKit ขา 0 จะไม่สามารถใช้งานได้ เนื่องจากถูกวงจรเขียนโปรแกรมลงชิพใช้งาน และบอร์ด ESP-WROVER-KIT จะไม่สามารถใช้ขา 0,2,4 และ 15 ได้ เนื่องจากถูกใช้ในวงจรเขียนชิพ และ 2,4,15 เชื่อมต่อกับหน่วยความจำแรมแบบ SPI หรือวงจรเสริมอื่น ๆ ที่เพิ่มนอกโมดูลของ ESP32 ปกติ

และกรณีที่ไม่ได้เชื่อมต่อวงจรเข้ากับขา ADC จะทำให้ค่าของขานั้นมีค่าเป็นตัวเลขสุ่ม จึงมีประโยชน์ในการนำไปใช้เป็นค่าเริ่มต้นการสุ่มค่า

การใช้งาน ADC จะต้องนำเข้าไฟล์ส่วนหัวดังนี้

#include <driver/adc.h>

คำสั่ง

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

adc1_config_width( ค่าจำนวนบิต )

โดยค่าจำนวนบิตเป็นค่าคงที่ที่ใช้แทนความละเอียดในการแปลงที่สามารถกำหนดได้ คือ 9, 10, 11 และ 12 บิต

  • ADC_WIDTH_BIT_9
  • ADC_WIDTH_BIT_10
  • ADC_WIDTH_BIT_11
  • ADC_WIDTH_BIT_12

นอกจากนี้สามารถปรับค่าการลดทอนแรงดันนำเข้ เพื่อให้รองรับการแปลงแรงดันได้หลายระดับดัวยคำสั่ง adc1_config_channel_atten() ดังนี้

adc1_config_channel_atten(หมายเลขช่องสัญญาณ, ประเภทของค่าลดทอน)

โดยค่าการลดทอนมีดังนี้

  • ADC_ATTEN_DB_0 เพื่อรองรับการทำงานของแรงดันไม่เกิน 800mV
  • ADC_ATTEN_DB_2_5 เพื่อรองรับการทำงานของแรงดันประมาณ 0 ถึง 1.1VDC (1.33x)
  • ADC_ATTEN_DB_6 เพื่อรองรับการทำงานของแรงดันประมาณ 0 ถึง 2.2VDC (2x)
  • ADC_ATTEN_DB_11 เพื่อรองรับการทำงานของแรงดันประมาณ 0 ถึง 3.3VDC (3.55x)

โดยค่าหมายเลขช่องสัญญาณมีค่าได้ดังนี้

  • ADC1_CHANNEL_0 สำหรับขา 36
  • ADC1_CHANNEL_1 สำหรับขา 37
  • ADC1_CHANNEL_2 สำหรับขา 38
  • ADC1_CHANNEL_3 สำหรับขา 39
  • ADC1_CHANNEL_4 สำหรับขา 32
  • ADC1_CHANNEL_5 สำหรับขา 33
  • ADC1_CHANNEL_6 สำหรับขา 34
  • ADC1_CHANNEL_7 สำหรับขา 35

สำหรับการนำเข้าข้อมูลแอนล็อกมาเป็นดิจิทัลนั้นใช้คำสั่ง adc1_get_raw() ตามรูปแบบการใช้งานต่อไปนี้

ค่าระดับดิจิทัล = adc1_get_raw( หมายเลขช่องสัญญาณ )

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

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

การแปลงค่า

การคำนวณค่าแรงดันจากค่าดิจิทัลใช้สมการการคำนวณดังนี้

แรงดัน = (float)((dValue/4095.0f)*3.3f)

นำมาเขียนเป็นฟังก์ชันแปลงค่าได้ตามฟังก์ชัน dValueToVolt()

float dValueToVolt( int dValue ) 
{
    return (float)((dValue/4096.0f)*3.3f);
}

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

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

  1. บอร์ด esp32
  2. บอร์ดทดลอง
  3. ตัวต้านทานปรับค่าได้
ภาพที่ 5 วงจรนำเข้าสัญญาณแอนาล็อก

ดังตัวอย่างโปรแกรมต่อไปนี้

#include <stdio.h>
#include <time.h>
#include <string.h>
#include <math.h>
#include <driver/adc.h>
#include "driver/gpio.h"
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#define pinADC ADC1_CHANNEL_0 // GPIO36

float dValueToVolt( int dValue ) 
{
    return (float)((dValue/4096.0f)*3.3f);
}

void app_main(void)
{  
  int dValue = 0;
  float volt = 0.0;

  printf("Ep.06 ADC\n"); 
  adc1_config_width( ADC_WIDTH_BIT_12 );
  adc1_config_channel_atten( pinADC, ADC_ATTEN_DB_11);

  while(1) {
    dValue = adc1_get_raw( pinADC );
    volt = dValueToVolt( dValue );
    printf("dValue = %d, V = %.2f\n",
      dValue, volt);
    vTaskDelay( 250/portTICK_PERIOD_MS );
  }
}

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

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

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

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

ภาพที่ 6 ผลลัพธ์จากโปรแกรม ep6

สรุป

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

  1. กำหนดความละเอียดในการแปลงค่า ด้วยคำสั่ง adc1_config_width()
  2. กำหนดค่าการลดทอนของแรงดันที่นำเข้ามาที่ขานำเข้าสัญญาณแอนาล็อก ด้วยคำสั่ง adc1_config_channel_atten()
  3. การอ่านค่าจากขาที่กำหนดไว้ด้วยคำสั่ง adc1_get_raw()

สุดท้ายขอให้สนุกกับการเขียนโปรแกรมครับ

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

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

  1. ESP-IDF : ADC

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