Inconsistent Voltage Readings - Need Advice

Im working on a project that is centered around the MQ-7 Carbon Monoxide sensor. This sensor requires two modes to use it properly. Heating mode is when you apply 5 volts to the module for 50 seconds, then you apply 1.4 volts for 90 seconds and occasionally, you pop it to 5 to take your reading then pop it back to 1.4 …

Anyways, in order to do this, I decided to use a separate 5 volt regulator feeding the +5 pin on the module. then I sink the ground through a MOSFET and PWM the mosfet in order to have control of the voltage across the sensor board. I pulse the MOSFET with one pin, then I monitor the drain with another pin, and I wrote a routine that increases the PWM on the gate while reading the drain then calculating the voltage across the sensor.

The problem I’m having, is that when I set the pwm on the gate, then read the voltage on the drain, the voltage varies by quite a bit with each read. I want to assume that the problem has to be in the circuit - BUT I DON’T KNOW THIS TO BE FACT … I assume the Arduino does what it does and it is merely reporting what it sees. When I take a reading, I do take a lot of them and I average them so as to get some kind of consistency but it’s still not anywhere near a level of consistency that is usable.

When I measure the voltage across the sensor with a volt meter, then step the PWM, the voltage is consistent with each step and does not fluctuate at all which is totally inconsistent with the reading i’m getting from the Arduino.

Here is the schematic

Here is a table comparing actual measured values against what the Arduino reads. The ‘Step’ columns are merely the next reading minus the previous reading - for each column, color matched for clarity.

Here is the code … im dumping the whole program in here for thoroughness

#include <SPI.h>
#include <SD.h>

const byte SDPin  = 4;
const byte PWMPin = 3;
const byte SVPin  = A1;

const float vVR = 5.063; //voltage regulator measured
const float vRef  = 5.029; //measured
int cPwm = 0;
boolean serialReceived = false;
String inputString = "";
String logFile = "DATA.LOG";

void wait(int m) {
  long startTime = millis();
  boolean waiting = true;
  while (waiting)
  {
    if ((millis() - startTime) >= m) waiting = false;
  }
}

void setPwm(int v) {
  analogWrite(PWMPin, v);
}

float  readVPin() {
  float response = 0;
  for (int x = 0; x < 20; x++) {
    response += (float) analogRead(SVPin);
    wait(50);
  }
  response = response / 20;
  return response;
}

void readDataLog() {
  if (SD.exists(logFile)) {
    File dataLog = SD.open(logFile, FILE_READ);
    while (dataLog.available()) {
      char rd = (char) dataLog.read();
      Serial.write(rd);
    }
    dataLog.close();
  }
  else {
    Serial.println("File Problem");
  }
}

void logData(const String msg) {
  File dataLog = SD.open(logFile, FILE_WRITE);
  if (dataLog) {
    dataLog.println(msg);
    dataLog.close();
    Serial.println("Logged: " + msg);
  }
}

void recordValues(String av){
  float pinValue = readVPin();
  float finalV = vVR - ((pinValue / 1024) * vRef);//Voltage across MQ-7
  String logLine = String(cPwm)+"," + String(pinValue) + "," + String(finalV, 3)+","+av;
  logData(logLine);
  Serial.println(logLine);
}

void setup() {
  Serial.begin(57600);
  pinMode(PWMPin, OUTPUT);
  pinMode(SVPin, INPUT);
  if (!SD.begin(SDPin)) {
    Serial.println("NO SD");
  }

  Serial.println("Ready..\n.");
  setPwm(cPwm);
}

void loop() {
  if (serialReceived){
    serialReceived = false;
    processSerial();
  }
}

void serialEvent() {
  while (Serial.available()) {
    char inChar = (char)Serial.read();
    if (inChar == '\n') {
      serialReceived = true;
    }
    else {
      inputString += inChar;
    }
  }
}

void processSerial() {
  if (inputString.substring(0, 1).equals("p")) {
    int i = inputString.substring(1).toInt();
    setPwm(i);
    Serial.println("pwm set to: " + String(i));
  }
  else if (inputString.substring(0, 1).equals("l")) {
    float actual=inputString.substring(1).toFloat();
    recordValues(String(actual,3));
    cPwm++;
    if (cPwm > 80) cPwm = 0;
    setPwm(cPwm);
  }
  else if (inputString.substring(0, 2).equals("rp")) {
    float pin = readVPin();
    float volts = vVR - ((pin / 1024) * vRef);
    Serial.print("Pin Value: " + String(pin));
    Serial.println(" Volts: " + String(volts, 2) + "\n");
  }
  else if (inputString.substring(0, 2).equals("df")) {
    if (SD.exists(logFile)) {
      SD.remove(logFile);
    }  
  }
  else if (inputString.substring(0, 2).equals("rl")) {
    readDataLog();
  }

  inputString = "";
}

Anyone have any idea how I can get the Arduino to read the voltage more consistently and closer to the actual value as I get with my meter?

Thank you,

Mike Sims

PWM does NOT give you a voltage. So you can't simply read a voltage back from something you PWM. So you never really apply 1,4V to the sensor.

I also don't get what you want to read back. You use the MOSFET as a switch so theaverage voltage at it's drain will be exactly proportional to the duty cycle you use for the PWM. Sensor will not change a thing about that.

septillion:
PWM does NOT give you a voltage. So you can't simply read a voltage back from something you PWM. So you never really apply 1,4V to the sensor.

I also don't get what you want to read back. You use the MOSFET as a switch so theaverage voltage at it's drain will be exactly proportional to the duty cycle you use for the PWM. Sensor will not change a thing about that.

The MOSFET acts as basically a current choke so when the gate is gradually opened, it gradually allows more current to pass to ground which has the effect of changing the voltage applied to the sensor ... if you look at the table I posted, you can see that as I vary PWM on the gate, it does change the voltage applied to the sensor ... my actual readings were taken from the + and - pins on the sensor ...

But thats not what this post is about, what i'm trying to understand is why - when I take a voltage reading with the arduino, each reading is different and it can vary by as much as a full volt ... and I don't understand why that is the case when my volt meter reads a flat voltage consistently.

Schematic

Table

EasyGoing1:
But thats not what this post is about, what i'm trying to understand is why - when I take a voltage reading with the arduino, each reading is different and it can vary by as much as a full volt ... and I don't understand why that is the case when my volt meter reads a flat voltage consistently.

Because you are supplying a constant 1.4V. The meter is averaging. Have you checked the AC reading on the meter? I would bet the reading is not 0 (or a few millivolts). To further prove the point, don't use a meter, but instead check the voltage with an oscilloscope.

How would the MOSFET act as a choke? It's ON or it is OFF. Like @adwsystems also tells you, it has everything to do with it. A multimeter will average over time. But PWM is "instant".

To get a varying voltage from PWM you need to filter it, that is basically how a switch mode power supply works.

septillion:
How would the MOSFET act as a choke? It's ON or it is OFF.

No, MOSFETS, like transistors have a saturation threshold voltage on the gate and the amount of current that can pass from source to drain is not "wide open" until you hit the saturation voltage. So any voltage applied to the gate below the threshold allows you to choke the current.

This is why transistors work in anything that has frequency (a change in voltage / current) because they can essentially control an output proportional to the input ... MOSFETS make great audio amp drivers because their source to drain resistance is virtually ZERO (cleaner audio) ... but thats off topic. :slight_smile:

adwsystems:
To further prove the point, don't use a meter, but instead check the voltage with an oscilloscope.

That's a good idea, ill check it with the scope and report back.

I really don't understand what you mean by the fact the your FET is operating as a choke. "Choke" is one of the terms used for an inductor. It is a frequency dependant device acting as an energy store, and altering the phase between current and voltage. Nothing to do with switching a current on or off, which from your diagram is all that your FET is doing.

And in any case, in measuring the voltage between gate and drain with a multimeter, don't forget that the multimeter is sampling the voltage at it's own rate which isn't synced to the PWM of your circuit. You are of course going to get strange readings depending on when the multimeter starts and stops its conversion and how your circuit has switched up and down during the conversion.

As already stated above, a DVM is not the correct instrument to use in this case.

OP: You appear to have reached analysis paralysis...

Yes, you can use PWM to lower the effective applied voltage. All you need to do is to set the analog output to 1.4 / 5 * 256. If you want to measure the actual voltage with an analog input, you need to filter it to remove the pulses. But, that is really unnecessary since you have a regulated power supply.

Several things that have not been mentioned are that you absolutely need a logic level mosfet for the application and that 1k gate resistor is too high in value, regardless of mosfet being used. It should be in the 100-150 ohm range, maximum. Finally, the 7805 needs both input and output side bypass capacitors for stable, proper operation. Refer to its data sheet for appropriate values.

adwsystems:
Because you are supplying a constant 1.4V. The meter is averaging. Have you checked the AC reading on the meter? I would bet the reading is not 0 (or a few millivolts). To further prove the point, don't use a meter, but instead check the voltage with an oscilloscope.

Well ... you were correct and I should have thought of this ... the signal coming off the drain of the MOSFET is a square wave ... or more accurately, a pulse width modulated signal. What would I expect when I apply a pulse width modulated signal to the gate? DUH!

Here it is set at roughly 125

And here at about 70

And here at something else ...

So I guess what's happening is when I take my analogRead in the code, the arduino must do a shitty job at averaging the pulse value, or the snapshot is so fast, that the reading is capturing it at some place in the square wave that makes it ... not accurate.

Is there not a way to take PWM readings with the arduino and get a solid average value of a PWM signal?

TCSC47:
I really don't understand what you mean by the fact the your FET is operating as a choke.

OK, lets assume for the sake of argument, that PWM and analog voltage are the same thing ... THEY'RE NOT, but for this discussion, they are ... because the net effect that a PWM signal has over time is the same as applying a voltage at a certain value.

As far as the FET is being used ... if I apply a very small voltage to the gate of the FET, it's going to allow a small amount of current to pass from source to drain... the amount of current, of course, depends on the load attached to the drain and the amount of voltage applied to that load.

If I increase the voltage on the gate, eventually, it will saturate, which will then fully open the path from source to drain, allowing the maximum amount of current to flow through the load (up to whatever the FET can handle of course).

I CALL THAT CHOKING THE CURRENT - I may be technically wrong in calling it that, but that's what I'm calling it ...

Is there not a way to take PWM readings with the arduino and get a solid average value of a PWM signal?

There is no "solid average value" because the voltage depends on the (nonlinear) heater load current and supply impedance.

Ideally you would use a regulated power supply capable of switching between two recommended voltages (5 and 1.5V), and of supplying the necessary current at each voltage. That is not so simple.

However, you might be able to come up with a series heater resistor, switched on and off using a logic-level MOSFET, that effectively switches the heater voltage between the recommended values.

Why do you think the ADC averages? If it did we couldn’t use it to capture accurate values while the signal changes and would slow down measurements while the average catches up. For RMS readings you either have to take multiple samples and do the math or convert your “AC” in this case PWM into DC and measure that voltage as PerryBebbington suggested.

PerryBebbington:
To get a varying voltage from PWM you need to filter it, that is basically how a switch mode power supply works.

Thank you ... I totally forgot about using RC filters to smooth out PWM ... I think this is my solution...

EasyGoing1:
No, MOSFETS, like transistors have a saturation threshold voltage on the gate and the amount of current that can pass from source to drain is not "wide open" until you hit the saturation voltage. So any voltage applied to the gate below the threshold allows you to choke the current.

True, but you are dumping just 0v or 5V onto it's gate. Don't know the current or transistor used but I'm pretty sure it will just turn on hard.

EasyGoing1:
This is why transistors work in anything that has frequency (a change in voltage / current) because they can essentially control an output proportional to the input ... MOSFETS make great audio amp drivers because their source to drain resistance is virtually ZERO (cleaner audio) ... but thats off topic. :slight_smile:

For them to be have continues output you need a continues input as well. Which they have a a A/AB class amp. Class D is something different because you need to modulate and filter. Both you don't do here :wink: But reading on I think you came to the same conclusion :wink:

septillion:
True, but you are dumping just 0v or 5V onto it's gate. Don't know the current or transistor used but I'm pretty sure it will just turn on hard.

But with PWM making the net effect exactly as i described...

Assuming a linear load. Don't know if we can assume that with the sensor. :slight_smile: