Solving Timing Mechanism for C & Arduino Water Sensor

  • Thread starter thedude36
  • Start date
  • Tags
    Mechanism
In summary: Prev = %ld, secInt = %ld, seconds = %ld\n", timer, secPrev, secInt, seconds);Put that statement just before and just after the statement that increments seconds. Then when you run your code, you should see the values of those variables each time.It looks like you're using a lot of ASCII characters that are outside the standard ASCII character set. I'm not sure why I'm seeing that.
  • #1
thedude36
30
0
I'm using arduino to make a water sensor. The sensor needs to go off after a certain period of time of not having come into contact with any water. The difficulty is that i can't use a delay() mechanism as it would mess with other functions of the sensor. I had thought i found a solution but i can't get it to work. what i came up with was

int seconds = 0;
long secPrev = 0;
long secInt = 1000;

void loop() {
∴long timer = millis();
∴if (timer - secPrev > 1000000) //to compensate for roll over
∴∴secPrev = 0;

∴if (timer - secPrev > secInt) { //should increment seconds by 1
∴∴seconds += 1;
∴∴secPrev = timer;
∴}
}


For some reason the seconds arent increasing. the secPrev value is behaving as it should, I am just not sure why the seconds arent. would anyone know why this is?
 
Technology news on Phys.org
  • #2
If you post code, put it between [noparse]
Code:
 and
[/noparse] tags. I did this for you, below.
thedude36 said:
I'm using arduino to make a water sensor. The sensor needs to go off after a certain period of time of not having come into contact with any water. The difficulty is that i can't use a delay() mechanism as it would mess with other functions of the sensor. I had thought i found a solution but i can't get it to work. what i came up with was
Code:
int seconds = 0;
long secPrev = 0;
long secInt = 1000;

void loop() {
∴long timer = millis();
∴if (timer - secPrev > 1000000)   //to compensate for roll over
∴∴secPrev = 0;

∴if (timer - secPrev > secInt) {   //should increment seconds by 1
∴∴seconds += 1;
∴∴secPrev = timer;
∴}
}

For some reason the seconds arent increasing. the secPrev value is behaving as it should, I am just not sure why the seconds arent. would anyone know why this is?

If seconds isn't incrementing, it must be that timer - secPrev <= secInt. I don't understand your logic well enough to guess why this is happening. I haven't worked with the Arduino board at all, or its development environment. Do you have a debugger to work with? If so, that would make it easy to find why your code is doing what it's doing.

If no debugger is available, put in printf statements here and there so you can see the value of your variables.
 
Last edited:
  • #3
Mark44 said:
If seconds isn't incrementing, it must be that timer - secPrev <= secInt. I don't understand your logic well enough to guess why this is happening. I haven't worked with the Arduino board at all, or its development environment. Do you have a debugger to work with? If so, that would make it easy to find why your code is doing what it's doing.

If no debugger is available, put in printf statements here and there so you can see the value of your variables.

arduino uses C primarily, with a few libraries of its own. what i was going for was for every 1000 miliseconds (timer - secPrev) the value of seconds should increase by one and the new value of secPrev should become the current time in milliseconds (secPrev = timer). the value of secPrev behaves how it should, its like the code just skips over seconds all together. I think the problem is with the scope, because when i have it print the value of seconds outside of the if statement it only returns 0 but when inside the if statement it returns 1. I attempted to use pointers but I'm not entirely sure if i used them correctly. to set pointers, it would look like this, right?

Code:
 long *secPtr = &seconds;

but it had given me the same result.
 
Last edited by a moderator:
  • #4
Are seconds, secPrev, and secInt global variables (declared outside of any function)? If so, they should be visible within your loop() function.

I don't understand why you would get different values for seconds depending on whether you were inside the if statement (the second one) or not.

Are you using pointers in the code you're looking at? The code you posted doesn't use pointers at all.
 
  • #5
Mark44 said:
Are you using pointers in the code you're looking at? The code you posted doesn't use pointers at all.

No, though i did try pointers. that didnt seem to help any. with the pointers, the code looked like

Code:
long seconds = 0;
long *secPtr = &seconds;
long secInt = 1000;
long secPrev = 0;

void loop() {
  timer = millis();
  if ((timer - secPrev) > 1000000) {
    secPrev = 0;
  }
  if ((timer-secPrev) > secInt) {
    *secPtr += 1;
    secPrev = timer;
  }
}

with this, i get the same result. And the variables are declared outside of any function. they are declared at the very beginning of the sketch, before setup or loop. atleast, i thought that's how you declare global variables, i could be wrong.
 
  • #6
