smooth blink

nibelung
Offline
Зарегистрирован: 21.04.2021

Купил я себе у китайцев платку с контроллером STM32F411 с завода она идет с прошитым загрузчиком под STMDUINO. При включении обнаружилось, что светодиод на этой плате плавно загорается а затем гаснет. Делает это загрузчик или прошитый для примера скетч, я тогда разбираться не стал, но эффект мне понравился.

Сейчас праздники, есть немного свободного времени. Вспомнил я про этот эффект и захотелось мне его повторить, но уже на обычной ардуинке. В качестве подопытного мыша, у меня, выступает китайский клон "SparkFun Pro Micro". Если у Вас другая Aduino, подправьте в первой строке привязку к выводу управляющему светодиодом.

Всех с праздником.

Morroc
Offline
Зарегистрирован: 24.10.2016

Стандартный из Examples Fade не такой ? По описанию похоже.

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Всё не так. 

Например millis() совсем не uint8_t, а совсем даже unsigned long. Можно очень даже нарваться.

Почитайте лучше "блинк без делей".

negavoid2
negavoid2 аватар
Offline
Зарегистрирован: 06.05.2020

mykaida пишет:
Всё не так. Например millis() совсем не uint8_t, а совсем даже unsigned long. Можно очень даже нарваться.

Всё ок. Просто код нарывается на переполнение байта, а не дворда, более того, это не баг, это фича.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ну не знаю, если поменять:
 

1led_state ^= 1;
2 
3на
4 
5led_state = !led_state;

вроде более читабельный код, да и по памяти:
 

01Скетч использует 824 байт (2%) памяти устройства. Всего доступно 32256 байт.
02Глобальные переменные используют 12 байт (0%) динамической памяти, оставляя 2036 байт для локальных переменных. Максимум: 2048 байт.
03 
04 
05Скетч использует 826 байт (2%) памяти устройства. Всего доступно 32256 байт.
06Глобальные переменные используют 12 байт (0%) динамической памяти, оставляя 2036 байт для локальных переменных. Максимум: 2048 байт.
07 
08 
09А если задействовать сериал, то:
10 
11Скетч использует 2022 байт (6%) памяти устройства. Всего доступно 32256 байт.
12Глобальные переменные используют 191 байт (9%) динамической памяти, оставляя 1857 байт для локальных переменных. Максимум: 2048 байт.
13 
14Скетч использует 1918 байт (5%) памяти устройства. Всего доступно 32256 байт.
15Глобальные переменные используют 191 байт (9%) динамической памяти, оставляя 1857 байт для локальных переменных. Максимум: 2048 байт.

Не всё так однозначно, где найдёшь, где потеряешь )))

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

negavoid2 пишет:

Всё ок. Просто код нарывается на переполнение байта, а не дворда, более того, это не баг, это фича.

Фича - это косяк. Идею понял, но не одобряю.

negavoid2
negavoid2 аватар
Offline
Зарегистрирован: 06.05.2020

Мы расстроены, продолжайте держать нас в курсе :)

На самом деле, нормально. И delay использовать нормально. И даже goto (хоть оно, конечно, почти никогда и не нужно). Реальный мир - он того, не такой, как проповедуют великие теоретики, он полон компромиссов, и неудобностей, и прочего, и хоть я их (теоретиков) и уважаю, но свою голову-то на плечах тоже надо иметь.

Green
Offline
Зарегистрирован: 01.10.2015

