Hi I have the following code. My trouble is with timing....the code keeps going into for loop and the embedded while loop endlessly: serial monitor shows that millis doesn't get updated after exiting the while loop; can't figure out why
#include <Math.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
static uint32_t last_time, now = 0; // RTC
void setup() {
Serial.begin(9600);
pinMode(BPM, INPUT);
pinMode(Tidal_Volume, INPUT);
pinMode(IE, INPUT);
// declare OUTPUT PINS FOR INHALE AND EXHALE PWMs:
pinMode(motor_inhale, OUTPUT);
pinMode(motor_dir, OUTPUT);
// declare buttons as input
pinMode(motor_home, INPUT);
pinMode(opto_interrupt, INPUT);
pinMode(pressure_sensor,INPUT);
// LCD setup
lcd.init(); // initialize the lcd
lcd.init();
// Print a message to the LCD.
lcd.backlight();
now = millis();
}
void loop(){
lcd.setCursor(0,0);
lcd.print("BPM ");
lcd.print(LCD_BPM);
lcd.setCursor(7,0);
lcd.print(" Vol ");
lcd.print(LCD_Tidal_Volume);
lcd.setCursor(6,1);
lcd.print("IE ");
lcd.print(LCD_IE);
for(int i = 0; i < 5; i++){
Serial.println("Completed =\t");
Serial.println(i);
while ((now-last_time) < 300) //delay by millis_t_inhale
{
now = millis();
Serial.println(now);
}
last_time = now;
}
}
I have stripped down your code to the minimum for examining the use of the function milli()
because I don't have a I2C-LCD and the definitions for the constants like in
pinMode(BPM, INPUT);
in your code is missing in the code you posted above.
So this code-version is counting up on an arduino Una-Board
#include <Math.h>
#include <Wire.h>
static uint32_t last_time, now = 0; // RTC
void setup() {
Serial.begin(9600);
now = millis();
}
void loop(){
/*
lcd.print("BPM ");
lcd.print(LCD_BPM);
lcd.print(" Vol ");
lcd.print(LCD_Tidal_Volume);
lcd.print("IE ");
lcd.print(LCD_IE);
*/
for(int i = 0; i < 5; i++){
Serial.println("Completed =\t");
Serial.println(i);
while ((now-last_time) < 300) //delay by millis_t_inhale
{
now = millis();
Serial.println(now);
}
last_time = now;
}
}
Maybe the reason why your code is not counting up is that you are using another board. Though I doubt that this is the reason.
Anyway what board are you using?
What does the serial monitor show if you upload my code-version?
Can you describe in normal words what your code should do?
The mostly used way how the command millis() is used is a bit different. But maybe for what you would like to do
your version is best suited. Though I don't know (yet) what you want to do in the end.
Thanks for your attempt. I should have mentioned it in my previous post, the counter code left alone by itself works as intended...as you have correctly assumed by suggesting to run the stripped version. That's why I needed someone else to look at my code and maybe see the source of the problem. So you think that the LCD board is causing the for loop to fail and not reset? The LCD board I'm using is this one:
As far as the function of my code, it has 3 user inputs via potentiometers the values of which calculate certain time durations (let's call it X) within the code. What I am trying to do with the for loop and millis function is to have a non-blocking timer and perform certain actions while the timer value is less than X. I am doing all the math (involving the potentiometer values) within the loop function. (would that cause any problems?)
I ran your code and it still doesn't get out of the for loop.
I'm also attaching the original working code (which I am trying to integrate into mine)
static uint32_t last_time, now = 0; // RTC
void setup() {
// put your setup code here, to run once:
now = millis();
}
void loop() {
Serial.begin(9600);
// improved replacement of delay(1000)
// Much better accuracy, no more dependant of loop execution time
for ( int i=0 ;i<5 ;i++)// make 5 time 300ms loop, for faster Button response
{
Serial.println("Completed =\t");
Serial.println(i);
while ((now-last_time)<300) //delay200ms
{
now=millis();
Serial.println(now);
}
// inner 300ms loop
last_time = now; // prepare for next loop
}
}
when i tried running the code in the previous post it stopped after about a second.
i then moved the Serial.begin() to setup() and it ran continuously
static uint32_t last_time, now = 0; // RTC
void setup() {
Serial.begin(9600);
// put your setup code here, to run once:
now = millis();
}
void loop() {
// improved replacement of delay(1000)
// Much better accuracy, no more dependant of loop execution time
for ( int i=0 ;i<5 ;i++)// make 5 time 300ms loop, for faster Button response
{
Serial.println("Completed =\t");
Serial.println(i);
while ((now-last_time)<300) //delay200ms
{
now=millis();
Serial.println(now);
}
// inner 300ms loop
last_time = now; // prepare for next loop
}
}
with all the other stuff commented out. You can see that the while() loop spins many times before millis() updates but since you are doing Serial.print() inside that loop, the serial buffer eventually fills up since you are pushing more into it than 9600 baud can spit out. Once full, that statement slows down the loop since println() must block until there is room to add more characters.
This kind of while-loop does have the same effect as a delay(). With the additional disadvantgae that you have to type more code.
The microcontroller stays inside the while-loop and is busy executing the commands inside the while-loop and is unable to execute other commands.
I post a demo-code that shows the principle
in some way it is opposite to what you tried.
You tried to do a delay at a certain point in the sequence of your code. to achieve a delayed execution.
In the demo-code below the big mainloop is executed at high speed and
**only if a certain amount of time has passed by **some of the commands are executed.
This enables fast running through the big loop in combination with "delayed" execution of parts of the code.
The code does printout a lot of dots to show that the main-loop is running fast.
It is still slowed down to make it visible for human eyes what is going on and serial output needs some time too.
every five "time-slices" the printed character is changed to a double-cross
every second an extra line with a number is printed
unsigned long currentMillis;
unsigned long Period = 1000;
unsigned long LastTime_Period_Elapsed;
unsigned long SlowDownPeriod = 20;
unsigned long LastTime_SlowDownPeriod_Elapsed;
unsigned long DoubleCrossPeriod = 5 * SlowDownPeriod;
unsigned long LastTime_DoubleCrossPeriod_Elapsed;
int NumberOfElapsedPeriods = 0;
const char dot = '.';
const char doubleCross = '#';
char CharToPrint;
void setup() {
Serial.begin(115200);
LastTime_Period_Elapsed = millis();
LastTime_SlowDownPeriod_Elapsed = millis();
LastTime_DoubleCrossPeriod_Elapsed = millis();
}
void loop() {
currentMillis = millis();
visualiseLooping();
if (currentMillis - LastTime_Period_Elapsed >= Period) {
LastTime_Period_Elapsed = currentMillis;
NumberOfElapsedPeriods ++;
Serial.println();
Serial.print(NumberOfElapsedPeriods);
Serial.println(" period is over");
}
}
void visualiseLooping() {
if (currentMillis - LastTime_DoubleCrossPeriod_Elapsed >= DoubleCrossPeriod) {
LastTime_DoubleCrossPeriod_Elapsed = currentMillis;
CharToPrint = doubleCross;
}
else {
CharToPrint = dot;
}
if (currentMillis - LastTime_SlowDownPeriod_Elapsed >= SlowDownPeriod) {
LastTime_SlowDownPeriod_Elapsed = currentMillis;
Serial.print(CharToPrint);
}
}
So try to change your code into this direction. If you have any questions just post them.
best regards Stefan