Electronics > Beginners
Arduino Code - volts/amps/power monitor
<< < (7/10) > >>
paulca:
Much better.  A few points.

This might not do what you think it does:

--- Code: ---  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }

--- End code ---

It will just return from the setup() method and the application will proceed onto the loop() anyway.  I'm not sure how exactly you would call "halt()" in Arduino, but you could do:

while(1){ delay(10000); }

Or better yet...

while(1){ digitalWrite(LED_BUILTIN, HIGH); delay(100); digitalWrite(LED_BUILTIN, LOW); delay(250);}

To signal "error" until the board is reset.

Alternatively, you can retry the card.  Just wrap the test:


--- Code: ---  while (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    digitalWrite(LED_BUILTIN, HIGH); delay(100); digitalWrite(LED_BUILTIN, LOW); delay(250);
  }

--- End code ---

Then it will wait until you insert the card.


--- Code: ---Serial.print(count);
  Serial.print("\taverages\t");
  Serial.print(volts);
  Serial.print("\tV\t");
  Serial.print(amps);
  Serial.print("\tA\t");
  Serial.print(ah);
  Serial.print("\tAh\t");
  Serial.print(watts);
  Serial.print("\tW\t");
  Serial.print(whr);
  Serial.print("\tWhr\t");
  Serial.print(maxVolts);
  Serial.print("\tVmax\t");
  Serial.print(minVolts);
  Serial.print("\tVmin\t");
  Serial.print(maxAmps);
  Serial.print("\tAmax\t");
  Serial.print(minAmps);
  Serial.print("\tAmin\t");
  Serial.print(time1/60000.0);
  Serial.println("\tmin\t");

--- End code ---
Becomes:


--- Code: ---char buffer[1024];
memset( buffer, 0, 1024 );
snprintf( buffer, 1024, "%d \t averages %.2fV %.2fA %.2fAh %2.fW %.2fWhr %.2fVmax %.2fVmin %.2fAmax %.2fAmin [%d] minutes",
              count, volts, amps, ah, watts, whr, maxVolts, minVolts, maxAmps, minAmps, time1/60000);
Serial.println(buffer);

--- End code ---

Or similar.  I didn't test compile that, but basically....

%d  - Integer value
%.2f - Decimal value with 2 decimal places.

For each "token" you place the value after the string in a list.

The only concern with regards an MCU here is you could run out of memory, allocating 1k of memory for the string to built up is nothing on a PC but I believe the ATMega 328p only has 8k total.  Of course if you work out the maximum length of the string to only be 256, then you can use a shorter buffer.

You can do the same for printing to the SD card, but I would recommend you use CSV format, then you can import the file into Excel or similar and graph it.

Note that as you use the same, more or less, print statement in two places, you could make it a function.  You will need to create the memory "buffer" in the common parent and pass the pointer to the string creation function and the two functions (serial and sdc) that use it.  Or just  put the

char buffer[512];  // or 256 if you can fit the string into it.

As a global.  Don't forget to memset it to 0 each time though ;)
frozenfrogz:

--- Quote from: paulca on March 12, 2018, 07:52:00 pm ---
--- Code: ---char buffer[1024];
memset( buffer, 0, 1024 );
snprintf( buffer, 1024, "%d \t averages %.2fV %.2fA %.2fAh %2.fW %.2fWhr %.2fVmax %.2fVmin %.2fAmax %.2fAmin [%d] minutes",
              count, volts, amps, ah, watts, whr, maxVolts, minVolts, maxAmps, minAmps, time1/60000);
Serial.println(buffer);

--- End code ---
Or similar.  I didn't test compile that, but basically....

%d  - Integer value
%.2f - Decimal value with 2 decimal places.

--- End quote ---

You wish!

Suggesting to use printf or sprintf to a buffer was also my initial thought. Needing hundreds of Serial.print() lines just to get some barely formatted text totally bugs me every time. Arduino sucks big time in that regard!
The printf() method is not implemented in the Serial class, so Serial.printf() will not compile.

In addition, sprintf() on Arduino does not understand doubles (%f %e %g). I read somewhere that this is on purpose, because of memory limitations of the smaller Atmegas.

To make some use of the above, you need to use dtostrf from the stdlib:

--- Code: ---#include<stdlib.h>
dtostrf(FLOAT,WIDTH,PRECISION,BUFFER);
--- End code ---

If there is a better way, I would love to hear it :)
Still trying to get my head around all of these Arduino »specialties«.

Might be another argument against using floats.
paulca:

--- Quote from: frozenfrogz on March 12, 2018, 08:14:32 pm ---In addition, sprintf() on Arduino does not understand doubles (%f %e %g). I read somewhere that this is on purpose, because of memory limitations of the smaller Atmegas.

--- End quote ---

Aww balls.  I know I've used it before, but not sure if I have used it with %f.   Aww well, it's the thought that counts. :)  You could always do:

"%d.%d", value, value*100%100

or something similarly cheesy.

I went hunting  for where I was formatting decimal output and sure enough; dtostrf:


--- Code: ---  sensorValue = analogRead(A1);
  vOut = (sensorValue * AREF) / 102.4;
  memset(buffer,0, 16); 
  dtostrf(vOut,5,1,buffer);
  oled.print("Is: "); oled.print(buffer); oled.print("A"); oled.clearToEOL(); oled.println();

--- End code ---

metrologist:
I started off reading fixed point math and that will have to wait.

One idea I had was to build a string and then send that to the serial and SD ports when needed.

String data = "";
data += count;
data += "\tavegs\t";
data += volts;
data += "\tV\t";
...
(that ^ wipes out my remaining program space)


I also implemented the below, but not because I understand it...


#define ADC_AMPS(a,count)  (((float)((float)a)*26.7)/(((float)count)*1024.0));
#define ADC_VOLTS(v,count) (((float)((float)v)*50.0)/(((float)count)*1024.0));
...
amps = ADC_AMPS(a,count);
volts = ADC_VOLTS(v,count);

Now, about 1023. I read more and suspect a routine could be applied. One suggesting is to simply add half a bit to the adc reading, or perhaps with k in the following a variable with value based on some factor.

V = (analogRead(pin) + k) * AREF / 1024;
with k of
0 for floor
0.5 for mean
1 for ceiling
paulca:

--- Quote from: metrologist on March 12, 2018, 08:53:14 pm ---String data = "";
data += count;
data += "\tavegs\t";
data += volts;
data += "\tV\t";

--- End quote ---

This works in Java, but it will only work in C++ if you use STL string class and it is Satan's niece.  Not because it's evil, but when it goes wrong it gives you errors like these:
https://codegolf.stackexchange.com/questions/1956/generate-the-longest-error-message-in-c

String streams are another option.
http://www.dreamincode.net/forums/topic/95826-stringstream-tutorial/

Not sure of AVR compat though.
Navigation
Message Index
Next page
Previous page
There was an error while thanking
Thanking...

Go to full version
Powered by SMFPacks Advanced Attachments Uploader Mod