А я вообще не понимаю этих перестраховщиков.
Простейший скетч и столько поноса.(

01#define LED  LED_BUILTIN_RX
02#define INTERVAL1 (23u) //на кой здесь u и скобки?
03#define INTERVAL2 (24u)
04#define toggle(x) digitalWrite(x, !digitalRead(x))
05 
06void setup() {
07  pinMode (LED, OUTPUT);
08}
09 
10void loop() {
11  static uint8_t clk1 = 0, clk2 = 0; //на кой здесь 0-ли?
12  static uint8_t led_state = 0; //на кой вообще этот state?
13  uint8_t now = millis();
14 
15  if (INTERVAL1 < (uint8_t)(now - clk1)) //отчего бы не написать по нормальному:
16  if (now - clk1 > INTERVAL1) {
17  { //стиль идиотский!
18    clk1 += INTERVAL1;
19    led_state ^= 1; //toggle(LED);
20  }
21 
22  if (INTERVAL2 < (uint8_t)(now - clk2)) //аналогично
23  {
24    clk2 += INTERVAL2;
25    led_state ^= 1;
26  }
27 
28  digitalWrite(LED, ((0 == led_state) ? LOW : HIGH)); //это лишнее и это вообще порнография
29 }

 

nibelung
Offline
Зарегистрирован: 21.04.2021

Green, прежде чем ругать чужой, работающий код, да еще с таким наездом, подумали бы хорошенько. Если чего не понятно могли бы спросить и вам бы ответили.

А так, вы только свою безграмотность продемонстрировали.

b707
Offline
Зарегистрирован: 26.05.2017

nibelung пишет:

Green, прежде чем ругать чужой, работающий код, да еще с таким наездом, подумали бы хорошенько. Если чего не понятно могли бы спросить и вам бы ответили.

А так, вы только свою безграмотность продемонстрировали.

nibelung - а что так резко-то? Критики не любите?

"Работающий код" не принято ругать в одном случае - когда он делает что-то важное, что до него никому не удавалось. Вы выложили элементарнейшую мигалку на эффекте интерференции - а ведете себя так, будто как минимум теорему Ферма решили...

Что касакется "безграмотности" - я бы поспорил. Попытайтесь обосновать, зачем вы написали 23u

nibelung
Offline
Зарегистрирован: 21.04.2021

b707 пишет:

Попытайтесь обосновать, зачем вы написали 23u

Чтобы объяснить компилятору, что это unsigned константа. По умолчанию все константы имеют тип int (знаковый).

b707 пишет:

nibelung - а что так резко-то? Критики не любите?

А где там критика? Только самоутверждение за счет новичка. Вот этого не люблю.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Нибелунг! Ща я встану и напишу пост в защиту тебя. Все у тебя правильно. Может слегка избыточно, но правильно и красиво.
Не будь нежным таким, как кожа на залупе, только больше троллить станут.
Некоторые перегибают в чморении новичков. Прости им. ;))

nibelung
Offline
Зарегистрирован: 21.04.2021

wdrakula пишет:
Нибелунг! Ща я встану и напишу пост в защиту тебя. Все у тебя правильно. Может слегка избыточно, но правильно и красиво. Не будь нежным таким, как кожа на залупе, только больше троллить станут. Некоторые перегибают в чморении новичков. Прости им. ;))

Спасибо на добром слове.

Им простил :))

b707
Offline
Зарегистрирован: 26.05.2017

nibelung пишет:

Чтобы объяснить компилятору, что это unsigned константа. По умолчанию все константы имеют тип int (знаковый).

где ты увидал в этом выражении константу?

nibelung
Offline
Зарегистрирован: 21.04.2021

Ну вот, троллинг продолжается :)))

b707 пишет:

где ты увидал в этом выражении константу?

А где ты увидал в этом выражении переменную?

 
Bruzzer
Offline
Зарегистрирован: 17.03.2020

wdrakula пишет:
... Ща я встану и ....

Не будь нежным таким, как кожа на ....

Сразу представилось общение тертого жизней члена форума с молодым и нежным.

b707
Offline
Зарегистрирован: 26.05.2017

wdrakula пишет:
Может слегка избыточно, но правильно и красиво. ))

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

Добавление скобок и "u"  к величине, применяемой не в составе выражения. а отдельно - скорее свидетесльствует о том, что автор не понимает, что пишет.

Изначально еще хотел написать о избыточности явного приведения разности двух байт к типу uint8_t - но подумал, что сам, наверно, написал бы так же - просто на автомате, чтобы не задумыватся о том, какой тип тут примет компилятор. Но вряд ли такой кастинг "на всякий случай" говорит в пользу "грамотности". скорее просто лень :)

nibelung
Offline
Зарегистрирован: 21.04.2021

b707 пишет:

Изначально еще хотел написать о избыточности явного приведения разности двух байт к типу uint8_t - но подумал, что сам, наверно, написал бы так же - просто на автомате, чтобы не задумыватся о том, какой тип тут примет компилятор. 

Вот это, кстати, интересное замечание. Написал так, именно на автомате. Потом убрал приведение типа, ибо выглядит немного громоздко. Убедился, что компилятор, ожидаемо, ошибся. И вернул приведение типа на место.

b707
Offline
Зарегистрирован: 26.05.2017

