# Raspberry Pi GPIO projects

Raspberry Pi GPIO projects

# Educational projects using the Custard Pi range

Seggy T Segaran

First published in 2015 by Ohm Books Publishing

Kindle Version 2015 V1

The moral right of the author has been asserted.

CONTENTS

Project 11 – Using the Raspberry Pi to measure temperature

Project 12 – Writing to a serial LCD with the Raspberry Pi

Project 13 – Using the Raspberry Pi to measure battery voltage

Project 14 – Using the Raspberry Pi to measure current

Project 11 – Using the Raspberry Pi to measure temperature

Outline

This application note shows the hardware and Python code required to measure temperature using the Raspberry Pi. Any of the Raspberry Pi models can be used including B, B+ and the Raspberry Pi 2.

Hardware

TMP36: We are going to use this simple 3-pin device which outputs a voltage proportional to the temperature. For a given voltage V (in mV) the temperature t in deg C is given by:

t = (V-500)/10

Custard Pi 3: The Raspberry Pi GPIO does not have any analogue inputs so we are going to use the Custard Pi 3 which has 8 analogue inputs.

For ease of assembly, this project uses a Custard Pi base and a prototyping board. The assembled hardware is shown below.

The red wire is soldered to the 3.3V via hole on the CPi3 and goes to pin 1 of the TMP36. The green wire goes from 0V via hole on the CPi3 and goes to pin 3 of the TMP36. The middle pin (pin 2) of the TMP36 goes to the input labelled 1.

Software

To make life easier, we are going to use a routine called cpi3x.py to read the voltage from any of the 8 inputs available on the Custard Pi 3. This has been provided by SF Innovations and is available on their website under the ‘Downloads’ tab. A full listing of cpi3x is also provided in appendix A.

By using the function ‘readanalog(y)’ the program for reading temperature is very simple. The Python code below reads the voltage on channel 0, converts it to a temperature and prints the result.

import RPi.GPIO as GPIO

from time import sleep

import cpi3x

GPIO.setmode(GPIO.BOARD)

while True:

V = round(V,3)

print V

t = (1000*V-500)/10

print “Ch 0 temperature = “, t

print

sleep (1)

The value V is rounded off to 3 decimal places and then converted to temperature. (V is in volts, so we first multiply by 1000 to convert it to mV). This routine will run continuously with a 1 second pause between measurements until terminated by CTRL C.

It should be possible also to run the TMP36 on a long cable (a few metres) and get reasonable results as the voltage output is just under 1V at room temperature and will not be affected too much by noise. However the supply voltage may be an issue, so a 100uF capacitor placed close to the TMP36 across pins 1 and 3 (the supply pins) will help stabilise this.

Log the measured temperature to a file along with real time to find how this varies over the day.

Build a 2- channel temperature logger to measure inside and outside temperature. (Pot the TMP36 and capacitor inside a potting box to seal it from moisture).

Use the temperature measurement and a heater connected to the Mains Switch Widget to keep the temperature in the room within a specified range.

Notes:

The Custard Pi 3, Custard Base and Mains Switch Widget are available from amazon.co.uk and directly from SF Innovations. The code presented here can be downloaded from the SF Innovations website.

Appendix A – cpi3x

The function ‘readanalog(y)’ in this routine returns a value in volts for channel y.

#1/usr/bin/env python

#Program to read an analogue input on Custard Pi 3

#www.sf-innovations.co.uk

import RPi.GPIO as GPIO

import time

GPIO.setmode(GPIO.BOARD)

GPIO.setup(24, GPIO.OUT) #pin 24 is chip enable

GPIO.setup(23, GPIO.OUT) #pin 23 is clock

GPIO.setup(19, GPIO.OUT) #pin 19 is data out

GPIO.setup(21, GPIO.IN, pull_up_down = GPIO.PUD_UP) #pin 21 is data in

#set pins to default state

GPIO.output(24, True)

GPIO.output(23, False)

GPIO.output(19, True)

#set address channels 0 to 7

#1st bit selects single/differential

#5th bit 1 bit delay for data

#6th bit 1st null bit of data

GPIO.output(19, True)

#select the right channel

if y == 0:

word= [1 ,1, 0, 0, 0, 1, 1] #set channel 0

if y == 1:

word= [1 ,1, 0, 0, 1, 1, 1] #set channel 1

if y == 2:

word= [1 ,1, 0, 1, 0, 1, 1] #set channel 2

if y == 3:

word= [1 ,1, 0, 1, 1, 1, 1] #set channel 3

if y == 4:

word= [1 ,1, 1, 0, 0, 1, 1] #set channel 4

if y == 5:

word= [1 ,1, 1, 0, 1, 1, 1] #set channel 5

if y == 6:

word= [1 ,1, 1, 1, 0, 1, 1] #set channel 6

if y == 7:

word= [1 ,1, 1, 1, 1, 1, 1] #set channel 7

if y == 8:

word= [1 ,0, 0, 0, 0, 1, 1] #set diff ch0 +ve ch1 -ve

if y == 9:

word= [1 ,0, 0, 0, 1, 1, 1] #set diff ch0 -ve ch1 +ve

if y == 10:

word= [1 ,0, 0, 1, 0, 1, 1] #set diff ch2 +ve ch3 -ve

if y == 11:

word= [1 ,0, 0, 1, 1, 1, 1] #set diff ch2 -ve ch3 +ve

if y == 12:

word= [1 ,0, 1, 0, 0, 1, 1] #set diff ch4 +ve ch5 -ve

if y == 13:

word= [1 ,0, 1, 0, 1, 1, 1] #set diff ch4 -ve ch5 +ve

if y == 14:

word= [1 ,0, 1, 1, 0, 1, 1] #set diff ch6 +ve ch7 -ve

if y == 15:

word= [1 ,0, 1, 1, 1, 1, 1] #set diff ch6 -ve ch7 +ve

GPIO.output(24, False) #enable chip

anip=0 #clear variable

#clock out 7 bits to select channel

for x in range (0,7):

GPIO.output(19, word[x])

time.sleep(0.01)

GPIO.output(23, True)

time.sleep(0.01)

GPIO.output(23, False)

#clock in 11 bits of data

for x in range (0,12):

GPIO.output(23,True) #set clock hi

time.sleep(0.01)

time.sleep(0.01)

GPIO.output(23,False) #set clock lo

value=bit*2(12-x-1) #work out value of this bit

#print (bit,value,anip)

GPIO.output(24, True) #disable chip

volt = anip*2.5/4096 #use ref voltage of 2.5 to work out voltage

#volt = ("%.2f" %round(volt,2)) #round to 2 decimal places

#print “voltage ch”, y, volt #print to screen

return volt

Project 12 – Writing to a serial LCD with the Raspberry Pi

Outline

This application note describes how to write to a 2-line LCD display the I2C bus of the Raspberry Pi. Any of the Raspberry Pi models can be used including B, B+ and the Raspberry Pi 2.

Hardware

2-Line LCD display: The standard 2 lines x 16 character display has 14 connections. However these are also supplied with a piggy back board which uses the I2C bus. This means that the Raspberry Pi can drive this display using just the SDA and SCL pins. The other 2 pins are supply at 5V and a 0V connection.

There are different versions of this LCD available. The ones used for this project had LCM1602 IIC V1 marked on it.

Custard Pi 1: The Raspberry Pi GPIO is not easy to connect to and can be damaged if the wrong voltage is connected to certain pins. We are going to use the Custard Pi 1 break out board as this has some protection built in to prevent accidental damage.

For ease of assembly, this project uses a Custard Pi base and a prototyping board. The assembled hardware is shown below.

Connecting up the LCD is very easy. Just connect 4 wires from the Custard Pi 1 to the LCD piggy back board. These are 5V and 0V (on connector J3) and SCL and SDA (on connector J7). The LCD looks better with backlighting. To enable this, please solder a wire from pin 1 to pin 16 of the LCD.

Software

The Python code presented here writes to both lines of the LCD and writes blanks to clear the display. It uses the LCD routine which is listed in the Appendix 2. The I2C address of the piggy back board on the LCD is 0×27.

The I2C bus needs to be enabled on the Raspberry Pi before we can use it. Appendix 1 shows how to do this as well as to check the I2C bus address of the piggy back board.

#1/usr/bin/env python

import time

import pylcdlibseg

#start program

lcd = pylcdlibseg.lcd(0×27,1)

while True:

lcd.lcd_clear

time.sleep (0.5)

lcd.lcd_puts(“LCD line 1 test”,1) #display text on line 1

time.sleep (0.5)

lcd.lcd_clear

lcd.lcd_puts(“LCD line 2 test”,2) #display text on line 1

time.sleep (0.5)

lcd.lcd_puts(” “,1)

lcd.lcd_puts(” “,2)

time.sleep(1)

import sys

sys.exit()

Notes:

The Custard Pi 1 and Custard Base are available from amazon.co.uk and directly from SF Innovations. The code presented here can be downloaded from the SF Innovations website.

Buy a 4 line display and adapt the demo code to write to this.

APPENDIX 1

Setting up the I2C Bus

By default, the I2C bus routines are turned off in the operating system. The following steps need to be followed to enable these.

Step 1

At the command prompt type:

sudo nano /etc/modules

This uses the nano editor to make some changes to the modules file.Add the following two lines to this file

