In this post I will demonstrate how you can utilize a modest PICAXE micro-controller as a multi channel ADC.We would be utilizing I2C bus to access the PICAXE, which will dump the values to memory registers.Your Pi must be configured to use the I2C bus.You can refer to this post for setting up I2C.
Very few PICAXEs can act as an I2C slave.One of them is 28X1. I have collected some fundamental information about PICAXEs, but in the event that you have never utilized one before, I suggest you to get basic knowledge about PICAXE's (Google is your friend ;) ).
You will require a minimum working circuit for PICAXe with power,reset and download socket to proceed.Here I am connecting 4 potentiometer with the ADC channel of PICAXE to demonstrate the working.
You will need to download the below code into your PICAXE. Values from ADC is dumped into the micro-controller's scratchpad memory which can be accessed via I2C bus.
#no_data
#no_table
hi2csetup i2cslave, 100000
main:
readadc 0,b1
readadc 1, b2
readadc 2, b3
readadc 3, b4
put 1, b1
put 2, b2
put 3, b3
put 4, b4
goto main
Code for Raspberry Pi:-
I have created a python script to access the PICAXE's scratchpad memory over I2C bus.It reads and displays the values.Save the script as read_adc.py.
import smbus
import time
bus=smbus.SMBus(0)
add=0x10
def read(reg):
value=bus.read_byte_data(add, reg)
return value
adc_channel1=0
adc_channel2=0
adc_channel3=0
adc_channel4=0
while True:
adc_channel1=read(1)
adc_channel2=read(2)
adc_channel3=read(3)
adc_channel4=read(4)
print adc_channel1
print adc_channel2
print adc_channel3
print adc_channel4
time.sleep(0.3)
Testing:-
Run the script on your pi as-
root@raspberrypi:~# sudo python read_adc.py
It should now display the ADC values in your screen!
Warning:- Use a voltage level shifter ( 5V <----> 3.3V ) when interfacing the PICAXE with Raspberry Pi, as Pi cannot tolerate 5V!.
(Update):- If you have a Raspberry Pi with a revision 2.0 board, you need to use I²C bus 1, not bus 0, so you will need to change the bus number used. In this case, the line bus=smbus.SMBus(0) would become bus=smbus.SMBus(1).
You can check that the device is present on the bus by using the i2cdetect program from the i2ctools package-
i2cdetect 0 -y or i2cdetect 1 -y
Hitachi HD44780 based 16x2 character LCD are very cheap and widely available, and is a essential part for any projects that displays information. Using the I2C bus on Raspberry Pi ,PCF8574 IC, and Python characters/strings can be displayed on the LCD. The PCF8574 is an general purpose bidirectional 8 bit I/O port expander that uses the I2C protocol.
The LCD(HD44780) is connected in 4 bit mode as follows to the PCF8574:-

