| Electronics > Beginners |
| Arduino Code - volts/amps/power monitor |
| (1/10) > >> |
| metrologist:
I've been working on this for my solar system. It will display the panel voltage, current, and power consumed. I wanted some affirmation that the averaging routing and other calculations are correct. I've padded dummy data for the sensor reads. I'm noticing a steady 0.02 or 0.03 WHr discrepancy. --- Code: ---#include "U8glib.h" //U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE|U8G_I2C_OPT_DEV_0); // I2C / TWI U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_DEV_0|U8G_I2C_OPT_NO_ACK|U8G_I2C_OPT_FAST); // Fast I2C / TWI //U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NO_ACK); // Display which does not send AC float amps = 0; float volts = 0; float v = 0; float a = 0; float maxAmps = 0; float minAmps = 10; float maxVolts = 0; float minVolts = 50; float lastAmps = 0; float lastVolts = 0; float anoise = 0; float vnoise = 0; float ah = 0; float watts = 0; float whr; float time0 = 1; float time1 = 1; float count = 0; void setup(void) { Serial.begin(9600); // flip screen, if required // u8g.setRot180(); // assign default color value if ( u8g.getMode() == U8G_MODE_R3G3B2 ) { u8g.setColorIndex(255); // white } else if ( u8g.getMode() == U8G_MODE_GRAY2BIT ) { u8g.setColorIndex(3); // max intensity } else if ( u8g.getMode() == U8G_MODE_BW ) { u8g.setColorIndex(1); // pixel on } else if ( u8g.getMode() == U8G_MODE_HICOLOR ) { u8g.setHiColorByRGB(255,255,255); } pinMode(A0, INPUT); pinMode(A1, INPUT); pinMode(8, OUTPUT); } void loop(void) { if (millis() - time0 >= 100){ // fudge averaging time0 = millis(); count=count+1.0; //a = (analogRead(A0)- 509) * 26.7 / 1023; //v = analogRead(A1) * 4.6 / 1023; a = 60; //temporary test value v = 10; //temporary test value amps = amps + a; volts = volts + v; maxAmps = max(maxAmps, a); minAmps = min(minAmps, a); anoise = (maxAmps - minAmps); maxVolts = max(maxVolts, v); minVolts = min(minVolts, v); vnoise = (maxVolts - minVolts); if (millis() - time1 >= 5000){ amps = amps/count; volts = volts/count; watts = amps * volts; ah = ah + ((amps) * (millis() - time1)) / 3600000; whr = whr + ((watts) * (millis() - time1)) / 3600000; time1 = millis(); serial(); lcd(); count = 0; amps = 0; volts = 0; lastAmps = amps; lastVolts = volts; maxAmps = 0; minAmps = 10; maxVolts = 0; minVolts = 50; } } } void serial(void){ Serial.print(amps); Serial.print("A "); Serial.print(ah); Serial.print("Ah "); Serial.print(volts); Serial.print("V "); Serial.print(watts); Serial.print("W "); Serial.print(whr); Serial.print("Whr Noise: "); Serial.print(vnoise); Serial.print("Vn "); Serial.print(anoise); Serial.println("An"); Serial.print(maxVolts); Serial.print("Vmax "); Serial.print(minVolts); Serial.print("Vmin "); Serial.print(maxAmps); Serial.print("Amax "); Serial.print(minAmps); Serial.println("Amin "); Serial.println("."); } void lcd(void){ // picture loop u8g.firstPage(); do { draw1(); } while( u8g.nextPage() ); } void draw0(void) { } void draw1(void) { //graphic commands to redraw the complete screen should be placed here // u8g.setFontPosTop(); u8g.setFont(u8g_font_gdr14); u8g.setPrintPos(0, 14); u8g.print(volts); u8g.setFont(u8g_font_unifont); u8g.print("V"); u8g.setFont(u8g_font_gdr14); u8g.setPrintPos(66, 14); u8g.print(amps); u8g.setFont(u8g_font_unifont); u8g.print("A"); u8g.setFont(u8g_font_gdr14); u8g.setPrintPos(0, 31); u8g.print(ah); u8g.setFont(u8g_font_unifont); u8g.print(" AHr"); u8g.print((int)count); u8g.setFont(u8g_font_gdr14); u8g.setPrintPos(0, 48); u8g.print(watts); u8g.setFont(u8g_font_unifont); u8g.print(" watts"); u8g.setFont(u8g_font_gdr14); u8g.setPrintPos(0, 64); u8g.print(whr); u8g.setFont(u8g_font_unifont); u8g.print(" WHr"); u8g.print(millis()/6000.0); } --- End code --- |
| rstofer:
You're doing a lot of mixed mode arithmetic (it seems to me!). If you want to use floating point then make certain that all values in an expression are floating point. Float your constants or add a decimal point. We just had a thread where mixed mode arithmetic cause substantial errors. I would expect the compiler to promote integer constants to floating point when used with other floating point values in an evaluation but I guess we can't guarantee it. |
| Wimberleytech:
Ditto what rstofer said... A good example is your use of the variable count. It is typed as a float and in one case assigned a float and in another an int. A counter is typically typed as an int but you may have been worried about mixed arithmetic and so you typed it as a float but were not consistent. You could have typed it as an int and then use a cast to promote it to a float when doing an operation with a float. Doing so saves some compute cycles. |
| frozenfrogz:
The discrepancy you are describing is in respect to actual data compared to a power meter or from a fed data set vs. what you calculated yourself? If I understand correctly, you are polling every 0.1 seconds and calculating the cumulative moving average after 5 seconds. As rstofer pointed out, feeding integer values to floating point variables might or might not work as expected. |
| bitseeker:
Floating point arithmetic has many gotchas including inaccuracies (potentially huge ones) and performance penalties. If possible, you'll benefit from using and operating on either integer or fixed-point values instead. For example, if you need 1/1000 resolution, convert everything into millis (ms, mV, mA, etc.), accumulate and compute on them, and convert to "normal" values only on output. |
| Navigation |
| Message Index |
| Next page |