Как моргать светодиодами без delay()?

107
15 марта 2022, 18:30

Есть 4 светодиода. Мне надо чтобы 1 светодиод горел 8 секунд, а остальные 3 по 500 миллисекунд. Как это сделать? Код:

byte r1 = 2;
byte y1 = 3;
byte b1 = 4;
byte r2 = 5;
void setup() {
  pinMode(r1, OUTPUT);
  pinMode(y1, OUTPUT);
  pinMode(b1, OUTPUT);
  pinMode(r2, OUTPUT);
}
void Svet1()
{
  digitalWrite(r2, LOW);
  digitalWrite(r1, HIGH);
}
void Svet2()
{
  digitalWrite(r1, LOW);
  digitalWrite(y1, HIGH);
}
void Svet3()
{
  digitalWrite(y1, LOW);
  digitalWrite(b1, HIGH);
}
void Svet4()
{
  digitalWrite(b1, LOW);
  digitalWrite(r2, HIGH);
}
void loop() {
}
Answer 1

Вот часть библиотеки, использующей сторожевой таймер для этой цели

#include <avr/io.h> 
#include <avr/interrupt.h>

volatile unsigned long int cikle;

    class Interval{
        unsigned long int temp;
        bool f1;
        public:
        bool interval(unsigned int time,  void (*func)(),bool f=1); //выполнение функции через определённые интервалы времени (мс). должна находиться в цикле
    };
    void delay(unsigned long int time);     //создание задержки (мс)
    void wBegin();                          //инициализация сторожевого таймера
    unsigned long int getCicle();           //возвращает время(кратное 16) в миллисекундах с начала запуска программы 

//################################################
    ISR(WDT_vect)
        {
        cikle+=16;
        }
        unsigned long int getCicle(){
        return cikle;} 
    void wBegin(){
                WDTCSR |= 1 << WDCE;
                WDTCSR |= 0b01000000; // 1 переполнение -- 16 мс
        sei();
        }
    void delay(unsigned long int time){
        unsigned long int t=getCicle();
        while(getCicle()-t<(time));
        return;
        }

bool Interval::interval(unsigned int time, void (*func)(),bool f) {
    if (f) {
        if(f1){
            f1 = 0;
            temp = getCicle();
            func();
            return 1;
        }
        else {
            if (getCicle() - temp >= time)f1 = 1;
            return 0;
        }   
    }
    return 0;
}

Если вставить её в начало или вынести в отдельную библиотеку , то дальше можно сделать так

//тут вставить верхний код
    byte r1 = 2;
    byte y1 = 3;
    byte b1 = 4;
    byte r2 = 5;
    boolean L1 = 0;
    boolean L2 = 0;
    boolean L3 = 0;
    boolean L4 = 0;
    void Svet1();
    void Svet2();
    void Svet3();
    void Svet4();
Interval Led1, Led2, Led3, Led4;
    void setup() {
      pinMode(r1, OUTPUT);
      pinMode(y1, OUTPUT);
      pinMode(b1, OUTPUT);
      pinMode(r2, OUTPUT);
      wBegin();
    }
    void loop() {
    Led1.interval(8000,Svet1,1);
    Led1.interval(500,Svet2,1);
    Led1.interval(500,Svet3,1);
    Led1.interval(500,Svet4,1);
    }
void Svet1()
    {
      if(L1)  digitalWrite(r1, HIGH);
      else    digitalWrite(r1, LOW);
    }
    void Svet2()
    {
      if(L2)  digitalWrite(r2, HIGH);
      else    digitalWrite(r2, LOW);
    }
    void Svet3()
    {
      if(L3)  digitalWrite(r3, HIGH);
      else    digitalWrite(r3, LOW);
    }
    void Svet4()
    {
      if(L4)  digitalWrite(r4, HIGH);
      else    digitalWrite(r4, LOW);
    }
Answer 2

Я бы сделал так: создал структуру с двумя полями. Первое: описание состояния светодиодов (горит/не горит) второе: длительность работы этого состояния. Объединил все состояния в массив. В обработчике таймера сделал счетчик, который сравнивал с длительностью текущего состояния. Если меньше - выходим из обработчика, увеличив счетчик. Если равно (или больше) - счетчик в ноль, переходим к следующему состоянию, зажигаем светодиоды так, как записано в структуре. Ну, и, конечно, нужна переменная статик с номером текущего состояния. Вот набросок кода:

struct SD {         // Структура, описывающая состояние светодоидов.
    bool sd1;
    bool sd2;
    bool sd3;
    bool sd4
}
struct States {     // Состояние сисетмы и длительность состояния.
    SD state;
    int time;
}
State[5] stm;       // Набор сосятояний.

interrupt Timer1 {
static int curr_state = 0;      // Текущее состояние
static unsigned int count;      // время с начала состояния
    if (count >= stm[curr_state]) {
        curr_state = (curr_state >=4) ? 0 : (++curr_state);
        count = 0;
        // Здесь выполняем установку нового состояния диодов
    }
    else ++count;
}
Answer 3

Когда-то давно вендингом занимался, тоже надо было написать легковестную библиотеку которая бы не блокировала основной поток Delay'ями

https://github.com/latdev/eugenetaskstool

Вот пример использования

#include <ectask.h>
TasksTool timelib;
void Once30sec() {
  Serial.println("This will run once 30 seconds from Arduino starts");
  timelib.once(1000, ThisWillRunOnceAfter30SecondOnce);
}
void Every15sec() {
  Serial.println("This will runs every 15 seconds");
}
void Every40sec() {
  Serial.println("This will runs every 40 seconds");
  timelib.once(1000, ThisWillRunNotOnceAfter40SecondOnce);
}
void ThisWillRunNotOnceAfter40SecondOnce() {
  Serial.println("One second after 40 passed");
}
void ThisWillRunOnceAfter30SecondOnce() {
  Serial.println("One second after 30 passed");
}
void setup() {
  Serial.begin(9600);
  timelib.once(30000, Once30sec);
  timelib.every(15000, Every15sec);
  timelib.every(40000, Every40sec);
}
void loop() {
  timelib.loop(); // This is important part of timers
}
READ ALSO
Как в массиве найти некое количество наибольший или наименьших значений

Как в массиве найти некое количество наибольший или наименьших значений

Как найти и вывести на экран, например, три максимальных или минимальных элемента массива, на языке программирования "Си"? Например массив,

104
#1111 - Invalid use of group function

#1111 - Invalid use of group function

Пытаюсь выполнить запросЗапрос должен полю users

91
Стек для web разработки на java

Стек для web разработки на java

Посоветуйте какой стек сейчас популярен для web разработки на java, и с чего лучше начать учить

133