Плавное/ступенчатое изменение низкой частоты

blackenning
Offline
Зарегистрирован: 21.01.2021

Доброго времени суток, всем читающим эту тему.

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

   
 if (millis() - timer >= 300) { // Задержка с которой тикает насос
      if (fpstate == LOW) //fp - fuel pump собственно насос
        fpstate = !fpstate;
      else
        fpstate = !fpstate;
      digitalWrite(fp, fpstate);  
      do {
        timer += 300;
        if (timer < 300) break; 
      } while (timer < millis() - 300); 
    }

 

Но я столкнулся с тем, что мне надо временами изменять частоту насоса, по таймеру. При чем делать это несколько раз варьируя частоту от 2х до 6ти герц (по задержке в коде примерно выходит 250мс-70мс).

И так собственно вопрос стоит таким образом - как плавно (или на крайняк ступенчато) изменить частоту пульсов на выходе?

Я пробовал следующим образом, но:

а) Этим получилось только плавно затормозить

б) работает только один раз, если несколько раз вкинуть с разными счетчиками, то работает только один

в) в идеале хотел бы обойтись без delay, но это не принципиально

puls=constrain(puls,0,300); //puls это доп переменная, которой я и собирался урегулировать частоту пульсов
	puls=puls+1;
	delay(20);

	if (millis() - timer >= puls) {
		if (fpstate == HIGH)
			fpstate = !fpstate;
		else
			fpstate = !fpstate;
		digitalWrite(fp, fpstate); 
		do {
			timer += puls;
			if (timer < puls) break;  
		} while (timer < millis() - puls);
	}

Пожалуйста пните куда смотреть, я дальше сам разберусь))

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

У Вас все перепутано. Проверку в 1-й строке надо делать после изменения переменной (строка 2). Кроме того кто Вам мешает вместо puls=puls+1; поставить puls=puls-1;? (кстати в си обычно пишут puls++; или puls--;)

А, в принципе, очень сложно что-то советовать, когда Вы даете кусок программы, в котором, как Вам кажется. проблема. Скорее всего проблема в другом, но я этого не вижу.

Представьте полную программу, а не непонятный огрызок.

OK0
Offline
Зарегистрирован: 06.03.2020
включил
пауза ps мили секунд
выключил
пауза ps мили секунд
изменил значение переменной ps

 

blackenning
Offline
Зарегистрирован: 21.01.2021
// 9 - вентилятор
// 10 - паливний насос
// 11 - водний насос
// 12 - свічка накала
#define PERIOD1 70 //6hz
#define PERIOD2 90 //5.3hz
#define PERIOD3 160 //3.05hz
#define PERIOD4 250 //2hz
uint32_t timer = 0;
uint32_t timer1, timer2;
int fan = 9; // вентилятор
const int fp =  13; // паливний насос
int fpstate = LOW;
int wp = 11;
int ign = 12;
int puls = 300;
int test;
int temp = 0;
void setup() {
	pinMode(fan, OUTPUT);
	pinMode(fp, OUTPUT);
	pinMode(wp, OUTPUT);
	pinMode(ign, OUTPUT);
	for (int i = 0; i <= 70; i++) {
		analogWrite(fan, i);
		delay(30);
	}
	analogWrite(fan, 70);
	delay(10);
}

void loop() {
	puls=puls-1;
	puls=constrain(puls,70,300); 
	delay(20);
	if (millis() - timer >= puls) {
		if (fpstate == HIGH)
			fpstate = !fpstate;
		else
			fpstate = !fpstate;
		digitalWrite(fp, fpstate); 
		do {
			timer += puls;
			if (timer < puls) break;  
		} 
		while (timer < millis() - puls);
	}
	}
	
	

Программа сама по себе не дописана, ибо не могу вот расчехлить с изменением. Попробовал последовать вашему совету и о чудо - одна проблема ушла) но осталось следующее - если я попробую повторить этот же таймер только с другими параметрами, оба считают сразу и мешают друг другу получается.

