Проблема стабильности кода прерываний, связанного с датчиком расхода

Возникла проблема с кодом, связанным по ссылке Проблема прерываний с датчиком расхода. Код работает, но когда я останавливаю насосы, значение расхода на ЖК-дисплее замораживается, пока я не перезагружу Arduino. А когда я запускаю насосы, расходомер сначала показывает значение 0,54, а затем начинает показывать реальные значения. Но всегда на 0,54 вниз или вверх (если расход составляет 5 л/мин, ЖК-дисплей иногда показывает 5 л/мин, 5+0,54 л/мин или 5-0,54 л/мин). Когда нет потока масла в датчик расхода, значение расхода имеет фиксированное значение, которое является последним показанием. Не могли бы вы мне помочь?

 #include <Wire.h> //I2C lib
#include <LCD.h>
#include <LiquidCrystal_I2C.h>
 // LCD lib
LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

const int pot_pin = A0;
const int pump_pwm = 3;

const int resetButton = 11;
byte press_pin = A1;

//flowmeter parameters
int flowPin = 2;  // input pin on arduino D2

volatile double flowRate;   // value intented to calculate
volatile double flowR; // flow value in lt
volatile double totalFlow; // total output of flow from system

byte sensorInterrupt = 0; // interrupt 0 on D2 pin Arduino Nano

volatile int count; ////integer needs to be set as volatile to ensure it updates correctly during the interrupt process. 

int pot_init= 0;
int pump_init= 0;
int percentValue =0;


unsigned long previous_read;
void setup() {


  pinMode(resetButton, INPUT);
  digitalWrite(resetButton, HIGH);

  lcd.begin(20,4);  // A4 - A5 connection SDA - SCL
  lcd.backlight();
  Serial.begin(9600); 

  pinMode( flowPin,INPUT); // Set D2 pin as an input

  attachInterrupt(sensorInterrupt,Flow,RISING); // Configures interrupt 0 ( pin D2 on Arduino Nano ) to run function "Flow" 
}
void flow_control(void) {

  // Print the flow rate for this second in litres / minute
    Serial.print("Flow rate: ");
    Serial.print(int(flowRate));  // Print the integer part of the variable
    Serial.print("L/min");
    Serial.print("\t");       // Print tab space

    // Print the cumulative total of litres flowed since starting
    Serial.print("Output Liquid Quantity: ");        
    Serial.print(totalFlow/1000);
    Serial.println("L");

 if(digitalRead(resetButton) == LOW)
  {
    totalFlow = 0;
    lcd.setCursor(0, 3);
    lcd.print("Resetting....        ");



}

else {
 lcd.setCursor(0,3);
  lcd.print("Total: "); 
  lcd.setCursor(7,3);
  lcd.print(totalFlow/1000);
  lcd.print(" lt");

}
  lcd.setCursor(0,2);
  lcd.print("Flow: ");
    lcd.setCursor(6,2);
  lcd.print(flowRate);
  lcd.print(" lt/min");



}

void Flow(void) 
{
  count++; // every time this function is called, increment  "count" by 1

  if(millis() -  previous_read > 1000){
    noInterrupts(); // disable interrupts on arduino nano
    int local_count = count;
    count=0;
    interrupts(); // enables interrupts on arduino nano
    previous_read += 1000;

  flowR = (local_count*8.93);   // 112 pulse/lt 423.84 pulse /gallon 
  flowRate= flowR*60;     // convert seconds to minutes, new unit is ml/minutes
  flowRate= flowRate/1000; // convert ml to liters, new unit is lt/minutes

  totalFlow += flowR;
 //process flowrate based on local_count




  //calculation for flowmeter 


  }
}

void loop() {

  pressure_cal(); 
  pump_control();
  flow_control();

}



