В подтверждение этого светодиод будет мигать с заданной частотой

Я хочу мигать светодиодом с определенной частотой, то есть 7 Гц

вот что я делаю

int ledPin = 4;
float freq = 7;

void setup() {
  pinMode(ledPin, OUTPUT);
}

float periodo() {
  float peri = 1/freq;
  float halfer = peri/2;
  float millisec = halfer*1000;
  return millisec;
  //return ((1/freq)/2)*1000;
}

void loop() {
  digitalWrite(ledPin, HIGH);    
  delay(periodo());                       
  digitalWrite(ledPin, LOW);     
  delay(periodo());                       
}

Это правильно? это лучший способ сделать это?

заранее спасибо!

, 👍0

Обсуждение

В дополнение к ответу: я бы не стал вызывать "periodo" в цикле, если freq не меняется. Используйте глобальную переменную int actPeriod и инициализируйте ее только в функции setup с помощью actPeriod=periodo(freq); и каждый раз, когда переменная preq может изменяться (в последующих версиях ;-)). Затем используйте новую переменную в задержке. С реальным кодом проблем не было бы, но вы просили оптимальный код, и если вы добавите временную критическую функциональность, это может иметь значение., @Peter Paul Kiefer


1 ответ


Лучший ответ:

2

Вы можете проверить, правильно ли это, рассчитав время на одну минуту и проверив, все ли (приблизительно) в порядке.

Тем не менее, я вижу несколько улучшений:

  • Во-первых, вы всегда возвращаете 1/7/2*1000 = 71,429, который округляется до 71,71 * 14 = 994 мс, так что вы получаете немного более высокую скорость, чем 7 Гц. если это проблема, вы должны компенсировать это.
  • Еще одна небольшая проблема заключается в том, что вы задерживаетесь, но команды digitalWrite также занимают некоторое время, которое не учитывается для задержек. Поэтому вам также нужно учитывать это при использовании точной задержки.
  • При использовании float я всегда использую плавающие постоянные числа, такие как 1.0 и 7.0 вместо 1 и 7. Это может быть особенно полезно, когда вы делите два целых числа (например, 1/7), в результате чего получается 0,14.

Лучшее, что вы можете сделать, - это использовать команду millis. Вы сохраняете таймер и сравниваете его с текущим значением миллиса. Если он слишком высок, выполните изменение состояния. Это будет учитывать все остальные методы, которые вы делаете в то же время digitalWrites.

Что-то вроде: (код исправлен из-за замечаний EdgarBonet)

const float FREQ = 7.0; // Hz
const int PIN_NR = 4;

unsigned long _startTime;
unsigned long _counter;

int _currentState = LOW;

void setup() 
{
  _startTime = millis();
  _counter = 0;
  _currentState = LOW;
  digitalWrite(PIN_NR, _currentState);
}

void loop() 
{
  if (_startTime + _counter * 1000.0 / FREQ / 2.0 >= millis())
  {
    _counter++;
    _currentState = ~_currentState;
    digitalWrite(PIN_NR, _currentState);
  }
}

Несколько небольших заметок:

  • _currentState - это текущее состояние светодиода, с помощью ~ вы можете перевернуть его (он называется оператором not).
  • _startTime - это (близкое к нулю) значение значения millis при запуске.
  • Имейте в виду, что существует ограничение на то, как долго это приложение может работать или работать. миллис работает с мс, то есть вы не можете выйти за пределы 500 Гц, и в некоторых случаях вы получаете "приближения" с частотами ниже. Например, когда Freq = 80 Гц, вы получаете 1000 * 1 / 80 / 2 = 1000 / 160 = 6.25 => 6, что на самом деле 1000/6/2=83,3 Хз.
  • Также счетчик добавляется один раз за изменение состояния, и из-за 1000 * _counter ... переполнение существует, когда _counter >= 256 * 256 * 256 * 256 / 1000 = около 4 миллионов. При 1000 изменениях состояния в секунду это происходит через 4000 секунд, то есть через 66 минут. Для 7 Гц это не будет происходить быстро.
,

1. Это сделает каждый интервал на 71 мс длиннее предыдущего, что означает, что частота модулируется вниз по направлению к нулю. 2. Это может привести к ошибке опрокидывания. Избежать ошибки так же просто, как следовать учебнику Blink Without Delay, так что нет никаких веских причин держать ошибку. 3. Если вы вызываете millis() дважды за одну итерацию цикла, вы вполне можете получить разные результаты, и в этом случае ваши вычисления времени будут сбиты. Вызовите millis() один раз и запишите значение, если оно вам нужно дважды. 4. Почему эти раздражающие подчеркивания перед каждым именем переменной?, @Edgar Bonet

@EdgarBonet Спасибо за ваши комментарии. 1 действительно был глупым жуком. 2. Учебник Blink without delay не совсем точен, так как интервал является фиксированным значением. Это можно было бы улучшить с некоторой компенсацией, хотя и без того, чтобы мое умножение на 1000 приводило к опрокидыванию. 3. Хороший момент, я изменил его в своем коде. 4 Не в каждом имени переменной, а только в переменных "global/class", чтобы было ясно, что это не локальные переменные., @Michel Keijzers