# Particle hardware: PCF8574

See details about the PCF8574 board in the Micro:bit notes.

Write example, sets all inputs high then low:

``````#include <Wire.h>

void pcfSend(int a, unsigned int d) {
Wire.beginTransmission(a);
Wire.write(d);
Wire.endTransmission();
delay(100);
}

void setup() {
Wire.begin();
}

void loop() {
delay(1000);
delay(1000);
}``````

# Project: A Micro:bit calculator

Using a 4×4 keypad and a 16×2 LCD screen, can you construct a simple calculator?

Step 1: Connect up the hardware. Review the notes on keypads and LCD screens, make sure you understand how they work, connect them up and run some test programs. Both should be able to connect to pins 19 and 20 (the I2C pins) and operate independently.

Step 2: Can you make what you type appear on the screen, one character at a time? What about using * to clear the screen?

Step 3: Start with a very simple calculator that will accept a single digit, use A-D for +,-,x and ÷, then calculate on the second digit pressed. Show the input on the top line and the answer on the second. Tip, you will find the function int(string) useful for converting strings to integers.

Step 4: Make the calculator more advanced. Allow you to put in multiple digit numbers, then use the # key for an =. You will need to break down the string into variables for each part. There is a list of string functions at w3schools. What might be useful is the split() function. Remember you can make a note of which operator is used as it is pressed. This avoids having to search the string for operators, or you could use the find() function.

# Micro:Bit More IO pins (PCF8574), binary and hex

The Micro:bit comes with 20 IO (input/output) pins which can be used to connect a range of hardware devices, however if you look at a pinout diagram, you find that 8 of these are used by the LED display and the buttons. If you start using devices which require a lot of pins (such as keypads), then you can quickly run out of usable pins.

One solution is to use devices such as PCF8574 modules which connect to the I2C (19 and 20) pins and will provide 8 additional pins. As you can connect multiple devices to I2C, you can either add more pin expansion modules or other types of device. For example, with a keypad attached to a PCF8574 and an I2C LCD screen, you can attach both to the Micro:bit and only use pins 19 and 20.

When all onboard switches are set to off, PCF8574 modules usually use the I2C address 0x20. If we connect LEDs to the first six pins of a module (P0 to P5) with 220 or 330 ohm resistors to ground on the other side (as pictured below). Build this circuit but ignore the buttons for now. We can flash all six LEDs with the following code:

``````# Testing of a IO expanded - PCF8574
from microbit import *

# I2C send, function to simplify writing
# Convert sent value to a byte array, which is
# required for I2C
buf = bytearray(1)
buf = value
# Send value
# Short delay to send
sleep(5)

while True:
sleep(1000)
sleep(1000)``````

What is going on here? The PCF8574 has 8 IO pins labelled P0 through to P7. If we want to set the output to one of those pins to high, we need to send it a 1, or a zero to be low. Where as with the normal Micro:Bit IO pins, we set them individually, with the PCF8574, we set them all in one go by sending a single byte containing all the information we need. An I2C write to the modules address with the value 0xFF means send all 1s, or turn all the IO pins on. Sending 0x00 means turn all the IO pins off. The above code flashes all the LEDs.

To really understand what is happening and have greater control of the LEDs, we need to understand binary and hexadecimal.

### Understanding binary

Binary is another way of counting. We are used to using the numbers 0 to 9 (known as decimal), but in binary we only use 0 and 1. There is a BBC Bitesize module which gives a lot more information into understanding binary. Here we have a very brief description.

In decimal counting, a single digit 0 to 9 is not a lot of use if we want to count higher than 9. To go higher, we use the same digits again, arranged into columns increasing in value as we go from right to left. We start with units, then tens, hundreds, thousands and so on. We think of the number 157 as:

We are saying 157 is no thousands add 1 x 100 add 5 x 10 add 1 x 7. You will also notice that the columns as you go from right to left increase by a multiple of 10 each time.

In binary, as we only have the two digits 0 and 1, the columns increase by a multiple of 2 each time we move one to the left, which means we can think of numbers as:

With all numbers set to 1, 1111 1111 in decimal is 128+64+32+16+8+4+2+1, which is 255. If we changed all the values to 0, this would be 0 x 128 + 0 x 64 + 0 x 32 etc. The result would be 0, so in binary and decimal, 0 is the same. (So is 1).

How does this relate to our LEDs? Each of the IO pins is controlled by a single binary digit, so we can think of them all as:

So, looking at the above, we know that 1111 1111 is 255 in decimal, and 0000 0000 is 0, so what would happen if we changed our loop to:

``````while True:
sleep(1000)
sleep(1000)``````