You haven't told us eaxctly what function millis() does, but if it "rolls over" to 0, or to a big negative number, I think you can get timer - secprev < 0. In that case your test for (timer - secPrev > 1000000) looks wrong.

Or maybe timer and secprev should be declared unsigned long, not long?
 
  • #7
AlephZero said:
You haven't told us eaxctly what function millis() does, but if it "rolls over" to 0, or to a big negative number, I think you can get timer - secprev < 0. In that case your test for (timer - secPrev > 1000000) looks wrong.

Or maybe timer and secprev should be declared unsigned long, not long?


yes, they should be unsigned, but with that change it still doesn't allow seconds to increase any. the test (timer - secprev)> 1000000 is to compensate for the rollover.

And millis() counts from 0 the number of milliseconds that have passed since the program started running. in this case, i want seconds to increase by 1 every 1000 milliseconds.
 
  • #8
Do you have printf? You didn't say whether you had a debugger available.
You could try putting in some output statements, which I suggested before. If your variables are visible outside the if statements, they should be visible inside as well.

If they aren't, you need to take a close look at the documentation for the Arduino C compiler, because it doesn't seem to be working like other C systems.

Code:
void loop() {
  timer = millis();
  printf("timer: %d\n", timer);  // Or %ld if timer is type long.
  printf("secPrev: %ld\n", secPrev);
  if ((timer - secPrev) > 1000000) {
    secPrev = 0;
  }
  if ((timer-secPrev) > secInt) {
    *secPtr += 1;
    secPrev = timer;
  }
}
 
  • #9
How big is an int on this system? If it's a 16-bit system, it could be that an int and a long are the same size (16 bits), in which case the largest signed int or long would be 32,767. And unsigned, the largest values would be 65,535.
 
  • #10
Mark44 said:
Do you have printf? You didn't say whether you had a debugger available.
You could try putting in some output statements, which I suggested before. If your variables are visible outside the if statements, they should be visible inside as well.

If they aren't, you need to take a close look at the documentation for the Arduino C compiler, because it doesn't seem to be working like other C systems.[/code]

I do not have a debugger available. and having it print the values, for seconds its constantly zero, however secPrev does behave how it should. every second its value increases by 1000 as it should. when i remove the test and replace it with 1

Code:
if (1) {
  seconds += 1;
  secPrev = timer;
}

the seconds do incriment as they should, but it does so at a much greater rate (the 1000 millisecond restriction is gone). also, when i run the original code with the print inside of the if statement, it shows that seconds does increase by 1 but the value is lost immediately after the end of the if statement. so when it prints from within the if statement, it constantly returns 1.
 
  • #11
Mark44 said:
How big is an int on this system? If it's a 16-bit system, it could be that an int and a long are the same size (16 bits), in which case the largest signed int or long would be 32,767. And unsigned, the largest values would be 65,535.

it is 8 bit
 
  • #12
How big is a long? I'm guessing that it is 16 bits, but I don't know that.
The largest value of a signed long (if 16 bits) is 32,767, so there's no chance of timer - secPrev ever getting anywhere close to a million, as you have in this code.
Code:
if ((timer - secPrev) > 1000000) {
    secPrev = 0;
  }
 
  • #13
Mark44 said:
How big is a long? I'm guessing that it is 16 bits, but I don't know that.
The largest value of a signed long (if 16 bits) is 32,767, so there's no chance of timer - secPrev ever getting anywhere close to a million, as you have in this code.
Code:
if ((timer - secPrev) > 1000000) {
    secPrev = 0;
  }

a long is 32 bits. a signed long would be around 2000000.
 
  • #14
You're off by a factor of 1000. A signed long would be more than 2,000,000,000. Are you sure that a long is 32 bits? That's a surprising jump from 8 bit integers.
 
  • #15
If you're using the Arduino programming language, their online documentation says that an int is 16 bits, not 8.

Also, the millis() function returns an unsigned long, but your variable is declared as a long. What might be happening is that millis() is returning a value that is too large for a signed long, but not an unsigned long, and timer interprets that value as being negative. You should declare time as unsigned long so that it matches the return type of the millis() function.

Their docs are here: http://arduino.cc/en/Reference/HomePage
 
  • #16
To build on other advice, try printing to some output device the actual value of the timer at each loop (i.e. the one given by millis()).

If this is screwing up, has values that don't make sense, has a rollover aspect not what you are expecting, or even is contingent on some other behaviour that you haven't described (contingent on interrupt behaviour, calling specified functions, setting system variables, etc), then you will see this when it is printed out.

If you can't do this on your board for some reason, see if you can pipe the output to another device.
 
  • #17