P0 - D4
P1 - D5
P2 - D6
P3 - D7
P4 - RS
P5 - R/W
P6 - E
Port A0 is connected to VCC(5V) with a 10k resistor so that it will be addressed at 0x21.
Coming to the software part, Python is used to drive the logic.I have written a simple library to communicate with the LCD using the I2C bus.For this code to work python-smbus package must be installed(sudo apt-get install python-smbus).Save the below code as pylcdlib.py.
import smbus
from time import *
# General i2c device class so that other devices can be added easily
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
'''
Reverse Codes:
0: lower 4 bits of expander are commands bits
1: top 4 bits of expander are commands bits AND P0-4 P1-5 P2-6
2: top 4 bits of expander are commands bits AND P0-6 P1-5 P2-4
'''
def __init__(self, addr, port, reverse=0):
self.reverse = reverse
self.lcd_device = i2c_device(addr, port)
if self.reverse:
self.lcd_device.write(0x30)
self.lcd_strobe()
sleep(0.0005)
self.lcd_strobe()
sleep(0.0005)
self.lcd_strobe()
sleep(0.0005)
self.lcd_device.write(0x20)
self.lcd_strobe()
sleep(0.0005)
else:
self.lcd_device.write(0x03)
self.lcd_strobe()
sleep(0.0005)
self.lcd_strobe()
sleep(0.0005)
self.lcd_strobe()
sleep(0.0005)
self.lcd_device.write(0x02)
self.lcd_strobe()
sleep(0.0005)
self.lcd_write(0x28)
self.lcd_write(0x08)
self.lcd_write(0x01)
self.lcd_write(0x06)
self.lcd_write(0x0C)
self.lcd_write(0x0F)
# clocks EN to latch command
def lcd_strobe(self):
if self.reverse == 1:
self.lcd_device.write((self.lcd_device.read() | 0x04))
self.lcd_device.write((self.lcd_device.read() & 0xFB))
if self.reverse == 2:
self.lcd_device.write((self.lcd_device.read() | 0x01))
self.lcd_device.write((self.lcd_device.read() & 0xFE))
else:
self.lcd_device.write((self.lcd_device.read() | 0x10))
self.lcd_device.write((self.lcd_device.read() & 0xEF))
# write a command to lcd
def lcd_write(self, cmd):
if self.reverse:
self.lcd_device.write((cmd >> 4)<<4)
self.lcd_strobe()
self.lcd_device.write((cmd & 0x0F)<<4)
self.lcd_strobe()
self.lcd_device.write(0x0)
else:
self.lcd_device.write((cmd >> 4))
self.lcd_strobe()
self.lcd_device.write((cmd & 0x0F))
self.lcd_strobe()
self.lcd_device.write(0x0)
# write a character to lcd (or character rom)
def lcd_write_char(self, charvalue):
if self.reverse == 1:
self.lcd_device.write((0x01 | (charvalue >> 4)<<4))
self.lcd_strobe()
self.lcd_device.write((0x01 | (charvalue & 0x0F)<<4))
self.lcd_strobe()
self.lcd_device.write(0x0)
if self.reverse == 2:
self.lcd_device.write((0x04 | (charvalue >> 4)<<4))
self.lcd_strobe()
self.lcd_device.write((0x04 | (charvalue & 0x0F)<<4))
self.lcd_strobe()
self.lcd_device.write(0x0)
else:
self.lcd_device.write((0x40 | (charvalue >> 4)))
self.lcd_strobe()
self.lcd_device.write((0x40 | (charvalue & 0x0F)))
self.lcd_strobe()
self.lcd_device.write(0x0)
# put char function
def lcd_putc(self, char):
self.lcd_write_char(ord(char))
# put string function
def lcd_puts(self, string, line):
if line == 1:
self.lcd_write(0x80)
if line == 2:
self.lcd_write(0xC0)
if line == 3:
self.lcd_write(0x94)
if line == 4:
self.lcd_write(0xD4)
for char in string:
self.lcd_putc(char)
# clear lcd and set to home
def lcd_clear(self):
self.lcd_write(0x1)
self.lcd_write(0x2)
# add custom characters (0 - 7)
def lcd_load_custon_chars(self, fontdata):
self.lcd_device.bus.write(0x40);
for char in fontdata:
for line in char:
self.lcd_write_char(line)
Main Program:-
import pylcdlib
lcd = pylcdlib.lcd(0x21,0)
lcd.lcd_puts("Raspberry Pi",1) #display "Raspberry Pi" on line 1
lcd.lcd_puts(" Take a byte!",2) #display "Take a byte!" on line 2
Save the above code as test_lcd.py and enter sudo python test_lcd.py
My code assumes that the first 4 bits of the LCD(11,12,13,14) are connected to P0,P1,P2,P3 ports on PCF8574. The next 3 ports on PCF8574(P4,P5,P6) should be connected to 4-RS, 5-R/W, 6-E.However there are other serial backpack lcd's with different pinouts. According to the wiring of your serial backpack LCD you can override the default mapping during initialization.There are 3 modes available-
lcd = pylcdlib.lcd(0x21,0) lower 4 bits of expander are commands bits
lcd = pylcdlib.lcd(0x21,0,1) top 4 bits of expander are commands bits AND P0-4 P1-5 P2-6
lcd = pylcdlib.lcd(0x21,0,2) top 4 bits of expander are commands bits AND P0-6 P1-5 P2-4
(Update):- If you have a Raspberry Pi with a revision 2.0 board, you need to use I²C bus 1, not bus 0, so you will need to change the bus number used. In this case, the line lcd = pylcdlib.lcd(0x21,0) would become lcd = pylcdlib.lcd(0x21,1).
You can check that the device is present on the bus by using the i2cdetect program from the i2ctools package-
i2cdetect 0 -y or i2cdetect 1 -y
The TMP102 is an I2C temperature sensor from Texas Instruments.It's a perfect sensor for Raspberry Pi as it lacks any onboard ADC and TMP102 eliminates the requirement for analyzing the analog signals.When compared with the analog sensors TMP102 is very accurate and capable of measuring 0.0625ºC changes between -25°C and +85°C.

