การเริ่มต้นใช้งานบอร์ด Seeed Studio XIAO ESP32-C3#


Seeeduino XIAO ESP32-C3#

บทความนี้กล่าวถึง การทดลองใช้งานบอร์ดไมโครคอนโทรลเลอร์ XIAO ESP32-C3 ของบริษัท Seeed Studio ในเบื้องต้น

→ แนะนำให้อ่านบทความที่เกี่ยวข้อง: การเริ่มต้นใช้งานชิป Espressif ESP32-C3 (RISC-V CPU Core)

รูป: บอร์ด Seeeduino XIAO ESP32-C3 (มุมมองจากด้านหน้าและด้านหลัง)

รูป: แผนผังแสดงตำแหน่งขา (PinOut) ของบอร์ด Seeeduino XIAO ESP32-C3

ข้อมูลเกี่ยวกับบอร์ด

  • เริ่มจำหน่ายในเดือนกรกฎาคม ค.ศ. 2022
  • มีตัวประมวลผลหลักคือ ชิป Espressif ESP32-C3FN4 SoC
    • 32-bit RISC-V (single-core, 160MHz)
    • RV32IMC ISA, Four-stage Pipeline, 32-bit Multiplier/Divider
    • On-chip Memory: 400KB SRAM, 384KB ROM
    • มีชิปหน่วยความจำแฟลชภายในชิป ขนาด 4MB (QSPI Flash)
  • รองรับการสื่อสารข้อมูลไร้สาย 2.4GHz Wi-Fi (IEEE 802.11 b/g/n) และ Bluetooth / BLE 5.0, Bluetooth Mesh
  • ทำงานที่ระดับแรงดันไฟเลี้ยง +3.3V
  • มีปุ่มกด BOOT / GPIO-9 (Active-low, 10k Pullup) สำหรับการเลือกเข้าสู่โหมด USB-Serial Bootloader และ CHIP_EN (Active-low, 10k Pullup) สำหรับรีเซตการทำงานของชิป
    • ขาของชิป ESP32-C3 จำนวนหนึ่ง จะถูกใช้งานเป็นขาที่เรียกว่า Strapping Pins และจะต้องมีสถานะลอจิกตามที่กำหนดไว้เมื่อชิปถูกรีเซต แล้วหลังจากนั้นจึงใช้เป็นขา GPIO ตามปรกติได้ เช่น ขาสำหรับเลือกโหมดการทำงานหลังจากรีเซต (Boot Mode Selection)
    • ถ้าขา GPIO-9 มีลอจิกเป็น LOW (0) และขา GPIO-8 เป็น HIGH (1) จะเข้าสู่ ROM Serial Bootloader หลังจากรีเซต และสามารถใช้โปรแกรม esptool.py ในการอัปโหลดโปรแกรมได้ แต่ถ้า GPIO-9 เป็น HIGH (1) จะเข้าสู่การทำงานและรันคำสั่งของโปรแกรมตามปรกติ (Normal Execution Mode)
  • เชื่อมต่อกับคอมพิวเตอร์ของผู้ใช้ด้วยคอนเนกเตอร์ USB Type-C
    • ไม่มีชิป USB-to-Serial Converter / Bridge ดังนั้นจะต้องเลือกใช้ USB CDC on Boot: Enabled สำหรับการสื่อสารข้อมูลแบบอนุกรมผ่านบัส USB เมื่อเขียนโปรแกรมด้วย Arduino-ESP32 Core
  • มีไอซี XC6210B332MR ควบคุมแรงดันไฟฟ้าให้เป็น +3.3V (700mA max.)
  • มีวงจร Crystal Oscillator สร้างสัญญาณ Clock ที่มีความถี่ 40MHz และ 32.768kHz ให้ ESP32C3
  • แรงดันไฟเลี้ยงของบอร์ดได้จาก USB (VBUS=+5V) ต่อผ่านไดโอดไปยังขา VIN และมีฟิวส์แบบ Polyfuse ป้องกันการใช้กระแสเกิน (ขนาด 500mA)
  • ในกรณีที่ต่อกับแบตเตอรรี่ชาร์จประจุได้แบบ LiPo (+3.7V) แรงดันที่ขา VBAT จะถูกนำไปป้อนให้ไอซีแปลงแรงดันให้เป็น +3.3V (ถ้าไม่มีแรงดันไฟเลี้ยงจาก VUSB หรือไม่ได้เชื่อมต่อพอร์ต USB)
  • ความแตกต่างจากบอร์ดอื่นที่ใช้ชิป ESP32-C3
    • โมดูลมีขนาดเล็ก (20x17.5mm, XIAO Series Form Factor) และมีจำนวนขา I/O ค่อนข้างจำกัด
    • มีวงจรชาร์จประจุสำหรับแบตเตอรี่ (LiPo Battery, Single-cell, 3.7V) + Charging LED
    • มีคอนเนกเตอร์สำหรับเชื่อมต่อสายอากาศภายนอก (U.FL Antenna Connector)
    • ไม่มี On-board User LED
  • ไฟล์ Schematic (.pdf)

