Output variable at time intervals

That's when I was suggesting that doing a little light cleaning to the code would help you get done faster and would help you get better help so you don't waste as much time with people not being able to read your code. You called it a waste of time. I didn't. You did.

None of the other stuff is any different. Fixing up the variable names? Hit refactor and type over one of them. Takes like 3 seconds. Could shave a day or two off of trying to get help here when you make some error that you can't necessarily see obvious to someone here.

why not something like this?


const int N = 100;
int   adcVal [N];
int   idx;

const unsigned long FifteenSec = 15 * 1000;
      unsigned long msec0;

// -----------------------------------------------------------------------------
void
loop (void)
{
    unsigned long msec = millis ();

    if (msec < msec0 || N <= idx)
        return;

    msec0 += FifteenSec;

    adcVal [idx++] = analogRead (A0);

    // performCalcultions();
    // displayUpdate();
}

void
setup (void)
{
    Serial.begin (9600);
}

So what you're saying is that you need to display the discharge history over a period of time? And to do that, you want to have a series of values spaced evenly through that time period? From your first post:

But this needs to create from 20-40 different variables so I am trying to make this into a struct and increase the variable every time the interval comes up. This might be the wrong approach, but I'm trying something. What this is doing is measuring the voltage of a battery during discharge every 15 seconds. I need to print these values to a display. I'll figure out the printing to a display after I get this part done. But when just trying to print this to Serial I am not getting anything.

There's a lot of misunderstanding along the way that might have been alleviated with a better description of purpose and need. This isn't 40 discrete variables, it's a time series of values for a single variable. Again, the language we use is important. I understand, you're learning, but constructively, I hope you'll glean from this that a clear problem description up front makes a world of difference. If a tenth of the time and anguish you've put into this thread so far had been put into problem presentation, we might not be at this point. There's a world of helpers here, if you work hard to gain their attention by concise problem presentation.

I think, re-reading that single paragraph, that you hope eventually to actually graph, or chart, the voltage/time performance on your TFT. I look forward to seeing that.

2 Likes

Let me guess, only in V2.x, right? I'll stick to 'find and replace'.

Yes! This is a voltage vs time plot. Well, graphing would be great, it is on the list, but that is way over my head...

I probably had the wrong idea going in. I thought using the same variable and having to display that in multiple locations would update that variable in every location every time the interval was up. So I thought make a separate variable for each interval. On page 4 of my menu, it shows the running discharge data. Real time voltage for the pack (voltageFull), real time voltage for each cell, discharge rate, time, mAh taken out of the battery. So the user can see real time data, but they want to see the voltage drop over time. Then use this to compare against other batteries.

But yes, you have the idea of what I want to do.

Even F&R is just a couple of seconds.

I actually tried out the leaky integration formula in an earlier version of this code. It worked for one sensor, but I have 3 sensors and I had issues using it for the others. As to the voltage being stable. Yes it should be, but it fluctuates quite a bit in the 20mV range. Fluctuating a couple of mV is fine, but 20mV is a lot. The system uses pwm to maintain a constant current discharge, with the PI controller. I've got low pass filters in the hardware for the voltage sensors and putting my scope on them shows a dc line, but there is still fluctuation that I am taking care of with averaging. I've tried a lot of different sample sizes, and 1000 seems good.

Yes, but I expect refactor doesn't change similar words in comments as well, willy-nilly, only occurrences in the actual code.
/Tangent

so you're going to sample ever 15 msec, sum the samples and every 15 secs use that value / 1000 as the measured value?

No,

voltageFull is calculated in my getCalculations() function. It is an average of 1000 reads. getCalculations() updates every time through the loop if current page =4. On page 4 of the display it show voltageFull and updates continuously. So all the calculations are done, this variable is ready to use for what I want.

Now, lets just take a picture of the value of the variable starting at time=0 (press the discharge button) and every 15 seconds after that until the discharge is done. On a different page, display those values.

And ultimately, a graph. But that is a bridge to cross at a later time.

So you've got a vTime[40] array that you're trying to populate and print with:

This is bad because there are two vt variables with different scopes: the global one and the local one that persists for just one line. in the for loop, vt will iterate from 0 to 39, and then get discarded, as if it was just:

void getVTime() {
  if(isrunning==true){
  getCalculations();
  intervalTime = millis() - previntervalTime;
  if (intervalTime >= 15000) {
    previntervalTime = millis();
    vTime[vt] = voltageFull;
    Serial.println(vTime[vt]);
  }
  }
}

Then every 15000ms, it copies voltageFull over vTime[40], which is dangerously past the end of the vTime[0...39] array. It won't fill the array.

If I understand your goal, it is to update and display the full vTime[] array of historical 15sec values of voltageFull. For that, you may want to use vTime[] as a ring buffer, place values in it every 15 sec, and then print the full buffer as needed.

@gcjr posted the following.

const int N = 100;
int   adcVal [N];
int   idx;

const unsigned long FifteenSec = 15 * 1000;
      unsigned long msec0;

// -----------------------------------------------------------------------------
void
loop (void)
{
    unsigned long msec = millis ();

    if (msec < msec0 || N <= idx)
        return;

    msec0 += FifteenSec;

    adcVal [idx++] = analogRead (A0);

    // performCalcultions();
    // displayUpdate();
}

void
setup (void)
{
    Serial.begin (9600);
}

This look in theory to do what I want, right? Looks like it updates the interval period and adds 15 seconds to it to check again. It would increase the array and record a new value. I would use voltageFull instead of the analogRead. But I would need to print all the values, which is what you are suggesting to use a ring buffer for?

Although I think

if (msec < msec0 || N <= idx)

Needs to change to

if (msec < msec0 && N <= idx)

