ATMega4808 logger high power consumption

Hi!
I am a beginner, working on my first Arduino project! I want to measure the surface temperature of an alpine plant over the summer! I want it to log 3 times rapidly and then wait 15 minutes and log again.

I am using the Rocketscream Mini Ultra board (https://www.rocketscream.com/blog/product/mini-ultra/), the I2C sensor Melexis Contact-less Infrared Sensor - MLX90614 3V (Melexis Contact-less Infrared Sensor - MLX90614 3V [MLX90614ESF-BAA] : ID 1747 : $15.95 : Adafruit Industries, Unique & fun DIY electronics and kits), and the Adafruit Micro SD SPI or SDIO Card Breakout Board (Adafruit Micro SD SPI or SDIO Card Breakout Board - 3V ONLY! : ID 4682 : $3.50 : Adafruit Industries, Unique & fun DIY electronics and kits).
I am having some issues with power consumption, as it is using a lot of battery power in less than 3 days and stops logging. I have been working on trying to put it in sleep or standby mode to save power.

I am assuming I should connect the batteries to the BAT pin on the board, but I am seeing higher power consumption on this pin compared to VCC. I have added a paint drawing of how I have connected everything below.

Realistically, how low power can I get on "standby" with 2 x AA batteries? I am getting as low as 6 mA, but sometimes a lot higher power consumption. I was hoping to get as low as 1.2 mA, or under, so my batteries can last long enough. Is this possible?

As of now I have tried using the example from the LowPowerAVRZero library, found here:
RocketScream_LowPowerAVRZero/StandbyRTC.ino at master · rocketscream/RocketScream_LowPowerAVRZero · GitHub).
But when I put the code in the void toggle it would not read the temperature. It worked in void loop, but with high power consumption.

Here is the code that I could get to work, but this is without attachInterupt. Is this needed, and are there any other obvious issues in this code?

#include <RocketScream_LowPowerAVRZero.h>
#include <RocketScream_RTCAVRZero.h>
#include <SPI.h>
#include <SD.h>
#include <Adafruit_MLX90614.h>

Adafruit_MLX90614 mlx = Adafruit_MLX90614();
const int chipSelect = 8;
const uint8_t unusedPins[] = {0, 1, 7, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25};

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);

  uint8_t index;

  for (index = 0; index < sizeof(unusedPins); index++) {
    pinMode(unusedPins[index], INPUT_PULLUP);
    LowPower.disablePinISC(unusedPins[index]);
  }

  RTCAVRZero.begin(false);
  RTCAVRZero.enableAlarm(30, true);

  if (!SD.begin(chipSelect)) {
        while (1);
  }

  if (!mlx.begin()) {
        while (1);
  }

  File dataFile = SD.open("datalog.csv", FILE_WRITE);
  String header = "";
  if (dataFile) {
    header += String("Time");
    header += ",";
    header += String("Ambient 1");
    header += ",";
    header += String("Object 1");
    header += ",";
    header += String("Ambient 2");
    header += ",";
    header += String("Object 2");
    header += ",";
    header += String("Ambient 3");
    header += ",";
    header += String("Object 3");
    header += ",";
    dataFile.println(header);
    dataFile.close();
  }
}

void loop() {
  String dataString = "";

  dataString += String(millis());
  dataString += ",";
  dataString += String(mlx.readAmbientTempC());
  dataString += ",";
  dataString += String(mlx.readObjectTempC());
  dataString += ",";

  delay(1000);
  dataString += String(mlx.readAmbientTempC());
  dataString += ",";
  dataString += String(mlx.readObjectTempC());
  dataString += ",";

  delay(1000);
  dataString += String(mlx.readAmbientTempC());
  dataString += ",";
  dataString += String(mlx.readObjectTempC());

  File dataFile = SD.open("datalog.csv", FILE_WRITE);
  if (dataFile) {
    dataFile.println(dataString);
    dataFile.close();
      } else {
      }

  LowPower.standby();
}

Any tips or feedback would be highly appreciated! :smile:

Kind regards,
Sara

The processor board can do waaaay better than that, it seems, out of the box.

