Как контролировать мигание светодиода во время работы таймера?

Когда я нахожусь в 30-секундном режиме ожидания, я хочу включать и выключать светодиод с интервалом в 5 секунд.

Как я могу сделать то, что хочу, используя функцию read_counter() ?

Проблема здесь в том, что я уже нахожусь в функции таймера с помощью функции read_counter() .

void wait_function() {
  timer_init();
  while(read_counter()<30000) { //30 секунд ожидания
    // Светодиод мигает с интервалом в 1 секунду ???
  }
}

Примечание: Функция read_counter() увеличивается каждые 1 миллисекунду с помощью вектора ISR COMPA. Я пробовал много раз и не мог найти стабильного решения. Пример:

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

Обновление: Мой новый код:

while((TIFR1 & (1 << OCF1A))==0) //4secondIf я делаю этот цикл 8 раз, он
                                 //составляет 32 секунды.
            {
                if(TCNT1%15624==0) //за 15624=1 секунду,
                PORTA^=(1<<0);
                 //led_blink_1s
            }

Но это не работает.Должен ли я использовать функцию задержки util?

, 👍2

Обсуждение

подсчитайте шесть 5-секундных интервалов ... это не полностью описывает, как светодиод должен мигать "включите и выключите светодиод с 5-секундными интервалами"., @jsotola

это не вопрос о программном или аппаратном обеспечении arduino, поэтому он не по теме, @Juraj

`if (read_counter() / 5000 % 2) PINB^=(1<, @Gerben

я обновил свой код, но он работает неправильно., @harun caliskanoglu


3 ответа


1

Ваш цикл ожидания выполняется намного быстрее, чем один раз в миллисекунду, и даже быстрее в секунду. Таким образом, чтобы получить только одно "событие" в секунду, вам нужно обнаружить изменение второго.

void wait_function() {
  timer_init();
  for (int second = 0; second < 30; ++second) { // 30 секунд ожидания
    // Дождитесь следующей секунды
    int old_second = read_counter() / 1000;
    int new_second;
    do {
      new_second = read_counter() / 1000;
    } while (new_second == old_second);

    // Светодиод мигает с интервалом в 1 секунду
    PORTB ^= 1 << LED;
  }
}

Однако вы можете подумать о рефакторинге своего таймера. Вы можете поместить деление в ISR, а затем установить флаг, если прошла секунда. В цикле ожидания вы можете дождаться флага, сбросить его и переключить светодиод.

ПРАВКА:

Если у вас есть (псевдо) код, как это:

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

у вас будет следующее ошибочное поведение: предполагается, что цикл выполняется 1 миллион раз в секунду, а таймер увеличивается на 20000 раз в секунду.

  1. Например, таймер начинается с 1000 и только что увеличился.
  2. Цикл выполняется 50 раз, пока таймер не увеличится до 1001.
  3. Это происходит многократно, пока таймер не получит 20000, что будет после (20000 - 1001) * 50 = 949950 циклов.
  4. Теперь цикл будет выполняться 50 раз, в то время как таймер все еще находится на отметке 20000.
  5. Условие истинно при каждом повторении, поэтому do_something() будет выполняться 50 раз подряд.
  6. Затем таймер увеличивается до 20001, и условие становится ложным.

Это именно то, что вы наблюдаете: если условие if становится истинным, его оператор будет выполняться повторно.

Поскольку связь между частотой повторения цикла и частотой таймера не является предполагаемым значением (но аналогична) и даже зависит от выполняемых инструкций, состояние выходного сигнала субъективно случайно. Если команда XOR выполняется четным числом, светодиод не меняется, а если он выполняется нечетным числом, светодиод меняется.

,

я обновил свой код, но он работает неправильно., @harun caliskanoglu

У вас все еще есть та же ошибка: пока выполняется цикл "while", условие "if" будет истинным много раз в секунду. Как и угаданное число, предположим, что цикл выполняется 1 миллион раз в секунду. Условие TCNT1% 15624==0 будет выполняться примерно 60 раз подряд каждую секунду. Кроме того, TCNT1 будет переполнен на 65535 до 0., @the busybee


0

Если счетчик считывания уже увеличивается один раз в миллисекунду, используйте его для определения времени мигания светодиода:

void wait_function() {
  timer_init();
  bool LED_State = LOW
  while(read_counter()<30000) { //30 секунд ожидания
    // Светодиод мигает с интервалом в 1 секунду ???
    if (read_counter % 1000 == 0) { //Переключите 1000 на 500 здесь, если он мигает слишком медленно
       LED_State = !LED_State;
       digitalWrite(LEDPin, LED_State ? HIGH : LOW);
    }
  }
}

Этот код включит светодиод на одну секунду, затем выключит на одну секунду и т. Д. (Для общего времени цикла 2 секунды.) Если вы хотите, чтобы полный цикл включения-выключения длился 1 секунду, уменьшите значение оператора if с 1000 до 500.

,

1

Мое решение:

uint16_t st_led=0;
  uint16_t et_led=0;
  
    while((TIFR1 & (1 << OCF1A))==0) //30 секунд
    {
      
      st_led=TCNT1;
      et_led=st_led;
      while((et_led-st_led)<=15624) //1 секунда
      {
        et_led=TCNT1;
      }
      PORTA ^= (1<<ledno);
    }
    TIFR1=(1<<OCF1A);
    TCCR1B=0;
,