รูป: ผังวงจรของบอร์ด Seeeduino XIAO ESP32-C3

 


Arduino ESP32 Core#

ถัดไปเป็นการสาธิตขั้นตอนใช้งานซอฟต์แวร์ Arduino IDE v2.2.x โดยได้ติดตั้ง Arduino ESP32 Core ใน Arduino IDE ไว้แล้ว เพื่อทดลองคอมไพล์ และอัปโหลดโปรแกรมที่ได้ไปยังบอร์ดไมโครคอนโทรลเลอร์

การติดตั้ง Arduino ESP32 Core ใน Arduino IDE ทำได้ง่าย โดยไปที่เมนู "File -> Preferences -> Additional Boards Manager URLs" แล้วเพิ่มรายการ ซึ่งเป็น URL ของไฟล์ .json ดังต่อไปนี้

https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_dev_index.json

จากนั้นใน Boards Manager ให้ค้นหาและติดตั้งแพ็กเกจต่าง ๆ สำหรับ esp32 เวอร์ชันล่าสุด

คำแนะนำ: ในการใช้งานบอร์ด ESP32-C3 ซึ่งไม่มีชิป USB-to-Serial Bridge ให้กดปุ่ม BOOT ค้างไว้ แล้วกดปุ่ม EN แล้วปล่อย เพื่อทำการรีเซตการทำงานของบอร์ด ให้เข้าสู่โหมด ROM Serial Bootloader จากนั้นใน Arduino IDE จึงสามารถมองเห็นหมายเลขพอร์ตอนุกรมของบอร์ด แล้วเลือกพอร์ตดังกล่าวในขั้นตอนการอัปโหลด เมื่ออัปโหลด Arduino Sketch ครั้งแรกได้สำเร็จแล้ว ครั้งถัดไป ไม่จำเป็นต้องกดปุ่มใด ๆ เพื่อเข้าสู่ Serial Bootloader แต่ต้องเลือกหมายเลขพอร์ตให้ถูกต้องตรงกับที่ใช้งานจริง

 


Arduino Sketch Demo 1#

โค้ดตัวอย่างแรกสาธิตการแสดงข้อมูลเชิงฮาร์ดแวร์เกี่ยวกับชิป ESP32C3 และเวอร์ชันของ Espressif ESP-IDF ที่ได้ใช้ในการคอมไพล์โค้ด