But you've got the SD always powered, that will kill you.

And don't worry about it yet, but you might be able to sleep through those 1000 millisecond delays by programming the loop a bit differently.

I'm not sure to what you refer when you say you haven't used attachInterrupt. What code example are you working from where it was used?

Can you run the sketch without actually doing the logging as an experiment? Leave off the SD module and program around the fact that it isn't there, that is to say just comment away temporarly any references to it.

This would let you see the processor board achieve truly deep sleep or standby or whatever.

added: OIC you have another power hungry (it's all relative) component. I think you'll need to switch those both on when you need them, and off for the resting period. Either may require some time to start up and become stable; thjs will be a hard limit in just how long your batteries can last.

They do make bigger batteries...

The current may be too low for the meter you have!

I'll leave it there and to others for the moment. I can say chasing low power is addictive…

a7

1 Like

Thank you for the feedback! I will test out without the SD module tomorrow. :slight_smile:

When I mention attachInterrupt, I meant that it was part of the example code I tried to follow, but could not get it to work. This is the code I meant, and have used as a base for standby:

#include <RocketScream_LowPowerAVRZero.h>
#include <RocketScream_RTCAVRZero.h>

/* Example on a 32-pin ATMega4808, LED on pin D7, using internal ULP OSC32K */
const uint8_t unusedPins[] = {0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13,
                              14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25};
                              
void setup()
{
  uint8_t index;

  for (index = 0; index < sizeof(unusedPins); index++)
  {
    pinMode(unusedPins[index], INPUT_PULLUP);
    LowPower.disablePinISC(unusedPins[index]);
  }

  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);

  /* true: external 32.768 kHz crystal */
  /* false: internal 32.768 kHz ULP oscillator */
  RTCAVRZero.begin(false);
  /* Time in seconds, true: repeat, false: once */
  RTCAVRZero.enableAlarm(5, true);
  RTCAVRZero.attachInterrupt(toggle);  
}

void loop()
{
  /* RTC works down to standby mode only. In power down, PIT is required */
  LowPower.standby();
}

void toggle(void)
{
  digitalWrite(LED_BUILTIN, CHANGE);
}

I will update tomorrow when I have tried my code without the SD part! :+1:

Sara

Ps: Just a thought I had! Not sure if this is possible, but because I have SD and sensor on VCC pin, and batteries on BAT pin.. maybe there is a way to tell it turn on and off VCC when I want it to scan??

THX.

I make no sense of CHANGE in this context

void toggle(void)
{
  digitalWrite(LED_BUILTIN, CHANGE);
}

so I ask if this code works for you and what does it do?

This would make more sense

void toggle(void)
{
  digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
}

so if the code did not work, try substituting the above.

I do not think Vcc can be switched on and off, but good idea. Doing the equivalent is fairly easy.

The use of Capital S Strings may compromise the long time running of your program. You may also want to consider not stashing nice text on your SD card. Just store the numbers, which you can write without the use of Strings, and make it pretty later when you offload the data.

Ppl sometime write a file like the one you seek to end up with using CSV format, then into a spreadsheet on a real computer for analysis or whatever.

a7

This syntax to toggle a pin is part of the extra functionality of the megaavr processor 4808 and is supported by MegaCoreX which is the core @saralhp is using.

In https://github.com/MCUdude/MegaCoreX/blob/master/megaavr/cores/coreX-corefiles/api/Common.h

you find

#define FALLING        2
#define RISING         3
#define CHANGE         4

