I apologize for the probably (as usual) stupid question.
My understanding is that variables declared outside of functions are global and are stored in the program storage space. Does that include member variables of classes?
I have two classes. For testing the use of memory, I am including them in an empty .ino file that declares instances and then does nothing. I am not deliberately dynamically allocating/deallocating memory anywhere (malloc).
The whole thing compiles, but the dynamic memory use is unexpectedly large. I have added up the size of all the member variables in the classes (even though they are declared outside of functions and should be global?), and it's nowhere near the amount the compiler reports, even though there are quite a few unsigned long variables.
Sketch uses 1356 bytes (0%) of program storage space. Maximum is 253952 bytes.
Global variables use 674 bytes (8%) of dynamic memory, leaving 7518 bytes for local variables. Maximum is 8192 bytes.
And if I assume that all my member variables --assigned outside of functions and thus presumably in program memory -- are somehow being placed in dynamic memory, I get a much higher value: 11,000 bytes, more than the dynamic memory space!
One hypothesis: are the return value from functions counted as dynamic memory, since memory has to be allocated when they return a value?
The code is long, but I'll post it here anyway, in case anyone has the time to look through this.
//PollingTimer.h
#ifndef PollingTimer_h
#define PollingTimer_h
#include <Arduino.h>
class PollingTimer{
public:
enum TimeUnits {_micros, _millis, _seconds, _minutes, _hours};
PollingTimer();
void reset();
void startTimer();
void stopTimer();
void restartTimer();
unsigned long readMicros(); //limited by rollover of micros() every ~71.6 minutes
unsigned long readMillis(); //limited by rollover of millis() every ~49.7 days
unsigned long readSeconds(); //limited by rollover of millis() every ~49.7 days
unsigned long readMinutes(); //limited by rollover of millis() every ~49.7 days
unsigned long readHours(); //limited by rollover of millis() every ~49.7 days
unsigned long read(int timeUnit);
private:
static const int numTimeUnits = 5;
unsigned long startTime[numTimeUnits];
unsigned long prevTime[numTimeUnits];
unsigned long currentTime[numTimeUnits];
const unsigned long microsPerMilli = 1000;
const unsigned long microsPerSec = 1000000;
const unsigned long microsPerMin = 60000000;
const unsigned long microsPerHour = 3600000000;
const unsigned long millisPerSec = 1000;
const unsigned long millisPerMin = 60000;
const unsigned long millisPerHour = 3600000;
const int secsPerMinute = 60;
const int minsPerHour = 60;
bool running = false;
void incrementSecMinHours();
};
#endif
//PollingTimer.cpp
#include "PollingTimer.h"
PollingTimer::PollingTimer(){
reset();
}
void PollingTimer::reset(){
for(int tUnit = _millis; tUnit <= _hours; tUnit++){
startTime[tUnit] = prevTime[tUnit] = currentTime[tUnit] = 0;
}
running = false;
}
void PollingTimer::startTimer(){ //starts timer from 0
startTime[_micros] = prevTime[_micros] = micros();
startTime[_millis] = prevTime[_millis] = millis();
running = true;
}
void PollingTimer::stopTimer(){
currentTime[_micros]=micros();
currentTime[_millis]=millis();
running = false;
}
void PollingTimer::restartTimer(){ //restarts timer from previous time
running = true;
}
unsigned long PollingTimer::readMicros(){
if(running){currentTime[_micros] = micros();}
return (currentTime[_micros] - startTime[_micros]);
}
unsigned long PollingTimer::readMillis(){ //rounded down
if(running){currentTime[_millis] = millis();}
return (currentTime[_millis] - startTime[_millis]);
}
unsigned long PollingTimer::readSeconds(){ //rounded down
if(running){incrementSecMinHours();}
return currentTime[_seconds];
}
unsigned long PollingTimer::readMinutes(){ //rounded down
if(running){incrementSecMinHours();}
return currentTime[_minutes];
}
unsigned long PollingTimer::readHours(){ //rounded down
if(running){incrementSecMinHours();}
return currentTime[_hours];
}
unsigned long PollingTimer::read(int timeUnit){
unsigned long timeResult;
if(running){
currentTime[_micros] = micros();
incrementSecMinHours();
}
if (timeUnit == _millis){timeResult = (currentTime[_millis] - startTime[_millis]);}
else if (timeUnit == _micros){timeResult = (currentTime[_micros] - startTime[_micros]);}
else{timeResult = currentTime[timeUnit];}
return timeResult;
}
void PollingTimer::incrementSecMinHours(){
currentTime[_millis]=millis();
if((currentTime[_millis] - prevTime[_millis]) >= millisPerSec) {
currentTime[_seconds] = currentTime[_seconds] + (int) ((currentTime[_millis] - prevTime[_millis]) / millisPerSec);
prevTime[_millis] = currentTime[_millis];
if((currentTime[_seconds] - prevTime[_seconds]) >= 60){
currentTime[_minutes] = currentTime[_minutes] + (int) ((currentTime[_seconds] - prevTime[_seconds]) / secsPerMinute);
prevTime[_seconds] = currentTime[_seconds];
}
if((currentTime[_minutes] - prevTime[_minutes]) >= 60){
currentTime[_hours] = currentTime[_hours] + (int)((currentTime[_minutes] - prevTime[_minutes]) / minsPerHour);
prevTime[_minutes] = currentTime[_minutes];
}
}
}
//PollingDelay.h
#ifndef PollingDelay_h
#define PollingDelay_h
#include <Arduino.h>
#include <PollingTimer.h>
class PollingDelay{
private:
//enum DelayMode {_micros, _millis, _seconds, _minutes, _hours};
PollingTimer pollingTimer; //DUPLICATE
enum TimeUnits {_micros, _millis, _seconds, _minutes, _hours};
int delayMode; //DUPLICATE
unsigned long delayTime; //in μs //DUPLICATE
bool running = false;
bool justFinishedFlag = false; //DUPLICATE
const unsigned long microsPerMilli = 1000;
const unsigned long microsPerSec = 1000000;
const unsigned long microsPerMin = 60000000;
const unsigned long microsPerHour = 3600000000;
const unsigned long millisPerSec = 1000;
const unsigned long millisPerMin = 60000;
const unsigned long millisPerHour = 3600000;
const int secsPerMinute = 60;
const int minsPerHour = 60;
public:
PollingDelay();
void startDelayMicros(unsigned long delayTimeMicros); //limited by rollover of micros() every ~71.6 minutes
void startDelayMillis(unsigned long delayTimeMillis); //limited by rollover of millis() every ~49.7 days
void startDelaySeconds(unsigned long delayTimeSeconds); //limited by rollover of millis() every ~49.7 days
void startDelayMinutes(unsigned long delayTimeMinutes); //limited by rollover of millis() every ~49.7 days
void startDelayHours(unsigned long delayTimeHours); //limited by rollover of millis() every ~49.7 days
bool isRunning();
bool justFinished();
void reset();
unsigned long PollingDelay::read(int tUnit);
};
#endif
//PollingDelay.cpp
#include "PollingDelay.h"
PollingDelay::PollingDelay(){
reset();
}
void PollingDelay::startDelayMicros(unsigned long delayTimeMicros){
this->delayTime = delayTimeMicros;
delayMode = PollingTimer::_micros;
pollingTimer.reset();
pollingTimer.startTimer();
running = true;
}
void PollingDelay::startDelayMillis(unsigned long delayTimeMillis){
this->delayTime = delayTimeMillis;
delayMode = PollingTimer::_millis;
pollingTimer.reset();
pollingTimer.startTimer();
running = true;
}
void PollingDelay::startDelaySeconds(unsigned long delayTimeSeconds){
this->delayTime = delayTimeSeconds;
delayMode = PollingTimer::_seconds;
pollingTimer.reset();
pollingTimer.startTimer();
running = true;
}
void PollingDelay::startDelayMinutes(unsigned long delayTimeMinutes){
this->delayTime = delayTimeMinutes;
delayMode = PollingTimer::_minutes;
pollingTimer.reset();
pollingTimer.startTimer();
running = true;
}
void PollingDelay::startDelayHours(unsigned long delayTimeHours){
this->delayTime = delayTimeHours;
delayMode = PollingTimer::_hours;
pollingTimer.reset();
pollingTimer.startTimer();
running = true;
}
bool PollingDelay::isRunning(){
if(running){
if(pollingTimer.read(delayMode) >= delayTime){
pollingTimer.reset();
pollingTimer.stopTimer();
running = false;
justFinishedFlag = true;
}
}
return running;
}
bool PollingDelay::justFinished(){
if(!isRunning() && justFinishedFlag){
justFinishedFlag = false;
return true;
}
else {return false;}
}
void PollingDelay::reset(){
delayTime = 0;
running = justFinishedFlag = false;
pollingTimer.stopTimer();
pollingTimer.reset();
}
unsigned long PollingDelay::read(int tUnit){
return pollingTimer.read(tUnit);
}
//PollingDelay.ino
#include <string.h>
#include "PollingDelay.h"
PollingDelay microDelay;
PollingDelay milliDelay;
PollingDelay secDelay;
PollingDelay minDelay;
PollingDelay hourDelay;
void setup() {
}
void loop() {
}
PollingDelay/.ino isn't doing anything except declaring several instances of PollingDelay, each of which contains a member of type PollingTime.
After scouring the code and doing the math according to my (clearly incorrect) understanding of program memory vs. dynamic memory, I can't figure out where the compiler is getting it's values.
Somehow I am looking at this wrong. Can anyone help me with my understanding of what is being placed in program vs. dynamic memory?