ตัวอย่างการใช้คำสั่งจากคลาส ESP (cores/esp32/Esp.h) เช่น

  • ESP.getSdkVersion(): เวอร์ชันของซอฟต์แวร์ Espressif ESP-IDF ที่ใช้
  • ESP.getChipRevision(): เวอร์ชันการแก้ไขชิป SoC
  • ESP.getCpuFreqMHz(): ความถี่ของซีพียูสำหรับการทำงาน (MHz)
  • ESP.getHeapSize(): ขนาดของหน่วยความจำที่ใช้งานสำหรับ Heap ของ SRAM
  • ESP.getFreeHeap(): ความจุที่ยังใช้ได้สำหรับการใช้งานของ SRAM ในส่วนที่เป็น Heap
  • ESP.getPsramSize(): ขนาดความจุของหน่วยความจำ PSRAM (SPI SRAM)
  • ESP.getFreePsram(): ความจุที่ยังใช้ได้สำหรับการเก็บข้อมูลใน PSRAM
  • ESP.getFlashChipSize(): ขนาดความจุของหน่วยความจำแฟลช
  • ESP.getFlashChipSpeed(): ความเร็วหรือความถี่สำหรับการทำงานของหน่วยความจำแฟลซ (MHz)
void setup() {
  Serial.begin(115200);
  while(!Serial);
  delay(1000);
  Serial.println("\nESP32 C3 Demo...\n");
}

void loop() {
  Serial.println("=========================================");
  Serial.printf( "Arduino ESP32 Core v%u.%u.%u\n",
     ESP_ARDUINO_VERSION_MAJOR, 
     ESP_ARDUINO_VERSION_MINOR, 
     ESP_ARDUINO_VERSION_PATCH );

  Serial.printf("Espressif IDF: %s\n", ESP.getSdkVersion() );
  Serial.printf("Chip Revision %lu\n", ESP.getChipRevision() );
  Serial.printf("Cpu Freq. %lu MHz\n", ESP.getCpuFreqMHz() );
  Serial.printf("Heap (total/free): %lu / %lu bytes\n", 
         ESP.getHeapSize(), ESP.getFreeHeap());
  Serial.printf("PSRAM (toal/free): %lu / %lu bytes\n", 
         ESP.getPsramSize(), ESP.getFreePsram());
  Serial.printf("Flash Size: %lu MB, Flash Speed: %lu MHz\n",
         ESP.getFlashChipSize()/(1024*1024UL), 
         ESP.getFlashChipSpeed()/(uint32_t) 1e6 );

  // more info...
  Serial.printf("Espressif chip model: %s\n",
         ESP.getChipModel() );
  Serial.printf("Number of CPU Cores: %d\n", 
         ESP.getChipCores() );
  String str;
  switch(ESP.getFlashChipMode()) {
     case FM_QIO:  str = "QIO";  break;
     case FM_QOUT: str = "QOUT"; break;
     case FM_DIO:  str = "DIO";  break;
     case FM_DOUT: str = "DOUT"; break;
     default:      str = "Unknown"; break;
  }
  Serial.printf("Flash model: %s\n", str.c_str() );
  Serial.println("=========================================\n");
  delay(4000);
}

รูป: ตัวอย่างข้อความเอาต์พุตใน Arduino IDE - Serial Monitor

 


Arduino Sketch Demo 2#

โค้ดตัวอย่างที่สองสาธิตการปรับความถี่ในการทำงานของซีพียู และทดสอบความเร็วในการทำงานของซีพียูเมื่อใช้ความถี่ที่แตกต่างกัน เช่น 10MHz, 20MHz, 40MHz, 80MHz และ 160MHz (default)

uint32_t saved_freq;

void setup() {
  Serial.begin(115200);
  while(!Serial);
  delay(1000);
  Serial.println("\n\nESP32 C3 Demo...\n");
  // Get the current CPU frequency (in MHz).
  saved_freq = getCpuFrequencyMhz();
}

#define SEP_LINE  "====================================="

