Sunday 14 June 2020

BBC Micro:Bit Menu system (with persistent choice)

The BBC Micro:Bit is a simple microcontroller with a 5 x 5 matrix of LEDs, two buttons, 3D magnetic and acceleration sensors and a CPU temperature sensor.
The two buttons can make complicated interfaces rather difficult, however it is possible to build one.
One aadditional feature of this menu system is that your choices are persistent. If you select menu item, power off the Micro:Bit then subsequently power it back one, it will remember the choice (subject to it not being reflashed of course).

Code

This was written in Micropython using the Mu editor.
from microbit import *
import os
import utime
menuitem = 0
if 'choice.opt' in os.listdir():
    with open('choice.opt') as choice:
        menuitem = int(choice.read())
display.scroll("Menu item" + str(menuitem))
start = utime.ticks_ms()+6000
interval = 2000
while True:
    now = utime.ticks_ms()
    if start > now or now - start > interval:
        if menuitem == 0:
            temp = temperature()
            interval = 2000
            display.scroll(str(temp) + 'C', delay=100, wait=False)
        elif menuitem == 1:
            temp = temperature()
            interval = 2000
            display.scroll(str(temp + 273.15) + 'K', delay=100, wait=False)
        elif menuitem == 2:
            level = display.read_light_level()
            interval = 2000
            display.scroll(str(level) + ' light', delay=100, wait=False)
        elif menuitem == 3:
            level = compass.get_field_strength()
            interval = 6000
            display.scroll(str(level) + ' nTesla', delay=100, wait=False)
        elif menuitem == 4:
            display.scroll("Menu test")
        start = now 
    if button_a.is_pressed():
        display.scroll("Menu", delay = 100)
        sleep(50)
        while not button_a.is_pressed():
            display.set_pixel(4,menuitem,5)
            if button_b.is_pressed():
                display.set_pixel(4,menuitem,0)
                menuitem = menuitem + 1
                if menuitem > 4:
                    menuitem = 0
                with open('choice.opt','w') as choice:
                    choice.write(str(menuitem))
                display.scroll("Menu item" + str(menuitem), delay = 100)
            sleep(100)
            display.set_pixel(4,menuitem,5)
            sleep(100) 
    sleep(400)
The persistent choice is handled by this code:
menuitem = 0
if 'choice.opt' in os.listdir():
    with open('choice.opt') as choice:
        menuitem = int(choice.read())
The menu item is given a default value (0).
The file 'choice.opt' is checked if it exists in the directory list, if it is, then the value of the menu item is read from the file and assigned to the menuitem variable. When a subsequent decision is made to change the menuitem, this value is written out to the file, making it available the next time the Micro:Bit is switched on.

The main loop is entered after the start variable is set in advance of the current tick count and the display interval is set (strictly speaking the interval should be dependent on the menu choice but it only affects the first cycle).

Each loop, if the difference between the ticks now and the (loop) start ticks is greater than the interval, then the menuitem is used to choose what to do.
In this example it is used to choose which sensor is read and the results displayed.
Menu choices are:

  1. Temperature in degrees Celsius.
  2. Temperature in Kelvin
  3. Light level (based on the light falling on the LED matrix)
  4. Magnetic field strength in nanoTesla (using the compass module)
  5. A message.
The first three keep the interval at two seconds, but the magnetic field strength is a longer piece of text, so that is stretched to six seconds by setting the interval.
The Start ticks value is set to the Now value.

The next part of the code checks for the A button (left side) being pressed.
If so, it then loops until the button is pressed again.
Inside that loop, pressing the B (right hand) button increments the menuitem value, writes it to the file and shows a pixel on the right hand column indication which option is currently chosen.
Pressing button A exits the loop and recommences the outer infinite loop.

Disadvantages

This does mean that during normal operation, button A is not available. This might not be an issue but is something to bear in mind.

References


Saturday 13 June 2020

Pimoroni Envirobit

Pimoroni Envirobit


The Pimoroni Envirobit is a set of sensors for the BBC Micro:Bit .


As you can see, it is equipped with a slot to take the Micro:Bit, so no soldering is required.

The Envirobit is fitted with the following sensors:

  • BME280 environmental sensor - which measures temperature, pressure, humidity and can calculate the altitude based on a supplied base pressure level (discuss).
  • tcs3472 RGB sensor - which measures Red Green and Blue light levels as well as “white” light levels. Also includes two illuminating (white) LEDs,
  • Sound - a small microphone allows the sound level to be measured on one of the Micro:Bit’s analogue pins

Assembly

Assembly is simple. Take the Envirobit board with the sensors facing forward, and insert the Micro:Bit with the LEDs also facing forward.
Due to the nature of the connection, you can swap the Microbits if the colour scheme does not match your needs.

Software

The main software support for the Envirobit is orientated towards the Microsoft MakeCode block based system.
There is some support for MicroPython. There is a GitHub link here: https://github.com/pimoroni/micropython-envirobit

There are three python files in the Library.
  • sound.py
  • bme280.py
  • tcs3472.py

The files can be transferred to your Micro:Bit using the Files function in Mu.

Sound

Contrary to the description on GitHub, this is not a class, just three methods.

  • sound.read() - This takes a reading of the sound level and returns a value between 0 and 440. There is an offset value in the code to set the minimum sensitivity.
  • sound.wait_for_double_clap() - listen for two high level sound events in a second, returns True if detected
  • sound.wait_for_clap() - listen for a single high sound level event in a second, returns True if detected

tcs3472

This uses a class to access the TCS3472 sensor via I2C.
To use the sensor, import the module (having transferred it to the Micro:Bit) and instantiate an instance.
import tcs3472
light_sensor = tcs3472.tcs3472() 
Methods:

  • r, g, b = light_sensor.rgb() - returns a tuple of the corrected levels of red, green and blue out of 255
  • r, g, b = light_sensor.scaled() - return a tuple of the amounts of red, green and blue on a scale of 0-1
  • level = light_sensor.light() - return a raw reading of light level on a scale of 0-65535
  • light_sensor.set_leds(0) - Turn the LEDs off
  • light_sensor.set_leds(1) - Turn the LEDs on

BME280

This uses a class to access the BME280 sensor via I2C.
The instructions on GitHub are incorrect, there is a missing () on the end of the class instantiation. Python can be very unforgiving if you make a mistake of this kind.
import bme280
bme = bme280.bme280()

The bme280 class has the following methods:

  • temp = bme.temperature() - return the temperature in degrees C
  • pressure = bme.pressure() - return the pressure in hectopascals
  • humidity = bme.humidity() - return the relative humidity in %
  • alt = bme.altitude() - return the altitude in feet, calculated against the current QNH value
  • bme.set_qnh(value) - set the QNH value for calculating altitude

QNH is the atmospheric pressure adjusted to sea level (what the pressure sensor should read at sea level).
https://en.wikipedia.org/wiki/QNH

References

https://github.com/pimoroni/micropython-envirobit
https://en.wikipedia.org/wiki/QNH