if the array size is 1, N == 1, is an idx value of 1 valid?

I think I read it wrong. I was reading it as if the interval wasn't at least x time or if idx is less than the array size do stuff. I don't understand the "return;", but I think that does something there.

sorry, misread
these are conditions to NOT process by just returning, exiting loop()

this could have been written

    if (msec >= msec0 && N > idx)  {
        msec0 += FifteenSec;

        adcVal [idx++] = analogRead (A0);
     // performCalcultions();
     // displayUpdate();
    }

not a ring (i.e. circular) buffer. an array to capture your voltage profile.

or do you have a requirement to capture the last N values? if sp, then

    if (N <= ++idx)
        idx = 0;

You'd use a ring buffer if you want to be able to handle more observations than fit in your buffer. @gcjr's code uses a plain buffer, with the observations in adcVal[0] through adcVal[idx-1], so if you wanted to print them in reverse chronological order you'd do something like:

void printBuffer(void){
  for (int ii = idx-1; ii >=0; --ii){
  Serial.print(adcVal[ii]);
  Serial.print(" ");
  }
}

With the ring buffer it would be a bit more complicated, since your indexing would have to take into account rolling around the corner between vTime[39] and vTime[0];

If N=100 is sufficient for your purposes, it is simpler system to understand/maintain/debug. If you want to run the process for longer than fits in memory, you might want to learn about a circular buffer.

I am back to working on the code this evening. Can't remember where I left off, or if I made any progress, lol.

I had to revert back to v1.8 of my code which has the struct for the one variable. I'm going to read back through a few posts and see if I can use anything.

A little update.
I tried using what @gcjr posted, but I did not have any luck with it. I had to modify it a bit since the code he suggested wasn't updating at the correct interval. Also I had to do the manual repetitive code for printing to the tft. But I did get it to work, not the pretty way.

Unfortunately though, my code being ungainly, I am running out of space... When I compile my code above 92% it freezes the tft display. Right now I am at 89%. I'm sure the tft library can be downsized, but I don't know where to begin with that... I only added the code for about half of my vTime array, so I still have some to add. I don't think graphing will happen without significant restructuring or a different mcu. I thought about using a 2560, but I don't want to solder them on my pcbs!

A couple of things I still need to work on. I need to average all the values of the vTime[] array that are non zero values. As it stands all the values are zero and update as time progresses. At time = 0, when the function starts, vTime[0] updates, and then vTime[1] updates at 15 seconds, vTime[2] at 30 seconds and so on. But the function may only run for 8 minutes and there will be enough variables for 10 minutes and I want an average of the voltage over the run.

Last thing, and I may need to open a new thread on this. I went back and was looking at my averaging of my sensors. It makes sense that my sensors are going to fluctuate a little because the pi controller will continually make adjustments. So I average that out. But it seemed that a sample size of 1000 is a bit extreme. So I dropped that down to 50 and did some experimentation. I am using code to measure the 328pb own vcc.

// calibrates the VCC using the bandgap ref.  This works and doesn't work.  Probably be better to add an external vref to the design
void getAccurateVoltage() {
  int vv;
  float rawgetVoltage = 0;
  for (vv = 0; vv < 1; vv++) {
    getVoltage();
    rawgetVoltage += getVoltage();
  }
  VCCC = rawgetVoltage / 1;
}
// Read the voltage of the battery the Arduino is currently running on (in millivolts)
int getVoltage() {
  const long InternalReferenceVoltage = 1095L;  // Adust this value to your boards specific internal BG voltage x1000
                                                // REFS1 REFS0          --> 0 1, AVcc internal ref.
                                                // MUX3 MUX2 MUX1 MUX0  --> 1110 1.1V (VBG)
  ADMUX = (0 << REFS1) | (1 << REFS0) | (0 << ADLAR) | (1 << MUX3) | (1 << MUX2) | (1 << MUX1) | (0 << MUX0);
  ;
  // Start a conversion
  ADCSRA |= _BV(ADSC);
  // Wait for it to complete
  while (((ADCSRA & (1 << ADSC)) != 0))
    ;
  // Scale the value                                                             // Wait for it to complete
  int results = (((InternalReferenceVoltage * 1024L) / ADC) + 5L);  // Scale the value; calculates for straight line value
  return results;
}  // end VCC calibration

I found this online. When there is no battery being measured, the VCC returned is stable. As soon as I connect a battery to measure the VCC starts fluctuating. Measuring the VCC with my 5.5 digit dmm there is no fluctuation. I did put a 100nF 0603 cap between the aref and ground pins as suggested in another thread. The batteries are ran through a voltage divider, 2 5k1 resistors with a 1uF filter cap. If I measure the aref pin with my dmm without a battery attached it is stable. Once I attach the battery the aref pin fluctuates. So is this a bad chip?

Your getVoltage method changes the reference voltage and the mux. So you should probably throw away the first reading and take a second reading after those changes.

Gee, was someone trying to help you fix that earlier? What did you call it? Oh yeah, you called it a waste of time.

Well I won't waste your time anymore by telling how to shrink this code to make it fit.

[quote="Delta_G"]
Your getVoltage method changes the reference voltage and the mux. So you should probably throw away the first reading and take a second reading after those changes. [/quote]

Doesn't

void getAccurateVoltage() {
  int vv;
  float rawgetVoltage = 0;
  for (vv = 0; vv < 1; vv++) {
    getVoltage();
    rawgetVoltage += getVoltage();

The first "getVoltage();" call get thrown away? I thought that was what I was doing with that. Like I said though, the aref pin actually fluctuates when measured with my dmm. VCC does not fluctuate measuring at the 100nF cap attached to VCC pins.

Yes, I know. But why would the tft freeze at only 92%? I would expect issues at a higher percentage.