And in [MegaCoreX/megaavr/cores/coreX-corefiles /wiring_digital.c](https://MegaCoreX/megaavr/cores/coreX-corefiles /wiring_digital.c)

You find this for digitalWrite( )

void digitalWrite(uint8_t pin, uint8_t val)

 /* Set output to value */
    if (val == LOW)
    { /* If LOW */
      port->OUTCLR = bit_mask;
    }
    else if (val == CHANGE)
    { /* If TOGGLE */
      port->OUTTGL = bit_mask;
      /* If HIGH OR  > TOGGLE  */
    }
    else
    {
      port->OUTSET = bit_mask;
    }

I also find some issue with the interrupt use with the timer in RTCAVRZero for wake up. I find that the ISR is better set as a simple flag, the let loop do its thing and then go back to sleep.

This documentation would indicate the possibility of using
LowPower.powerDown() instead LowPower.standby() and using the PIT Timer interrupt for wakeup.
https://ww1.microchip.com/downloads/en/Appnotes/TB3213-Getting-Started-with-RTC-DS90003213.pdf

It's worth a close look at the source in RocketScream_RTCAVRZero.h to see what the library is actually doing.

Thanks for all the input! I tried removing all logging elements @alto777 and now it is steadily measuring 1.8 mA, but I am pretty sure I also removed the temperature part as it is entangled in the logging (datastring etc.).

When I run the example code I have been going off, without doing any changes to it it results in a blinking LED light, measuring 1.8 mA when off, and 2.66 mA when on.

The code I have been using (first post - the one I wrote worked) is not cooperating with me today, which leads me to believe I am making some obvious stupid mistake, like maybe connecting on the wrong pins (see paint drawing) or using the multimeter wrong (I am measuring in m A DC), or just mistakes in the code. I am now measuring a power consumption between 40 and 50 mA, which is stupidly high :sweat_smile: I still log the temperature, but why is it so high?? I tried multiple times and ended up trying to connect the batteries to VCC with the others instead of BAT (which is what I must have accidentally done yesterday), which gave the results between 5.5 and 6 mA.. I have no idea what is causing this, especially as the example codes seem to give "normal results" even when the batteries are connected to BAT and not VCC??

As of now, I can only think of trying from scratch again, but should I keep trying to have my batteries on BAT or change to VCC?

This seems like a good idea @cattledog ! I will try making a new code using powerDown, and use the PIT timer interrupt.

PS: Sorry for the messy answer, I just got very confused :sweat_smile:

Sara

EDIT: I tried the example code (StandyRTC) again but connected to VCC and not BAT, and it does measure lower mA when connected to VCC 1.96 mA LED on, 1.38 mA LED off (vs. 2.6 and 1.8 on BAT)

Thanks, and for the reminder to look a little further than the end of my nose. I can take the rest of the day off, having learned something. Good thing if you could see the weather here…

But now I recall a bizarre odd feature of even an UNO - setting a bit in, say, PIND will toggle the output bit, and the hardware resets that bit so you are good to go again. So I wonder if CHANGE couldn't be implemented to be more universally available.

Those currents are orders of magnitude higher than you should be able to achieve with relative ease.

If you've just got the bare board and are not powering anything but the LED, it should switch between some few mA, LED on, and nearly immeasurably small when the LED is off.

What kind of meter do you have and describe how you are doing the measurements. There are a few problems and tricks to measuring low current. When I can I'll post a diagram of a little device I made that can help. In the meantime, say and show more and share any new results.

I have also been thinking about the SD card. TBH I've had rotten luck getting them to work in low power designs. I say luck because it is a personal failing, I know it can be done…

There's a memory type called FRAM which is basically a giant EEPROM you can attach to. I have marked that as something to experiment with if I ever try to tackle my issues with SD cards. at a glance, it looks like it would use very low power even when on, and might be something even I could manage to turn on and off at the will of my code. It uses so little power I think it could be turned on and off simply by powering it through an output pin.

HTH

a7

Oh, my bad! I did not have a bare board when measuring this, but everything connected - just no changes to the example code. With a bare board, it measures 0.00/01 (flickers a little back and forth) mA when LED off, and 0.56 mA when LED on while connected to VCC, and on BAT 0.01 mA when LED low and 0.88 mA when LED high.

I am using a "Fluke 175 True RMS Multimeter", putting black kable in COM and red cable in 400 mA, Then I connect the red cable to the red wire of the battery, and the black cable to either VCC or BAT on the board (depending on what I want to check). I also have the black battery wire in GND. I turn the knob to the one that sais mAHz, and hit the orange button until I'm on the one that measures mA DC. There I keep it in Auto Range and do not hit any more buttons.
I do find it a little difficult to maintain a good connection, so I tried fastening the measure pins with some wire like this:

This is how the multimeter looks:

Sara

That's more like it!

I've never learned to trust or like autoranging, that's just me, so I use my meter on the lowest scale, and only measure when I know the current is at the low point. I also have "real" meters that can be delicate.

So in your case, I would increase the period from 5 seconds to something my reflexes would be less taxed by (!), and have a wire shunt across the meter until I was trying to measure.

When I was deep into it, I made a little rig with a few switches to make these measurements easier.

If it looks like I drew this with my finger it is because:


So you see keep the meter switch closed, close the power switch, wait for the LED to go off then open the meter switch and get the reading.

It looks like you don't need to do that, but it comes in handy if you are using a real microammeter like from before you were born. :expressionless:

a7

1 Like

I am still stuck on this :sweat_smile:
I decided to order some MOSFET to control the flow of electricity that way. I have not received them yet but will update when I have them connected and can measure the power consumption.

I have other questions though; I have this code that I have been using:

#include <RocketScream_LowPowerAVRZero.h>
#include <RocketScream_RTCAVRZero.h>
#include <SPI.h>
#include <SD.h>
#include <Adafruit_MLX90614.h>

Adafruit_MLX90614 mlx = Adafruit_MLX90614();
const int chipSelect = 8;
const uint8_t unusedPins[] = {0, 1, 7, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25};

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);

  uint8_t index;

  for (index = 0; index < sizeof(unusedPins); index++) {
    pinMode(unusedPins[index], INPUT_PULLUP);
    LowPower.disablePinISC(unusedPins[index]);
  }

  RTCAVRZero.begin(false);
  RTCAVRZero.enableAlarm(30, true);

  if (!SD.begin(chipSelect)) {
    while (1);
  }

  if (!mlx.begin()) {
    while (1);
  }

  File dataFile = SD.open("datalog.csv", FILE_WRITE);
  if (dataFile) {
    String header = "Time,Ambient1,Object1,Ambient2,Object2,Ambien3,Object3";
    dataFile.println(header);
    dataFile.close();
  }
}

void loop() {
  String dataString = "";

  dataString += String(millis()); //Time
  dataString += ",";
  dataString += String(mlx.readAmbientTempC()); //Ambient1
  dataString += ",";
  dataString += String(mlx.readObjectTempC()); //Object1
  dataString += ",";

  delay(1000);

  dataString += String(mlx.readAmbientTempC()); //Ambient2
  dataString += ",";
  dataString += String(mlx.readObjectTempC()); //Object2
  dataString += ",";

  delay(1000);

  dataString += String(mlx.readAmbientTempC()); //Ambient3
  dataString += ",";
  dataString += String(mlx.readObjectTempC()); //Object3

  File dataFile = SD.open("datalog.csv", FILE_WRITE);
  if (dataFile) {
    dataFile.println(dataString);
    dataFile.close();
  }

  delay(1000); // Delay to allow time for SD card write

  LowPower.standby();
}

And as well as high power consumption, I also have an issue with the time. I let it stay on for a little over 5 minutes, and as expected it logged 11 times (this part is correct), but the time it logged was wrong (ish).
It logged:
|Time|Ambient1|Object1|Ambient2|Object2|Ambien3|Object3|
|27|28.25|28.63|28.29|28.89|28.31|29.03|
|3048|28.47|28.89|28.49|28.97|28.49|28.85|
|6070|28.71|28.99|28.75|29.09|28.75|28.95|
|9092|28.93|28.91|28.95|28.97|28.95|29.03|
|12117|29.01|29.03|29.03|29.09|29.07|28.91|
|15139|29.21|28.79|29.19|29.09|29.23|29.57|
|18161|29.33|28.75|29.33|28.91|29.37|28.79|
|21182|29.23|28.63|29.21|28.57|29.19|28.63|
|24204|29.23|28.51|29.23|28.71|29.27|28.85|
|27233|29.27|29.25|29.29|29.31|29.31|29.31|
|30255|29.53|29.35|29.53|29.17|29.53|29.05|

5 minutes should be 300 000 milliseconds, not 30 000. It is probably due to my use of "standby", although I do not understand how or why..
Also, any tips on how to improve the code to save power are also welcome, and tips on how to implement the MOSFET. I did try to look into PIT Timer, but I did not understand that much. I am noticing that I am a little bit over my head as a beginner here, but I am still trying to have fun with it :smile:

Kind regards,
Sara

The millis() value does not increase while in standby. What you are seeing is the three 1000 ms delays when the processor is awake.

It's not clear to me that power down will give lower usage than standby but here's some examples using the PIT timer for you to look at.
The longest PIT interrupt interval can be set for either 1 second or 30 seconds depending on the clock setting. Longer sleeps can be implemented by incrementing a counter.

#include <avr/sleep.h>

void RTC_init(void)
{
  /* Initialize RTC: */
  while (RTC.STATUS > 0)
  {
    ;                                   /* Wait for all register to be synchronized */
  }
  
   //Select one of two clock speeds, RTC presecaler does not apply to PIT
  
  //RTC.CLKSEL = RTC_CLKSEL_INT32K_gc;    /* 32.768kHz Internal Ultra-Low-Power Oscillator (OSCULP32K) */
  RTC.CLKSEL = RTC_CLKSEL_INT1K_gc;      /* 1kHz Internal Ultra-Low-Power Oscillator (OSCULP32K) */

  RTC.PITINTCTRL = RTC_PI_bm;           /* PIT Interrupt: enabled */

  RTC.PITCTRLA = RTC_PERIOD_CYC32768_gc /* RTC Clock Cycles 32768, resulting in 1Hz or 1/32 Hz */
                 | RTC_PITEN_bm;           /* Enable PIT counter: enabled */
}

ISR(RTC_PIT_vect)
{
  RTC.PITINTFLAGS = RTC_PI_bm;          /* Clear interrupt flag by writing '1' (required) */
}

void setup() {
  RTC_init();                           /* Initialize the RTC timer */
  pinMode(LED_BUILTIN, OUTPUT);                   /* Configure pin#7 as an output */
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);  /* Set sleep mode to POWER DOWN mode */
  sleep_enable();                       /* Enable sleep mode, but not going to sleep yet */
}

void loop() {
  sleep_cpu(); /* Sleep the device and wait for an interrupt to continue */
  //do things after wake
  digitalWrite(LED_BUILTIN, HIGH);              /* Device woke up and toggle LED on pin#7 */
  delay(500);
  digitalWrite(LED_BUILTIN, LOW);
  delay(500);
  digitalWrite(LED_BUILTIN, HIGH);              /* Device woke up and toggle LED on pin#7 */
  delay(500);
  digitalWrite(LED_BUILTIN, LOW);
}

This next example is a slight modifcation of code here
https://github.com/amadeuspzs/attiny1614-rtc/blob/main/attiny1614-rtc-blink-long-sleep/attiny1614-rtc-blink-long-sleep.ino

/*

  Use PIT with counter for long sleep

  LED blinks every time it wakes up

*/

#include <avr/sleep.h>
#define led LED_BUILTIN                           // positive lead of LED, PB0

volatile int current_sleeps = 0;        // counter for how many times PIT has woken up
int target_sleeps = 2;                  // target for total sleep time. Increment of the RTC_PERIOD setting below
                                        // e.g. RTC_PERIOD_CYC32768_gc = 32s, target_sleeps = 2 -> 64s sleep
// setup for the RTC
void RTC_init(void) {
  // initialise RTC:
  while (RTC.STATUS > 0)
  {
    ;                                   // wait for all registers to be synchronised
  }
  RTC.CLKSEL = RTC_CLKSEL_INT1K_gc;     // 1.024kHz Internal Ultra-Low-Power Oscillator (from OSCULP32K)

  RTC.PITINTCTRL = RTC_PI_bm;           // PIT Interrupt: enabled

  RTC.PITCTRLA = RTC_PERIOD_CYC32768_gc // RTC Clock Cycles 32768, resulting in 32768/1024Hz = every 32 seconds
  | RTC_PITEN_bm;                       // enable PIT counter
}

// interrupt subroutine, runs when PIT wakes up
ISR(RTC_PIT_vect) {
  current_sleeps += 1;                  // increment sleep counter
  RTC.PITINTFLAGS = RTC_PI_bm;          // clear interrupt flag by writing '1' (required)
}

// function to blink led
void blink(int times = 1, int interval = 100) {
  for (int n=0; n < times; n++) {
    digitalWrite(led, HIGH);
    delay(interval);
    digitalWrite(led, LOW);
    delay(interval);
  }
}

void setup() {
  // switch off unneeded pins for power saving
  pinMode(PIN_PA1, INPUT_PULLUP);
  pinMode(PIN_PA2, INPUT_PULLUP);
  pinMode(PIN_PA3, INPUT_PULLUP);
  pinMode(PIN_PA4, INPUT_PULLUP);
  pinMode(PIN_PA5, INPUT_PULLUP);
  pinMode(PIN_PA6, INPUT_PULLUP);
  pinMode(PIN_PA7, INPUT_PULLUP);
  pinMode(PIN_PB1, INPUT_PULLUP);
  
  pinMode(led, OUTPUT);                 // blinker
  digitalWrite(led, LOW);               // turn off
  
  RTC_init();                           // initialise the RTC timer
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);  // set sleep mode to POWER DOWN mode
  sleep_enable();                       // enable sleep mode, but not going to sleep yet
  sei();                                // enable interrupts
}

void loop() {
  if (current_sleeps == 0 || current_sleeps == target_sleeps ) { // just switched on, or we've hit our target
    // main code to run here
    blink(5);
    // end main code
    current_sleeps = 0;                           // reset sleep counter to 0
  }
  sleep_cpu();                                    // sleep the device and wait for an interrupt to continue
}
1 Like

Thank you for providing examples! Here comes a little update from me.

I have now tested both the codes with the PIT, and they both work fine. I still have the same issue with the timer (millis) falling asleep and thereby counting wrong, so I am exploring if there is some sort of "elapsed time" function or something else I can use instead of "millis". This proves more difficult to find than I thought it would be.

Both running my logger with the first and second example is actually using more power than using standby. BUT I am now down to between 1.7 and 1.8 mA with standby (and 2.1 ish mA with sleep) by changing what SD card I used!! :blush:
When I put in the SD card I have been using before it jumps up to 30+++ mA, but changing puts it right back down again to 1.73 mA (ish).

I was using SanDisk Ultra MicroSDHC 32 GB, and now I am using Verbatim MicroSDHC 16 GB. (I find it really hard to find anything smaller in the stores, but I may want to test an 8 or 2 GB or even less).
I have not connected any MOSFET or resistors or anything, but with it now being under 2 mA, I think I will not use time on that, as I really should have them ready by the end of this week!

Tips on how to get the time logged would be helpful! As of now, I have switched it out with the log nr. (eg. log 1 right away, log for 100 milliseconds, standby 15 min, log 2, etc), and then I might do the math afterward, but I would prefer to have the time in milliseconds (or actually seconds might be better?) logged too without the time falling asleep. :smile:

Here is the updated Standby code:

//// **** **** SURFACE AND AMBIENT TEMPERATURE LOGGER **** **** ////

#include <RocketScream_LowPowerAVRZero.h>
#include <RocketScream_RTCAVRZero.h>
#include <SPI.h>
#include <SD.h>
#include <Adafruit_MLX90614.h>

Adafruit_MLX90614 mlx = Adafruit_MLX90614();

const int chipSelect = 8;  // digital pin used on board (for SD card breakout board)

const uint8_t unusedPins[] = { 0, 1, 7, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 };  // I use pins 2-6 and 8, nb 7 is built in LED

int time = 0;

