Помигаем светодиодом. Опять!

Старик Похабыч

★★★★★★★
14 Авг 2019
3,792
1,146
Москва
Тема избитая и повторять то, что было сказано уже 100500 раз до меня я не буду. Поэтому сразу "КОД в студию!":

Ссылка для обязательного ознакомления https://alexgyver.ru/lessons/led-crt/

C++:
#define LED_1 9
#define LED_2 10
#define TMD 5 // задержка между шагами
void setup() {
  pinMode(LED_1, OUTPUT);
  pinMode(LED_2, OUTPUT);

}
uint8_t step = 0;
uint32_t tmr = 0;
void loop() {
  if (millis() - tmr > TMD)
  {
    tmr = millis();
    analogWrite(LED_1, step);
    analogWrite(LED_2, step + 128);
    step++;
  }
}
Этот простой код будет ПЛАВНО зажигать 2 светодиода из выключеннго состояния до максимума не задерживая выполнения основного кода. Из хитрожопости тут использование такой особенности языка Си, как переполнение переменной. После того, как переменная шаг дойдет до своего максимума - 255, следующим числом будет 0 и все повториться заново. Надеюсь тут всем понятно, что для изменения яркости используются порты ардуины с ШИМ, задержка между шагами описана 3-ей строкой. Ну и диоди как бы зажигаются поочередно.
Хорошо, но мало, хотя для какой то визуализации деятельности пойдет.
Хотелось бы что бы диод не только загорался , то и гас плавно. Можно пойти разными путями, я решил изменить тип данных для шага и ввести второй шаг для 2-го светодиод.
Теперь и гаснет и тухнет.. тьфу, зажигается плавно.
C++:
#define LED_1 9
#define LED_2 10
#define TMD 5 // задержка между шанами
void setup() {
  pinMode(LED_1, OUTPUT);
  pinMode(LED_2, OUTPUT);

}
uint16_t step = 0;
uint16_t step2 = 256;
uint32_t tmr = 0;
void loop() {
  if (millis() - tmr > TMD)
  {
    tmr = millis();
    if (step<256) analogWrite(LED_1, step);
    else analogWrite(LED_1, 511-step);

    if (step2<256) analogWrite(LED_2, step2);
    else analogWrite(LED_2, 511-step2);


    step++;
    if (step==512) step=0;
    step2++;
    if (step2==512) step2=0;
  }
}
Далее можно разделить функции , ввести для каждого свою задержку и свой таймер. Вот так:
C++:
#define LED_1 9
#define LED_2 10
#define TMD 5 // задержка между шанами
#define TMD2 10 // задержка между шанами
void setup() {
  pinMode(LED_1, OUTPUT);
  pinMode(LED_2, OUTPUT);

}
uint16_t step = 0;
uint16_t step2 = 256;
uint32_t tmr = 0;
uint32_t tmr2 = 0;
void loop() {
  if (millis() - tmr > TMD)
  {
    tmr = millis();
    if (step<256) analogWrite(LED_1, step);
    else analogWrite(LED_1, 511-step); 
    step++;
    if (step==512) step=0;
  }

  if (millis() - tmr2 > TMD2)
  {
    tmr2= millis();
    if (step2<256) analogWrite(LED_2, step2);
    else analogWrite(LED_2, 511-step2);
    step2++;
    if (step2==512) step2=0;
  }
}
Результат намного интереснее. Прям машина времени из малобюджетного фильма.

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

Для того , что бы описать режим работы воспользуемся такой удобной штукой как массив
uint8_t time_delay[] = {0, 2, 4, 1, 2};
В данном массиве будет храниться время каждого этапа в целых секундах. Перевод в миллисекунды, в не целые секунды можете делать сами.
Что представляет собой каждый элемент массива ? 0- общее время цикла. Будет рассчитываться один раз в setup . 2 - время выключенного состояния, 4 время плавного включения, 1 время максимального горения, 2 время выключения.
Массив потому что он очень удобен в использовании . Для упрощения понимания кода я пока оставил только один светодиод.

C++:
#define LED_1 9