void speed_test() {
  const uint32_t repeat_times = 1e6;
  Serial.println( SEP_LINE SEP_LINE );
  uint32_t frequencies_mhz[] = {20,40,80,160};
  int n = sizeof(frequencies_mhz)/sizeof(uint32_t);

  for ( uint32_t i=0; i < n; i++ ) {
    uint32_t freq = frequencies_mhz[i]; 
    setCpuFrequencyMhz( freq );
    Serial.printf("Freq. (CPU/XTAL/APB): %3lu/%lu/%lu MHz", 
                  getCpuFrequencyMhz(), 
                  getXtalFrequencyMhz(), 
                  getApbFrequency()/(uint32_t)1e6);
    uint32_t ts = micros(); // Get the start ime in usec.
    // Simple counting loop
    for ( volatile uint32_t j=0; j < repeat_times; j++);
    ts =  micros() - ts;  // Compute the time difference.
    Serial.printf( ", Exec. time: %6lu usec\n", ts );
  }
  Serial.println( SEP_LINE SEP_LINE "\n" );
  // Restore the CPU frequency.
  setCpuFrequencyMhz( saved_freq );
}

void loop() {
  static uint32_t ts = 0;
  if ( millis() - ts >= 5000 ) {
    ts = millis();
    speed_test();
  }
}

จากข้อความเอาต์พุตใน Arduino Serial Monitor จะเห็นได้ว่า ความถี่ของซีพียูมีผลต่อระยะเวลาในการทำคำสั่ง ถ้าเพิ่มความถี่ของซีพียู ก็จะใช้ระยะเวลาน้อยลง

รูป: ตัวอย่างข้อความเอาต์พุต

 


Arduino Sketch Demo 3#

ตัวอย่างถัดไปเป็นการสาธิตการรับส่งข้อมูลระหว่างวงจร USB-CDC กับวงจร Hardware Serial ภายในชิป ESP32-C3 ซึ่งมีสองตัวเลือกคือ

  • Serial0 (ใช้ขา TX=GPIO-21 / RX=GPIO-20) และ
  • Serial1 (ใช้ขา TX=GPIO-9 / RX=GPIO-10)

ในตัวอย่างนี้ ถ้าทดลองกับบอร์ด ESP32-C3 จะต้องมีการใช้ลวดสายไฟ เชื่อมต่อขา TX กับ RX ที่ใช้กับวงจร Hardware Serial เมื่อมีข้อมูส่งมาจากคอมพิวเตอร์ผู้ใช้ โดยใช้ USB-CDC ข้อมูลดังกล่าว จะถูกส่งต่อไปยังขา TX ของ Hardware Serial และมีการรับข้อมูลกลับเข้ามาทางขา RX แล้วส่งกลับไปยังคอมพิวเตอร์ของผู้ใช้

#include <HardwareSerial.h>

#define HW_SERIAL_ID  (0)  // 0 or 1
HardwareSerial MySerial( HW_SERIAL_ID );

void setup() {
  if (HW_SERIAL_ID==0) {
    MySerial.begin(115200, SERIAL_8N1, 21 /*Tx*/, 20 /*Rx*/ ); 
  } else {
    MySerial.begin(115200, SERIAL_8N1, 9 /*Tx*/, 10 /*Rx*/ ); 
  }
  MySerial.setDebugOutput(false);
  while (MySerial.available()) { (void)MySerial.read(); }

  Serial.begin(921600); //  USB-CDC
  while(!Serial);
  Serial.flush();
  delay(1000);
  Serial.println("ESP32C3 Serial Bridge Test...");
}

void loop() {
  // Read data bytes from Serial and send them to MySerial.
  while( Serial.available()) {
    char ch = Serial.read();
    MySerial.write(ch);
  }
  // Read data bytes from MySerial and send them to Serial.
  while( MySerial.available()) {
    char ch = MySerial.read();
    Serial.write(ch);
  }
}

รูป: ตัวอย่างข้อความที่ถูกส่งจากคอมพิวเตอร์ของผู้ใช้ผ่านทาง Arduino Serial Monitor และได้รับกลับมา

 


Arduino Sketch Demo 4#

ชิป ESP32-C3 มีวงจรแปลงสัญญาณแอนะล็อกให้เป็นข้อมูลดิจิทัล (ADC: Analog-to-Digital Converter) จำนวน 2 ชุด (ADC1 & ADC2) ซึ่งเป็นประเภทที่เรียกว่า SAR (Successive Approximation Register) และให้ข้อมูลที่มีขนาด 12 บิต (ADC Sampling Resolution)

  • วงจร ADC1 ใช้กับขา GPIO0 .. GPIO4 (ซึ่งตรงกับช่องอินพุต ADC1_CHANNEL_0 .. ADC1_CHANNEL_4 ตามลำดับ)
  • วงจร ADC2 ใช้กับขาอินพุต GPIO5 (ช่องอินพุต ADC2_CHANNEL_0)

วงจร ADC ใช้แรงดันไฟเลี้ยงภายในเป็นแรงดันอ้างอิงซึ่งคงที่ (Vref) สำหรับการแปลงข้อมูล ซึ่งปรกติแล้ว Vref จะมีค่าโดยประมาณ 1100mV (ชิปแต่ละตัวอาจมีค่า Vref แตกต่างกันได้ และอยู่ในช่วงประมาณ 1100mV +/- 100mV) ดังนั้นสัญญาณแอนะล็อก ก็ควรจะมีแรงดันไฟฟ้าไม่เกิน Vref แต่ถ้าต้องการจะรับแรงดันไฟฟ้าให้สูงกว่า ก็สามารถทำได้โดยการตั้งค่าลดทอนสัญญาณ หรือ Attenuation เพื่อลดขนาดของสัญญาณอินพุตก่อนป้อนให้วงจร ADC และมีค่าที่เลือกได้ดังนี้

  • ADC_ATTEN_DB_0: ช่วงแรงดัน 0mV .. 750mV
  • ADC_ATTEN_DB_2_5: ช่วงแรงดัน 0mV .. 1050mV
  • ADC_ATTEN_DB_6: ช่วงแรงดัน 0mV .. 1300mV
  • ADC_ATTEN_DB_11: ช่วงแรงดัน 0mV .. 2500mV

ถ้าพิจารณาค่า ADC_ATTEN_DB_0 หรือ 0dB ก็หมายความว่า ไม่มีการลดทอนสัญญาณ หรือมีอัตรา 1:1 และมีแรงดันไม่เกิน 750mV ซึ่งน้อยกว่า Vref=1100mV แต่ถ้าเลือกค่า ADC_ATTEN_DB_11 เนื่องจากมีการลดทอนสัญญาณ ก็จะรับแรงดันอินพุตได้สูงขึ้น แต่ไม่เกิน 2500mV (เป็นค่าโดยประมาณ) ถ้าคำนวณอัตราส่วนระหว่าง 750mV : 2500mV แล้วแปลงเป็นหน่วยเป็น dB ก็จะได้

ในกรณีที่มีการอ่านค่าด้วย ADC แล้วเลือกใช้ค่าความละเอียดจำนวน 12 บิต ซึ่งจะได้ค่าในช่วง 0..4095 (หรือ ค่าสูงสุด ) และถ้านำมาคำนวณเป็นแรงดันไฟฟ้าในหน่วยมิลลิโวลต์ (mV) โดยใช้ความสัมพันธ์แบบเชิงเส้น ก็มีสูตรคำนวณดังนี้

โดยที่ คือ ค่าแรงดันสูงสุดสำหรับการเลือกอัตราการลดทอนสัญญาณอินพุตในแต่ละกรณี

อย่างไรก็ตาม จากเอกสารของผู้ผลิต ได้มีการแนะนำให้ทำการปรับค่าและชดเชยค่าความผิดพลาด (ADC Calibration) จากการอ่านค่าด้วย ADC ภายในชิป ESP32C3

รูปตัวอย่างต่อไปนี้ แสดงรูปกราฟความสัมพันธ์ของข้อมูลระหว่างค่าแรงดันไฟฟ้าที่ใช้เป็นอินพุตและค่าที่อ่านได้ โดยใช้ค่าลดทอนสัญญาณเป็น ADC_ATTEN_DB_11 และควรจะมีค่าแรงดันอินพุตได้ไม่เกิน 2500mV

