2

When I am in the 30-second standby function, I want to turn the LED on and off at 5-second intervals.

How can I do what I want using the read_counter() function?

The problem here is that I am already in the timer function with the read_counter() function.

void wait_function() {
  timer_init();
  while(read_counter()<30000) { //30 second wait
    // A LED blinking at 1 second intervals ???
  }
}

Note: The read_counter() function increases every 1 millisecond with ISR COMPA vector. I tried many times and couldn't find a stable solution. Example:

if (read_counter() % 1000) PORTB^=(1<<LED);

Update: My new code :

while((TIFR1 & (1 << OCF1A))==0) //4secondIf I do this cycle 8 times, it 
                                 //makes 32 seconds.
            {
                if(TCNT1%15624==0) //per 15624=1 second,
                PORTA^=(1<<0);
                 //led_blink_1s
            }

But,it doesn't work.Should I use util delay function?

4
  • 1
    count six 5 second intervals .... this does not fully describe how the LED is to flash turn the LED on and off at 5-second intervals
    – jsotola
    Dec 22, 2020 at 20:21
  • 3
    this is not a question about arduino software or hardware so off-topic
    – Juraj
    Dec 22, 2020 at 20:32
  • if (read_counter() / 5000 % 2) PINB^=(1<<LED);
    – Gerben
    Dec 23, 2020 at 15:48
  • i updated my code but it doesn't work right. Dec 29, 2020 at 9:28

3 Answers 3

1

Your waiting loop runs much faster than once per millisecond, and even faster per second. So to get just one "event" per second, you need to detect the change of the second.

void wait_function() {
  timer_init();
  for (int second = 0; second < 30; ++second) { // 30 second wait
    // Wait for the next second
    int old_second = read_counter() / 1000;
    int new_second;
    do {
      new_second = read_counter() / 1000;
    } while (new_second == old_second);

    // A LED blinking at 1 second intervals
    PORTB ^= 1 << LED;
  }
}

However, you may think about refactoring your timer. You can put the division in the ISR, and then set a flag if a second has past. In your waiting loop you could wait for the flag, reset it, and toggle the LED.

EDIT:

If you have your (pseudo) code like this:

while (!timed_out) {
    if (timer % ticks_per_second == 0) {
        do_something();
    }
}

you will have the following erroneous behavior, presumed that the loop runs 1 million times per second and the timer increments 20000 times per second.

  1. The timer starts at 1000, for example, and has just incremented.
  2. The loop runs for 50 times until the timer increments to 1001.
  3. This happens repeatedly until the timer gets 20000, which will be after (20000 - 1001) * 50 = 949950 loops.
  4. Now the loop will run for 50 times, while the timer is still at 20000.
  5. The condition is true on each repetition, so do_something() will be executed 50 times in a row.
  6. Next, the timer increments to 20001, and the condition becomes false.

This is exactly what you observe: If the condition of the if becomes true, its statement will be executed repeatedly.

Because the relation between the loop's repetition frequency and the timer's frequency is not the presumed value (but similar) and even depends on the instructions executed, the state of the output is subjectively random. If the XOR instruction is executed an even number, the LED does not change, and if it is executed an odd number, the LED changes.

2
  • i updated my code but it doesn't work right. Dec 29, 2020 at 9:28
  • You still have the same error: While the while loop is running, the condition of the if will be true many times each second. Just as a guessed number, let's say the loop runs 1 million times a second. The condition TCNT1%15624==0 will be true for about 60 times in sequence each second. Additionally, TCNT1 will overflow on 65535 to 0. Dec 29, 2020 at 9:38
1

My solution:

uint16_t st_led=0;
  uint16_t et_led=0;
  
    while((TIFR1 & (1 << OCF1A))==0) //30 second
    {
      
      st_led=TCNT1;
      et_led=st_led;
      while((et_led-st_led)<=15624) //1 second
      {
        et_led=TCNT1;
      }
      PORTA ^= (1<<ledno);
    }
    TIFR1=(1<<OCF1A);
    TCCR1B=0;
0

If read-counter is already incremented once a millisecond, use that to time your LED flashes:

void wait_function() {
  timer_init();
  bool LED_State = LOW
  while(read_counter()<30000) { //30 second wait
    // A LED blinking at 1 second intervals ???
    if (read_counter % 1000 == 0) { //Switch 1000 to 500 here if it flashes too slowly
       LED_State = !LED_State;
       digitalWrite(LEDPin, LED_State ? HIGH : LOW);
    }
  }
}

That code will turn the LED on for one second, then off for one second, etc. (For a total cycle time of 2 seconds.) If you want the full on-off cycle to last 1 second, lower the if statement's value from 1000 to 500.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.