0

I am working with a micro-controller that has an interrupt that counts every 1ms since start.

I have a variable which can be between 0 and 999 and I want to toggle another value if the time elapsed is less than x milliseconds (in following example it is 500ms). So between time 0 and 500 I want shouldActivate to be TRUE, and between 500 and 1000 it should be false, then between 1000 and 1500 it should be true and so on.

int activeTime = 500; // 500ms active
int shouldActivate = 0;
int elapsed = 0; //how many ticks we had so far
// This function gets automatically called every 1ms
void tick() {
  if(elapsed < activeTime) {
     elapsed++;
     shouldActivate = 1;
  } else {
     shouldActivate = 0;
     elapsed--;
  }
}

The above code works when I just start, while elapsed goes over 500, I get problems as it just does the decrement operation only once.

What conditions should I put into my function to achive the desired result?

Lundin
  • 195,001
  • 40
  • 254
  • 396
DEKKER
  • 877
  • 6
  • 19
  • If the `elapsed == activeTime`, and `else` branch triggers, once your `elapsed--` runs, the condition of `elapsed < activeTime` is, once again, true. Why don't just reset `elapsed` to `0`, and invert `shouldActivate`, once the value of `elapsed` reaches `activeTime`? – Algirdas Preidžius Feb 14 '18 at 10:42
  • @AlgirdasPreidžius Thanks, I think what you say is right but works only if target time is 500...but what if my active time is 700 or 300? – DEKKER Feb 14 '18 at 10:47
  • Where did I mention, any specific number (apart from `0`), in my comment? Why do you think, that it won't work with any other number? – Algirdas Preidžius Feb 14 '18 at 10:49
  • The affected variables should be declared `volatile` to prevent the optimizer from holding them in registers only (I guess you have code outside `tick()` that accesses them) – tofro Feb 14 '18 at 11:30
  • These kind of questions are getting tiresome. Where is your re-entrancy protection mechanism? What code is executed in the ISR? https://stackoverflow.com/a/48517862/584518 – Lundin Feb 14 '18 at 11:55

6 Answers6

2

You have two solutions, make new variable "direction" (for specify if you are decrementing or incrementing) but I think better is something like:

void tick() {
  elapsed++;
  if(elapsed < activeTime) {
     shouldActivate = 1;
  } else {
     shouldActivate = 0;
  }
  if(elapsed>999)
    elapsed = 0;
}
Karol T.
  • 543
  • 2
  • 13
1

As per my understanding your application should active for 500 ms and sleep or inactive for 500ms. You can achieve that like below:-

int activeTime = 500; // 500ms active
int shouldActivate = 0;
int elapsed = 0; //how many ticks we had so far
// This function gets automatically called every 1ms
void tick() {
   if(elapsed < activeTime) {
   elapsed++;
   shouldActivate = 1;
  } else {
     shouldActivate = 0;
     elapsed++;//keep increasing elapsed for another 500ms
  }
    // after sleeping for 500ms assign elapsed to zero so that it should active again
    if(elapsed >= (activeTime + 500))       
      elapsed = 0
    //with the above condition you can switch off and on every after 500ms 
}
Abhijit Pritam Dutta
  • 5,521
  • 2
  • 11
  • 17
1

How about:

const int activeTime = 500; // 500ms active
int shouldActivate = 0;
int elapsed = 0; //how many ticks we had so far

// This function gets automatically called every 1ms
void tick() {
    elapsed = (elapsed + 1) % 1000;
    shouldActivate = (elapsed < activeTime);

    // And possibly:
    // if (elapsed == activeTime) { /* State change to Inactivate */}
    // if (elapsed == 0) { /* State change to activate */}
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302
1

So your code only decrements elapsed once then the next time through, elapsed < active, so it increments again.

Most answers so far reset elapsed when it gets to 500 or 1,000. However, if it is called elapsed I think it should contain the elapsed time since the start. Here's a solution that allows elapsed to go on increasing forever, or at least for just over 2 billion milliseconds for a 32 bit int.

void tick()
{
     shouldActivate = elapsed % (2 * activeTime) < activeTime;
     elapsed++;
}
JeremyP
  • 84,577
  • 15
  • 123
  • 161
1

What you are basically describing is a cycle, in which elapsed ranges from 0 to 2*activeTime-1 and the next ms it is back to 0. So in order to check in which part of the range you are at every moment, you can simply do

elapsed = (elapsed+1) % (2*activeTime);

Which will make the final code look like this:

int activeTime = ...;
int shouldActivate = 0;
int elapsed = 0; //how many ticks we had so far
// This function gets automatically called every 1ms
void tick() {
  elapsed = (elapsed+1) % (2*activeTime);
  if(elapsed < activeTime) {
     shouldActivate = 1;
  } else {
     shouldActivate = 0;
  }
}
ndi equals
  • 187
  • 1
  • 9
0

The reason for why your code isn't working is: If the elapsed == activeTime, and else branch triggers, your elapsed-- runs, and after which, the condition of elapsed < activeTime is, once again, true, hence why it keeps going back-and-forth between branches.

Simplest solution, in my opinion, is just resetting elapsed to 0, and inverting shouldActivate, once the value of elapsed reaches activeTime.

void tick() {
  if(elapsed < activeTime) {
     elapsed++;
  } else {
     elapsed = 0;
     shouldActivate = !shouldActivate;
  }
}
Algirdas Preidžius
  • 1,769
  • 3
  • 14
  • 17