บทความนี้กล่าวถึงหลักการทำงานของโมดูลแปลงสัญญาณดิจิทัลเป็นแอนาล็อกแบบ 12 บิตจำนวน 2 ช่องสัญญาณที่ทำงานด้วยไอซี MCP4922 ด้วย MicroPython ของบอร์ด ml4m ผ่านทางบัส SPI เพื่อนำอออกสัญญาณแอนาล็อกเป็นรูปคลื่นสามเหลี่ยมและสี่เหลี่ยมดังภาพที่ 6 และ 7 ของตัวอย่างในบทความนี้
อุปกรณ์
อุปกรณ์สำหรับการทดลองในบทความนี้ประกอบด้วย
- ET-mini MCP4922 หรือไอซี MCP4922 ที่ต่อตามภาพที่ 2
- บอร์ดไมโครคอนโทรลเลอร์ esp32
MCP4922
คุณสมบัติ
- มีความละเอียดในการทำงานแปลงค่าดิจิทัลเป็นสัญญาณแอนาล็อกขนาด 12 บิต
- มีช่องนำออกสัญญาณแอนาล็อก 2 ช่องสัญญาณผ่านทาง OUT_A และ OUT_B
- ความเร็วสูงสุดในการสื่อสารผ่านบัส SPI อยู่ที่ 20MHz
- ใช้เวลาในการแปลงระดับแรงดันหรือสัญญาณแอนาล็อกประมาณ 45nsec
- ทำงานกับแรงดันกระแสงตรงที่ระดับแรงดัน 2V7 ถึง 5V5
- กำหนดการขยายสัญญาณได้ระหว่าง x1 และ x2
ผังการเชื่อมต่อ
การเชื่อมต่อระหว่าง MCP4922 กับ esp32 เป็นดังภาพที่ 2 คือ
- ขา SCK ของ MCP4922 ต่อเข้ากับขา IO18 ของ esp32
- ขา SDI ของ MCP4922 ต่อเข้ากับขา IO23 ของ esp32
- ขา CS ของ MCP4922 ต่อเข้ากับขา IO27 ของ esp32
การวางขา
ไอซี MCP4922 ที่ทางเราใช้เป็นไอซี 14 ขาที่มีการจัดวางขาเป็นดังภาพที่ 3
จากภาพที่ 3
- ขา SDI ใช้รับข้อมูลจากไมโครคอนโทรลเลอร์
- ขา CS สำหรับรับสัญญาณ CS
- ขา VOUTA สำหรับนำออกแรงดันจากช่องสัญญาณ A
- ขา VOUTB สำหรับนำออกแรงดันจากช่องสัญญาณ B
- ขา LDAC สำหรับส่งพัลส์เพื่อนำออกข้อมูลจากบัฟเฟอร์ไปยัง VOUTA หรือ VOUTB
- ขา SHDN สำหรับเปิดหรือปิดการทำงานของไอซี
- ขา VREFA และ VREFB สำหรับแรงดันอ้างอิงของช่องสัญญาณ A และ B
ผังการทำงาน
ผังการทำงานเป็นดังภาพที่ 4 โดยขาสำหรับควบคุมการทำงานจะเป็นขา SHDN ซึ่งเมื่อกำหนดให้ 0 จะส่งผลให้โมดูล MCP4922 หยุดทำงาน และถ้าเป็น 1 เป็นการสั่งให้ทำงาน หรือสั่งงานการเปิดหรือปิดการทำงานนี้ได้จากการกำหนดในชุดคำสั่งที่กล่าวถึงต่อไป นอกจากนี้การทำงานของ MCP4922 รองรับการเพิ่มระดับแรงดันแบบ 1 เท่า (x1) และ 2 เท่า (x2) โดยกำหนดจาก Gain Logic ซึ่งกำหนดค่าจากบิตคำสั่งเช่นเดียวกัน
การกำหนดระดับแรงดันนำออกของ VOUTA และ VOUTB ทำได้จากการกำหนดระดับแรงดันจากขา VREFA และ VREFB
ผังไม์ทมิง
ผังไทม์มิง (Timing Diagram) ของไอซี MCP4922 เป็นดังภาพที่ 5 ซึ่งการสั่งงานจะใช้การกำหนดคำสั่งผนวกเข้าไปใน 4 บิตแรกของข้อมูลที่ส่งไปยังขา MOSI ซึ่งจะกล่าวถึงในหัวข้อถัดไป
จากภาพที่ 5 จะได้ความสัมพันธ์ในการสั่งงาน คือ ก่อนเริ่มขา CS และ LDAC จะมีสถานะเป็น 1 และเมื่อให้โมดูลทำงานต้องเปลี่ยนสถานะของ CS เป็น 0 หลังจากนั้นทำการส่งข้อมูลผ่านทาง SI หรือขา MOSI ของไมโครคอนโทรลเลอร์ไล่เรียงจากไบต์บนสุดไปจนถึงบิตสุดท้ายของไบต์ต่ำสุดหลังจากนั้นยกระดับของขา CS กลับไปเป็น 1 ซึ่งตอนนี้ผู้เขียนโปรแกรมสามารถสั่งให้นำออกข้อมูลจากบัฟเฟอร์ไปที่ OUT_A หรือ OUT_B ด้วยการส่งพัลซ์ 1->0->1 จากขา LDAC หรือกำหนดให้ขา LDAC เป็นสถานะ 0 ตลอดเพื่อให้นำออกอัตโนมัติได้เช่นกัน
ชุดคำสั่ง
การสั่งงานโมดูล MCP4922 จะต้องใช้คำสั่งขนาด 4 บิตไบต์บนหรือบิตที่ 8 ถึง 15 เพื่อกำหนดการทำงานดังนี้
บิต | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 |
ความหมาย | ช่องสัญญาณ | การบัฟเฟอร์ค่า | Gain หรือระดับแรงดัน | เปิด/ปิดการทำงานของไอซี | ข้อมูลบิตที่11 | ข้อมูลบิตที่10 | ข้อมูลบิตที่9 | ข้อมูลบิตที่8 |
ค่า | 0 ช่อง A 1 ช่อง B | 0 ไม่ทำบัฟเฟอร์ 1 ให้ทำบัฟเฟอร์ไว้ | 0 ใช้ระดับแรงดัน x2 1 ใช้ระดับแรงดัน x1 | 0 ปิดการทำงาน 1 เปิดการทำงาน |
และสำหรับไบต์ล่างหรือบิตที่ 0 ถึง 7 เป็นดังนี้
บิต | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
ความหมาย | ข้อมูลบิตที่7 | ข้อมูลบิตที่6 | ข้อมูลบิตที่5 | ข้อมูลบิตที่4 | ข้อมูลบิตที่3 | ข้อมูลบิตที่2 | ข้อมูลบิตที่1 | ข้อมูลบิตที่0 |
ตัวอย่างโปรแกรม
ตัวอย่างโปรแกรมการส่งเวฟสามเหลี่ยม หรือเริ่มจาก 0 ไปหา 4095 และลดลงจาก 4094 มาที่ 0 เขียนโค้ดได้ดังนี้
######################################################################
#
# MCP4922 12-bit ADC with SPI Interface
#
# (C) 2021, JarutEx
# https://www.jarutex.com
######################################################################
from machine import SPI, Pin, ADC
import time
pinCS = Pin(27, Pin.OUT)
pinCS.on()
spi = SPI(1,baudrate=20000000,sck=Pin(18,Pin.OUT),mosi=Pin(23,Pin.OUT),miso=Pin(19,Pin.IN))
try:
dacData = 0
dacDir = 0
while True:
x2 = 0b0111000000000000
x2 |= (dacData & 0b0000111111111111)
buffer = x2.to_bytes(2,'big')
pinCS.off()
spi.write(buffer)
pinCS.on()
if (dacDir):
dacData -= 1
if (dacData < 0):
dacData = 1
dacDir = 0
else:
dacData += 1
if (dacData > 4095):
dacData = 4094
dacDir = 1
time.sleep_us(10)
except KeyboardInterrupt:
pass
tmr0.deinit()
spi.deinit()
ตัวอย่างผลลัพธ์เป็นดังภาพที่ 6
ตัวอย่างถัดมาเป็นการสร้างคลื่นสี่เหลี่ยมดังตัวอย่างผลลัพธ์ภาพที่ 7
######################################################################
#
# MCP4922 12-bit ADC with SPI Interface
#
# (C) 2021, JarutEx
# https://www.jarutex.com
######################################################################
from machine import SPI, Pin, ADC
import time
spi = SPI(1,baudrate=20000000,sck=Pin(18,Pin.OUT),mosi=Pin(23,Pin.OUT),miso=Pin(19,Pin.IN))
pinCS = Pin(27, Pin.OUT)
pinCS.on()
try:
dacData = 0
dacDir = 0
while True:
dacData = 4000
x2 = ((dacData & 0b0000111111111111) | 0b0111000000000000)
buffer = x2.to_bytes(2,'big')
pinCS.off()
spi.write(buffer)
pinCS.on()
time.sleep_ms(500)
dacData = 100
x2 = ((dacData & 0b0000111111111111) | 0b0111000000000000)
buffer = x2.to_bytes(2,'big')
pinCS.off()
spi.write(buffer)
pinCS.on()
time.sleep_ms(500)
except KeyboardInterrupt:
pass
tmr0.deinit()
spi.deinit()
สรุป
จากบทความนี้ทางทีมงานของเราหวังว่าผู้อ่านจะสามารถนำการใช้โมดูล DAC ไปใช้กับบอร์ดไมโครคอนโทรลเลอร์ต่อไปในอนาคน ซึ่งจะพบว่าการสั่งงานนั้นง่ายเนื่องจาก MCP4922 มีวิธีการสั่งงานที่ไม่ซับซ้อนด้วยการกำหนดค่า 4 บิตแรกของข้อมูลที่ส่งไปในบัส SPI เพื่อเลือกช่องสัญญาณ การทำบัฟเฟอร์ การเกน และการสั่งเปิดหรือปิดการทำงานของช่องสัญญาณนั้น และขอให้สนุกกับการเขียนโปรแกรมครับ
ท่านใดต้องการพูดคุยสามารถคอมเมนท์ไว้ได้เลยครับ
แหล่งอ้างอิง
(C) 2020-2021, โดย อ.ดนัย เจษฎาฐิติกุล/อ.จารุต บุศราทิจ
ปรับปรุงเมื่อ 2021-09-12, 2021-11-29