สารบัญ:

วิธีสร้างและทดสอบ DAC ที่ดีขึ้นด้วย ESP32: 5 ขั้นตอน
วิธีสร้างและทดสอบ DAC ที่ดีขึ้นด้วย ESP32: 5 ขั้นตอน

วีดีโอ: วิธีสร้างและทดสอบ DAC ที่ดีขึ้นด้วย ESP32: 5 ขั้นตอน

วีดีโอ: วิธีสร้างและทดสอบ DAC ที่ดีขึ้นด้วย ESP32: 5 ขั้นตอน
วีดีโอ: ESP32 เริ่มต้นใช้งานครั้งแรก | Arduino#64 | #เฮ็ดสิดี 2024, พฤศจิกายน
Anonim
วิธีสร้างและทดสอบ DAC ที่ดีขึ้นด้วย ESP32
วิธีสร้างและทดสอบ DAC ที่ดีขึ้นด้วย ESP32
วิธีสร้างและทดสอบ DAC ที่ดีขึ้นด้วย ESP32
วิธีสร้างและทดสอบ DAC ที่ดีขึ้นด้วย ESP32

ESP32 มีตัวแปลงดิจิทัลเป็นอนาล็อก (DAC) 8 บิต 2 ตัว DAC เหล่านี้ช่วยให้เราสร้างแรงดันไฟฟ้าตามอำเภอใจได้ภายในช่วงที่กำหนด (0-3.3V) ด้วยความละเอียด 8 บิต ในคำแนะนำนี้ ฉันจะแสดงวิธีสร้าง DAC และกำหนดลักษณะการทำงานของมัน รวมทั้งเปรียบเทียบกับ ESP32 DAC ดัชนีประสิทธิภาพฉันจะดูรวมถึง

  • ระดับเสียง
  • แบนด์วิดธ์
  • ความไม่เชิงเส้นเชิงปริพันธ์
  • ความไม่เชิงเส้นเชิงอนุพันธ์

เพื่อทดสอบดัชนีเหล่านี้ ฉันจะใช้ ADS1115

สิ่งสำคัญคือต้องทราบว่าการประเมินดัชนีทั้งหมดของคุณจะแม่นยำเท่ากับอุปกรณ์อ้างอิงของคุณเท่านั้น (ในกรณีนี้คือ ADS115) ตัวอย่างเช่น ADS115 ไม่มีความแม่นยำ 16 บิตเมื่อพูดถึงการชดเชยแรงดันไฟฟ้าและอัตราขยาย ข้อผิดพลาดเหล่านี้อาจมีขนาดใหญ่ถึง 0.1% สำหรับระบบจำนวนมาก ข้อผิดพลาดเหล่านี้สามารถละเลยได้เมื่อมีความกังวลอย่างจำกัดถึงความถูกต้องสมบูรณ์

เสบียง

  • ADS1115
  • บอร์ด ESP32
  • เขียงหั่นขนม
  • สายจัมเปอร์
  • ตัวต้านทาน 5 kOhm
  • ตัวเก็บประจุเซรามิกไมโครฟารัด 1 ตัว

ขั้นตอนที่ 1: วางเขียงหั่นขนม

วางเขียงหั่นขนม
วางเขียงหั่นขนม

ต่อหมุดต่อไปนี้

ระหว่าง ESP32 และ ADS1115

3v3 VDD

GND GND

GPIO22 SCL

GPIO21 SDA

ที่ ADS1115

ADDR GND (ADS115)

การทำ DAC

มีหลายวิธีในการสร้าง DAC วิธีที่ง่ายที่สุดคือกรองสัญญาณความถี่ต่ำผ่านสัญญาณ PWM พร้อมตัวต้านทานและตัวเก็บประจุ ฉันสามารถเพิ่ม op-amp ที่นี่เป็นบัฟเฟอร์ได้ แต่ต้องการให้สิ่งต่าง ๆ ง่ายขึ้น การออกแบบนี้ง่ายและราคาถูกในการใช้งานกับไมโครคอนโทรลเลอร์ที่รองรับ PWM ฉันจะไม่พูดถึงทฤษฎีการออกแบบที่นี่ (google PWM DAC)

เพียงเชื่อมต่อตัวต้านทาน GPIO255 KOhm 1 microFarad Capacitor gnd

ตอนนี้เชื่อมต่อสายจัมเปอร์จากจุดที่ตัวต้านทานตรงกับตัวเก็บประจุถึง A0 บน ADS115

ขั้นตอนที่ 2: ประเมินสัญญาณถึงระดับเสียงรบกวน

ประเมินสัญญาณถึงระดับเสียงรบกวน
ประเมินสัญญาณถึงระดับเสียงรบกวน

