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

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

★★★★★★★
14 Авг 2019
4,220
1,291
Москва
Код рабочий, но плохо тут вот что: в период разницы millis() - timer с 301 по 1000 будет все время выключаться светодиод. а это занимает определенное время, что снижает скорость.
Это легко проверить выводя в монитор порта данные о включении - выключении.
Считывать состояние пина тоже н вариант, т.к. это тоже время.

ЗЫ. Код лучше оформить специальным тегом на верхней панели в сообщении, что бы выглядел как код.
 

Vinchy

✩✩✩✩✩✩✩
21 Янв 2022
2
1
Оформи код соответствующим тэгом
И ещё, может поможет таким же новичкам, как я, самый простой код для тактовой кнопки. Осталось разобраться и оптимизировать дребезг.
boolean led = 2; //Пин светодиода
boolean button = 3; //Пин батона
boolean st = LOW; //Переменная, для запоминания состояния светодиода
void setup() {
pinMode(2, OUTPUT);
pinMode(3, INPUT_PULLUP);
}
void loop() {
if (digitalRead(3) == LOW) { //Опрос батона - если с батона "0" (что в наше случае означает нажатый хлеб, поскольку значение инвертировано)
digitalWrite(2,!st); //То, подать на пин 2 инвертированное значение st
st = !st; //st меняет своё значение на противоположное в следующем цикле
}
}

@Старик Похабыч, в этом и смысл моргания. 1000 - полный период от начало вкл. до начала следующего вкл. , а 300 - это длительность высокого уровня, то бишь время свечения.
 

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

★★★★★★★
14 Авг 2019
4,220
1,291
Москва
1) Эта таем исключительно по светодиодам. Если снесут офтопиковые сообщения - будут правы

2) boolean led = 2; //Пин светодиода
boolean button = 3; //Пин батона
boolean -логическая переменная, она хранит только 0 или 1, т.е. логическое значение, 0- ложь, 1 - истина. Теоретически она может хранить что то еще, та же 2 все равно будет истиной, ибо не 0, но объявлять пины логическими перменными -ошибка.

3) кнопка будет ЛОУ всегда, когда не нажата. значит изменение светодиода будет происходить более 150 000 раз в секунду.
Если смысл был менять значение с каждым нажатием и отпусканием кнопки, то надо отрабатывать такое поведение только 1-ый раз и только после того как кнопка была нажата.


По поводу смысла.
Какой смысл выключать свет в темной комнате ? И делать это всю ночь например ?


3-обновленое!
Посморел, что пин подтянут к +
тогда при все далеть наоборот. При нажатии будет меняться состояние светодиода более 150 000 раз в секунду. Но обрабатывать точно так же. Если кнопка была отпущена, а теперь нажата, то менять состояние светодиода.

Откройте для себя Serial и выводите туда отладочную информацию, так будет проще понять процессы.
 
Изменено:

Kir

★✩✩✩✩✩✩
28 Мар 2020
69
16
Очередная мигалка:
#define UNUSED(arg) (void)arg

template<typename T, size_t CNT>
constexpr size_t COUNT_OF(T(&)[CNT]) { return CNT; }



/*
 * Объект отвечающий за переключение действий.
 * Переключение инициируется после истечении периода
 */
class sequencer {
public:
  /* short typename */
  typedef void(*func_t)(uint32_t mil, uint8_t period, uint8_t pin);

  /* Описатель действия */
  struct action_t {
    uint8_t period;
    func_t  Action;
  };

public:
  void operator()(void) {
    auto m          = millis();
    auto stampDelta = m - timeStamp;
    actionList[iterator].Action(stampDelta, actionList[iterator].period, PIN);
    if ((stampDelta) >= (actionList[iterator].period * 1000UL)) {
      /* переключение на следующее действие */
      iterator = (iterator + 1) % CNT_MAX;
      timeStamp = m; 
    }
  }

  template<uint8_t MAX_CNT>
  sequencer(const action_t (&actionList)[MAX_CNT], uint8_t pin)
    : CNT_MAX(MAX_CNT), PIN(pin), actionList(actionList), iterator(0), timeStamp(0) {
      pinMode(PIN, OUTPUT);
  }

private:
  const uint8_t         CNT_MAX;
  const uint8_t         PIN;
  const action_t* const actionList;
  uint8_t               iterator;
  uint32_t              timeStamp;
};


/*
 * Функции определяющие поведение описываемых ниже действий 
 */
void TurneOff   (uint32_t mil, uint8_t period, uint8_t pin) { UNUSED(mil), UNUSED(period); digitalWrite(pin, LOW);   }
void TurneOn    (uint32_t mil, uint8_t period, uint8_t pin) { UNUSED(mil), UNUSED(period); digitalWrite(pin, HIGH);  }
void SmoothRise (uint32_t mil, uint8_t period, uint8_t pin) { analogWrite(pin, map(mil, 0 , period * 1000, 0, 255)); }
void Fade       (uint32_t mil, uint8_t period, uint8_t pin) { analogWrite(pin, map(mil, 0 , period * 1000, 255, 0)); }


