I've bought this sensor module board to link to an Arduino nano: http://www.ebay.com/itm/For-Arduino-Liquid-PH-Value-Detection-detect-Sensor-Module-Monitoring-Controller/321764233326

I assumed the two screws were for calibration (low point + slope), but it seems the operation is different and I can't figure out how. I've got two reference liquids for pH of 4.0 and 7.0. When I put the probe in either one, I get readings. Turning one of the two screws seems to offset the reading so for instance I had pH 4 = 900 and pH 7 = 1000 (0 - 1023 range). Turning one of two screws would lower the value a bit, but it never gets below 500 or so.

So what I can do is measure two points (4.0 and 7.0) and their respective measurement values. That way I could calculate points in between, but as far as I know pH is not a linear scale, but logarithmic. If I get this wrong, the reading might seem right but only show 4.0 and 7.0 correct and not the rest of the values (I don't have 10.0 reference fluid at the moment).

Now onto the second screw, that one at first seemed to do nothing. But then I noticed that it sets some kind of threshold value, turning a LED on the board on and off. That LED seems to be linked to the value being read, but it's further purpose? Calibration? No idea.

Ok so best case someone has an equal module and wants to detail how it works. Otherwise maybe some of you have some bright ideas on what I could try in order to get this to work the way I want it to :)

Update 09-11-2015

Got feedback from the seller. She sent me the following ZIP: http://1drv.ms/1MSk1DX. It contains some files in Chinese but one had sourcecode in it. Tried it on my Arduino but unfortunately the values still don't make much sense. Depending on how I turn the knob on the print, I get values between 9 and 17 for a liquid that's in real life 7.0. I didn't try but doubt that doing a -7 offset is sensible.

The code itself is pretty straightforward, taking a 6-center average of ten consecutive measures. The interesting lines are these:

 avgValue = 0;
 for (int i=2;i<8;i++)       // take the average value of 6 center sample

 float phValue = (float)avgValue*5.0/1024/6; // convert the analog into millivolt

Maybe someone can make sense of this, because I can't. I don't understand the 5.0 multiplication and the 3.5 after that one. Where do these come from?

Anyway, when I dip the probe into the storage liquid, my normal meter plummets to pH 0.5 whilst the software is giving me 17 (which is a higher value than the one I got from reading my 7.0 liquid). So either my board is broken or this sample code is useless.

Schematics can be found in the ZIP file by the way.

Update 11-11-2015

Did some more experimenting. First I found out that the readings from the module increased for more acidic liquid. So I reversed the value by using

buf[i]=1024 - analogRead(SensorPin);

Ok, now the values made more sense. Then I adjusted the pot to be in the middle of the available range. I dipped the probe in the 7.0 liquid, read the value and adjusted the offset. Then dipped in 4.0, adjusted the pot to match with 4.00, here are the results:

pH 7.0 reference --> 6.27
set offset to: 0.73
pH 4.0 reference --> 5.17
adjusted the pot so value read 4.0
pH 7.0 reference --> 5.86

So as I expected, adjusting the pot also messes up the 7.0 reference measurement. I then though it might be because of the slope of the pot (if there would be any), so I went to the lowest value first to have the least difference. Again the readings:

pH 7.0 reference --> 8.70
set offset to: -1.70
pH 4.0 reference --> 5.17
adjusted the pot so value read 4.0
pH 7.0 reference --> 5.70

The interesting thing here is that the 4.0 value reads 5.17 in both cases, even though the pot was in a different position. I cannot explain why though.

To make sure the probe is fine I re-calibrated my normal pH meter, operates as usual. This one also has two pots, one for 7.0 calibration and one for 4.0 slope. Calibration is done by setting 7.0, then measuring 4.0 and ajusting the slope pot. Measure 7.0 again, change 7.0 pot, measure 4.0 again, etc. until the values match their liquids. Usually takes me about 3 - 4 loops to get it right.

Another update

Took the two containers of reference fluids and started mixing. This gave me measurements in the range of pH 4 - 7.5. Also measured the storage liquid which has a pH of 1.00. Results are in an Excel sheet: http://1drv.ms/1lkAO6e. Next question is how to convert this into a suitable formula?

Update 18-11-2015

Working on @slash-dev's solution, here's what I did:

I first turned the pot all the way down to the lowest value. The readings (for pH 7.0) are as follows: low = 540 and high = 1017. Code as follows:

int rawValue = analogRead(SensorPin);
int buf[10];                //buffer for read analog

for(int i=0;i<10;i++)       //Get 10 sample value from the sensor for smooth the value
   buf[i] = rawValue;

// sorting left out to reduce the sample length

int avgValue=0;
for(int i=2;i<8;i++)  // take the average value of 6 center samples
   avgValue += (buf[i] - CENTER);

In this stage I'm printing the raw value of course.

The shorting of the BNC connector I don't exactly understand, should I short the inside (where the pin goes) or the outside of the connector? And short it to the GND? I used the reference solution instead.

Now I added the formula to determine the voltage. For the low value that reads 0.10. I now put in the center value of 540 which brings the voltage reading to 0.0, seems good.

Now for step 2 I placed the probe into the 4.0 reference solution. The voltage now reads 0.48, raw value 637. I start adjusting the pot to where the voltage reads 2.25, takes quit some adjusting. Raw now reads 1000.

Now comes the part I don't exactly get. You say we can now calculate the pH/V, but with what variables? I mean, -3 / 2.25 will always result in -1.33 but shouldn't there be a variable here depending on how far I actually adjusted the pot?

When I now put in the formula to calculate the pH as expected it reads 4.0 for the 4.0 reference solution. But it now screws up the 7.0 solution as we adjusted the pot but didn't compensate for it as far as I see? I also tried the adjusted pH formulas but I guess those are meant for the first code we had and not this adjusted one.

So what am I missing between step 2 and 3 that messes up things here? Also, you state that the inverting by subtracting from 1024 is correct, but when I do that the voltage readings become minus.

Another thing I wonder about; if the pot has to be a slope, shouldn't it be a different one than the one next to it (where a linear one makes more sense)? Cause it isn't, they both read "W103 / 143C". In the meantime, the vendor is kindly sending over a replacement one to ensure it's not a hardware defect somewhere.

Next update: :)

So I now reverted to my original code to try the adjusted pH calculations. I used the 7.0 reference solution to calibrate again and then measured the 4.0 solution. It reads 4.1! Ok, not completely spot on but not bad either. It's a small difference which might as well come from the probe, not the most expensive one.

So I wonder whether we should still try to get the other approach working cause it sounds better (more scientific?) for some reason. Anyway, this is at least a whole lot better than nothing :)

USB power vs linked? Another strange thing seems to happen when I disconnect the Nano from the USB port of my laptop and instead power it via a Raspberry. I want to use I2C to send the value from the Nano to the RPi. This works, but as soon as I power the nano from the RPi (5V connected to vIn), the calculated pH value drops?

  • I'm interested in this too, because I might use one of those sensors soon. See if the links on this page are helpful: tindie.com/products/rezahussain/dormant-labs-ph-module-v2
    – Jerry
    Nov 3, 2015 at 3:59
  • There seems to be a remarkable lack of information about these modules, from the eBay vendors I skimmed. I am guessing none of them knows what they do. If you could find a datasheet, that might help. Maybe if you post what sort of chips are on the board it might help narrow down what the adjustments might do.
    – Nick Gammon
    Nov 3, 2015 at 4:53
  • I've mailed the seller with a request for info, will update when I get it (and write a blog post). As for the chip types, will do but I'll have to check tonight when I'm home :)
    – Jasper
    Nov 3, 2015 at 11:55
  • @Jerry; thanks, but that's a different module which has software calibration instead of hardware knobs. Not the same and thus not much useful info there.
    – Jasper
    Nov 3, 2015 at 11:56
  • I think i have exactly the same sensor and tried to reproduce the solution, but with no results. Could you share the code which made it working for you? TIA Thomas
    – user16749
    Jan 26, 2016 at 20:59

6 Answers 6


The schematic only shows one trim pot (R23), and it does, as you suspect, set a level for the LED to illuminate. More of a GOOD/BAD indicator, and is available on pin DO.

The other trim pot is not on the schematic. Is it marked on the board? R6, R7, R8 or R9 maybe? It probably controls the gain on p_AOUT.

t_AOUT is an analog temperature voltage, and appears to measure the temperature of the board.

Edit - official but totally bogus: According to my secret source, you are supposed to put the probe in the pH 7.0 reference solution and, with Offset defined to be 0.0, run the program and display the calculated pH value. You may need to decrease the trim pot gain to get smaller (the smallest?) numbers. Now take that displayed value and modify the Offset constant in the sketch to be 7.0 minus the displayed value. If the displayed value is 8.1,

#define Offset (-1.1)

Build and upload the modified sketch. This time, put the probe in your pH 4.0 reference solution and adjust the gain pot until the displayed value is as close to 4.0 as you can get. This will calibrate it for mostly acidic solutions.

Edit 1: Iterate?

It's not clear, but I also wondered if this procedure is supposed to be iterated. Go back to 7 and make sure that adjusting the gain didn't change Offset. Then test the pH 4 solution again; the gain pot may require a small(er) change. If it seems to be diverging, um, don't do that. ;) I think it would diverge only if the probe had an inverted response, which would probably mean it's bad.

If you are measuring basic solutions, do the same procedure with reference solutions of pH 7.0 (of course) and a basic reference solution.


NB: For the 7.0 test, you could short the probe pins together. It really should look like a short circuit when pH == 7.0. If switching to using the real probe in the pH 7.0 solution gives wildly different readings, the probe may be bad. If you're able to calibrate it, it may be "good enough".

Edit 2: Fix the formulas in the provided sketch.

The schematic shows a non-inverting op amp with PH+ on the input, and p_AOUT on the output. The (adjustable?) gain is

R9/R8 + 1 = 10k/10k + 1 = 2

The slope of an ideal probe response is -59mV/pH. You were experimentally getting a negative slope, which agrees with the schematic. I believe it was correct to "invert" the analogRead value by subtracting it from 1024. There is no way that the provided code could have worked with a positive slope of 3.5.

The reference voltage provided to the the PH- pin is half the zener diode voltage... which is unidentified. It could be the very-common 5.1V part, which is essentially forcing PH- to be at

5.1V/((R6+R7)/R6) = 5.1V/2 = 2.55V

I say probably, because you usually want the plus or minus probe voltage swing to have as much room as possible. This would imply (an ideal) analogRead of pH 7.0 to be

2.55V/5.0V * 1024 = 522

This is the "center" of the probe swing about pH 7.0.

Step 1: Determine the reference voltage

At pH 7.0, print out the raw analogRead return value, before inverting it. (The pot wiper should be at it's limit. Which way, I don't know. Changing the gain pot shouldn't change the analogRead very much at the low-gain end. If it does change it, turn it to the other extreme.)

As stated before, you can run the pH 7.0 test by shorting the BNC connector pin to the shield or by using your reference solution. I recommend shorting for now, to eliminate any possible interference from the probe. It will absolutely determine the offset, but only if the gain is as small as possible. You have to start here. Once you know the center reading, you can change the code to display the voltage:

#define CENTER 522
int avgValue=0;
for(int i=2;i<8;i++)  // take the average value of 6 center samples
  avgValue += (buf[i] - CENTER);
float voltage = (((float)avgValue) / 6.0) * (5.0 / 1024.0);

Print this out. You'd better get something close to 0.0... don't make me come over there. :)

Step 2: Set the gain pot.

This is determining the slope, but you need to maximize the swing for the most extreme pH you want to read, say 4.0. Using the 4.0 reference solution, adjust the gain pot so that the displayed voltage is close to +2.5V, say +2.25V to make sure it's not pegged at 1024. (Let's see, slope is negative, 4.0 is < 7.0, so voltage should increase...) With that reading, you can calculate the pH/V:

-3pH/2.25V  =  -1.33 pH/V

Step 3: Calculate and print pH

Modify the original computation to use the pH/V slope:

float phValue = voltage * (-1.33) + 7.0;

This is not even close to phValue = 3.5*voltage + Offset. -_-   I have found several source now that echo my original answer. Totally wrong, and wrong to the point of misleading. I do think these steps will do it. It sounds good in my head, anyway. :D

Edit 3: "Next question is how to convert this into a suitable formula?"

Ok, if you don't want to fix the formula in the code, you can fit a linear or quadratic curve to your data. Linear is actually recommended as "good enough", and that is effectively the change suggested in Edit 2. If we just use your data points, though, this would be the linear approximation:

float adjustedPh = phValue * 1.627 - 2.499;

...and the quadratic approximation:

float adjustedPh = (-0.01796 * phValue + 1.8056) * phValue - 2.94;
  • A secret source heh? Sounds interesting :) Anyway, I will try this approach. My readings are far off from 7, so that means the offset will be something like 5 or 6, seemed a bit too far off. Also, when I adjust the gain pot for the 4.0 solution, won't that also mess up the 7.0 reading? Wil try tonight when I'm at home.
    – Jasper
    Nov 11, 2015 at 7:01
  • Yes, I also thought about iteration because that is the way it works for my normal meter. The problem is that this set-up now has two offsets; one as the pot on the board, one in the software. Changing either one for 4.0 messes up the 7.0 just as quickly. The only way this would work is when the software would apply a slope, or the pot would. Neither do as far as I can see. I tried your solution, see update.
    – Jasper
    Nov 11, 2015 at 19:52
  • @Jasper, you haven't posted in several days, although I see you have visited. Have you tried "Edit 2" or "Edit 3"?
    – slash-dev
    Nov 17, 2015 at 13:31
  • I'm sorry, you're right. I read your response but didn't get to testing it. Now I have, see update above.
    – Jasper
    Nov 18, 2015 at 19:46
  • Btw the bounty expired but I'm more than willing to grant it to you. Let me know whether you want to try to get the other solution working and otherwise I'll go and do a new one + answer it.
    – Jasper
    Nov 18, 2015 at 20:10

USB power vs linked

Just to add my 2 cents on your latest update about the USB or 5V from the PI.

You say you connect it to the VIN:

as soon as I power the nano from the RPi (5V connected to vIn), the calculated pH value drops?

If you look at the below image you see that Vin goes to a good old 7805, which needs a IN voltage > 7.5V, thus the output when its connected to the 5V of the PI is going to be very low and thus mess up readings.

enter image description here

I recommend you connect your power from the PI to the arduino's VCC as this is a regulated 5v and doesn't need to be regulated again.

  • I'm not entirely sure I understand. You state that it should need > 7.5V to work properly. But when I connect the power from the Pi to VCC of the Arduino; how many volts are we talking then? I thought that was 5V but maybe I'm wrong there? Which port from my cobbler should I use to connect to VCC?
    – Jasper
    Jan 13, 2016 at 13:24
  • From what I read on your edit you were say you connected the Pi 5V to the nanos Vin if that is so, you need to connect VCC - VCC
    – RSM
    Jan 13, 2016 at 15:23

I don't know if this is a complete answer, but I can't comment yet.

The analogRead function in Arduino which is used by your sensor reads values from 0 - 5V. It divides the values between 0 and 5V in 1024 steps. So it returns a value between 0 and 1023. That is why it is multiplied by 5. It is easier to understand if the calculation is done in reverse order. Example:

analogRead returns 512, so that is on 1024 / 512 = 0,5th part of its range. Multiply that by 5.0 to get the actual voltage. 0.5 * 5.0 = 2.5. It is then divided by 6 to get the average.

I would also change the order of the calculation. The comments say that it calculates the average, but it doesn't it just adds the values. It does divide it by 6 eventually so that does not cause the error, but for readability it is generally good practice to let your code do what the comments say.

  • Thanks, as this doesn't solve the problem I won't mark is as an answer but it is valuable input anyway. The code comes from the sample, I'll improve it and redo the calculation, indeed seems to make more sense.
    – Jasper
    Nov 10, 2015 at 10:55
  • One other thing. Are you sure the connections are correct? Your results look a lot like when you are measuring a voltage divider at the wrong resistor. So try inverting your measurements, so: measuredValue = 1024 - analogWrite(pin);
    – larzz11
    Nov 10, 2015 at 12:26
  • Thank you, used the hint about inverting the measurements. Improved the reading but didn't solve the issue.
    – Jasper
    Nov 11, 2015 at 19:53

As a first approach, I'd collect a number of measurements from each of as many knowns as you can find or make, and plot them for a visual clue to the linearity or not (probably not) of the sensor's output vs. pH. You could try to eyeball-fit a curve to the data; interpolate linearly between sample points if you have enough of them; or run a least-squares approximation fit. The key is you'll need enough data - knowns - to make whatever approach you use give results accurate enough for your intended use. (Obviously this will be different if you just need to know if something is acidic or basic, or you're monitoring tropical fish tanks, etc.)

Update: If your pH meter is good enough for the fish, and if your sensor is reliably repeatable and sensitive enough, why not check your meter against the two standards, then calibrate the sensor to your meter? Once you're happy with the result, lock down the screws with a dab of nail polish (it's not very tamper-proof but it will be tamper-evident). A pH 10.0 standard won't be very useful to you; at that extreme you'll already know the pH is out and you probably won't care about the exact value. You need your precision between the fish-tolerable limits, close to the pH goal. In fact, if you trust your meter, you don't even need the standards. In that case you need only make up a few samples as you described, covering the pH range of interest, and use them to calibrate your sensor to the meter.

  • It's a fish tank indeed. I understand the approach, but I don't have many 'knowns', at the moment only 4.0 and 7.0 reference fluids. I could buy an additional 10.0 but wonder whether that will do it. Another thing I could try is to take tap water and a lemon (or some other acid) to increase the acidity step by step. I have a normal pH meter too which I could use to track the values. I guess the measurements would then tell me more. The issue I have with this is that this still doesn't tell me what the resistors are for and how it should work. Maybe it's just a faulty module, who knows.
    – Jasper
    Nov 10, 2015 at 13:41

I can't ask a question but make sure you're giving it enough power for the heating element, its not much but you never know try a separate power source if you are not.

Now you mentioned the nano, are you using a 3.3v nano or 5V nano? (the regulator would have a 33 or 50 on it after a letter or two) if 3.3V and assuming by example code they give the analog output is 5V you'll need a level shifter of sorts to map to 3.3V, then change the calculations to use 3.3 instead of 5 value. if that's not the case and it's not power or connections then it may be broke or the probe etc.... there's a few variables.

  • Using a 5V nano. I've linked the module to both the 3.3V and 5V outputs, readings are the same.
    – Jasper
    Nov 11, 2015 at 6:58

USB power vs linked

Read it and use current Vcc instead of 5.0 in your code.

I have the same sensor and have the same problem. I'll be glad if you share full working code in this thread.

  • 3
    Please don't just post a link. The link might go down. If it has useful information in it, summarize it, or state it, here.
    – Nick Gammon
    Jan 12, 2016 at 5:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.