void setup()
{
  time = 1;

  uint8_t index;

  for (index = 0; index < sizeof(unusedPins); index++) {
    pinMode(unusedPins[index], INPUT_PULLUP);
    LowPower.disablePinISC(unusedPins[index]);
  }

  RTCAVRZero.begin(false);
  RTCAVRZero.enableAlarm(900, true);  // 900 sek = 15 minutes, use (30, true) 30 seconds for testing.

  if (!SD.begin(chipSelect)) {
    while (1)
      ;
  }

  if (!mlx.begin()) {
    while (1)
      ;
  }

  File dataFile = SD.open("datalog.csv", FILE_WRITE);
  String header = "";
  if (dataFile) {
    header += String("Log nr.");
    header += ",";
    header += String("Ambient 1");
    header += ",";
    header += String("Object 1");
    header += ",";
    header += String("Ambient 2");
    header += ",";
    header += String("Object 2");
    header += ",";
    header += String("Ambient 3");
    header += ",";
    header += String("Object 3");
    header += ",";
    dataFile.println(header);
    dataFile.close();
  }
}

void loop()
{
  String dataString = "";

  delay(80);
  dataString += String(time);
  dataString += ",";
  dataString += String(mlx.readAmbientTempC());
  dataString += ",";
  dataString += String(mlx.readObjectTempC());
  dataString += ",";

  delay(10);
  dataString += String(mlx.readAmbientTempC());
  dataString += ",";
  dataString += String(mlx.readObjectTempC());
  dataString += ",";

  delay(10);
  dataString += String(mlx.readAmbientTempC());
  dataString += ",";
  dataString += String(mlx.readObjectTempC());

  File dataFile = SD.open("datalog.csv", FILE_WRITE);
  if (dataFile) {
    dataFile.println(dataString);
    dataFile.close();
  }

  SD.end();

  time = time + 1;

  LowPower.standby();
}

Kind regards,
Sara

These two if statements hang when you haven't found the hardware they call begin() for:

  if (!SD.begin(chipSelect)) {
    while (1)
      ;
  }

  if (!mlx.begin()) {
    while (1)
      ;
  }

In an regular sketch, these might also print out an error message. It would be hard to tell if this was what making trouble for you, as there is no other indication that the system is functioning.

I understand you may not have or want to use the serial monitor, but I recommend you find room for one or better two LEDs that would remain off unless you got stuck because of a hardware issue - usually it would be missing, but other things too. And illuminate the appropriate LED so you could see that there is a problem.

A little re-write could test both devices and either succeed, or illuminate one, the other or both LEDs.

I'll look at the rest of the sketch when I am in the lab. I still think the current you are drawing is enormous (!), something like this should run for a long time on a few batteries, perhaps your calculations show you have adequate time between recharging or replacing the power source.

a7

Ok, I tried putting mlx.begin into the loop itself instead of setup, and putting in SD.end after the headers were written, and then starting it and ending it again in the loop. Not quite sure if this is what you meant. It didn't make a noticeable difference in mA, but I might just keep it like that, as it didn't have a negative impact either.

I know 1.7mA is a very high amount of power, but compared to what I had it is a lot less. I would preferably like to be able to leave them for themselves for ca. 80 days but I can (and might have to) switch batteries 1-2 times within the period.

I still wish the power consumption to be way lower, so I am now testing using MOSFET as a switch. I have not used this before, but I thought it was kind of straight forwards. For some reason, the MOSFET is not working as it should.