เมื่อมีการปรับชดเชยค่าความผิดพลาด โดยให้มีการเริ่มต้นค่าที่ 0mV ก็จะได้รูปกราฟทางขวามือ และค่า จะได้ประมาณ 2700mV ในกรณีที่อ่านค่าได้ 4095 (สูงสุด) และถ้ามีการเพิ่มแรงดันอินพุตให้สูงกว่าค่าดังกล่าว (แต่ต้องไม่เกิน VCC=+3.3V) การแปลงค่าด้วย ADC ก็จะให้ค่าคงเดิม ไม่เพิ่มตามแรงดันอินพุต

รูป: การแสดงความสัมพันธ์ระหว่างค่าแรงดันไฟฟ้าที่ใช้เป็นอินพุตและค่าที่อ่านได้ โดยเปรียบเทียบ 2 กรณี คือ ไม่มีการชดเชยค่าความผิดพลาดที่อ่านได้ (รูปซ้ายมือ) กับมีการชดเชยค่าความผิดพลาด (รูปขวามือ)

คำสั่งสำหรับการใช้งาน ADC1 และ ADC2 มีอยู่หลายคำสั่ง และสามารถดูได้จาก ESP-IDF v4.4.5 - ADC API Reference และคำสั่งสำหรับ Arduino-ESP32 Core ดูได้จากไฟล์ของซอร์สโค้ดต่อไปนี้

โค้ดตัวอย่างถัดไปสาธิตการอ่านค่าจากขาแอนะล็อก-อินพุต โดยใช้วงจร ADC1 (Analog-to-Digital Converter) ภายในชิป ESP32C3 ซึ่งมีขาให้เลือกใช้ได้สำหรับบอร์ด XIAO ESP32-C3

XIAO Pin ESP32C3 Pin GPIO / ADC Channel
A0 Pin 6 GPIO2 / ADC1_CHANNEL_2
A1 Pin 8 GPIO3 / ADC1_CHANNEL_3
A2 Pin 9 GPIO4 / ADC1_CHANNEL_4
A3 Pin 10 GPIO5 / ADC2_CHANNEL_0

ในโค้ดตัวอย่างนี้มีการเลือกใช้ขา GPIO2 / XIAO A0 Pin โดยนำไปต่อกับวงจรแบ่งแรงดัน (Voltage Divider) ที่สร้างขึ้นโดยใช้ตัวต้านทานปรับค่าได้ (Potentiometer) ขนาด 10k ใช้แรงดันไฟเลี้ยง 3.3V จากบอร์ด

นอกจากนั้นแล้ว ก็มีการตั้งค่า ADC_11db สำหรับ ADC Attenuation และความละเอียดของข้อมูลเท่ากับ 12 บิต มีการใช้คำสั่ง analogRead(...) และ analogReadMilliVolts(...) เพื่ออ่านค่าจากขา A0 ทุก ๆ 100 มิลลิวินาที

ค่าที่อ่านได้จากคำสั่ง analogRead(...) จะเป็นเลขจำนวนเต็ม อยู่ในช่วง 0 .. 4095 ถ้าต้องการจะแปลงให้เป็นค่านี้ให้เป็นแรงดันไฟฟ้า ก็จะต้องนำไปคำนวณแบบเชิงเส้น โดยเทียบกับค่าแรงดันสูงสุด ซึ่งได้กำหนดไว้เท่ากับ 2735mV ในตัวอย่างนี้

ค่าที่อ่านได้ด้วยคำสั่ง analogReadMilliVolts(...) จะได้เป็นค่าตัวเลข มีหน่วยเป็นมิลลิโวลต์ และมีการชดเชยความผิดพลาดมาให้แล้ว โดยใช้ค่าที่เก็บไว้ในหน่วยความจำ eFuse สำหรับ ADC Calibration มาคำนวณ

#define AIN_PIN  (A0)     // Use XIAO A0 pin (GPIO2)
#define ADC_BITS (12)     // ADC reading resolution: 9..12 bits
#define VREF     (1100)   // Internal ADC reference voltage (in mV)
#define DMAX     ((1UL<<ADC_BITS)-1)
#define VMAX     (2735)   /// max. voltage for ADC attenuation of 11dB

