Выкарыстоўваючы Миллис (), у ўкладзеных цыклаў

Я выкарыстоўваю Миллис() адштабнаваць некалькі агнёў (neopixels) на Arduino Pro Mini. Праблема заключаецца ў тым, што я не магу міргаць агні на патрабаваны перыяд. Больш канкрэтна, агні міргаюць на працягу ~ 250 мс, у той час як я хачу міргаць на працягу 9 секунд! Вось спрошчаная версія таго, што я раблю.

У цыкле (), у мяне ёсць час цыклу (назавем яе контур 1), які павінен працаваць на працягу 250 мс. Ўнутры завесы 1, я выклікаю функцыю ўспышкі (), які павінен працаваць на працягу 9 секунд! Я паклаў іншую пятлю (пятля 2) пасля цыклу 1, які будзе працаваць на працягу 3 секунд.

Вось вялікая карціна ... Я на самой справе хачу радыё, каб прачнуцца на 250 мс. Калі ў гэтым інтэрвале часу ён атрымлівае што-небудзь, ўспышка() будзе называцца, які будзе мігаць святло на працягу 9 секунд. Калі ён нічога не атрымлівае гэта будзе проста пайсці спаць на працягу 3 секунд, а затым вярнуцца ў жывых на працягу 250 мс, гэтак далей і гэтак далей

void loop() { 
    previousMillis = millis();
    while (millis() - previousMillis < awake_interval) {  //awake_interval = 250 ms    
        flash();  //flash for 9 seconds
    }

    previousMillis = millis();
    while (millis() - previousMillis < sleep_interval);  //sleep_interval = 3 secs
}

Функцыя ўспышкі() выглядае наступным чынам,

void flash() {
    unsigned long x = millis();
    while(millis() - x < flash_time){  //flash_time = 9 secs 
        lights_on();
        delay(t1);
        lights_off(); 
        delay(t2); 
    }
}

Я паставіў пятлю 2 там, таму што без яго святло ўспышкі назаўжды. Гэта мае сэнс, таму што ўвесь код у бясконцым цыкле - пустая пятлю ().

Для адладкі, я стаўлю серыйныя адбіткі пасля ўводу завесы. Здаецца, што гняздуюцца дзве завесы (у маім выпадку ўспышкі() усярэдзіне цыклу 1), абодва з якіх выкарыстоўвае Миллис() з'яўляецца крыніцай праблемы. Калі гэта праўда, то як яшчэ я павінен зрабіць гэта? Калі гэта не праблема, любыя ідэі будуць ацэнены.

Edit: The suggestions made by @VE7JRO and @ratchet freak are neat but I was still having problems making my thing work. Turns out it was a problem with one my initializations. I am posting my whole code below (that uses LEDs). I guess I should post the correct code as an answer.

const long sleep_interval = 3000; 
const long awake_interval = 250; 
const int ledPin = 3;

const uint8_t flash_time = 9000;  //bug 
const uint16_t t1 = 5; 
const uint16_t t2 = 495;

void flash() {  
    unsigned long x = millis();
    while(millis() - x < flash_time){ 
        digitalWrite(ledPin, HIGH);
        delay(t1);
        digitalWrite(ledPin, LOW);
        delay(t2);
    }   
}   

void setup() {
    Serial.begin(57600);  
    pinMode(ledPin, OUTPUT);
}

void loop() {
    unsigned long x = millis();
    while(millis() - x < awake_interval){
        Serial.println("flash time!");
        flash();  //overflow will occur    
    }

    unsigned long y = millis();; 
    while (millis() - y < sleep_interval) {  //sleep_interval = 3 secs
        Serial.println("Sleep time!");
    }
}
1
Размесціце поўны код.
дададзена аўтар Hugo, крыніца
ваш 'у той час як (Миллис() - previousMillis
дададзена аўтар Juraj, крыніца
@Juraj Я не разумею, што вы маеце на ўвазе пад «графікам часовай шкалы». І я не магу выкарыстоўваць затрымку, таму што гэта блякаваньне, і гэта не будзе ісці з астатняй часткай (большай) праграмы
дададзена аўтар Demi, крыніца

5 адказы

Выкарыстоўвайце дзяржаўную машыну замест таго, каб:

bool  flashing;
unsigned long lastflashingChange;

void loop() { 
    unsigned long currentMillis = millis;
    if(flashing){
        flash();  //update flash state and change IO pin
        if (lastflashingChange - currentMillis >= awake_interval) {  //awake_interval = 250 ms    
            flahsing = false;
            //turn off the led
            lastflashingChange = currentMillis;
        }
    } else {
        if (lastflashingChange - currentMillis >= sleep_interval) {  //awake_interval = 250 ms    
            flashing = true; 
            //possible initialize flash state
            lastflashingChange = currentMillis;
        }
    }
}

And a similar bit of code inside flash()

