Mäta spänning & ström med Arduino
Postat: 20 juni 2012, 15:56:46
Jag tänker bygga olika apparater som mäter spänning & ström. Exvis solcellsregulator. Det jag märkt är att det är inte helt enkelt att mäta med någorlunda god nogrannhet. Här kommer en liten sammanställning av mina tester och slutsatser som jag hoppas få kommentarer på.
I de fall man (mha Arduino) vill mäta spänning och ström någorlunda exakt kommer man ganska snart till slutsatsen att de flesta exempel & tutorials inte ger några bra mätvärden. Exvis utgår många exempel från att den interna 5V-spänningen är exakt 5 volt, vilket den inte alltid är.
I en del andra exempel använder man då den interna 1.1V referensen men inte heller den är exakt (se stycke ADC Characteristics i http://www.atmel.com/Images/doc8161.pdf). Ett exempel där 1.1V referensen används (med mindre bra resultat) http://www.arduino.cc/playground/Main/CurrentSensing.
Experiment
Vid behov finns läsning om mätning på en analog ingång http://arduino.cc/it/Reference/AnalogReference.
I experimenten nedan vill vi kunna variera den interna 5V spänningen en aning mellan de olika testerna. Detta för att vi vill kunna mäta ”rätt” analog inspänning oavsett andra omständigheter.
I mitt fall använder jag olika USB-kablar. Vissa tunna USB-kablar ger en lägre spänning.
I samtliga mina experiment utgår jag från att mitt spänningsaggregat är "sanningen". Det är såklart inte sant men det duger i de här experimenten.
Experiment #1a
Mätning med 5V referens (DEFAULT). Power supply kopplad till analog ingång. Med exakt samma spänning (4.0 volt) mäter vi värdet på ingången med de olika intern 5V (olika USB-kablar).
Trots att vi har exakt samma spänning på analoga ingången kommer vi att få olika värden på avläsningen eftersom Arduino använder den interna 5v som en referens vid mätningen.
Experiment #1b
Användning av Arduinos interna 1.1V referens. Anslut en voltmeter till pinne 5V och kör följande program och jämför.
Prova oxå med olika Arduinon och jämför.
Experiment #2
Med hjälp av en mycket noggrann spänningsreferens ta reda på Arduinons egentliga värde på 1.1 volt referens.
TL431 ger 2.495 volt med en viss noggrannhet som specificeras i databladet. Några vanliga värden är 0.5%, 1% & 2%. Man bör använda 1% eller noggrannare. Det måste flöda minst 1mA genom TL431 för att den ska fungera. Därför ska motståndet R inte vara för stort. Ett värde runt 1kohm bör fungera. I=2.5/1000=2.5mA. I fallet med en National LM431BCZ är spänningen mellan 2.470 & 2.520. Tillräckligt noggrant för att vi ska anse det vara 2.5V. I Arduino-programmet läser vi av analoga ingången och kan därmed ta reda på vilket värde den interna 1.1V referensen egentligen har.
I mitt fall när jag har fler än en Arduino görs detta för samtliga genom att numrera dem var och en och sedan dokumentera värdena i en tabell.
Med följande kalibreringsprogram kan man ta reda på värdet för 1.1 volt referensen för varje enskild Arduino. Programmet är uppdelat på så sätt att man tar reda på den aktuella Arduinons korrekta 1.1 volt referens i två steg. Steg ett itererar från 1.0 till 1.2 volt och visar de värden som ligger nära den aktuella 2.5 volt som anslutits till analog ingång A0. När man fått fram ett ungefärligt värde övergår man till steg 2 genom att ange det nya värdet i början av koden (long ref_1_1volt = xxxxL;) och aktiverar int step = 2;. När man sedan exekverar ska värdet som visas vara mycket nära 2500.
Om man vill kan man lagra denna information i EEPROM för varje enskild Arduino så att man slipper ange värdet i koden.
Experiment #4
Om den interna 1.1volt referensen inte är tillräckligt bra kan man använda en extern referens kopplad till ingången Aref. Det finns olika referenser som är mycket exakta (ex REF02, TL431 & spänningsdelare). Om man använder TL431 bör man tänka på att motstånden i spänningsdelaren har en noggrannhet som påverkar den totala noggrannheten förutom noggrannheten i TL431. Använd helst 0.1% motstånd el nogrannare.
Oavsett vilken referens man har måste man dessutom försäkra sig om att man har mellan 7 & 12 volt matning till Arduinon.
I de fall man (mha Arduino) vill mäta spänning och ström någorlunda exakt kommer man ganska snart till slutsatsen att de flesta exempel & tutorials inte ger några bra mätvärden. Exvis utgår många exempel från att den interna 5V-spänningen är exakt 5 volt, vilket den inte alltid är.
I en del andra exempel använder man då den interna 1.1V referensen men inte heller den är exakt (se stycke ADC Characteristics i http://www.atmel.com/Images/doc8161.pdf). Ett exempel där 1.1V referensen används (med mindre bra resultat) http://www.arduino.cc/playground/Main/CurrentSensing.
Experiment
Vid behov finns läsning om mätning på en analog ingång http://arduino.cc/it/Reference/AnalogReference.
I experimenten nedan vill vi kunna variera den interna 5V spänningen en aning mellan de olika testerna. Detta för att vi vill kunna mäta ”rätt” analog inspänning oavsett andra omständigheter.
I mitt fall använder jag olika USB-kablar. Vissa tunna USB-kablar ger en lägre spänning.
I samtliga mina experiment utgår jag från att mitt spänningsaggregat är "sanningen". Det är såklart inte sant men det duger i de här experimenten.
Experiment #1a
Mätning med 5V referens (DEFAULT). Power supply kopplad till analog ingång. Med exakt samma spänning (4.0 volt) mäter vi värdet på ingången med de olika intern 5V (olika USB-kablar).
Trots att vi har exakt samma spänning på analoga ingången kommer vi att få olika värden på avläsningen eftersom Arduino använder den interna 5v som en referens vid mätningen.
Experiment #1b
Användning av Arduinos interna 1.1V referens. Anslut en voltmeter till pinne 5V och kör följande program och jämför.
Prova oxå med olika Arduinon och jämför.
Kod: Markera allt
void loop(){
long InternalVcc = readInternalVcc();
Serial.print("InternalVcc: ");
Serial.print(InternalVcc, DEC);
Serial.println("");
delay(1000);
}
long readInternalVcc() {
long result;
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
delay(2); // Wait for Vref to settle
ADCSRA |= _BV(ADSC); // Convert
while (bit_is_set(ADCSRA,ADSC));
result = ADCL;
result |= ADCH<<8;
result = 1126400L / result; // Back-calculate AVcc in mV
return result;
}
Med hjälp av en mycket noggrann spänningsreferens ta reda på Arduinons egentliga värde på 1.1 volt referens.
TL431 ger 2.495 volt med en viss noggrannhet som specificeras i databladet. Några vanliga värden är 0.5%, 1% & 2%. Man bör använda 1% eller noggrannare. Det måste flöda minst 1mA genom TL431 för att den ska fungera. Därför ska motståndet R inte vara för stort. Ett värde runt 1kohm bör fungera. I=2.5/1000=2.5mA. I fallet med en National LM431BCZ är spänningen mellan 2.470 & 2.520. Tillräckligt noggrant för att vi ska anse det vara 2.5V. I Arduino-programmet läser vi av analoga ingången och kan därmed ta reda på vilket värde den interna 1.1V referensen egentligen har.
I mitt fall när jag har fler än en Arduino görs detta för samtliga genom att numrera dem var och en och sedan dokumentera värdena i en tabell.
Med följande kalibreringsprogram kan man ta reda på värdet för 1.1 volt referensen för varje enskild Arduino. Programmet är uppdelat på så sätt att man tar reda på den aktuella Arduinons korrekta 1.1 volt referens i två steg. Steg ett itererar från 1.0 till 1.2 volt och visar de värden som ligger nära den aktuella 2.5 volt som anslutits till analog ingång A0. När man fått fram ett ungefärligt värde övergår man till steg 2 genom att ange det nya värdet i början av koden (long ref_1_1volt = xxxxL;) och aktiverar int step = 2;. När man sedan exekverar ska värdet som visas vara mycket nära 2500.
Kod: Markera allt
long ref_1_1volt = 1068L; // Corrected 1.1 V reference in mV
/*
* To find the best value of the inernal 1.1V volt reference of the
* current Arduino unit you can execute the following two steps:
* 1/ Iterate to find values that match the voltage connected to input A0
* 2/ Set the value of 1.1 ref and see if input A0 reads correct after setting
* the ref_1_1volt above.
*/
//int step = 1;
int step = 2;
long sensorValue;
void setup() {
pinMode(A0, INPUT);
Serial.begin(57600);
}
void loop() {
sensorValue = analogRead(A0);
if (step == 1) {
Serial.println("one");
long ref = 0;
long v = 0;
// Iterate from 1.0 to 1.2 volt
for (long i=1000; i<=1200; i++) {
ref_1_1volt = i;
v = sensorValue * readVcc() /1024;
if (v < 2505 && v > 2495) {
Serial.print(" adjusted 1.1 ref: "); Serial.print(ref_1_1volt);
Serial.print(" => "); Serial.print(v);
ref = ref_1_1volt;
}
}
ref_1_1volt = ref;
} else {
Serial.print(" calibrated internalVcc: "); Serial.print(readVcc());
Serial.print(" input ADC: "); Serial.print(sensorValue);
Serial.print(" adjusted input volt: "); Serial.print(sensorValue * readVcc() /1024);
}
Serial.println(" ");
delay(1000);
}
// Read 1.1V reference against AVcc
long readVcc() {
long result; // Read 1.1V reference against AVcc
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
delay(2); // Wait for Vref to settle
ADCSRA |= _BV(ADSC); // Convert
while (bit_is_set(ADCSRA,ADSC));
result = ADCL;
result |= ADCH<<8;
// Use an adjusted value for 1.1 volt ref.
result = ref_1_1volt * 1024L / result; // Back-calculate AVcc in mV
return result;
}
Experiment #4
Om den interna 1.1volt referensen inte är tillräckligt bra kan man använda en extern referens kopplad till ingången Aref. Det finns olika referenser som är mycket exakta (ex REF02, TL431 & spänningsdelare). Om man använder TL431 bör man tänka på att motstånden i spänningsdelaren har en noggrannhet som påverkar den totala noggrannheten förutom noggrannheten i TL431. Använd helst 0.1% motstånd el nogrannare.
Oavsett vilken referens man har måste man dessutom försäkra sig om att man har mellan 7 & 12 volt matning till Arduinon.