#1 2020-10-29 10:19:29

UW5EGA
Учасник
Зареєстрований: 2020-10-29
Повідомлень: 11

Потрібна допомога

Добрий день. Малу по малу вивчаю ардуіно і зіткнувся з проблемою. Ось так зараз виглядає мій код, оснований на схрещенні прикладів з мережі. Все працює начебто, але при виконанні затримок втрачається зв'язок з контролером через Delay. Тобто неможливо зупинити виконання циклу кнопкою на вебсторінці. Мені порадили приклад за посиланням, але я не можу його адаптувати під себе, не вистачає кеби зібрати все до купи.
http://arduino.ru/tutorials/BlinkWithoutDelay

#include <SPI.h>
#include <Ethernet.h> 
boolean newInfo = 0;

byte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDA, 0x02 };     
IPAddress ip(192,168,4,70);
byte gateway[] = { 192, 168, 4, 1 };
byte subnet[] = { 255, 255, 255, 0 }; 
EthernetServer server(80);

void setup()
{
  pinMode(8, OUTPUT);
  digitalWrite(8,HIGH);
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.begin(9600);
}

void blinker()
{
  digitalWrite(8, LOW);
  delay(8000);
  digitalWrite(8, HIGH);
  delay(5000);
  digitalWrite(8, LOW);
  delay(8000);
  digitalWrite(8, HIGH);
  delay(10000);
  digitalWrite(8, LOW);
  delay(180000);
  digitalWrite(8, HIGH);
}

void loop()
{
  EthernetClient client = server.available();
  if(client){
  boolean currentLineIsBlank = true;
  while (client.connected()) {
    if (client.available()) {
      char c = client.read();
                                                  
      if(newInfo && c == ' '){
        newInfo = 0;
      }
      
      if(c == '$'){                                 
                                                    
        newInfo = 1;                                
      }
      
                                                     
      if(newInfo == 1){                              
          Serial.println(c);
          if(c == '1'){                              
          Serial.println("ON");
          digitalWrite(8, LOW);
          blinker();
          }
          
          if(c == '2'){                              
          Serial.println("OFF");
          digitalWrite(8, HIGH);                     
          }    
      } 
      
      if (c == '\n') {                              
        currentLineIsBlank = true;                  
      } 
      else if (c != '\r') {
        currentLineIsBlank = false;
      }
    
      if (c == '\n' && currentLineIsBlank) {
        client.println("HTTP/1.1 200 OK");
        client.println("Content-Type: text/html");
        client.println("Connection: close");  
        client.println("Refresh: 30");
        client.println();
        client.println("<!DOCTYPE HTML>");
        client.println("<html>");
        client.print("<title>Alarm</title>");
        client.print("<H1>Block 1</H1>");
        client.print("<a href=\"/$1\"><button>On</button></a>");
        client.print("<a href=\"/$2\"><button>Off</button></a>");
        client.println("<br />");       
        client.println("</html>");
        break;
      }
    
    }
    
  }
  delay(1);
  client.stop();
}
}

Неактивний

#2 2020-10-29 12:55:59

г0cть
Гість

Re: Потрібна допомога

1) Микроконтроллер - это не компьютер. Он выполняет все команды строго в той последовательности, которую Вы ему задаёте в своей программе. Здесь нет операционной системы, которая сама распараллеливает выполняющиеся задачи. Поэтому Вам и предложили разобраться в примере, который показывает, как сделать псевдо-параллельное выполнение разных задач при последовательно выполняющейся программе.
2) Ваша программа - это конечно хорошо, но в Вашем посте нет ни слова о том, что и как она должна делать. Может всё именно так и задумано, как написано? С этой точки зрения в Вашей программе нет никаких ошибок и всё работает именно так, как и запланировано!  wink

#3 2020-10-29 15:23:11

UW5EGA
Учасник
Зареєстрований: 2020-10-29
Повідомлень: 11

Re: Потрібна допомога

Єдина проблема стоїть у неможливості виконання аварийного зупинення, поки не відпрацюють всі затримки. Навіщо там кнопка "OFF" якщо вона все одно не працює? А мені потрібно щоб функціонувало.

Остання редакція UW5EGA (2020-10-29 15:35:46)

Неактивний

#4 2020-10-29 18:31:33

ard125
Учасник
Зареєстрований: 2019-01-30
Повідомлень: 121

Re: Потрібна допомога

Ваш blinker() должен отрабатывать интервалы циклично или однократно?

Неактивний

#5 2020-10-30 10:54:32

UW5EGA
Учасник
Зареєстрований: 2020-10-29
Повідомлень: 11

Re: Потрібна допомога

Однократно. После окончания последовательности должен остановится и повторно запущен только по кнопке "on".