I haven't read all of the replies so I apologize if this has already been addressed...

In general there are three ways to time things; using a hardware timer built into the processors event manager block, an external real time clock chip, or counting clocks... Counting clocks is the easiest, if you want a delay for 100ms and you're operating at 100mhz you know that each clock is 10ns so you use asm NOP instructions in a 10,000 count loop... of course this is blocking, meaning no other code can run while you are delaying. If you must run code on the same processor while you are keeping track of the time I'm afraid I know of no other solution than to use a hardware based timer. Many processors, DSP's, microcontrollers etc have built in hardware timers, and if they don't you can purchase a real time clock chip for pennies and interface with it using any standard bus (SPI, UART, I2C, etc...).
 
  • #18
C standard guarantees that an int is at least 16 bits, and a long is at least 32 bits. Of course, any specific compiler could be can be non-conforming, but it's generally a safe bet to assume this much.
yes, they should be unsigned, but with that change it still doesn't allow seconds to increase any. the test (timer - secprev)> 1000000 is to compensate for the rollover.
Show the code. I think it's most likely you think you did the change right but did not.

Among other things, you really mean 1000000u, not 1000000.The second most likely, I think, is that you are using threading but didn't think to mention it.EDIT: whoops, you aren't even programming in C/C++, but instead a language based on it. This opens up even more possibilities for integer conversions and promotions to behave in strange and confusing ways.

And also for integer constants to behave badly. C guarantees that 1000000 would be interpreted as a signed long value (on systems where 1000000 would overflow an unsigned int), but I don't see any such guarantee in Arduino's documentation: in fact, it suggests that Arduino will interpret it as a signed int! So you need both the U and the L suffix to tell it you want an unsigned long value.
 
Last edited:
  • #19
here is the complete code for what i am doing

Code:
 int ledstate1=LOW;
 long seconds = 0;
 long *secPtr = &seconds;
 long minutes = 0;
 long hours = 0;
 long days = 0;
 long weeks = 0;
 long previous = 0;
 long interval = 4900;
 unsigned long secInt = 1000;
 unsigned long secPrev = 0;
 unsigned long num = 100000;
 
 void setup(){
   pinMode(6,OUTPUT);
   pinMode(10,OUTPUT);
   pinMode(11,OUTPUT);
   pinMode(12,OUTPUT);
   pinMode(13,OUTPUT);
   Serial.begin(9600);
 }

 void loop() {
   //Timing Mechanism

   
   unsigned long timer = millis();
   if ((timer - secPrev) > num)
     secPrev = 0;
     
   if ((timer - secPrev)>secInt) {
     *secPtr += 1;
     secPrev = timer;
   }
   Serial.println(seconds);
   if (seconds == 60) {
     minutes += 1;
     seconds = 0;
   }
   if (minutes == 60) {
     hours += 1;
     minutes = 0;
   }
   if (hours == 24){
     days += 1;
     hours = 0;
   }
   if (days == 7) {
     weeks += 1;
     days = 0;
   }
   
   int sensorValue = analogRead(A1);
   //light control
    long current = millis();
    if (current - previous > interval) {
        ledstate1 = HIGH;
       previous = current;
    }
    else
    ledstate1 = LOW;
     if (seconds%2!=0) {
       if (analogRead(A0) > 900)
         digitalWrite(13,ledstate1);
       else
         digitalWrite(13,LOW);
       if (analogRead(A0) < 900){
          if (analogRead(A2) < 900){
            seconds = 0;
            minutes = 0;
            hours = 0;
            days = 0;
            weeks = 0;
          }
          if (seconds > 30)
            digitalWrite(12,ledstate1);
          else
            digitalWrite(12,LOW);
          if(seconds <= 1)
            digitalWrite(6,ledstate1);
          else
            digitalWrite(6,LOW);
          if (seconds > 1 && seconds <= 10)
            digitalWrite(10, ledstate1);
          else
            digitalWrite(10,LOW);
          if (seconds > 10 && seconds <= 30)
            digitalWrite(11,ledstate1);
          else
            digitalWrite(11,LOW);
          }
       else{
          digitalWrite(6,LOW);
          digitalWrite(10,LOW);
          digitalWrite(11,LOW);
       }
     }
     if (seconds%2==0) {
          if (analogRead(A3) < 900){
            seconds = 0;
            minutes = 0;
            hours = 0;
            days = 0;
            weeks = 0;
          }
       if (analogRead(A1) > 900)
         digitalWrite(13, ledstate1);
       else
         digitalWrite(13,LOW);
            if (analogRead(A1) < 900){
          if (seconds > 30)
            digitalWrite(12,ledstate1);
          else
            digitalWrite(12,LOW);
          if(seconds <= 1)
            digitalWrite(6,ledstate1);
          else
            digitalWrite(6,LOW);
          if (seconds > 1 && seconds <= 10)
            digitalWrite(10, ledstate1);
          else
            digitalWrite(10,LOW);
          if (seconds > 10 && seconds <= 30)
            digitalWrite(11,ledstate1);
          else
            digitalWrite(11,LOW);
          }
       else{
          digitalWrite(6,LOW);
          digitalWrite(10,LOW);
          digitalWrite(11,LOW);
       }
     }
   //Analog input/output
   if (seconds % 2 == 0){
     pinMode(A0, OUTPUT);
     pinMode(A1,OUTPUT);
     pinMode(A2, OUTPUT);
     pinMode(A3,OUTPUT);
     digitalWrite(A0,HIGH);
     digitalWrite(A1,LOW);
     digitalWrite(A2,HIGH);
     digitalWrite(A3,LOW);     
   }
   else{
     pinMode(A0,OUTPUT);
     pinMode(A1,OUTPUT);
     pinMode(A2,OUTPUT);
     pinMode(A3,OUTPUT);
     digitalWrite(A0,LOW);
     digitalWrite(A1,HIGH);
     digitalWrite(A2,LOW);
     digitalWrite(A3,HIGH);
   }
 }