ในการประเมินระดับเสียง ให้เรียกใช้สคริปต์ด้านล่าง ในการประเมินสิ่งนี้ เราเพียงแค่ปล่อยให้ DAC เป็นค่าคงที่และวัดว่าแรงดันไฟฟ้าผันผวนอย่างไรเมื่อเวลาผ่านไป

เนื่องจากการออกแบบ DAC เสียงรบกวนจะสูงสุดเมื่อสัญญาณ PWM อยู่ที่ 50% รอบการทำงาน ดังนั้นนี่คือที่ที่เราจะประเมิน เราจะประเมิน ESP32 ที่ระดับสัญญาณเดียวกันนี้ด้วย นอกจากนี้เรายังจะกรอง ESP32 DAC ด้วยตัวกรองความถี่ต่ำเดียวกัน เพื่อให้สามารถเปรียบเทียบการวัดได้

สำหรับฉันผลลัพธ์นั้นชัดเจน การออกแบบ PWM มี SNR ที่ดีกว่า >6dB (ดีกว่า 2 เท่า) ชัยชนะที่ชัดเจนสำหรับ DAC ใหม่ ความสับสนเล็กน้อยประการหนึ่งคือมีตัวกรองที่สร้างขึ้นใน ADC ที่เพิ่มประสิทธิภาพ SNR ได้อย่างแน่นอนที่สุด ดังนั้นค่าสัมบูรณ์อาจตีความได้ยาก ถ้าฉันใช้ตัวกรองอันดับสอง จะไม่เป็นเช่นนั้น

รหัสอยู่ด้านล่าง

#รวม

#include โฆษณา Adafruit_ADS1115; // ห้องสมุด adafruit สำหรับ adc int16_t adc0; // การตั้งค่าเป็นโมฆะ (เป็นโมฆะ) { Serial.begin (115200); // เริ่มโฆษณาแบบอนุกรม setGain(GAIN_TWO); // 2x ได้รับ +/- 2.048V 1 บิต =0.0625mV ads.begin(); // เริ่ม adc float M = 0; // ค่าเฉลี่ยเริ่มต้นลอย Mp = 0; // previouos หมายถึง float S = 0; // ความแปรปรวนเริ่มต้นลอย Sp = 0; // ความแปรปรวนก่อนหน้า const int reps = 500; // จำนวนการทำซ้ำ int n = 256; // จำนวนตัวอย่าง ledcSetup(0, 25000, 8); // ตั้งค่า pwm frequecny =25000 Hz ที่ความละเอียด 8 บิต ledcAttachPin(25, 0); // ตั้งค่า pwm บนพิน 25 ledcWrite(0, 128); // ตั้งค่าเป็นครึ่งรอบการทำงาน (เสียงรบกวนที่ใหญ่ที่สุด) ล่าช้า (3000); // รอการชำระเวลา float snrPWM[reps]; // อาร์เรย์ของ snrs สำหรับ PWM float snrDAC[reps]; // อาร์เรย์ของ snrs สำหรับ DAC สำหรับ (int i = 0; i < reps; i++) { // loope over repititions for (int k = 1; k < (n + 1); k++) { // loope เหนือตัวอย่าง adc0 = ads.readADC_SingleEnded(0); // อ่าน M = Mp + (adc0 - Mp) / k; // คำนวณค่าเฉลี่ยกลิ้ง Mp = M; // ตั้งค่าค่าเฉลี่ยก่อนหน้า S = Sp + (adc0 - Mp) * (adc0 - M); // คำนวณความแปรปรวนการกลิ้ง Sp = S; // ตั้งค่าความแปรปรวนก่อนหน้า } // snr เป็น dB snrPWM = 20 * log10(3.3 / (sqrt(S / n) *.0625 *.001)); // รีเซ็ตค่า M = 0; Mp = 0; ส = 0; Sp = 0; } ledcDetachPin(25); // ถอด PWM ออกจากพิน 25 dacWrite (25, 128); // เขียนไปยัง DAC ล่าช้า (3000); // รอชำระ (int i = 0; i < reps; i++) { // เหมือนกับ PWM loop for (int k = 1; k < (n + 1); k++) { adc0 = ads.readADC_SingleEnded (0); M = Mp + (adc0 - Mp) / k; Mp = ม; S = Sp + (adc0 - Mp) * (adc0 - M); Sp = S; } snrDAC = 20 * log10(3.3 / (sqrt(S / n) *.0625 *.001)); ม = 0; Mp = 0; ส = 0; Sp = 0; } // พล็อต SNR บนกราฟเดียวสำหรับ (int i = 1; i < reps; i++) { Serial.print("PWM_SNR(dB):"); Serial.print(snrPWM[ผม]); Serial.print(", "); Serial.print("ESP32_SNR(dB):"); Serial.println(snrDAC); } } โมฆะลูป (โมฆะ) { }