I have IRF540 N-channel MOSFET (https://www.vishay.com/docs/91021/irf540.pdf) and connected G to pin 10, D to the GND of the mini ultra, and S to the GND of the SD card breakout board.
I wrote in pinMode(10, OUTPUT); as seen in different tutorials, anwhd then digitalWrite(10, HIGH); and digitalWrite(10, LOW); when I want the gate open or glose (so to speak).

Here is the code:

//// **** **** SURFACE AND AMBIENT TEMPERATURE LOGGER **** **** ////

#include <RocketScream_LowPowerAVRZero.h>
#include <RocketScream_RTCAVRZero.h>
#include <SPI.h>
#include <SD.h>
#include <Adafruit_MLX90614.h>

Adafruit_MLX90614 mlx = Adafruit_MLX90614();

const int chipSelect = 8;  // digital pin used on board (for SD card breakout board)

const uint8_t unusedPins[] = { 0, 1, 7, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 };  // I use pins 2-6 and 8, nb 7 is built-in LED

int time = 0;

void setup()
{
  time = 1;

  uint8_t index;

  for (index = 0; index < sizeof(unusedPins); index++) {
    pinMode(unusedPins[index], INPUT_PULLUP);
    LowPower.disablePinISC(unusedPins[index]);
  }

  RTCAVRZero.begin(false);
  RTCAVRZero.enableAlarm(30, true);  // 900 sek = 15 minutes, use (30, true) 30 seconds for testing.

pinMode (10, OUTPUT);
digitalWrite(10, HIGH); //HIGH

  if (!SD.begin(chipSelect)) {
    while (1)
      ;
  }

  File dataFile = SD.open("datalog.csv", FILE_WRITE);
  String header = "";
  if (dataFile) {
    header += String("Log nr.");
    header += ",";
    header += String("Ambient 1");
    header += ",";
    header += String("Object 1");
    header += ",";
    header += String("Ambient 2");
    header += ",";
    header += String("Object 2");
    header += ",";
    header += String("Ambient 3");
    header += ",";
    header += String("Object 3");
    header += ",";
    dataFile.println(header);
    dataFile.close();
  }
  SD.end();

  digitalWrite(10, LOW); //LOW
}

void loop()
{
  pinMode (10, OUTPUT);
  digitalWrite(10, HIGH); //HIGH

  if (!SD.begin(chipSelect)) {
    while (1)
      ;
  }
  if (!mlx.begin()) {
    while (1)
      ;
  }
  String dataString = "";

  delay(80);
  dataString += String(time);
  dataString += ",";
  dataString += String(mlx.readAmbientTempC());
  dataString += ",";
  dataString += String(mlx.readObjectTempC());
  dataString += ",";

  delay(10);
  dataString += String(mlx.readAmbientTempC());
  dataString += ",";
  dataString += String(mlx.readObjectTempC());
  dataString += ",";

  delay(10);
  dataString += String(mlx.readAmbientTempC());
  dataString += ",";
  dataString += String(mlx.readObjectTempC());

  File dataFile = SD.open("datalog.csv", FILE_WRITE);
  if (dataFile) {
    dataFile.println(dataString);
    dataFile.close();
  }

  SD.end();

  time = time + 1;
  digitalWrite(10, LOW); //LOW

  LowPower.standby();
}

I am still using 1.7 mA (ish) on standby, and it didn't seem to make much of a difference. Shouldn't it be 0mA?? 10kohm pull down resistor inline between the #10 and the gate pin.

Any tips are appreciated!! Sorry for being so confused over this!

Kind regards,
Sara

Could you just draw your circuit with a pencil and post a picture of that drawing? I can't be sure you mean what you say.

And I think for switching on and off the SD card, you'll need to use a "high side" MOSFET power switch arrangement. Think of me at the beach while you google that.

Can you link any website you've relied on for the MODFET circuitry? They may have it right but not for a particular deployment scenario.

a7

Maybe? There is a long and somewhat confusing discussion of that issue here
https://forum.arduino.cc/t/using-npn-transistor-to-turn-off-sd-card-reader/666219

Sry, they are fine where they are (or were). I only note that it makes your code die, and doesn't offer a clue as to why, should there be a failure.

if (!SD.begin(chipSelect)) {
    while (1)
      ;
  }

  if (!mlx.begin()) {
    while (1)
      ;
  }

Instead, do something right in setup() like

  bool sdCardOK = true;    // unkess we learn othertwise
  if (!SD.begin(chipSelect))
    sdCardOK = false;

  bool mlxThingOK = true;    // unkess we learn othertwise
  if (!mlx.begin())
    mlxThingOK = false;

  while (!sdCardOK || !mlxThingOK) {    // some one or two errors
    if (!sdCardOK) digitalWrite(sdError, HIGH);
    if (!mlxThingOK) digitalWrite(mlxError, HIGH);
    delay(400);

    digitalWrite(sdError, LOW);
    digitalWrite(mlxError, LOW);
    delay(400);
  }

Where you have OUTPUTs sdError and mlxError attached to LEDs which will flash in case of failure.

a7

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.