// временные интревалы на каждый этам. 0 - общее время, будет считаться отдельно. 2 - время выключенного состояния. 5 время включения. 3 время максимального горения, 1 вреям затухания.
uint8_t time_delay[] = {0, 2, 4, 1, 2};
void setup() {
  pinMode(LED_1, OUTPUT);
  Serial.begin(115200);

  for (uint8_t i = 1; i < 5; i++) time_delay[0] = time_delay[0] + time_delay[i];
}

void loop() {
  uint32_t vrem = millis() % (1000 * time_delay[0]); // вычисление времени, по которому будет рассчитан этап

  uint8_t n = 0;
  uint8_t s = 0;
  for (int i = 1; i < 5; i++)
  {
    n = i;
    s = s + time_delay[i];
    if (vrem / 1000 < s)break;
  } // после выхода мы будем иметь в n номер этапа (1-4) в s будет сумма времен от начала до конца этапа.
  //Serial.print(1000 * time_delay[0]); Serial.print(" "); Serial.print(vrem); Serial.print(" "); Serial.print(s); Serial.print(" "); Serial.println(n); // этот вывод что бы посмотреть что получается

  switch  (n)
  {
    case 1:
      {
        digitalWrite(LED_1, LOW);  
      }
      break;
    case 2:
      {  
        uint32_t l = 1000 * (s - time_delay[n]);  
        analogWrite(LED_1, map(vrem, l , s * 1000, 0, 255));
      }
      break;
    case 3:
      {
        digitalWrite(LED_1, HIGH);  
      }
      break;
    case 4:
      {
        uint16_t l = 1000 * (s - time_delay[n]);
        analogWrite(LED_1, map(vrem, l , s * 1000, 255, 0));  
      }
      break;
  }
}

Что мы добились таким кодом ? Легкого и понятного редактирования в самом начале , в массиве. Выполнение без задержек.
Что тут плохо : очень частое выполнение этого самого кода. Я бы сказал избыточно частое. Если в предыдущих примерах цикл loop крутился более 100 000 раз в секунду, то в данном примере он максимум крутиться 12 000 раз, а минимум ближе к 7 000. Есть несколько вариантов оптимизации, 1) сделать изменение освещенности не более 30 раз в секунду. 2) не вызывать запись в порты, если значение не менялось.
Код с ограничением в 30 обновлений в секунду, по 1-ому варианту, позволяет "крутить " loop более 150 000 раз в секунду.
C++:
#define LED_1 9

// временные интревалы на каждый этам. 0 - общее время, будет считаться отдельно. 2 - время выключенного состояния. 5 время включения. 3 время максимального горения, 1 вреям затухания.
uint8_t time_delay[] = {0, 2, 4, 1, 2};
void setup() {
  pinMode(LED_1, OUTPUT);
  Serial.begin(115200);

  for (uint8_t i = 1; i < 5; i++) time_delay[0] = time_delay[0] + time_delay[i];
}

uint32_t tmr = millis();

void loop() {
  ShowFPS();

  if (millis() - tmr < 33) return;
  tmr = millis();

  uint32_t vrem = millis() % (1000 * time_delay[0]); // вычисление времени, по которому будет рассчитан этап

  uint8_t n = 0;
  uint8_t s = 0;
  for (int i = 1; i < 5; i++)
  {
    n = i;
    s = s + time_delay[i];
    if (vrem / 1000 < s)break;
  } // после выхода мы будем иметь в n номер этапа (1-4) в s будет сумма времен от начала до конца этапа.
  //Serial.print(1000 * time_delay[0]); Serial.print(" "); Serial.print(vrem); Serial.print(" "); Serial.print(s); Serial.print(" "); Serial.println(n); // этот вывод что бы посмотреть что получается

  switch  (n)
  {
    case 1:
      {
        digitalWrite(LED_1, LOW);
      }
      break;
    case 2:
      {
        uint32_t l = 1000 * (s - time_delay[n]);
        analogWrite(LED_1, map(vrem, l , s * 1000, 0, 255));
      }
      break;
    case 3:
      {
        digitalWrite(LED_1, HIGH);
      }
      break;
    case 4:
      {
        uint16_t l = 1000 * (s - time_delay[n]);
        analogWrite(LED_1, map(vrem, l , s * 1000, 255, 0));
      }
      break;
  }
}

