Authorized Online Retailers:
![]() |
![]() |
![]() |
In previous lesson, we’ve learned how to output Raspberry Pi data through IIC (sometimes call I2C) and display characters in 1602 LCD . This lesson, we’ll combine our knowledge learnt from Lesson 11 and Lesson 13. We will use a potentionmeter to change voltage, convert the voltage analog signal to digit signal through MCP3008 and send it to Pi via SPI. Then Pi will send voltage data via I2C and display data on 1602 LCD screen.
1 * Raspberry Pi
1 * Breadboard
1 * Potentiometer(10kΩ)
1 * IIC 1602 LCD
Several jumper wires
Software Preparation
Note: In this lesson, we remotely control raspberry pi via PuTTy on PC. To learn how to config raspberry pi, please visit lesson 1: getting started with raspberry pi.
A Potentiometer is an adjustable resistor with three-terminal: two end terminals and a wiper. it could create a variable resistor using one of the end terminals and the wipers by sliding wiper to adjust the resistor value. for more information ,please click here.
The construction and working of a Potentiometer can be understood from the below diagram, A and B are end terminals, C is wiper.

In this project, we’ll wire up the Pi with an external MCP3008 ADC, and measure the analog value via that. Then display the voltage value on 1602 LCD,The schematic as shown below:

Regarding how to enable SPI and I2C, please read lesson10 and lesson13
for C language user
1) Download the C sample code by typing following command in terminal:
cd ~
sudo wget http://osoyoo.com/driver/pi3_start_learning_kit_lesson_15/voltmeter.c
If you want to customize the sample code file , you can use nano editor to edit source code by typing following command:
sudo nano voltmeter.c
2) Compile code
gcc -Wall -o voltmeter voltmeter.c -lwiringPi
3) Run the program
Before running program, please run command gpio readall to check whether MOSI、MISO、SCLK(B10、B9、B11) works as alternative functions, If the terminal shows as following:
Please run the following command to change as alternative functions
gpio -g mode 9 alt0
gpio -g mode 10 alt0
gpio -g mode 11 alt0
If the terminal shows as the following, please go on running program

