ESP32 with Dual-Channel DAC Output
ตัวอย่างการเขียนโค้ดไมโครไพธอน สำหรับ ESP32 เพื่อสร้างสัญญาณเอาต์พุต โดยใช้วงจร DAC (Digital-to-Analog Converter) ที่อยู่ภายใน ESP32 จำนวน 2 ช่องสัญญาณ
การใช้งาน DAC ของ ESP32
ถ้าต้องการใช้งานวงจร DAC ภายในชิป ESP32 ก็มี 2 ช่องสัญญาณสำหรับขา I/O ให้เลือกใช้ได้ และในส่วนการเขียนโค้ดไมโครไพธอน ก็มีคำสั่งในไลบรารี machine.DAC
ไว้ใช้งานร่วมกับ machine.Pin
เมื่อแปลงข้อมูลเป็นสัญญาณไฟฟ้า จะได้แรงดันไฟฟ้าในช่วง 0V และไม่เกิน +3.3V (VCC) แต่ความละเอียดของข้อมูลเอาต์พุตสำหรับ DAC ของ ESP32 นั้น มีขนาดเพียง 8 บิต ดังนั้นจึงเขียนค่าเป็นจำนวนเต็มได้ในช่วง 0..255 เท่านั้น
การสร้างสัญญาณรูปไซน์ (Sine Wave Generation)
ถ้าเราต้องการจะสร้างเอาต์พุตให้มีลักษณะเป็นรูปคลื่นสัญญาณไซน์โดยใช้ ESP32 แต่มีแรงดันไฟฟ้าอยู่ระหว่าง 0V แต่ไม่เกิน +3.3V จะเขียนโค้ดอย่างไร ?
ถ้าสร้างสัญญาณรูปคลื่นไซน์ได้ (Sinusoidal Waveform) และมีจำนวนสองฟังก์ชันที่ขึ้นกับตัวแปรเวลา t แล้วนำมากำหนดพิกัด (x(t),y(t)) ในการวาดกราฟแบบพาราเมตริก (Parametric Plot) ก็จะเป็นการวาดเส้นโค้งให้ได้รูปที่เรียกว่า “Lissajous Figures” (“รูปลิสซาจูส์”)
กำหนดให้ฟังก์ชันทั้งสองมีความต่างเฟสกัน (เช่น ให้มีความต่างเฟสกัน 90 องศา) อาจมีความถี่เท่ากันหรือต่างกัน (แต่เป็นอัตราส่วนที่เป็นจำนวนตรรกยะ)
ลองมาดูตัวอย่างการสร้างฟังก์ชันสำหรับ x(t) และ y(t) ให้เป็นรูปแบบฟังก์ชันไซน์ ในกรณีนี้ ค่าของ x(t) และ y(t) จะอยู่ระหว่าง -A และ A ถ้า A > 0 ซึ่งเป็นค่าแอมพลิจูดของฟังก์ชันทั้งสอง
ถ้าให้ผลต่างเฟส (Phase Difference) เท่ากับ 90 องศา ก็จะเขียนใหม่ได้เป็น
แต่ถ้าจะนำไปวาดรูปกราฟด้วยคอมพิวเตอร์หรือประมวลผลเชิงตัวเลข ตัวแปร t จะถูกแทนที่ด้วยตัวแปร i ที่เป็นเลขจำนวนเต็ม (เป็น discrete-time steps) เช่น อยู่ในช่วง 0 ถึง (N-1) สำหรับลำดับของข้อมูลหรือจุดพิกัดที่มีจำนวนเท่ากับ N
ดังนั้นเราสามารถสร้างฟังก์ชันสำหรับพิกัด (x,y) ที่ขึ้นอยู่กับตัวแปร i ที่เป็นเลขจำนวนเต็ม (เป็น index แทนการใช้ตัวแปร t) ตามรูปสมการดังนี้
ถ้าให้ N เป็นเลขจำนวนเต็มบวก เราสามารถสร้างอาร์เรย์เพื่อเก็บค่าที่คำนวณไว้ล่วงหน้า ใช้เป็นตารางค่าคงที่ (Lookup Table) หรือบางทีก็เรียกว่า Waveform Table ดังนั้นเวลาจะสร้างสัญญาณเอาต์พุต ก็อ่านค่าตัวเลขดังกล่าวไปตามลำดับจนครบแล้ววนซ้ำ
ข้อสังเกต: การเลือกค่าสำหรับ N จะมีผลต่อขนาดของตารางและการใช้หน่วยความจำของไมโครคอนโทรลเลอร์ และเมื่อคำนวณค่าสำหรับ (x,y) จะต้องกำหนดให้เป็นค่าเลขจำนวนเต็ม และอยู่ในช่วง 0..255 (มีค่ากลางเท่ากับ 127) และเมื่อนำไปบวกหรือลบกับ A (แอมพลิจูด) จะต้องอยู่ในช่วงดังกล่าว เมื่อจะนำไปใช้กับ DAC ของ ESP32
อย่างไรก็ตาม เอาต์พุตที่ได้และเมื่อแปลงเป็นแรงดันไฟฟ้าแล้ว มีค่าไม่ต่อเนื่อง (Discrete Values) ในเชิงแอมพลิจูด ( ถ้าไม่มีวงจรกรองสัญญาณที่เรียกว่า Smoothing Filter )
ตัวอย่างการเขียนโค้ด
ในโค้ดตัวอย่างนี้ เราจะใช้ตัวแปร index
เริ่มนับขึ้นจาก 0 ไปจนถึง (N-1)
แล้ววนซ้ำเริ่มใหม่ ค่าของตัวแปรนี้จะถูกใช้ในการอ่านค่าจากอาร์เรย์ sin_table
และ cos_table
ที่ได้มีการคำนวณค่าเก็บไว้ก่อนแล้วหลังจากได้ทำคำสั่งในฟังก์ชัน create_wave_tables()
ค่าที่อ่านได้จากตารางตามตำแหน่งที่อ้างอิงด้วยตัวแปร index
ในแต่ละครั้ง จะถูกนำไปใช้เป็นค่าเอาต์พุต DAC จำนวน 2 ช่องสัญญาณตามลำดับ การทำงานในลูปแต่ละรอบ จะไม่มีการหน่วงเวลา และความถี่ของสัญญาณเอาต์พุตที่ได้ จะขึ้นอยู่กับความเร็วในการประมวลผลของ ESP32 ที่เขียนโค้ดด้วยไมโครไพธอน
ในโค้ดตัวอย่างนี้ ได้เลือกใช้ค่า N=200, A=100, P=2 และ Q=3
การหยุดการทำงานของโค้ด ทำได้โดยการกดปุ่มที่ต่อกับขา GPIO-37 (ทำงานแบบ Active-Low) และถ้าใช้อุปกรณ์ M5Stack-Core ก็จะตรงกับปุ่ม Button C (BtnC)
ถัดไปลองเปลี่ยนมาใช้ Hardware Timer ของ ESP32 เป็นตัวกำหนดจังหวะการเขียนค่าเอาต์พุตให้ DAC จะเขียนโค้ดอย่างไร มาดูตัวอย่างกัน
ในโค้ดตัวอย่างนี้ เราใช้คำสั่งที่เกี่ยวข้องกับ machine.Timer
เพื่อเปิดใช้งาน Hardware Timer
(เลือกใช้หมายเลข 4 )
การทำงานของไทม์เมอร์ (Timer) เป็นแบบ periodic คือ จะทำให้เกิดอินเทอร์รัพท์จากไทม์เมอร์ซ้ำอีก โดยระบุคาบ (Period) เป็นตัวเลขจำนวนเต็มบวก (หน่วยเป็น มิลลิวินาที)
เมื่อเกิดอินเทอร์รัพท์ในแต่ละครั้ง และฟังก์ชัน Callback (Interrupt Handler) ที่เกี่ยวข้องจะคอยทำหน้าที่อ่านค่าจากตารางค่าคงที่ตามลำดับของ index แล้วเขียนค่าเอาต์พุตสำหรับ DAC ทั้งสองช่อง
ถ้ากำหนดให้ N=200 และคาบเวลาเท่ากับ 1 msec จะได้สัญญาณเอาต์พุต (ไซน์) ที่มีคาบเท่ากับ 200 msec หรือมีความถี่เท่ากับ 5 Hz (กำหนดให้ P=Q=1)
ถ้าเราลองวัดสัญญาณที่ขาเอาต์พุตของ DAC ทั้งสองช่อง ที่ขา GPIO-25 และ GPIO-26 โดยใช้เครื่องออสซิลโลสโคป และเลือกโหมดการแสดงผลเป็นแบบ X-Y แทนการใช้โหมด Y-T และเลือก Coupling Mode เป็นแบบ AC จะได้รูปตามตัวอย่างดังนี้ (ถ้ามีโอกาสได้ทดลองกับอุปกรณ์จริง ให้ทดลองเปลี่ยนค่า P และ Q)
เราสามารถนำไปเปรียบเทียบรูปคลื่นสัญญาณที่สร้างจากเครื่องกำเนิดสัญญาณ (Function Generator) แบบสองช่องเอาต์พุต
โค้ดวาดรูปกราฟสำหรับ ESP32-M5Stack
จากการกำหนดรูปแบบของฟังก์ชันสำหรับพิกัด (x,y) เราก็มาดูตัวอย่างการเขียนโค้ดไมโครไพธอน เพื่อลองวาดรูปกราฟ และแสดงผลบนจอ LCD ขนาด 320x240 ของอุปกรณ์ M5Stack-Core (ESP32-based) โดยมีการสุ่มค่า P และ Q ให้เป็นจำนวนเต็มในช่วง 1..10 ดังนั้นรูปกราฟหรือเส้นโค้ง (Curve) ที่ได้ จะแตกต่างกันไปตามอัตราส่วน P:Q
ถ้าเราใช้ API หรือไลบรารีของ M5Stack สำหรับภาษาไมโครไพธอน ก็มีคำสั่ง lcd.drawPixel()
เพื่อวาดจุดหนึ่งพิกเซลบนสกรีน (Screen) โดยระบุตำแหน่งหรือค่า (x,y)
ถ้าต้องการเชื่อมต่อจุดเหล่านั้นที่อยู่ถัดไปตามลำดับด้วยเส้นตรง ก็สามารถใช้คำสั่ง lcd.drawLine()
พร้อมกำหนดสีของเส้นตรงนั้นได้ด้วย
ในโค้ดตัวอย่างนี้ ได้กำหนดให้ N=256 และ A=100
โค้ดนี้จะทำงานต่อเนื่องไปเรื่อย ๆ ถ้าต้องการหยุดการทำงาน ให้กดปุ่มแล้วปล่อยที่ Button C (BtnC) ของ M5 Stack
กล่าวสรุป
เราได้เห็นตัวอย่างการเขียนโค้ดไมโครไพธอนสำหรับ ESP32 เพื่อสร้างสัญญาณเอาต์พุตเป็นรูปคลื่นไซน์ โดยใช้ DAC จำนวน 2 ช่อง เพื่อวาดรูปเส้นโค้ง Lissajous แล้ววัดสัญญาณด้วยเครื่องออสซิลโลสโคป เพื่อดูคลื่นสัญญาณที่ได้ในโหมด XY และได้สาธิตการเขียนโค้ดเพื่อวาดรูปเส้นโค้ง Lissajous และแสดงผลบนจอ LCD ของอุปกรณ์ M5Stack Core
เผยแพร่ภายใต้ลิขสิทธิ์ Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)
Last updated