the issue i am having occurs in the timing mechanism section. it happens just below that. everything else is pretty irrelevant.
 
  • #20
One thing that sticks out is this Serial.begin(9600).

According to the arduino API reference (http://arduino.cc/en/Reference/SoftwareSerial), this sets the data rate for the board.

Now if the data-rate is affected by every system call and you are flooding the system with such calls, then this is going to affect how the system functions and perhaps will affect you even being able to get anything useful for millis(), especially if the interrupt service routines are being affected by this 9600 parameter and the fact that you are flooding the system with calls to millis().

It says that you can attach interrupts, and the best thing IMO that you can do is to attach your own custom interrupt to the interrupt vector for the timer mechanism and simply store the results in some specially allocated word which is accessed by another routine. In other words, you have a global word to store this clock data from your new interrupt service routine, and you have a function that just returns the contents of the word.

This way, the ISR will activate every time a timer event has occurred and instead of calling millis(), you just get a copy of the value used in the ISR.
 

Related to Solving Timing Mechanism for C & Arduino Water Sensor

1. How does the timing mechanism work for the C & Arduino water sensor?

The timing mechanism for the C & Arduino water sensor works by using a microcontroller, such as an Arduino, to monitor the water sensor and trigger a response when the sensor detects water. The microcontroller is programmed to send a signal to a relay, which in turn activates or deactivates a mechanism, such as a pump or valve, to control the flow of water.

2. Can the timing mechanism be adjusted for different timing intervals?

Yes, the timing mechanism can be adjusted by changing the programming code on the microcontroller. By adjusting the code, the timing intervals can be customized to fit the specific needs of the water sensor and any connected mechanisms.

3. What happens if the timing mechanism malfunctions?

If the timing mechanism malfunctions, it can potentially lead to incorrect timing intervals or failure to trigger the connected mechanisms. This can result in issues such as over or under watering, or failure to detect water. It is important to regularly test and maintain the timing mechanism to ensure proper functioning.

4. Can the timing mechanism be integrated with other sensors or devices?

Yes, the timing mechanism can be integrated with other sensors or devices by connecting them to the microcontroller. This allows for a more complex and customized system that can monitor and control multiple factors, such as soil moisture levels or temperature, in addition to water levels.

5. How can I troubleshoot issues with the timing mechanism?

If you are experiencing issues with the timing mechanism, first check the programming code and connections to ensure they are correct. You can also use a multimeter to test for power and signal flow. If the issue persists, it may be helpful to consult the user manual or seek assistance from the manufacturer.

Similar threads

  • Programming and Computer Science
Replies
2
Views
2K
  • Programming and Computer Science
Replies
2
Views
2K
  • Computing and Technology
Replies
13
Views
777
  • Engineering and Comp Sci Homework Help
Replies
1
Views
5K
  • Engineering and Comp Sci Homework Help
Replies
9
Views
2K
Replies
22
Views
2K
Replies
17
Views
4K
  • Programming and Computer Science
Replies
2
Views
3K
  • Programming and Computer Science
Replies
1
Views
1K
  • MATLAB, Maple, Mathematica, LaTeX
Replies
1
Views
3K
Back
Top