sudo ./voltmeter
4) Running result
Once you run the program,the terminal will show print message as code firstly. the 1602 lcd will display the Potentiometer voltage, rotate the shaft of the potentiometer to adjust voltage between 0-3.3V.
C language Code Analysis
#include < stdint.h>
#include < string.h>
#include < errno.h>
#include < wiringPi.h>
#include < stdio.h>
#include < stdlib.h>
#include < wiringPiSPI.h>
#include < wiringPiI2C.h>
#define LCDADDR 0x3F //IIC LCD address
#define BLEN 1 //1--open backlight,0--close backlight
#define CHAN_CONFIG_SINGLE 8 //setup channel 0 as Single-ended input
#define SPICHANNEL 0 //MCP3008 connect to SPI0
#define ANALOGCHANNEL 0 //Potentiometer connect MCP3008 analog channel 0
static int spifd ;
static int i2cfd;
void spiSetup (int spiChannel)
{
if ((spifd = wiringPiSPISetup (spiChannel, 10000)) < 0)
{
fprintf (stderr, "Can't open the SPI bus: %s\n", strerror (errno)) ;
exit (EXIT_FAILURE) ;
}
}
int myAnalogRead(int spiChannel,int channelConfig,int analogChannel)
{
if(analogChannel7)
return -1;
unsigned char buffer[3] = {1}; // start bit
buffer[1] = (channelConfig+analogChannel) << 4;
wiringPiSPIDataRW(spiChannel, buffer, 3);
return ( (buffer[1] & 3 ) << 8 ) + buffer[2]; // get last 10 bits
}
void print_info()
{
printf("\n");
printf("|************************************|\n");
printf("| Voltemter |\n");
printf("| ------------------------- |\n");
printf("| | ADC | | Pi | |\n");
printf("| |-----|-----------|-----| |\n");
printf("| | CS | connect to| CE0 | |\n");
printf("| | Din | connect to| MOSI| |\n");
printf("| | Dout| connect to| MISO| |\n");
printf("| | CLK | connect to| SCLK| |\n");
printf("| | CH0 | connect to| 3.3V| |\n");
printf("| | CH1 | connect to| GND | |\n");
printf("|************************************|\n");
printf("| Potentiometer connect to ADC CH0 |\n");
printf("| OSOYOO|\n");
printf("|************************************|\n");
printf("\n");
}
//write a word to lcd
void write_word(int data){
int temp = data;
if ( BLEN == 1 )
temp |= 0x08;
else
temp &= 0xF7;
wiringPiI2CWrite(i2cfd, temp);
}
//send command to lcd
void send_command(int comm){
int buf;
// Send bit7-4 firstly
buf = comm & 0xF0;
buf |= 0x04; // RS = 0, RW = 0, EN = 1
write_word(buf);
delay(2);
buf &= 0xFB; // Make EN = 0
write_word(buf);
// Send bit3-0 secondly
buf = (comm & 0x0F) << 4;
buf |= 0x04; // RS = 0, RW = 0, EN = 1
write_word(buf);
delay(2);
buf &= 0xFB; // Make EN = 0
write_word(buf);
}
//send data to lcd
void send_data(int data){
int buf;
// Send bit7-4 firstly
buf = data & 0xF0;
buf |= 0x05; // RS = 1, RW = 0, EN = 1
write_word(buf);
delay(2);
buf &= 0xFB; // Make EN = 0
write_word(buf);
// Send bit3-0 secondly
buf = (data & 0x0F) << 4;
buf |= 0x05; // RS = 1, RW = 0, EN = 1
write_word(buf);
delay(2);
buf &= 0xFB; // Make EN = 0
write_word(buf);
}
//initialize the lcd
void init(){
send_command(0x33); // Must initialize to 8-line mode at first
delay(5);
send_command(0x32); // Then initialize to 4-line mode
delay(5);
send_command(0x28); // 2 Lines & 5*7 dots
delay(5);
send_command(0x0C); // Enable display without cursor
delay(5);
send_command(0x01); // Clear Screen
wiringPiI2CWrite(i2cfd, 0x08);
}
//clear screen
void clear(){
send_command(0x01); //clear Screen
}
//Print the message on the lcd
void write(int x, int y, char data[]){
int addr, i;
int tmp;
if (x < 0) x = 0; if (x > 15) x = 15;
if (y < 0) y = 0; if (y > 1) y = 1;
// Move cursor
addr = 0x80 + 0x40 * y + x;
send_command(addr);
tmp = strlen(data);
for (i = 0; i < tmp; i++){
send_data(data[i]);
}
}
int main()
{
int adc;
float voltage;
char buf[5];
if(wiringPiSetup() < 0)
{ fprintf(stderr,"Can't init wiringPi: %s\n",strerror(errno));
exit(EXIT_FAILURE);
}
spiSetup(SPICHANNEL);//init spi
i2cfd = wiringPiI2CSetup(LCDADDR);//init i2c
init();//init LCD
clear();//clear screen
print_info();
while(1)
{
adc = myAnalogRead(SPICHANNEL,CHAN_CONFIG_SINGLE,ANALOGCHANNEL);
voltage = adc/1024.*3.3;
write(0,0,"Voltage:");
sprintf(buf,"%1.2f",voltage);//float change to string
write(8,0,buf);//print voltage on lcd
write(12,0,"V");//print unit
write(8,1,"--OSOYOO");
delay(1000);
}
return 0;
}
For python user, please take steps as following:
1) Download the python sample code by typing the command as followed:
cd ~
sudo wget http://osoyoo.com/driver/pi3_start_learning_kit_lesson_15/voltmeter.py
If you want to customize the sample code file , you can use nano editor to edit source code by typing following command:
sudo nano voltmeter.py
2) Run the program
sudo python ./voltmeter.py
3) Running result
Once you run the program,the terminal will show print message as code firstly. the 1602 lcd will display the Potentiometer voltage, rotate the shaft of the potentiometer to adjust voltage between 0-3.3V.
Python sample code Analysis
import time
import os
import RPi.GPIO as GPIO
import smbus
# Define some device parameters
I2C_ADDR = 0x3F # I2C device address, if any error, change this address to 0x27
LCD_WIDTH = 16 # Maximum characters per line
# Define some device constants
LCD_CHR = 1 # Mode - Sending data
LCD_CMD = 0 # Mode - Sending command
LCD_LINE_1 = 0x80 # LCD RAM address for the 1st line
LCD_LINE_2 = 0xC0 # LCD RAM address for the 2nd line
LCD_LINE_3 = 0x94 # LCD RAM address for the 3rd line
LCD_LINE_4 = 0xD4 # LCD RAM address for the 4th line
LCD_BACKLIGHT = 0x08 # On
#LCD_BACKLIGHT = 0x00 # Off
ENABLE = 0b00000100 # Enable bit
# Timing constants
E_PULSE = 0.0005
E_DELAY = 0.0005
# change these as desired - they're the pins connected from the
# SPI port on the ADC to the Cobbler
SPICLK = 11
SPIMISO = 9
SPIMOSI = 10
SPICS = 8
analogChannel = 0
#Open I2C interface
#bus = smbus.SMBus(0) # Rev 1 Pi uses 0
bus = smbus.SMBus(1) # Rev 2 Pi uses 1
#setup function for some setup---custom function
def setup():
#set the gpio modes to BCM numbering
GPIO.setmode(GPIO.BCM)
# set up the SPI interface pins
GPIO.setup(SPIMOSI, GPIO.OUT)
GPIO.setup(SPIMISO, GPIO.IN)
GPIO.setup(SPICLK, GPIO.OUT)
GPIO.setup(SPICS, GPIO.OUT)
pass
def lcd_init():
# Initialise display
lcd_byte(0x33,LCD_CMD) # 110011 Initialise
lcd_byte(0x32,LCD_CMD) # 110010 Initialise
lcd_byte(0x06,LCD_CMD) # 000110 Cursor move direction
lcd_byte(0x0C,LCD_CMD) # 001100 Display On,Cursor Off, Blink Off
lcd_byte(0x28,LCD_CMD) # 101000 Data length, number of lines, font size
lcd_byte(0x01,LCD_CMD) # 000001 Clear display
time.sleep(E_DELAY)
def lcd_byte(bits, mode):
# Send byte to data pins
# bits = the data
# mode = 1 for data
# 0 for command
bits_high = mode | (bits & 0xF0) | LCD_BACKLIGHT
bits_low = mode | ((bits<<4) & 0xF0) | LCD_BACKLIGHT # High bits bus.write_byte(I2C_ADDR, bits_high) lcd_toggle_enable(bits_high) # Low bits bus.write_byte(I2C_ADDR, bits_low) lcd_toggle_enable(bits_low) def lcd_toggle_enable(bits): # Toggle enable time.sleep(E_DELAY) bus.write_byte(I2C_ADDR, (bits | ENABLE)) time.sleep(E_PULSE) bus.write_byte(I2C_ADDR,(bits & ~ENABLE)) time.sleep(E_DELAY) def lcd_string(message,line): # Send string to display message = message.ljust(LCD_WIDTH," ") lcd_byte(line, LCD_CMD) for i in range(LCD_WIDTH): lcd_byte(ord(message[i]),LCD_CHR) #print message at the begining ---custom function def print_message(): print ('|**********************************|') print ('| Voltmeter |') print ('| ------------------------- |') print ('| | ADC | | Pi | |') print ('| |-----|-----------|-----| |') print ('| | CS | connect to| CE0 | |') print ('| | Din | connect to| MOSI| |') print ('| | Dout| connect to| MISO| |') print ('| | CLK | connect to| SCLK| |') print ('| | CH0 | connect to| 3.3V| |') print ('| | CH1 | connect to| GND | |') print ('| ------------------------- |') print ('| Potentiometer connect to CH0 |') print ('| OSOYOO|') print ('|**********************************|\n') print ('Program is running...') print ('Please press Ctrl+C to end the program...') # read SPI data from MCP3008 chip, 8 possible adc's (0 thru 7) def readadc(adcnum, clockpin, mosipin, misopin, cspin): if ((adcnum > 7) or (adcnum < 0)):
return -1
GPIO.output(cspin, True)
GPIO.output(clockpin, False) # start clock low
GPIO.output(cspin, False) # bring CS low
commandout = adcnum
commandout |= 0x18 # start bit + single-ended bit
commandout <<= 3 # we only need to send 5 bits here
for i in range(5):
if (commandout & 0x80):
GPIO.output(mosipin, True)
else:
GPIO.output(mosipin, False)
commandout <<= 1
GPIO.output(clockpin, True)
GPIO.output(clockpin, False)
adcout = 0
# read in one empty bit, one null bit and 10 ADC bits
for i in range(12):
GPIO.output(clockpin, True)
GPIO.output(clockpin, False)
adcout <<= 1 if (GPIO.input(misopin)): adcout |= 0x1 GPIO.output(cspin, True) adcout >>= 1 # first bit is 'null' so drop it
return adcout
#main function
def main():
#print info
print_message()
# Initialise display
lcd_init()
#clear screen
lcd_byte(0x01, LCD_CMD)
while True:
adc = readadc(analogChannel, SPICLK, SPIMOSI, SPIMISO, SPICS)
voltage = round((adc/1024.*3.3),2)
voltage = str(voltage) #float change to string
lcd_string("Voltage: <",LCD_LINE_1)
lcd_string(voltage,LCD_LINE_2)
time.sleep(1.5)
#define a destroy function for clean up everything after the script finished
def destroy():
#release resource
GPIO.cleanup()
#
# if run this script directly ,do:
if __name__ == '__main__':
setup()
try:
main()
#when 'Ctrl+C' is pressed,child program destroy() will be executed.
except KeyboardInterrupt:
destroy()
pass
#clear screen
finally:
lcd_byte(0x01, LCD_CMD)
DownLoad Url osoyoo.com
You must be logged in to post a comment.
Where is the function to toggle the backlight on/off?
You can turn around the Potentiometer at the back of LCD to adjust LCD backlight
I know about the potentiometer. But i am asking about the function to turn off the backlight from the python code. the backlight consumes too much battery so i need to put it to sleep for some time.