Короче. Влад.

когда встанешь - с радостью выслушаю твою лекцию, зачем тут в выражении

скобки и "u" . Только не вообще, а конкретно в этом коде, из первого сообщения.

 

PS   нибелунг - вопрос конкретному человеку, не вам

rkit
Offline
Зарегистрирован: 23.11.2016

Так себе код. Если добавить другую нагрузку, то будет работать плохо. Даже как учебный не годится - слишком специфичный и мудреный.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

b707 пишет:

Короче. Влад.

когда встанешь - с радостью выслушаю твою лекцию, зачем тут в выражении

скобки и "u" . Только не вообще, а конкретно в этом коде, из первого сообщения.

 

PS   нибелунг - вопрос конкретному человеку, не вам

По поводу неуместности Фединого toggle() в данном коде вопросов нет, надеюсь? Ок.

Сразу ответ: в этом конкретном случае ни скобки ни u не нужны. "Но есть один нюанс!" ;))

Это очень правильный подход - всегда ставить скобки и явное указание типа константы в макросах.

Макросы, в отличии от констант и константных выражений не позволяют указать тип иным способом. Макрос подставляется просто графически, как есть. Сколько уже тут было "вычислителей" времени в макросах с криками: "Памагити ниработаит!"? Так вот явное указание типа не меняет размер или скорость кода, но делает его читаемым и легко сопроводжаемым. То же касается скобок. Ставь их вообще всегда, не задумываясь, иначе будет, как в эпическом фейле Архата с его макросом, который работал ТОЛЬКО потому, что Архат, по дурости, скобки не поставил. ;)))

То есть скобки и "u" - это просто полезные привычки, как комментарии, расстановка фигурных скобок, скобки вокруг единственного оператора в if, while, for и прочее. Указывать на это, как на ошибку - высокомерие, больше похожее на дурость, уж прости.

Green
Offline
Зарегистрирован: 01.10.2015

Ух ты! Да, получилось не красиво. nibelung, я извиняюсь. По трезвому выглядит совсем иначе.(

b707
Offline
Зарегистрирован: 26.05.2017

nibelung пишет:

b707 пишет:

Изначально еще хотел написать о избыточности явного приведения разности двух байт к типу uint8_t - но подумал, что сам, наверно, написал бы так же - просто на автомате, чтобы не задумыватся о том, какой тип тут примет компилятор. 

Вот это, кстати, интересное замечание. Написал так, именно на автомате. Потом убрал приведение типа, ибо выглядит немного громоздко. Убедился, что компилятор, ожидаемо, ошибся. И вернул приведение типа на место.

Компилятор ошибся? - он у вас китайский. наверно...

проверим? - первое условие - без приведения типа, второе - с оным.

результат

как видите, результат одинаков на всех возможных значениях

nibelung
Offline
Зарегистрирован: 21.04.2021

Green, я тоже немного погорячился, Простите если обидел.

b707
Offline
Зарегистрирован: 26.05.2017

wdrakula пишет:

То есть скобки и "u" - это просто полезные привычки, как комментарии, расстановка фигурных скобок, скобки вокруг единственного оператора в if, while, for и прочее.

с этим согласен. Но это как раз те самые замечания "вообще", которых я просил избежать. В конкретном коде эти элементы не обязательны, согласен? и потому Грин не так уж неправ - и уж точно его не за что было обвинять в "беграмотности".

 

А если рассматривать вообще :) - то подавать свой элементарный  код как что-то, "отлитое в бронзе", где уже нельзя поправить ни одну букву - вот это как раз глупость и заносчивость...

 

nibelung
Offline
Зарегистрирован: 21.04.2021

b707 пишет:

nibelung пишет:

b707 пишет:

Изначально еще хотел написать о избыточности явного приведения разности двух байт к типу uint8_t - но подумал, что сам, наверно, написал бы так же - просто на автомате, чтобы не задумыватся о том, какой тип тут примет компилятор. 

Вот это, кстати, интересное замечание. Написал так, именно на автомате. Потом убрал приведение типа, ибо выглядит немного громоздко. Убедился, что компилятор, ожидаемо, ошибся. И вернул приведение типа на место.

Компилятор ошибся? - он у вас китайский. наверно...

проверим? - первое условие - без приведения типа, второе - с оным.

результат

как видите, результат одинаков на всех возможных значениях