void ShowFPS()
{
  static uint32_t tm_m = 0;
  static uint32_t cnt_m = 0;
  cnt_m++;
  if ((millis() - tm_m) > 1000)
  {
    Serial.print("loop per sec: "); Serial.println(cnt_m);
    cnt_m = 0;
    tm_m = millis();
  }
}

Добавление второго светодиода сначала хотел оформлять отдельно, но подумав решил, что просто покажу как это сделать сразу.
Код практически полностью повторяет предыдущий, но добавлен еще один внешний цикл.
C++:
// временные интревалы на каждый этам. 0 - общее время, будет считаться отдельно. 2 - время выключенного состояния. 5 время включения. 3 время максимального горения, 1 вреям затухания.
uint8_t time_delay[2][5] = {
  {0, 2, 4, 1, 2},
  {0, 1, 1, 1, 1}
};
uint8_t pins[2]={9,10}; // теперь номера пинов храним в массиве!

void setup() {
  Serial.begin(115200);

  for (uint8_t j = 0; j < 2; j++)
    {
    for (uint8_t i = 1; i < 5; i++) time_delay[j][0] = time_delay[j][0] + time_delay[j][i];
    pinMode(pins[j], OUTPUT);

    }
}

uint32_t tmr = millis();

void loop() {
  ShowFPS();

  if (millis() - tmr < 33) return;
  tmr = millis();
  for (uint8_t j = 0; j < 2; j++)
  {
    uint32_t vrem = millis() % (1000 * time_delay[j][0]); // вычисление времени, по которому будет рассчитан этап

    uint8_t n = 0;
    uint8_t s = 0;
    for (int i = 1; i < 5; i++)
    {
      n = i;
      s = s + time_delay[j][ i];
      if (vrem / 1000 < s)break;
    } // после выхода мы будем иметь в n номер этапа (1-4) в s будет сумма времен от начала до конца этапа.
    //Serial.print(1000 * time_delay[0]); Serial.print(" "); Serial.print(vrem); Serial.print(" "); Serial.print(s); Serial.print(" "); Serial.println(n); // этот вывод что бы посмотреть что получается

    switch  (n)
    {
      case 1:
        {
          digitalWrite(pins[j], LOW);
        }
        break;
      case 2:
        {
          uint32_t l = 1000 * (s - time_delay[j][n]);
          analogWrite(pins[j], map(vrem, l , s * 1000, 0, 255));
        }
        break;
      case 3:
        {
          digitalWrite(pins[j], HIGH);
        }
        break;
      case 4:
        {
          uint16_t l = 1000 * (s - time_delay[j][n]);
          analogWrite(pins[j], map(vrem, l , s * 1000, 255, 0));
        }
        break;
    }
  }
}

void ShowFPS()
{
  static uint32_t tm_m = 0;
  static uint32_t cnt_m = 0;
  cnt_m++;
  if ((millis() - tm_m) > 1000)
  {
    Serial.print("loop per sec: "); Serial.println(cnt_m);
    cnt_m = 0;
    tm_m = millis();
  }
}

AelexGyver, один диод плавно зажигается и гаснет:
void setup() {
  pinMode(3, OUTPUT);
}
uint32_t tmr;
int val = 0;
bool dir = true;

void loop() {
  if (millis() - tmr >= 20) {
    tmr = millis();
    val += dir ? (1) : (-1);     // увеличиваем или уменьшаем на шаг
    if (val >= 255) dir = false; // разворачиваем
    if (val <= 0) dir = true; // разворачиваем
    analogWrite(3, val);
  }
}
bort707, два светодиода в разнобой.:
#define LED_1 9
#define LED_2 10
#define TMD 5 // задержка между шанами
void setup() {
  pinMode(LED_1, OUTPUT);
  pinMode(LED_2, OUTPUT);

}
int8_t step = 0;
uint32_t tmr = 0;
void loop() {
  if (millis() - tmr > TMD)
  {
    tmr = millis();
    analogWrite(LED_1, (abs(abs(2*step) -1)) );
    analogWrite(LED_2, (abs(abs(2*(step+128)) -1)));
    step++;
  }
}


Часть очередная. Реализация светодиода в виде класса.
Предварительно советую как следует ознакомиться с соответствующим уроком https://alexgyver.ru/lessons/class/

