代码之家  ›  专栏  ›  技术社区  ›  Marc

将IO草图转换为C++类,无效使用非静态成员函数

  •  1
  • Marc  · 技术社区  · 6 年前

    我试图将一个.Ny草图转换成C++类,工作代码是:

    byte statusLed    = 13;
    byte sensorInterrupt = 0;  // 0 = digital pin 2
    byte sensorPin       = 2;
    
    // The hall-effect flow sensor outputs approximately 4.5 pulses per second per
    // litre/minute of flow.
    float calibrationFactor = 4.5;
    
    volatile byte pulseCount;  
    
    float flowRate;
    unsigned int flowMilliLitres;
    unsigned long totalMilliLitres;
    
    unsigned long oldTime;
    
    void setup()
    {
    
      // Initialize a serial connection for reporting values to the host
      Serial.begin(38400);
    
      // Set up the status LED line as an output
      pinMode(statusLed, OUTPUT);
      digitalWrite(statusLed, HIGH);  // We have an active-low LED attached
    
      pinMode(sensorPin, INPUT);
      digitalWrite(sensorPin, HIGH);
    
      pulseCount        = 0;
      flowRate          = 0.0;
      flowMilliLitres   = 0;
      totalMilliLitres  = 0;
      oldTime           = 0;
    
      // The Hall-effect sensor is connected to pin 2 which uses interrupt 0.
      // Configured to trigger on a FALLING state change (transition from HIGH
      // state to LOW state)
      attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
    }
    
    /**
     * Main program loop
     */
    void loop()
    {
    
       if((millis() - oldTime) > 1000)    // Only process counters once per second
      { 
        // Disable the interrupt while calculating flow rate and sending the value to
        // the host
        detachInterrupt(sensorInterrupt);
    
        // Because this loop may not complete in exactly 1 second intervals we calculate
        // the number of milliseconds that have passed since the last execution and use
        // that to scale the output. We also apply the calibrationFactor to scale the output
        // based on the number of pulses per second per units of measure (litres/minute in
        // this case) coming from the sensor.
        flowRate = ((1000.0 / (millis() - oldTime)) * pulseCount) / calibrationFactor;
    
        // Note the time this processing pass was executed. Note that because we've
        // disabled interrupts the millis() function won't actually be incrementing right
        // at this point, but it will still return the value it was set to just before
        // interrupts went away.
        oldTime = millis();
    
        // Divide the flow rate in litres/minute by 60 to determine how many litres have
        // passed through the sensor in this 1 second interval, then multiply by 1000 to
        // convert to millilitres.
        flowMilliLitres = (flowRate / 60) * 1000;
    
        // Add the millilitres passed in this second to the cumulative total
        totalMilliLitres += flowMilliLitres;
    
        unsigned int frac;
    
        // 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(".");             // Print the decimal point
        // Determine the fractional part. The 10 multiplier gives us 1 decimal place.
        frac = (flowRate - int(flowRate)) * 10;
        Serial.print(frac, DEC) ;      // Print the fractional part of the variable
        Serial.print("L/min");
        // Print the number of litres flowed in this second
        Serial.print("  Current Liquid Flowing: ");             // Output separator
        Serial.print(flowMilliLitres);
        Serial.print("mL/Sec");
    
        // Print the cumulative total of litres flowed since starting
        Serial.print("  Output Liquid Quantity: ");             // Output separator
        Serial.print(totalMilliLitres);
        Serial.println("mL"); 
    
        // Reset the pulse counter so we can start incrementing again
        pulseCount = 0;
    
        // Enable the interrupt again now that we've finished sending output
        attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
      }
    }
    
    /*
    Insterrupt Service Routine
     */
    void pulseCounter()
    {
      // Increment the pulse counter
      pulseCount++;
    }
    

    我尝试转换如下:

    h文件:

    class FlowSensor
    {
    public:
        FlowSensor(int pin);
        void begin();
        void run();
    private:
        int _pin;
        byte sensorInterrupt = 0;  // 0 = digital pin 2
    
        // The hall-effect flow sensor outputs approximately 4.5 pulses per second per
        // litre/minute of flow.
        float calibrationFactor = 4.5;
    
        float flowRate;
    
        unsigned int flowMilliLitres;
        unsigned long totalMilliLitres;
    
        unsigned long oldTime;
        volatile unsigned long pulseCount;
        //volatile byte pulseCount;
        void pulseCounter();
    };
    

    C文件:

    FlowSensor::FlowSensor(int pin)
    {
        _pin = pin;
    }
    
    void FlowSensor::begin()
    {
        pinMode(_pin, INPUT);
        digitalWrite(_pin, HIGH);
    
        pulseCount = 0;
        flowRate = 0.0;
        flowMilliLitres = 0;
        totalMilliLitres = 0;
        oldTime = 0;
    
        sensorInterrupt = digitalPinToInterrupt(_pin);
    
        // The Hall-effect sensor is connected to pin 2 which uses interrupt 0.
        // Configured to trigger on a FALLING state change (transition from HIGH
        // state to LOW state)
        attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
    }
    
    void FlowSensor::run()
    {
        if ((millis() - oldTime) > 1000)    // Only process counters once per second
        {
            // Disable the interrupt while calculating flow rate and sending the value to
            // the host
            detachInterrupt(sensorInterrupt);
    
            // Because this loop may not complete in exactly 1 second intervals we calculate
            // the number of milliseconds that have passed since the last execution and use
            // that to scale the output. We also apply the calibrationFactor to scale the output
            // based on the number of pulses per second per units of measure (litres/minute in
            // this case) coming from the sensor.
            flowRate = ((1000.0 / (millis() - oldTime)) * pulseCount) / calibrationFactor;
    
            // Note the time this processing pass was executed. Note that because we've
            // disabled interrupts the millis() function won't actually be incrementing right
            // at this point, but it will still return the value it was set to just before
            // interrupts went away.
            oldTime = millis();
    
            // Divide the flow rate in litres/minute by 60 to determine how many litres have
            // passed through the sensor in this 1 second interval, then multiply by 1000 to
            // convert to millilitres.
            flowMilliLitres = (flowRate / 60) * 1000;
    
            // Add the millilitres passed in this second to the cumulative total
            totalMilliLitres += flowMilliLitres;
    
            unsigned int frac;
    
            // 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(".");             // Print the decimal point
            // Determine the fractional part. The 10 multiplier gives us 1 decimal place.
            frac = (flowRate - int(flowRate)) * 10;
            Serial.print(frac, DEC);    // Print the fractional part of the variable
            Serial.print("L/min");
            // Print the number of litres flowed in this second
            Serial.print("  Current Liquid Flowing: ");          // Output separator
            Serial.print(flowMilliLitres);
            Serial.print("mL/Sec");
    
            // Print the cumulative total of litres flowed since starting
            Serial.print("  Output Liquid Quantity: ");          // Output separator
            Serial.print(totalMilliLitres);
            Serial.println("mL");
    
            // Reset the pulse counter so we can start incrementing again
            pulseCount = 0;
    
            // Enable the interrupt again now that we've finished sending output
            attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
        }
    }
    
    /*
     * Interrupt Service Routine
     */
    void FlowSensor::pulseCounter()
    {
      // Increment the pulse counter
        pulseCount++;
    }
    

    我得到的错误是:

    C:\Users\marcp\Dropbox\Arduino\FlowSensor\FlowSensor.cpp: In member function 'void FlowSensor::begin()':
    C:\Users\marcp\Dropbox\Arduino\FlowSensor\FlowSensor.cpp:24:56: error: invalid use of non-static member function
      attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
                                                            ^
    C:\Users\marcp\Dropbox\Arduino\FlowSensor\FlowSensor.cpp: In member function 'void FlowSensor::run()':
    C:\Users\marcp\Dropbox\Arduino\FlowSensor\FlowSensor.cpp:80:57: error: invalid use of non-static member function
       attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
    

    是否应标记为静态?

    1 回复  |  直到 6 年前
        1
  •  0
  •   Delta_G    6 年前

    ISR必须不返回任何内容,不接受任何参数。这就是ISR的规则。这只是规则,我想你不能改变。成员函数都有不可见的“this”伴随它们。

    考虑一下,如果您有这个类的多个实例,那么中断调用应该来自哪个实例?它不知道,这就是您不能将成员函数用作ISR的原因。

    您可以创建一个静态方法(使所有实例共享),并将静态方法用作ISR,但这样它就不能访问任何成员变量。也可以在草图中编写ISR,从类的正确实例调用正确的方法。

    但您不能简单地将成员函数用作ISR。这是违反规定的。