Temp / stepper / millis, specific timing?

trying to code a project i'm working on (my first ever serious attempt on arduino so i'm a comlpleat noob) and got stuck.
i have a temperature transmitter that i want in realtime millis();
then i have a stepper motor i want to run xx steps every 3,5h under a 14h duration.
then i want a longer (10h) pause on the stepper motor.

const unsigned long readtemp = 1000; //every sec
const unsigned long feed = 5000;  //every 5 sec
const unsigned long night = 30000;  //every 30 sec

unsigned long previousTime_readtemp = 0; // vairable to save the last executed time
unsigned long previousTime_feed = 0;
unsigned long previousTime_night = 0;

#include <OneWire.h>
#include <LiquidCrystal.h>
#include <DallasTemperature.h>
#include <Stepper.h>
#define ONE_WIRE_BUS 13

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
LiquidCrystal lcd(2,3,4,5,6,7);

float tempC = 0;

// Define number of steps per rotation:
const int stepsPerRevolution = 942;
// Create stepper object called 'revolver', note the 6+/pin order:
Stepper revolver = Stepper(stepsPerRevolution, 9, 11, 10, 12);
int time = 0;



void setup() {
  sensors.begin();
  lcd.begin(16,2);
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Cubes"); 
  lcd.setCursor(11,0);
  lcd.print("of 28");
  revolver.setSpeed(50);  // Set the speed to 5 rpm:
  pinMode(3, OUTPUT);
  time = 1;
  Serial.begin(9600);
  
}

void loop() {
unsigned long currentTime = millis(); // store the current time
//read and write temp to lcd
    sensors.requestTemperatures();
    tempC = sensors.getTempCByIndex(0);
    //tempF = sensors.toFahrenheit(tempC);
    Serial.println(tempC);
    lcd.setCursor(5,1); //set cursor to center line #2
    lcd.print(tempC); lcd.print((char)223); lcd.print("C");  //lcd.setCursor(0,1);//lcd.print(tempC); lcd.print("");  lcd.print("C");  
    millis();
//feed 08:00/10:30/14:00
  if (currentTime - previousTime_feed >= feed){
     Serial.println("feed");
      revolver.step(stepsPerRevolution);
      lcd.setCursor(6,0);
      lcd.print(time++);
      previousTime_feed = currentTime;
  }
//feed 17:30 and wait 10h
  if (currentTime - previousTime_night >= night){
     Serial.println("night");
     revolver.step(stepsPerRevolution);
     lcd.setCursor(6,0); //set cursor to center line #1
     lcd.print(time++);  //print nubers used  
     previousTime_night = currentTime;   
 }
}

this is what i get from serial monitor under the 2 min duration after that thre is no break probably a small error but i cant find it