Начнем как всегда с самого простого.
Будем подключать 1 светодиод к ШИМ выходу радуины. А так же подключим одну кнопку на 3-ий пин (у меня, можно любой другой)
В двух словах класс это переменная определенного, хитрого!, типа, которая содержит в себе не только значениЯ (да, их может быть много) но и функции для работы с этими значениями.
Что мы хотим от светодиода ? Для начала, что бы он был куда то подключен, а так же что бы он мог включаться и выключаться.
Для этого создадим свой класс , а в нем несколько полей и методов :
У меня этот фрагмент назван "c_led.h":
C++:
class class_LED
{
  private:
    uint8_t _l_pin;
  public:
    class_LED(uint8_t l_pin);
    void setOn();
    void setOff();
};

class_LED::class_LED(uint8_t l_pin)
{
  _l_pin = l_pin;
  pinMode(_l_pin, OUTPUT);
}


void class_LED::setOn()
{
    digitalWrite(_l_pin, HIGH);
}
void class_LED::setOff()
{
    digitalWrite(_l_pin, LOW);
}
А это основная программа, которая уже работает с классом:
C++:
#define BTN_PIN 3

#include "c_led.h"

class_LED LED1(9);

void setup() {
  Serial.begin(115200);
  pinMode(BTN_PIN,INPUT_PULLUP);
}

void loop() {
 
  if (!digitalRead(3)) LED1.setOn(); else LED1.setOff();
 
  ShowFPS();
}

void ShowFPS()
{
  static uint32_t tm_m = 0;
  static uint32_t cnt_m = 0;
  cnt_m++;
  if ((millis() - tm_m) > 1000)
  {
    Serial.print("loop per sec: "); Serial.println(cnt_m);
    cnt_m = 0;
    tm_m = millis();
  }
}
И это уже работает. Казалось бы зачем городить такие сложности ? Просто мы жертвуем объемами и временем программирования для дальнейшего удобства работы, уменьшения числа ошибок.
Данный фрагмент будет включать и выключать светодиод по нажатию кнопки. При этом цикл loop будет крутиться в районе 70 000 раз в секунду. А все из за чрезмерных обращений к портам. Что бы уменьшить кол-во обращений добавим в класс еще одно поле , помимо поля пина, Это будет логическое поле, в которому сохраняется текущее состояние светодиода и посмотрим что будет.
C++:
class class_LED
{
  private:
    uint8_t _l_pin;
    bool _state = false;
  public:
    class_LED(uint8_t l_pin);
    void setOn();
    void setOff();
};

class_LED::class_LED(uint8_t l_pin)
{
  _l_pin = l_pin;
  pinMode(_l_pin, OUTPUT);
  _state = digitalRead(_l_pin);
}


void class_LED::setOn()
{
  if (!_state)
  {
    digitalWrite(_l_pin, HIGH);
    _state = true;
  }
}
void class_LED::setOff()
{
  if (_state)
  {
    digitalWrite(_l_pin, LOW);
    _state = false;
  }
}
Заметьте, что тут мы изменили только файл класса, а сам проект не трогали и он все равно работает. Это УДОБНО! В результате мы потратили еще немного памяти, но получили ощутимую прибавку в скорости! Теперь цикл loop крутиться более 107 000 раз в секунду. А было 70. В полтора раза быстрее. При этом мы опрашиваем кнопку с максимально возможной скорость.
Ремарка: можно еще ускорить работу программы прямыми чтениями регистров, но тогда потеряется совместимость между разными видами микропроцессоров, поэтому оставим это дело так. Хотите оптимизации ? Делайте непосредственно у себя.

Пример достаточно синтетический. Теперь давайте добавим постепенное зажигание и включение. Сделаем так, что бы пока кнопка была нажата светодиод плавно увеличивал свою яркость. И при отпускании плавно гас. Код я приведу чуть позже, однако замечу, что при выполнении проверок на допустимость и необходимость изменений он зажигает светодиод чрезвычайно быстро и эффект теряется.