Остання редакція UW5EGA (2020-10-30 10:54:54)

Неактивний

#6 2020-10-30 11:43:42

ard125
Учасник
Зареєстрований: 2019-01-30
Повідомлень: 121

Re: Потрібна допомога

ну так применяете 5 раз (или сколько у вас там интервалов) BlinkWithoutDelay плюс флаги отработки каждого интервала.

Остання редакція ard125 (2020-10-30 11:44:09)

Неактивний

#7 2020-10-30 14:05:14

UW5EGA
Учасник
Зареєстрований: 2020-10-29
Повідомлень: 11

Re: Потрібна допомога

А вы можете показать хотя бы на небольшом примере?

Неактивний

#8 2020-10-30 14:53:02

ard125
Учасник
Зареєстрований: 2019-01-30
Повідомлень: 121

Re: Потрібна допомога

Если в общих чертах ,то вводите дополнительную переменную (флаг), устанавливаете ее в какое-то значение и дальше:
если (флаг разрешен) то if currentmillis-prevmillis>=interval выполняете то что вам нужно

Неактивний

#9 2020-10-30 17:51:26

UW5EGA
Учасник
Зареєстрований: 2020-10-29
Повідомлень: 11

Re: Потрібна допомога

Все равно не понимаю как это все написать. Нужен букварь.

Неактивний

#10 2020-10-30 20:37:32

г0сть
Гість

Re: Потрібна допомога

UW5EGA пише:

Все равно не понимаю как это все написать. Нужен букварь.

Странно, сервер подняли, кнопочки к нему прикрутили, а элементарные if-ы написать не можете?

#11 2020-10-31 11:59:53

ard125
Учасник
Зареєстрований: 2019-01-30
Повідомлень: 121

Re: Потрібна допомога

UW5EGA пише:

Все равно не понимаю как это все написать. Нужен букварь.

