В подтверждение этого светодиод будет мигать с заданной частотой
Я хочу мигать светодиодом с определенной частотой, то есть 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());
}
Это правильно? это лучший способ сделать это?
заранее спасибо!
@manuelBetancurt, 👍0
Обсуждение1 ответ
Лучший ответ:
Вы можете проверить, правильно ли это, рассчитав время на одну минуту и проверив, все ли (приблизительно) в порядке.
Тем не менее, я вижу несколько улучшений:
- Во-первых, вы всегда возвращаете 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
- Реализовать связь Visible Light с помощью Arduino
- 4-битный счетчик вверх и вниз
- Светодиодная лента RGB с дистанционным управлением Arduino, проблемы с яркостью/затемнением
- Скетч мигания ESP8266 не мигает светодиодом
- Pro Micro ATMEGA32U4 не может загрузить
- Акцептант векселей ИКТ
- Нужна помощь с матрицей 2X3 для шрифта Брайля
- Отдельный ATmega 2560 - включение одного светодиода - устранение неполадок
В дополнение к ответу: я бы не стал вызывать "periodo" в цикле, если
freqне меняется. Используйте глобальную переменнуюint actPeriodи инициализируйте ее только в функции setup с помощьюactPeriod=periodo(freq);и каждый раз, когда переменная preq может изменяться (в последующих версиях ;-)). Затем используйте новую переменную в задержке. С реальным кодом проблем не было бы, но вы просили оптимальный код, и если вы добавите временную критическую функциональность, это может иметь значение., @Peter Paul Kiefer