void pressure_cal(void) {

  float sensorVoltage = analogRead(press_pin);   // sensor voltage A0
  float psi = ((sensorVoltage-102)/204)*25;  // Offset    0 PSI= 0.5V=102 unit, 50 PSI= 2.5, 100 PSI= 4.5V, 1 PSI= 0.04V

  // calibration 
  float bar = psi*(0.0689475729);           // Conversion PSI to BAR


  lcd.setCursor (0,1);
  lcd.print (psi);
  lcd.print (" PSI");

  lcd.setCursor ( 10,1);
  lcd.print(bar);
  lcd.print( " BAR");

  //lcd.setCursor(17,1);
  //lcd.print(sensorVoltage);



  Serial.print("\t Sensor Value = ");
  Serial.print(sensorVoltage);
  Serial.print("\t Bar = ");
  Serial.print(bar);
  Serial.print("\t PSI = ");
  Serial.println(psi);

  delay (100);
}

void pump_control(void)

{

  // read the analog in value:
  pot_init = analogRead(pot_pin);
  // map it to the range of the analog out:
  pump_init = map(pot_init, 0, 1023, 50, 230);  //  duty cycle between %20 - %90: speed control , duty cycle between %0 - %20: turned off  , duty cycle between %90 - %100: full speed
  // map pump speed percent of full scale
  percentValue = map (pump_init, 50, 230,0,100);
  // change the analog out value:
  analogWrite(pump_pwm, pump_init);

  // print the results to the Serial Monitor:
  Serial.print("\t Speed Input = ");
  Serial.print(pot_init);
  Serial.print("\t Speed Output = ");
  Serial.print(pump_init);
  Serial.print("\t Pump Speed Percentage = ");
  Serial.println(percentValue);

  lcd.setCursor(2,0);         
  lcd.print("Speed: ");
  lcd.setCursor(8,0);         
  lcd.print("%");         
  lcd.setCursor(9,0);         
  lcd.print(percentValue); 
  lcd.print("     ");         

 //  delay after the last reading:
  delay(10);

}

, 👍0

Обсуждение

Речь идет о переменной flowRate? Где эта переменная вычисляется? Спойлер: в прерывании. Когда прерываний нет, это значение не вычисляется. Я не вижу простого решения. Прерывание подсчитывает, и flowR должен использовать это количество (даже если оно равно нулю). Это означает, что вам нужно вычислить flowR в цикле Arduino, вы можете использовать millis для вычисления фактического прошедшего времени, чтобы учесть, что иногда оно больше 1 секунды., @Jot

Но я добавляю код прерывания в цикл void и функцию, вызываемую основным циклом. Код не работает. Код, который я добавил, работает, но есть проблема со стабильностью. Когда я запускаю arduino, датчик расхода показывает 0,54 л/мин на ЖК-дисплее. А когда начинается поток, расход изменяется с ошибкой +- 0,54 (например, 4,00 л/мин, затем 4,54 л/мин, затем 3,46 л/мин и т. д.) Как мне решить эту проблему в цикле void?, @sapphire


1 ответ


1

если (millis() - предыдущее_прочитанное > 1000) { [...] предыдущее_прочитанное += 1000; [...] }

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

Расходомер сначала показывает значение 0,54

Неслучайно, что 0,54 — это то, что вы получаете, когда count == 1.

Фрагмент кода выше следует переместить в основной loop() или в Функция вызывается из loop(). Таким образом, она будет выполняться последовательно независимо от того, есть ли какой-то поток или нет, это единственный способ для надежного считывания нулевого потока. Обратите внимание, что для лучшей согласованности по времени вам следует избегать таких действий...

задержка(100);

Не делайте этого. Вместо этого используйте тот же трюк, что и выше:

if (millis() -  previous_pressure_print > 100) {
    previous_pressure_print += 100;
    pressure_cal();
}
,

Но я добавляю код прерывания в пустой цикл и функцию, вызываемую основным циклом. Код не работает. Код, который я добавил, работает, но есть проблема со стабильностью. Когда я запускаю arduino, датчик расхода показывает 0,54 л/мин на ЖК-дисплее. А когда начинается поток, расход изменяется с ошибкой +- 0,54 (например, 4,00 л/мин, затем 4,54 л/мин, затем 3,46 л/мин и т. д.) Как мне решить эту проблему в пустом цикле?, @sapphire

@sapphire: Не _описывайте_ код, _покажите_ его! Отредактируйте свой вопрос и добавьте версию кода, о которой вы говорите., @Edgar Bonet