If you have more than one device on the I2C bus you can modify the address of the sensor using the address pin (ADD0).The sensor's address will be 72(0×48 in hex) when the address pin is grounded.It will be set to 73 (0×49 in hex) if the address pin is tied to VCC.
Pi GPI0 Function
---------------------------
Pin 2 SDA
Pin 3 SCL
Pin 26 5V
Make sure your system has the latest version of Linux 3.2 kernel and a proper I2C driver.Also you will be requiring two utilities:-
1) "lm-sensors" package, enter "apt-get install lm-sensors"
2) "I2C tools" package, enter "apt-get install i2c-tools"
After installation we can now use the modprobe i2c-tools.Run "i2cdetect" to check whether TMP102 is connected.
root@raspberrypi:~# i2cdetect -y 0
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- 48 -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
As we have received the address from i2cdetect, the system has to be updated to get new drivers.
rahul@raspberrypi:~# echo tmp102 0x48 > /sys/class/i2c-adapter/i2c-0/new_device
Run the "sensors" command to get the temperature:-
rahul@raspberrypi:~# sensors
tmp102-i2c-0-48
Adapter: bcm2708_i2c.0
temp1: +35.7°C (high = +70.0°C, hyst = +55.0°C)
(Update):- If you have a Raspberry Pi with a revision 2.0 board, you need to use I²C bus 1, not bus 0.You can check that the device is present on the bus by using the i2cdetect program from the i2ctools package:-
i2cdetect 0 -y or i2cdetect 1 -y

If you have more than one device on the I2C bus you can modify the address of the sensor using the address pin (ADD0).The sensor's address will be 72(0×48 in hex) when the address pin is grounded.It will be set to 73 (0×49 in hex) if the address pin is tied to VCC.
Pi GPI0 Function
---------------------------
Pin 2 SDA
Pin 3 SCL
Pin 26 5V
Make sure your system has the latest version of Linux 3.2 kernel and a proper I2C driver.Also you will be requiring two utilities:-
1) "lm-sensors" package, enter "apt-get install lm-sensors"
2) "I2C tools" package, enter "apt-get install i2c-tools"
After installation we can now use the modprobe i2c-tools.Run "i2cdetect" to check whether TMP102 is connected.
root@raspberrypi:~# i2cdetect -y 0
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- 48 -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
As we have received the address from i2cdetect, the system has to be updated to get new drivers.
rahul@raspberrypi:~# echo tmp102 0x48 > /sys/class/i2c-adapter/i2c-0/new_device
Run the "sensors" command to get the temperature:-
rahul@raspberrypi:~# sensors
tmp102-i2c-0-48
Adapter: bcm2708_i2c.0
temp1: +35.7°C (high = +70.0°C, hyst = +55.0°C)
(Update):- If you have a Raspberry Pi with a revision 2.0 board, you need to use I²C bus 1, not bus 0.You can check that the device is present on the bus by using the i2cdetect program from the i2ctools package:-
i2cdetect 0 -y or i2cdetect 1 -y




