İçindekiler:
- Gereçler
- Adım 1: Breadboard'u Yerleştirme
- Adım 2: Sinyali Gürültü Seviyesine Göre Değerlendirin
- Adım 3: İntegral Doğrusal Olmayanlık ve Diferansiyel Doğrusal Olmayanlık
- 4. Adım: Bant Genişliği
- Adım 5: Düşünceleri Kapatmak
Video: ESP32 ile Daha İyi Bir DAC Nasıl Yapılır ve Test Edilir: 5 Adım
2024 Yazar: John Day | [email protected]. Son düzenleme: 2024-01-30 13:17
ESP32'de 2 adet 8 bit Dijital - Analog Dönüştürücüler (DAC'ler) bulunur. Bu DAC'ler, 8 bit çözünürlükte belirli bir aralıkta (0-3.3V) isteğe bağlı voltajlar üretmemizi sağlar. Bu Eğitilebilir Kitapta, size bir DAC'nin nasıl oluşturulacağını ve performansını karakterize etmenin yanı sıra ESP32 DAC ile karşılaştırmayı göstereceğim. Bakacağım performans endeksleri şunları içeriyor:
- Gürültü seviyesi
- Bant genişliği
- integral doğrusal olmama
- diferansiyel doğrusal olmama
Bu endeksleri test etmek için ADS1115'i kullanacağım.
Tüm bu endekslere ilişkin değerlendirmenizin yalnızca referans cihazınız (bu durumda ADS115) kadar doğru olacağını belirtmek önemlidir. Örneğin, ADS115, voltaj ofseti ve kazancı söz konusu olduğunda 16 bit hassasiyete sahip değildir. Bu hatalar %0,1 kadar büyük olabilir. Mutlak doğruluk sınırlı endişe olduğunda birçok sistem için bu hatalar göz ardı edilebilir.
Gereçler
- ADS1115
- ESP32 Kurulu
- ekmek tahtası
- atlama telleri
- 5 kOhm Direnç
- 1 mikro-Farad seramik kondansatör
Adım 1: Breadboard'u Yerleştirme
Aşağıdaki pinleri bağlayın
ESP32 ve ADS1115 arasında
3v3 VDD
GND GND
GPIO22 SCL
GPIO21 SDA'sı
ADS1115'te
ADDR GND (ADS115)
DAC'yi yapmak
DAC yapmanın birçok yolu vardır. En basiti, bir direnç ve bir kapasitör ile bir PWM sinyalini düşük geçişli filtrelemektir. Buraya tampon olarak bir op-amp ekleyebilirdim ama işleri basit tutmak istedim. Bu tasarım, PWM'yi destekleyen herhangi bir mikrodenetleyici ile uygulanması basit ve ucuzdur. Burada tasarım teorisinden geçmeyeceğim (google PWM DAC).
Sadece GPIO255 KOhm direnç 1 microFarad Kapasitör gnd'yi bağlayın
Şimdi direncin kondansatörle buluştuğu noktadan ADS115'teki A0'a bir aktarma kablosu bağlayın.
Adım 2: Sinyali Gürültü Seviyesine Göre Değerlendirin
Gürültü seviyesini değerlendirmek için aşağıdaki komut dosyasını çalıştırmanız yeterlidir. Bunu değerlendirmek için DAC'yi sabit bir değerde bırakıyoruz ve voltajın zaman içinde nasıl salındığını ölçüyoruz.
DAC'nin tasarımı nedeniyle, PWM sinyali %50 görev döngüsündeyken gürültü en büyük olacaktır. Bu nedenle değerlendireceğimiz yer burasıdır. ESP32'yi de aynı sinyal seviyesinde değerlendireceğiz. Ayrıca ölçümü karşılaştırılabilir kılmak için ESP32 DAC'yi aynı düşük geçiş filtresiyle filtreleyeceğiz.
Benim için çıktı açıktı. PWM tasarımı >6dB daha iyi SNR'ye sahipti (2 kat daha iyi). Yeni DAC için net bir galibiyet. Hafif bir karışıklık, ADC'de SNR'yi kesinlikle artıran filtrelerin olmasıdır. Bu nedenle mutlak değerleri yorumlamak zor olabilir. İkinci dereceden bir filtre kullanmış olsaydım, durum böyle olmazdı.
Neyse kod aşağıda
#Dahil etmek
#Adafruit_ADS1115 reklamlarını dahil et; // adc için adafruit kitaplığı int16_t adc0; // void setup(void) { Serial.begin(115200); // Seri ads.setGain(GAIN_TWO); // 2x kazanç +/- 2.048V 1 bit =0.0625mV ads.begin(); // adc kayan nokta M = 0; // ilk ortalama kayan nokta Mp = 0; // önceki şamandıra anlamına gelir S = 0; // ilk Varyans kayan nokta Sp = 0; // önceki varyans const int reps = 500; // tekrar sayısı int n = 256; // örnek sayısı ledcSetup(0, 25000, 8); // pwm frekansı =25000 Hz'yi 8 bit çözünürlükte ayarla ledcAttachPin(25, 0); // pwm'yi pin 25'e ayarla ledcWrite(0, 128); // onu yarı görev döngüsüne ayarla(en büyük gürültü) gecikme(3000); // oturma süresini bekle float snrPWM[tekrar]; // PWM kayan nokta için snrs dizisi snrDAC[tekrar]; // DAC için snrs dizisi for (int i = 0; i < reps; i++) { // tekrarlar üzerinden döngü for (int k = 1; k < (n + 1); k++) { // örnekler üzerinden döngü adc0 = ads.readADC_SingleEnded(0); // okumaya başla M = Mp + (adc0 - Mp) / k; // yuvarlanan ortalamayı hesapla Mp = M; // önceki ortalamayı ayarla S = Sp + (adc0 - Mp) * (adc0 - M); // yuvarlanan varyansı hesapla Sp = S; // önceki farkı ayarla } // dB olarak snr snrPWM = 20 * log10(3.3 / (sqrt(S / n) *.0625 *.001)); // değerleri sıfırla M = 0; en = 0; S = 0; Sp = 0; } ledcDetachPin(25); // PWM'yi pin 25 dacWrite(25, 128)'den ayır; // DAC gecikmesine yaz(3000); // yerleşmek için bekle (int i = 0; i < reps; i++) { // PWM döngüsü ile aynı for (int k = 1; k < (n + 1); k++) { adc0 = ads.readADC_SingleEnded(0); M = Mp + (adc0 - Mp) / k; Mp = M; S = Sp + (adc0 - Mp) * (adc0 - M); Sp = S; } snrDAC = 20 * log10(3.3 / (sqrt(S / n) *.0625 *.001)); M = 0; en = 0; S = 0; Sp = 0; } // (int i = 1; i < reps; i++) için SNR'leri bir grafik üzerinde çizin { Serial.print("PWM_SNR(dB):"); Serial.print(snrPWM); Seri.print(", "); Serial.print("ESP32_SNR(dB):"); Serial.println(snrDAC); } } geçersiz döngü(void) { }
Adım 3: İntegral Doğrusal Olmayanlık ve Diferansiyel Doğrusal Olmayanlık
İntegral doğrusal olmama, DAC çıkış voltajınız ile düz bir çizgi arasında kabaca ne kadar sapma olduğunun bir ölçüsüdür. Bu ne kadar büyükse o kadar kötü…
Diferansiyel doğrusal olmama, voltajda (bir koddan diğerine) gözlenen değişimin düz bir çizgiden beklenenden ne kadar saptığının kabaca bir ölçüsüdür.
Buradaki sonuçlar gerçekten ilginçti. Her şeyden önce, her ikisinde de 0,5 lsb'den daha az hata (8 bit çözünürlükte) vardır, bu da iyidir, ancak PWM çok daha iyi integral doğrusallığa sahiptir. Her ikisi de karşılaştırılabilir diferansiyel doğrusal olmayanlığa sahiptir, ancak ESP32 DAC'de bazı çok garip artışlar vardır. Dahası, PWM yönteminin hatalar için bir yapısı vardır. Esasen, alternatif bir şekilde doğru voltajı aşar ve altına düşürür.
Benim şüphem, bunun ESP32'de 8 bitlik bir PWM sinyalinin nasıl üretildiğine dair garip bir yuvarlama hatası.
Bunu düzeltmenin bir yolu, PWM ile iki bitişik kod (örneğin 128, 129) arasında hızla geçiş yapmaktır. Analog bir alçak geçiren filtre ile ortaya çıkan hataların ortalaması sıfır olacaktır. Bunu yazılımda simüle ettim ve gerçekten de tüm hatalar ortadan kayboldu. Artık PWM yöntemi, 16-bit'e kadar doğru olan doğrusallığa sahiptir!
Verileri oluşturacak kod aşağıdadır. Çıktı,.csv formatında seri monitörde olacaktır. Daha fazla işlem için bir metin dosyasına kopyalamanız yeterlidir.
#Dahil etmek
#Adafruit_ADS1115 reklamlarını dahil et; /* 16 bitlik sürüm için bunu kullanın */ int16_t adc0; void setup(void) { Serial.begin(115200); ads.setGain(GAIN_ONE); // 2x kazanç +/- 2.048V 1 bit = 1mV 0.0625mV ads.begin(); ledcSetup(0, 25000, 8); ledcAttachPin(25, 0); Serial.println("Beklenen, Gözlemlenen"); ledcWrite(0, 2); gecikme(3000); for (int i = 2; i < 255; i++) { ledcWrite(0, i); gecikme(100); adc0 = ads.readADC_SingleEnded(0); beklenen kayan nokta = (i / 256,0 * 3.3) / 4.096 * 32767; Serial.print(beklenen); Seri.print(", "); Seri.println(adc0); } } geçersiz döngü(void) { }
4. Adım: Bant Genişliği
Bant genişliğini burada DAC çıkışının 3dB düştüğü frekans olarak tanımlayacağım. Bu bir sözleşmedir ve bir dereceye kadar keyfidir. Örneğin, 6dB noktasında, DAC yine de bir sinyal verecek ve bu sadece ~%50 genlik olacaktır.
Bunu ölçmek için, sinüs dalgalarını DAC'den ADC'ye artan bir frekansta geçiriyoruz ve standart sapmalarını ölçüyoruz. Şaşırtıcı olmayan bir şekilde, 3dB noktası 30Hz'de (1/(2*pi*5000*1e-6)).
ESP32 saniyede 1 Mega örnekleme yapabilir. Bu, ESP32 için pratik bir kazançtır. Genliği 100Hz bant genişliği test bölgesinde hiç azalmaz.
Aşağıdaki kod, PWM DAC bant genişliğini test edebilir.
#Dahil etmek
#Adafruit_ADS1115 reklamlarını dahil et; /* 16 bitlik sürüm için bunu kullanın */ int16_t adc0; int16_t adc1; void setup(void) { float M; kayan nokta Mp = 0; yüzer S = 0; yüzer Sp = 0; Seri.başla(115200); ads.setGain(GAIN_ONE); // 1x kazanç +/- 4.096V 1 bit = 2mV 0.125mV ads.begin(); ledcSetup(0, 25000, 8); ledcAttachPin(25, 0); gecikme (5000); Serial.println("Frekans, Genlik"); for (int i = 1; i < 100; i++) { unsigned uzun başlangıç = millis(); imzasız uzun T = millis(); Sp = 0; S = 0; M = 0; en = 0; int k = 1; yüzer norm; while ((T - başlangıç) < 1000) { int çıkış = 24 * sin(2 * PI * i * (T - başlangıç) / 1000.0) + 128; ledcWrite(0, çıkış); adc0 = ads.readADC_SingleEnded(0); M = Mp + (adc0 - Mp) / k; Mp = M; S = Sp + (adc0 - Mp) * (adc0 - M); Sp = S; T = millis(); k++; } if (i == 1) { norm = sqrt(S / k); } Seri.print(i); Seri.print(", "); Serial.println(sqrt(S / k) / norm, 3); k = 0; } } geçersiz döngü(void) { }
Ve bu kod ESP32 bant genişliğini test edecek. Kondansatörü çıkardığınızdan emin olun, aksi takdirde sonuçlar her iki yöntem için de aynı olacaktır.
#Dahil etmek
#Adafruit_ADS1115 reklamlarını dahil et; /* 16 bitlik sürüm için bunu kullanın */ int16_t adc0; int16_t adc1; void setup(void) { float M; kayan nokta Mp = 0; yüzer S = 0; yüzer Sp = 0; Seri.başla(115200); ads.setGain(GAIN_ONE); // 1x kazanç +/- 4.096V 1 bit = 2mV 0.125mV ads.begin(); gecikme (5000); Serial.println("Frekans, Genlik"); for (int i = 1; i < 100; i++) { unsigned uzun başlangıç = millis(); imzasız uzun T = millis(); Sp = 0; S = 0; M = 0; en = 0; int k = 1; yüzer norm; while ((T - başlangıç) < 1000) { int çıkış = 24 * sin(2 * PI * i * (T - başlangıç) / 1000.0) + 128; dacWrite(25, çıktı); adc0 = ads.readADC_SingleEnded(0); M = Mp + (adc0 - Mp) / k; Mp = M; S = Sp + (adc0 - Mp) * (adc0 - M); Sp = S; T = millis(); k++; } if (i == 1) { norm = sqrt(S / k); } Seri.print(i); Seri.print(", "); Serial.println(sqrt(S / k) / norm, 3); k = 0; } } geçersiz döngü(void) { }
Adım 5: Düşünceleri Kapatmak
Yeni DAC tasarımı, doğrusallık ve gürültü açısından kazanıyor, ancak bant genişliği konusunda kaybediyor. Uygulamanıza bağlı olarak bu endekslerden biri diğerinden daha önemli olabilir. Bu test prosedürleriyle, bu kararı objektif olarak verebilmelisiniz!
Ayrıca, burada PWM çıkışının düşük gürültülü olması ve olağanüstü doğrusallıkla PWM çıkışı ile çok daha yüksek çözünürlüklü bir DAC (belki de 16-bit hassasiyet) oluşturmanın mümkün olması gerektiğini belirtmeye değer olduğunu düşünüyorum. Bu biraz iş alacak. O zamana kadar sana veda ediyorum!
Önerilen:
Daha Az Alanda Daha Fazla Marul Yetiştirmek Veya Uzayda Marul Yetiştirmek, (Daha Fazla veya Daha Az).: 10 Adım
Daha Az Alanda Daha Fazla Marul Yetiştirmek Veya… Uzayda Büyüyen Marul, (Daha Fazla veya Daha Az).: Bu, Instructables aracılığıyla gönderilen Growing Beyond Earth, Maker Yarışması'na profesyonel bir başvurudur. Uzay mahsulü üretimi için tasarım yapmaktan ve ilk Instructable'ımı göndermekten daha fazla heyecanlanamazdım. Başlamak için yarışma bizden
Bir Farnsworth Füzyon Reaktörü Nasıl İnşa Edilir ve Nükleer Kültür Kanonunun Bir Parçası Nasıl Olunur: 10 Adım
Bir Farnsworth Füzyon Reaktörü Nasıl İnşa Edilir ve Nükleer Kültür Kanonunun Bir Parçası Nasıl Olunur: Bilgi gücü hiyerarşilerini merkezden uzaklaştırma ve bireyi güçlendirme umuduyla, aşağıdakileri kullanarak parçacıkları plazmaya iyonize edecek bir cihaz inşa etmek için gerekli adımlardan geçeceğiz. elektrik. Bu cihaz gösterecek
GÜNCELLENMİŞ !!!! Kağıt Antenlerden Daha İyi ve Daha Hızlı Ucuz ve Kolay WIFI Anten Sinyal Güçlendirici !!!: 9 Adım
GÜNCELLENMİŞ !!!! Kağıt Antenlerden Daha İyi ve Daha Hızlı, Ucuz ve Kolay WIFI Anten Sinyal Güçlendirici !!!: WIFI sinyalinizi geliştirmek için eski bir fikir üzerinde yeni bir dönüş
Sony Kulaklık Jakının Değiştirilmesi - Daha İyi ve Daha Güçlü: 10 Adım (Resimlerle)
Sony Kulaklık Jakının Değiştirilmesi - Daha İyi ve Daha Güçlü: Çoğu kulaklık hafif, sesi iyi ve fişte kırılmak üzere tasarlanmıştır. Bu adımlar, tüm kulaklık modellerinin çoğu için kullanılabilir. Çok ucuz kulaklıklar için teller çalışmak için çok ince (küçük) olacak Bu Eğitilebilir Dosya için ben
Yüksek Hızlarda Daha İyi Yol tutuşu için RC Arabalarınızın Şoklarını Daha Kısa Hale Getirin: 5 Adım
Yüksek Hızlarda Daha İyi Yol tutuş için RC Arabalarınızın Amortisörlerini Daha Kısa Yapın: Bu Eğitilebilir Kitapta, amortisörlerinizi nasıl kısaltacağınızı göstereceğim, böylece arabanızı yere yaklaştırırsınız, böylece kanat çırpmadan daha yüksek hızlı dönüşler yapabilirsiniz. Diğer Arabalarınızın amortisörlerinde bakımın nasıl yapılacağına dair Talimatlar, yani