insufficient accuracy for internal Vcc measurement



  • Hi,

    I'm working on a battery operated node doing motion + temp, and I use Yveaux's Arduino_Vcc library to measure battery voltage.

    I've tested the voltage from the 2 AAs and it's 2.99v, but the internal measurement gives 2.22v. I have a 25% difference where we should expect max 10%, shouldn't we ?

    I'll try to debug that tomorrow with a dedicated sketch, but maybe someone can easily spot the error in the following code ?

    /**
     * DESCRIPTION
     * Motion Sensor (HC-SR501) + Temp sensor (MCP9700 analog sensor)
     * inspired by :
     * mysensors PIR example created by Henrik Ekblad : http://www.mysensors.org/build/motion
     * Slim Node as a Mini 2AA Battery PIR Motion Sensor : http://forum.mysensors.org/topic/2715/slim-node-as-a-mini-2aa-battery-pir-motion-sensor
     * Kevin Kessler's blog for reading MCP9700 temperature sensor : http://blog.kkessler.com/2012/06/20/mcp9700/
     */
    
    #include <MySensor.h>  
    #include <SPI.h>
    #include <Vcc.h>
    
    #define NODE_ID 30
    #define MOTION_INPUT_PIN 3   // The digital input you attached your motion sensor.  (Only 2 and 3 generates interrupt!)
    #define CHILD_ID_MOTION 1
    #define CHILD_ID_TEMP 2  
    #define CHILD_ID_BATT 3
    #define DOMOTICZ_OFF_DELAY 10000
    #define MINIMUM_SEND_INTERVAL 86400000 // once a day
    #define TEMP_SEND_FREQ 300000 // every 5min
    #define TEMP_SEND_THRESHOLD 0.3 // do not send temp if variation is below delta
    #define VCC_MIN 1.9
    #define VCC_MAX 3.3
    
    float lastTemperature = 0;;
    float lastVoltage = 0;
    
    int loopCounter = 0;
    
    bool interruptReturn = false; // "false" will make the first loop disregard high output from HC-SR501 (from start-up) and make a battery+temp report instead.
     
    Vcc vcc(1.34); // 2.98/2.22=1.3423 . Can this be ok ???
    
    MySensor gw;
    MyMessage msgMotion(CHILD_ID_MOTION, V_TRIPPED);
    MyMessage msgTemp(CHILD_ID_TEMP,V_TEMP);
    MyMessage msgBattery(CHILD_ID_BATT, V_VOLTAGE);
    
    
    void setup()  
    {  
      delay(100); // to settle power for radio
      
      gw.begin(NULL, NODE_ID);
    
      // Send the sketch version information to the gateway and Controller
      gw.sendSketchInfo("Motion & Temp Sensor", "1.0");
    
      pinMode(MOTION_INPUT_PIN, INPUT);      // sets the motion sensor digital pin as input
    
      // Register all sensors to gw (they will be created as child devices)
      gw.present(CHILD_ID_MOTION, S_MOTION);
      gw.present(CHILD_ID_TEMP, S_TEMP);
      gw.present(CHILD_ID_BATT, S_MULTIMETER);
      
      gw.sleep(20000); // Wait until motion sensor warmed-up and output returned low.    
    }
    
    void loop()     
    {     
      int sleeptime = 0;
      
      if (interruptReturn) {    // Woke up by rising pin
        gw.send(msgMotion.set("1"));  // Domoticz will take care of setting the node off after some delay
        sleeptime = DOMOTICZ_OFF_DELAY;  // sleep until domoticz sets the sensor off on its side    
      } 
      else 
      {
        float voltage = vcc.Read_Volts();    
        float temperature = readMCP9700(4,0);
    
        // send if variation is enough or if delay was reached       
        if (abs(temperature - lastTemperature) >= TEMP_SEND_THRESHOLD) {
          lastTemperature = temperature;
          sleeptime = 3000;
          loopCounter = 0;
          gw.send(msgTemp.set(temperature, 1));
        } 
    
        // send on first iteration, then if variation is enough  or if delay was reached
        if (abs(voltage - lastVoltage) >= 0.1) {
          sendBatteryReport(voltage);
          sleeptime = 3000;
          loopCounter = 0;
          lastVoltage = voltage;      
        }
    
        if (loopCounter++ * TEMP_SEND_FREQ >= MINIMUM_SEND_INTERVAL) {
          loopCounter = 0;
          sleeptime = 3000;      
          gw.send(msgTemp.set(temperature, 1));
          sendBatteryReport(voltage);        
        }
      }  
    
      if (sleeptime) {
        gw.sleep(sleeptime); // Make sure everything is stable before start to sleep with interrupts. (don't use "gw.wait()" here). Tests shows false trip ~2s after battery report otherwise.
      }
      interruptReturn = gw.sleep(MOTION_INPUT_PIN-2, RISING, TEMP_SEND_FREQ);  
    }
    
    void sendBatteryReport(float voltage) {
      float perc = 100.0 * (voltage-VCC_MIN) / (VCC_MAX-VCC_MIN);
      gw.send(msgBattery.set(voltage, 2));          
      gw.sendBatteryLevel(static_cast<int>(perc));
    }
    
    // this function comes from Kevin Kessler's blog : http://blog.kkessler.com/2012/06/20/mcp9700/
    float readMCP9700(int pin,float offset)
    {
      analogReference(INTERNAL);
      for (int n=0;n<5;n++)
        analogRead(pin);
    
      int adc=analogRead(pin);
      float tSensor=((adc*(1.1/1024.0))-0.5+offset)*100;
      float error=244e-6*(125-tSensor)*(tSensor - -40.0) + 2E-12*(tSensor - -40.0)-2.0;
      float temp=tSensor-error;
    
      return temp;
    }
    

    Regards
    Mikael


Log in to reply
 

Suggested Topics

  • 3
  • 5
  • 2
  • 1
  • 8
  • 6

51
Online

11.5k
Users

11.1k
Topics

112.7k
Posts