Give it a try.

No change. We are setting pins 7 and 6 when we have nothing attached, so why bother? What if we wanted to stop sending to those and only flash the lights on alternate pins with P5 on? What value would we need to send instead of 255? Consider it as a table:

We need to add all the columns where there is a 1, which is 32+8+2. The answer is 42. Try changing this in the main loop and see what happens? What other patterns can you produce?

In python, you can write binary numbers directly, using the prefix ‘0b’. Another way to send the above example would be ‘0b101010’. Give that a try.

#### Binary Operators

In binary, we have a number of binary operators available. These are functions in the same way we have plus and multiply in decimal. Using these, we can get other effects. You need to be aware that these operate on bytes. A byte is 8 binary digits, so 42 should always be considered as 0010 1010, not just 101010. Our PCF8574 requires a single byte send to cover all 8 IO pins.

We can have a bit of fun with these. What if we wanted to create a pattern and flash the opposite? Just assign our pattern to the variable ‘p’ and use the NOT function:

``````while True:
p = 0b101010
sleep(1000)
sleep(1000)``````

Try changing the pattern.

What if we wanted to flash each light in turn then return to the start? We can work out that to light only the right most light, we need to send a 1 or 0b1, then to only light the next we can send a 2 or 0b10, then 4 or 0b100 etc, but that gets a bit repetitive. All we are doing each time is moving the 1 to the left and we know we have 6 LEDs, so we can keep the code short and use the left shift:

``````while True:
# Set the initial pattern, right light on
p = 1

# Loop 6 times
for x in range(6):
sleep(500)
# Shift the pattern 1 place to the left
p = p << 1``````

Hexadecimal is another numbering system. Rather than use the digits 0-9 or just 1 and 0, hexadecimal has the numbers 0 to 15. Going into double digits gets confusing so we use the letters A to F. In Python, we use the 0x prefix to mean something is hexadecimal. It was this we were using in the original code snippet. There is a BBC Bitesize module on hexadecimal.

When counting in hexadecimal (or hex for short), the columns go up in multiples of 16. E.g.:

In the above, we have 2x 16 + 10 x 1, which is 42 again. We previously used the binary 0010 1010 to represent 42, but look at the table of hex to decimal to binary digits. A 2 in binary is 0010 and a A is 1010. If we put them together 2A = 0010 1010. Basically by looking at each hex digit we can quickly convert between hex and binary without worrying about how man 32s, how many 16s we have etc. This is why programmers often use hex. Computers operate using binary and hex gives a very short hand notation for writing binary.

In the very first example, we set all the outputs to 1 by sending 0xFF. Can you see why that works?

What if we wanted to attach some buttons? Can we read inputs? Yes. Now connect up P6 and P7 to buttons as in the picture above. If we write a 1 to each of these pins to put them in a high state, connect then to one side of a button and the other side to ground, when you press the button, it will be pulled low and turn to zero.

The following code writes a 1 to P6 and P7, then reads it back and prints the value back as a decimal. If you convert the binary, 0b1100 0000 is 192. If no button is pressed it will return a 192. However if you press the left button, the left most bit will turn to zero. This is 128 less, so 64 will be reported on the REPL console. If you press the right button, 128 should be reported and both will set the returned state to zero.

``````# Testing of a IO expanded - PCF8574
from microbit import *

# I2C send, function to simplify writing
# Convert sent value to a byte array, which is
# required for I2C
buf = bytearray(1)
buf = value
# Send value
# Short delay to send
sleep(5)

# Read in as a single byte and return
return v

# Input test
# Set P6 and P7 to high
buttonSet = 0b11000000
while True:
print ("Button input = ", v)
sleep(1000)``````

If you want to look at the returned value as binary or hex, use bin(v) or hex(v) in the print statement. Note that it will always trim leading zeros off the binary string, so when you press the left button, the binary string shrinks by 1 bit.

### Combining Input And Output

That is all very well, but now the LEDs are broken. If we send our LED pattern the buttons will stop working. If we send our pattern to set the button state, the LEDs will stop working. If you can set the button states and the LEDs together, when you read back the values, you will also read back the LED state, meaning our 192, 128 and 64 for the buttons no longer hold true. Their values will be higher depending on which LEDs are currently showing. How can we handle both?

This is where the bitwise operators come in very useful. An OR essentially combines two binary values together. If we have one value for our LED state and one value to set the buttons, then OR them together before sending, the two values are combined and we can have both. For example if we want the third LED from the right showing and to set our button states we can can see what happens with the following table:

What about reading values back? The AND function is often described as a mask. If we only want to know the state of P7 then we can make a binary string where only the left most bit is set to 1. If we AND this with the returned value we ‘mask’ out the other bits and can only look at the state of the one bit. If the whole value is zero then the button is pressed and if the button is not pressed, it should be 128. However we do not really care what the value is, just if it is not equal to zero. In the following table, P7 is being pressed but P6 is not.

Can you see what the result would be if P7 were not being pressed?

Lets put this into our code. Reading the result on the REPL console is slow, so as we have made sure we can still use the LED display on the Micro:Bit, lets make use of it. If we say the left button on P7 has a value of 2 and P6 has a value of 1. We can say if no button is pressed show a 0, if P7 is pressed, show a 2, if P6 is pressed show a 1 and show a 3 if both are pressed. Meanwhile, show our marching LEDs from the previous example. Also use hax values as this is more common when coding. Change the main loop to:

``````# Input test
# Set P6 and P7 to high
buttonSet = 0xC0
while True:
# Set the initial pattern, right light on
p = 0x01

# Loop 6 times
for x in range(6):
# Combine the two values with an OR and
# send to the Micro:But. Use the variable
# s for send
s = buttonSet | p

# Shift the pattern 1 place to the left
p = p << 1

# Check the button state, use the variable
# bState. Initially set it to zero
bState = 0

# Read a value in from the PCF8574

# If that value AND the binary 1000 000 is
# zero then button on P7 is being pressed
if( ( v & 0x80 ) == 0 ):
# Button is pressed, add 2 to bState
bState = bState + 2

# Now do the same for P6
if( ( v & 0x40 ) == 0 ):
# Button is pressed, add 1 to bState
bState = bState + 1

# Show the button state on the display
display.show(bState)

sleep(500)``````

We can make the button check and the display set even more efficient with the following code. We could even combine everything to one line if we wanted. Can you describe what is happening here (I’ve deliberately left the comments out) and can you make this a one liner? Remember, you can use the REPL console for debugging and print values as binary to see what is going on, e.g. `print ("v = ", bin(v))`. A pencil and paper may help too.

``````# Input test
# Set P6 and P7 to high
buttonSet = 0xC0
while True:
# Set the initial pattern, right light on
p = 0x01

# Loop 6 times
for x in range(6):
# Combine the two values with an OR and
# send to the Micro:But. Use the variable
# s for send
s = buttonSet | p

# Shift the pattern 1 place to the left
p = p << 1

# Check the button state, use the variable
# bState. Initially set it to zero
bState = 0

# Read a value in from the PCF8574

a = v >> 6
b = ~ a
bState = b & 0x03

# Show the button state on the display
display.show(bState)

sleep(500)``````

# Project: Rotary Encoder & Servo

Can we control a servo with a rotary encoder? Can we make it turn in the same direction as we turn the rotary encoder? What could we attach to the servo arm? Perhaps use this to control a crane or fork lift? Can it be attached to some lego to make something interesting?

Step 1: Set up the rotary encoder. Review Micro:bit Rotary Encoder and connect up the hardware. Run the test code to make sure the encoder is working.

Step 2: Can you turn this code into a function? Sit in the loop and call a function checkEncoder(), which will report back the direction (if any) it is being turned. Perhaps return 0 for stationary, 1 for turning clockwise and 2 for turning anti-clockwise. Consider returning two values to also report the state of the button.

Step 4: Connect the servo. Follow Micro:bit SG09 Servo and test the servo. Note, both examples use pin0 so you will have to make adjustments.

Step 5: Can you turn the servo in the same direction as the rotary encoder? You may need to write a function to tell the servo to move by X number of degrees. Try playing with different values for X and different sensitivities to control how fast the encoder turns the servo. Don’t forget to make sure you do not try to turn the servo beyond it’s limits.

# Micro:bit Rotary Encoder

A rotary encoder, such as the common KY-040 above, is a knob that you can turn continuously either clockwise or anti-clockwise and detect which direction it is being turned. Types such as the KY-040 are known as incremental encoders. These will tell you the direction they are being turned, but can not report which direction they are pointing. The shaft can be pushed down to act like a push button. A common application for this is to navigate menu screens on devices such as 3d printers.

To connect a KY-040 to a Micro:bit, + and GND go to 3V and GND on the Micro:bit. The other three pins go to any digital input pins. In the following examples, SW goes to pin0, DT to pin1 and CLK to pin2.

For a detailed explanation of how rotary encoders work, see wikipedia. To use one, all you need to know is if CLK changes, then the encoder is being turned. If CLK is the same as DT (could be high or low), then it is being turned anti-clockwise. If CLK is different to DT it is being turned clockwise. Generally the sensitivity is changed with a sleep statement. The button on the top acts as a simple push button. The CLK and DT pins have their own internal resistors so we must disable the internal pull-up resistor to work. For a description about this, see Micro:bit Buttons. The one on the switch is still required.

This gives us a basic procedure to follow to read input from a rotary encoder:

• Define the pins in use
• Disable the internal pull-up resistors.
• Read CLK and store this in a variable for the last known state of CLK.
• Start a loop:
• Read all three input pins
• If CLK has changed since the last known state of CLK (lastCLK), the encoder is moving.
• If CLK is not equal to DT it is moving clockwise
• Otherwise it is moving anti-clockwise.
• Wait, according to the sensitivity you want
• Set lastCLK equal to CLK
• Check for button press

In code form, this makes:

``````# Rotary encoder test
from microbit import *

RSW = pin0
RDT = pin1
RCLK = pin2

# KY-040 has its own pull up resistors.
# Disable the Micro:bit internal ones but
# ensure we use the one for the switch pin
RCLK.set_pull( RCLK.NO_PULL )
RDT.set_pull ( RDT.NO_PULL )
RSW.set_pull ( RSW.PULL_UP )

print ( "Ready to start" )
display.show ( Image.HAPPY )

while True:

if ( clk != clkLast ) :
if ( clk != dt ) :
print ( "Clockwise" )
display.show(Image.ARROW_E)
sleep(300)
else:
print ( "Anti-clockwise" )
display.show(Image.ARROW_W)
sleep(300)

clkLast = clk
else:
# Has the switch been pressed?
if (sw == 0) :
display.show('X')
sleep(500)
else :
display.clear()``````

There is a problem with this approach. If you try it and watch either the arrows or serial lines, you find while turning the encoder, you occasionally get the wrong direction reported. This is known as ‘switch bounce’ and is often caused by cheaper components in encoders such as the KY-040. There are many ways to look at solving this, either in hardware using capacitors or in code. In a few tests with capacitors, I did not find a significant difference. However I always found that the wrong direction was reported once in a row, never twice.

A ‘quick and dirty’ solution is to wrap up the detection into a function which takes a number of readings then reports back which direction was detected the most. This does mean it will take a little longer to react to a turn or change in direction, but only by a fraction of a second. In the code below, the function readEncoder returns a pair of values for the direction and the state of the switch. A 0 represents no movement, 1 for clockwise movement and -1 for anti-clockwise.

In python, you can build lists of values in brackets with a comma, e.g. a=(2, 4, 8). To access the first element of the list, use square brackets, a. For the third value, a. This allows us to return the direction as the first value and the switch state as the second. The function in the below code takes a few attempts to read the encoder direction and returns a pair of values, the first for the direction and the second for the switch state.

``````# Rotary encoder test
from microbit import *

RSW = pin0
RDT = pin1
RCLK = pin2

# KY-040 has its own pull up resistors.
# Disable the Micro:bit internal ones but
# ensure we use the one for the switch pin
RCLK.set_pull(RCLK.NO_PULL)
RDT.set_pull(RDT.NO_PULL)
RSW.set_pull(RSW.PULL_UP)

# Return a pair of values direction and switch state
#   0 = no movement
#   1 = clockwise
#   2 = anti-clockwise

# Set sensitivity - how long we wait between readings in ms
sens = 50
# Accuracy is how many checks we perform. This should at least
# be 3. Note that the more checks, the longer it will take and
# the greater the chance of the direction changing while we checks
acc = 5

# Record the last known state of the CLK line

# Set direction counters, clockwise and anti-clockwise
cw = 0
ac = 0

# Checking loop
for i in range(0, acc):
# Read data from the encoder

if(clk != clkLast):
# print ("clkLast = "+str(clkLast)+" - clk = "+str(clk)+" - dt = "+str(dt))
if(clkLast != dt):
# Clockwise, add 1 to clockwise count
cw = cw+1
else:
# Anti-clockwise, add 1 to anti-clockwise count
ac = ac+1

# Record the last known state of the clock
clkLast = clk
# Wait according to sensitivity setting
sleep(sens)

# Initially assume the direction is 0
d = 0
# Check the clockwise and anti-clockwise counters
# If they are the same, no change to d is made. We assume
# the encoder is not moving
if(cw > ac):
# More clockwise movement than anti-clockwise
d = 1
elif(ac > cw):
# More anti-clockwise movement than clockwise
d = -1

# Return data as a pair
# We can return the value of the switch directly
return (d, sw)

display.show(Image.HAPPY)
sleep(1000)

# Main loop
while True:

# Check the direction and report. The screen
# will show the last recorded direction
if(r == 1):
# Clockwise movement
print("Clockwise")
display.show(Image.ARROW_E)
elif(r == -1):
# Anti-clockwise movement
print("Anti-clockwise")
display.show(Image.ARROW_W)

# Check for a switch press
if(r == 0):
display.show('X')
sleep(500)
display.clear()``````

# Micro:bit Buttons

Microcontrollers such as the Micro:bit all do one similar thing, accept an input (some sort of ‘message’ from the outside world), process (run some code) and output (show something to the outside world). The most common type of input everyone uses is a button.

What is a button? Essentially a button is a couple of bits of wire or metal plate that touch together when pressed. This allows electricity to flow between the connectors at either side, making the connection. There are a few different types of button each with different properties. Some stay on or stay off after being pressed (or toggled), like a light switch. Some only make a contact when the button or lever is being moved and some you push to break the circuit. The types we are looking at in this tutorial are momentary push buttons, which only make a connection while they are being pressed. The standard circuit symbols below shows a little about how they work.

There is a connection at either side, when the buttons are pressed, the two connections are joined and electricity flows.

### Micro:bit Onboard Buttons

The easiest two buttons to use are the two build onto the Micro:bit board itself, labelled A and B. There is a lot of information on the Micropython tutorial page about using these. When using the microbit library, two objects are defined, button_a and button_b. You can check if these are pressed with the is_pressed() function. The following code loops checking for a button press then points an arrow to the last pressed button:

``````from microbit import *

while True:
if ( button_a.is_pressed() ) :
display.show(Image.ARROW_W)
if ( button_b.is_pressed() ) :
display.show(Image.ARROW_E)``````

While quick and easy to use, this does not help us add other buttons. By wiring in a button, it will not automatically create a button object. External buttons are connected to pins, but consider the Micro:bit pinout diagram. When you look at this, the buttons A and B are connected to pins 5 and 11. For us, this means two things. First is that when connecting hardware, if we want to use buttons A and B, we should not use pins 5 and 11 for anything else. But it also means we can read the buttons as if they were digital pins. When we read digital pins, the result can be a 1 or a 0. The following will show on the display the value of the A pin, pin 5:

``````from microbit import *

while True:

Try it. What does the value change to when you press the button? We often think of 1 as being on and 0 as being off, but find this works the other way round. There is a reason for this which will be revealed below. For now, as long as we are happy that 0 means a button is being pressed, if we want to rewrite the first program to use pin numbers, we can write it as:

``````from microbit import *

while True:
if ( pin5.read_digital() == 0 ) :
display.show(Image.ARROW_W)
if ( pin11.read_digital() == 0 ) :
display.show(Image.ARROW_E)``````

### External Buttons

We can add external buttons to the Micro:bit to give a larger number of buttons, or to use different types of buttons. One end can connect to a data pin, but what do we connect the other end to? Consider the circuit diagram below:

pin0 is said to be ‘floating’. It is neither connected to ground (0v) or the positive 3v. If we read the value of this, it could be anything. Putting an open button on it would leave it in the same state. Imagine a kite free to fly in the wind. If we pin it to the ground, then we know it is on the ground. If it were possible to pin it into the air, again we would know where it was. Anything else, it is at the mercy of the wind and can keep flying and crashing all day long.

Electronic inputs are the same. Unless we decide to ‘pin’ them to something, we can not predict what state they would be in. In practice, I have found an unconnected Mirco:bit input always seems to be zero. The same is not true of other micro controllers, such as a Raspberry Pi or an Arduino, so it is good practice to make sure you know what state your inputs are in. This is done with the use of pull-up or pull-down resistors.

In the diagram on the left, we are using a pull-down resistor. (10k ohm is a common value for this.) When the button is not pressed, the resistor connects pin0 to ground, meaning a read_digital function will always return 0. However when the button is pressed, it connects pin0 to +3v, which the Micro:bit reads as 1. The resistor limits how much of the current can flow between +3v and GND, leaving a higher current to be detected on pin0.

In the diagram on the right, we do the opposite. pin0 is pulled high (read as 1), unless the button is pressed, at which point it is pulled low (read as 0). This means in our code, we detect a button press as a 0 and no button press as a 1.

The Micro:bit has a built in pull-up and pull-down resistors that you can turn on in the code, using the command set_pull. If you want to use your own external resistors with buttons, then you must disable these:

``pin0.set_pull(pin0.NO_PULL)``

However, as they are there it is best to make use of them. If you remember, reading the internal buttons give a 1 when not pressed and a 0 when pressed, meaning they must be using the internal pull-up resistor. If we use external buttons on pins 0 and 1, we can use the same code again.

``````from microbit import *

# Set the pull up state for the internal resistors
pin0.set_pull(pin0.PULL_UP)
pin1.set_pull(pin1.PULL_UP)

while True:
if ( pin0.read_digital() == 0 ) :
display.show(Image.ARROW_W)
if ( pin1.read_digital() == 0 ) :
display.show(Image.ARROW_E)``````

### Button Modules

You can also use button modules such as the one in the middle of the picture above. Going from left to right, pin S connects to one of the IO pins of the Micro:bit, the middle to 3v and the right pin to GND. If you look closely, you can see a small black rectangle labelled 103 connecting S and 3v. This is a small pull-up resistor. As this has its own resistor, we need to make sure we disable the internal resistor. We can then check the button state after connecting it to pin2.

``````from microbit import *

# Disable the internal pull up
pin2.set_pull(pin2.NO_PULL)

while True:
``````

Button modules may come on their own or be included as part of a joystick module, game controller package, etc. If the instructions do not say if a pull-up or pull-down resistor is used, you should be able to check with the the above code.

# Micro:bit SG09 Servo

Servos are small motors with gearing that can add a high amount of torque (turning strength), and reliably turn to a precise angle. Servos such as the SG09 are small, cheap, run on low power and can rotate around 180 degrees, or a half circle. This makes them different to a normal motor which will spin round. You can commonly use this for things that need to turn by small amounts, such as a joint in a robotic arm, to lift the arm of a barrier or to steer a radio controlled car.

The SG09 only requires 3 connections two for power and one for data/control, but it does require 4.8v to operate. As the Micro:bit can only produce low current and 3v, an external battery pack is required. In the above wiring, brown is ground, red is +4.8v and orange is control. Connect a 3xAA battery pack to the two power pins and control to one of the Micro:bit pins, as shown below. Note a 4xAA battery pack is shown on the diagram.

There are a number of pages on controlling the SG09 with a Micro:bit, however none of these worked when I tried this. The servo operates by receiving pulses of 50Hz (50 pulses per second). If we divide one second by 50 pulses, we get a time of 20ms between pulses. We start our code by defining this. Next, if we write the analog value 1 to the servo, it will turn all the way to it’s clockwise limit. (If you send a 0, it does nothing.) Sending a high enough value will turn the servo the other way.

If you try a value of 150 or higher, you will feel the servo straining beyond it’s limits and you could damage it. Start with a low value for maxLimit in the following code (say 80) and gradually increase it until the motor just reaches it’s anti-clockwise limit. I found 122 to be a figure which does not strain the servo but reaches the other side.

``````from microbit import *

servo = pin0

# Motor requires a 50 Hz signal. 1 second / 50 gives
# a pulse every 20 ms. Set this as the analog period
servo.set_analog_period(20)

maxLimit = 122

while True:
servo.write_analog(0)      # Set the servo to 90 degrees - the middle
sleep(500)
for i in range(10,maxLimit):
servo.write_analog(i)    # Turn the servo to the clockwise limits, 0 degrees
sleep(50)
``````

As the servo moves between 0 and 180 degrees, and values between 1 and 122 causes this movement, we can work out what value to analog write to achieve by dividing the angle we want by 180 then multiplying this by 122. We can wrap this up in a function and then call it to move the servo to a desired angle. The below code moves the servo to its limits and back again, like a windscreen wiper.

``````from microbit import *

servo = pin0

def servoAngle(s, a) :
maxLimit = 122

# Set the values into a sensible range
# 1 is the smallest value
if a < 1 :
a = 1
# Max limit is the highest value
if a > 180 :
a = 180

v = (a/180) * maxLimit
s.write_analog(v)

# Motor requires a 50 Hz signal. 1 second / 50 gives
# a pulse every 20 ms. Set this as the analog period
servo.set_analog_period(20)

while True:
servo.write_analog(1)
sleep(1000)
#servo.write_analog(122)
servoAngle(servo, 180)
sleep(1000)

``````

Note that this angle is an approximation and not exact. The design specs of the servo detail exactly what sort of pulses to send for precise control. This gives a very quick and simple way of achieving something close to what we require for a lot of applications.

# Project: Neopixel game

Given what we have learned about controlling the joystick and neopixel hardware in Micro:bit Joystick Module and Micro:bit Neopixels, can we construct a simple game? We need to consider the hardware, animation, random position generation and collision detection.

Step 1: Construct the hardware. Can you connect both the Neopixel grid and the joystick to the micro:bit? Is there any testing we can do to make sure they work?

Step 2: Start the game by positioning the ‘player’ in the top left corner. Pick a colour for the player and light up that LED. Be sure to use variables to describe the player position as we are going to move this soon.

Step 3: Can we move the player around with the joystick? In a loop detect joystick movement then adjust the coordinates of the players position accordingly. Be sure to put a delay in the loop, otherwise the player will move very fast! What happens when the player reaches the edge of the display? Can we stop the player leaving the screen?

Step 4: Can you make something happen to the player when you press the joystick down? Perhaps flash?

Step 5: Using a random number generator, can you put some ‘food’ at a random point on the screen? How can we check this food does not land on top of the player? Do we need to store the food coordinates for when we redraw the screen?

Step 6: Now lets look at collision detection. Can you detect when the player lands on the food? Can it ‘eat’ the food and then new food appears at another random location? Can you keep a score of food eaten on the micro:bit LEDs? End the game when the you reach 10 bits of food.

Step 7: Can you make the game more interesting or use what you have learned to make a different game? What if there were two players taking it in turn to move? What if the food made the player grow like a worm? Could painting the screen a different colour be part of the game?

# Micro:bit Neopixels

NeoPixels are Adafruit’s brand of individually addressable RGB LEDs. However the name has become common use to describe most kinds of WS2812 (and similar) LED arrays. Each LED can have it’s colour set individually using a RGB value. This can lead to interesting light and animation displays. The above image is not an Adafruit branded matrix, it was cheaper and has one ‘stuck’ LED. Adafruit’s offerings are generally considered to be higher quality. For this article, all similar arrays will be referred to as Neopixels.

Neopixels can come in a large range of shapes and sizes, rings, strips, arrays, long strings or as individuals. They come with 3 connections, Vcc (3v), GND and Data/IN. Data connects to any pin which supports PWM. It is not clear from the docs if all pins support PWM, though pins 0-3 certainly do. Most units also have output connections for power and data, allowing you to daisy chain units together for large LED displays. Chaining more units together may require the use of external power supplies.

Micropython has a Neopixel library, which has 2-3 simple steps:

• Clear the display (optional)
• Configure colour values for each pixel
• ‘Show’ the display.

The following code clears the display, then sets the first three pixels to be red, green and blue. Like most things in computing, counting starts at zero not one:

``````# NeoPixel Demo
from microbit import *
import neopixel

# Init a 64 Neopixel display on Pin0
np = neopixel.NeoPixel(pin0, 64)

# Clear the display
np.clear()

# Set the first pixel to red
np = (255, 0, 0)
# Set the second pixel to green
np = (0, 255, 0)
# Set the third pixel to blue
np = (0, 0, 255)

# Show new display settings
np.show()
``````

This version of the neopixel library does not allow the adjustment of brightness. The only supported method is to lower the RGB values. Adafruit does have a library which does allow brightness lowering.

### Pixel numbering

Different Neopixel shapes have different numbering schemes to determine how your pixels are laid out, the following code will flash each pixel in turn:

``````# NeoPixel Demo
from microbit import *
import neopixel

# Init a 64 Neopixel display on Pin0
np = neopixel.NeoPixel(pin0, 64)

for i in range(64):
# Clear the display
np.clear()

# Set the pixel to red
np[i] = (64, 0, 0)

# Show new display settings
np.show()
sleep(300)``````

From this, I could determine the layout on the left of the below image for my 8×8 matrix.

It would be more useful if we could address the pixels using coordinates as demonstrated on the right, especially if we want to do an animation or move a cursor. The red pixel has the coordinates (4,3), pixel number 28. The green pixel is (1,6), pixel 49. The formula p=8*y + x can be used to calculate the pixel number. If we wrap this up in a function, we can address our pixels using coordinates. The following code displays the red and green pixel in the right image.

``````# NeoPixel Demo
from microbit import *
import neopixel

# Init a 64 Neopixel display on Pin0
np = neopixel.NeoPixel(pin0, 64)

# Function neoCoord
def neoCoord(n, x, y, col):
# Accept a neopixel object, x and y values then set the pixel to be that colour
# Calculate pixel number
p = y*8 + x

# Set the pixel
n[p]=col

# Set red and green pixels by coordinate
# Clear the display
np.clear()

neoCoord(np, 4, 3, (128,0,0))
neoCoord(np, 1, 6, (0,128,0))

# Show new display settings
np.show()
``````

You may need to write your own formula in neoCoord depending on your display. It may be rectangular or you could join two 4×4 displays together to make a 8×4 display.

### Displaying Images