/*
 * Определение списков действий.
 * Списки могут быть абсолютно разные, даже с разным количеством действий,
 * но не менее 1-го
 */
const sequencer::action_t actionListA[] = {
/* period,  Action fuction */
    2,       TurneOff,
    4,       SmoothRise,
    1,       TurneOn,
    2,       Fade
};

const sequencer::action_t actionListB[] = {
   1, TurneOff,
   1, SmoothRise,
   1, TurneOn,
   1, Fade
};



const sequencer::action_t actionListC[] = {
   1, TurneOff,
   1, TurneOn
};



/* Экземпляры мигалок, на базе секвенсора */
sequencer leds[] = {
  sequencer(actionListA, 9),
  sequencer(actionListB, 10),
  sequencer(actionListC, 13),
};


void setup() { }

void loop() {
  for (uint8_t i = 0; i < COUNT_OF(leds); ++i) {
    leds[i]();
  }
}
 
Изменено:

kakmyc

✩✩✩✩✩✩✩
7 Окт 2020
35
8
А я на UNO/NANO(328) вот так мигаю.
Хотя по коду сразу и не ясно что это всего лишь блинк.
C++:
int *x;
void setup(){       
    x=36;
    *x|=32;
    x=35;   
}
void loop(){   
    *x|=32;
    delay(500);
}
 

poty

★★★★★★✩
19 Фев 2020
3,118
917
@kakmyc, тут больше пытались уйти от delay, чем отрабатывали технологию прямого доступа к портам.
Почему только указатель на память объявлен как (int *), регистры-то, вроде, байтовые?
И для читаемости лучше символьные названия адресов в памяти применять, как и названия байтов.
 

poty

★★★★★★✩
19 Фев 2020
3,118
917
@kakmyc, запись
C++:
int *x;
Обозначает, что нужно выделить область памяти для хранения адреса (в данном случае она будет иметь размер 16 бит и не имеет ничего общего со словом int). При обращении по этому адресу рассматривать содержащиеся там данные как переменную типа int.
 

kakmyc

✩✩✩✩✩✩✩
7 Окт 2020
35
8
Ну и какого размера память по твоему нужно было выделить под адрес в микроконтроллере на борту которого 32кб памяти ?
256 байт ?

И почему тогда этот код работает ?
 

poty

★★★★★★✩
19 Фев 2020
3,118
917
@kakmyc, работает потому, что применяется операция |=. Константа 32 превращается в int, в старший байт которого = 0 (0x0020 в 16-ричном формате). Таким образом, несмотря на то, что затронутыми оказываются два регистра, старший не изменяется.
Память, выделяемая под указатель не зависит от типа, на который он указывает. "int" , относится не к указателю, а к тому, на что он указывает. Таким образом, в данном случае, правильнее было бы указать
uint8_t *x;
 

VKN

✩✩✩✩✩✩✩
23 Июл 2023
7
9
Интересная тема! Тем более, что сейчас копаюсь с проектом, где надо устроить рассвет/закат на 2-х каналах светодиодного освещения.
Головное устройство ESP32, там обработка практически всего. И есть пара устройств, которые являются исполнителями задач.
ESP32 Mini - ШИМ куллера (ну, просто под рукой было).
ESP8266 - ШИМ LED подсветки. Теплая и холодная. Пока не добрался до ЛЕД-математики.
r001.png
Но задача у меня такая:
- в заданное время включается "Рассвет", это один из каналов ("холодный") и плавно (в заданном диапазоне (0-30мин)) доводится до максимума и остается на этом уровне до заданного времени выключения, где срабатывает "Закат", что приводит к уменьшению интенсивности освещения в заданном временном интервале 0-30мин. Где 0, это просто вкл/выкл, а 30, это растянутое на 30 минут действие. Так же и со вторым ("теплым" каналом).
Да, сейчас у меня конечно все на начальном этапе и я черпаю вдохновение в подобных темах. Спасибо, за интересный материал!

Ну и до кучи вопрос камрадам: как растянуть выполнение "раскачки" на такое длительное/произвольное время?
 
Изменено:

PiratFox

★★★★★✩✩
13 Фев 2020
1,707
474
как растянуть выполнение "раскачки" на такое длительное/произвольное время?
Так это не сложно. Например, имеем 8-битный ШИМ для управления яркостью. Следовательно, минимальное значение = 0(выключено), максимальное значение будет: 28 - 1 = 255(максимальная яркость). Растягиваем "рассвет" на, допустим, 30 минут. Время удобнее выразить в миллисекундах. Значит, каждые 30 * 60 * 1000 / 255 = 7059 mS инкрементируем второй аргумент(значение ШИМ) функции analogWrite() от нуля и до тех пор, пока он(аргумент) не достигнет максимума(255). С "закатом" аналогично, только делаем декремент от максимального значения до нуля.
 
Изменено:
  • Лойс +1
Реакции: VKN