benleentje
Golden Member
Hardware: Potmeter 10k tussen 0V en 5V
Als de ingangsimpedantie van de ESP bv 10k is de potmeter staat op 1/10 ingesteld dan heb je 1K // 9K // 10k. // = parallel, dat geeft een behoorlijke meetfout.
Offset zou makkelijk moeten zijn gewoon de ADC ingang hard aan de gnd hangen.
[Bericht gewijzigd door benleentje op (16%)]
OPTOdesign
R&D | Design | Light | Innovation | Education
De ingangsimpedantie van de ESP is meer dan 100k. Met een 100k weerstand aan GND geeft een ADC waarde van 0. Zonder zit die te zweven rond een willekeurig getal.
Een LM35 en een pulldown van 100k, trekt wel de adc-ingang naar beneden, maar niet de LM35. Dus de 10k potmeter zit wel goed.
Offset zou makkelijk moeten zijn gewoon de ADC ingang hard aan de gnd hangen.
Dat krijg ik een 0.
elmowww
PA0EJE - www.eje-electronics.nl - e.jongerius[aapje]eje-electronics.nl - EJE Electronics - Elektronica/firmware ontwikkeling
Attenuation = verzwakking
Dat heeft niets met offset te maken, maar met de full-range input.
Als je een goede spanningsreferentie aan boord hebt, kan je met een weerstandsdeler de offset en de gain calibreren. Je stelt eigenlijk een lijnvergelijking op:
y = aX + b.
a = gain (factor, ideaal is die dan 1)
b = de offset. Ideaal is die 0.
Hoe steek jet het hardware matig in elkaar:
- Je maakt een weerstandsdeler met 2 uitgangsspanningen, die onder worst-case omstandigheden binnen geldig gebied moeten liggen volgens de datasheet (Echter: specs zijn onvindbaar). Kies voor jouw geval bijv. 300mV en 800mV.
Buffer deze spanningen met een condensatortje 10n/100n, en voer ze naar een niet gebruikte, analoge IO pin.
Een ingang direct aan GND hangen kan niet, omdat een ADC geen negatief resultaat kan hebben, wat nodig is bij een positieve offset.
In jouw geval heb je misschien geen referentie bron nodig, en is de 3.3V nauwkeurig genoeg om je spannignsdeler op aan te sluiten.
Lees deze pin uit in dezelfde configuratie zoals je jouw analoge ingang wilt gebruiken.
Noem deze bijv. cal_low_reading en cal_high_reading.
Vervolgens kan je met de delta tussen deze twee (je weet immers het daadwerkelijke spanningsverschil) de factor a uitrekenen:
const float cal_low_mv = 300; //mV, daadwerkelijke waarde op de ADC pin
const float cal_high_mv = 800; //mV
uint32_t cal_low_reading = DoeAdcConversieOpPinLow(); (bijv 500 dec.)
uint32_t cal_high_reading = DoeAdcConversieOpPinHigh(); (bijv 3123 dec)
float a;
//Reken de factor uit: deltaV / deltaReading
a = (cal_high_mv-cal_low_mv)/(cal_high_reading-cal_low_reading) // = 0.1906214 in dit voorbeeld
//Reken offset uit:
//y = a*X + b. a heb je, en je hebt ook een bekend meetpunt. Immers,
//cal_low_reading moet overeenkomen met cal_low_mv
b = cal_low_mv - (a*cal_low_reading) // 261.87571 in dit voorbeeld.
Nu is je calibratie voltooid, en hoef je enkel a en b te bewaren.
Je kunt de ingangsspanning (ook in mv) berekenen door:
vin = a*reading + b
Jammer dat die ADC zoveel werk nodig heeft.
<Edit: typefout aangepast>
rew
four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/
Je origineel gemeten 1795 bij 500mV in komt op 482mV theoretisch, mits de referentiespanning van de ADC 1100mV is. Omdat je die 1100mV ook regelmatig noemt (maar niet als referentiespanning) gok ik dat dit toch je referentiespanning is.
Atmel CPUs hebben ook een ingebouwde referentie van 1.1V. Echter dat is +/- 10%: Niet zo nauwkeurig. Allicht dat dit bij je ESP beter is, maar dan is de afwijking van 482mV vs 500mV van ongeveer 4% niet eens zo slecht.
ADCs hebben wel eens een "offset" fout. Dus dat ze bij 0V in al een uitlezing van 3 geven of dat ze pas bij vref * 3/4096 een andere waarde dan "0" gaan geven.
Ook die LM35 temp sensor kan makkelijk een offset hebben. Het beste is gewoon om de boel te calibreren bij 0 en bij 100 graden.
Probleem met de LM35 is dat die precies 0V moet leveren bij 0 graden celcius. Daar kan ook een niet lineariteit in je ADC zitten. (dus stel je referentiespanning is 4096 mV, dan krijg je 5 uit je adc bij 5mV. Maar als je dan omlaag gaat kan dat dan 4, 3,3,3,2 zijn bij respectievelijk 4,3,2,1 en 0mV aan de ingang. Een MCP9701 is precies hetzelfde chipje behalve dan dat er een bewuste offset in de output zit, zodat je ook 0 en zelfs negatieve temperaturen kan meten (zonder negatieve voeding).
OPTOdesign
R&D | Design | Light | Innovation | Education
@elmowww:
Heel erg bedankt voor je uitgebreide beschrijving en uitwerking. Ik ga dit binnenkort eens proberen!
@rew:
Dank voor je aanvulling. De 1100mV is de 'attenuation value'. De 'full-range input' zoals elmowww duidelijk maakt. Deze kan ik zelf instellen. Zie screenshot in de bijlage.
Bij 500mV is de afwijking niet heel groot, ergens zijn de waardes, de ingang en de berekende spanning vanuit de ADC, aan elkaar gelijk. In het lage gebied geeft de ADC veel minder aan dan werkelijk en in het hoge gebied zit het heel dicht tegen elkaar aan. Helaas kunnen we dus niet over een vaste afwijking (van 4%) spreken.
Met de offset is iets vreemds aan de hand: De ADC geeft een waarde van 0 bij 0V in. Deze blijft stabiel en wordt ook niet negatief. Echter, pas bij een ingangsspanning van meer dan 75mV gaat de ADC waarde schommelen tussen 0 en 2 (het gemiddelde van 100 monsters). Dit zou naar mijn idee al bij een lagere spanning moeten zijn.
Edit: De datasheet bied hierbij de uitkomst: De ingang moet meer dan 100mV zijn (tabel 8). De afwijking kan dus 46mV afwijken. Dat is een ruim begrip voor een LM35: bijna 5°C.
Ook die LM35 temp sensor kan makkelijk een offset hebben. Het beste is gewoon om de boel te calibreren bij 0 en bij 100 graden.
Probleem met de LM35 is dat die precies 0V moet leveren bij 0 graden celcius. Daar kan ook een niet lineariteit in je ADC zitten. (dus stel je referentiespanning is 4096 mV, dan krijg je 5 uit je adc bij 5mV. Maar als je dan omlaag gaat kan dat dan 4, 3,3,3,2 zijn bij respectievelijk 4,3,2,1 en 0mV aan de ingang. Een MCP9701 is precies hetzelfde chipje behalve dan dat er een bewuste offset in de output zit, zodat je ook 0 en zelfs negatieve temperaturen kan meten (zonder negatieve voeding).
Voor nu doet dit er niet toe. Ik heb enkel een potmeter die een spanning aan de ingang voor de ADC levert.
Als het trucje van elmowww niet voldoende werkt, is kalibratie zoals jij noemt ook een optie. Echter moet er een spanning te meten zijn naar mijn idee. Als ik daar een stukje code voor kan schrijven, kan ik dat voor alle projecten gebruiken wat je ook op de ADC aansluit zonder altijd te moeten kalibreren wat niet altijd mogelijk is en ook z'n onzuiverheden kent.
SparkyGSX
Een manager is iemand die denkt dat negen vrouwen in één maand een kind kunnen maken
Heb je een capje (10-100nF) heel dicht bij de ingang van de microcontroller gezet? Ik weet niet wat de ADC van de ESP32 precies doet, maar bij sommige controller wordt de interne sample-and-hold condensator ontladen, opgeladen tot de halve referentiespanning, of hij blijft op de spanning van de vorige meting. Zonder condensator dicht bij de ingang krijg je de sample-and-hold condensator niet goed opgeladen in de korte tijd dat hij verbonden is met de ingang, en bij je potmeter is de uitgangsimpedantie (Norton weerstand) afhankelijk van de stand van de potmeter, dus dan is het logisch dat de meting veranderd over het bereik.
En inderdaad, de ESP32 ADC doet het slecht aan beide uiteinden van het bereik, daar tussenin zou het nog redelijk lineair moeten zijn. Het is wel ongeveer de slechtste ADC die ik ooit in een microcontroller heb gezien.
[Bericht gewijzigd door SparkyGSX op (15%)]
OPTOdesign
R&D | Design | Light | Innovation | Education
Dank SparkyGSX.
Ik heb wel zitten expirimenteren met een 100n aan de ingang van de ADC-pin. Echter ging mijn waarde daardoor nog meer van afwijken. Ik heb niet gecheckt of de afwijking over het gehele bereik stabieler werd. Dat kan ik nog wel eens testen!
Hmm, interessant wat je schrijft over de veranderende impedantie van de potmeter. Zonder toevoeging van een actief component (ik denk dan aan een opamp) is hier zeker niks aan te doen?
Yes, de ESP32 en zeker de M5STACK modules zijn leuk om snel en goedkoop wat in elkaar te kunnen zetten, maar kent ook zijn beperkingen. Daar is dit ook weer een goed voorbeeld van (helaas).
De ADC van de ESP32 is niet helemaal lineair, en vooral onderin niet erg bruikbaar. Dus als je lage temperaturen wilt meten met een LM35 dan heb je een offset nodig en dus een opamp. Of je moet de MCP9701 gebruiken zoals rew al zei.
Zie https://randomnerdtutorials.com/esp32-adc-analog-read-arduino-ide/
Dus het klopt wel dat er niks gebeurt onder 75mV. Dat is een beperking van de hardware en daar kun je met software niks aan veranderen.
PS: de MCP9701 geeft al 400mV bij 0 °C
OPTOdesign
R&D | Design | Light | Innovation | Education
Dank voor het meedenken over de temperatuurmeting. Ik heb de LM35 genoemd, maar die moet niet leidend gaan worden in mijn hulpvraag. Dan zou de MCP9701 zeker een mooi alternatief kunnen zijn. Toevallig ga ik nu de LM35 ook binnen gebruiken, dus dat zullen spanningen zijn van 150mV en meer.
Echter krijg ik ook boven de 150mV geen juiste uitslag, wat de hoofdvraag betreft (om de waarde uit de ADC te vertalen naar spanning in mV).
Ik ga experimenteren met de suggesties van elmowww en SparkyGSX. Ik sta open voor eventuele aanvullingen.
rew
four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/
Op 28 oktober 2023 14:05:01 schreef SparkyGSX:
Het is wel ongeveer de slechtste ADC die ik ooit in een microcontroller heb gezien.
Dan moet je ook nog eens kijken naar die van de RP2040. In de praktijk zitten er 3 forse "hikken" in de output. Schijnt iets te zijn met een condensator op de chip met een verkeerde waarde.
Dat van die 100mV van de ESP32 is ook wel raar. Maar de RP2040 doet ook zoiets, maar niet zo extreem.
Over meedenken voor de temperatuurmeting: Overweeg ook een DS18x20. Die meet de temperatuur en geeft dat digitaal door. (en waar je voor 2, 3, 4 temperatuurmetingen 2, 3, 4 pins op de ESP32 nodig hebt, is dat voor de DS18x20 familie chips respectievelijk 1, 1 en 1.
)
[Bericht gewijzigd door rew op (11%)]
Op 28 oktober 2023 17:16:49 schreef benleentje:
Waarom niet gewoon een temperatuur sensor met digitale uitgang?
Misschien omdat het kan.
Maar een paar aan elkaar geplakte DS18B20 kan ook eenvoudig.
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
OPTOdesign
R&D | Design | Light | Innovation | Education
Dank voor de aanvullingen en meedenken. De keuze voor een LM35 was omdat het me niet zo ingewikkeld leek om een analoge waarde in te lezen met een ADC 
Het project betreft een (modulaire) ventilator sturing met een 4-polige connector waar naast de voedingsspanning één pin voor de temperatuursensor en één voor de potmeter gereserveerd is. Dus naast de LM35 of wat voor sensor dan ook, moet ik toch ook een potmeter inlezen. Nu hoeft dat niet persé in mV. Maar kom op, ik moet toch gewoon een adc kunnen gebruiken!!
SparkyGSX
Een manager is iemand die denkt dat negen vrouwen in één maand een kind kunnen maken
Op 28 oktober 2023 14:15:45 schreef OPTOdesign:
Dank SparkyGSX.
Ik heb wel zitten expirimenteren met een 100n aan de ingang van de ADC-pin. Echter ging mijn waarde daardoor nog meer van afwijken.
Het feit dat het toevoegen van die condensator iets veranderd, bewijst m.i. dat je wat dat betreft een probleem hebt. Ik denk dat je met de condensator wel de juiste (of best haalbare) conversie van je ADC krijgt, maar een fout hebt gemaakt bij het omrekenen (misschien met getallen van eerdere metingen), waardoor het verkeerd leek.
Die condensator heeft juist als doel om de impedantie van het hele circuit veel kleiner te maken; in de kort tijd (meestal een paar honderd nanoseconde) die de ADC neemt om de sample-and-hold condensator op te laden, komt vrijwel alle lading uit de externe condensator. De potmeter moet die dan alleen bijladen voordat het volgende sample genomen wordt, waardoor de impedantie daarvan veel minder kritisch wordt.
OPTOdesign
R&D | Design | Light | Innovation | Education
Ik heb je berekening uitgevoerd in Excel. Om even gemakkelijk te kunnen spelen met de variabelen en dan kijken wat de uitkomst is. De waarde van a in jouw voorbeeldcode komt niet overeen met mijn berekening, maar de uitslag b waar a in zit weer wel. Klopt de berekening zo? Zie bijlage. Dank!
Edit:
OPTOdesign
R&D | Design | Light | Innovation | Education
Dank voor de oplettendheid!
[Bericht gewijzigd door OPTOdesign op (25%)]
OPTOdesign
R&D | Design | Light | Innovation | Education
Op 27 oktober 2023 22:00:06 schreef elmowww: Jammer dat die ADC zoveel werk nodig heeft.
Ik wil je heel hartelijk danken voor je inbreng! Het werkt heel netjes! 
Trouwens, iedereen bedankt.
Ik heb een beetje vals gespeeld door niet een weerstandsnetwerk te nemen, maar de DAC van de (zelfde) controller. Ik was benieuwd hoe stabiel dit zou zijn en of de uitkomst betrouwbaar genoeg zou zijn. Ik ben voor nu erg tevreden met het resultaat.
Dat omgezet naar een stukje code:
cal_high_mv = float(1005)
cal_high_reading = float(3900)
cal_low_mv = float(122.8)
cal_low_reading = float(145)
# =(cal_high_mv-cal_low_mv)/(cal_high_reading-cal_low_reading)
gain = float(((cal_high_mv - cal_low_mv) / (cal_high_reading - cal_low_reading)))
# =cal_low_mv-(a*cal_low_reading)
Offset_Var = float((cal_low_mv - gain * cal_low_reading))
for i in range(1, 1001):
Var = (Var if isinstance(Var, Number) else 0) + (adc0.read())
wait_ms(1)
ADCVar = int((Var / 1000))
# Vin = a*reading + b
TempVar = int((gain * ADCVar + Offset_Var))De ADC weer op de potmeter aangesloten en het werkt!
De afwijking bedraagt afhankelijk van de waarde 1mV (onderin) tot 3mV (bovenin). De spanning die de multimeter aangeeft staat nu ook op het display! Super.
Alleen bij een ingangsspanning van 1100mV is er 50mV te kort. Terwijl bij precies 1000mV er slechts 2mV te veel wordt gerekend. Dat zal vast komen omdat ik in de buurt van een grens zit van de ADC.
Met 'de condensator van SparkyGSX' van 10n, wordt de afwijking zo'n 4mV in het hoge bereik groter. De ruwe ADC waarde wiebelt wat minder. Ik weet niet of ik dit nou een vooruitgang vindt en of het echt wat bijdraagt.
Je zou de lm35 eens kunnen belasten met een 10k weerstand.
Zie hier meer voorbeelden https://www.ti.com/lit/ds/symlink/lm35.pdf
elmowww
PA0EJE - www.eje-electronics.nl - e.jongerius[aapje]eje-electronics.nl - EJE Electronics - Elektronica/firmware ontwikkeling
Mooi zo! Bedankt voor de terugkoppeling en excuus voor de fout. Ik had het niet echt nagelezen, zal het voor de toekomst in de post even aanpassen.
Succes!
Dat de waarde gaat fluctueren met extra capaciteit vindt ik apart. Ik kan dat niet helemaal thuisbrengen eigenlijk.
rew
four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/
Als je nu de "cal_high_mv" een stuk of vier omhoog of omlaag doet (*), dan zal die 4mV afwijking /met/ de condensator naar nul of 8 gaan.
Die situatie MET condensator lijkt me een wenselijke situatie. Je hebt met een verkeerde "cal" waarde de fout door "geen condensator" deels gecompenseerd. Omdat die fout afhangt van waar je de boel mee aanstuurt (potmeter, weerstandsnetwerk of LM35) is het fijn om de condensator WEL toe te passen en de boel even af te regelen zodat ie juist is.
Merk op dat je ook 1008.5 kan opgeven als cal_high_mv. Als dit een lagere afwijking geeft (in het hoge bereik) dan 1008 of 1009 moet je dat gewoon doen.
(*) als jij niet vertelt of die afwijking naar boven of naar beneden is, dan kan ik niet zeggen of die omhoog of omlaag moet.
elmowww
PA0EJE - www.eje-electronics.nl - e.jongerius[aapje]eje-electronics.nl - EJE Electronics - Elektronica/firmware ontwikkeling
Ah, ja, je moet mét condensator wel de calibratie opnieuw doen natuurlijk.
Het gedrag zónder condensator is namelijk wel te verklaren: de ADC (afhankelijk van het soort) kan een stroompiek op de ingang trewkken ten tijde van mux-switchen (dat doe je nu niet) of van acquisitie (dat doe je nu wel). Samen emt een hoog impedante spanningsbron (je weerstandsdeler) heeft dat een spanningsval tot gevolg.
Daarom buffer je de analoge pin: je kunt dan vanuit de condensator snelle stroompieken opvangen. Een andere reden (in jouw geval een pluspunt) is dat je een low-pass filter creëert waarmee je snelle fluctuaties in je sensor signaal kan opvangen.
rew
four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/
De AVR heeft op de sample-and-hold condensator "de vorige analoge spanning" staan als je van kanaal wisselt. Dus meet je eerst een "voedingsspanning" signaal" en daarna een lagere spanning, dan zie je een verhoging van de eerste paar metingen van die lagere spanning.
Het lijkt er op dat bij de ESP32 de condensator altijd bij nul begint, waardoor je afhankelijk van de impedantie van je signaal iets lager meet dan wat zou moeten.
OPTOdesign
R&D | Design | Light | Innovation | Education
Dank elmowww, dank rew!
Jaaa, daar ging ik de fout in! Ik stak de condensator er gewoon bij zonder de Kalibratie opnieuw uit te voeren...
Ik ben nu een kalibratie-sotware-tooltje aan het maken, zodat ik via de seriële poort (over USB) de kalibratie kan uitvoeren op ieder gewenst moment op verschillende poorten van verschillende controllers. Als ik het tooltje ga testen neem ik de condensator mee!
rew: Merk op dat je ook 1008.5 kan opgeven als cal_high_mv. Als dit een lagere afwijking geeft (in het hoge bereik) dan 1008 of 1009 moet je dat gewoon doen.
Precies, dat ga ik wel toepassen als ik de LM35 ga gebruiken. Handmatig bijstellen (als dat nodig is) om een zeer nauwkeurige meting te krijgen in een klein bereik (150mV t/m 250mV voor de ventilatorregeling).
elmowww: Het gedrag zónder condensator is namelijk wel te verklaren: de ADC (afhankelijk van het soort) kan een stroompiek op de ingang trewkken ten tijde van mux-switchen (dat doe je nu niet) of van acquisitie (dat doe je nu wel). Samen emt een hoog impedante spanningsbron (je weerstandsdeler) heeft dat een spanningsval tot gevolg.
Tijdens kalibratie had ik de DAC-pin via een 10k weerstand op de ADC-pin gezet. Dus niet echt een weerstandsdeler (los van interne koppelingen). Tijdens gebruik dan weer wel: namelijk de (10k)potmeter (zonder 10n) Mijns inziens had dat geen zin - maar ik heb ook weer wat geleerd dankzij jullie theoriën! Dus ik zet altijd een C-tje aan de ingang voorlopig 
rew: Het lijkt er op dat bij de ESP32 de condensator altijd bij nul begint, waardoor je afhankelijk van de impedantie van je signaal iets lager meet dan wat zou moeten.
Ik weet niet precies waar je dat op baseerd, als dat op mijn waardes is, weet dan dat ik de adc-waarde steeds 1000x uitlees en daar het gemiddelde van neem. Bij het wisselen van Cal_ADC_High & _Low startte ik steeds 2x op omdat de waarde van de vorige meting nog in het systeem leek te zitten. Overigens kan dat ook door de systeem-reset zelf komen. Dus baseer je theorie vooral niet op mijn resultaten... 