Добавим еще одно поле, которое будет "помнить" интервал изменений светодиода, а так же поле последнего изменения яркости. Попутно я добавлю второй светодиод, работающий в противофазе.
В результате работа выполняется, основная программа выглядит чрезвычайно простой, все "сложности" зашиты в класс. При изменении яркости скорость работы программы снижается практически в 2 раза, но как только яркость меняется на конечную цикл loop набирает 100 000 раз в секунду.
Оба файла (примера и класса) я прикрепляю к посту для дальнейшего изучения.
 

Вложения

Изменено:
  • Лойс +1
Реакции: Divin, Leon111_09 и xof

Nikanor

★★✩✩✩✩✩
1 Окт 2020
181
60
для красивого плавного зажигания-затухания нужно логарифмическую последовательность использовать.
 

bort707

★★★★★★✩
21 Сен 2020
2,500
760
Хотелось бы что бы диод не только загорался , то и гас плавно. Можно пойти разными путями, я решил изменить тип данных для шага и ввести второй шаг для 2-го светодиод.
Теперь и гаснет и тухнет.. тьфу, зажигается плавно.
да ну..... первый код с переполнением был красивым, а второй непонятно что :) - куча лишних операторов :)
Можно сделать плавное зажигание и плавное затухание , тоже основанное на переполнении - если взять для шага знаковый тип int8_t
Тогда step при итерировании будет периодично менятся от -127 до 128. Остается взять от него абсолютное значение и растянуть в диапазон 0..255 - будем иметь периодичную кривую без всех этих хлопот с условиями и ровно с тем же числом строк, как в первом коде:
C++:
#define LED_1 9
#define LED_2 10
#define TMD 5 // задержка между шанами
void setup() {
  pinMode(LED_1, OUTPUT);
  pinMode(LED_2, OUTPUT);

}
int8_t step = 0;
uint32_t tmr = 0;
void loop() {
  if (millis() - tmr > TMD)
  {
    tmr = millis();
    analogWrite(LED_1, (abs(abs(2*step) -1)) );
    analogWrite(LED_2, (abs(abs(2*(step+128)) -1)));
    step++;
  }
}
 

AlexGyver

★★★★★★✩
Команда форума
30 Июл 2018
340
533
Предложу и свой вариант с флагом, который читается и понимается без рюмки горячительного, а также позволяет настроить пределы и шаг изменения
C++:
void setup() {
  pinMode(3, OUTPUT);
}
uint32_t tmr;
int val = 0;
int8_t dir = 1;

void loop() {
  if (millis() - tmr >= 10) {
    tmr = millis();
    val += dir;     // увеличиваем или уменьшаем на шаг
    if (val == 255 || val == 0) dir = -dir;   // разворачиваем
    analogWrite(3, val);
  }
}
 
Изменено:
  • Лойс +1
Реакции: Старик Похабыч

AlexGyver

★★★★★★✩
Команда форума
30 Июл 2018
340
533
для красивого плавного зажигания-затухания нужно логарифмическую последовательность использовать.
Особо умные дяди с форума flprog используют для этого формулу с логарифмом (выполняется вечность, ~300мкс, жрет почти три килобайта за счёт флоат функций), я обычно использую целочисленную параболу
C++:
byte getBrightCRT(byte val) {
  return ((long)val * val + 255) >> 8;
}
Эту функцию используем как прослойку между значением и аналограйтом
C++:
analogWrite(pin, getBrightCRT(val));
Остальные алгоритмы и примеры есть в уроке https://alexgyver.ru/lessons/led-crt/
 
Изменено:
  • Лойс +1
Реакции: kostyamat

Александр Симонов

★★★★✩✩✩
2 Авг 2018
730
209
А если заюзать FreeRTOS, получим и асинхронность работы и человекопонятную императивную запись с дилеями.
 

Старик Похабыч

★★★★★★★
14 Авг 2019
3,792
1,146
Москва
@Nikanor, @bort707, Это код для НАГЛЯДНОСТИ. можно запилить кучу операторов типиа step=(step+1)%512; но их надо объяснять. Тут люди только только ходить учатся. Так что я пытался написать максимально прозрачно.
 

Nikanor

★★✩✩✩✩✩
1 Окт 2020
181
60
чтобы научиться ходить нужно хоть немного правильные книжки почитать)))
 

Старик Похабыч