bool flashOn;
unsigned long lastFlashLightChange;
void flash() {
    unsigned long x = millis();

    if(flashOn){
        if (lastFlashLightChange - x >= t1) {
            flashOn = false;
            lights_off();
            lastFlashLightChange = currentMillis;
        }
    } else {
        if (lastFlashLightChange - x >= t2) {
            flashOn = true;
            lights_on();
            lastFlashLightChange = currentMillis;
        }
    }

}
1
дададзена
@Tahseen няма, гэта не з'яўляецца неабходным.
дададзена аўтар CTKeane, крыніца
@Tahseen вы можаце выбраць іншыя спосабы змены стану, чым проста час таго, прайшло. Проста зменіце ўмовы ў КРП. Вы таксама можаце мець больш станаў, змяніць лагічнае значэнне для пералічэння і змяніць, калі/іншае да камутатара.
дададзена аўтар CTKeane, крыніца
Гэта выглядае вельмі добра ... збіраюся паспрабаваць. Але лінія previousMillis = Миллис (); ў першым блоку кода не з'яўляецца сапраўды неабходным, дакладна?
дададзена аўтар Demi, крыніца
Гэта разумны, але ён не будзе міргаць святло на працягу 9 секунд, але толькі 250 мс (гэта значыць awake_interval). Вось вялікая карціна ... Я на самой справе хачу радыё, каб прачнуцца на 250 мс. Калі ў гэтым інтэрвале часу ён атрымлівае што-небудзь, ўспышка() будзе называцца, які будзе мігаць святло на працягу 9 секунд. Калі ён нічога не атрымлівае гэта будзе проста пайсці спаць на працягу 3 секунд, а затым вярнуцца ў жывых на працягу 250 мс, гэтак далей і гэтак далей
дададзена аўтар Demi, крыніца

Вось эскіз, каб вы пачалі. Ён не выкарыстоўвае затрымку або якія-небудзь бібліятэкі. У мяне няма ніякіх NeoPixel прылад, так што я выкарыстаў Arduino убудаваны ў LED для мэт тэставання. Проста выдаліце ​​функцыю «myTimer4» і звязаную з імі коду/зменнымі, каб спыніць мігценне святлодыёда. Я не ведаю, які тыпу «радыё» вы карыстаецеся, так што я выкарыстаў знак у занесены паслядоўным маніторы для імітацыі радыёсігналу прымаецца. Ёсць некалькі аператараў паслядоўнай друку на працягу ўсяго кода для мэт тэставання, а таксама.

const unsigned long delayTime = 3000;
const unsigned long delayTime2 = 250;
const unsigned long delayTime3 = 9000;
const unsigned long delayTime4 = 500;
unsigned long previousMillis = 0;
unsigned long previousMillis2 = 0;
unsigned long previousMillis3 = 0;
unsigned long previousMillis4 = 0;
byte checkForData = 0;
byte dataReceived = 0;
byte flashLED = 0;
byte doOnce = 0;

void setup(){
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
}

void loop(){

 //Get current time.
  unsigned long currentMillis = millis();

 //First event.
  if(checkForData == 0){
    if(myTimer1(delayTime, currentMillis) == 1){
      Serial.println("3 second timer done");
      checkForData = 1;
      previousMillis2 = currentMillis;
    }
  }

 //Second event.
  if(checkForData == 1){

   //Your radio code here to check for data.

   //I'm simulating data input from your device using the serial monitor.
    if(Serial.read() > 0){dataReceived = 1;}

    if(myTimer2(delayTime2, currentMillis) == 1){
      Serial.println("250 ms timer done");
      checkForData = 0;
      previousMillis = currentMillis;
      if(dataReceived == 1){
        flashLED = 1;
        previousMillis3 = currentMillis;
        dataReceived = 0;
      }
    }
  }

 //Third event.
  if(flashLED == 1){
    if(doOnce == 0){
      flash(1);
      doOnce = 1;
    }
    if(myTimer3(delayTime3, currentMillis) == 1){
      Serial.println("9 second timer done");
      flashLED = 0;
      flash(0);
      doOnce = 0;
      digitalWrite(LED_BUILTIN, LOW);
    }
  }

 //Fourth event. 
  if(myTimer4(delayTime4, currentMillis) == 1 && flashLED == 1){
    //Serial.println("500 ms timer done");
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
    previousMillis4 = currentMillis;
  }

}

// Function to send data to the NeoPixel device.
void flash(byte startStop){
  if(startStop == 1){Serial.println("flash function started");}
  if(startStop == 0){Serial.println("flash function ended");}  
}

// First event timer.
byte myTimer1(unsigned long delayTime, unsigned long currentMillis){
  if(currentMillis - previousMillis >= delayTime){previousMillis = currentMillis;return 1;}
  else{return 0;}
}

// Second event timer.
byte myTimer2(unsigned long delayTime2, unsigned long currentMillis){
  if(currentMillis - previousMillis2 >= delayTime2){previousMillis2 = currentMillis;return 1;}
  else{return 0;}
}

// Third event timer.
byte myTimer3(unsigned long delayTime3, unsigned long currentMillis){
  if(currentMillis - previousMillis3 >= delayTime3){previousMillis3 = currentMillis;return 1;}
  else{return 0;}
}

// Fourth event timer.
byte myTimer4(unsigned long delayTime4, unsigned long currentMillis){
  if(currentMillis - previousMillis4 >= delayTime4){previousMillis4 = currentMillis;return 1;}
  else{return 0;}
}
1
дададзена
<�Р> індыкатары міргаюць на працягу ~ 250 мс, у той час як я хачу міргаць на працягу 9 секунд!

што логіка не мае сэнсу. Па сутнасці вы хочаце з'есці 2 гадзіны еду на працягу 5 секунд.

код адлюстроўвае такую ​​логіку: калі выкананне выходзіць выбліск (), ён таксама павінен выйсці з цыклу ў той час як завесы ().

так што падумайце, што менавіта вы хочаце зрабіць, запішыце яго, а затым код да яго.

0
дададзена

Я быў няправы занадта ўпэўнена ўвесь мой код. Калі людзі прапанавалі размясціць увесь свой код, я толькі што зрабіў гэта !!!

Ва ўсякім разе, тут памылка, якую я зрабіў. Я ініцыялізуюцца пераменная flash_time як 8-разраднае цэлы лік. Вядома, 8 біт можа ўтрымліваць толькі да 255. Я спрабую захоўваць 9000 !!! Наступны код мае гэтую памылку выправіць.

const long sleep_interval = 3000; 
const long awake_interval = 250; 
const int ledPin = 3;

const uint16_t flash_time = 9000;  //bug fixed by using uint16_t instead of uint8_t
const uint16_t t1 = 5; 
const uint16_t t2 = 495;

void flash() {  
    unsigned long x = millis();
    while(millis() - x < flash_time){ 
        digitalWrite(ledPin, HIGH);
        delay(t1);
        digitalWrite(ledPin, LOW);
        delay(t2);
    }   
}   

void setup() {
    Serial.begin(57600);  
    pinMode(ledPin, OUTPUT);
}

void loop() {
    unsigned long x = millis();
    while(millis() - x < awake_interval){
        Serial.println("flash time!");
        flash();    
    }

    unsigned long y = millis();; 
    while (millis() - y < sleep_interval) {  //sleep_interval = 3 secs
        Serial.println("Sleep time!");
    }
}

Такім чынам, укладзеныя цыклы, якія выкарыстоўваюць Миллис (), каб вызначыць умовы ўзгадняючыя працаваць нармальна, нават калі контур 1 працуе на працягу 250 мс і 2 завесы (г.зн. ўнутры контуру 1) працуе нашмат даўжэй, як 9 секунд.

Прабачэнні, калі я марна занадта шмат часу людзей.

0
дададзена

Ваша логіка няправільная. Пры абнаўленні previousMillis з Millis() значэнне ў першым радку, вы заўсёды адніманнем розніцу ў часе паміж першай і другой радкоў кода (што тое ж самае вы робіце ў пятлю ўнутры ўспышкі ()). Калі тое, што вам трэба, каб атрымаць час, якое прайшло з пачатку праграмы запуску, вам трэба мець фіксаваную зменную для гэтага ў настройках() замест таго, каб абнаўляць яго кожны раз у цыкле ().

Тым не менш, я не разумею, чаму Миллис() неабходна ў вашым выпадку. Выкарыстанне затрымкі() будзе значна прасцей і па-ранейшаму атрымаць працу. прыклад:

void setup() {
delay(250);
}

void loop(){

    for(int i = 0; i < 9; i++){
        digitalWrite(LED, HIGH);
        delay(time);
        digitalWrite(LED, LOW);
        delay(time);

        delay(1000 - 2*time); //Delays the loop exactly one second per iteraction
    }

}
0
дададзена
@Tahseen: Вы напісалі "<�я> я не магу выкарыстоўваць затрымку » і ўсё ж вы выкарыстоўваеце яго ў ўспышка() . Так у чым жа справа?
дададзена аўтар Sprogz, крыніца
Я не магу выкарыстоўваць затрымку, таму што ён блакуе, і гэта не будзе ісці з астатняй часткай (большай) праграмы. Не маглі б вы пашырыць трохі больш на ідэі пакласці фіксаваную зменную ў наладах ()? Мае у той час як завесы спрабуюць вызначыць перыяд часу, каб заставацца ўнутры.
дададзена аўтар Demi, крыніца
Я выкарыстаў яго ўспышкі (), каб мець эфект агнёў ўключэння і выключэнні. Але калі я выкарыстоўваю яго ў сапраўдным цыкле у той час як іншыя рэчы, якія, я спадзяюся ўключыць у будучыні не могуць працаваць. Напрыклад, я хачу выкарыстоўваць радыё, якое будзіць на працягу 250 мс, бачыць, калі ён мае любую каманду, а затым пераходзіць у спячы рэжым на працягу 3 секунд. Калі ён атрымаў каманду ў гэтым інтэрвале 250 мс, то Arduino будзе міргаць святло на працягу 9 секунд
дададзена аўтар Demi, крыніца
Точно ... Я не разумею, што вы маеце на ўвазе "гэта блякаваньне», у чым прычына, вы не можаце выкарыстаць яго?
дададзена аўтар milton, крыніца