i2c-bcm2708

i2c-dev

Then save and exit the file using CTRL-x and Y.

Step 2

Make sure that you have the I2C utilities installed by executing the following two commands. The Pi will need to be connected to the Internet for this.

sudo apt-get install python-smbus

sudo apt-get install i2c-tools

If you get a 404 error do an update first:

sudo apt-get update

Note : The installation could take a few minutes to do, depend on how busy the server is.

Now add a new user to the i2c group:

Step 3

On the Raspberry Pi, the I2C and the SPI buses are usually disabled. This is done in the /etc/modprobe.d/raspi-blacklist.conf file.

If this file is not present then there is nothing to be done. Otherwise edit the file by typing the following at the command prompt.

sudo nano /etc/modprobe.d/raspi-blacklist.conf

If the I2C and the SPI is blacklisted, you will see the following commands.

blacklist spi-bcm2708

blacklist i2c-bcm2708

Insert a # in front of these to comment them out.

Then save and exit the file using CTRL-x and Y.

After editing the file, you will need to reboot for the changes to take effect.

Step 4

Now we need to test if the I2C bus is working correctly.

Connect up the Custard Pi 6 board (or any other I2C bus device) and run the following command.

sudo i2cdetect -y 1 (for Rev 2 boards which uses port 1)

Or

sudo i2cdetect -y 0 (for Rev 1 boards which uses port 0)

If everything is OK, then the I2C address of the device will be shown as on the following slide. This shows two devices with address 40 and 70 in hexadecimal code. .

Now that we have set up the I2C serial bus routines, we are ready to drive the relays on the Custard Pi 6.

APPENDIX 2

This routine initialises the LCD and writes text to line 1 or line 2 of the display using the lcd_puts function.

import smbus

from time import sleep

1. General i2c device class so that other devices can be added easily

class i2c_device:

self.bus = smbus.SMBus(port)

def write(self, byte):

class lcd:

#initializes objects and lcd

delay=0.0005

self.lcd_device.write(0×30)

self.lcd_strobe()

sleep(delay)

self.lcd_strobe()

sleep(delay)

self.lcd_strobe()

sleep(delay)

self.lcd_device.write(0×20)

self.lcd_strobe()

sleep(delay)

self.lcd_write(0×28)

self.lcd_write(0×08)

self.lcd_write(0×01)

self.lcd_write(0×06)

self.lcd_write(0×0C)

self.lcd_write(0×0F)

1. clocks EN to latch command

def lcd_strobe(self):

1. write a command to lcd

def lcd_write(self, cmd):

self.lcd_device.write((cmd >>4) <<4)

self.lcd_strobe()

self.lcd_device.write((cmd & 0×0F)<<4)

self.lcd_strobe()

self.lcd_device.write(0×0)

1. write a character to lcd (or character rom)

def lcd_write_char(self, charvalue):

self.lcd_device.write((0×01 | (charvalue >>4)<<4))

self.lcd_strobe()

self.lcd_device.write((0×01 | (charvalue & 0×0F)<<4))

self.lcd_strobe()

self.lcd_device.write(0×0)

1. put char function

def lcd_putc(self, char):

self.lcd_write_char(ord(char))

1. put string function

def lcd_puts(self, string, line):

if line == 1:

self.lcd_write(0×80)

if line == 2:

self.lcd_write(0xC0)

if line == 3:

self.lcd_write(0×94)

if line == 4:

self.lcd_write(0xD4)

for char in string:

self.lcd_putc(char)

1. clear lcd and set to home

def lcd_clear(self):

self.lcd_write(0×1)

self.lcd_write(0×2)

1. add custom characters (0 – 7)

self.lcd_device.bus.write(0×40);

for char in fontdata:

for line in char:

self.lcd_write_char(line)

Project 13 – Using the Raspberry Pi to measure battery voltage

Outline

This application note shows the hardware and Python code required to measure the voltage of a 9V PP3 battery using the Raspberry Pi. Any of the Raspberry Pi models can be used including B, B+ and the Raspberry Pi 2.

Hardware

MCP6002 op-amp: The voltage of a PP3 battery is nominally 9V and can be a little bit higher. The maximum input into the A to D convertor that we are planning to use is 3.3V. For this reason we have to convert the actual battery voltage into a lower voltage. We are going to use one of the op-amps from the chip shown below for this.

Custard Pi 2: The Raspberry Pi GPIO does not have any analogue inputs so we are going to use the Custard Pi 2 which has 2 analogue inputs.

For ease of assembly, this project uses a Custard Pi base and a prototyping board. The assembled hardware is shown below.

We are going to use the 3.3V and 0V connections on the Custard Pi 2 to power the MCP6002. The circuit diagram is shown below along with a detailed description.

The input from the battery is taken to the + ve input and the -ve input has resistor R1 to the output another resistor R2 to 0V. In this configuration the gain is given by the following equation.

Gain = 1 + R1/R2.

Resistors R1 and R2 provide a gain of 2 through the op-amp as they are both 10k. The main purpose of the op-amp is to buffer the signal going to the ADC (Analogue to Digital Convertor) input of the Custard Pi 2. ie the input resistance of the ADC has no effect on the voltage of the measuring circuits.

As the battery voltage (at 9V) is much higher than the maximum of 3.3V expected by the ADC, we have to attenuate the signal. This is done by resistors R3 and R4. The attenuation provided is given by the equation:

Attenuation = R4/(R3+R4) = 1/11 = 0.091

So the battery voltage is first attenuated by 0.091 and then amplified by 2. To get to the battery voltage from the measured voltage we have to multiply by (1/0.091 or 10.99) and then divide by 2.

Software

To make life easier, we are going to use a routine called cpi2adc.py to read the voltage from one of the 2 channels available on the Custard Pi 2. This has been provided by SF Innovations and is available on their website under the ‘Downloads’ tab. A full listing of cpi2adc.py is also provided in appendix A.

By using the function ‘readchannel0()’ the program for reading voltage is very simple. The Python code below reads the voltage on channel 0, converts it to the true battery voltage and prints the result.

import RPi.GPIO as GPIO

from time import sleep

GPIO.setmode(GPIO.BOARD)

while True:

V=V*10.99

V=V/2

V= round (V,2)

print “Battery Voltage=”, V

print

sleep (1)

The above program uses the routine ‘readchannel0’ in cpi2adc to read in the modified battery voltage. This value is then multiplied by 10.99 to compensate for the attenuation and divided by 2 to offset the gain introduced by the op-amp. This is then printed to the screen.

When the battery voltage drops below a pre-determined level, send out an alert e-mail.

Modify the circuit and software to check the voltage of two PP3 batteries in series at a total voltage of 18V.

Notes:

The Custard Pi 2 and Custard Base are available from amazon.co.uk and directly from SF Innovations. The code presented here can be downloaded from the SF Innovations website.

The functions ‘readchannel0()’ and ‘readchannel1() in this routine return a value in volts for input to channel 0 and channel 1.

#1/usr/bin/env python

#program to read analogue voltage on Custard Pi 2

import RPi.GPIO as GPIO

import time

GPIO.setmode(GPIO.BOARD)

GPIO.setup(26, GPIO.OUT) #pin26 is chip select 1

GPIO.setup(23, GPIO.OUT) #pin23 is clock

GPIO.setup(19, GPIO.OUT) #pin19 is data out

GPIO.setup(24, GPIO.OUT) #pin24 is chip select 0

GPIO.setup(21, GPIO.IN) #pin21 is data in

#set pins to default state

GPIO.output(24, True)

GPIO.output(26, True)

GPIO.output(23, False)

GPIO.output(19, True)

#set up data for ADC chip

word5= [1, 1, 0, 1, 1]

word6= [1, 1, 1, 1, 1]

#reads analogue voltge from channel 0

GPIO.output(24, False) #select channel 0

anip=0 #initialise variable

#set up channel 0

for x in range (0,5):

GPIO.output(19, word5[x])

time.sleep(0.01)

GPIO.output(23, True)

time.sleep(0.01)

GPIO.output(23, False)

for x in range (0,12):

GPIO.output(23,True)

time.sleep(0.01)

bit=GPIO.input(21)

time.sleep(0.01)

GPIO.output(23,False)

value=bit*2(12-x-1)

anip=anip+value

GPIO.output(24, True)

volt = anip*3.3/4096

return volt

#reads analogue voltge from channel 1

GPIO.output(24, False) #select channel 1

anip=0 #initialise variable

#set up channel 1

for x in range (0,5):

GPIO.output(19, word6[x])

time.sleep(0.01)

GPIO.output(23, True)

time.sleep(0.01)

GPIO.output(23, False)

for x in range (0,12):

GPIO.output(23,True)

time.sleep(0.01)

bit=GPIO.input(21)

time.sleep(0.01)

GPIO.output(23,False)

value=bit*2(12-x-1)

anip=anip+value

GPIO.output(24, True)

volt = anip*3.3/4096

return volt

Project 14 – Using the Raspberry Pi to measure current

Outline

This application note shows the hardware and Python code required to measure DC current using the Raspberry Pi. Any of the Raspberry Pi models can be used including B, B+ and the Raspberry Pi 2.

Hardware

MCP6002 op-amp: Although we can measure voltage directly using an Analogue to Digital Converter, it’s a bit more tricky measuring current. One way of measuring current is to insert a low value resistor and then measure the voltage across it. We are going to use one of the op-amps from the chip shown below to convert the voltage across the resistor into a single voltage and also to introduce some gain. This will amplify the fairly small voltage into one that we can easily measure.

Custard Pi 3: The Raspberry Pi GPIO does not have any analogue inputs so we are going to use the Custard Pi 3 which has 8 analogue inputs.

For ease of assembly, this project uses a Custard Pi base and a prototyping board. The assembled hardware is shown below.

We are going to use the 3.3V and 0V connections on the Custard Pi 3 to power the MCP6002. The circuit diagram is shown below along with a detailed description.

We are going to measure the current flowing through the LED by using a 10 ohm resistor in series with the circuit. One side of the 10ohm resistor is taken to 0V and the other taken to 0V and the other taken to the -ve input of the MCP6002.

This input has resistor 82k to the output another resistor of 10k to 0V. In this configuration the gain is given by the following equation.

Gain = 1 + 82/10 = 9.2

The main purpose of the op-amp is to amplify and buffer the signal going to the ADC (Analogue to Digital Convertor) input of the Custard Pi 3. ie the input resistance of the ADC has no effect on the voltage of the measuring circuits.

The voltage measured by the Custard Pi 3 is first divided by 9.2 to give the voltage across the 10 ohm resistor. Dividing this by 10 gives the current in amps. Multiply by a 1000 to give the current in milli-amps.

Software

To make life easier, we are going to use a routine called cpi3x.py to read the voltage from one of the 8 channels available on the Custard Pi 3. This has been provided by SF Innovations and is available on their website under the ‘Downloads’ tab. A full listing of cpi2adc.py is also provided in appendix A.

By using the function ‘readanalog(y)’ the program for measuring the current is very simple. The Python code below reads the voltage on channel 0, converts it to a current in milli-amps and prints the result.

import RPi.GPIO as GPIO

from time import sleep

import cpi3x

GPIO.setmode(GPIO.BOARD)

while True:

I = V/10

I = I*1000

I = I/9.2

I = round(I,1)

print “current in mA =”, I

print

sleep (1)

The above program uses the routine ‘readanalog(0)’ in cpi3x.py to read in the voltage across the 10 ohm resistor multiplied by 9.2. This value is then divided by 9.2 to compensate for the gain of the op-amp and divided by 10 to work out the current through the 10 ohm resistor. This is then printed to the screen.

Modify the circuit and program to measure higher currents of up to 1 amp.

Notes:

The Custard Pi 3 and Custard Base are available from amazon.co.uk and directly from SF Innovations. The code presented here can be downloaded from the SF Innovations website.

Appendix A – cpi3x

The function ‘readanalog(y)’ in this routine returns a value in volts for channel y.

#1/usr/bin/env python

#Program to read an analogue input on Custard Pi 3

#www.sf-innovations.co.uk

import RPi.GPIO as GPIO

import time

GPIO.setmode(GPIO.BOARD)

GPIO.setup(24, GPIO.OUT) #pin 24 is chip enable

GPIO.setup(23, GPIO.OUT) #pin 23 is clock

GPIO.setup(19, GPIO.OUT) #pin 19 is data out

GPIO.setup(21, GPIO.IN, pull_up_down = GPIO.PUD_UP) #pin 21 is data in

#set pins to default state

GPIO.output(24, True)

GPIO.output(23, False)

GPIO.output(19, True)

#set address channels 0 to 7

#1st bit selects single/differential

#5th bit 1 bit delay for data

#6th bit 1st null bit of data

GPIO.output(19, True)

#select the right channel

if y == 0:

word= [1 ,1, 0, 0, 0, 1, 1] #set channel 0

if y == 1:

word= [1 ,1, 0, 0, 1, 1, 1] #set channel 1

if y == 2:

word= [1 ,1, 0, 1, 0, 1, 1] #set channel 2

if y == 3:

word= [1 ,1, 0, 1, 1, 1, 1] #set channel 3

if y == 4:

word= [1 ,1, 1, 0, 0, 1, 1] #set channel 4

if y == 5:

word= [1 ,1, 1, 0, 1, 1, 1] #set channel 5

if y == 6:

word= [1 ,1, 1, 1, 0, 1, 1] #set channel 6

if y == 7:

word= [1 ,1, 1, 1, 1, 1, 1] #set channel 7

if y == 8:

word= [1 ,0, 0, 0, 0, 1, 1] #set diff ch0 +ve ch1 -ve

if y == 9:

word= [1 ,0, 0, 0, 1, 1, 1] #set diff ch0 -ve ch1 +ve

if y == 10:

word= [1 ,0, 0, 1, 0, 1, 1] #set diff ch2 +ve ch3 -ve

if y == 11:

word= [1 ,0, 0, 1, 1, 1, 1] #set diff ch2 -ve ch3 +ve

if y == 12:

word= [1 ,0, 1, 0, 0, 1, 1] #set diff ch4 +ve ch5 -ve

if y == 13:

word= [1 ,0, 1, 0, 1, 1, 1] #set diff ch4 -ve ch5 +ve

if y == 14:

word= [1 ,0, 1, 1, 0, 1, 1] #set diff ch6 +ve ch7 -ve

if y == 15:

word= [1 ,0, 1, 1, 1, 1, 1] #set diff ch6 -ve ch7 +ve

GPIO.output(24, False) #enable chip

anip=0 #clear variable

#clock out 7 bits to select channel

for x in range (0,7):

GPIO.output(19, word[x])

time.sleep(0.01)

GPIO.output(23, True)

time.sleep(0.01)

GPIO.output(23, False)

#clock in 11 bits of data

for x in range (0,12):

GPIO.output(23,True) #set clock hi

time.sleep(0.01)

time.sleep(0.01)

GPIO.output(23,False) #set clock lo

value=bit*2(12-x-1) #work out value of this bit

#print (bit,value,anip)

GPIO.output(24, True) #disable chip

volt = anip*2.5/4096 #use ref voltage of 2.5 to work out voltage

#volt = ("%.2f" %round(volt,2)) #round to 2 decimal places

#print “voltage ch”, y, volt #print to screen

return volt

Outline

This application note describes how to read a 3 x 4 data keypad using the Raspberry Pi. Any of the Raspberry Pi models can be used including B, B+ and the Raspberry Pi 2.

Hardware

3 × 4 data keypad: This is a common low-cost keypad for data entry in an industrial control system. It has 3 columns and 4 rows.

Custard Pi 7: Although the GPIO pins of the Raspberry Pi can be used for this project, we are going to use the Custard Pi 7 for this. This has an 8 bit bi-directional port which can be used to interface to the keypad. THis project will form the basis of further projects based around the Custard Pi 7.

For ease of assembly, this project uses a Custard Pi base to mount the Raspberry Pi. The assembled hardware is shown below.

The layout of the keypad is shown here. When a key is pressed the particular row and column is connected together.

At the bottom of the keypad the connections go from left to right as shown above. Pin 1 has no solder pad on it. Then we have Column 2, Row 1 etc up to Row 2 which is at the right hand side of the keypad. The connections between this and connector J10 of the Custard Pi 7 are as follows.