ขั้นตอนที่ 3: ความไม่เชิงเส้นเชิงปริพันธ์และความไม่เชิงเส้นเชิงอนุพันธ์

ความไม่เชิงเส้นเชิงปริพันธ์และความไม่เชิงเส้นเชิงอนุพันธ์
ความไม่เชิงเส้นเชิงปริพันธ์และความไม่เชิงเส้นเชิงอนุพันธ์

ความไม่เชิงเส้นเชิงปริพันธ์คือการวัดค่าความเบี่ยงเบนโดยประมาณระหว่างแรงดันเอาต์พุต DAC กับเส้นตรงของคุณ ยิ่งโตยิ่งแย่…

ความไม่เชิงเส้นเชิงอนุพันธ์คือการวัดคร่าวๆ ว่าการเปลี่ยนแปลงของแรงดันไฟฟ้าที่สังเกตได้ (จากโค้ดหนึ่งไปยังโค้ดถัดไป) เบี่ยงเบนไปจากสิ่งที่คาดหวังจากเส้นตรงมากน้อยเพียงใด

ผลลัพธ์ที่นี่น่าสนใจจริงๆ อย่างแรกเลย ทั้งคู่มีข้อผิดพลาดน้อยกว่า 0.5lsb (ที่ความละเอียด 8 บิต) ซึ่งถือว่าดี แต่ PWM มีความเป็นเส้นตรงของอินทิกรัลที่ดีกว่ามาก ทั้งสองมีความไม่เชิงเส้นเชิงอนุพันธ์ที่เปรียบเทียบกันได้ แต่ ESP32 DAC มีหนามแหลมที่แปลกประหลาดมาก ยิ่งไปกว่านั้น วิธี PWM มีโครงสร้างบางอย่างเกี่ยวกับข้อผิดพลาด โดยพื้นฐานแล้วจะเกินและ undershoots แรงดันไฟฟ้าที่ถูกต้องในแบบสลับกัน

ความสงสัยของฉันคือนี่เป็นข้อผิดพลาดในการปัดเศษแปลก ๆ ในการสร้างสัญญาณ PWM 8 บิตบน ESP32

วิธีหนึ่งในการแก้ไขปัญหานี้คือวนรอบอย่างรวดเร็วระหว่างสองรหัสที่อยู่ติดกัน (เช่น 128, 129) กับ PWM ด้วยตัวกรองสัญญาณความถี่ต่ำแบบอะนาล็อก ข้อผิดพลาดที่ได้จะเฉลี่ยเป็นศูนย์ ฉันจำลองสิ่งนี้ในซอฟต์แวร์และข้อผิดพลาดทั้งหมดหายไปอย่างแน่นอน ตอนนี้วิธี PWM มีความเป็นเส้นตรงที่แม่นยำถึง 16 บิต!

ใครก็ตามที่รหัสเพื่อสร้างข้อมูลอยู่ด้านล่าง เอาต์พุตจะอยู่บนจอภาพอนุกรมในรูปแบบ.csv เพียงคัดลอกไปยังไฟล์ข้อความเพื่อดำเนินการต่อไป

#รวม

#include โฆษณา Adafruit_ADS1115; /* ใช้สำหรับเวอร์ชัน 16 บิต */ int16_t adc0; การตั้งค่าเป็นโมฆะ (เป็นโมฆะ) { Serial.begin (115200); ads.setGain(GAIN_ONE); // 2x ได้รับ +/- 2.048V 1 บิต = 1mV 0.0625mV ads.begin(); ledcSetup(0, 25000, 8); ledcAttachPin(25, 0); Serial.println("คาดหวัง, สังเกต"); ledcWrite(0, 2); ล่าช้า (3000); สำหรับ (int i = 2; i <255; i++) { ledcWrite(0, i); ล่าช้า (100); adc0 = ads.readADC_SingleEnded(0); ลอยตัว = (i / 256.0 * 3.3) / 4.096 * 32767; Serial.print (คาดว่า); Serial.print(", "); Serial.println(adc0); } } โมฆะลูป (โมฆะ) { }

ขั้นตอนที่ 4: แบนด์วิดท์

แบนด์วิดธ์
แบนด์วิดธ์

ฉันจะกำหนดแบนด์วิดธ์ตามความถี่ที่เอาต์พุตของ DAC ลดลง 3dB นี่เป็นอนุสัญญาและในระดับหนึ่งโดยพลการ ตัวอย่างเช่น ที่จุด 6dB DAC จะยังคงส่งสัญญาณออก โดยจะมีแอมพลิจูดประมาณ 50%