blackenning
Offline
Зарегистрирован: 21.01.2021

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

// 9 - вентилятор
// 10 - паливний насос
// 11 - водний насос
// 12 - свічка накала
#define PERIOD1 70 //6hz
#define PERIOD2 90 //5.3hz
#define PERIOD3 160 //3.05hz
#define PERIOD4 250 //2hz
uint32_t timer = 0;
uint32_t timer1, timer2;
int fan = 9; // вентилятор
const int fp =  13; // паливний насос
int fpstate = LOW;
int wp = 11;
int ign = 12;
int puls=300;
int test;
int temp = 0;
void setup() {
	pinMode(fan, OUTPUT);
	pinMode(fp, OUTPUT);
	pinMode(wp, OUTPUT);
	pinMode(ign, OUTPUT);
	for (int i = 0; i <= 70; i++) {
		analogWrite(fan, i);
		delay(30);
	}
	analogWrite(fan, 70);
	delay(10);
}

void loop() {
	test=millis();
	for(puls=300; puls>=71 && timer<= 20000; puls){

		puls=puls-1;
		puls=constrain(puls,70,300); 
		delay(20);
		if (millis() - timer >= puls) {
			if (fpstate == HIGH)
				fpstate = !fpstate;
			else
				fpstate = !fpstate;
			digitalWrite(fp, fpstate); 
			do {
				timer += puls;
				if (timer < puls) break;  
			} 
			while (timer < millis() - puls);
		}
		if(puls==71) break;
	}

	for(puls=300; puls>=250 && timer<= 20000; puls){
		puls=puls-1;
		puls=constrain(puls,250,300); 
		delay(20);
		if (millis() - timer >= puls) {
			if (fpstate == HIGH)
				fpstate = !fpstate;
			else
				fpstate = !fpstate;
			digitalWrite(fp, fpstate); 
			do {
				timer += puls;
				if (timer < puls) break;  
			} 
			while (timer < millis() - puls);
		}
		if(timer >= 20000) break;
	}
	if (millis() - timer >= 2000) {
		if (fpstate == HIGH)
			fpstate = !fpstate;
		else
			fpstate = !fpstate;
		digitalWrite(fp, fpstate); 
		do {
			timer += 2000;
			if (timer < 2000) break;  
		} 
		while (timer < millis() - 2000);
	}
}

 

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

blackenning пишет:

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

Вот положа руку на сердце - бред бреднёвый. 68 и 82 строки - это что? delay() в замаскированной форме?

Может Вы сядете и нормальным языком опишите алгоритм, а затем потихонечку переведёте его на си++?

А то херня - с получается.

blackenning
Offline
Зарегистрирован: 21.01.2021

да и пофиг, главное работает)) я с ардуино знаком двое суток, мне не для комерции, а для души поделать всяко-разные вещи. Я вот что по видеоурокам успел ухватить, тем и орудую. Тут понимаете в чем дело то, да я думал использовать дилей, но вот где не читаю, все эту функцию хают на чем свет стоит. Ну и мне нужно будет еще "вписать" в это тело три-четыре дополнительные функции, которые могут не сочетаться с дилеем. 

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

1)  Первая минута - включение водного насоса, продувка вентилятором на 20% от его мощности, с 30й секунды поджиг свечи накала на 100% с выдержкой 10с и затуханием за 20с до 70% (так и останеться вплоть до третей минуты)

2) С 60й секунды дозирующий насос работает на 6гц, 4с, после чего на 2гц, 10с. Также вентилятор вращаеться на 37-40% номинальной мощности. Примерно на 80й секунде будет стабильное горение топлива. Далее нарастает частота до 5.25гц вплоть до выхода на полную нагрузку (примерно 6я минута в зависимости от наружных условий). После 80й секунды вентилятор выходит на 90% мощности и держит ее в режиме полной нагрузки.

3) Переход на частичную нагрузку при достижении температуры 80-85С, при которой вентилятор 65%, насос 3,1гц

4) Защиты по температуре, уровню топлива, охлаждайки тоже должны входить в цикл.