18:30:43.893 -> 29.31
18:30:44.583 -> 29.37
18:30:45.333 -> 29.37
18:30:46.083 -> 29.37
18:30:46.785 -> 29.37
18:30:47.535 -> 29.37
18:30:48.239 -> 29.37
18:30:48.987 -> 29.37
18:30:48.987 -> feed
18:30:50.910 -> 29.31
18:30:51.661 -> 29.37
18:30:52.364 -> 29.37
18:30:53.113 -> 29.37
18:30:53.818 -> 29.37
18:30:54.567 -> 29.37
18:30:54.567 -> feed
18:30:56.489 -> 29.31
18:30:57.238 -> 29.31
18:30:57.941 -> 29.37
18:30:58.692 -> 29.37
18:30:59.396 -> 29.37
18:31:00.145 -> 29.37
18:31:00.145 -> feed
18:31:02.066 -> 29.31
18:31:02.817 -> 29.31
18:31:03.520 -> 29.31
18:31:04.270 -> 29.37
18:31:04.972 -> 29.31
18:31:05.722 -> 29.31
18:31:05.722 -> feed
18:31:07.644 -> 29.31
18:31:08.395 -> 29.31
18:31:09.098 -> 29.31
18:31:09.848 -> 29.31
18:31:10.552 -> 29.31
18:31:11.302 -> 29.31
18:31:11.302 -> feed
18:31:13.224 -> 29.31
18:31:13.974 -> 29.31
18:31:13.974 -> night
18:31:15.895 -> 29.31
18:31:16.644 -> 29.31
18:31:16.644 -> feed
18:31:18.567 -> 29.31
18:31:19.271 -> 29.31
18:31:20.019 -> 29.31
18:31:20.722 -> 29.31
18:31:21.472 -> 29.31
18:31:22.223 -> 29.31
18:31:22.223 -> feed
18:31:24.148 -> 29.31
18:31:24.852 -> 29.31
18:31:25.601 -> 29.31
18:31:26.305 -> 29.31
18:31:27.055 -> 29.31
18:31:27.802 -> 29.31
18:31:27.802 -> feed
18:31:29.724 -> 29.31
18:31:30.427 -> 29.31
18:31:31.176 -> 29.31
18:31:31.927 -> 29.31
18:31:32.632 -> 29.31
18:31:33.383 -> 29.31
18:31:33.383 -> feed
18:31:35.305 -> 29.25
18:31:36.009 -> 29.31
18:31:36.759 -> 29.31
18:31:37.505 -> 29.31
18:31:38.208 -> 29.31
18:31:38.958 -> 29.31
18:31:38.958 -> feed
18:31:40.881 -> 29.25
18:31:41.630 -> 29.25
18:31:42.333 -> 29.31
18:31:43.083 -> 29.25
18:31:43.788 -> 29.31
18:31:44.538 -> 29.31
18:31:44.538 -> feed
18:31:45.708 -> night
18:31:47.676 -> 29.25
18:31:48.379 -> 29.25
18:31:49.129 -> 29.25
18:31:49.832 -> 29.25
18:31:49.878 -> feed
18:31:51.802 -> 29.25
18:31:52.505 -> 29.25
18:31:53.255 -> 29.25
18:31:53.959 -> 29.25
18:31:54.710 -> 29.25
18:31:55.413 -> 29.25
18:31:55.413 -> feed
18:31:57.336 -> 29.25
18:31:58.085 -> 29.25
18:31:58.837 -> 29.25
18:31:59.541 -> 29.25
18:32:00.290 -> 29.25
18:32:00.990 -> 29.25
18:32:01.037 -> feed
18:32:02.956 -> 29.25
18:32:03.660 -> 29.25
18:32:04.411 -> 29.25
18:32:05.114 -> 29.25
18:32:05.864 -> 29.25
18:32:06.567 -> 29.25
18:32:06.614 -> feed
18:32:08.535 -> 29.25
18:32:09.238 -> 29.25
18:32:09.989 -> 29.25
18:32:10.691 -> 29.25
18:32:11.442 -> 29.25
18:32:12.192 -> 29.25
18:32:12.192 -> feed
18:32:14.113 -> 29.25
18:32:14.817 -> 29.25
18:32:14.817 -> night
18:32:16.740 -> 29.19
18:32:17.488 -> 29.19
18:32:17.488 -> feed
18:32:19.408 -> 29.19
18:32:20.158 -> 29.19
18:32:20.862 -> 29.19
18:32:21.612 -> 29.25
18:32:22.363 -> 29.25
18:32:23.066 -> 29.25
18:32:23.066 -> feed
18:32:24.989 -> 29.19
18:32:25.739 -> 29.19
18:32:26.443 -> 29.19
18:32:27.194 -> 29.25
18:32:27.944 -> 29.19
18:32:28.647 -> 29.25
18:32:28.647 -> feed
18:32:30.568 -> 29.19
18:32:31.317 -> 29.19
18:32:32.019 -> 29.19
18:32:32.769 -> 29.19
18:32:33.518 -> 29.25
18:32:34.221 -> 29.19
18:32:34.221 -> feed
18:32:36.142 -> 29.19
18:32:36.894 -> 29.19
18:32:37.642 -> 29.19
18:32:38.346 -> 29.19
18:32:39.097 -> 29.19
18:32:39.800 -> 29.19
18:32:39.800 -> feed
18:32:41.722 -> 29.19
18:32:42.473 -> 29.19
18:32:43.222 -> 29.19
18:32:43.925 -> 29.19
18:32:44.675 -> 29.19
18:32:45.378 -> 29.19
18:32:45.378 -> feed
18:32:46.596 -> night

post full code.

Its a bit hard to understand what the problem is -- Is it that feed and night are supposed to interact over a 24 hour cycle?

If so, I might feed every 3.5 hours unless I was in the night portion, determining night based off of something like:

  int half_hour_of_day = (millis()/1000UL/1800UL) % 48; // susceptible to 70 day rollover
 ...
  if (currentTime - previousTime_feed >= feed){
      previousTime_feed += feed;
      if (half_hour_of_day <= 28 ) { // only feed during the daytime
         Serial.println("feed");
         revolver.step(stepsPerRevolution);
         lcd.setCursor(6,0);
         lcd.print(time++);
      }
  }

I like using the previousTime_feed += feed; over previousTime_feed = currentTime; so you stay in sync with millis(), rather than drifting later with the processing involved in each cycle.

The first conditional attempts to feed every 3.5 hours, and the inner conditional chooses only the portions of days in the first 14 hours of each day (as measured in half-hours)

The int half_hour_of_day = (millis()/1000UL/1800UL) % 48; line makes a 0-47 number indicating which half-hour of successive days after the arduino boots up.

If it were (millis()/1000UL/3600UL) % 24; it would be a 0-23 hour_of_day, and the inner conditional could be:

if ( hour_of_day <= 14 ) { //...
1 Like

sorry missed the last
}

1 Like

The logic on the if (millis() - lastTime >= duration) is correct

What does really happen that you don't want ?

hi the problem is that it should feed... lets say 08:00 am / 10:30 am / 02:00 pm and 05:30 pm
after that it should wait until 08:00 am to start over again but it continues after "night"

it continues after "night" remember i'm like a 3 years old when it comes to this :slight_smile:

ah... the way you coded it is that it happens every ∆t

you have a couple issues, the first one being that millis() will loose precision over time and you never know it's 8:30... millis() is just the number of ms since you booted the Arduino.