★★★★★★★
14 Авг 2019
3,792
1,146
Москва
Дополнил 1-ый пост. Так же планирую его и далее дополнять . Если это вообще кому то надо. А то зубры набежали, закидали.. А эта тема вовсе не для них. И не понятно читает ли кто то из новичков это все..
 

bort707

★★★★★★✩
21 Сен 2020
2,500
760
А то зубры набежали, закидали.. А эта тема вовсе не для них. И не понятно читает ли кто то из новичков это все..
ну не обижайся :) Для того, чтобы получилась интересная беседа - нужны собеседники, способные поддержать разговор. Новички на эту роль вряд ли сгодятся. Новички пусть читают и впитывают :)
 

Старик Похабыч

★★★★★★★
14 Авг 2019
3,792
1,146
Москва
Да кто обижается ? Я это чисто ради продолжения разовора.
Меня в своё время от Си оттолкнуло именно все эти хитрожопые записи и преобразования. Ну некому было мне все растолковать, а сам я тогда не справлялся. Поэтому учил паскаль, там все по рабоче-крестьянскому и для определенного этапа это благо. Да , можно использовать разные , даже часто правильные, записи, но для понимания процессов иногда лучше показать длинную запись.

И да, я изначально хотел сделать именно такой вариант с короткой 8-битной переменной, но по какой то причине решил сделать "длинный" способ. Вот теперь бы вспомнить почему. А так.. Надо будет собрать разные варианты в кучу.
 

kDn

★★★★★✩✩
18 Ноя 2019
1,112
439
На всяк случай видео на тему:
Собственно подобным бы образом и я делал. Ну да, без FreeRTOS пришлось бы городить на тикере, но это по-любому был бы класс, который просто выполняет нужную задачу и нет необходимости задумываться что там происходит внутри. Структурный подход решения задачи хоть и проще для чего-то небольшого, но для более-менее нормальных реализаций он становится крайне неудобным. :) . Так что осваивать ООП полезно даже для контроллеров. :)
 

Kostya.I