Надеюсь мой текст вас не утомил)

 

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Смело. Зная ардуино два дня :) Застрахуйте гараж и сами застрахуйтесь !

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

blackenning пишет:

да и пофиг

Прочитал. Вот тут и проблема. Вы исходите из неправильных предпосылок. Что вам надо в итоге? - вот оттуда прыгайте, а не от "на 10-й секунде наступил конец этого мира и начался новый".

Например:

1) Включаем циркуляционный насос;

2) Включаем вытяжной вентилятор (нахера?);

3) Включаем свечу зажигания до загорания, которое контролируем???

4) достигаем установленной температуры теплоносителя, останавливаем горение.

 

Теперь понимаем, что предыдущая шняга - это только кусок программы. Ведь в итоге нам нужно получить в гараже конкретную температуру.

Так что:

в сетапе:

включаем циркуляционный насос

включаем вентилятор

в основной программе:

контролируем температуру в помещении и в соответствии с ней регулируем температуру теплоносителя (используя подпрограмму запуска и остановки котла).

В проектах я такую шнягу опубликовал. Чуть доработать под Вашу задачу - и все...

И вообще - Вам что больше нужно - температура в гараже или запуск котла?

 

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

brokly пишет:

Смело. Зная ардуино два дня :) Застрахуйте гараж и сами застрахуйтесь !

Да лыдыть - там на соляре. Это Вам не на газу.

blackenning
Offline
Зарегистрирован: 21.01.2021

Вентилятор не вытяжной, а нагнетающий, в котлах с нагнетанием всегда включается до рабочего цикла и после него, для насыщения кислородом камеры сгорания и выдува паров топлива, если таковые имеются.

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

По достижению температуры, горение не нужно останавливать, его нужно снизить. Это делается для меньшего расхода топлива. Остановка будет более-менее эффективной только, если разброс между уставкой старта и стопа небольшой, но в таком случае будут перепады температуры из-за инертности запуска.

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

А за проект, премного благодарен, правда. Я чуть подучусь и разберу что там и как, ибо с библиотеками я еще не разобрался, сложно))

Я потому все жестко по таймерам решил завязать, взяв за пример работу штатной вебасты, для того, чтобы в итоге понять что нужно подстраивать и как. Ведь автомобильная автономка гоняет меньше охлаждайки, чем если это будет отопление помещения.

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

blackenning пишет:

Вентилятор не вытяжной, а нагнетающий, в котлах с нагнетанием всегда включается до рабочего цикла и после него, для насыщения кислородом камеры сгорания и выдува паров топлива, если таковые имеются.

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

По достижению температуры, горение не нужно останавливать, его нужно снизить. Это делается для меньшего расхода топлива. Остановка будет более-менее эффективной только, если разброс между уставкой старта и стопа небольшой, но в таком случае будут перепады температуры из-за инертности запуска.

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

А за проект, премного благодарен, правда. Я чуть подучусь и разберу что там и как, ибо с библиотеками я еще не разобрался, сложно))

Я потому все жестко по таймерам решил завязать, взяв за пример работу штатной вебасты, для того, чтобы в итоге понять что нужно подстраивать и как. Ведь автомобильная автономка гоняет меньше охлаждайки, чем если это будет отопление помещения.

Понимаете - скорее всего Вы не сможете всего этого реализовать. Но если у Вас достаточно большой объем помещения (3 тыщи кубов и более) и большой объем теплоносителя, то Вам не надо "ловить блох" - работайте на максимуме котла. Достигаете максимума - останавливаете - гистерезис - запускаете. Можно попытаться использовать  подачу топлива в котел (с помощью AnalogWrite()), но не советую. Скорее всего не получится.

blackenning
Offline
Зарегистрирован: 21.01.2021

Итак, забил я на это дело и уехал на работу) но так вышло, что немного в другом месте пришлось делать что-то подобное и за походом я таки допилил код под свои условия.

Теперь только дописать условия защит и убрать лишнее, но в целом все реализовано как я и хотел.