You should get an RTC, like the DS3231, it's a cheap component that maintain time like your watch.

yes i'm aware of that and its not that big deal. my thought was to start it when i wanted the first feed. then it last for 28 feeds until i have to reset and reload

will try youre code :+1:

You could count the 28 feed times and then stop feeding after that, or reset once you get to to the full 24 hours.

here is a demo-code that shows how a software-RTC can be used with function millis(). This software-RTC still has the problem of beeing unprecise as the timing is derivated from the microprocessors system-clock

For intergrating the times you want to activate the next feeding calculate minutes of the day by

hours * 60 + minutes
this means 08:00 am / 10:30 am / 02:00 pm and 05:30 pm

8:00 is equal to 8 * 60 = 480
10:30 is equal to 10 * 60 + 30 = 630
02:00 pm is equal to 14 * 60 = 840
5:30 pm is equal to 17 * 60 + 30 = 1050

minuteOfDay is always calculated
hour * 60 + minute

and then you simply check

if (minuteOfDay == 480 && feededRightNow == false)  {
  // activatefeeding
  feededRightNow = true;
}
  
if (minuteOfDay == 481 )  {
  feededRightNow = false;
}

and this is repeated for all times of the day you want to feed

This is the software-RTC-code

unsigned long RTC_Timer  = 0;
unsigned long MyTestTimer;

int RTC_Hour   = 0;
int RTC_Minute = 0;
int RTC_Second = 0;
int RTC_10nth_Seconds = 0;


boolean TimePeriodIsOver (unsigned long &periodStartTime, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();  
  if ( currentMillis - periodStartTime >= TimePeriod )
  {
    periodStartTime = currentMillis; // set new expireTime
    return true;                // more time than TimePeriod) has elapsed since last time if-condition was true
  } 
  else return false;            // not expired
}

void PrintRTC_Data() {
  Serial.print(RTC_Hour);
  Serial.print(":");
  Serial.print(RTC_Minute);
  Serial.print(":");
  Serial.print(RTC_Second);
  Serial.println();
}


void SoftRTC() {
  if ( TimePeriodIsOver(RTC_Timer,100) ) {
    RTC_10nth_Seconds ++;
    if (RTC_10nth_Seconds == 10) {      
      RTC_10nth_Seconds = 0;    
      RTC_Second++;
      
      if (RTC_Second == 60) {
        RTC_Minute++;
        RTC_Second = 0;
      }
    }
    
    if (RTC_Minute == 60) {
      RTC_Hour++;
      RTC_Minute = 0;  
    }
  
    if (RTC_Hour == 24) {
      RTC_Hour = 0;
    }      
    if ( TimePeriodIsOver(MyTestTimer,1000) ) {
      PrintRTC_Data();
    }  
    
  }
}


void setup() {
  Serial.begin(115200);
  Serial.println("Setup-Start");
}


void loop() {
  SoftRTC(); // this must be called faster than every 0,1 seconds as this very simple Software-RTC is based on a fast running loop
// to say it explicit: Your code is NOT allowed to stay more than 0,1 seconds in any function
// you could deviate from this 0,1 seconds if the basic "heartBeat" is increased to a higher value with an according modified counting of the seconds
// another solution would be to use a hardware-timer that invokes a timer-interrupt
}

This is a library that provides a software-RTC that is based on a hardware-timer
You have to check if this library wants to use the same hardware-timer than your stepper-motor-library

best regards Stefan

If you switch over to an ESP32 as the microcontroller which has WLAN onboard you can connect the ESP32 to your local WLAN to sync with internet-time. And additionally an ESP32 has an RTC onboard. No extra hardware needed.

ESP32 can be programmed just the same way as an arduino Uno etc.

best regards Stefan

its a tropic fish feeder im working on. the container fit's 28 portions of food after that i have to reload it. the food last's for a week if i feed 4 times a day. feeding under the time lights are on 08:00am-10:00pm

was looking on that but i need it to run on 12v so i just use 1 power cord... theres enogh cords as it alredy is :upside_down_face:

with such a DC-DC-step-down-converter placed next to any microcontroller you only need some very short wiring from the DC-DC-step-down-converter to the microcontroller

best regards Stefan

One thing struck my mind. when does the first feed occur if i start this let's say 00:00
Or when does it decide it's daytime?

Ah, this code initializes at zero, so it would wait the feed time before starting. To start off the sketch with a feed due, put a line like this in setup:

previousTime_feed = millis() - feed;

I figured you had some way of syncing your code with physical day-night. Maybe a cheap lamp timer or something. If you want your code to do it, you might look into a RTC module.

could you please explain the

and

im a bit confused... :thinking:

millis()/1000UL is seconds, millis()/1000UL/1800UL is half-hours and millis()/1000UL/1800UL %48 gives a index of a half hour each day. This way of determining a particular half hour is a bit sloppy -- it is susceptible to the millis() rollover at and will start giving bad results after 49.7 days, when it rolls back over to zero.

Then the (half_hour_of_day <= 28 ) are the indexes of half hours in the first 14 hours of the day.