void setup() {
  Serial.begin(115200);
  pinMode(AIN_PIN, ANALOG);
  delay(2000);

  // Set the ADC attenuation to -11dB
  analogSetPinAttenuation( AIN_PIN, ADC_11db ); // default
  // Set the ADC resolution to 12 bits 
  analogReadResolution( ADC_BITS ); // default
}

void loop() {
  static uint32_t ts_saved = 0;
  static String str;
  uint32_t ts_now = millis();
  if ( ts_now - ts_saved >= 100 ) {
    ts_saved = ts_now;
    uint32_t value   = analogRead(AIN_PIN);
    uint32_t voltage = analogReadMilliVolts(AIN_PIN);
    str = "mV(1):";
    str += value*VMAX/DMAX;
    str += ",mV(2):";
    str += voltage;
    Serial.println( str.c_str() );
  }
}

รูป: ตัวอย่างข้อความเอาต์พุตที่ได้รับมาจากบอร์ด

รูป: ตัวอย่างการแสดงกราฟของข้อมูลที่ได้รับมาจากบอร์ด โดยใช้ Arduino Serial Plotter ในขณะที่มีการหมุนปรับค่าแรงดันอินพุต-แอนะล็อก

จากรูปกราฟ ข้อมูล mV(1) ได้จากการอ่านค่า ADC โดยใช้คำสั่ง analogRead(...) แล้วนำมาคำนวณให้เป็นแรงดันไฟฟ้า และ mV(2) ได้จากการใช้คำสั่ง analogReadMilliVolts(...) โดยตรง

รูป: การเปรียบเทียบค่า mV(1) และ mV(2) ที่ได้จากการอ่านค่าสัญญาณแอนะล็อกในช่องอินพุตเดียวกัน

 

โค้ดตัวอย่างถัดไปเป็นการเปรียบเทียบการใช้คำสั่ง analogReadMilliVolts(...) ของ Arduino-ESP32 API กับการใช้คำสั่งต่อไปนี้ของ Espressif ESP-IDF API เพื่อค่าจาก ADC แล้วนำไปแปลงให้เป็นตัวเลขสำหรับแรงดันไฟฟ้า

  • esp_adc_cal_characterize(...)
  • adc1_get_raw(...)
  • esp_adc_cal_raw_to_voltage(...)
#include "esp_adc_cal.h"

// ADC characteristics structure used for ADC calibration.
esp_adc_cal_characteristics_t adc_chars;

void setup() {
  Serial.begin(115200);
  delay(2000);

  // ADC Single Read mode
  // Set the ADC resolution to 12 bits 
  adc1_config_width( ADC_WIDTH_12Bit );
  // Set the ADC attenuation level (11dB) for ADC1 Channel 2 (GPIO2)
  adc1_config_channel_atten(ADC1_CHANNEL_2, ADC_ATTEN_DB_11);

  // ADC calibration can be based on Two Point values
  if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_TP) == ESP_OK) {
    Serial.println( "Two-point values calibration is supported in eFuse." );
  }

  // Initialize the ADC1 characteristics structure.
  esp_adc_cal_value_t cal_value = esp_adc_cal_characterize( ADC_UNIT_1,
                  ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, 1100, &adc_chars );
  switch (cal_value) {
    case ESP_ADC_CAL_VAL_EFUSE_VREF: 
       Serial.println( "eFuse Vref used for characterization" ); break;
    case ESP_ADC_CAL_VAL_EFUSE_TP:
       Serial.println( "Two-point values used for characterization" ); break;
    case ESP_ADC_CAL_VAL_DEFAULT_VREF:
       Serial.println( "Default Vref used for characterization" ); break;
    default:
       Serial.println( "Unknown ADC calibration method.. error" ); break;
  }  
}

