Measurement of low frequencys based on timing between pulses

Dependents:   Energy_Meter_S0_Example

Files at this revision

API Documentation at this revision

Comitter:
jocis
Date:
Wed Nov 07 18:38:59 2012 +0000
Child:
1:6eb686d7d16a
Commit message:
First commit

Changed in this revision

Pulses.cpp Show annotated file Show diff for this revision Revisions of this file
Pulses.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pulses.cpp	Wed Nov 07 18:38:59 2012 +0000
@@ -0,0 +1,99 @@
+#include "Pulses.h"
+
+//////////////////////////////////////////////////////////////////////////////////
+
+Pulses::Pulses(PinName inPin, PulseType type, unsigned int timeout) : _in(inPin) {
+    _timer.reset();
+    _timer.start();
+    
+    _ActTime = 0;
+    _SumTime = 0;
+    _SumCount = 0;
+    _Counter = 0;
+    _Factor = 1.0f;
+    _bFirst = true;
+    
+    if ( timeout > 900 ) timeout = 900;   // not more than 15 minutes
+    _Timeout = timeout;
+    _TimeoutCount = 0;
+    
+    _in.mode(PullUp);
+    
+    _type = type;
+    if ( type & RISE )
+        _in.rise(this, &Pulses::callback_in);
+    if ( type & FALL )
+        _in.fall(this, &Pulses::callback_in);
+        
+    _timeout.attach(this, &Pulses::callback_timeout, 1);
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+
+float Pulses::getAct() {
+    if ( _ActTime == 0 ) return 0.0f;
+    
+    return _Factor / (float)_ActTime;
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+
+float Pulses::getAverage() {
+    unsigned int sumTime = 0;
+    unsigned int sumCount = 0;
+
+    __disable_irq();    // Disable Interrupts for atomic copy
+    sumTime = _SumTime;
+    sumCount = _SumCount;
+    _SumTime = 0;
+    _SumCount = 0;
+    __enable_irq();     // Enable Interrupts
+
+    if ( sumCount == 0 ) return -1.0f;
+    
+    float average = _Factor / ( (float)sumTime / (float)sumCount );
+    return average;
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+
+unsigned int Pulses::getCounter() {
+    return _Counter;
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+    
+void Pulses::setFactor(float factor) {
+    _Factor = factor * 1000000.0f;
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+
+void Pulses::callback_in() {
+    unsigned int diff = _timer.readDiff_us();
+
+    _Counter++;
+    _TimeoutCount = 0;
+
+    if ( _bFirst ) {   // ignore first pulse to synchronize timer (maybe timer overflow)
+        _bFirst = false;
+        return;
+    }
+    
+    _ActTime = diff;
+    _SumTime += diff;
+    _SumCount++;
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+
+void Pulses::callback_timeout() {
+    _TimeoutCount++;
+    if ( _TimeoutCount >= _Timeout ) {
+        _TimeoutCount = 0;
+        _ActTime = 0;
+        _bFirst = true;
+        }
+}
+
+//////////////////////////////////////////////////////////////////////////////////
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pulses.h	Wed Nov 07 18:38:59 2012 +0000
@@ -0,0 +1,160 @@
+/* 
+* @author Jochen Krapf
+*
+* @section LICENSE
+*
+* Copyright (c) 2012 Jochen Krapf, MIT License
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+* and associated documentation files (the "Software"), to deal in the Software without restriction,
+* including without limitation the rights to use, copy, modify, merge, publish, distribute,
+* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or
+* substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*
+* @section DESCRIPTION
+* mbed Pulses Library, for calculate low frequencys based on timing between pulses
+*
+* Use cases:
+* - Motor rotations (rpm)
+* - Energy meter with SO interface
+*
+* Example:
+*
+* @code
+#include "mbed.h"
+#include "Pulses.h"
+
+Pulses pulses(p8, Pulses::FALL);
+Serial pc(USBTX, USBRX); // tx, rx
+
+int main() {
+    // choose on of the following unit scales
+    pulses.setFactor(1.0f);   // Hz
+    pulses.setFactor(60.0f);   // rpm
+    pulses.setFactor(3600.0f/2000.0f);   // kWh; energy meter with SO interface - 2000 pulses per kWh
+    
+    while(1) {
+        pc.printf ( "Pulses: counter=%d act=%.3f average=%.3f\r\n", 
+            pulses.getCounter(), 
+            pulses.getAct(), 
+            pulses.getAverage() );
+        
+        wait(3.14);
+    }
+}
+ * @endcode
+ *
+*/
+
+#ifndef MBED_PULSES_H
+#define MBED_PULSES_H
+
+#include "mbed.h"
+
+class TimerDiff : public Timer {
+public:
+    TimerDiff(const char *name = NULL) : Timer(name) {
+        reset();
+        start();
+        _last = 0;
+    };
+    
+    unsigned int readDiff_us() {
+        unsigned int act = read_us();
+        unsigned int diff;
+        
+        if ( act < _last )   // overflow
+            diff = act - _last;
+        else
+            diff = act - _last;
+        _last = act;
+        return diff;
+    }
+    
+    float readDiff() {
+        return (float)readDiff_us() * 0.000001;
+    }
+
+protected:
+    unsigned int _last;
+};
+
+
+/** A class to calculate frequencys based on timing between pulses. Pulse-frequency can be about or slower than loop/aquisition time
+ *
+ */
+class Pulses {
+public:
+
+    /** Pulses type format */
+    enum PulseType {
+        RISE=1,
+        FALL=2,
+        CHANGE=3
+    };
+
+    /** constructor of Pulses object
+     *
+     * @param inPin    Pin number of input pin. All port pins except p19 and p20
+     * @param type     Type of edge detection.
+     * @param timeout  Timeout in seconds to handle an offline pulse-generator (standing motor). Max 15 minutes.
+     */
+    explicit Pulses(PinName inPin, PulseType type = RISE, unsigned int timeout=600);
+
+    /** Gets the frequency based on the last 2 pulses
+     *
+     * @return        Actual frequence
+     */
+    float getAct();
+
+    /** Gets the average frequency based on all pulses since last call of this function
+     *
+     * @return        Average frequency. -1 if no new pulses occoured since last call
+     */
+    float getAverage();
+
+    /** Gets the number of pulses since start
+     *
+     * @return        Number of pulses
+     */
+    unsigned int getCounter();
+    
+    /** Sets the factor for the getter-functions to convert in another unit (1.0=Hz, 60.0=rpm, ...)
+     *
+     * @param factor  Factor to scale from Hz to user unit
+     */
+    void setFactor(float factor);
+    
+
+protected:
+
+    void callback_in();
+    void callback_timeout();
+
+    InterruptIn _in;
+    TimerDiff _timer;
+    Ticker _timeout;
+    
+    PulseType _type;
+    
+    unsigned int _ActTime;
+    unsigned int _SumTime;
+    unsigned int _SumCount;
+    unsigned int _Counter;
+    float _Factor;
+    bool _bFirst;
+    unsigned int _Timeout;
+    unsigned int _TimeoutCount;
+    
+};
+
+#endif