The onboard LEDs can be sent an image to display, either using a pre-defined image or defining your own. See the tutorial here. Wouldn’t it be nice if we could do the same? With large displays we could use images smaller than the overall display. We tell it where we want the image to appear, what colour and what image. If we define this is a binary bitmap (using 0 and 1 only) and code correctly, we need not worry if the image goes off the ‘screen’. We can use this to produce nice animation effects and call the function multiple times with different colours to produce multi-colour images.

neoImage takes a Image object and prints it in the colour col, at the coordinates specified. It is happy if that prints part of the image (including the starting point) off the screen, as this allows images to scroll on and off the screen. Use negative coordinates to go off the top or left of the screen. The following code includes the image displaying function neoImage along with a short bit of code to scroll a TIE fighter across the screen twice.

``````# Neopixel Images
from microbit import *
import neopixel

# Init a 64 Neopixel display on Pin0
np = neopixel.NeoPixel(pin0, 64)

# Set the display width and height. We need this for correctly
# displaying images
dwidth = 8
dheight = 8

tie = Image("10001:"
"10101:"
"11111:"
"10101:"
"10001")

# Function neoCoord
def neoCoord(n, x, y, col):
# Accept a neopixel object, x and y values then set the pixel to be that colour
# Calculate pixel number
p = y*8 + x

# Set the pixel
n[p]=col

# Display an image on a neoPixel matrix
def neoImage(n, px, py, col, img):
# n=NeoPixel object, px & py=top left positional coordinates,
# col=colour and img is a binary image object
# The position may be negative to allow an image to scroll onto
# the screen

# Find dimensions
w = img.width()
h = img.height()

# Set coordinates to start plotting (x and y)
x = px
y = py

# Run through each row of the image as iy (image y)
for iy in range(h):
# Run through each column in the image as ix (image x)
# Reset x to start of row
x = px
for ix in range(w):
# Find the value of that pixel
v = img.get_pixel(ix, iy)
if(v > 0):
# Check the pixel is in the range of the screen
# If not, ignore
if(x >= 0 and y >= 0 and x < dwidth and y < dheight):
# Set that pixel
neoCoord(n, x, y, col)

# Increase x
x = x + 1

# Move to the next row
y = y + 1

# Scroll the image onto the top left and across the screen
for i in range(-5,9):
# Clear the display
np.clear()

# Display the image
neoImage(np, i, 0, (0,0,80), tie)

# Show new display settings
np.show()

# Pause
sleep(200)

# Scroll back on the from the other side at the bottom
for i in range(9,-6,-1):
# Clear the display
np.clear()

# Display the image
neoImage(np, i, 3, (0,0,80), tie)

# Show new display settings
np.show()

# Pause
sleep(200)
``````

# Micro:bit Joystick Module

These small joystick modules are composed of a single switch (triggered when pushing down), and two potentiometers set by moving the X and Y axis. As well as two power pins, it has three ouput pins, SW, VRy and VRx. VRy and VRx must be connected to analog capable pins, while SW can be read as a digital value.

The switch is a basic push button which connects SW to GND. In order to function, either an external pull-up resistor must be used to Vcc or make use of the internal pull-ups as demonstrated in the code below.

The following code performs the basic read operations and outputs the joystick status tothe serial console:

``````# Testing a joystick module
# Connections:
#   sw - pin 0
#   VRy - pin 1
#   VRx - pin 2

from microbit import *

jsSW = pin0
jsX = pin2
jsY = pin1

# Configure switch for internal pullup
jsSW.set_pull(jsSW.PULL_UP)

while True:

print("sw="+str(sw)+", jx="+str(jx)+", jy="+str(jy))
sleep(500)``````

The following code introduces a function to check the direction based on the above values, then change the LED matrix accordingly.

``````# Testing a joystick module
# Connections:
#   sw - pin 0
#   VRy - pin 1
#   VRx - pin 2

from microbit import *

jsSW = pin0
jsX = pin2
jsY = pin1

# Configure switch for internal pullup
jsSW.set_pull(jsSW.PULL_UP)

def getJSdir():
# Returns joystick direction when pushed towards the limits
# 0 = middle, 1 = up, 2 = right, 3 = down, 4 = left

if(jy < 100):
return 1
if(jx > 900):
return 2
if(jy > 900):
return 3
if(jx < 100):
return 4

return 0

while True:

d = getJSdir()
if(d == 0):
display.show(Image.HAPPY)
if(d == 1):
display.show(Image.ARROW_N)
if(d == 2):
display.show(Image.ARROW_E)
if(d == 3):
display.show(Image.ARROW_S)
if(d == 4):
display.show(Image.ARROW_W)

if(sw == 0):
display.show(Image.COW)

sleep(200)
``````