void loop() {
  static uint32_t ts_saved = 0;
  static String str;
  uint32_t ts_now = millis();
  if ( ts_now - ts_saved >= 100 ) {
    ts_saved = ts_now;
    // read millivolts from XIAO A0 pin (ADC1 channel 2)
    uint32_t mV  = analogReadMilliVolts(A0); 
    // Read a raw value from the ADC1 channel 2.
    uint32_t raw = adc1_get_raw(ADC1_CHANNEL_2); 
    // Convert the raw value to voltage using the built-in ADC calibration 
    uint32_t voltage = esp_adc_cal_raw_to_voltage(raw, &adc_chars);
    str = "mV(1):";
    str += mV;
    str += ",mV(2):";
    str += voltage;
    Serial.println( str.c_str() );
  }
}

รูป: ตัวอย่างข้อความเอาต์พุต แสดงค่าแรงดันที่วัดได้ (ได้ค่า 1596 mV เมื่อวัดแรงดันอินพุตด้วยมัลติมิเตอร์)

รูป: กราฟข้อมูลเปรียบเทียบระหว่าง mV(1) และ mV(2) ที่มีการเปลี่ยนแปลงในเชิงเวลา


Arduino Sketch Demo 5#

โค้ดตัวอย่างถัดไปสาธิตการทำให้ ESP32-C3 เข้าสู่โหมด Deep Sleep เพื่อประหยัดพลังงาน และสามารถปลุกให้ซีพียูกลับมาทำงานได้ตามปรกติโดยการกดปุ่ม (Wakeup Pin) ซึ่งในตัวอย่างนี้ได้เลือกใช้ขา GPIO-5 ดังนั้นจะต้องมีการต่อวงจรปุ่มกดเพิ่มที่ขาดังกล่าว และต่อตัวต้านทานแบบ Pullup (10k)

เมื่อชิปถูกปลุกให้ทำงานในแต่ละครั้ง จะทำให้ LED ที่ขา GPIO-8 กระพริบ 3 ครั้ง ก่อนจะเข้าสู่โหมด Deep Sleep ถ้าไม่มีการกดปุ่มค้างไว้ ซึ่งจะเห็นได้ว่า LED จะไม่กระพริบ ดังนั้นซีพียูจะไม่ทำงานในขณะนั้น และรอการปลุกด้วยปุ่มกดในครั้งถัดไป

#define LED_PIN     (8)
#define WAKEUP_PIN  (5)
#define LED_ON      (0)
#define LED_OFF     (!LED_ON)

void setup() {
  int state = LED_OFF;
  pinMode( LED_PIN, OUTPUT );
  digitalWrite( LED_PIN, LED_OFF );
  pinMode( WAKEUP_PIN, INPUT_PULLUP );

  for (int i=0; i < 6; i++) { // Blink the LED.
    digitalWrite( LED_PIN, state^=1 );
    delay(500);
  }

  if ( digitalRead(WAKEUP_PIN) ) {
    // Enable deep sleep with GPIO wakeup.
    esp_deep_sleep_enable_gpio_wakeup( 
         (1<< WAKEUP_PIN), ESP_GPIO_WAKEUP_GPIO_LOW );
    // Enter the deep sleep mode.
    esp_deep_sleep_start();

    // The following statements will be not reached.
    while(1) { // Blink the LED repeatedly.
      digitalWrite( LED_PIN, state^=1 );
      delay(50);
    }
  } 
  else { // The button is hold pressed.
    Serial.begin( 115200 );
    delay(2000);
    Serial.println( "ESP32C3 is running normally." );
    digitalWrite( LED_PIN, LED_ON );
  }
}

void loop(){
}

 


กล่าวสรุป#

บทความนี้ได้นำเสนอรายละเอียดในเบื้องต้นสำหรับการเริ่มต้นใช้งานบอร์ด Seeeduino XIAO ESP32-C3 และได้สาธิตการทำงานของบอร์ดโดยการเขียนโปรแกรม Arduino Sketch เป็นตัวอย่าง

 


This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.

Created: 2023-09-16 | Last Updated: 2024-01-07