Innehållsförteckning:
- Tillbehör
- Steg 1: Lägg ut brödbrädan
- Steg 2: Bedöm signal till bullernivå
- Steg 3: Integral olinearitet och differentiell olinearitet
- Steg 4: Bandbredd
- Steg 5: Avslutande tankar
Video: Hur man gör och testar en bättre DAC med ESP32: 5 steg
2024 Författare: John Day | [email protected]. Senast ändrad: 2024-01-30 12:38
ESP32 har 2 8-bitars digitala till analoga omvandlare (DAC). Dessa DAC gör att vi kan producera godtyckliga spänningar inom ett visst område (0-3.3V) med 8 bitars upplösning. I denna instruktionsbok kommer jag att visa dig hur man bygger en DAC och karakteriserar dess prestanda samt jämför den med ESP32 DAC. Prestationsindexen jag kommer att titta på inkluderar
- Ljudnivå
- Bandbredd
- Integrerad olinearitet
- Differentiell olinearitet
För att testa dessa index kommer jag att använda ADS1115.
Det är viktigt att notera att din bedömning av alla dessa index bara kommer att vara lika exakt som din referensenhet (i detta fall ADS115). Till exempel har ADS115 inte 16-bitars precision när det gäller dess spänningsförskjutning och förstärkning. Dessa fel kan vara så stora som 0,1%. För många system kan dessa fel ignoreras när absolut noggrannhet är av begränsad anledning.
Tillbehör
- ADS1115
- ESP32 -kort
- bakbord
- bygelkablar
- 5 kOhm motstånd
- 1 mikro-Farad keramisk kondensator
Steg 1: Lägg ut brödbrädan
Anslut följande stift
Mellan ESP32 och ADS1115
3v3 VDD
GND GND
GPIO22 SCL
GPIO21 SDA
På ADS1115
ADDR GND (ADS115)
Att göra DAC
Det finns många sätt att göra en DAC. Det enklaste är att lågpassfiltrera en PWM-signal med ett motstånd och en kondensator. Jag kunde ha lagt till en op-amp här som en buffert men ville hålla det enkelt. Denna design är enkel och billig att implementera med alla mikrokontroller som stöder PWM. Jag tänker inte gå igenom teorin om designen här (google PWM DAC).
Anslut bara GPIO255 KOhm motstånd 1 microFarad kondensator gnd
Anslut nu en bygelkabel från den punkt där motståndet möter kondensatorn till A0 på ADS115.
Steg 2: Bedöm signal till bullernivå
För att bedöma ljudnivån, kör helt enkelt skriptet nedan. För att bedöma detta lämnar vi helt enkelt DAC vid ett fast värde och mäter hur spänningen svänger över tiden.
På grund av DAC: s konstruktion blir bullret störst när PWM -signalen är på 50% driftscykel. Därför kommer vi att bedöma det. Vi kommer också att bedöma ESP32 på samma signalnivå. Vi kommer också att filtrera ESP32 DAC med samma lågpassfilter för att göra mätningen jämförbar.
För mig var resultatet klart. PWM -designen hade> 6dB bättre SNR (det är 2 gånger bättre). En klar vinst för nya DAC. En liten förvirring är att det finns filter inbyggda i ADC som definitivt förbättrar SNR. Så de absoluta värdena kan vara svåra att tolka. Om jag hade använt ett andra ordningsfilter skulle detta inte vara fallet.
Koden finns i alla fall nedan
#omfatta
#inkludera Adafruit_ADS1115 annonser; // adafruit bibliotek för adc int16_t adc0; // void setup (void) {Serial.begin (115200); // Starta seriella annonser.setGain (GAIN_TWO); // 2x gain +/- 2.048V 1 bit = 0.0625mV ads.begin (); // börja adc float M = 0; // initial medelflöde Mp = 0; // previouos betyder float S = 0; // initial Variance float Sp = 0; // föregående varians const int reps = 500; // antal repitioner int n = 256; // antal prover ledcSetup (0, 25000, 8); // ställ in pwm frequecny = 25000 Hz vid 8 bitars upplösning ledcAttachPin (25, 0); // ställ pwm på pin 25 ledcWrite (0, 128); // ställ in den på halvdriftscykel (största buller) fördröjning (3000); // vänta på avvecklingstid float snrPWM [reps]; // array av snrs för PWM float snrDAC [reps]; // array av snrs för DAC för (int i = 0; i <reps; i ++) {// loope over repititions for (int k = 1; k <(n+1); k ++) {// loope over samples adc0 = ads.readADC_SingleEnded (0); // läs M = Mp + (adc0 - Mp) / k; // beräkna rullande medelvärde Mp = M; // ställ in tidigare medelvärde S = Sp + (adc0 - Mp) * (adc0 - M); // beräkna rullande varians Sp = S; // ställ in tidigare varians} // snr i dB snrPWM = 20 * log10 (3.3 / (sqrt (S / n) *.0625 *.001)); // återställ värden M = 0; Smältpunkt = 0; S = 0; Sp = 0; } ledcDetachPin (25); // lossa PWM från stift 25 dacWrite (25, 128); // skriva till DAC -fördröjning (3000); // vänta med att nöja sig med (int i = 0; i <reps; i ++) {// samma som PWM -loop för (int k = 1; k <(n+1); k ++) {adc0 = ads.readADC_SingleEnded (0); M = Mp + (adc0 - Mp) / k; Smp = M; S = Sp + (adc0 - Mp) * (adc0 - M); Sp = S; } snrDAC = 20 * log10 (3.3 / (sqrt (S / n) *.0625 *.001)); M = 0; Smältpunkt = 0; S = 0; Sp = 0; } // plot SNR på en graf för (int i = 1; i <reps; i ++) {Serial.print ("PWM_SNR (dB):"); Serial.print (snrPWM ); Serial.print (","); Serial.print ("ESP32_SNR (dB):"); Serial.println (snrDAC ); }} void loop (void) {}
Steg 3: Integral olinearitet och differentiell olinearitet
Den integrerade olineariteten är ett mått på ungefär hur stor avvikelse det finns mellan din DAC -utspänning och en rak linje. Ju större detta är desto värre är det …
Den olikära differentialen är ett mått på ungefär hur mycket den observerade förändringen i spänningen (från en kod till nästa) avviker från vad som kan förväntas från en rak linje.
Resultaten här var riktigt intressanta. Först och främst har båda mindre än 0,5 lbs fel (vid 8-bitars upplösning) vilket är bra men PWM har mycket bättre integrerad linearitet. Båda har jämförbar differentiell olinearitet men ESP32 DAC har några väldigt konstiga spikar. Dessutom har PWM -metoden en viss struktur för felen. I grund och botten överskjuter och överskjuter den rätt spänning på ett växlande sätt.
Min misstanke är att detta är något konstigt avrundningsfel i hur en 8-bitars PWM-signal produceras på ESP32.
Ett sätt att korrigera för detta är att snabbt växla mellan två intilliggande koder (t.ex. 128, 129) med PWM. Med ett analogt lågpassfilter är de resulterande felen genomsnittliga till noll. Jag simulerade detta i mjukvara och alla fel försvann. Nu har PWM-metoden linjäritet som är exakt till 16-bitars!
Vem som helst som koden för att generera data finns nedan. Utmatningen kommer att visas på den seriella bildskärmen i.csv -format. Kopiera bara den till en textfil för vidare bearbetning.
#omfatta
#inkludera Adafruit_ADS1115 annonser; / * Använd detta för 16-bitarsversionen */ int16_t adc0; void setup (void) {Serial.begin (115200); ads.setGain (GAIN_ONE); // 2x förstärkning +/- 2.048V 1 bit = 1mV 0.0625mV ads.begin (); ledcSetup (0, 25000, 8); ledcAttachPin (25, 0); Serial.println ("Förväntat, observerat"); ledcWrite (0, 2); fördröjning (3000); för (int i = 2; i <255; i ++) {ledcWrite (0, i); fördröjning (100); adc0 = ads.readADC_SingleEnded (0); float förväntas = (i / 256,0 * 3,3) / 4,096 * 32767; Serial.print (förväntat); Serial.print (","); Serial.println (adc0); }} void loop (void) {}
Steg 4: Bandbredd
Jag kommer att definiera bandbredd som här som frekvensen vid vilken utmatningen från DAC sjunker med 3dB. Detta är en konvention och till viss del godtyckligt. Till exempel, vid 6dB -punkten, kommer DAC fortfarande att sända ut en signal, det kommer bara att vara ~ 50% amplitud.
För att mäta detta passerar vi helt enkelt sinusvågor med en ökande frekvens från DAC till ADC och mäter deras standardavvikelse. Inte överraskande är 3dB-punkten vid 30Hz (1/(2*pi*5000*1e-6)).
ESP32 kan göra 1 megaprov per sekund. Detta är en praktisk vinst för ESP32. Dess amplitud förfaller inte alls i 100Hz bandbreddstestområdet.
Koden nedan kan testa PWM DAC -bandbredd.
#omfatta
#inkludera Adafruit_ADS1115 annonser; / * Använd detta för 16-bitarsversionen */ int16_t adc0; int16_t adc1; void setup (void) {float M; float Mp = 0; flyta S = 0; float Sp = 0; Serial.begin (115200); ads.setGain (GAIN_ONE); // 1x förstärkning +/- 4.096V 1 bit = 2mV 0.125mV annonser. Börjar (); ledcSetup (0, 25000, 8); ledcAttachPin (25, 0); fördröjning (5000); Serial.println ("Frekvens, amplitud"); för (int i = 1; i <100; i ++) {osignerad lång start = millis (); osignerad lång T = millis (); Sp = 0; S = 0; M = 0; Smältpunkt = 0; int k = 1; float norm; medan ((T - start) <1000) {int ut = 24 * sin (2 * PI * i * (T - start) / 1000.0) + 128; ledcWrite (0, ut); adc0 = ads.readADC_SingleEnded (0); M = Mp + (adc0 - Mp) / k; Smp = M; S = Sp + (adc0 - Mp) * (adc0 - M); Sp = S; T = millis (); k ++; } om (i == 1) {norm = sqrt (S / k); } Serial.print (i); Serial.print (","); Serial.println (sqrt (S / k) / norm, 3); k = 0; }} void loop (void) {}
Och den här koden kommer att testa ESP32 -bandbredden. Var noga med att ta bort kondensatorn annars blir resultaten desamma för båda metoderna.
#omfatta
#inkludera Adafruit_ADS1115 annonser; / * Använd detta för 16-bitarsversionen */ int16_t adc0; int16_t adc1; void setup (void) {float M; float Mp = 0; flyta S = 0; float Sp = 0; Serial.begin (115200); ads.setGain (GAIN_ONE); // 1x förstärkning +/- 4.096V 1 bit = 2mV 0.125mV annonser. Börjar (); fördröjning (5000); Serial.println ("Frekvens, amplitud"); för (int i = 1; i <100; i ++) {osignerad lång start = millis (); osignerad lång T = millis (); Sp = 0; S = 0; M = 0; Smältpunkt = 0; int k = 1; float norm; medan ((T - start) <1000) {int ut = 24 * sin (2 * PI * i * (T - start) / 1000.0) + 128; dacWrite (25, ut); adc0 = ads.readADC_SingleEnded (0); M = Mp + (adc0 - Mp) / k; Smp = M; S = Sp + (adc0 - Mp) * (adc0 - M); Sp = S; T = millis (); k ++; } om (i == 1) {norm = sqrt (S / k); } Serial.print (i); Serial.print (","); Serial.println (sqrt (S / k) / norm, 3); k = 0; }} void loop (void) {}
Steg 5: Avslutande tankar
Den nya DAC -designen vinner på linearitet och brus men förlorar på bandbredd. Beroende på din ansökan kan ett av dessa index vara viktigare än det andra. Med dessa testförfaranden bör du kunna fatta det beslutet objektivt!
Jag tycker också att det är värt att påpeka här att eftersom PWM-utgång är lågt brus, med exceptionell linjäritet bör det vara möjligt att konstruera en mycket högre upplösning DAC med PWM-utgången (kanske till och med 16-bitars precision). Det kommer att kräva lite arbete. Tills dess säger jag hejdå!
Rekommenderad:
Hur man gör luftfuktighet och temperatur i realtid Data Recorder med Arduino UNO och SD-kort - DHT11 Datalogger Simulering i Proteus: 5 steg
Hur man gör luftfuktighet och temperatur i realtid Data Recorder med Arduino UNO och SD-kort | DHT11 Datalogger Simulering i Proteus: Introduktion: hej, det här är Liono Maker, här är YouTube-länk. Vi gör kreativa projekt med Arduino och arbetar med inbäddade system.Data-Logger: En datalogger (även datalogger eller dataregistrator) är en elektronisk enhet som registrerar data över tid med
Hur man gör en drönare med Arduino UNO - Gör en quadcopter med mikrokontroller: 8 steg (med bilder)
Hur man gör en drönare med Arduino UNO | Gör en Quadcopter Med Microcontroller: Introduktion Besök min Youtube -kanal En Drone är en mycket dyr gadget (produkt) att köpa. I det här inlägget ska jag diskutera, hur gör jag det billigt ?? Och hur kan du göra din egen så här till billigt pris … Tja i Indien alla material (motorer, ESC
Hur man gör din högtalare bättre !: 4 steg
Hur man gör din högtalare bättre !: Jag vill göra min högtalare bättre eftersom jag har det här problemet om min högtalare inte har någon räckvidd. Till exempel, när jag är i min pool och simmar till andra sidan kan jag inte höra musiken spela från en sida till en annan. Jag tycker att det här är speciellt eftersom jag tror att
Hur man testar bipolära transistorer om du har en analog multimeter: 4 steg
Hur man testar bipolära transistorer om du har en analog multimeter: Vi vet hur transistorn fungerar men några av oss vet inte riktigt hur vi ska testa själva komponenten. Numera har de flesta digitala multimetrar uttag för att testa dem, men vad gör du om du har de gamla analoga/nåltypen? Det här är en sim
Hur du gör ditt klipp Tek Gun syftar bättre: 4 steg
Hur gör du ditt Clip Tek Gun -mål bättre: Så du vill få din Clip Tek -pistol att ha ett bättre mål? jag ska berätta hur du gör. det bästa sättet att förbättra ditt mål är att använda en laserriktare. det kommer att kosta dig mindre än $ 10