Так уж и "на всех возможных значениях"?

"clk1" вы менять поленились, а ошибки проявляются, когда происходит переполнение.

b707
Offline
Зарегистрирован: 26.05.2017

nibelung пишет:

Так уж и "на всех возможных значениях"?

"clk1" вы менять поленились, а ошибки проявляются, когда происходит переполнение.

Свою точку зрения кодом я подтвердил.

Если не согласны - давайте сделаем так. Вы выкладываете коротенький код, который демонстрирует, что с приведением типа и без него условие if формирует разный результат - тогда и обсудим.

 

nibelung
Offline
Зарегистрирован: 21.04.2021

Немного поправил ваш код.

разница совсем небольшая, только clk1 инициализировал отличным от нуля значением.

а вот вывод

как видите не везде результат одинаков.

b707
Offline
Зарегистрирован: 26.05.2017

ок, очко в вашу пользу

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

b707 пишет:

ок, очко в вашу пользу

Упрямый, но честный! ;))

Это же история, как раз из той области, в которой был мой срач с Андриано. Неявное преобразование между знаковым и беззнаковым. Если не поставить явное преобразование, то будут эти самые грабли. Как же можно забыть такую тему? ;))))

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

b707 пишет:
подавать свой элементарный  код

Код на интерференции двух волн не элементарный, а красивый, признай. Много тут новичков, способных выдать такое?

И нормально оформленное. Поправить "ради красоты" там можно только строчку:

1digitalWrite(LED, ((0 == led_state) ? LOW : HIGH));

заменив на:

1digitalWrite(LED,  led_state ? HIGH : LOW);

или просто

1digitalWrite(LED,  led_state );

;))))))

Green
Offline
Зарегистрирован: 01.10.2015

Я намекал на такое. Хотя знаю, что Влад это не приветствует.

01#define LED       LED_BUILTIN
02#define INTERVAL1 23
03#define INTERVAL2 24
04#define toggle(x) digitalWrite(x, !digitalRead(x))
05 
06void setup() {
07  pinMode (LED, OUTPUT);
08}
09 
10void loop() {
11  static uint8_t clk1, clk2;
12   
13  uint8_t now = millis();
14  if ((uint8_t)(now - clk1) > INTERVAL1) {
15    clk1 += INTERVAL1;
16    toggle(LED);
17  }
18  if ((uint8_t)(now - clk2) > INTERVAL2) {
19    clk2 += INTERVAL2;
20    toggle(LED);
21  }
22}
nibelung
Offline
Зарегистрирован: 21.04.2021

Green пишет:

Я намекал на такое. Хотя знаю, что Влад это не приветствует.

01#define LED       LED_BUILTIN
02#define INTERVAL1 23
03#define INTERVAL2 24
04#define toggle(x) digitalWrite(x, !digitalRead(x))
05 
06void setup() {
07  pinMode (LED, OUTPUT);
08}
09 
10void loop() {
11  static uint8_t clk1, clk2;
12   
13  uint8_t now = millis();
14  if ((uint8_t)(now - clk1) > INTERVAL1) {
15    clk1 += INTERVAL1;
16    toggle(LED);
17  }
18  if ((uint8_t)(now - clk2) > INTERVAL2) {
19    clk2 += INTERVAL2;
20    toggle(LED);
21  }
22}

Такое тоже работать будет, но есть маааленький косячок.

Когда условия по INTERVAL1 и INTERVAL2 выполнятся на одном проходе Loop, у вас на диоде получится очень короткий импульс, а по задумке его там быть не должно.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

nibelung пишет:

Green пишет:

Я намекал на такое. Хотя знаю, что Влад это не приветствует.

01#define LED       LED_BUILTIN
02#define INTERVAL1 23
03#define INTERVAL2 24
04#define toggle(x) digitalWrite(x, !digitalRead(x))
05 
06void setup() {
07  pinMode (LED, OUTPUT);
08}
09 
10void loop() {
11  static uint8_t clk1, clk2;
12   
13  uint8_t now = millis();
14  if ((uint8_t)(now - clk1) > INTERVAL1) {
15    clk1 += INTERVAL1;
16    toggle(LED);
17  }
18  if ((uint8_t)(now - clk2) > INTERVAL2) {
19    clk2 += INTERVAL2;
20    toggle(LED);
21  }
22}

