, ,


In a previous post (link), I was happy with the voltage reading results I was able to get from a test environment in which the value being measured – a DC voltage from a voltage divider – had a very low impedance.  As discussed earlier (link), pH probes have a very high impedance.  Too high to be measured with a DMM.  So one handy debugging tool is no longer available…..in this post I will test hooking up a pH probe submersed in 3 pH calibration solutions for pH levels 4, 7, and 10.


The Goal

The goal of this post is to determine how close voltage measurements recorded from a pH probe submersed in a pH calibration solution to expected values.  I look at it as a litmus test for whether I should go to more specific pH testing including probe calibration and pH measurement of a bath relative to the minipH and Atlas-Scientific pH stake.

Thanks to Those That Went Before

  • I constantly – and rightly – thank Chris Gammell.  Chris has been an exceptional mentor/guide as well as provides the Contextual Electronics courses that I took.  I have learned more from Chris’s courses, the other students, and Chris than I have through any other learning process.  For a person that loves to learn new things – that says A LOT!
  • Ryan (Sparky’s Widgets) open sourced and provided background on his minipH breakout board.  The Healthy pH Shield is based on Ryan’s work.  In addition, Ryan has kindly answered my questions.  Answering questions from a n00b like me is very time consuming.  It shows the openness and dedication to learning/community.  I highly recommend Sparky’s Widgets.
  • We’ve all benefit from the tremendous amount of shared knowledge folks have posted on the web. This post is no exception.  Google is my friend.  

The Test

I do not expect to get accurate pH readings.  This requires calibration of the pH probe (discussed here) and adjustment for the bath’s temperature.

I do expect to get voltage readings that are within the values I expect for pH 4, pH 7, pH 10.  I need more testing to know if a repeatable reading is “good enough” to determine the pH reading or precise readings are important.  My current knowledge makes me think that given the high impedance of the pH probe and the noise in the circuit, there will be a higher STDEV in results than I would like.  This then goes to the smoothing technique.  My current technique is to take multiple readings multiple times and then average the averages.

Table of pH values Mapped to Their Voltage Values

In this post (link) I had a table that listed the voltage reading for each pH level.

pH Signal(s)
0 0.414
1 0.359
2 0.309
3 0.249
4 0.189
5 0.129
6 0.069
7 0.009
8 -0.069
9 -0.129
10 -0.189
11 -0.249
12 -0.309
13 -0.369
14 -0.419

I am interested in pH 4, 7, and 10.  Here is a table of results:

pH Expected Volts Measured Volts, n=25 STDEV Measured Volts, n=50 STDEV Measured Volts, n=100 STDEV
4 0.189 0.16 0.1 0.17 0.1 0.17 0.1
7 0 0.03 0.08 0.01 0.09 0.02 0.08
10 -0.189 -0.14 0.09 -0.14 0.09 -0.14 0.09

Plotting the ideal line and drawing a line between the points that were measured:


the measurements appear close!  This is without adjusting for temperature or taking into account the current quality of the probe.  A very very excited YIPPEE! But of course – it is the last 20% of a project that takes 80% of the time and work.  Still, I have a big smile on my face (for at least one minute 🙂 ).

 Reading just one value would be too noisy so I took a variety of readings.  The first time, I averaged 25, then 50, then 100.

Negative Numbers and 24 Bits

Previous tests assumed adc values would be positive.  pH voltage values range from +/- .414V.  I changed the test code to handle negative values.

A challenge I had due to my lack of background in computer science, was reading negative numbers.  As pointed out in the MCP3901 data sheet – Section 5.6 – negative numbers are stored in two’s complement.  This would be easy-peasy if I was dealing with a 32 or 16 bit value.  But the adc value is 24 bits.  Perhaps there is an easier way, but I translate a 24 bit negative adc value into a 32 bit value doing the following:

    //start with the 2nd byte since this is a 24 bit number and bit twiddling is needed if the number is negative.

    for (byte i=1;i<4;i++){

        adc_value_bytes[i] = SPI.transfer(0xFF);


#define CHECK_BIT(var,pos) ((var) & (1<<(pos)))

    if (CHECK_BIT(adc_value_bytes[1],7)) {

        adc_value_bytes[0]  = 0xFFFF;

        adc_value_bytes[1] &= ~0x8000;


    adc_value =   (long)adc_value_bytes[0] << 24 | (long)adc_value_bytes[1]<<16 | (long)adc_value_bytes[2] << 8  | (long)adc_value_bytes[3];

See the code at this GitHub location – it includes all of the above in the MCP3901 library.


As a litmus test, I am happy with these readings.  While they are not accurate enough to determine the pH level with .1 accuracy, the voltage readings are “close enough” to tell me the voltages are being recorded.  What I do not know is what is causing the voltage readings to be the STDEV they are.  And why the values aren’t equivalent to the expected values.  I am ok with the results for the rev of the Healthy pH Shield.  I will do further testing and refinement in future revs.  I have enough to change in this rev to move incrementally to better results.  This will give me spacing in the testing process to figure out how to improve results

Thanks for reading this far.  Please find many things to smile about!