uint32_t timer = 0;
uint32_t timer1 = 0;
uint32_t timer2 = 0;
uint32_t timer3 = 0;
uint32_t timer4 = 0;
uint32_t timer5 = 0;
uint32_t timer6 = 0;
uint32_t timer7 = 0;
int fan = 9; // нагнетательный вентилятор
const int fp =  13;  // топливный насос
int fpstate = LOW;
int wp = 11; // водный насос
int ign = 10; // свеча накаливания
// check, fancheck, igncheck - доп переменные для определенных условий
int test;
int puls; // собственно величина периода пульса для плунжерного насоса
int check;
int check1;
int check2;
int check3;
int check4;
int check5;
int check6;
//----------------------
int fancheck = LOW;
int fancheck1;
int fancheck2;
int fancheck3;
int fancheck4;
int fancheck5;
int fancheck6;
//-----------------
int igncheck = LOW;
int igncheck1 = LOW;
int igncheck2;
int igncheck3;
int igncheck4;

int fanstep1 = 1; // шаг изменения для вентилятора

int ignstep1 = 1; // шаг изменения для свечи 

int temp = 0;
int tmpr;
int PWM = 0;     
int stepsize1 = 1;  // шаг изменения для топливного насоса
int stepsize5 = 10;   
unsigned long currentTime;
unsigned long loopTime;
long previousMillis = 0;
long interval = 1000;  
void setup() {
  pinMode(A3, INPUT);
  pinMode(fan, OUTPUT);
  pinMode(fp, OUTPUT);
  pinMode(wp, OUTPUT);
  pinMode(ign, OUTPUT);
  currentTime = millis();
  loopTime = currentTime; 
  timer = millis();

  if(puls == 0){
    fpstate = LOW;
  }
  puls = 0;

  check = LOW;
  check1 = LOW;
  check2 = LOW;
  check3 = LOW;
  check4 = LOW;
  PWM = 50;
  fancheck = LOW;
  fancheck1 = LOW;
  fancheck2 = LOW;
  fancheck3 = LOW;

}

