BBC micro:bit
MPRLS Pressure Sensor

Introduction

The Adafruit MPRLS Ported Pressure Sensor Breakout is a pressure sensor that has a little port that you can connect a tube to. The board costs around £14 and needs you to solder on some headers. The board works at 3V with the micro:bit over i2c and spits out numbers for you with far less work than some other pressure sensors need. The port is 2.5mm in diameter and it is easy to get some silicone tubing that will fit snugly over the port. This allows you to blow or sip air in or from the tube and get a reading on the sensor.

micro:bit circuit

In the image, I have the micro:bit in an Elecfreaks 'sensor:bit'. This board has a built-in buzzer on pin 0, which was used for one of the experimental programs on this page.

Programming

In this first program I was just trying to see what kind of readings I was going to get from the sensor. Using the REPL in Mu, I echoed them to the screen whilst I copied, converted and trimmed from the Arduino library that Adafruit have published.

from microbit import *

def _status():
    buf = i2c.read(0x18, 1)
    return buf[0]

def _raw():
    i2c.write(0x18,b'\xaa\x00\x00')
    a = _status() & 0x20
    while a:
        sleep(10)
        a = _status() & 0x20
    buf = i2c.read(0x18,4)
    a = buf[0]    
    if a & 0x01 or a & 0x04:
        return 0xFFFFFFFF    
    return (buf[1]<<16) + (buf[2]<<8) + buf[3]

def read_pressure():
    raw = _raw()
    if raw==0xFFFFFFFF:
        return -1
    psi = ((raw-0x19999A) * 25)/0xCCCCCC
    return psi

def hpa(p):
    return p * 68.947572932

while True:
    p = read_pressure()
    print(p,"PSI.",hpa(p),"hPA")
    sleep(50)

This second program was about detecting the sip and puff. I took a handful of readings to get a base from which to detect upward and downward changes in pressure.

from microbit import *

def _status():
    buf = i2c.read(0x18, 1)
    return buf[0]

def _raw():
    i2c.write(0x18,b'\xaa\x00\x00')
    a = _status() & 0x20
    while a:
        sleep(10)
        a = _status() & 0x20
    buf = i2c.read(0x18,4)
    a = buf[0]    
    if a & 0x01 or a & 0x04:
        return 0xFFFFFFFF    
    return (buf[1]<<16) + (buf[2]<<8) + buf[3]

def read_pressure():
    raw = _raw()
    if raw==0xFFFFFFFF:
        return -1
    psi = ((raw-0x19999A) * 25)/0xCCCCCC
    return psi

def hpa(p):
    return p * 68.947572932

    

def sip_puff(m,o):
    p = hpa(read_pressure())
    if p<(m-o):
        return -1
    elif p>(m+o):
        return 1
    else:
        return 0

display.show(Image.SURPRISED)
sleep(1000)
# average of 10 readings
mid = 0
for i in range(10):
    mid += hpa(read_pressure())
    sleep(100)
mid = mid / 10.0
print(mid)
display.show(Image.HAPPY)
sleep(1000)



last = 0
sp = ["Sip", "None", "Puff"]

while True:
    current = sip_puff(mid,30)
    if last!=current:
        print(sp[current+1])
    last = current
    sleep(50)        

Although the offset is fairly small, I found that I could comfortably trigger the sip and puff messages.

My final experiment was to see if performance was good enough to allow the sensor to be used for musical instrument purposes. The following program plays a note if the user puffs down the tube. Holding down the A button means you get a different note.

from microbit import *
import music

def _status():
    buf = i2c.read(0x18, 1)
    return buf[0]

def _raw():
    i2c.write(0x18,b'\xaa\x00\x00')
    a = _status() & 0x20
    while a:
        sleep(10)
        a = _status() & 0x20
    buf = i2c.read(0x18,4)
    a = buf[0]    
    if a & 0x01 or a & 0x04:
        return 0xFFFFFFFF    
    return (buf[1]<<16) + (buf[2]<<8) + buf[3]

def read_pressure():
    raw = _raw()
    if raw==0xFFFFFFFF:
        return -1
    psi = ((raw-0x19999A) * 25)/0xCCCCCC
    return psi

def hpa(p):
    return p * 68.947572932

    

def sip_puff(m,o):
    p = hpa(read_pressure())
    if p<(m-o):
        return -1
    elif p>(m+o):
        return 1
    else:
        return 0

display.show(Image.SURPRISED)
sleep(1000)
# average of 10 readings
mid = 0
for i in range(10):
    mid += hpa(read_pressure())
    sleep(100)
mid = mid / 10.0
print(mid)
display.show(Image.HAPPY)
sleep(1000)

while True:
    current = sip_puff(mid,30)
    if current==1:
        if button_a.is_pressed():
            music.pitch(440,-1)
        else:
            music.pitch(494,-1)
    else:
        music.stop()
    sleep(20)     

This last program worked a lot better than I thought. I was using the pressure sensor as a straight on/off switch and it proved pretty easy to start, stop and sustain the notes. The use of the button made the experience a little like covering up finger holes whilst blowing into a whistle. The sensor works well enough to make more projects like this possible.

Review

It's not a cheap sensor but it does its job really well. Getting clear readings that make sense is a lot easier than I have found with other pressure sensors and the code I have written could be trimmed a lot more. The reading of the status register is not as essential to the process as I thought it might be.

With the setup that I had for these projects, I could comfortably vary the reading by around 100 - 120 hectopascals, sipping as well as puffing. I have not yet established the extent to which a user can feel completely in control of that pressure though. For a project where that mattered, it might be worth looking more carefully at the range of the sensor and trying to find one that gives more resolution around the pressures that a user can generate.