Having a bit of a "Brain fade" and need some guidance.
I am trying to set up a timing loop for a integer input.
I can get the millis to function as a stand alone sketch but once I try to integrate it into another sketch I cannot seem to get Millis to act as a timer.
type or paste code here
unsigned long ledStarted = 0;
//const long interval = 1000;
void setup() {
Serial.begin(9600);
Serial1.begin(9600);
}
void ReC()
{
int InpuT = Serial1.read();
Serial.print(InpuT); Serial.println(" Started");
unsigned long currentMillis = millis();
if (currentMillis - ledStarted >= 5000) {
Serial.println(" Inside Timing Loop");
ledStarted = currentMillis;
Serial.println(" Finished");
}
Serial.println(" After Timing Loop");
}
void loop()
{
if (Serial1.available()) {
ReC();
}
}
You should describe in normal words what this means
These words do not contain any filename of an "official" example-code so it is unclear which sketch you mean. Post this sketch where you
From looking at your code I assume:
your code shall wait until you send a character from serial monitor to your arduino
If character is received start "waiting" for 5 seconds
If 5 seconds are over print "Finished"
If "waiting" is over print "After Timing Loop"
I'm unsure if this is what you are trying to do.
Anyway you are another victim of this still to this day ignored very bad introduction to programming provided by the Arduino-Team:
These are really harsh words - I know. It is a very concious decision to write them. And I want to explain why:
1.) A lot of of the basic introductional examples installed with the arduino-IDE use the function delay().
2.) an easy to understand introduction to non-blocking programming is missing
The combination of these two things put newcomers
on the wrong track
It teaches the newcomers to think in a linear = non-looping way.
additionally this famous infamous blink without delay-example shows an
unnescessary complicated way
of how non-blocking timing can be coded.
In summary I call this
"the experts blindness for beginner-difficulties"
An easy to understand example starts with a very common everyday example analogon
and describes the principial function based on this analogon.
Here is my attempt to do it this way
and of course as me myself are to some extent an "expert" myself,
me myself suffer from experts blindness for beginner-difficulties too. This can be resolved through a lot of beginners questions that guide "the expert" what is still difficult to understand and to improve the explanations.
Very simple, you only call ReC( ) once for each serial char available. ReC( ) HAS to run very often to know what time it is or it can't be expected to work right.
if serial is available, read it and get the char which.. you don't use, and then set a variable that causes ReC( ) to run a timer once.
My own way to make a 1-shot timer, in pseudocode:
// inside of a function..... whatever triggers this must set both startMs and waitMs
if ( waitMs > 0 )
{
if ( millis() - startMs >= waitMs )
{
waitMs = 0;
}
else
{
return;
}
} // if the timer is set, function code past here won't run until the time is up.
void loop() goes around and around. All time-checkers should run as often as loop() even if just to see that time is not up and return to check later.
When you write this kind of code, it's about time, it should expect the laters.
Yes.
If you take a look at his code you can see that his knoweldge is pretty limited.
If it would be somehow advanced she/he would have coded a different way.
That is no reason not to show the questioner new ways of programming just because you cannot handle them yourself.
Well, we are all here to share our knowledge, and if the questioner has problems with the answers, he has three options:
ignore
ask questions
put it in their own sketch box and look at it later and learn.
I do not presume to judge the intellectual structure of the questioner.
I have a Arduino controlled station watering pump system which I have programmed in C++.It turns on and off at preset times controlled by the Arduino RTC and On Off signals are transmitted via Lora to the pump solenoids some distance away. This system works just fine.
I am now trying to implement a "Manual Operation" on the system that will come on when a "Numbered Button' between 22 and 33 is pressed on a Nextion display device.
EG If I send the number 22 from the nextion to the arduino
the Arduino will send a Lora signal to that particular pump solenoid to turn it ON.
I need a " timer function " which will control the " on run time " and which will signal the pumps to "stop" after 30 Minutes have expired.
still some details missing.
Which exact type of Arduino are you using?
Arduino Uno?
Arduino Mega 2650?
Arduino Nano or what ever?
This makes a big difference how it has to be coded. Using a hardware-serial interface or a software-serial interface
Do you have successfully tested if reveiving the "22" the "33" into the arduino works?
If you are unable to do this test yourself. You have to provide the Nextion-definition file so that somebody else can look inside and make a suggestion.
To repeat the wanted functionality in my own words:
a nextion-display connected to your arduino sends a message with a number "22" or "33" to the arduino
if the arduino has received this message
depending on the message beeing a "22" or a "33" a solenoid shall be switched on for 30 minutes.
Do you have successfully tested if reveiving the "22" the "33" into the arduino works? yes
if the arduino has received this message depending on the message beeing any number between "22" & "33" a solenoid shall be switched on for 30 minutes.
after 30 minutes switch off solenoid. Yes
As GoForSmoke suggests I see now that once the program leaves the "
void ReC()
it never returns to check the status of "Millis"
It seems to me that I should have the Millis Timing Loop inside the "void loop()" to be continuously checked for " Turn off Time".
unsigned long previousTime = 0;
const long Time = 5000;
int InpuT = 0;
void setup() {
Serial.begin(9600);
Serial1.begin(9600);
}
void ReC()
{
InpuT = Serial1.read();
if (( InpuT > 21) && (InpuT < 33))
{
Serial.print(InpuT); Serial.println(" Started");
}
}
void loop()
{
if (Serial1.available()) {
ReC();
}
if (millis() - previousTime >= Time) {
Serial.println(" TURN OFF PUMP =");
previousTime = millis();
}
}
In this code the Millis timing works just fine.
But how can I get it to output ONLY if variable "InpuT" is between 22 and 33.?
1 -- I'm floating a solution to see if the OP can get past this to what the OP wants.
2 -- I'm NOT spending hours up front crafting a full lesson-in-a-post to make a bruised ego happy.
3 -- So my posts are for the OP to see where the OP is at and not assume total lameness when we do get a very mixed bag of OP's.
4 -- If the OP is up for it, then through interaction I don't need to assume.
5 -- The first other people's code I worked on as a beginner was the company business package that came with the computers, had some bugs and needed changes. I learned loads from that, it was an early CompSci PhD's thesis that I cut coding teeth on.
Maybe where you come from everyone is the same or just gets treated so.
Let the OP decide what the OP is capable of. You take care of yourself Mr. Perfect.
The old code did run the timer but only when serial gave a char.
And great that it was clear to you, you are building good code reading skill.
Here's the thing, you have the stop on time part down but what about the start part?
Inside of void loop(), this timer should only run after it has been started. Another code block in void loop() sets a flag or condition (like wait time > 0 or just a byte variable runTheTimer set to 1 but... I like the code that starts the timer to supply start and wait times and get the light or motion started before the timer runs because then the timer doesn't need to initialize itself (another if-exception).
When the timer runs out, it zeros its own run-trigger so it only runs once on trigger.
That's called a 1-shot as opposed to a repeater that blinks.
You only have to check timers that are being used.
baking a frosted pizza:
you switch on the oven to heat up to 180 degree.
If oven is heated up baking the pizza can start.
You put the pizza into the oven and take a look onto your watch: it is 13:05
the package says "baking-time 10 minutes"
This means at 13:15 pizza should be ready to eat.
You have done two things:
taking a look onto your watch and store startTime. You did this not at any point in time you did it at that moment the baking started.
You made a snapshot of time in your brain. "baking started at 13:05
that is what you do in your code too
if a byte with value 22 or 33 is received store a snapshot of time in a variable
Storing a value greater than zero can be used to indicate "this timer is activated"
so here is the code that does this
Some variable-names are changed to be spot-on self-explaining
unsigned long StartTime = 0;
const unsigned long waitingTime = 5000;
byte InpuT = 0;
void setup() {
Serial.begin(9600);
Serial1.begin(9600);
}
void ReC() {
InpuT = Serial1.read();
if (( InpuT > 21) && (InpuT < 33)) {
Serial.print(InpuT);
Serial.println(" Started");
// store actual value of millis() to do two things
// 1. the non-ZERO-value does ACTIVATE timing see if (StartTime > 0)
// 2. the value itself is used to calculate how much time has passed by since start
StartTime = millis();
}
}
void loop() {
if (Serial1.available()) {
ReC();
}
if (StartTime > 0) { // time-checking: check if timer is ACTIVATED
// if timer IS activated
if (millis() - StartTime >= waitingTime) { // check if more milliseconds than stored in variable "waitingTime" have passed by
// if more milliseconds than "waitingTime" REALLY have passed by
Serial.println(" TURN OFF PUMP =");
StartTime = 0; // DE-activate this timer through assigning value zero
}
}
}
That is a 1-shot. The reason I use wait time > 0 as trigger is that millis() rolls over in a bit under 48 days. On startup millis() returns 0 and every rollover after.
For short periods, a minute or less, I use 16 bit unsigned time variables that work but roll over after 65535 ms = 65.353 seconds. It uses half as much RAM and checks time twice as fast. Rollover happens very often then, start time zero is a legitimate possibility. That's why I run 1-shots when the wait is > 0 which allows it to vary per use.
How could I modify your code to handle multiple turn on requests.
Say Station 22 is selected at 9:00 and then station 27 is selected at 11;30 and then station 32 selected at 2:00pm.All would remain on for the same length of time.
I presume I would need to have a different "StartTime" for each station in "Void ReC" loop but cant see how I could word the" Millis Timing" to cover the 3 different events.
the code in post 15 shows the principle demonstrated on a single timer.
You are on the right track with
each valve needs
his own StartTime
his own WaitTime (if the WaitTimes shall be different)
his own checking for a byte that indicates valve 22, valve 27 etc. which will activate the valvle-specific timer
his own checking how much milli-seconds have passed by
his own switching off the valve
so as the next step make an own attempt to write code for using two valves
There is a good chance that you will code it the right way.
If this happends it is your success
There is a chance that new questions arise if new questions arise post them together with your attempt how it may work.
Posting your own attempt will give specific information about how you think about it. And this will enable more specific explanations that fits to you over a generalised explanation.