เพื่อวัดสิ่งนี้ เราเพียงแค่ส่งคลื่นไซน์ที่ความถี่ที่เพิ่มขึ้นจาก DAC ไปยัง ADC และวัดค่าเบี่ยงเบนมาตรฐานของพวกมัน ไม่น่าแปลกใจเลยที่จุด 3dB อยู่ที่ 30Hz (1/(2*pi*5000*1e-6))

ESP32 สามารถทำตัวอย่างได้ 1 เมกะต่อวินาที นี่เป็นชัยชนะแบบลงมือสำหรับ ESP32 แอมพลิจูดของมันไม่ลดลงเลยในพื้นที่ทดสอบแบนด์วิดท์ 100Hz

รหัสด้านล่างสามารถทดสอบแบนด์วิดท์ PWM DAC

#รวม

#include โฆษณา Adafruit_ADS1115; /* ใช้สำหรับเวอร์ชัน 16 บิต */ int16_t adc0; int16_t adc1; การตั้งค่าเป็นโมฆะ (เป็นโมฆะ) { float M; ลอย Mp = 0; ลอย S = 0; ลอย Sp = 0; Serial.begin(115200); ads.setGain(GAIN_ONE); // 1x ได้รับ +/- 4.096V 1 บิต = 2mV 0.125mV ads.begin(); ledcSetup(0, 25000, 8); ledcAttachPin(25, 0); ล่าช้า (5000); Serial.println("ความถี่, แอมพลิจูด"); สำหรับ (int i = 1; i <100; i++) { unsigned long start = millis(); ยาวที่ไม่ได้ลงนาม T = millis(); Sp = 0; ส = 0; ม = 0; Mp = 0; int k = 1; บรรทัดฐานลอย ในขณะที่ ((T - start) < 1000) { int out = 24 * sin(2 * PI * i * (T - start) / 1000.0) + 128; ledcWrite(0, ออก); adc0 = ads.readADC_SingleEnded(0); M = Mp + (adc0 - Mp) / k; Mp = ม; S = Sp + (adc0 - Mp) * (adc0 - M); Sp = S; T = มิลลิวินาที (); เค++; } if (i == 1) { norm = sqrt(S / k); } Serial.print(i); Serial.print(", "); Serial.println(sqrt(S / k) / บรรทัดฐาน 3); k = 0; } } โมฆะลูป (โมฆะ) { }

และรหัสนี้จะทดสอบแบนด์วิดธ์ ESP32 ตรวจสอบให้แน่ใจว่าได้ถอดตัวเก็บประจุออก ไม่เช่นนั้นผลลัพธ์จะเหมือนกันสำหรับทั้งสองวิธี

#รวม

#include โฆษณา Adafruit_ADS1115; /* ใช้สำหรับเวอร์ชัน 16 บิต */ int16_t adc0; int16_t adc1; การตั้งค่าเป็นโมฆะ (เป็นโมฆะ) { float M; ลอย Mp = 0; ลอย S = 0; ลอย Sp = 0; Serial.begin(115200); ads.setGain(GAIN_ONE); // 1x ได้รับ +/- 4.096V 1 บิต = 2mV 0.125mV ads.begin(); ล่าช้า (5000); Serial.println("ความถี่, แอมพลิจูด"); สำหรับ (int i = 1; i <100; i++) { unsigned long start = millis(); ยาวที่ไม่ได้ลงนาม T = millis(); Sp = 0; ส = 0; ม = 0; Mp = 0; int k = 1; บรรทัดฐานลอย ในขณะที่ ((T - start) < 1000) { int out = 24 * sin(2 * PI * i * (T - start) / 1000.0) + 128; dacWrite(25, ออก); adc0 = ads.readADC_SingleEnded(0); M = Mp + (adc0 - Mp) / k; Mp = ม; S = Sp + (adc0 - Mp) * (adc0 - M); Sp = S; T = มิลลิวินาที (); เค++; } if (i == 1) { norm = sqrt(S / k); } Serial.print(i); Serial.print(", "); Serial.println(sqrt(S / k) / บรรทัดฐาน 3); k = 0; } } โมฆะลูป (โมฆะ) { }

ขั้นตอนที่ 5: ปิดความคิด

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

นอกจากนี้ ฉันคิดว่ามันคุ้มค่าที่จะชี้ให้เห็นที่นี่ว่าเนื่องจากเอาต์พุต PWM มีสัญญาณรบกวนต่ำ ด้วยความเป็นเส้นตรงที่ยอดเยี่ยม จึงควรเป็นไปได้ที่จะสร้าง DAC ที่มีความละเอียดสูงกว่ามากด้วยเอาต์พุต PWM (อาจมีความแม่นยำถึง 16 บิต) นั่นจะใช้เวลาทำงาน ถึงเวลานั้น ฉันขอลาก่อน!

แนะนำ: