CC Blog Design Solutions Projects Research & Design Hub

Under Pressure?

Figure 1 I was a bit surprised to find that a digital pressure/vacuum sensor (-1bars to +2bars, or about -15psi to +30psi) was available for less than $20. This has three connections: +5V, ground, and Vout. Full scale has a nominal output of between 0.5V and 4.5V. Voltages outside this range may be interpreted as an error. A mechanical gauge for the same range was less than $16.
Written by Jeff Bachiochi

May the Force Be with You

Electronic pressure sensors detect critical pressure changes in applications as varied as automobile engine oil pressure and airflow in clean rooms. Using an electromagnetic vaccum/pressure sensor and a PIC16F18313 microcontroller (MCU), in this month’s project, I build an I2C peripheral for monitoring the backwashing cycles of the filtration/softening system in a well water tank. 

  • How can I use an MCU to monitor my well water tank?
  • What are some uses of an electronic vacuum/pressure sensor?
  • Digital pressure/vacuum sensor
  • PIC16F18313 microcontroller

There was a time when the inside of your automobile looked like the cockpit of an airplane. There were gauges all across the console, including a tachometer, a speedometer, water temperature, oil pressure, and battery amps. These assured the driver that all was well with the internal combustion power plant under the hood. 

It seems like overnight, all of that disappeared and was replaced with a “check engine” idiot light. While many mechanical, electrical, pressure, and temperature sensors are still implemented, all sensor information is now relegated to the vehicle’s electronic control unit. You need an on-board diagnostic-II (OBD-II) reader to dump error codes, and then you still have to decode the error codes to get a hint of the problem. It used to be that when you opened the hood, you saw the motor and a lot of ground beneath the engine. Today you can’t see the ground, because every possible nook and cranny carries some kind of gadget, doodad, and gizmo.

The oil pressure gauge was my first introduction to this kind of sensor. Electronic pressure sensors generally use a force collector, such as a diaphragm, piston, or bellows, to measure strain (or deflection) due to the applied force. The force might be a liquid or a gas; in this case the liquid was oil. Proper oil pressure ensured that your engine was getting the life-saving oil that would keep its parts from freezing up due to friction/heat. Among the technologies are piezoresistive strain gauge, capacitive, electromagnetic, piezoelectric, strain gauge, optical, potentiometric, and force balancing.

In this month’s project, I developed an I2C peripheral for my well water tank—using a PIC16F18313 microcontroller (MCU) and an electromagnetic pressure sensor. I needed it to monitor vacuum and pressure, to ensure that the tank’s filtration/softening system was being backwashed properly.

ELECTROMAGNETIC PRESSURE SENSOR

Many of today’s pressure sensors fall into the electromagnetic category. They measure the displacement of a diaphragm by means of changes in inductance (reluctance), a linear variable differential transformer (LVDT), the Hall effect, or by the eddy current principle. 

I’ve used a pressure gauge in the past for measuring the water pressure in a water tank. Monitoring the water tank’s pressure gives me a whole lot of information. The water pump’s regulator should turn on the water pump when the tank’s pressure falls to 40psi. It remains on until the pressure in the tank reaches 60psi. Under normal conditions, the tank pressure should never exceed 60psi or fall below 40psi. If it exceeds 60psi, there must be something wrong with the pressure regulator. If it falls below 40psi, there must be something wrong with the pump. The pump’s ON time tells me the efficiency of the pump, whereas the pump’s OFF time tells me how much water is being used.

I bought the pressure sensor (Figure 1) on Amazon for less than $20. It’s been working fine. This sensor incorporates a pressure deflected diaphragm with a magnet attached. The diaphragm deflects toward a Hall-effect element when pressure increases. Hence, the output voltage produced is proportional to the pressure applied. There is a bit of analog circuitry along with Hall-effect devices to amplify (scale) the output and move (offset) the range. In this case, when there is zero pressure, the offset is set to 0.5V. At 100psi the scale sets the output to 4.5V. This means that the output ranges from 0.5V to 4.5V, when the pressure goes from 0psi to 100psi. That’s a 4V span for 100psi, or 0.04V/psi. Therefore, 40psi will equal 0.5V + (40psi x 0.04V/psi) = 2.1V, and 60psi equals 2.9V.

Figure 1
I was a bit surprised to find that a digital pressure/vacuum sensor (-1bars to +2bars, or about -15psi to +30psi) was available for less than $20. This has three connections: +5V, ground, and Vout. Full scale has a nominal output of between 0.5V and 4.5V. Voltages outside this range may be interpreted as an error. A mechanical gauge for the same range was less than $16.
Figure 1
I was a bit surprised to find that a digital pressure/vacuum sensor (-1bars to +2bars, or about -15psi to +30psi) was available for less than $20. This has three connections: +5V, ground, and Vout. Full scale has a nominal output of between 0.5V and 4.5V. Voltages outside this range may be interpreted as an error. A mechanical gauge for the same range was less than $16.

I created an I2C peripheral to monitor the pressure sensor’s output voltage (Figure 2), using a PIC16F18313, an 8-pin microcontroller (MCU) that has an integrated 10-bit ADC. At its 5V working voltage, the ADC has a resolution of 5V/1,024bits = 4.88mV/bit—that’s almost a resolution of 0.1psi. It looks like I really only needed seven bits to achieve a 1psi resolution. One byte will handle the required psi measurement. 

Figure 2
The PCB in my project is sized to fit a Hammond 1551S. This plastic enclosure has handy mounting tabs.
Figure 2
The PCB in my project is sized to fit a Hammond 1551S. This plastic enclosure has handy mounting tabs.

Using an MCU with only eight pins is perfect for this application. We have power, ground, reset, two I2C pins (SCL and SDA), two programming pins (PgmD and PgrmC), and Vin. Actually, reset and the two programming pins can be reassigned once the device has been programmed, giving an input pin (reset) and two additional I/O pins. I used one of the programming pins as a TX output, used for a serial 4×20 LCD. This gives the circuit a stand-alone quality, since I can display the present measurement. I don’t even have to bit-bang a serial port, since the PIC16F18313 also has a UART!

As can be seen in Figure 1, the pressure sensor has a 1/8” National Pipe Taper (NPT, ~1.8 degrees on axis) connection to the water supply. Note that the dimension stated is an inside hole size. The threads are actually a tapered 3/8” outside diameter (OD. A waterproof connector tops the sensor. The three leads are +5V (red), ground (black), and Vout (other).

NEW PROBLEM

I wrote the preceding introduction as background to preface a different issue. My well water has a high iron content, and I have installed a separate filter and softener to remove the iron and other trace elements. The filter and softener use different media that attract the substances I wish to have removed—basically iron and magnesium. The medium can attract or collect only so much, and then it has to be cleansed. The cleaning process uses separate chemicals for each medium, which act to release the collected particles, allowing them to be backwashed (rinsed) out of the system. 

For this to happen, you must program a backwashing cycle to occur when necessary. It can be based on water used or days between cycles. Backwashing is generally performed overnight, while the system is idle. It occurs in four cycles—backwash, brine draw, rinse, and brine refill. The brine is in a separate container that holds a solution of water and a chemical agent. 

The first cycle disconnects the supply output (preventing anything in the filter/softener from getting into the water main). Then it runs water backward though the medium to loosen it up. Water exits to the septic system. The second cycle draws brine from the chemical tank through the medium. This reaction releases particles, and they exit to the septic system. The third cycle shuts off the brine draw, and sends water through the medium to rinse off all of the chemicals and exit to the septic system. The fourth cycle returns water to the chemical tank to prepare for the next backwash. These four cycles last about 10 minutes each, except for the brine draw (soaking of the medium with brine), which lasts about an hour.

This sounds pretty simple, and it is, but in two of the cycles, some special things are going on. The brine draw and brine refill both take place via the same 1/4” piping. This means that brine is sucked from the brine tank to the medium tank, and then water is forced back into the brine tank during brine refill. In the filter/softener, a venturi tube is used to create a vacuum from the flow of water through a restricted opening. This vacuum draws liquid from the chemical tank. During the brine refill, cycle water is forced back into the brine tank. To prevent overfilling, the brine tank has a float valve that shuts off the water flow when the float rises to a predefined level.

As you can see, the brine tank pipe should be under vacuum during the second cycle and under pressure during the fourth cycle. To monitor this, we need to have a meter or sensor that can show both vacuum and pressure. Why monitor these? The system relies on the periodic backwashing to keep the medium clean and able to provide filtered and softened water. If something goes wrong with this, the backwashing will not be effective or may not occur. A clog could prevent the venturi from drawing in brine. By monitoring for correct vacuum and pressure during these cycles, we can be notified of a problem before too many unclean cycles can accumulate.

NEW EQUIPMENT

Much to my amazement there are both mechanical and electrical combination gauges for vacuum and pressure. These handle a vacuum of -1bar to a pressure of +2bars. The bar and the millibar were introduced by the Norwegian meteorologist, Vilhelm Bjerknes, for use in the practice of weather forecasting. A bar is roughly the Earth’s atmospheric pressure at an altitude of 111 meters and a temperature of 15°C. The bar’s equivalent in the avoirdupois system is: 1bar = 14.50377psi. So these items measure a vacuum from -15psi to a pressure of +30psi. 

This seems to be the only combination range sensor I’ve found available. I’m charting undiscovered territory here. I know that most of these gauges can handle 2x over-pressures; but I have no idea what the system creates to handle the backwash flows, so I’ll proceed with the understanding that I could be taxing the devices.

From the 0psi to 100psi gauge we know that the output will be from 0.5V to 4.5V or a 4V span for 100psi. This new gauge is bipolar. It has a -15psi to +30psi span—so that 4V span now covers 45psi. I use the ADC conversion value to calculate the voltage and the pressure in psi. I’ll display both calculated results to make it most useful. The code previously used to display the tank pressure will be expanded to add a second analog input for the new pressure gauge. Figure 3 is the schematic of the monitor.

Figure 3
A second analog input has been added to the original I2C remote device that accepted input from a 0-100psi digital pressure sensor. The second sensor input is now used for the new digital pressure/vacuum sensor.
Figure 3
A second analog input has been added to the original I2C remote device that accepted input from a 0-100psi digital pressure sensor. The second sensor input is now used for the new digital pressure/vacuum sensor.

Let’s briefly go over converting the sampled ADC value to a voltage based on the +5V operating voltage. The 10-bit ADC is capable of a resolution of 5V/1,024bits. This means every bit is worth 4.883mV. To convert the ADC value we must multiply it by the resolution. I avoid floating-point routines whenever possible, because they take up a ton of precious program space in small MCUs. In contrast, integer routines require you to choose the appropriate routines and use variables of sufficient size to support the calculation required. Our 10-bit value will vary from 0 to 1,023, so it will require a word variable (16bits). To retain as much accuracy as possible, I’ll use the (decimal) value 4,883µV, which also needs a word variable (0x1313). This means the routine required for multiplying these will be a 16-bit x 16-bit multiple.

The PIC16F18313 being used here has assembly routines available from Microchip for math functions [1]. It’s easy to use, but requires its own set of variables. As shown in Table 1, you place numbers you want to multiply in the 16-bit registers AARGB0:1 and BARGB0:1, and make a call to the routine FXM1616U. Note that when you multiply 0xFFFF x 0xFFFF, the maximum values that fit in a 16-bit word, you can get a 32-bit answer. This means that the result must use a 32-bit variable, in this case AARGB0:3 (where the MSB—most significant byte—is stored in AARGB0.) 

Table 1
Registers AARGB0:3 and BARGB0:1 are used to hold the "Conversion Value" and "ADC resolution" prior to making a call to the multiplication routine FXM1616U. When the routine exits, the result is left in these registers.
Table 1
Registers AARGB0:3 and BARGB0:1 are used to hold the “Conversion Value” and “ADC resolution” prior to making a call to the multiplication routine FXM1616U. When the routine exits, the result is left in these registers.

In this case, the largest values will be 1,023 and 4.883mV, which result in the value 4,995.309mV or 4.995309V. I am displaying numbers as 5-decimal digits (16-bit word), so I need to divide the result by some factor of 10 to get to a reasonable number. I think that millivolts is plenty of accuracy. This means that the result will be in the format 04995. (I’ll talk about the use of a decimal point in just a second). First, we need to divide this result by 1,000, to get a word value of 4,995. Because I know that the result (4,995,309) won’t be greater than 24-bit, I can use a 24-bit/16-bit routine for this. The result of the last division is still in AARGB0:3, so I move the least significant 24bits of the 32-bit result into the AARGB0:2 registers, load BARGB0:1 with the divisor 1,000, and call FXD2416U (Table 2).

Table 2
Registers AARGB0:3 and BARGB0:1 are shown holding the result of the FXM1616U routine. The three LSBs must be shifted to set up for a divide. The "Result Value" and the "constant 1000" become the inputs to the routine FXD2416U. When the routine exits, the new result is left in these registers.
Table 2
Registers AARGB0:3 and BARGB0:1 are shown holding the result of the FXM1616U routine. The three LSBs must be shifted to set up for a divide. The “Result Value” and the “constant 1000” become the inputs to the routine FXD2416U. When the routine exits, the new result is left in these registers.

This new result is a 16-bit result, with a remainder in AARGB2—which I don’t need. Note that the remainder is a fraction consisting of the remainder over 256. The whole part of that division is then saved into my 16-bit voltH:L register pair. This is the value I will display. 

GETTING TO THE POINT 

Now let’s finish the decimal point discussion. To display some number, I use a routine to evaluate a register value in HEX and convert it to a decimal number for display. Since register values are hexadecimal, we need to perform some division on the register value to create ASCII decimal digits. A byte hexadecimal value is made up of two nibble digits 0-F. I want to display the equivalent in decimal, 0-255. To do this I use 3-byte registers to hold the digits, called Digit0:2. These will hold the ASCII values for the three digits that make up the decimal value. To fill in these values, pass the byte to be converted in register Value, to the ValuesToDigits routine.

This routine will divide Value by 10 to get the hundredths digit, and the remainder is divided by 10 to get the tenths digit, with the remainder becoming the ones digit. In each of these sections we end up with a number from 0-9. Before moving these to the Digit0:2 registers, make them printable (ASCII) by adding 0x30 to each. They have now become printable digits from 0x30-0x39. The routine is easily expanded to handle words (16-bit values) by increasing the resulting digits to 5, Digit0:4. This also requires more complex routines than the FXD0808U division routines, because we are now dealing with larger, 16-bit numbers.

Our digit registers values can be plugged directly into the appropriate positions in the print routine buffer TXBufferwithout further conversion. So what about a decimal point? We actually can make several additions to the DisplayDigits routine that add our digits to the TXBuffer. The TXBuffer is a ring buffer that holds the messages we want to display on the LCD. It is long enough to hold a complete line of text. The simple DisplayDigits routine will just add Digits0:4 to the TXBuffer. We can add more code to this routine to allow formatted numbers to be displayed. 

The decimal alteration to this routine uses a new byte variable, DecimalPoint, to determine where a decimal point, if any, is to be added into the TXBuffer. I use the bit positions to indicate this. If DecimalPoint equals 00000000b, then no decimal points are added. If DecimalPoint equals 00000010b, then a decimal point is added between the last two digits, xxxx.x. We make bit tests before and after each digit and add a 0xE2 (decimal point) where necessary.

Although we haven’t seen it yet, the next conversion we will be talking about can be positive or negative. So, the next addition to this routine is to see if Value has its MSB set. This indicates that this is a negative number. If it has been set, then we need to add a 0x2D (minus sign) to the TXBuffer before adding the digits. Note that you may wish to add 0x2B (plus sign) when the Value is positive, just to be consistent with values that have a polarity associated with them. We don’t want to display this bipolar negative number as it stands—that is, 65,535 (0xFFFF) signifies -1, but change it to a positive number, since we are displaying a minus sign. Use the 2’s complement, complement the value and add 1 to it, in order to convert a signed negative number to its positive equivalent to be used with a minus sign. For 0xFFFF, this becomes 0x0000 + 1, 0x0001. Along with the minus sign, it will be displayed as -00001. You might want to remove any zeros before a digit between 1 and 9. It presents a value a little more cleanly, but I chose not to include this feature.

Pressure or vacuum

Let’s finish up with a little discussion of the conversion from ADC value to pressure in psi. Under normal use, all the pressure sensors have a legal output between 0.5V and 4.5V. It is possible that if a sensor is stressed, breaks, or is removed, the voltage presented at the ADC input could be outside these boundaries. For this reason, we need to be able to handle inputs between 0V and 5V. A 0-100psi sensor will output 0.5V at 0.0psi. Zero volts will therefore mean less than 0.0psi, or a negative pressure. If we extrapolate (linearly) what the pressure would be for 0V to 5V, we find:

5.0V = 112.5psi

4.5V = 100psi

4.0V = 87.5psi

3.5V = 75psi

3.0V = 62.5psi

2.5V = 50psi 

2.0V = 37.5psi

1.5V = 25psi

1.0V = 12.5psi

0.5V = 0psi

0.0V = -12.5psi

We see that even the 0-100psi sensor must be interpreted as having a negative pressure (vacuum) at 0V. This is obviously true with the new sensor (-15psi to 30psi, seen in Figure 4) that I am using for this project:

5.0V = 35.625psi

4.5V = 30psi

4.0V = 24.375psi

— ADVERTISMENT—

Advertise Here

3.5V = 18.75psi

3.0V = 13.125psi

2.5V = 7.5psi

2.0V = 1.875psi

1.5V = -3.75psi

1.0V = -9.375psi

0.5V = -15psi

0.0V = -20.625psi

Here, the span of 0.5V is equal to a range of 5.625psi. Since the sensor is -15psi at 0.5V, it would be -15 minus 5.625 or -20.625psi at 0.0V. With a full-scale ADC conversion of 0-1,023 for 0V to 5V, we need to use the full-scale vacuum/pressure span of -20.625 to 35.625 or 56.25psi. This span divided by the ADC resolution is 56.25/1,024bits or 0.054931640625psi/bit. We can use the same routines here as we did above when we calculated the voltage. We will end up with a pressure that is from 0 to 56.25psi. But in the list above, the maximum (5.0V) should be 35.625psi. What gives? We are forgetting the offset of the sensor. It doesn’t start at 0psi—it starts at -20.625psi. If we subtract this offset from 56.25 we get 35.625psi. 

Figure 4
It took two trips to the hardware store and the better part of a $50 bill to purchase all the necessary fittings to connect the digital and mechanical sensor to the 1/4” plastic pipe that goes between the water softener or filter to its external brine tank. Since this 1/4” pipe has a vacuum to suck brine, and pressure to refill the brine tank, the sensors must withstand both vacuum and pressure.
Figure 4
It took two trips to the hardware store and the better part of a $50 bill to purchase all the necessary fittings to connect the digital and mechanical sensor to the 1/4” plastic pipe that goes between the water softener or filter to its external brine tank. Since this 1/4” pipe has a vacuum to suck brine, and pressure to refill the brine tank, the sensors must withstand both vacuum and pressure.
AD HOC PLUMBING 

The plumbing between any filter/softener tank and its associated brine tank is a 1/4” plastic pipe. I will be adding the sensor to this pipe with the aid of a T fitting. Cut the plastic pipe where you want to add the sensor. These two ends are reattached to either side of the top of a 3/8” T-compression fitting. The bottom of the T becomes the stub at which our sensor can be attached. You can see in Figure 4 that I added the digital sensor and a mechanical gauge to the stub using a second T. But this T uses NPT-standard, tapered connections, and as such, pipe dope or Teflon tape is used on each joint. Just a quick note on costs: The brass fittings used here cost more than both sensors. 

Although the LCD makes a nice stand-alone sensor, the installation will use the I2C bus as the communication medium. Once the sensor is permanently installed, the LCD will be removed, since all sensor information is collected and displayed elsewhere. For the (vacuum) test in Figure 4, the LCD is used along with the mechanical gauge to verify that the digital sensor is working correctly. Even though only the pressure and vacuum need to be displayed, having the ADC conversion value along with the computed sensor voltage allows conversion computations to be verified without any other test equipment.

CONCLUSION

Three PCBs for this project were about $16, with the total parts cost for each board under $20. The PIC16F18313 MCU was developed in assembler using Microchip’s free MPLAB-X IDE and the low-cost PICkit 3 debugger. I enjoy the speed of developing with the Arduino IDE, but for a small, code-efficient project I still prefer getting down to the register-level programming with assembler. Now that Microchip owns Atmel, they have integrated the Atmel processors into MPLAB-X IDE, so you can use Microchip tools for Atmel MCUs.

My monitoring software (Node-RED) already reports when one of the softeners or filters goes through a backwashing service. The CAMs positions that push the valves to create the four backwash cycles are already being monitored. Now the new vacuum/pressure sensor will indicate if the brine is moving properly to keep the system clean. I love solving problems to make life easier. After all, there is so much to do, and so little time. 

REFERENCES
[1] Microchip’s Application Note AN617, Fixed Point Routines
https://www.microchip.com/en-us/application-notes/an617

Code and Supporting Files

PUBLISHED IN CIRCUIT CELLAR MAGAZINE • FEBRUARY 2023 #391 – Get a PDF of the issue

Keep up-to-date with our FREE Weekly Newsletter!

Don't miss out on upcoming issues of Circuit Cellar.


Note: We’ve made the Dec 2022 issue of Circuit Cellar available as a free sample issue. In it, you’ll find a rich variety of the kinds of articles and information that exemplify a typical issue of the current magazine.

Would you like to write for Circuit Cellar? We are always accepting articles/posts from the technical community. Get in touch with us and let's discuss your ideas.

Sponsor this Article
Website | + posts

Jeff Bachiochi (pronounced BAH-key-AH-key) has been writing for Circuit Cellar since 1988. His background includes product design and manufacturing. You can reach him at: jeff.bachiochi@imaginethatnow.com or at: www.imaginethatnow.com.

Supporting Companies

Upcoming Events


Copyright © KCK Media Corp.
All Rights Reserved

Copyright © 2024 KCK Media Corp.

Under Pressure?

by Jeff Bachiochi time to read: 15 min