0
Καλημέρα,
Δοκιμάζοντας τον έτοιμο κώδικα που βρήκα για να έχω λίγο καλύτερη ανάλυση στην μέτρηση τάσης με AnalogRead, διαπίστωσα ότι δουλεύει μεν αλλά το έως τώρα μικρό σφάλμα μέτρησης λόγο μη-γραμμικότητας στην σχέση τιμής ADC και πραγματικής τάσης, τώρα είναι πολύ μεγαλύτερο και αναιρεί όποια οφέλη προσφέρει η ψευδό-12bit ανάλυση...
Aυτό που έχω δει εγώ τουλάχιστον είναι ότι η καμπύλη των τιμών που δίνει ο ADC σε σχέση με την πραγματική τάση δεν είναι γραμμική, έχει μία ελαφριά καμπύλη. Συγκεκριμένα και με τους 3 Nano που έχω πάντα παίρνω χαμηλότερη τιμή από την πραγματική όταν η τάση είναι κάτω από τα περίπου 200mV και μεγαλύτερη τιμή από την πραγματική από εκεί και πάνω. Ο τρόπος που μετράω είναι να χρησιμοποιώ την εσωτερική Vref των περίπου 1.1V που αλλάζει από τσιπ σε τσιπ (στα δικά μου 1.072 με 1.084V) αλλά είναι αρκετά σταθερή στις αλλαγές θερμοκρασίας κτλ. Εκτός λοιπόν από το να μετράω και να χρησιμοποιώ την "σωστή" Vref στον κώδικα, εμπειρικά κατέληξα να βάζω και άλλη μια παράμετρο στοω υπολογισμό της τάσης, που βοηθάει να ισιώσει κάπως αυτή η καμπύλη: από δοκιμές βρήκα ότι (AnalogRead + 2.0περίπου ) / 1024.0 * Vref λειτουργεί αρκετά καλά, με 1-2mV λιγότερα στις μικρότερες μετρήσεις και άλλα +1-2mV για το μέγιστο του ~1.1V
Είπα λοιπόν να δοκιμάσω την βιβλιοθήκη NewAnalogRead του eRCaGuy και όντος είδα μία μικρή βελτίωση στην ανάλυση, αλλά μαζί χειροτερεύει και το πρόβλημα της μη-γραμμικότητας: στα 35mV μετράει -5mV πιο κάτω και στα 736mV μετράει +41mV περισσότερα!
Για την ιστορία η διαφορά στην ανάλυση που είδα είναι η παρακάτω: για πραγματική τάση μεταξύ 100 και 101mV στα 10bit είχα μόνο ένα βήμα στην μέτρηση με AnalogRead, τώρα έχω τουλάχιστον 3!!! Μέχρι εκεί όμως, στα 12bit που το δοκίμασα δουλεύει αλλά με 14bit δεν υπάρχει πρακτικά διαφορά αφού δεν δουλεύω στην NASA να έχω εξοπλισμό που να μετράει ένα-ένα τα μικροβόλτ...
Βοηθήστε με βρε παιδιά, τι κάνω λάθος ???
Ο απλός κώδικας που χρησιμοποιώ και μετράει στα +-2mV περίπου:
Βίντεο (χείριστης ποιότητας ) που δείχνει ότι μετράει "OK":Κώδικας:#include <LiquidCrystal.h> LiquidCrystal lcd(2, 4, 6, 7, 8, 9); float Vref11 = 1.082; float CalibV = 2.0; int Read1 = A0; void setup() { analogReference (INTERNAL); lcd.begin(20, 2); } void loop() { lcd.setCursor(0, 0); lcd.print(millis() / 1000); // κλόπη-Paste μέθοδος για απόρριψη "κουλών" τιμών μέτρησης που μπορεί να προέρχονται από θόρυβο κτλ. Κάνει δουλειά! int rawADC0 = analogRead (Read1); int rawADC1 = analogRead (Read1); int rawADC2 = analogRead (Read1); int rawADC3 = analogRead (Read1); int rawADC4 = analogRead (Read1); int rawADC5 = analogRead (Read1); int rawADC6 = analogRead (Read1); int rawADC7 = analogRead (Read1); int rawADC8 = analogRead (Read1); int rawADC9 = analogRead (Read1); int rawADC10 = analogRead (Read1); int rawADC11 = analogRead (Read1); int rawADC12 = analogRead (Read1); int rawADC13 = analogRead (Read1); int rawADC14 = analogRead (Read1); int rawADC15 = analogRead (Read1); int rawADC16 = analogRead (Read1); int rawADC17 = analogRead (Read1); int rawADC18 = analogRead (Read1); int rawADC19 = analogRead (Read1); int average = (rawADC0 + rawADC1 + rawADC2 + rawADC3 + rawADC4 + rawADC5 + rawADC6 + rawADC7 + rawADC8 + rawADC9 + rawADC10 + rawADC11 + rawADC12 + rawADC13 + rawADC14 + rawADC15 + rawADC16 + rawADC17 + rawADC18 + rawADC19) / 20; float OnePercentADC = (float) average / 1000; float percentADC = OnePercentADC * 6; float average2 = 0; int count = 0; if (rawADC0 <= average+percentADC && rawADC0 >= average-percentADC) {average2 = average2 + rawADC0; count++;} if (rawADC1 <= average+percentADC && rawADC1 >= average-percentADC) {average2 = average2 + rawADC1; count++;} if (rawADC2 <= average+percentADC && rawADC2 >= average-percentADC) {average2 = average2 + rawADC2; count++;} if (rawADC3 <= average+percentADC && rawADC3 >= average-percentADC) {average2 = average2 + rawADC3; count++;} if (rawADC4 <= average+percentADC && rawADC4 >= average-percentADC) {average2 = average2 + rawADC4; count++;} if (rawADC5 <= average+percentADC && rawADC5 >= average-percentADC) {average2 = average2 + rawADC5; count++;} if (rawADC6 <= average+percentADC && rawADC6 >= average-percentADC) {average2 = average2 + rawADC6; count++;} if (rawADC7 <= average+percentADC && rawADC7 >= average-percentADC) {average2 = average2 + rawADC7; count++;} if (rawADC8 <= average+percentADC && rawADC8 >= average-percentADC) {average2 = average2 + rawADC8; count++;} if (rawADC9 <= average+percentADC && rawADC9 >= average-percentADC) {average2 = average2 + rawADC9; count++;} if (rawADC10 <= average+percentADC && rawADC10 >= average-percentADC) {average2 = average2 + rawADC10; count++;} if (rawADC11 <= average+percentADC && rawADC11 >= average-percentADC) {average2 = average2 + rawADC11; count++;} if (rawADC12 <= average+percentADC && rawADC12 >= average-percentADC) {average2 = average2 + rawADC12; count++;} if (rawADC13 <= average+percentADC && rawADC13 >= average-percentADC) {average2 = average2 + rawADC13; count++;} if (rawADC14 <= average+percentADC && rawADC14 >= average-percentADC) {average2 = average2 + rawADC14; count++;} if (rawADC15 <= average+percentADC && rawADC15 >= average-percentADC) {average2 = average2 + rawADC15; count++;} if (rawADC16 <= average+percentADC && rawADC16 >= average-percentADC) {average2 = average2 + rawADC16; count++;} if (rawADC17 <= average+percentADC && rawADC17 >= average-percentADC) {average2 = average2 + rawADC17; count++;} if (rawADC18 <= average+percentADC && rawADC18 >= average-percentADC) {average2 = average2 + rawADC18; count++;} if (rawADC19 <= average+percentADC && rawADC19 >= average-percentADC) {average2 = average2 + rawADC19; count++;} average = average2 / count; float voltage = ((float) average + CalibV ) / 1024.0 * Vref11; lcd.setCursor(5, 0); lcd.print(voltage,3);lcd.print("V"); lcd.setCursor(12, 0); lcd.print(" "); lcd.setCursor(12, 0); lcd.print(average); lcd.setCursor(17, 0); lcd.print(" "); lcd.setCursor(17, 0); lcd.print(count); }
Πάνω γραμμή είναι Timer, Τάση , ADC , count. Η κάτω γραμμή είναι άλλη μία τάση που μετράω, δεν αλλάζει. Το κύκλωμα είναι μόνο η LCD και ένας διαιρέτης με δύο pot που βγάζουν τις τάσεις που μετράω.
Κώδικας από το Παράδειγμα (basic_demo) της βιβλιοθήκης NewAnalogRead, που μετράει +40mV στα 745mV:
*το παράδειγμα είναι σε 14bit αλλά δεν έχει νόημα όπως είπα, οι τιμές που πήρα και έφτιαξα τα γραφήματα πιο κάτω είναι όπως παρακάτω, στα 12bit
Γράφημα που δείχνει τις καμπλύλες για τα παραπάνω παραδείγματα:Κώδικας:/* NewAnalogRead_basic_demo.ino -This is a demo of this library: eRCaGuy_NewAnalogRead, which replaces eRCaGuy_analogReadXXbit -Written for Library Version: 2.1 Library webpage: http://electricrcaircraftguy.blogspot.com/2014/05/using-arduino-unos-built-in-16-bit-adc.html -This is a library to utilize oversampling, by the 10-bit Arduino ADC (Analog to Digital Converter), in order to obtain much higher resolutions. You may command any resolution from 10-bit to 21-bit, though oversampling has its limiations and you may not see improvements beyond ~16-bit commands. There are a lot of variables, so you will just have to play around and find out. The tradeoff in commanded resolution is speed. The higher the commanded resolution, the longer it takes to get an ADC reading. Each new bit of resolution decreases the max read speed by a factor of 4. See the top of the .h file for much more info. -Additionally, this library provides automatic averaging of multiple readings, at your desired resolution of course, in order to smooth incoming data. -For the theory behind oversampling, see AVR121 Application Note: http://www.atmel.com/images/doc8003.pdf --esp. take a look at Table 3-1, Resolution Options, on pg. 8 By Gabriel Staples http://electricrcaircraftguy.blogspot.com/ -My contact info is available by clicking the "Contact Me" tab at the top of my blog. Written: 17 Feb. 2015 Last Updated: 17 Feb. 2015 */ /* ================================================== ================================================= LICENSE & DISCLAIMER Copyright (C) 2014-2015 Gabriel Staples. All right reserved. This file is part of eRCaGuy_NewAnalogRead. I AM WILLING TO DUAL-LICENSE THIS SOFTWARE. HOWEVER, UNLESS YOU HAVE PAID FOR AND RECEIVED A RECEIPT FOR AN ALTERNATE LICENSE AGREEMENT, FROM ME, THE COPYRIGHT OWNER, THIS SOFTWARE IS LICENSED AS FOLLOWS: ------------------------------------------------------------------------------------------------ License: GNU General Public License Version 3 (GPLv3) or later - https://www.gnu.org/licenses/gpl.html ------------------------------------------------------------------------------------------------ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/ ================================================== ================================================= */ /* Circuit: We need to read an analog voltage on A0, so place a pot with the outer legs going to 5V and GND, respectively, and the wiper (middle leg) going to A0 -make sure to set your Serial Monitor to 115200 baud rate */ //include the library #include <eRCaGuy_NewAnalogRead.h> //Global variables byte pin = A0; byte bitsOfResolution = 12; //commanded oversampled resolution unsigned long numSamplesToAvg = 1; //number of samples AT THE OVERSAMPLED RESOLUTION that you want to take and average ADC_prescaler_t ADCSpeed = ADC_FAST; /*Speed options to store into ADCSpeed are as follows: ADC_PRESCALER_128_CLOCK_125KHZ ADC_DEFAULT (same as above) ADC_SLOW (same as above) ADC_PRESCALER_64_CLOCK_250KHZ ADC_PRESCALER_32_CLOCK_500KHZ ADC_PRESCALER_16_CLOCK_1MHZ ADC_FAST (same as above) CAUTION_ADC_PRESCALER_8_CLOCK_2MHZ CAUTION_ADC_PRESCALER_4_CLOCK_4MHZ CAUTION_ADC_PRESCALER_2_CLOCK_8MHZ NB: if you change the ADC clock speed, it doesn't just affect this library, it also affects the ADC sample rate when calling the standard core Arduino analogRead() function. */ void setup() { Serial.begin(115200); Serial.println(F("Oversampling example, commanding 10-bit to 21-bit resolution using a 10-bit ADC on an Arduino")); Serial.println(F("Basic demo")); Serial.println(""); //add a line space //print defaults Serial.println(F("Default adc values:")); printValues(); //Configure the adc how you want it adc.setADCSpeed(ADCSpeed); adc.setBitsOfResolution(bitsOfResolution); adc.setNumSamplesToAvg(numSamplesToAvg); //Verify your changes Serial.println(F("New adc values:")); printValues(); } void loop() { //local variables unsigned long analogReading; //take a reading on the analog pin //note: this is an overloaded function, so there are 4 ways to do it! //Method 1: just take a reading, providing the pin number only; the library will use other values as necessary // that you already set with the "adc.set..." functions above analogReading = adc.newAnalogRead(pin); //get the avg. of [num_samples] [bits_of_resolution]-bit readings //Method 2: update what the library has stored for bitsOfResolution, AND take a new reading // analogReading = adc.newAnalogRead(pin,bitsOfResolution); //UNCOMMENT TO USE //Method 3: update what the library has stored for bitsOfResolution and numSamplesToAvg, AND take a new reading // analogReading = adc.newAnalogRead(pin,bitsOfResolution,numSamplesT oAvg); //UNCOMMENT TO USE //Method 4: update what the library has stored for bitsOfResolution and numSamplesToAvg, then set the ADCSpeed, AND take a new reading // analogReading = adc.newAnalogRead(pin,bitsOfResolution,numSamplesT oAvg,ADCSpeed); //UNCOMMENT TO USE //output results Serial.print("analogReading = "); Serial.print(analogReading); Serial.print(", Voltage (V) = "); Serial.println(5.0*analogReading/adc.getMaxPossibleReading(),5); //display up to 5 digits of precision //wait a bit before taking another reading, so as to not overburden the serial port delay(50); } //print adc settings void printValues() { Serial.print(F("bitsOfResolution = ")); Serial.println(adc.getBitsOfResolution()); Serial.print(F("MaxPossibleReading at this res = ")); Serial.println(adc.getMaxPossibleReading()); Serial.print(F("numSamplesToAvg = ")); Serial.println(adc.getNumSamplesToAvg()); Serial.print(F("ADCSpeedSetting = ")); Serial.println(adc.getADCSpeedSetting()); Serial.print(F("ADCClockFreq (Hz) = ")); Serial.println(adc.getADCClockFreq()); //Hz Serial.println(""); //new line }
Ευχαριστώ πολύ για τον χρόνο σας!