This code reads analog data continually 400 times (lines 86 - 91), then takes an average (line 92).
Is it wise to read the analog input so fast?
If this code needs to be modified to read 4 analog inputs, would it be a good idea to use an array and read consecutively in the same for-loop all 4 analog inputs?
does reading from different analog inputs not require more time for the ADC to settle, and how much more time?
/*
Version DCC_Booster_v1-4
http://www.trainelectronics.com/DCC_Arduino/DCC_Booster/
The H-Bridge can act as a DCC booster without much more than the Opto Coupler circuit
(top left of the schematic) and the one transistor converter (lower left).
The H-Bridge does hove an over current shutdown capability but it doesn't react until
well over 30 amps are being drawn, way more than we are going to use.
To get around this problem so that the system shuts down immediately if the track is
shorted an Arduino Pro Mini has been added. The Arduino monitors the current sensing
pin on the H-Bridge and can turn it off should it detect a high reading.
*/
#include<EEPROM.h>
int LED = 13; // LED to blink when DCC packets are sent in loop
int PowerOn = 3; // pin to turn booster on/off
int Pot1 = 1;
float PotReading = 0;
int CurrentPin = 0;
int CurrentPinReading = 0;
int SetPotFlag = 0;
float version = 1.4;
#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>
#define I2C_ADDR 0x27 // <<----- Add your address here. Find it from I2C Scanner
#define BACKLIGHT_PIN 3
#define En_pin 2
#define Rw_pin 1
#define Rs_pin 0
#define D4_pin 4
#define D5_pin 5
#define D6_pin 6
#define D7_pin 7
LiquidCrystal_I2C lcd(I2C_ADDR, En_pin, Rw_pin, Rs_pin, D4_pin, D5_pin, D6_pin, D7_pin);
unsigned long time;
unsigned long now;
long cAverage = 0;
int avgTimes = 400;
int lastAverage = 0;
int resetFlag = 0;
float percentage = 0;
int temp1 = 0;
void setup() {
delay(500);
pinMode(LED, OUTPUT);
pinMode(PowerOn, OUTPUT );
lcd.begin (16, 2); // LCD is 16 characters x 2 lines
lcd.setBacklightPin(BACKLIGHT_PIN, POSITIVE);
lcd.setBacklight(HIGH); // Switch on the backlight
lcd.home (); // go home
Serial.begin (115200);
lcd.setCursor(0, 0);
lcd.print("DCC Booster");
lcd.setCursor(0, 1);
lcd.print("2-11-16 - v");
lcd.print(version, 1);
Serial.print("2-11-2016 version ");
Serial.println(version, 1);
delay(1000);
lcd.clear();
turnPowerOn();
delay(500);
now = millis();
}
// NOTE: about 0.014 amps / digit of reading with 10K resistor on sense line
void loop() {
PotReading = analogRead(Pot1);
PotReading = PotReading / 100;
lcd.setCursor(12, 0);
lcd.print(PotReading, 1);
lcd.print(" ");
lcd.setCursor(7, 0);
lcd.print("MaxA=");
showPercentage();
resetFlag++;
if (resetFlag >= 100) {
resetFlag = 0;
}
cAverage = 0;
for (int xx = 0; xx < avgTimes ; xx++) {
CurrentPinReading = analogRead(CurrentPin);
if (CurrentPinReading >= 1000) {
Serial.println("STOPPPPPPPPPPPPPPPPPPPPPPING");
turnPowerOff();
}
cAverage = cAverage + CurrentPinReading;
}
CurrentPinReading = cAverage / avgTimes;
if (CurrentPinReading != lastAverage) {
if (millis() - now >= 450) { // only update LCD every 1/2 second to limit flicker
lcd.setCursor(0, 0);
lcd.print("C=");
lcd.print(CurrentPinReading);
lcd.print(" ");
}
turnPowerOn();
}
lastAverage = CurrentPinReading; // keep for compare & print
} //END LOOP
void showPercentage()
{
percentage = (CurrentPinReading * 0.0105) / PotReading; // was 0.014
percentage = percentage * 100;
if (millis() - now >= 500) // only update LCD every 1/2 second to limit flicker
{
lcd.setCursor(9, 1);
lcd.print(percentage,1);
lcd.print("% ");
now = millis();
}
if (percentage > 100) turnPowerOff();
}
void turnPowerOff() {
digitalWrite(PowerOn, LOW);
lcd.setCursor(0, 1);
lcd.print("PWR OFF-2 sec");
delay(2000);
turnPowerOn();
lcd.setCursor(0, 1);
lcd.print(" ");
}
void turnPowerOn() {
digitalWrite(PowerOn, HIGH);
lcd.setCursor(0, 1);
lcd.print("PWR On");
}
For question 3 the dummy read configures the ADC to take its input from the given pin (load a small cap) which lets the voltage settle if there is a large change from the previous pin (edit: and impedance is not in usual range)
The spec has all the detailed information
For question 1 I’m not sure what you expect from so many reads…
I had been thinking the same thing: the purpose is to be able to react fast as soon as overcurrent is detected but without false detections causing a shutdown.
I thought more something like this: take very fast 10 readings, eliminate the 2 outliers (min and max from the 10 readings) and divide by 8. Or something like that.
Other, better ideas?
What would be an acceptable time? You can do some timed readings using millis(); read the 4 inputs (will take approx. 800 microseconds including the dummies), wait e.g. 100 milliseconds and do a second reading of the 4 inputs. You can speed up the reading by using 8-bit resolution instead of 10-bit; for the given purpose, I don't think that that will pose a problem.
There is no need to do that if the input impedance of the thing driving the analogue inputs is 10K or so. You only need a double read when the driving impedance is a lot higher.
I can't see anything in that original code that reads the A/D faster than the normal speed. There are tricks where you can speed up the read by altering the prescaler values.
Remember any D/A is always subject to +/- 1 least significant bit, taking the avrage of 400 readings seems to me to be a bit of an overkill, especial as you are only using ints in your averaging.
How long do you want to wait to determine if it's really an overload? I stated "e.g.", if you think that 5 milliseconds will be sufficient, you can use that. The advantage that I see is that your code can do other things and does not have to wait for N readings to be completed.
Oh good to know too. the driving impedance is about 1k.
400 readings indeed are unnecessary; I will rather take ten, discard 2 outliers and average over 8.
And use long unsigned int.
If you want an average then you should be using a float to find the average. As I said the digital readings should be all the same except for the least significant bit.
Are your readings more noisy than that? With 1K drive they shouldn't be unless you have a source of interference or have wired the grounds in series with a high current load, that is causing ground bounce.
Or the voltage on the inputs are not stable.
On ATmega based boards (UNO, Nano, Mini, Mega), it takes about 100 microseconds (0.0001 s) to read an analog input, so the maximum reading rate is about 10,000 times a second.
The Arduino Nano ADC is set at 10 ksps, but can be much faster if you're willing to sacrifice a little accuracy. I used ATmega88 with ADCSRA register set up for faster ADC reading.