Обновите атрибут класса с помощью attachInterrupt

Я хочу реорганизовать этот код

/*
YF‐ S201 Water Flow Sensor
Water Flow Sensor output processed to read in litres/hour
Adaptation Courtesy: www.hobbytronics.co.uk
*/
volatile int flow_frequency; // Измеряет импульсы датчика расхода
unsigned int l_hour; // Расчетные литры/час
unsigned char flowsensor = 2; // Вход датчика
unsigned long currentTime;
unsigned long cloopTime;
void flow () // Функция прерывания
{
   flow_frequency++;
}
void setup()
{
   pinMode(flowsensor, INPUT);
   digitalWrite(flowsensor, HIGH); // Дополнительное внутреннее подтягивание
   Serial.begin(9600);
   attachInterrupt(0, flow, RISING); // Настройка прерывания
   sei(); // Разрешить прерывания
   currentTime = millis();
   cloopTime = currentTime;
}
void loop ()
{
   currentTime = millis();
   // Каждую секунду вычисляем и печатаем литры/час
   if(currentTime >= (cloopTime + 1000))
   {
      cloopTime = currentTime; // Обновляет cloopTime
      // Частота импульсов (Гц) = 7,5Q, Q — скорость потока в л/мин.
      l_hour = (flow_frequency * 60 / 7.5); // (Частота импульсов x 60 мин) / 7,5Q = расход в л/час
      flow_frequency = 0; // Сброс счетчика
      Serial.print(l_hour, DEC); // Печать литров в час
      Serial.println(" L/hour");
   }
}

Первоначально найдено здесь: источник

к решению на основе классов:

/*
YF‐ S201 Water Flow Sensor
Water Flow Sensor output processed to read in litres/hour
Adaptation Courtesy: www.hobbytronics.co.uk
*/
class FlowSensor {
  volatile int flow_frequency;
  unsigned int l_hour;
  unsigned char pin;
  unsigned long currentTime;
  unsigned long cloopTime;
  public:
    void flow () {
      flow_frequency++;
    };
    void setup() {
      pinMode(pin, INPUT);
      digitalWrite(pin, HIGH); // Дополнительное внутреннее подтягивание
      Serial.begin(9600);
      attachInterrupt(digitalPinToInterrupt(pin), flow, RISING); // Настройка прерывания
      sei(); // Разрешить прерывания
      currentTime = millis();
      cloopTime = currentTime;
    }
    void loop() {
      currentTime = millis();
      // Каждую секунду вычисляем и печатаем литры/час
      if(currentTime >= (cloopTime + 1000))
      {
        cloopTime = currentTime; // Обновляет cloopTime
        // Частота импульсов (Гц) = 7,5Q, Q — скорость потока в л/мин.
        l_hour = (flow_frequency * 60 / 7.5); // (Частота импульсов x 60 мин) / 7,5Q = расход в л/час
        flow_frequency = 0; // Сброс счетчика
        Serial.print(l_hour, DEC); // Печать литров в час
        Serial.println(" L/hour");
      }
    }
    FlowSensor() {
      setup();
    };
};
FlowSensor flowsensor_intake;
void setup()
{
   flowsensor_intake = FlowSensor();
}
void loop ()
{
   flowsensor_intake.loop();
}

Но я получаю следующую ошибку в Arduino IDE:

/tmp/087639235/water_flow/water_flow.ino: в статической функции-члене 'статический недействительный FlowSensor::flow()':

/tmp/087639235/water_flow/water_flow.ino:17:19: ошибка: невозможно позвонить функция-член 'void FlowSensor::update_flow()' без объекта

обновление_потока()

^

статус выхода 1

Я понимаю, что поток не является статической функцией и что я не могу сделать ее статической, поскольку она обрабатывает нестатический элемент.

Но я не могу придумать альтернативного решения этой проблемы. Моя цель — контролировать несколько датчиков потока, создавая объект в функции setup() и обновляя их при каждом вызове loop().

, 👍1


1 ответ


1

Вы попали в классическую ловушку. Есть пара вещей, о которых стоит подумать. Во-первых, если это одноэлементный класс (так как всегда будет только один экземпляр), то вы можете просто иметь функцию, не являющуюся членом, которую вы используете с attachInterrupt, и эта функция просто вызывает нужную функцию-член. Обычно я бы создал экземпляр в .cpp и поместил объявление extern для него в заголовок, чтобы его можно было просто использовать без его создания. Посмотрите, как работает Serial для примера. Затем поместите все материалы типа конфигурации в метод begin или init для вызова из установки. Таким образом, функция, не являющаяся членом прерывания, может быть частью заголовка, и пользователю никогда не придется видеть ее или возиться с ней, и создается впечатление, что она является частью класса.

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

,

Да, я хочу иметь несколько экземпляров. Сейчас думаю о структурном подходе., @Valanthor

Хорошо, тогда у вас есть проблема. Как каждый экземпляр узнает, к какому прерыванию присоединить себя? Как прерывание узнает, какой экземпляр относится к какому прерыванию? Оказывается, это банка с червями, и поэтому это запрещено., @Delta_G

Я согласен. Singlton или статические функции-члены не будут работать. Моя текущая работа — это функция-член, которая вызывается определенной функцией для каждого attachInterrupt., @Valanthor