table<>. <>. |<>.
p<>{color:#000;}. Output pin no on keypad |<>.
p<>{color:#000;}. Reference |<>.
p<>{color:#000;}. J10 connector number of CPi 7 |<>.
p<>{color:#000;}. reference | <>. |<>.
p<>{color:#000;}. 1 |<>.
p<>{color:#000;}.

|<>. p<>{color:#000;}.   | <>. |<>. p<>{color:#000;}. 2 |<>. p<>{color:#000;}. Col 2 |<>. p<>{color:#000;}. pin 1 |<>. p<>{color:#000;}. input bit 1 | <>. |<>. p<>{color:#000;}. 3 |<>. p<>{color:#000;}. Row 1 |<>. p<>{color:#000;}. pin 4 |<>. p<>{color:#000;}. output bit 4 | <>. |<>. p<>{color:#000;}. 4 |<>. p<>{color:#000;}. Col 1 |<>. p<>{color:#000;}. pin 0 |<>. p<>{color:#000;}. input bit 0 | <>. |<>. p<>{color:#000;}. 5 |<>. p<>{color:#000;}. Row 4 |<>. p<>{color:#000;}. pin 7 |<>. p<>{color:#000;}. output bit 7 | <>. |<>. p<>{color:#000;}. 6 |<>. p<>{color:#000;}. Col 3 |<>. p<>{color:#000;}. pin 2 |<>. p<>{color:#000;}. input bit 2 | <>. |<>. p<>{color:#000;}. 7 |<>. p<>{color:#000;}. Row 3 |<>. p<>{color:#000;}. pin 6 |<>. p<>{color:#000;}. output bit 6 | <>. |<>. p<>{color:#000;}. 8 |<>. p<>{color:#000;}. Row 2 |<>. p<>{color:#000;}. pin 5 |<>. p<>{color:#000;}. output bit 5 | <>. |<>. p<>{color:#000;}. 9 |<>. p<>{color:#000;}. no solder pad |<>. p<>{color:#000;}.   |<>. p<>{color:#000;}.   |

Software

To read the keypad, we are going to take each row low in turn and then scan column 1, 2 and 3 to see which one of these goes low. If column 1 goes low when row 1 is taken low then this means that key 1 has been pressed. If column 2 goes low when row 3 is taken low then this means that key 8 has been pressed.

However there is more to reading the keypad then just scanning the columns when each row is taken low. We need to ‘debounce’ the key inputs. When a key is pressed, it does not settle down straight away. There is mechanical ‘bounce’ where the key makes and breaks the electrical connection very fast before it settles down. If one does not ‘debounce’ in the software, a single key press can be read as a multiple key entry.

One way to debounce a key is to read it twice and if one gets a low both times then accept this as a genuine key entry. The software below uses a flag for each key to monitor this. The flag is at status 0 by default. On the first key press the status changes to 1. On the second key press the key press is accepted and the status changes to 1.

Once a key press is detected, it is important not to read it again until the key has been released. Flag status 2 and 3 are used to monitor this and also to ‘debounce’ the key release.

The software prints ‘x pressed’ and ‘x released’ to the screen when these events are detected. Keys 1 to 9 are read and displayed. It uses the cpi7y routine (which is listed in the Appendix 2) to read and write to the 8-bit port on the Custard Pi 7 board. The I2C address of the port is 0×26.

The I2C bus needs to be enabled on the Raspberry Pi before we can use it. Appendix 1 shows how to do this as well as to check the I2C bus address of all the devices on the Custard Pi 7

#1/usr/bin/env python

import time

import cpi7y #routine to manage MCP23008 8-bit port expander

#start program

cpi7y.setinandout(board1) #set LSB 4 bits as inputs and MSB 4 bits as outputs

cpi7y.setpullups(board1) #set pullup resistors on all pins

1. set the 4 outpins to high

cpi7y.setbit(board1, cpi7y.ONbit4)

cpi7y.setbit(board1, cpi7y.ONbit5)

cpi7y.setbit(board1, cpi7y.ONbit6)

cpi7y.setbit(board1, cpi7y.ONbit7)

1. initialise flags

flag1 = 0

flag2 = 0

flag3 = 0

flag4 = 0

flag5 = 0

flag6 = 0

flag7 = 0

flag8 = 0

flag9 = 0

flag0 = 0

flagstar = 0

flaghash = 0

while True:

cpi7y.clrbit(board1, cpi7y.OFFbit4) #take row 1 low

if bit0 == 0: #flag = 0 default

if flag1 <2: #flag = 1 key press 1st time

if flag1 == 1: #flag = 2 key pressed 2nd time

print “1 pressed” #flag = 3 key released 1st time

flag1=2

else:

flag1=1

if bit0 ==1:

if flag1 >1:

if flag1 == 3:

print “1 released”

flag1=0

else:

flag1=3

if bit1 == 0: #flag = 0 default

if flag2 <2: #flag = 1 key press 1st time

if flag2 == 1: #flag = 2 key pressed 2nd time

print “2 pressed” #flag = 3 key released 1st time

flag2=2

else:

flag2=1

if bit1 ==2:

if flag2 >1:

if flag2 == 3:

print “2 released”

flag2=0

else:

flag2=3

if bit2 == 0: #flag = 0 default

if flag3 <2: #flag = 1 key press 1st time

if flag3 == 1: #flag = 2 key pressed 2nd time

print “3 pressed” #flag = 3 key released 1st time

flag3=2

else:

flag3=1

if bit2 ==4:

if flag3 >1:

if flag3 == 3:

print “3 released”

flag3=0

else:

flag3=3

cpi7y.setbit(board1, cpi7y.ONbit4) #take row 1 high again

cpi7y.clrbit(board1, cpi7y.OFFbit5) #take row 2 low

if bit0 == 0: #flag = 0 default

if flag4 <2: #flag = 1 key press 1st time

if flag4 == 1: #flag = 2 key pressed 2nd time

print “4 pressed” #flag = 3 key released 1st time

flag4=2

else:

flag4=1

if bit0 ==1:

if flag4 >1:

if flag4 == 3:

print “4 released”

flag4=0

else:

flag4=3

if bit1 == 0: #flag = 0 default

if flag5 <2: #flag = 1 key press 1st time

if flag5 == 1: #flag = 2 key pressed 2nd time

print “5 pressed” #flag = 3 key released 1st time

flag5=2

else:

flag5=1

if bit1 ==2:

if flag5 >1:

if flag5 == 3:

print “5 released”

flag5=0

else:

flag5=3

if bit2 == 0: #flag = 0 default

if flag6 <2: #flag = 1 key press 1st time

if flag6 == 1: #flag = 2 key pressed 2nd time

print “6 pressed” #flag = 3 key released 1st time

flag6=2

else:

flag6=1

if bit2 ==4:

if flag6 >1:

if flag6 == 3:

print “6 released”

flag6=0

else:

flag6=3

cpi7y.setbit(board1, cpi7y.ONbit5) #take row 2 high again

cpi7y.clrbit(board1, cpi7y.OFFbit6) #take row 3 low

if bit0 == 0: #flag = 0 default

if flag7 <2: #flag = 1 key press 1st time

if flag7 == 1: #flag = 2 key pressed 2nd time

print “7 pressed” #flag = 3 key released 1st time

flag7=2

else:

flag7=1

if bit0 ==1:

if flag7 >1:

if flag7 == 3:

print “7 released”

flag7=0

else:

flag7=3

if bit1 == 0: #flag = 0 default

if flag8 <2: #flag = 1 key press 1st time

if flag8 == 1: #flag = 2 key pressed 2nd time

print “8 pressed” #flag = 3 key released 1st time

flag8=2

else:

flag8=1

if bit1 ==2:

if flag8 >1:

if flag8 == 3:

print “8 released”

flag8=0

else:

flag8=3

if bit2 == 0: #flag = 0 default

if flag9 <2: #flag = 1 key press 1st time

if flag9 == 1: #flag = 2 key pressed 2nd time

print “9 pressed” #flag = 3 key released 1st time

flag9=2

else:

flag9=1

if bit2 ==4:

if flag9 >1:

if flag9 == 3:

print “9 released”

flag9=0

else:

flag9=3

cpi7y.setbit(board1, cpi7y.ONbit6) #take row 3 high again

Notes:

The Custard Pi 7 and Custard Base are available from amazon.co.uk and directly from SF Innovations. The code presented here can be downloaded from the SF Innovations website.

Add code to allow the software to read keys *, 0 and # and display this on the screen.

Set a 4 digit PIN number in software and when the user enters this print “WELCOME” on the screen. If they enter the wrong one then print “WRONG” on the screen. Use the ‘#’ key as the enter key.

APPENDIX 1

Setting up the I2C Bus

By default, the I2C bus routines are turned off in the operating system. The following steps need to be followed to enable these.

Step 1

At the command prompt type:

sudo nano /etc/modules

This uses the nano editor to make some changes to the modules file.Add the following two lines to this file

i2c-bcm2708

i2c-dev

Then save and exit the file using CTRL-x and Y.

Step 2

Make sure that you have the I2C utilities installed by executing the following two commands. The Pi will need to be connected to the Internet for this.

sudo apt-get install python-smbus

sudo apt-get install i2c-tools

If you get a 404 error do an update first:

sudo apt-get update

Note : The installation could take a few minutes to do, depend on how busy the server is.

Now add a new user to the i2c group:

Step 3

On the Raspberry Pi, the I2C and the SPI buses are usually disabled. This is done in the /etc/modprobe.d/raspi-blacklist.conf file.

If this file is not present then there is nothing to be done. Otherwise edit the file by typing the following at the command prompt.

sudo nano /etc/modprobe.d/raspi-blacklist.conf

If the I2C and the SPI is blacklisted, you will see the following commands.

blacklist spi-bcm2708

blacklist i2c-bcm2708

Insert a # in front of these to comment them out.

Then save and exit the file using CTRL-x and Y.

After editing the file, you will need to reboot for the changes to take effect.

Step 4

Now we need to test if the I2C bus is working correctly.

Connect up the Custard Pi 6 board (or any other I2C bus device) and run the following command.

sudo i2cdetect -y 1 (for Rev 2 boards which uses port 1)

Or

sudo i2cdetect -y 0 (for Rev 1 boards which uses port 0)

If everything is OK, then the I2C address of the device will be shown as on the following slide. This shows two devices with address 40 and 70 in hexadecimal code. .

Now that we have set up the I2C serial bus routines, we are ready to drive the relays on the Custard Pi 6.

APPENDIX 2

This routine assists the user in writing to and reading from the 8-bit port expander using the I2C bus.

#1/usr/bin/env python

import time

import smbus

#********************************************

1. Custard Pi 7 resources v1.0 5th Dec 2013

#Set suitable address on Custard Pi 7

bus=smbus.SMBus(1)

#set IODIR register

iodir= 0×00

#set bit 0 to 3 as inputs,bits 4 to 7 as outputs

inout= 0×0F

#set GPIO register

gpio= 0×09

#set output latch

olat=0×0A

#set output HIGH

ONbit4= 0×10

ONbit5= 0×20

ONbit6= 0×40

ONbit7= 0×80

#set output LOW

OFFbit4= 0xEF

OFFbit5= 0xDF

OFFbit6= 0xBF

OFFbit7= 0×7F

#sets selected port pin

#clears selected port pin

#read status of bit 0 to 3

return bitvalue

#set inputs & outputs

#set inputs & outputs

#clear all outputs low