if((flag==1)&&(millis-prevmillis>=period) {дальше по тексту}

Неактивний

#12 2020-10-31 12:44:50

Iris
Гість

Re: Потрібна допомога

delay(180000) большая пауза, смотрите, пример BlinkWithoutDelay

#13 2020-11-02 11:28:57

UW5EGA
Учасник
Зареєстрований: 2020-10-29
Повідомлень: 11

Re: Потрібна допомога

Iris пише:

delay(180000) большая пауза, смотрите, пример BlinkWithoutDelay

Смотрел. В самом начале на него ссылка есть.

Неактивний

#14 2020-11-02 11:30:23

UW5EGA
Учасник
Зареєстрований: 2020-10-29
Повідомлень: 11

Re: Потрібна допомога

г0сть пише:
UW5EGA пише:

Все равно не понимаю как это все написать. Нужен букварь.

Странно, сервер подняли, кнопочки к нему прикрутили, а элементарные if-ы написать не можете?

Так это украдено на просторах интернета из разных статей.

Неактивний

#15 2020-11-02 15:49:36

Mishka
Учасник
Зареєстрований: 2019-11-18
Повідомлень: 93

Re: Потрібна допомога

Судя по всему, когда выполняется delay(), весь остальной код просто останавливается и ждет возврата из функции, которая вызвала delay(). Чтобы blinker() работал, как ожидается, вся программа должна быть переписана в виде обработчиков асинхронных прерываний, тогда delay() может быть прерван в любой момент.

Вместо этого предлагается управлять светодиодом, синхронизировав его с часами, которые идут независимо от delay(). Таким образом каждый раз loop() будет иметь возможность оценить значение таймера и принять решение, как переключить светодиод. Например, если таймер меньше значения X, то светодиод зажечь. Если больше - погасить. Подробнее:

https://www.arduino.cc/en/Tutorial/Buil … thoutDelay

Для воспроизведения более сложной последовательности можно запомнить время начала этой последовательности, а затем зажигать или гасить светодиод по прошествии определенного времени относительно начала. При этом сам код переключения светодиода должен выполняться при каждом цикле loop():

#define BLINKER_NOTIME -1

void()
{
    unsigned long currentms = millis();
    long long blinkerstartms;

    // ... some blinker related event happened ...

    switch (event) {
    case BLINKER_ON_EVT:
        // engage the blinker()
        blinkerstartms = currentms;
        break;

    case BLINKER_OFF_EVT:
        blinkerstartms = BLINKER_NOTIME;
        break;

    default:
        // nothing to do
    }

    if (blinkerstartms != BLINKER_NOTIME)
        blinkerstartms = blinker(blinkerstartms, currentms);
}

long long
blinker(unsigned long startms, currentms)
{
    // defined as offsets cumulative 0 + 8000 + 5000 + 8000 + 10000 + 18000
    unsigned int blinkms[] = {0, 8000, 13000, 21000, 31000, 49000};

    if (startms < 0)
        return BLINKER_NOTIME;

    // invert the blinker every time it reaches the next blinkms value
    for (i = 0; i < sizeof(blinkms)/sizeof(blinkms[0]); i++) {
        // TODO: handle the timer overflows
        if (blinkms[i] >= startms - currentms) {
            digitalWrite(LED_ADDR, i % 2 ? LOW : HIGH);
            return startms;
    }

    // we're done with the blinkms[] array - shut the blinker down
    return BLINKER_NOTIME;
}

Извините, никогда не писал для Ардуино, но идею, надеюсь, передать удалось.

Остання редакція Mishka (2020-11-02 15:54:04)

Неактивний

#16 2020-11-04 01:46:30

ard125
Учасник
Зареєстрований: 2019-01-30
Повідомлень: 121

Re: Потрібна допомога

пробуйте так

#include <SPI.h>
#include <Ethernet.h>
boolean newInfo = 0;

byte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDA, 0x02 };
IPAddress ip(192, 168, 4, 70);
byte gateway[] = { 192, 168, 4, 1 };
byte subnet[] = { 255, 255, 255, 0 };
EthernetServer server(80);

unsigned long previousMillis = 0;
unsigned long currentMillis;
boolean flag1, flag2, flag3, flag4, flag5;
bool state = false;
bool ledstate;
unsigned long t1 = 8000;
unsigned long t2 = 5000;
unsigned long t3 = 10000;
unsigned long t4 = 18000;

void setup()
{
  pinMode(8, OUTPUT);
  digitalWrite(8, HIGH);
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.begin(9600);
}

void blinker() {
  ledstate=digitalRead(8);
  if (!flag1 && (millis() - previousMillis >= t1)) {
    digitalWrite(8, !ledstate);
    flag1 = 1;
    flag2 = 0;
    previousMillis = millis();
  }

  if (!flag2 && (millis() - previousMillis >= t2)) {
    digitalWrite(8, !ledstate);
    flag2 = 1;
    flag3 = 0;
    previousMillis = millis();
  }

  if (!flag3 && (millis() - previousMillis >= t1)) {
    digitalWrite(8, !ledstate);
    flag3 = 1;
    flag4 = 0;
    previousMillis = millis();
  }

  if (!flag4 && (millis() - previousMillis >= t3)) {
    digitalWrite(8, !ledstate);
    flag4 = 1;
    flag5 = 0;
    previousMillis = millis();
  }

  if (!flag5 && (millis() - previousMillis >= t4)) {
    digitalWrite(8, !ledstate);
    flag5 = 1;
    previousMillis = millis();
  }
}


void loop()
{
  state = digitalRead(8);
  EthernetClient client = server.available();
  if (client) {
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();

        if (newInfo && c == ' ') {
          newInfo = 0;
        }

        if (c == '$') {

          newInfo = 1;
        }


        if (newInfo == 1) {
          Serial.println(c);
          if (c == '1') {
            state = true;
            flag1 = 0;
            digitalWrite(8, LOW);
            previousMillis = millis();
            Serial.println("ON");
            }

          if (c == '2') {
            Serial.println("OFF");
            digitalWrite(8, HIGH);
            state = false;
          }
        }
        
if (state == true) {
       blinker();
  }

if (!state) {
    flag1 = 1;
    flag2 = 1;
    flag3 = 1;
    flag4 = 1;
    flag5 = 1;
  }  

        if (c == '\n') {
          currentLineIsBlank = true;
        }
        else if (c != '\r') {
          currentLineIsBlank = false;
        }

        if (c == '\n' && currentLineIsBlank) {
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");
          client.println("Refresh: 30");
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");
          client.print("<title>Alarm</title>");
          client.print("<H1>Block 1</H1>");
          client.print("<a href=\"/$1\"><button>On</button></a>");
          client.print("<a href=\"/$2\"><button>Off</button></a>");
          client.println("<br />");
          client.println("</html>");
          break;
        }

      }

    }
    delay(1);
    client.stop();
  }
}

Неактивний

#17 2020-11-10 10:45:25

UW5EGA
Учасник
Зареєстрований: 2020-10-29
Повідомлень: 11

Re: Потрібна допомога

ard125 пише:

пробуйте так

С ума сойти, вы проделали такую титаническую работу. Но к сожалению задержки не работают, реле включается и выключается без задержек.

Неактивний

#18 2020-11-10 10:46:39

UW5EGA
Учасник
Зареєстрований: 2020-10-29
Повідомлень: 11

Re: Потрібна допомога

Mishka пише:

Судя по всему, когда выполняется delay(), весь остальной код просто останавливается и ждет возврата из функции, которая вызвала delay(). Чтобы blinker() работал, как ожидается, вся программа должна быть переписана в виде обработчиков асинхронных прерываний, тогда delay() может быть прерван в любой момент.

Вместо этого предлагается управлять светодиодом, синхронизировав его с часами, которые идут независимо от delay(). Таким образом каждый раз loop() будет иметь возможность оценить значение таймера и принять решение, как переключить светодиод. Например, если таймер меньше значения X, то светодиод зажечь. Если больше - погасить. Подробнее:

https://www.arduino.cc/en/Tutorial/Buil … thoutDelay

Для воспроизведения более сложной последовательности можно запомнить время начала этой последовательности, а затем зажигать или гасить светодиод по прошествии определенного времени относительно начала. При этом сам код переключения светодиода должен выполняться при каждом цикле loop():
Извините, никогда не писал для Ардуино, но идею, надеюсь, передать удалось.

Я много чего понимаю, но написать сом не в состоянии.

Неактивний

#19 2020-11-10 11:27:09

ard125
Учасник
Зареєстрований: 2019-01-30
Повідомлень: 121

Re: Потрібна допомога

UW5EGA пише:
ard125 пише:

пробуйте так

Но к сожалению задержки не работают, реле включается и выключается без задержек.

У меня нет пока eternet-модуля, поэтому проверить полностью код не могу, возможно где-то есть ошибка. Но от обычной кнопки в простеньком коде у меня все работает.

unsigned long previousMillis = 0;
unsigned long currentMillis;
boolean flag1, flag2, flag3, flag4, flag5;

bool flag_btn1, flag_btn2 = false;

bool state = false;
bool ledstate;
unsigned long t1 = 8000;
unsigned long t2 = 5000;
unsigned long t3 = 10000;
unsigned long t4 = 18000;

void setup() {
  pinMode(5, INPUT_PULLUP);
  pinMode(8, OUTPUT);
  digitalWrite(8, HIGH);
  Serial.begin(9600);
}


void blinker() {
   
  ledstate = digitalRead(8);

  if (!flag1 && (millis() - previousMillis >= t1)) {
    digitalWrite(8, !ledstate);
    flag1 = 1;
    flag2 = 0;
    previousMillis = millis();
  }

  if (!flag2 && (millis() - previousMillis >= t2)) {
    digitalWrite(8, !ledstate);
    flag2 = 1;
    flag3 = 0;
    previousMillis = millis();
  }

  if (!flag3 && (millis() - previousMillis >= t1)) {
    digitalWrite(8, !ledstate);
    flag3 = 1;
    flag4 = 0;
    previousMillis = millis();
  }

  if (!flag4 && (millis() - previousMillis >= t3)) {
    digitalWrite(8, !ledstate);
    flag4 = 1;
    flag5 = 0;
    previousMillis = millis();
  }

  if (!flag5 && (millis() - previousMillis >= t4)) {
    digitalWrite(8, !ledstate);
    flag5 = 1; state = false;
    previousMillis = millis(); Serial.println("Stop ");
  }
}


void loop() {

  if (digitalRead(5) == LOW && !flag_btn1) {
    Serial.println("Start "); 
    state = true;
    flag_btn1 = 1;
    flag1 = 0; previousMillis = millis();digitalWrite(8, LOW);
    }

  if (state == true) {
       blinker();
  }

   if (digitalRead(5) && flag_btn1) flag_btn1 = 0;

  if (!state) {
    flag1 = 1;
    flag2 = 1;
    flag3 = 1;
    flag4 = 1;
    flag5 = 1;
  }
}

кнопка подключена к 5 пину. Замыкается на землю.

Остання редакція ard125 (2020-11-10 11:38:06)

Неактивний

#20 2020-11-10 12:03:57

UW5EGA
Учасник
Зареєстрований: 2020-10-29
Повідомлень: 11

Re: Потрібна допомога

Проверил. Да действительно работает.

Неактивний

#21 2020-11-10 12:21:12

ard125
Учасник
Зареєстрований: 2019-01-30
Повідомлень: 121

Re: Потрібна допомога

Возможно, нашел косяк, попробуйте убрать в самом начале loop строку state = digitalRead(8);

Остання редакція ard125 (2020-11-10 12:21:20)

Неактивний

#22 2020-11-10 12:54:16

UW5EGA
Учасник
Зареєстрований: 2020-10-29
Повідомлень: 11

Re: Потрібна допомога

Давайте я вам бесплатно отправлю ethernet shield для опытов?
Очень странно стало вести себя, после включения первая задержка где-то 3 минуты, потом 10 секунд пауза и снова включилось на долго но я уже не стал засекать время.

Неактивний

Швидке повідомлення

Введіть повідомлення і натисніть Надіслати

Підвал форуму