✩✩✩✩✩✩✩
16 Янв 2022
3
0
Подскажите, как такое мигание светодиодом, можно реализовать без delay?
Т.е. нужно мигать светодиодом два раза в секунду.
Пробовал пример мигания "таймером на millis", думал получится запихнуть один таймер в другой, что б один мигал к примеру каждые 100мс, а снаружи второй запускал, то что мигает каждую секунду... в общем ничего не получилось.
Пытался разобраться как работает режим стробоскоп из проекта палки на RGB лент - не осилил ((

C++:
#define LED_pin 13

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

void loop() {
  for (int i = 0; i < 2; i++)
  {
    digitalWrite(LED_pin, HIGH);
    delay (100);
    digitalWrite(LED_pin, LOW);
    delay (100);
  }
  delay(1000);
}
 

Sergo_ST

★★★★★✩✩
15 Мар 2020
520
456
Примерно так:
C++:
#define LED_pin 13
uint16_t time[] = {1000, 100, 100, 100}; //массив времени (выкл, вкл, выкл, вкл)

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

void loop() {
static uint32_t timer;
static uint8_t sw;

if (millis() > timer) {
    if (++sw >= (sizeof(time) / 2)) sw = 0;
    digitalWrite(LED_pin, (boolean)(sw % 2));
   timer = millis() + time[sw];
  }
}
 
Изменено:
  • Лойс +1
Реакции: Kostya.I

Старик Похабыч

★★★★★★★
14 Авг 2019
3,792
1,146
Москва
Немного другая реализация, но суть та же.
Если в пред. топике задавались интервалы свечения, то у меня задаются моменты времени для смены режима. ну и четностью не стал заморачиваться для большей наглядности:

C++:
#define LED_pin 13

uint16_t rejim[]={100,200,300,1000};

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

void loop() {
  static uint32_t tmr=millis();
  static uint8_t nomer=0;
  if ((millis()-tmr)>rejim[nomer]) nomer++;
  switch (nomer)
  {
    case 0:
    case 2:
      digitalWrite(LED_pin,HIGH);
      break;
    case 1:
    case 3:
      digitalWrite(LED_pin,LOW);
      break;     
    default:
      nomer=0;
      tmr=millis();
  }
}
 
  • Лойс +1
Реакции: Kostya.I

Kostya.I

✩✩✩✩✩✩✩
16 Янв 2022
3
0
О! Спасибо!
Вариант от Sergo_ST почему-то не заработал... ((
А этот (от Старик Похабыч) работает. Осталось разобраться как ))
 

Старик Похабыч

★★★★★★★
14 Авг 2019
3,792
1,146
Москва
На самом деле идея определять включать светодиод или нет по четности - очень правильная, сильно упрощает код. вместо switch ставиться digitalWrite(led,nomer%2) и все.
Но не все же разжевывать, надо до чего то и самому доходит.
 
  • Лойс +1
Реакции: Sergo_ST

Kostya.I

✩✩✩✩✩✩✩
16 Янв 2022
3
0
Sergo_ST - заработало, спасибо)
Да, самому доходить куда приятней ;), но у самого как-то не хватило знаний, но зато пока искал и пробовал варианты узнал что-то новое, но увы пока не спросил напрямую, у меня ничего кроме цикличного мигания не получалось.
Казалось бы, захотелось усложнить базовое мигание, более правильным способом, и с затыком уже пару дней сижу (
 

Старик Похабыч

★★★★★★★
14 Авг 2019
3,792
1,146
Москва
Вот сделал такую модификацию. Казалось бы зачем ?
Объясняю:
Функция ShowFPS() измеряет кол-во сделанных циклов за 1 секунду. Изначально код выполнялся 84 000 раз, после 1-ой модификации стал выполняться 120 000 раз, а это 50% прирост! Дополнительно избавился от лишнего обращения к пину, что дало в + еще 7000 циклов, хоть и 1% .

Скорость выполнения @Sergo_ST 195 000 циклов - еще выше, но не всем будет понятен. Есть тонкости, например чем отличаются ++sw и sw++. Изучайте.

C++:
#define LED_pin 13

uint16_t rejim[]={100,200,300,1000};
uint8_t size_r=sizeof(rejim)/sizeof(*rejim);
void setup() {
  Serial.begin(115200);
  pinMode (LED_pin, OUTPUT);
// что бы сразу было 2 мигания, а не начинать с одного!
  digitalWrite(LED_pin,HIGH); 
}

void loop() {
  ShowFPS();
  static uint32_t tmr=millis();
  static uint8_t nomer=0;
  static uint8_t old_nomer=10;
 
  if ((millis()-tmr)>rejim[nomer])
    {
    digitalWrite(LED_pin,(nomer)%2); 
    nomer++;
    }
 
  if (nomer==size_r)
    {
    nomer=0;
    tmr=millis();
    }

}

void ShowFPS()
{
  static uint32_t tm_m = 0;
  static uint32_t cnt_m = 0;
  cnt_m++;
  if ((millis() - tm_m) > 1000)
  {
    Serial.print("loop per sec: "); Serial.println(cnt_m);
    cnt_m = 0;
    tm_m = millis();
  }
}
 
  • Лойс +1
Реакции: Sergo_ST

poty

★★★★★★✩
19 Фев 2020
2,257
692
Если при вычислении
timer = millis() + time[sw];
произойдёт переполнение, то таймер сработает уже на следующем шаге. Да, эта ситуация редкая, но сам факт...
 

Старик Похабыч

★★★★★★★
14 Авг 2019
3,792
1,146
Москва
Для мигалки светодиодом это не критично конечно, да и скорее всего будет малозаметно, но если что то более серьезное, то да!
 
  • Лойс +1
Реакции: Sergo_ST

Vinchy

✩✩✩✩✩✩✩
21 Янв 2022
2
1
Оформи код соответствующим тэгом
Здорово, парни. Я, насмотревшись Гайвера, на старости лет, тоже решил изучить Ардуино. Уже третий день его ковыряю ))). Задачку с мигающим светодиодом решил так:

boolean Green = 2;
unsigned long timer;
void setup() {
digitalWrite(2, Green);
}
void loop() {
if(millis() - timer > 1000) {
timer = millis();
digitalWrite(2,HIGH);
}
if(millis() - timer > 300) {
digitalWrite(2,LOW);
}
}

Где, 1000 - период,
300 - коэффициент заполнения.
 
  • Лойс +1
Реакции: Старик Похабыч