Такое тоже работать будет, но есть маааленький косячок.

Когда условия по INTERVAL1 и INTERVAL2 выполнятся на одном проходе Loop, у вас на диоде получится очень короткий импульс, а по задумке его там быть не должно.

Вот именно про это я написал, когда сказал, что Федин toggle() неуместен.

nibelung
Offline
Зарегистрирован: 21.04.2021

И еще

1void loop() {
2  static uint8_t clk1, clk2;

Это, все таки, объявление глобальных переменных с областью видимости, ограниченной, функцией Loop. Их желательно явно инициализировать.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

nibelung пишет:

И еще

1void loop() {
2  static uint8_t clk1, clk2;

Это, все таки, объявление глобальных переменных с областью видимости, ограниченной, функцией Loop. Их желательно явно инициализировать.

а тут ты неправ... ;))) хороший тон, но необязательно. Ну и слово "глобальные" совершенно не к месту и не в тему.

nik182
Offline
Зарегистрирован: 04.05.2015

Пожалуйста объясните, зачем объявлять переменные локально для проектов на МК. Я понимаю зачем для ББ, но МК? Программа память не экономит. Несколько подпрограмм и так разберуться  какие переменные используются, а если про волатильные вспомнить - всё равно приходится глобальными объявлять. На хороший тон не ссылаться. Есть ли какие ни будь другие преимущества? В циклах можно областью видимости обойтись. 

nibelung
Offline
Зарегистрирован: 21.04.2021

wdrakula пишет:

nibelung пишет:

И еще

1void loop() {
2  static uint8_t clk1, clk2;

Это, все таки, объявление глобальных переменных с областью видимости, ограниченной, функцией Loop. Их желательно явно инициализировать.

а тут ты неправ... ;))) хороший тон, но необязательно. Ну и слово "глобальные" совершенно не к месту и не в тему.

Дык я и написал "желательно", а не "обязательно". Именно хороший тон.

По поводу слова "глобальный" спорить не буду.

staticheskie-lokalnye-peremennye

"Когда static применяется к локальной переменной, это приводит к тому, что компилятор создает долговременную область для хранения переменной почти таким же способом, как это делается для глобальной переменной. Ключевое различие между статической локальной и глобальной переменными заключается в том, что статическая локальная переменная остается известной только в том блоке, в котором она была объявлена. Проще говоря, статическая локальная переменная - это локальная переменная, сохраняющая свое значение между вызовами функций."

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

nik182 пишет:

Пожалуйста объясните, зачем объявлять переменные локально для проектов на МК. Я понимаю зачем для ББ, но МК? Программа память не экономит. Несколько подпрограмм и так разберуться  какие переменные используются, а если про волатильные вспомнить - всё равно приходится глобальными объявлять. На хороший тон не ссылаться. Есть ли какие ни будь другие преимущества? В циклах можно областью видимости обойтись. 

Ни за чем, кроме хорошего тона и удобства сопровождения. Ничто так не кричит об "авторе-чайнике", как обилие глобалов. Даже сам, через (для меня) два-три месяца, уже не помнишь, что  и для чего заведено. Объявления статиков там, где они используются, дает возможность вспомнить подробности. Это не говоря про совместную разработку. Тут даже комментировать нечего.

Короче так: если в программе много глобальных переменных - лучше не платить такому автору вообще! ;))) Ну я бы не стал и клиентам бы не посоветовал! ;))

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

nibelung пишет:

"Когда static применяется к локальной переменной, это приводит к тому, что компилятор создает долговременную область для хранения переменной почти таким же способом, как это делается для глобальной переменной. Ключевое различие между статической локальной и глобальной переменными заключается в том, что статическая локальная переменная остается известной только в том блоке, в котором она была объявлена. Проще говоря, статическая локальная переменная - это локальная переменная, сохраняющая свое значение между вызовами функций."

Это ты дискуссию со мной предлагаешь? ;)) Очень мило, с твоей стороны, но я, пожалуй, воздержусь. ;))

nibelung
Offline
Зарегистрирован: 21.04.2021

wdrakula пишет:

nibelung пишет:

"Когда static применяется к локальной переменной, это приводит к тому, что компилятор создает долговременную область для хранения переменной почти таким же способом, как это делается для глобальной переменной. Ключевое различие между статической локальной и глобальной переменными заключается в том, что статическая локальная переменная остается известной только в том блоке, в котором она была объявлена. Проще говоря, статическая локальная переменная - это локальная переменная, сохраняющая свое значение между вызовами функций."