void loop() {

  analogWrite(9, PWM);
  analogWrite(10, ign);
  timer = millis();
  timer3 = millis();
  timer5 = millis();
  tmpr = analogRead(A3);
  currentTime = millis();

  //--------------------------------------------------------------------------------------

  if(timer3 >= (timer4 + 2000) && fancheck == LOW){  

    PWM = PWM + fanstep1;   
    if ( PWM == 52) {
      fancheck = HIGH;
      fanstep1 = 0 ; 
      fancheck2 = HIGH;
      timer3 = millis();
      timer4 = millis();

    }     
    timer4 = millis();
  }

  if(fancheck2 == HIGH && fancheck == HIGH){
    fanstep1 = 1;
  }
  if(timer3 >= (timer4 + 100) && fancheck2 == HIGH){  

    PWM = PWM + fanstep1;   
    if ( PWM == 104) {
      fanstep1 = 0 ; 
      fancheck3 = HIGH;
      fancheck2 = LOW;

    }     
    timer4 = millis();
  }

  if(fancheck3 == HIGH){
    fanstep1 = 1;
  }

  if(timer3 >= (timer4 + 10000) && fancheck3 == HIGH){  
    PWM = PWM + fanstep1;   
    if ( PWM == 106) {
      fanstep1 = 0 ; 
      fancheck3 = LOW;
      fancheck4 = HIGH;
    }     
    timer4 = millis();
  }
  if(fancheck4 == HIGH){
    fanstep1 = 1;
  }

  if(timer3 >= (timer4 + 140) && fancheck4 == HIGH){  
    PWM = PWM + fanstep1;   
    if ( PWM == 240) {
      fanstep1 = 0 ; 
      fancheck3 = LOW;
      fancheck4 = LOW;
    }     
    timer4 = millis();
  }


  //---------------------------------------------------------------------------------------------

  unsigned long currentMillis = millis();
  if(currentMillis - previousMillis > puls) {
    previousMillis = currentMillis; 
    if (fpstate == LOW)
      fpstate = HIGH;
    else
      fpstate = LOW;
    digitalWrite(fp, fpstate);
  }

  if(puls == 0){
    fpstate = HIGH;
    check = HIGH;
  }

  if(currentTime >= (loopTime + 200) && check == HIGH){  

    puls = puls + stepsize5;   
    if (puls == 70) {
      stepsize5 = 0; 
      check = LOW;
      check1 = HIGH;
    }    
    loopTime = currentTime;
  }
  if(check1 == HIGH){
    stepsize1 = 1;
  }

  if(check1 == HIGH){
    if(currentTime >= (loopTime + 2000)){  

      puls = puls + stepsize1;   
      if (puls == 72) {
        stepsize1 = 0; 
        check1 = LOW;
        check2 = HIGH;
      }    
      loopTime = currentTime;
    }
    if(check2 == HIGH){
      stepsize1 = 1;

    }
  }

  if(currentTime >= (loopTime + 36) && check2==HIGH){  

    puls = puls + stepsize1;   
    if ( puls == 250) {
      stepsize1 = 0; 
      check2 = LOW;
      check3 = HIGH;
    }    
    loopTime = currentTime;
  }

  if(check3 == HIGH){
    stepsize1 = 1;
  }

  if(currentTime >= (loopTime + 8000) && check3 == HIGH){  
    puls = puls + stepsize1;
    if ( puls == 252){
      stepsize1 = 0; 
      check3 = LOW;
      check4 = HIGH;
    }    

    loopTime = currentTime;
  }

  if(check4 == HIGH){
    stepsize1 = 1;

  }

  if(currentTime >= (loopTime + 2222) && check4 == HIGH){  

    puls = puls - stepsize1;   
    if ( puls == 90) {
      stepsize1 = 0; 
      check3 = LOW;
      check4 = LOW;
      check5 = HIGH;

      //  fanstep1 = 1;
    }    
    loopTime = currentTime;
  }

  if(timer >= (timer1 + 118) && igncheck == LOW){  
    ign = ign + ignstep1;   
    if ( ign == 255) {
      ignstep1 = 0 ;
      igncheck = HIGH;
      igncheck1 = HIGH;

    }     
    timer1 = millis();
  }
  if(igncheck1 == HIGH){
    ignstep1 = 1;
  }

  if(timer >= (timer1 + 7500) && igncheck1 == HIGH){  

    ign = ign - ignstep1;   
    if ( ign == 253) {
      igncheck1 = LOW;
      igncheck2 = HIGH;
      ignstep1 = 0 ; 

    }     
    timer1 = millis();
  }

  if(igncheck2 == HIGH){
    ignstep1 = 1;
  }

  if(timer >= (timer1 + 274) && igncheck2 == HIGH){  

    ign = ign - ignstep1;   
    if ( ign == 180) {
      igncheck2 = LOW;
      igncheck3 = HIGH;
      ignstep1 = 0 ; 

    }     
    timer1 = millis();
  }
  if(igncheck3 == HIGH){
    ignstep1 = 1;
  }

  if(timer >= (timer1 + 60000) && igncheck3 == HIGH){  

    ign = ign + ignstep1;   
    if ( ign == 183) {
      igncheck3 = LOW;
      igncheck4 = HIGH;
      ignstep1 = 0 ; 

    }     
    timer1 = millis();
  }
  if(igncheck4 == HIGH){
  ign = LOW;
  igncheck4 = LOW;
  }
}

b707
Offline
Зарегистрирован: 26.05.2017

в код особо не вникал, одно замечание.

Вот так вот считать интервалы нельзя,

if(timer >= (timer1 + 118)

потому что при переполнении счетчика времени условие развалится.  Вместо этого все подобные скобки. коих у вас в коде десятка три. надо переписать вот так

if ((timer - timer1) >= 118))

 

blackenning
Offline
Зарегистрирован: 21.01.2021

большое спасибо за совет, обязательно поправлю!