Raspberry Pi GPIO projects
Seggy T Segaran
First published in 2015 by Ohm Books Publishing
Kindle Version 2015 V1
© 2015 Seggy T Segaran
All rights reserved.
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 15 – Reading a keypad with the Raspberry Pi
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)
read=cpi3x.readanalog
while True:
V = read(0)
V = round(V,3)
print V
t = (1000*V-500)/10
print “Ch 0 temperature = “, t
sleep (1)
(Download this code from here: http://www.sf-innovations.co.uk/downloads)
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.
Ideas for advanced projects
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.
(Download this code from here: http://www.sf-innovations.co.uk/downloads)
#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
#2nd bit channel address
#3rd bit channel address
#4th bit channel address
#5th bit 1 bit delay for data
#6th bit 1st null bit of data
def readanalog(y):
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)
bit=GPIO.input(21) #read input
time.sleep(0.01)
GPIO.output(23,False) #set clock lo
value=bit*2(12-x-1) #work out value of this bit
anip=anip+value #add to previous total
#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()
(Download this code from here: http://www.sf-innovations.co.uk/downloads)
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.
Ideas for Advanced projects
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:
sudo adduser pi i2c
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
class i2c_device:
def init(self, addr, port):
self.addr = addr
self.bus = smbus.SMBus(port)
def write(self, byte):
self.bus.write_byte(self.addr, byte)
def read(self):
return self.bus.read_byte(self.addr)
def read_nbytes_data(self, data, n): # For sequential reads > 1 byte
return self.bus.read_i2c_block_data(self.addr, data, n)
class lcd:
#initializes objects and lcd
def init(self, addr, port):
delay=0.0005
self.lcd_device = i2c_device(addr, port)
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)
def lcd_strobe(self):
self.lcd_device.write((self.lcd_device.read() | 0×04))
self.lcd_device.write((self.lcd_device.read() & 0xFB))
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)
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)
def lcd_putc(self, char):
self.lcd_write_char(ord(char))
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)
def lcd_clear(self):
self.lcd_write(0×1)
self.lcd_write(0×2)
def lcd_load_custon_chars(self, fontdata):
self.lcd_device.bus.write(0×40);
for char in fontdata:
for line in char:
self.lcd_write_char(line)
(Download this code from here: http://www.sf-innovations.co.uk/downloads)
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
import cpi2adc
GPIO.setmode(GPIO.BOARD)
read0=cpi2adc.readchannel0
read1=cpi2adc.readchannel1
while True:
V=read0()
V=V*10.99
V=V/2
V= round (V,2)
print “Battery Voltage=”, V
sleep (1)
(Download this code from here: http://www.sf-innovations.co.uk/downloads)
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.
Ideas for advanced projects
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.
Appendix A – cpi2adc
The functions ‘readchannel0()’ and ‘readchannel1() in this routine return a value in volts for input to channel 0 and channel 1.
(Download this code from here: http://www.sf-innovations.co.uk/downloads)
#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]
def readchannel0():
#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)
#read analogue voltage
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
def readchannel1():
#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)
#read analogue voltage
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)
read=cpi3x.readanalog
while True:
V = read(0)
I = V/10
I = I*1000
I = I/9.2
I = round(I,1)
print “current in mA =”, I
sleep (1)
(Download this code from here: http://www.sf-innovations.co.uk/downloads)
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.
Ideas for advanced projects
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.
(Download this code from here: http://www.sf-innovations.co.uk/downloads)
#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
#2nd bit channel address
#3rd bit channel address
#4th bit channel address
#5th bit 1 bit delay for data
#6th bit 1st null bit of data
def readanalog(y):
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)
bit=GPIO.input(21) #read input
time.sleep(0.01)
GPIO.output(23,False) #set clock lo
value=bit*2(12-x-1) #work out value of this bit
anip=anip+value #add to previous total
#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 15 – Reading a keypad with the Raspberry Pi
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;}. no solder pad
|<>.
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
#program to read keypad and print results to screen
import time
import cpi7y #routine to manage MCP23008 8-bit port expander
#start program
board1=cpi7y.add6 #set I2C address
cpi7y.setinandout(board1) #set LSB 4 bits as inputs and MSB 4 bits as outputs
cpi7y.setpullups(board1) #set pullup resistors on all pins
cpi7y.setbit(board1, cpi7y.ONbit4)
cpi7y.setbit(board1, cpi7y.ONbit5)
cpi7y.setbit(board1, cpi7y.ONbit6)
cpi7y.setbit(board1, cpi7y.ONbit7)
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
bit0 = (cpi7y.readbit (board1, 0×01)) #read col 1
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
bit1 = (cpi7y.readbit (board1, 0×02)) #read col 2
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
bit2 = (cpi7y.readbit (board1, 0×04)) #read col 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
bit0 = (cpi7y.readbit (board1, 0×01)) #read col 1
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
bit1 = (cpi7y.readbit (board1, 0×02)) #read col 2
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
bit2 = (cpi7y.readbit (board1, 0×04)) #read col 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
bit0 = (cpi7y.readbit (board1, 0×01)) #read col 1
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
bit1 = (cpi7y.readbit (board1, 0×02)) #read col 2
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
bit2 = (cpi7y.readbit (board1, 0×04)) #read col 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
(Download this code from here: http://www.sf-innovations.co.uk/downloads)
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.
Ideas for Advanced projects
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:
sudo adduser pi i2c
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.
(Download this code from here: http://www.sf-innovations.co.uk/downloads)
#1/usr/bin/env python
import time
import smbus
#********************************************
#I2C addresses
#Set suitable address on Custard Pi 7
add0= 0×20
add1= 0×21
add2= 0×22
add3= 0×23
add4= 0×24
add5= 0×25
add6= 0×26
add7= 0×27
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
def setbit(address, byte):
#sets selected port pin
outstatus = bus.read_byte_data(address, olat) | byte
bus.write_byte_data(address, gpio, outstatus)
def clrbit(address, byte):
#clears selected port pin
outstatus = bus.read_byte_data(address, olat) & byte
bus.write_byte_data (address, gpio, outstatus)
def readbit(address, bit):
#read status of bit 0 to 3
bitvalue = bus.read_byte_data(address, gpio) & bit
return bitvalue
def setinandout(address):
#set inputs & outputs
bus.write_byte_data(address, iodir, inout)
def setpullups(address):
#set inputs & outputs
bus.write_byte_data(address, 0×06, 0xFF)
def alloff(address):
#clear all outputs low
bus.write_byte_data (address, gpio, 0×00)
#******************************************