Это ты дискуссию со мной предлагаешь? ;)) Очень мило, с твоей стороны, но я, пожалуй, воздержусь. ;))

Завсегда приятно поговорить с умным и образованным человеком ;)) Но нет, я же признал, что слово "глобальные" там не совсем в тему.

b707
Offline
Зарегистрирован: 26.05.2017

wdrakula пишет:

Это ты дискуссию со мной предлагаешь? ;)) Очень мило, с твоей стороны, но я, пожалуй, воздержусь. ;))

какой-то ты, Влад, сегодня, не такой :)  Не заболел? :) не чувствуется привычной бодрости в общении с новичками :)

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

b707 пишет:

wdrakula пишет:

Это ты дискуссию со мной предлагаешь? ;)) Очень мило, с твоей стороны, но я, пожалуй, воздержусь. ;))

какой-то ты, Влад, сегодня, не такой :)  Не заболел? :) не чувствуется привычной бодрости в общении с новичками :)

последствия  Короны сказываются и, как показала практика у каждого они свои ...

таки и не понял почему всё таки не?:
 

1static bool led_state = 0;

 

nibelung
Offline
Зарегистрирован: 21.04.2021

ua6em пишет:

таки и не понял почему всё таки не?:

 

1static bool led_state = 0;

 

Да можно и так. Ошибкой не будет использование любого варианта. Так что, это из разряда личных предпочтений.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

nibelung пишет:

ua6em пишет:

таки и не понял почему всё таки не?:

 

1static bool led_state = 0;

 

Да можно и так. Ошибкой не будет использование любого варианта. Так что, это из разряда личных предпочтений.

я бы не был столь категоричным, если тип переменной bool, то это даёт экономию памяти программ 2 байта и памяти ОЗУ байт... если применять не битовую математику для изменения значения переменной...точнее  знающие подскажут

 

nibelung
Offline
Зарегистрирован: 21.04.2021

ua6em пишет:

nibelung пишет:

ua6em пишет:

таки и не понял почему всё таки не?:

 

1static bool led_state = 0;

 

Да можно и так. Ошибкой не будет использование любого варианта. Так что, это из разряда личных предпочтений.

я бы не был столь категоричным, если тип переменной bool, то это даёт экономию памяти программ 2 байта и памяти ОЗУ байт... если применять не битовую математику для изменения значения переменной...точнее  знающие подскажут

 

Я бы с вами согласился, если бы тип int менялся на bool. Но, в данном случае, меняется uint8_t на bool. Оба типа размерностью в один байт, так что экономии не будет.

Jaeger
Jaeger аватар
Offline
Зарегистрирован: 23.03.2018

   Если рассматривать данную функцию с точки зрения практического применения, то очевидно, что для нормальной работы она требует стабильного короткого цикла и вызов ее в основном лупе не всегда приведет к корректной её работе. Например в блинке с делеями она работать не будет. Выход - разместить функцию в прерывании таймера, например вариант в TMR0: 

01#define LED_IN  PB5  //LED_BUILTIN
02 
03void setup() {
04  cli();                  //stop interrupts
05  OCR0A = 0;
06  TIMSK0 |= _BV(OCIE0A);  //Разрешить прерывание Timer0 по совпадению
07  sei();                  //allow interrupts
08  DDRB |= _BV(LED_IN);    // вывод на выход
09 }
10 
11void loop() {
12  
13 }
14 //************************InterruptTMR0****************************
15ISR(TIMER0_COMPA_vect) {
16 
17#define INTERVAL1 23
18#define INTERVAL2 24
19static uint8_t  clk1 = 0,
20                clk2 = 0,
21                now  = 0,
22                led_state = 0;
23 
24  if ((uint8_t)(++now - clk1) > INTERVAL1)
25  {
26    clk1 += INTERVAL1;
27    led_state ^= 1;
28  }
29 
30  if ((uint8_t)(now - clk2) > INTERVAL2)
31  {
32    clk2 += INTERVAL2;
33    led_state ^= 1;
34  }
35  //digitalWrite(LED, led_state);
36  (led_state)? (PORTB |= _BV(LED_IN)): (PORTB &= ~_BV(LED_IN));
37   
38 }