According to ...
https://www.arduino.cc/reference/en/language/functions/analog-io/analogread/
"the maximum reading rate is about 10,000 times a second".
Anything seems possible when you don't know what you're talking about.
Thanks for the response. I now have a working voltage recorder and LCD display based on the Hall-effect sensor.
I'm now trying to create a current data logger based on an ACS712 bought from Amazon - WayInTop-US. The code works well but I have very odd results suggesting the device should have VCC connected to a much lower voltage than the Arduino nominal 5V or my 4020 reference voltage regulator chip.
The issue is that the A/D pin that's reading the ACS712 sensor gives a value that's too high.
Has anyone else found similar issues with that brand?
The ACS712 device from WayInTop seems to be almost identical to the one Will used in his tutorial except the circuit components and pins are 'handed'.
Oddly, the Amazon information indicates connecting VCC to 3.3V / 5V. I thought connecting VCC to the Reference 4.098V would be great. But, with nothing connected to the sensed terminals, the sketch shoes about 0.6A. Connecting to the Arduino's 5V, the sketch shows 7.5A. In both, I changed to code to match the VCC voltage supplied.
I have the centre signal pin going to A2 because A0 is in use for the hardware, and A1 is the voltage feather sensor.
I can see the A/D readings because I changed the code to summate the pin values over a series of readings, then divide by the number of readings, before calculating the apparent voltage. Then, I wrote out all of the data used in the calculations and the results. All made sense, except the A/D readings.
With 5V supplied
Hi, just now looking at the results of your print out, and a couple of things come to mind...
First, I have a couple of questions:, have you measured your circuit with a multi meter on amp scale to see what is actually the current you are using.. I see by your ACS712 scaling that you are using a 30A module. second, did you change the analogReference() command in you code to tell the Arduino that your using an external reference..this will make a big difference in how the ADC converts the counts to voltage.. example: the resolution of a 5 v reference is 0.004828125 mV/count, but for a 4.096 V external reference it is 0.004 mV/count. for more information on the analogReference() , see https://www.arduino.cc/en/Reference.AnalogReference
It will be more helpful if you can provide a copy of your code as well, as we are just guessing at what might be the problem.
hope this helps, good luck,
Regards,
LouisR
LouisR
I've set up the board using the 4020 reference connected to VCC. And, changed the code as I believe I should.
Rather than take multiple readings and average, with the risk of getting the wrong divider count, I disabled that and took one reading. The results using the same print out code shown earlier were:
0.004 is right for a 4.096 V refer and 1024 divisions, 2.046 is VRef/2, and 0.066 is correct for the 30A board. But the 521 to 523 count is off. The rest follows from the count and input values.
I've attached the diagnostic code that gave these results.
WRT reference voltage use, the code includes:
/* Current Data Logger to SD Card and LCD Display */ #include <Adafruit_RGBLCDShield.h> #include <utility/Adafruit_MCP23017.h> #include <SPI.h> #include <SD.h> #include <Wire.h> #include "RTClib.h" #define ECHO_TO_SERIAL 1 // Control whether data echoed to serial monitor for debugging #define WRITE_TO_SD 0 // Control whether data is written to SD Card during degugging // the digital pins that connect to the LEDs //#define redLEDpin 2 //#define greenLEDpin 3 // The LCD shield uses the I2C SCL and SDA pins. On classic Arduinos // this is Analog 4 and 5 so you can't use those for analogRead() anymore // However, you can connect other I2C sensors to the I2C bus and share // the I2C bus. Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield(); // These #defines make it easy to set the backlight color #define RED 0x1 #define YELLOW 0x3 #define GREEN 0x2 #define TEAL 0x6 #define BLUE 0x4 #define VIOLET 0x5 #define WHITE 0x7 RTC_PCF8523 RTC; // define the Real Time Clock object // for the data logging shield, we use digital pin 10 for the SD cs line const int chipSelect = 10; // the logging file File myFile; // The voltage breakout board uses pin A1 // Define analog input #define ANALOG_AIN_PIN A2 // Variables for measured voltage and calculated current on ACS712 double Vout = 0; double VADC = 0; double Current = 0; // Constants for Scale Factor // Use one that matches your version of ACS712 //const double scale_factor = 0.185; // 5A //const double scale_factor = 0.1; // 20A const double scale_factor = 0.066; // 30A // Constants for A/D converter resolution // Arduino has 10-bit ADC, so 1024 possible values // Reference voltage is 5V if not using AREF external reference // Zero point is half of Reference Voltage const double vRef = 4.096; const double resConvert = 1024; double resADC = vRef/resConvert; double zeroPoint = vRef/2; // Timer for current measurements unsigned long startMillis; unsigned long currentMillis; unsigned long elapsedMillis; void error(char *str) { Serial.print("error: "); Serial.println(str); // red LED indicates error //digitalWrite(redLEDpin, HIGH); while(1); } void setup(void) { Serial.begin(9600); // Debugging LCD output // set up the LCD's number of columns and rows: lcd.begin(16, 2); // Use external voltage reference analogReference(EXTERNAL); // Setup Serial Monitor // use debugging LEDs //pinMode(redLEDpin, OUTPUT); //pinMode(greenLEDpin, OUTPUT); // Setup SD Card #if WRITE_TO_SD while (!Serial) { ; // Wait for serial port to connect } Serial.print("Initializing SD Card ..."); if (!SD.begin(10)) { Serial.println("initialization failed!"); while(1); } Serial.println("initialization done."); // Open the file. Note that only one file can be open at a time. myFile = SD.open("Output.txt", FILE_WRITE); // if the file opened OK, write to it: if (myFile) { Serial.print("Writing test to file."); myFile.println("Current recording at short intervals"); // Close the file myFile.close(); Serial.println("Done"); } else { // if the file didn't open, print an error Serial.println("error opening file"); } #endif // connect to RTC Wire.begin(); if (!RTC.begin()) { #if ECHO_TO_SERIAL Serial.println("RTC failed"); #endif //ECHO_TO_SERIAL #if WRITE_TO_SD myFile.println("RTC failed"); #endif } #if ECHO_TO_SERIAL Serial.println("millisecs, Amp"); #endif //ECHO_TO_SERIAL #if WRITE_TO_SD myFile = SD.open("Output.txt", FILE_WRITE); Serial.println("millisecs, Amps"); // Close the file myFile.close(); #endif // Start timer startMillis = millis(); //initial start time } void loop(void) { //Measure current at about 1s intervals using ACS712 //Vout is read 10 Times for precision of current calculation // Reset Vout Vout = 0; VADC = 0; //for(int i = 0; i < 10; i++) { VADC = (VADC + analogRead(ANALOG_AIN_PIN)); delay(1); //} // Get average of i-readings for Vout in mv Vout = VADC * resADC / 1; // Convert Vout into Current using Scale Factor Current = (Vout - zeroPoint)/scale_factor; // fetch the time currentMillis = millis(); //get the current "time" (actually the number of ms elapsed) elapsedMillis = currentMillis - startMillis; // Print to the LCD lcd.setBacklight(WHITE); lcd.setCursor(1,0); lcd.print("Volts = "); lcd.print(Vout-zeroPoint, 4); lcd.println(" "); lcd.setCursor(1,1); lcd.print("Current = "); lcd.print(Current, 4); lcd.println(" "); // Print Vout and Current #if ECHO_TO_SERIAL Serial.print(resADC,6); Serial.print(", "); Serial.print(zeroPoint,4); Serial.print(", "); Serial.print(scale_factor,4); Serial.print(", "); Serial.print(VADC,4); Serial.print(", "); Serial.print(Vout,4); Serial.print(", "); Serial.print(Vout-zeroPoint,4); Serial.print(", "); Serial.print(Current,4); Serial.println(); //Serial.print(elapsedMillis); //Serial.print(" ms ,Vout = "); //Serial.print(Vout,2); //Serial.print(" Volts"); //Serial.print("\t Current = "); //Serial.print(Current,2); //Serial.println(" Amps"); //Serial.println(); #endif #if WRITE_TO_SD myFile = SD.open("Output.txt", FILE_WRITE); myFile.print(elapsedMillis); myFile.print(" ms, Vout = "); myFile.print(Vout, 2); myFile.print(" Volts"); myFile.print("\t Current = "); myFile.print(Current, 2); myFile.println(" Amps"); // Close the file myFile.close(); #endif // Short delay delay(950); //} }
Physically, the VCC on ACS712 board is connected to the 4020 board 4.096V output pin and to the Uno VRef pin.
See attached document for how to wire up an external voltage reference
also note the following:
Arduino megaAVR Boards (Uno WiFi Rev2)
-
DEFAULT: a built-in 0.55V reference
-
INTERNAL: a built-in 0.55V reference
-
VDD: Vdd of the ATmega4809. 5V on the Uno WiFi Rev2
-
INTERNAL0V55: a built-in 0.55V reference
-
INTERNAL1V1: a built-in 1.1V reference
-
INTERNAL1V5: a built-in 1.5V reference
-
INTERNAL2V5: a built-in 2.5V reference
-
INTERNAL4V3: a built-in 4.3V reference
-
EXTERNAL: the voltage applied to the AREF pin (0 to 5V only) is used as the reference
example: analogReference(EXTERNAL)
Notes and Warnings
After changing the analog reference, the first few readings from analogRead()
may not be accurate.
Don’t use anything less than 0V or more than 5V for external reference voltage on the AREF pin! If you’re using an external reference on the AREF pin, you must set the analog reference to EXTERNAL before calling analogRead()
. Otherwise, you will short together the active reference voltage (internally generated) and the AREF pin, possibly damaging the microcontroller on your Arduino board.
Alternatively, you can connect the external reference voltage to the AREF pin through a 5K resistor, allowing you to switch between external and internal reference voltages. Note that the resistor will alter the voltage that gets used as the reference because there is an internal 32K resistor on the AREF pin. The two act as a voltage divider, so, for example, 2.5V applied through the resistor will yield 2.5 * 32 / (32 + 5) = ~2.2V at the AREF pin.
regards,
LouisR
LouisR
Question: How do you know the count is off.. have you measured the current in the circuit with a multi-meter in (current mode)? The math and the formulas look ok, so unless you have a floating ground, I can see no reason why this shouldn't work.. Check your grounding from the ACS712 to the Arduino to make sure you don't have a bad connection or a broken wire.. check this with an ohm meter to rule that out.. those tiny wires are easy to break! good luck,
Regards,
LouisR
LouisR
I’ll check the soldering tomorrow.
Your last but one response showed the connections for the voltage sensor but my problem is with the ACS712 current sensor. Apart from checking everything is soldered well, my doubts lie with how the ACS712 VCC pin should be connected. I connected it to the 4020 board’s 4.096V pin that is already connected to the Arduino ARef pin. But now I’m wondering if that’s correct.
Note, the same Adafruit data logger board that I used to successfully set up 25V voltage and 4020 reference boards, was modified by adding the ACS712. The signals from each sensor board were taken to different pins, A1 and A2, but there are interconnections because both are on the same data logger and share grounds and +ve.
For a build with only the ACS712 and the 4020 voltage reference, it isn’t clear to me how they should be wired. Without the 4020, the wiring would be as your tutorial, i.e. VCC to Arduino 5V, Signal to A2 or similar and -Ve to Arduino GND. But with the 4020 added to Arduino ARef, should the ACS712 wiring change so VCC connects elsewhere?
At the root of this is perhaps my lack of understanding of how the Arduino A/D system works without and with an external VRef. My understanding is that the ACS712 Hall-effect current sensor works by splitting the voltage between GND and VCC pins so that a portion related to current goes to the Signal pin with the A/D converter generates a digital code.
I think your problem lies in the connection to the 4020 ref board. It is for reference ONLY.. no other connections to it as it has no capability to source any current.. The ACS712 VCC is connected to the Arduino +5v on the board, See attached file below. The reference board 4020 only affect the reference voltage used by the ADC mux., not the 5v buss that the ACS712 is using for power.. With the external reference board you get a little more resolution for the ADC , ~ 4 mV, (0.004) as opposed to the internal reference of 5v +/- 50 mV (at 1% tolerance) of 4.883 mV ( 0.004883). this will, in affect the accuracy of your counts in the ADC mux. But I digress.. I digital & analog inputs are subject to wild variations when their inputs are not connected, or grounding issues are present..Your on the right track.. just stick with it, and I'm sure you'll fix the problem..BTW,The code for your project is impressive..I'm not new to programming, but I'm just learning C++ after 30+ years of using MS VBA, and other industrial OOP like PLC (Programmatical Load Controller) and DCS (Distributed Control Systems) to program industrial control systems.. At 75, I'm still learning, lol
Good luck, and keep me advised.. I'll probably be hitting you up on tips on programming.. it's a steep curve for ol' timers like me...hehehe
Regards,
LouisR
LouisR
I've took the ACS712 off the same data logger board as the 30V voltage sensor and LM4040 reference voltage card, and now have 'sensible' zero results from the ACS712. That is the readings with no current is close enough to zero that it is within the 512 +/- 2 bits accuracy limit that might be expected of the A/D converter. I have to get another LM4040 reference voltage card so see if that makes any difference.
Using a multimeter to check the Arduino nominal 5V to GND, I found the voltage was actually a bit lower than 5V. That lead me to change the code to more replicate the voltage. And, then to lower it a bit more. Surprisingly, the specified vRef didn't really alter the measured zero with no external current.
In western Canada, I'm at the end of a long supply line for less common Adafruit parts, so it might be a while before I get another LM4040 reference voltage card. The shipping cost is much more than the item, too. So, it might be a while before I test the setup with an LM4040 added.
My next step is to measure check values from the ACS712 with a know current as you suggested.
To summarise, it seems there was some odd interaction between the two measurement cards or the ACS712 and the LM4040 aren't compatible, that led to the patently incorrect readings.
Good job!..Indeed, I did some measurement checking my self on the LM4020, and the Arduino Vcc +5V pin & Vref pin with external circuit loading, and unloading: In the attached file are are some of the results that I found. In conclusion, The results show that using the Arduino +5v pin to power anything over a few mA will pull the 5V down.. So I recommend using external power supply to power your circuits that are being connected to the Arduino, inputs and outputs.. making sure you tie the negative of the supply to the Arduino gnd connection to prevent ground loops, which can severely impact your readings.
See attached word doc for results of test:
kind regards,
LouisR
LouisR
You are most helpful to do that work. I’ll have to wait a bit for parts. And, find a way to rig up a separate PS. Unlike you, I don’t have a bench power supply.
I’m now looking at the Adafruit ADS1115 and ADS1015, which offer much greater precision in the analogue - digital conversion, albeit at a fair loss of sampling speed.
I’ll likely go silent for a while as I deal with other matters and supply chains.
LouisR
I’ve now had a chance to try different LM4040 voltage regulator and a new data logger board, i.e. a clean setup completely disconnected from the voltage measuring board that I thought might be the issue. However, the current measuring ACS712 still produces completely incorrect results when the voltage regulator is connected. Without the voltage regulator, the ACS712 shows a no load i.e. “zero” value, that one might expect, i.e. one or two bits wrong, <+/- 0.1A with a 30A range board. With a small current, the reading shifts about the right amount. I will have to try the ACS712 with a large current and use another meter of known accuracy to confirm it works accurately near the top end of it’s range, i.e. 30A for the one I am using.
I’ve not tried a separate power supply. That would be more complex than I feel is reasonable.
Thank you Bill.
I modified this sketch to control a battery charger so it can give a high signal to a gren led when battery voltage is above 13.8V and as well switch off charging via a relay module.
its not working. please i appreciate any help
// Define analog input #define ANALOG_IN_PIN A0 // Floats for ADC voltage & Input voltage float adc_voltage = 0.0; float in_voltage = 0.0; // Floats for resistor values in divider (in ohms) float R1 = 30000.0; float R2 = 7500.0; // Float for Reference Voltage float ref_voltage = 5.0; // Integer for ADC value int adc_value = 0; // other parameters for battery control and user interfaces int redled = 13; int greenled = 12; int blueled = 8; int cutoffhigh = 7; int cutofflow = 4; void setup(){ // Setup Serial Monitor Serial.begin(115200); Serial.println("DC Voltage Test"); pinMode(redled, OUTPUT); pinMode(greenled, OUTPUT); pinMode(blueled, OUTPUT); pinMode(cutoffhigh, OUTPUT); pinMode(cutofflow, OUTPUT); } void loop(){ // Read the Analog Input adc_value = analogRead(ANALOG_IN_PIN); // Determine voltage at ADC input adc_voltage = (adc_value * ref_voltage) / 1024.0; // Calculate voltage at divider input in_voltage = adc_voltage / (R2/(R1+R2)); // Print results to Serial Monitor to 2 decimal places Serial.print("Input Voltage = "); Serial.println(in_voltage, 2); // Short delay delay(500); if( in_voltage >=0.00 && in_voltage <=10.00){ digitalWrite(cutofflow, HIGH); digitalWrite(cutoffhigh, LOW); digitalWrite(redled, LOW); digitalWrite(greenled, LOW); digitalWrite(blueled, LOW); } else if(in_voltage >=10.10 && in_voltage <= 10.80){ digitalWrite(cutofflow, LOW); digitalWrite(cutoffhigh, LOW); digitalWrite(redled, HIGH); digitalWrite(greenled, LOW); digitalWrite(blueled, LOW); } else if( in_voltage >10.81 && in_voltage <= 12.29 ){ digitalWrite(cutofflow, LOW); digitalWrite(cutoffhigh, LOW); digitalWrite(redled, LOW); digitalWrite(greenled, LOW); digitalWrite(blueled, HIGH); } else if (in_voltage >= 12.30 && in_voltage <= 12.49){ digitalWrite(cutofflow, LOW); digitalWrite(cutoffhigh, LOW); digitalWrite(redled, LOW); digitalWrite(greenled, HIGH); digitalWrite(blueled, LOW); } else if (in_voltage >12.50 && in_voltage >=12.6){ digitalWrite(cutofflow, LOW); digitalWrite(cutoffhigh, HIGH); digitalWrite(redled, LOW); digitalWrite(greenled, LOW); digitalWrite(blueled, LOW); } else { digitalWrite(cutofflow, LOW); digitalWrite(cutoffhigh, LOW); digitalWrite(redled, LOW); digitalWrite(greenled, LOW); digitalWrite(blueled, LOW); } }