Raspberry Pi 5 Essentials Program Build - Dogan Ibrahim
Raspberry Pi 5 Essentials Program Build - Dogan Ibrahim
books books
books
Raspberry Pi 5
Essentials Raspberry Pi 5
Program, build, and master over 60 projects
Essentials
B u s = 0 , device=0
The Raspberry Pi 5 is the latest single-board computer from the Raspberry Pi
Program,) build, and master over 60 projects
#
spi.open(0, 0
Foundation. It can be used in many applications, such as in audio and
with
0000Python
0
video media centers, as a desktop computer, in industrial controllers,
robotics, and in many domestic and commercial applications. In addition
p e e d _ h z = 3 9
_s
spi.max
Prof Dogan Ibrahim has a BSc
to the well-established features found in other Raspberry Pi computers, (Hons) degree in Electronic
R I E D output
S
# GPIO26 is C
the Raspberry Pi 5 offers Wi-Fi and Bluetooth (classic and BLE), which Engineering, an MSc degree in
ED •
T
Automatic Control Engineering,
makes it a perfect match for IoT as well as in remote and Internet-based
CS = LED(26)
and a PhD degree in Digital Signal
• T
# Disable CESS T
control and monitoring applications. It is now possible to develop many Processing and Microprocessors.
real-time projects such as audio digital signal processing, real-time digital
CS.on()
filtering, real-time digital control and monitoring, and many other real-time Dogan has worked in many
operations using this tiny powerhouse. organizations and is a Fellow of
the Institution of Engineering
ta in „d
and Technology (IET) in UK as
a
The book starts with an introduction to the Raspberry Pi 5 computer well as a Chartered Electrical
D A C . T h e d
ements the
and covers the important topics of accessing the computer locally and Engineer. He has authored over
remotely. Use of the console language commands as well as accessing 100 technical books and over
u n c t i o n i m p l
and using the desktop GUI are described with working examples. The 200 technical articles on electronics,
# This f
# to the DAC
microprocessors, microcontrollers,
remaining parts of the book cover many Raspberry Pi 5-based hardware
and related fields. Dogan is a
projects using components and devices such as certified Arduino professional and
has many years of experience with
> LEDs and buzzers numerous types of microprocessors
:
def DAC(data) # Enable CS
> LCDs and microcontrollers.
> Ultrasonic sensors
>
>
Temperature and atmospheric pressure sensors
The Sense HAT
CS.off()
> Camera modules
#
yte
Example projects are given using Wi-Fi and Bluetooth modules to send # Send HIGH b
and receive data from smartphones and PCs, and sending real-time
# # Get upper
8) & 0x0F
temperature and atmospheric pressure data to the cloud.
> 0
temp = ( d a t a > # OR with 0x3
All projects given in the book have been fully tested for correct operation.
0x30
Only basic programming and electronics experience are required to follow Elektor International Media
temp = temp + # Send to DAC
mp])
spi.xfer2([te
the projects. Brief descriptions, block diagrams, detailed circuit diagrams, www.elektor.com
and full Python program listings are given for all projects described.
Readers can find the program listings on the Elektor Store website,
www.elektor.com (search for: book title).
#
Dogan Ibrahim
Dogan Ibrahim
● All rights reserved. No part of this book may be reproduced in any material form, including photocopying, or
storing in any medium by electronic means and whether or not transiently or incidentally to some other use of this
publication, without the written permission of the copyright holder except in accordance with the provisions of the
Copyright Designs and Patents Act 1988 or under the terms of a licence issued by the Copyright Licencing Agency
Ltd., 90 Tottenham Court Road, London, England W1P 9HE. Applications for the copyright holder's permission to
reproduce any part of the publication should be addressed to the publishers.
● Declaration
The author, editor, and publisher have used their best efforts in ensuring the correctness of the information contained
in this book. They do not assume, and hereby disclaim, any liability to any party for any loss or damage caused by
errors or omissions in this book, whether such errors or omissions result from negligence, accident or any other cause.
All the programs given in the book are Copyright of the Author and Elektor International Media. These programs
may only be used for educational purposes. Written permission from the Author or Elektor must be obtained before
any of these programs can be used for commercial purposes.
Elektor is the world's leading source of essential technical information and electronics products for pro engineers,
electronics designers, and the companies seeking to engage them. Each day, our international team develops and delivers
high-quality content - via a variety of media channels (including magazines, video, digital media, and social media) in
several languages - relating to electronics design and DIY electronics. www.elektormagazine.com
●4
Contents
Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.4 Accessing your Raspberry Pi 5 Console from your PC – the Putty program . . . . . . . 20
3.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
3.3.5 Networking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
4.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
●5
4.2.4 Terminal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
4.2.6 Wi-Fi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
6.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
7.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
7.4 Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
7.8 Indentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
7.10 Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
7.11 Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
●6
7.26 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
●7
9.9 Project 6 – Analog temperature sensor thermometer – output to the screen . . . . 156
●8
11.3 Project 1 – Generating a square wave signal with any peak voltage up to +3.3 V . 205
●9
14.4 Project 2 – Two-way communication with the smartphone using TCP/IP . . . . . . 262
15.4.2 Project 4 – Play audio (e.g. music) on Bluetooth speaker via Raspberry Pi 5 . . 303
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320
● 10
This book is about the Raspberry Pi 5 computer and its use in various control and moni-
toring applications. The book explains in simple terms and with many tested and working
example projects how to configure the Raspberry Pi 5 computer, how to use the latest
operating system (Bookworm), and how to write application programs using the popular
Python programming language.
The book starts with an introduction to the Raspberry Pi 5 computer and covers the impor-
tant topics of accessing the computer locally and remotely. Use of the console command
language as well as accessing and using the desktop GUI have been described with working
examples.
The remaining parts of the book cover many Raspberry-Pi-5-based hardware projects us-
ing components and devices such as LEDs, buzzers, LCDs, ultrasonic sensors, temperature
sensors, Sense HAT, camera modules, etc. Example projects are given using Wi-Fi and
Bluetooth modules to send and receive data from smartphones, from the PC, and sending
real-time temperature and atmospheric pressure data to the cloud.
All the projects presented in the book have been tested and are working. Complete circuit
diagrams and full program listings are given for each project, with detailed descriptions of
the operation of each project. The following subheadings are used in every project wher-
ever necessary:
• Project title
• Project description
• Block diagram
• Circuit diagram
• Program listing
• Suggestions for future work
● 11
I hope the readers find the book helpful and enjoy reading it, and use a Raspberry Pi 5 in
their next new projects.
● 12
1.1 Overview
The Raspberry Pi 5 is the latest credit card size computer from Raspberry Pi. In this chapter,
we will look at the specifications of this new computer and compare it with the Raspberry
Pi 4.
The Raspberry Pi 5 is claimed to have two or three times the processing power of The
Raspberry Pi 4, which is already a very popular single board computer. The Raspberry Pi 5
is currently available in 4 GB and 8 GB memory capacities, but smaller memory devices
may appear later. Although the Raspberry Pi 5 is the same size and shape as the Model 4B,
it has a number of interesting new features such as PCIe connector, power button, built-in
real-time clock and some others that we will investigate in this chapter.
The Raspberry Pi 5 is based on a 2.4 GHz Cortex-A76 ARM processor with a new south-
bridge for handling the peripheral interface. A new VideoCore VII GPU is provided with
800 MHz speed. The dual camera interface is another nice feature of the Raspberry Pi 5.
The microSD card interface now supports cards that work at much higher speeds.
Table 1.1 shows a comparison of the Raspberry Pi 4 and 5. Notice that both devices have
dual 2 × 4kp60 HDMI display interfaces, although Pi 5 supports HDR output. The 2 × 20 pin
GPIO interface is the same in both devices. The Raspberry Pi 5 additionally has two camera
interfaces, a PCIe bus connector, a UART interface, an RTC clock power connector, and a fan
power connector. Wi-Fi and Bluetooth are supported by both devices. The on-board power
switch on Pi 5 is a useful addition and was requested by many users. Pi 5 is powered from
5 V/4 A USB-C type power supply, where Pi 4 is powered from a 3 A power supply. Pi 5 is
slightly more expensive than Pi 4.
Raspberry Pi 4 Raspberry Pi 5
SoC BCM2711 SoC BCM2712 SoC
Cortex-A72 CPU at 1.8 GHz Cortex-A76 CPU at 2.4 GHz
CPU 4 core 4 core
Instruction set ARMv8-A ARMv8-2
Display 500 MHz VideoCore Vi GPU 800 MHz VideoCore VII GPU
L2 Cache 1 MB (shared) 2 MB
L3 Cache None 2 MB (shared)
RAM 1, 2, 4, 8 GB LPDDR4 4, 8 GB LPDDR4X
SD Card microSD microSD (high speed SDR104
compatible)
GPIO 2 × 20 pin 2 × 20 pin
● 13
There are two micro-HDMI based monitor ports on both devices, with both having the same
specifications.
The Ethernet port and USB ports are swapped. As a result of this, the Raspberry Pi 4 case
is incompatible with the Pi 5 and a new case is required.
The camera and display connectors on the Raspberry Pi 5 are 15-pin and smaller, instead
of the original 22-pin connector used on Pi 4. A ribbon cable with 22-pin on one side and
15-pin on the other side is required to connect an existing Raspberry Pi 4 camera to the
Raspberry Pi 5. The Raspberry Pi 5 has two connectors, allowing two cameras or DSI dis-
plays (or a mix of either) to be connected. The PCIe connector is for fast external PCIe
compatible peripherals, such as SSDs.
The new power button on the Raspberry Pi 5 could be very useful. When the device is On,
pressing the button brings the shutdown (logout) menu. A safe shutdown will occur with
another press of the power button.
Figure 1.1 shows the front view of the Raspberry Pi 5 with the components labelled for
reference.
● 14
The Raspberry Pi 5 gets rather hot, and it is recommended to use a cooler to lower the
CPU temperature. Although the idle CPU temperature is around 50°C, it can go higher than
85°C under a stress test. An active cooler is available for the Raspberry Pi 5. Holes and
power points are provided on the board to install and power the active cooler. Figure 1.2
shows the Raspberry Pi 5 with the active cooler installed. The active cooler cools down the
SoC, RAM, and the southbridge chip. When the CPU is idle, the active cooler keeps the CPU
temperature at around 40°C. The fan of the cooler operates automatically when the CPU
temperature goes just above 50°C.
The Raspberry Pi 5 operating system (OS) is based upon Debian 12 with the code name
Bookworm. This OS, released in July 2023, comes with a new Python interpreter (Py-
thon 3.11). This means that a Python package cannot be installed using the pip commands.
● 15
Another major software change is that the RPi.GPIO library (created by Ben Croston) was
not available at the time of writing this book. As a result of this, all the GPIO-based Python
programs in the book have been developed using the gpiozero library. Most third party
HATs are based on RPi.GPIO and these will not work until their software is changed by their
manufacturers. It is hoped that the manufacturers will change their software by the time
Raspberry Pi 5 becomes officially widely available.
● 16
Chapter 2 • I
nstalling the Raspberry Pi 5 Operating
System
2.1 Overview
The Raspberry Pi 5 operating system Bookworm is available either on a pre-installed mi-
croSD card, or you can download the operating system image on a blank microSD card. In
this chapter, you will learn to install the operating system using both methods.
• You should see the Raspberry Pi booting the first time and asking you various
questions to set up the device, such as the username, password, Wi-Fi network
name and password, any updates if necessary, etc. (see Figure 2.2 for some
displays on the monitor). In this book, the username is set to pi.
• The Raspberry Pi will boot in Desktop mode and will display the default screen.
You can press Ctrl+Alt+F1 at any time to change to the Console mode
● 17
● 18
● 19
• Click OK
You will now have to install a terminal emulation software on your PC. The one used by the
author is the popular Putty. Download Putty from the following website:
● 20
https://www.putty.org
• Putty is a standalone program and there is no need to install it. Simply double
click to run it. You should see the Putty startup screen as in Figure 2.8.
• Make sure that the Connection type is SSH and enter the IP address of your
Raspberry Pi 5. You can obtain the IP address by entering the command
ifconfig in console mode (Figure 2.9). In this example, the IP address was:
192.168.1.251 (see under wlan0:)
• Click Open in Putty after entering the IP address and selecting SSH
• The first time you run Putty, you may get a security message. Click Yes to
accept this security alert.
• You will then be prompted to enter the Raspberry Pi 5 username and password.
You can now enter all Console-based commands through your PC.
● 21
pi@raspberrypi: ~ $ passwd
• To shut down the Raspberry Pi, enter the following command. Never shutdown
by pulling the power cable, as this may result in the corruption or loss of files:
• Restart Putty
• Set the Default Foreground and Default Bold Foreground colours to black
(Red:0, Green:0, Blue:0)
• Set the Cursor Text and Cursor Colour to black (Red:0, Green:0, Blue:0)
• Select Appearance under Window and click Change in Font settings. Set
the font to Bold 12.
• Select Session and give a name to the session (e.g. MyZero) and click Save.
• Next time you restart Putty, select the saved session and click Load followed
by Open to start a session with the saved configuration
● 22
pi$raspberrypi:~ $ tightvncserver
You will be prompted to create a password for remotely accessing the Raspberry
Pi desktop. You can also set up an optional read-only password. The password
should be entered every time you want to access the Desktop. Enter a password
and remember your password.
pi$raspberrypi:~ $ vncserver :1
You can optionally specify screen pixel size and colour depth in bits as follows:
• We must now set up a VNC viewer on our laptop (or desktop) PC. There are
many VNC clients available, but the recommended one which is compatible with
TightVNC is TightVNC for the PC, which can be downloaded from the following
link:
https://www.tightvnc.com/download.php
• Download and install the TightVNC software for your PC. You will have to
choose a password during the installation.
• Start the TightVNC Viewer on your PC and enter the Raspberry Pi IP address
followed by ':1'. Click Connect to connect to your Raspberry Pi (Figure 2.10)
● 23
• Enter the password you have chosen earlier. You should now see the Raspberry
Pi 5 Desktop displayed on your PC screen (Figure 2.11)
• The VNC server is now running on your Raspberry Pi 5 and you have access to
the Desktop GUI.
In this section, you will learn how to fix your IP address so that it does not change between
reboots. The steps are as follows:
● 24
• Find the IP address of your router by entering the command ip r (Figure 2.13).
In this example, the IP address was: 192.168.1.254
• Add the following lines to the bottom of the file (these will be different for your
router). If these lines already exist, remove the comment character '#' at the
beginning of the lines and change the lines as follows (you may notice that
eth0 for Ethernet is listed):
● 25
interface wlan0
static_routers=192.168.1.254
static domain_name_servers=192.168.1.254
static ip_address=192.168.1.251/24
• Save the file by entering CTRL + X followed by Y and reboot your Raspberry Pi
• In this example, the Raspberry Pi should reboot with the static IP address:
192.168.1.251
• Click on the Bluetooth icon on your Raspberry Pi 5 at the top right-hand side,
and select Make Discoverable. You should see the Bluetooth icon flashing
• You should now see the message Connected Successfully on your Raspberry
Pi 5 and you can exchange files between your other device and the Raspberry
Pi computer.
Step 1: Connect a network cable between your Raspberry Pi 5 and your Wi-Fi router.
Step 2: Connect the keyboard, mouse and monitor to your Raspberry Pi and power up as
normal
Step 4: Providing your network hub supports DHCP (nearly all network routers support
DHCP), you will be connected automatically to the network and will be assigned a unique
IP address within your network. Note that DHCP assigns IP addresses to newly connected
devices.
Step 5: Check to find out the IP address assigned to your Raspberry Pi 5 by the network
router. Enter the command ifconfig as described earlier
● 26
In most cases, it is very unlikely that the network cable is faulty. Also, most network hubs
support the DHCP protocol. If you are having problems with the network, it is possible that
your Raspberry Pi is not configured to accept DHCP issued addresses. The Raspberry Pi is
normally configured to accept DHCP addresses, but it is possible that you have changed the
configuration somehow.
To resolve the wired network connectivity problem, follow the steps given below:
Step 1: find out whether your Raspberry Pi is configured for DHCP or fixed IP addresses.
Enter the following command:
If your Raspberry Pi is configured to use the DHCP protocol (which is normally the default
configuration), the word dhcp should appear at the end of the following line:
If, on the other hand, your Raspberry Pi is configured to use static addresses, then you
should see the word static at the end of the following line:
Step 2: To use the DHCP protocol, edit file interfaces (e.g. using the nano text editor)
and change the word static to dhcp. It is recommended to make a backup copy of the file
interfaces before you change it:
You should now restart your Raspberry Pi and an IP address will probably be assigned to
your device.
Step 3: To use static addressing, make sure that the word static appears as shown above.
If not, edit file interfaces and change dhcp to static
Step 4: You need to edit and add the required unique IP address, subnet mask and gate-
way addresses to file interfaces as in the following example (this example assumes that
● 27
the required fixed IP address is 192.168.1.251, the subnet mask used in the network is
255.255.255.0, and the gateway address is 192.168.1.1):
Save the changes and exit the editor. If you are using the nano editor, exit by pressing
Ctrl+X, then enter Y to save the changes, and enter the filename to write to as /etc/net-
work/interfaces.
• Insert a microSD card into your PC. You may need to use an SD card adapter
• Click to download the Raspberry Pi Imager. At the time of writing this book,
this file was called: imager_1.7.5.exe
• Click Operating System and select the operating system at the top of the list
as: Raspberry Pi OS (64-bit). See Figure 2.15
● 28
• Click Save
● 29
If you have a monitor and keyboard, you can log in to your Raspberry Pi 5 directly and
start using it. Otherwise, find the IP address of your Raspberry Pi 5 (e.g. from your router,
or there are many apps for smartphones, such as who's on my wifi that shows all the
devices connected to your router with their IP addresses). Then log in to your Raspberry
Pi 5 and start using it.
● 30
3.1 Overview
Raspberry Pi is based on a version of the Linux operating system. Linux is one of the most
popular operating systems in use today. Linux is very similar to other operating systems,
such as Windows and UNIX. Linux is an open operating system based on UNIX and has
been developed collaboratively by many companies since 1991. In general, Linux is harder
to manage than some other operating systems like Windows, but offers more flexibility and
configuration options. There are several popular versions of the Linux operating system,
such as Debian, Ubuntu, Red Hat, Fedora and so on.
Linux commands are text-based. In this chapter, you will be looking at some of the useful
Linux commands and see how you can manage your Raspberry Pi using these commands.
When you apply power to your Raspberry Pi 5, the Linux command line (or the Linux shell,
or Console commands) is the first thing you see, and it is where you can enter operating
system commands.
pi@raspberrypi: ~$
● 31
Command uname –s displays the operating system kernel name, which is Linux. Com-
mand uname –a displays complete detailed information about the kernel and the operat-
ing system. An example is shown in Figure 3.2.
Command cat /proc/meminfo displays information about the memory on your Raspber-
ry Pi. Information such as the total memory and free memory at the time of issuing the
command are displayed. Figure 3.3 shows an example, where only part of the display is
shown here.
Command whoami displays the name of the current user. In this case, pi is displayed as
the current user.
● 32
A new user can be added to your Raspberry Pi 5 using the command useradd. In the ex-
ample in Figure 3.5, a user called John is added. A password for the new user can be added
using the passwd command followed by the username. In Figure 3.4, the password for
user John is set to mypassword (not displayed for security reasons). Notice that both the
useradd and passwd are privileged commands, and the keyword sudo must be entered
before these commands. Notice that the –m option creates a home directory for the new
user.
You can log in to the new user account by specifying the username and the password as
shown in Figure 3.5. You can type command exit to log out from the new account.
Command sudo apt-get upgrade is used to upgrade all the software packages on the
system.
Figure 3.6 shows part of the Raspberry Pi 5 directory structure. Notice that the root direc-
tory is identified by the '/' symbol. Under the root we have directories named such as bin,
boot, dev, etc, home, lib, lost+found, media, mnt, opt, proc, and many more. The impor-
tant directory as far as the users are concerned is the home directory. The home directory
contains subdirectories for each user of the system. In the example in Figure 3.7, pi is the
subdirectory for user pi. In a new system, this subdirectory contains two subdirectories
called Desktop and python_games.
● 33
Some useful directory commands are given below. Command pwd displays the user home
directory:
pi@raspberrypi: ~$ pwd
/home/pi
pi@raspberry: ~$
To show the subdirectories and files in your working directory, enter ls:
pi@raspberrypi: ~$ ls
Bookshelf Documents Music Public Videos
Desktop Downloads Pictures Templates
pi@raspberrypi: ~$
Notice that the subdirectories are displayed in blue colour and files in black colour.
The ls command can take a number of arguments. Some examples are given below.
To display the subdirectories and files in a single row:
pi@raspberrypi: ~$ ls -1
Bookshelf
Desktop
Documents
Downloads
Music
● 34
Pictures
Public
Templates
Videos
pi@raspberrypi: ~$
To display the file types, enter the following command. Note that directories have a '/' after
their names, and executable files have a '*' character after their names:
pi@raspberrypi: ~$ ls –F
Bookshelf/ Documents/ Music/ Public/ Videos/
Desktop/ Downloads/ Pictures/ Templates/
pi@raspberrypi: ~$
pi@raspberrypi: ~$ ls –m
pi@raspberrypi: ~$
Subdirectories are created using the command mkdir followed by the name of the subdi-
rectory (Figure 3.9)
Command find is used to search the whole system for a file and outputs a list of all direc-
tories that contain the file. For example, the command find / -name myfile.txt searches
the whole system for the file myfile.txt.
File Permissions
One of the important arguments used with the ls command is -l (lower case letter l) which
displays the file permissions, file sizes, and when they were last modified. In the example
below, each line relates to one directory or file. Reading from right to left, the name of the
● 35
directory or the file is on the right-hand side. The date the directory or file was created is
on the left-hand side of its name. Next comes the size, given in bytes. The characters at
the beginning of each line are about permissions, i.e. who is allowed to use or modify the
file or the directory.
The first word pi in the example in Figure 3.10 shows who the user of the file (or directory)
is, and the second word pi shows the group name that owns the file. In this example, both
the user and the group names are pi.
The permissions can be analysed by breaking down the characters into four chunks for:
File type, User, Group, World. The first character for a file is '-' and for a directory, it is 'd'.
Next come the permissions for the User, Group and World. The permissions are as follows:
• Read permission (r): the permission to open and read a file or to list a directory
• Write permission (w): the permission to modify a file, or to delete or create a
file in a directory
• Execute permission (x): the permission to execute the file (applies to
executable files), or to enter a directory
The three letters rwx are used as a group and if there is no permission assigned then a '-'
character is used.
As an example, considering the Music directory, we have the following permission codes:
● 36
The chmod command is used to change the file permissions. Before going into details of
how to change the permissions, let us look and see what arguments are available in chmod
for changing the file permissions.
The available arguments for changing file permissions are given below. We can use these
arguments to add/remove permissions or to explicitly set permissions. It is important to
realize that if we explicitly set permissions, then any unspecified permissions in the com-
mand will be revoked:
+: add
-: remove
=: set
r: read
w: write
x: execute
To change the permissions of a file we type the chmod command, followed by one of the
letters 'u', 'g', 'o', or 'a' to select the people, followed by the '+', '-' or '=' to select the
type of change, and finally followed by the filename. In this example, a file with the name
mytestfile.txt was created in the home directory for demonstration purposes (See Figure
3.11). In this example, the file mytestfile.txt has the user read and write permissions.
We will be changing the permissions so that the user does not have read permission on
this file:
● 37
Notice that if you now try to display the contents of the file mytestfile.txt using the cat
command, you will get an error message:
All the permissions can be removed from a file by the following command:
To change our working directory, the command cd is used. In the following example, we
change our working directory to Music:
pi@raspberrypi: ~$ cd /home/pi/Music
pi@raspberrypi: ~/Music $
● 38
To change your working directory to Music, you can also enter the command:
pi@raspberrypi: ~$ cd ~/Music
pi@raspberrypi: ~/myfiles $
pi@raspberrypi: ~/Music $ cd ~
pi@raspberrypi: ~$
To find out more information about a file, you can use the file command. For example:
The –R argument of the command ls lists all the files in all the subdirectories of the current
working directory. An example is given below (only part of the display is shown). Notice here
in Figure 3.14 that subdirectory Bookshelf contains file BeginnersGuide-4thEd-Eng_
v2.pdf
To display information on how to use a command, you can use the man command. As an
example, to get help on using the mkdir command:
NAME
Mkdir – make directories
SYNOPSIS
● 39
Mkdir [OPTION]…DIRECTORY…
DESCRIPTION
Create the DIRECTORY(ies), if they do not already exist.
-m, --mode=MODE
Set file mode (as in chmod), not a=rwx – umask
---------------------------------------------------------------------------
---------------------------------------------------------------------------
Help
The man command usually gives several pages of information on how to use a command.
You can type q to exit the man command and return to the operating system prompt.
The less command can be used to display a long listing one page at a time. Using the up
and down arrow keys, we can move between pages. An example is given below. Type q to
exit:
Copying a File
To make a copy of a file, use the command cp. In the following example, a copy of the file
mytestfile.txt is made, and the new file is given the name test.txt:
Wildcards
You can use wildcard characters to select multiple files with similar characteristics. e.g. files
having the same file-extension names. The * character is used to match any number of
characters. Similarly, the ? character is used to match any single character. In the example
below, all the files with extensions .txt are listed:
pi@raspberrypi: ~$ ls *.txt
mytestfile.txt test.txt
pi@raspberrypi: ~$
● 40
The wildcard characters [a-z] can be used to match any single character in the specified
character range. An example is given below which matches any files that start with the
letters 'o', 'p', 'q', 'r', 's', and 't', and with the .txt extension:
pi@raspberrypi: ~$ ls [o-t]*.txt
test.txt
pi@raspberrypi: ~$
Renaming a File
You can rename a file using the mv command. In the example below, the name of file test.
txt is changed to test2.txt:
Deleting a File
The command rm can be used to remove (delete) a file. In the example below, the file
test2.txt is deleted:
pi@raspberrypi: ~$ rm test2.txt
pi@raspberrypi: ~$
The argument –v can be used to display a message when a file is removed. Also, the –i
argument asks for confirmation before a file is removed. In general, the two arguments are
used together as –vi. An example is given below:
Sorting a file
The command sort displays the contents of a file in ascending order. The general format of
this command is:
Word count
Command wc <filename> displays the word count in a file
● 41
File differences
Command diff <file1> <file2) displays the differences between two files line by line
Removing a Directory
A directory can be removed using the rmdir command:
The echo command can also be used to write a line of text to a file. An example is shown
below:
Matching a String
The grep command can be used to match a string in a file. An example is given below,
assuming that the file lin.dat contains sting a line of text. Notice that the matched word is
shown in bold:
● 42
Similarly, the tail command is used to display the last 10 lines of a file. The format of this
command is as follows:
The which command displays the location of an executable program. For example, the
location of the python program can be found as follows:
pi@raspberrypi: ~$ dpkg –l
…………………………….
…………………………….
pi@raspberrypi: ~$
You can also find out if a certain software package is already installed on our computer.
An example is given below which checks whether software called xpdf (PDF reader) is
installed. In this example, xpdf is installed and the details of this software are displayed:
● 43
If the software is not installed, you get a message similar to the following (assuming we are
checking to see if a software package called bbgd is installed):
pi@raspberrypi: ~$ top
pi@raspberrypi: ~$
● 44
Some of the important points in Figure 3.15 are summarized below (for lines 1 to 5 of the
display):
The process table gives the following information for all the processes loaded to the system:
The command htop is similar to the top command, except it has more features and is more
user-friendly.
The ps command can be used to list all the processes used by the current user. An example
is shown in Figure 3.16.
Command ps –ef gives a lot more information about the processes running in the system.
● 45
Killing a process
There are many options for killing (or stopping) a process. A process can be killed by spec-
ifying its PID and using the following command:
Command free shows how much memory is used and the amount of free memory.
The following command will stop all the processes and make the file system safe, and then
turn off the system safely:
The system can also be shut down and then restarted after a time by entering the following
command. Optionally, a shutdown message can be displayed if desired:
pi@raspberrypi: ~$ shutdown –r <time> <message>
● 46
Broadcast message from root @raspberrypi on pts/1 (Tue 2023-10-03 12:03:00 BST)
Note: Raspberry Pi 5 includes a power switch at its side. When the Raspberry Pi is ON, a
single press brings the shutdown/logout menu. Another press triggers a safe shutdown,
which is a standby with the Raspberry Pi consuming about 1.4 W. A press of the button
will start up the Raspberry Pi 5.
3.3.5 Networking
Some useful networking commands are:
iwconfig: check which network the Raspberry Pi is using. An example is shown in Figure
3.18. Here, the SSID of the Wi-Fi adapter used is BTHub5-6SPN
ping: used to test the availability of a network device. An example is shown in Figure 3.19
wget: this command is used to download a file from the web and saves the file in the
current directory.
● 47
If you have executed many commands and want to use some of them again, but you
cannot remember the command name, you can use the history command. An example
is shown in Figure 3.22. To execute a command from the history, enter ! followed by the
command number. For example, to execute the ls command again, you can enter !6 fol-
lowed by the Enter key.
● 48
The clear command is also useful, and it is used to clear the screen.
To install a package, use the command: sudo apt install <package_name>
The & operator allows you to run any command in the background so that you can use the
terminal for other tasks. This operator must be added to the end of a command.
The && operator allows you to run two or more commands at the same time. For example,
command1 && command2
● 49
4.1 Overview
In this chapter, you will learn how to access and use the desktop applications of your Rasp-
berry Pi 5.
If you wish to access the Desktop GUI applications from a desktop or a laptop computer,
then the required steps are as follows:
Step 1: Connect to your Raspberry Pi 5 using the Putty terminal emulator with the SSH
services as explained in earlier chapters.
Step 2: Run the VNC server by entering the following command into your SSH window:
pi@raspberrypi ~ $ vncserver :1
Step 3: Run the VNC Viewer program on your computer. Enter the IP address of your
Raspberry Pi 5 computer, followed by characters :1 to indicate that we are using port 1 (see
Figure 4.1). Click the Connect button.
You will be asked for your password that you created earlier. Enter the password, and you
will see the Raspberry Pi 5 Desktop displayed (Figure 4.2, only the upper part of the screen
is shown)
● 50
Assuming you are using a pre-installed micro SD card, at the top of the screen you have a
number of shortcut icons. Below that, you will see four menu icons with the names:
Applications menu
Web Browser
File Manager
Terminal
On the top right-hand side of the screen, starting from the left, you have the following
menus:
Updates
Bluetooth
Wi-Fi
Volume Control
Time
Programming: This menu item includes a number of programming languages that you
can use to program our Raspberry Pi 5. Figure 4.4 shows a list of the items in the Program-
ming menu.
● 51
In this book, you will be using the Thonny IDE in most of your Python programs. Details
about the Thonny IDE are given in a later chapter.
Web Browser: This menu item includes the Chromium and the Firefox web browsers.
Sound & Video: This menu item includes the video program VLC Media Player
Accessories: This menu item includes a number of useful programs, as shown in Fig-
ure 4.5. For example, the Calculator program can be used to perform simple and scientific
calculations (Figure 4.6)
● 52
Preferences: This menu is used for system and software settings, such as adding/remov-
ing software, print services, screen configuration, etc. (Figure 4.7)
● 53
4.2.4 Terminal
This menu item enables the command mode so that you can enter commands in this mode
(Figure 4.9, only part of the screen is shown)
4.2.6 Wi-Fi
The next menu item to the Bluetooth is the Wi-Fi menu, which can be used to turn the Wi-
Fi on and off, and to connect to a Wi-Fi router. When clicked, a list of the available Wi-Fi
devices is given (see Figure 4.10).
● 54
● 55
A text editor is used to create or modify the contents of a text file. There are many text
editors available for the Linux operating system. Some popular ones are nano, vim, vi, and
many more. In this chapter, we shall be looking at some of these text editors and see how
to use them.
You should see the editor screen as in Figure 5.1. The name of the file to be edited is written
at the top middle part of the screen. The message 'New File' at the bottom of the screen
shows that this is a newly created file. The shortcuts at the bottom of the screen are there
to perform various editing functions. These shortcuts are accessed by pressing the Ctrl key
together with another key. Some of the useful shortcuts are given below:
● 56
Step 2: Look for the word simple by pressing Ctrl+W and then typing simple in the win-
dow opened at the bottom left-hand corner of the screen. Press the Enter key. The cursor
will be positioned on the word simple (see Figure 5.3).
● 57
Step 3: Cut the first line by placing the cursor anywhere on the line and then pressing
Ctrl+K. The first line will disappear, as in Figure 5.4.
Step 4: Paste the line cut after the first line. Place the cursor on the second line and press
Ctrl+U (see Figure 5.5).
Step 5: Place cursor at the beginning of the word simple on the first row. Enter Ctrl+C.
The row and column positions of this word will be displayed at the bottom of the screen
(Figure 5.6).
● 58
Step 6: Press Ctrl+G to display the help page as in Figure 5.7. Notice that the display is
many pages long, and you can jump to the next pages by pressing Ctrl+Y or to the previ-
ous pages by pressing Ctrl+V. Press Ctrl+X to exit the help page.
Step 7: Press Ctrl+- and enter line and column numbers as 2 and 5, followed by the Enter
key, to move the cursor to line 2, column 5 (see Figure 5.8).
● 59
Step 8: Replace word example with word file. Press Ctrl+\ and type the first word as
example (see Figure 5.9). Press Enter and then type the replacement word as file. Press
Enter and accept the change by typing y.
Step 9: Save the changes. Press Ctrl+X to exit the file. Type Y to accept the saving, then
enter the filename to be written to, or simply press Enter to write to the existing file (first.
txt in this example). The file will be saved in your current working directory.
pi@raspberrypi: ~ $
● 60
In summary, nano is a simple and yet powerful text editor, allowing us to create new text
files or to edit existing files.
Notice that you cannot use the keyboard arrow keys with the vi editor. Some of the useful
vi editor commands are listed below:
● 61
Start the vi text editor by typing vi followed by the name of the file to be created or modi-
fied. In this example, it is assumed that a new file called myfile.txt is to be created:
pi@raspberrypi: ~ $ vi myfile.txt
You should see the vi text editor screen displayed as in Figure 5.10. The name of the file
being edited is displayed at the bottom of the screen.
The vi editor is different from most other text editors in that it is not possible to start typing
inside the editor window. The steps for editing this file are given below:
Step 1: The vi editor has different modes, and you must be in insert mode to be able to
write to the window. Press i to enter insert mode. Then type in the following text (see Fig-
ure 5.11):
● 62
Step 2: To come out of the insert mode, press the ESC key. To save the file, type the
characters :w. You can exit the editor after saving the changes by typing :q. Alternatively,
you can type ZZ (note upper case) to save and exit. If you modified the file and attempt to
quit without saving, you will get an error message. If you want to exit without saving the
changes, simply type :q!
Step 3: Make sure you are in the command mode and type the character / followed by a
word to search for this word in the text. For example, type /editor to search for the word
editor (see Figure 5.12) in the text.
Step 4: Insert word is before word editor. Type i followed by is and space, and terminate
insert mode by pressing the ESC key.
Step 5: Move cursor right by pressing the l key. Similarly, move the cursor left by pressing
the h key. Move the cursor down (to the second line) by pressing the j key.
● 63
Step 6: Search for the word this and delete it. Type /this followed by the Enter key. Type
dw to delete the word.
Step 8: Search for the word help and replace it with the word guide. Go to the line where
the word help is. Type /help, then type :s/help/guide/
Step 9: You can search and replace a word in any other line than the current line. For this
example, position the cursor on the first line. Change the word basic in the second line to
BASIC. Type:
:1,2s/basic/BASIC/
Notice that you can specify the range of lines by separating them with a comma. In this
example, the search starts from line 1 and terminates at line 2.
● 64
6.1 Overview
You will be programming your Raspberry Pi 5 using the Python programming language.
It is worthwhile to look at the creation and running of a simple Python program on your
Raspberry Pi 5 computer. In this chapter, the message Hello From Raspberry Pi 5 will be
displayed on your PC screen.
As described below, there are three methods that you can create and run Python programs
on your Raspberry Pi 5.
• At the command prompt, enter python. You should see the Python command
mode, which is identified by three characters ">>>"
• The text will be displayed interactively on the screen as shown in Figure 6.1.
Note that at the time of writing this book, the Python version was: 3.11.2.
● 65
The screen consists of two parts: the upper part is where you write your programs. The
lower part is the shell, where small interactive programs can be written. This part is mainly
used for testing code snippets.
● 66
The Thonny IDE must be configured before it is used to write and upload programs to your
Raspberry Pi. Click the bottom-right corner of the screen to select your processor type and
select Local Python 3. You are now ready to write your program. The steps are:
• Click File → Save and save with the name hello.py (Figure 6.4)
• Click the Run icon (green menu button at the top) to run the program. The
output of the program will be displayed at the bottom of the screen as shown in
Figure 6.5.
You can run small programs in interactive mode by entering them at the lower part of the
screen under shell. The results will be displayed under shell immediately.
● 67
● 68
7.1 Overview
Python is an interpreted, interactive and object-oriented programming language. It was
developed by Guido van Rossum in the 1980s at the National Institute for Mathematics and
Computer Science in the Netherlands. It is derived from many other languages, including
C, C++, Modula-3, SmallTalk, and Unix shells. The language is now maintained by a team
of people at the Institute.
Python is interactive, which means that you can issue a command and see the result im-
mediately without having to compile the command. It is interpreted, thus requiring no
pre-compilation before it is run.
In this and next chapters, you will be learning the details of the Python programming lan-
guage on the Raspberry Pi 5 computer, and see how you can write programs using this
language. Many example programs are given to show how electronic engineers can use the
Python language to help them in their calculations.
SUM - valid
Sum - valid
SUm - valid
_total - valid
Cnt5 - valid
8tot - invalid
%int - invalid
&xyz - invalid
My_Number - valid
@loop - invalid
_Account - valid
Note that variables total, Total, TOTAL, ToTaL, or toTAL are all different.
● 69
7.4 Comments
Comment lines in Python start with a hash sign '#'. All characters after the # sign are ig-
nored by the Python interpreter. An example comment line is shown below:
Sum = a +\
b +\
c
Sum = a + b + c
● 70
7.8 Indentation
In most programming languages, blocks of code are identified by using braces at the begin-
ning and end of the block, or by identifying the end of the block using a suitable statement.
e.g. END, WEND, or ENDIF. In the Python language, there are no braces or statements to
indicate the start and end of a block. Instead, blocks of code are identified by line indenta-
tion. All statements within a block must be indented the same amount. The actual number
of spaces used to indent a block is not relevant as long as all the statements in the block
use the same number of spaces.
A valid block of code is given below (don't worry at this stage what the code does):
if j == 5:
a=a+1
b=a+2
else:
a=0
b=0
The following block of code is not valid since the indentation is not correct:
if j == 5:
a=a+1
b=a+2
else:
a=0
b=0
• Numbers
• Strings
• Lists
• Dictionaries
• Tuples
• Sets
• Files
● 71
7.10 Numbers
Python supports the following numeric variable types:
Complex number
Numbers can be represented in decimal, octal, binary, or hexadecimal. Long integers are
shown with an upper-case letter L.
Integer
100 - decimal
-67 - decimal
500 - decimal
0x20 - hexadecimal
0b10000001 - binary
0o2377 - octal
202334567L - long decimal
0x3AEEFAE - hexadecimal
Floating point
2.355
23.780
-45.6
1.298
24.45E4
Complex
24.4+2,6j
0.78-4.2j
23.7j
We can assign numeric values to variables. These variable objects are created when values
are assigned to them:
sum = 28
a=0
● 72
Expression operators
+ addition
- Subtraction
* multiplication
/ division
>> shift right
<< shift left
** power (exponentiation)
% remainder
Bitwise operators
| bitwise OR
& bitwise AND
^ bitwise exclusive-or
~ bitwise complement
● 73
Figure 7.1 to Figure 7.3 show examples of using numbers in Python. Statement import is
used to import a library to a Python program. The math library contains a large number
of mathematical functions, such as logarithmic and trigonometric functions, square root,
hyperbolic functions, angular conversion, and so on. Further details on these functions can
be obtained from the following link:
https://docs.python.org/3/library/math.html
random library is useful to generate random numbers. The function randint(a, b) in this
library generates an integer random number between integers a and b inclusive. Details of
functions available in the random library can be obtained from the following link:
https://docs.python.org/2/library/random.html
● 74
7.11 Strings
In Python, strings are declared by enclosing characters between a pair of single or double
quotation marks. An example is given below:
We can manipulate strings by extracting characters, joining two strings, assigning a string
to another string, and so on. Some commonly used string manipulation operations are
shown in Figure 7.4 and Figure 7.5.
● 75
Notice that a third index as the step can be used in string slicing operation. The step is add-
ed to the first offset until the second offset, and the character at this position is extracted.
In the following example, the characters at positions 0, 2, 4, 6 are extracted:
>>> a = "computer"
>>> b = a[0:7:2]
>>> print(b)
cmue
● 76
• \n newline
• \a bell
• \b backspace
• \f form feed
• \r carriage return
• \t horizontal tab
• \v vertical tab
• \xhh character defined by the 2-digit hexadecimal value hh
As an example, the following statement will display the letter 'a' followed by two newlines:
print("a\n\n")
• %c character
• %s string
• %d signed integer
• %u unsigned integer
● 77
s =
mylist[0] # s = 'John'
s =
mylist[2] # s = 230
s =
mylist[2:4] # s = 230, 12.25
s =
mylist[3:] # s = 12.25, 'Peter', 89
s =
mylist * 2 # s = 'John', 'Adam', 230, 12.25, 'Peter', 89, 'John',
'Adam', 230, 12.25, 'Peter', 89
s = mylist + second # s = 'John', 'Adam', 230, 12.25, 'Peter', 89, 30, 23
The contents of a list can be modified by assigning a new value to the required index po-
sition. For example, we can change the 2nd element of the list mylist from 230 to 100 as:
mylist[2] = 100
Python does not allow to reference items that are not present in a list. For example, the
following statement gives an error message:
mylist[200]
● 78
M = [[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]
The nested list is indexed starting from [0][0]. For example, the elements of row 1 can be
accessed as follows:
● 79
s =
mytuple[0] # s = 'John'
s =
mytuple[2] # s = 230
s =
mytuple[2:4] # s = 230, 12.25
s =
mytuple[3:] # s = 12.25, 'Peter', 89
s =
mytuple * 2 # s = 'John', 'Adam', 230, 12.25, 'Peter', 89, 'John',
'Adam', 230, 12.25, 'Peter', 89
s = mytuple + second # s = 'John', 'Adam', 230, 12.25, 'Peter', 89, 30, 23
The following statement is not valid, since we cannot change the contents of a tuple:
mytuple[2] = 200
● 80
Figure 7.10 shows examples of using the keyboard input function. Notice that the function
returns a string. Therefore, if numeric data is entered, then it should be converted into a
numeric data type before being used in mathematical operations.
● 81
The Python programming language supports the following flow control statements:
• if
• if-else
• elif
• for
• while
• break
• continue
• pass
● 82
if expression: statement
or
if expression:
Statement 1
Statement 2
else:
Statement 1
Statement 2
Notice the use of indentation inside the if blocks and the colon character at the end of the
if and else statements.
if a == 5: print('a is 5')
If there is only one statement after the if, then it can be typed on the same line. If there
is more than one statement then all the statements must be written on the next lines with
the same amount of indentation. An example is given below:
if a == 100:
x=0
y=0
else:
x=1
y = 10
The elif statement is used to check for different conditions in an if block. An example is
given below:
if a > 10:
b=0
c=0
elif a == 10:
b=2
c=4
Notice that the if statements can be nested, as shown in the following example:
if a == 100:
c=0
k=1
if b == 10:
c = 20
m=1
else:
c = 23
● 83
Here, the sequence is evaluated first and the first item in the sequence is assigned to the
variable and the statements are executed. Then the second item is assigned to the varia-
ble and the statements are executed. This continues until there are no more items in the
sequence. An example use of the for statement is shown below:
The for statement is commonly used to create loops in programs. The range statement
denotes the range of the variable, as in the following example:
Notice that the upper value of the range is one less than the specified value. In the above
example, range is from 0 to 4 and not to 5.
We can specify a step size in the last parameter when using the range statement, in the
following example, the step size is 5 and the list takes values 0, 5, 10, 15, 20, 25:
● 84
while expression:
statements
The statements are executed while the expression evaluates to True. An example is given
below:
cnt = 0
while cnt < 5:
print(cnt)
cnt = cnt + 1
Notice that the statements that belong to the while statement must be indented. It is im-
portant to make sure that the expression is modified inside the loop; otherwise an infinite
loop will be formed as shown in the following example:
cnt = 0
while cnt < 5:
print(cnt)
cnt = 0
while cnt < 5:
cnt = cnt + 1
if cnt == 3:
continue
print(cnt)
● 85
cnt = 0
while cnt < 5:
cnt = cnt + 1
if cnt == 3:
break
print(cnt)
We have covered the basic statements of the Python programming language. We will now
develop example programs using the knowledge we have gained so far.
● 86
Background Information: Resistor values are identified by the following colour codes:
Black: 0
Brown: 1
Red: 2
Orange: 3
Yellow: 4
Green: 5
Blue: 6
Violet: 7
Grey: 8
White: 9
The first two colours determine the first two digits of the value, while the last colour deter-
mines the multiplier. For example, red red red corresponds to 22 × 102 = 2200 Ω.
Program Listing: Figure 7.11 shows the program listing (program: resistor.py). At the
beginning of the program, a list called colour is created which stores the valid resistor col-
ours. Then a heading is displayed, and a while loop is created which runs as long as string
variable yn is equal to y. Inside the loop, the program reads the three colours from the
keyboard using functions input and stores as strings in variables FirstColour, Second-
Colour and ThirdColour. These strings are then converted into lower case so that they are
compatible with the values listed in the list box. The index values of these colours in the list
are then found using function calls of the form colours.index. Remember that the index
values start from 0. As an example, if the user entered red, then the corresponding index
value will be 2. The resistor value is then calculated by multiplying the first colour number
by 10 and adding to the second colour number. The result is then multiplied by the power
of 10 of the third colour index. The final result is displayed on the screen. The program then
asks whether the user wants to continue. If the answer is y then the program returns to the
beginning; otherwise the program is terminated.
#=================================================
# RESISTOR COLOUR CODES
# ---------------------
#
# The user enters the three colours of a resistor
# and the program calculates and displays the value
# of the resistor in Ohms
#
# Program: resistor.py
# Date : October, 2023
● 87
while yn == 'y':
FirstColour = input("Enter First Colour: ")
SecondColour = input("Enter Second Colour: ")
ThirdColour = input("Enter Third Colour: ")
#
# Convert to lower case
#
FirstColour = FirstColour.lower()
SecondColour = SecondColour.lower()
ThirdColour = ThirdColour.lower()
#
# Find the values of colours
#
FirstValue = colours.index(FirstColour)
SecondValue = colours.index(SecondColour)
ThirdValue = colours.index(ThirdColour)
#
# Now calculate the value of the resistor
#
Resistor = 10 * FirstValue + SecondValue
Resistor = Resistor * (10 ** ThirdValue)
print("Resistance = %d Ohms" % (Resistor))
#
# Ask for more
#
yn = input("\nDo you want to continue?: ")
yn = yn.lower()
The program was created using the nano text editor and then run from the command line
by entering the following command:
● 88
Background Information: When a number of resistors are in series, then the resultant
resistance is the sum of the resistance of each resistor. When the resistors are in parallel,
then the reciprocal of the resultant resistance is equal to the sum of the reciprocal resist-
ances of each resistor.
Program Listing: Figure 7.13 shows the program listing (program: serpal.py). At the
beginning of the program, a heading is displayed, and the program enters into a while
loop. Inside this loop, the user is prompted to enter the number of resistors in the circuit
and whether they are connected in series or in parallel. The function str converts a number
into its equivalent string. e.g. number 5 is converted into the string "5". If the connection
is serial (mode equals to 's') then the value of each resistor is accepted from the keyboard
and the resultant is calculated and displayed on the screen. If on the other hand, the con-
nection is parallel (mode is equal to 'p'), then again the value of each resistor is accepted
from the keyboard and the reciprocal of the number is added to the total. When all the
resistor values are entered, the resultant resistance is displayed on the screen.
#===================================================
# RESISTORS IN SERIES OR PARALLEL
# -------------------------------
#
# This program calculates the total resistance of
# serial or parallel connected resistors
#
# Program: serpal.py
# Date : October, 2023
# Author : Dogan Ibrahim
#===================================================
print("RESISTORS IN SERIES OR PARALLEL")
print("===============================")
yn = "y"
while yn == 'y':
● 89
if mode == 's':
for n in range(0,N):
s = "Enter resistor " + str(n+1) + " value in Ohms: "
r = int(input(s))
resistor = resistor + r
print("Total resistance = %d Ohms" %(resistor))
● 90
The above formula is used to calculate the required value of R1, given Vin, Vo, and R2
Program Listing: Figure 7.16 shows the program listing (program: divider.py). At the
beginning of the program, a heading is displayed. The program then reads Vin, Vo, and R2
from the keyboard. The program calculates R1 and displays R1 and R2. The user is then
asked to enter a chosen physical value for R1. With the chosen value of R1, the program
displays Vin, Vo, R1, and R2 and asks the user whether the result is acceptable. If the an-
swer to this question is y then the program terminates. If, on the other hand, the answer
is n then the user is given the option of trying again.
#======================================================
# RESISTIVE POTENTIAL DIVIDER
# ---------------------------
#
# This is a resistive potential divider circuit program.
# The program calculates the resistance values that will
# lower the input voltage to the desired value
#
● 91
# Program: divider.py
# Date : October, 2023
# Author : Dogan Ibrahim
#=======================================================
print("RESISTIVE POTENTIAL DIVIDER")
print("===========================")
R1flag = 1
R2flag = 0
while R1flag == 1:
Vin = float(input("\nInput voltage (Volts): "))
Vo = float(input("Desired output voltage (Volts): "))
R2 = float(input("Enter R2 (in Ohms): "))
#
# Calculate R1
#
R1 = R2 * (Vin - Vo) / Vo
print("\nR1 = %3.2f Ohms R2 = %3.2f Ohms" %(R1, R2))
#
# Read chosen physical R1 and display actual Vo
#
NewR1 = float(input("\nEnter chosen R1 (Ohms): "))
#
# Display and print the output voltage with chosen R1
#
print("\nWith the chosen R1,the results are:")
Vo = R2 * Vin / (NewR1 + R2)
print("R1 = %3.2F R2 = %3.2f Vin = %3.2f Vo = %3.3f" %(NewR1,R2,Vin,Vo))
#
# Check if happy with the values ?
#
happy = input("\nAre you happy with the values? ")
happy = happy.lower()
if happy == 'y':
break
else:
mode = input("Do you want to try again? ")
mode = mode.lower()
if mode == 'y':
R1flag = 1
else:
R1flag = 0
break
● 92
Some examples of using the trigonometric functions are given in Figure 7.18.
● 93
A function that we create can be called from anywhere in a program. Functions have their
own variables and their own commands. As we have seen in earlier parts of this chapter,
Python has many built-in functions for various operations such as arithmetic, trigonometric,
string manipulation and so on. User-defined functions are created by programmers. In this
section, we shall be looking at how functions can be created and used in our programs.
• Functions begin with the keyword def, followed by the function name, and
round brackets, followed by a colon sign.
• Input arguments to the function must be placed inside the brackets at the
beginning of the function definition.
• The body of a function must be indented with the same number of spaces on
the left-hand side
• An optional text message can be displayed at the first line of a function to
describe what the function does.
• A function must be terminated with the return statement
An example function, named Mult is given below. This function takes two numbers first and
second as its arguments, multiplies them, and returns the result:
A function is called from the main program by specifying the name of the function and
enclosing any arguments in a pair of brackets. For example, to call the above function to
multiply numbers 5 and 3 and sore the result in a variable called 'a', we include the follow-
ing statement in our program:
a = Mult(5, 3)
a = Mult(first = 5, second = 3)
● 94
Another example is shown in Figure 7.20. In this example, the function displays a string
passed as an argument. Notice that there is no data returned from this function.
The variables used in a function are local to that function. Thus, for example, if there are
two variables with the same name, one inside the function and the other one outside,
changing the one inside the function does not change the one outside. Variables outside
a function are called global variables, whereas the ones inside a function are called lo-
cal variables. See Figure 7.21 for an example where the contents of variable res are not
changed outside the function.
• Global variables are variables assigned at the top of the program outside the
function definitions
• Global names must be declared only if they are assigned within a function
• Global names may be referenced within a function without being declared
Therefore, by declaring a variable outside the functions and also inside a function but with
the global keyword allows us to change its contents inside the function. An example is given
below which identifies the use of global variables:
As explained above, if the value of a global variable is not changed inside a function, then
there is no need to define it as global. In the following code, there is no need to define x
as global inside the function:
● 95
x = 10
y = 4
def tst():
global y
y = x + 2
It is important to note that the variables in a function call are passed by value. This means
that the value of a parameter cannot be changed inside a function. An example is shown
in Figure 7.22. In this example, notice that the value of variable cnt is not changed inside
the function call.
A function normally returns only one item to the calling program. In some applications,
we may want to return more than one item to the calling program. This is easily done
by returning a tuple and then unpacking it in the main program. An example is shown in
Figure 7.23. In this example, the function MyFunc is declared with two arguments. The
arguments are added and stored in a local variable called sum. Similarly, the difference of
the arguments is stored in variable diff. The function returns both sum and diff as a tuple.
The calling main program unpacks the returned data and stores in variables x and y.
7.26 Examples
Example 4
Write a program to read an angle from the keyboard in degrees and display the trigonomet-
ric sine of this angle. Repeat until the user stops the program.
Solution 4
The required program listing and example output are shown in Figure 7.24 (program: trig.
py). The angle entered by the user is converted into floating point and is stored in variable
angle. Then the trigonometric sine of this angle is displayed. The program continues until
the user enters n in response to the prompt Any more?
● 96
This program was created and run using the Thonny IDE.
Example 5
Modify the program in Example 4 so that the user can choose between sine, cosine, and
tangent.
Solution 5
The modified program listing and example output are shown in Figure 7.25 and Figure 7.26
(program: trigall.py). The user is given a menu with four choices: sine, cosine, tangent,
exit. The angle is read from the keyboard and is converted into radians. The program then
calculates the trigonometric value and displays on the screen. This process is repeated until
the user selects the exit option.
#--------------------------------------------------
# TRIGONOMETRIC SINE,COSINE,TANGENT PROGRAM
# =========================================
#
# This program reads an angle from the keyboard
# and displays its trigonometric sine, cosine, or
# tangent depending on user choice. The angle is
# read in degrees,converted into radians and then
# the required trigonometric function is calculated
#
# Author: Dogan Ibrahim
● 97
# File : trigall.py
# Date : October, 2023
#--------------------------------------------------
import math
choice = '1'
while choice != '0':
print(«Trigonometric Sine, Cosine, or Tangent»)
print(«======================================\n»)
print(«1. Sine»)
print(«2. Cosine»)
print(«3. Tangent»)
print(«0. Exit»)
choice = input(«Enter choice: «)
if choice != '0':
angle = float(input(«Enter angle in degrees: «))
r = math.radians(angle)
if choice == '1':
s = math.sin(r)
strng = «sine»
elif choice == '2':
s = math.cos(r)
strng = «cosine»
elif choice == '3':
s = math.tan(r)
strng = «tangent»
print(strng + « of %3.2f degrees is: %f\n» %(angle, s))
print(«End of program»)
● 98
This program was created using the nano text editor and then run using the command:
Example 6
Write a program to tabulate the trigonometric sines of angles from 0º to 90º in steps of 5º.
Solution 6
The required program listing is shown in Figure 7.27 (program: sinetable.py). After dis-
playing a heading, the for statement is used to create a loop. Variable angle takes values
from 0 to 90 (inclusive) in steps of 5. The trigonometric sine is calculated and displayed.
#--------------------------------------------------
# TRIGONOMETRIC SINE TABLE
# ========================
#
# This program tabulates the trigonometric sine of
# angles from 0 to 90 degrees in steps of 5 degress
#
# Author: Dogan Ibrahim
# File : sinetable.py
# Date : October, 2023
#--------------------------------------------------
import math
print("End of program")
● 99
Example 7
Write a program to read metres from the keyboard. Convert into yards and inches and
display the result.
Solution 7
The required program listing and example output are shown in Figure 7.29 program: conv.
py). After displaying a heading, metres is read from the keyboard using the input state-
ment. The value is then converted into yards and inches by multiplying with 1.0936 and
39.370 respectively. The results are displayed on the screen.
Example 8
Repeat Example 7 but do the conversion in a function called Conv. Show how this function
can be called from the main program.
● 100
Solution 8
The required program listing and example output are shown in Figure 7.30 (program: con-
vfunc.py). Function Conv is declared at the beginning of the program. Metres to be con-
verted into yards and inches is passed as an argument to the function. The function returns
the yards and inches in a tuple. The main program reads the metres from the keyboard and
calls the function Conv. The result is displayed on the screen.
Example 9
Write a function called Cyl to calculate the area and volume of a cylinder, given its radius
and height. Use this function in a main program.
Solution 9
The area and volume of a cylinder are given by the formula:
Area = 2πrh
Volume = πr2h
The required program listing and example output are shown in Figure 7.31 (program:
cylinder.py). The radius and height of the cylinder are passed as arguments to a function
which calculates the area and volume of the cylinder and returns the results to the main
program, which are displayed on the screen.
● 101
Example 10
Write a calculator program to carry out the four simple mathematical operations of addi-
tion, subtraction, multiplication, and division on two numbers received from the keyboard.
Solution 10
The required program listing is shown in Figure 7.32 (program: calc.py). Two numbers are
received from the keyboard and stored in variables n1 and n2. Then, the required mathe-
matical operation is received and it is performed. The result, stored in the variable result,
is displayed on the screen. The user is given the option of terminating the program.
#----------------------------------------------
# CALCULATOR PROGRAM
# ==================
#
# This is a simple calculator program that can
# carry out 4 basic arithmetic opertions
#
# Author: Dogan Ibrahim
# File : calc.py
# Date : October, 2023
#----------------------------------------------
any = 'y'
while any == 'y':
print("\nCalculator Program")
print("==================")
● 102
if op =="+":
result = n1 + n2
elif op == "-":
result = n1 - n2
elif op == "*":
result = n1 * n2
elif op == "/":
result = n1 / n2
print("Result = %f" %(result))
any = input("\nAny more (yn): ")
Example 11
Write a program to simulate double dice. i.e. to display two random numbers between 1
and 6 every time it is run.
Solution 11
The required program listing and example output are shown in Figure 7.34 (program: dice.
py). Here, the random number generator randint is used to generate random numbers
between 1 and 6 when the Enter key is pressed. The program is terminated when the letter
X is entered.
● 103
Example 12
Write a program to use functions to calculate and display the areas of shapes: square,
rectangle, triangle, circle, and cylinder. The sizes of the required sides should be received
from the keyboard.
Solution 12
The areas of the shapes to be used in the program are as follows:
The required program listing is shown in Figure 7.35 (program: areas.py). A different
function is used for each shape, and the sizes of the sides are received inside the functions.
The main program displays the calculated area for the chosen shape.
#----------------------------------------------
# AREAS OF SHAPES
# ===============
#
# This program calculates and displays the areas
# of various geometrical shapes
# of numbers in a list
#
# Author: Dogan Ibrahim
# File : areas.py
● 104
print("AREAS OF SHAPES")
print("===============\n")
print("What is the shape?: ")
shape = shape.lower()
if shape == 's':
a = float(input("Enter a side of the square: "))
area = Square(a)
s = "Square"
elif shape == 'r':
a = float(input("Enter one side of the rectangle: "))
b = float(input("Enter other side of the rectangle: "))
area = Rectangle(a, b)
s = "Rectangle"
elif shape == 'c':
radius = float(input("Enter radius of the circle: "))
area = Circle(radius)
s = "Circle"
elif shape == 't':
base = float(input("Enter base of the triangle: "))
height = float(input("Enter height of the triangle: "))
area = Triangle(base, height)
s = "Triangle"
elif shape == 'y':
● 105
7.28 Exceptions
There may be major errors in our programs, such as dividing by zero, file privilege error,
and so on. Normally, when Python encounters such errors, it cannot handle them and the
program crashes.
One way to handle such errors orderly and avoid crashes is to use exception handling in
our programs. The basic method is that whenever an error occurs, the program detects
this error and takes appropriate measures to handle the error and continue to execute
normally. Exception handling is also useful if we wish to terminate a running program in an
● 106
orderly manner, for example to shut down any input-output operations when the program
is terminated asynchronously by the user (e.g. by pressing the Ctrl+C key).
The statements try and except are used to handle unexpected errors or terminations in our
programs. The general format of exception handling is as follows:
try:
Normal program statements
Normal program statements
except condition 1:
if condition 1 type error occurs, then execute this block of code
……………..
……………..
except condition 2:
if condition 2 type error occurs, then execute this block of code
……………….
……………….
else:
if there are no errors detected, then execute this block of code
…………………
…………………
We can use the except statement with no condition to handle any type of exception. Some
of the commonly used exceptions are:
Example 13
Write a program to wait for an input from the keyboard. Terminate the program orderly
when the Ctrl+C keys are pressed on the keyboard.
● 107
Solution 13
Figure 7.38 shows the program listing (program: except1.py). Exception KeyboardInter-
rupt is used in this program. The message End of Program is displayed when Ctrl+C key
combination is pressed on the keyboard.
#=====================================================
# KeyboardInteerupt EXCEPTION
#
# This program detects the keyboard entry Cntrl+C and
# the program is teminated orderly after the message
# End of Program is displayed
#
# Author : Dogan Ibrahim
# File : except1.py
# Date : October, 2023
#======================================================
try:
mode = input("Enter Cntrl+C to terminate the program: ")
except KeyboardInterrupt:
print("\nEnd of Program")
Example 14
Write a program to detect division by zero and to display the message Divide by Zero when
this exception is detected.
Solution 14
Figure 7.39 shows the program listing (program: except2.py). Here, the program is forced
to divide a number by zero and this is detected as an exception and the program displays
a message when this occurs.
#=====================================================
# ZeroDivisionError EXCEPTION
#
# This program detects when a number is divided by zero
# and generates an exception to display a message
##
# Author : Dogan Ibrahim
# File : except2.py
# Date : October, 2023
#======================================================
print("Divide by zero exception")
try:
s = 10 / 0
● 108
except ZeroDivisionError:
print("Divide by Zero")
Example 15
Write a program to look for KeyboardInterrupt exception and display the message "Excep-
tion not occurred" if an exception has not occurred.
Solution 15
Figure 7.40 shows the program listing (program: except3.py). The block inside finally is
executed regardless of whether an exception occurs.
#=====================================================
# try/finally In EXCEPTION
#
# This program detects the keyboard entry Cntrl+C and
# displays the message Keyboard Interrupt if interrupt
# occurs. Message Continue is displayed regardless of
# whether an exception occurrede
#
# Author : Dogan Ibrahim
# File : except3.py
# Date : October, 2023
#======================================================
try:
mode = input("Enter Cntrl+C to terminate the program: ")
except KeyboardInterrupt:
print("\nKeyboard Interrupt")
finally:
print("\nContinue")
● 109
The datetime module can also be used for date and time functions. This module must be im-
ported to use these functions. Some examples of date functions are shown in Figure 7.42.
● 110
The function strftime(format) is very useful as it can be used to format a date and time
string. Some examples of using this function are given in Figure 7.43.
def hello():
print("Hello there!")
We can now import this module into our Python programs. An example program called
myprog.py is shown below:
import msg
msg.hello()
Running the program: python myprog.py will display the following output:
Hello there!
We can also modify our program myprog.py and import and then call the module as follows:
msg.py
def hello():
print("Hello there!")
name = "Jones"
● 111
myprog.py
import msg
msg.hello()
print(msg.name)
The program will display:
Hello there!
Jones
Aliases can be created for modules. This is shown in the following code:
myprog.py
import msg as tst
tst.hello()
Hello there!
Example 16
Write a module that calculates the cube of the integer number passed to it. Show how this
module can be imported and used in a program.
Solution 16
Figure 7.44 shows the module listing (program: cubeno.py). The function cube inside
cubeno.py has the number as its argument. The cube of this number is calculated and re-
turned. Figure 7.45 shows the program (program: myprog.py). As an example, when the
number is 3, the output from the program is:
Cube of 3 is: 27
def cube(N):
r = N * N * N
return r
import cubeno
n= 3
res = cubeno.cube(n)
print("Cube of %d is: %d" %(n,res))
● 112
Module Search Path: When a module is to be imported, Python looks at the following folders
in the order given:
The folder from which the module is called (where the calling main program is)
The Python search path can be displayed by entering the following command interactively:
To make sure that your module is found by Python, you can do one of the following:
• Put the module program file in the folder where your main program is
• Put the module program in one of the folders already contained in the
PYTHONPATH
● 113
8.1 Overview
This chapter is about the Raspberry Pi 5 hardware interface and using LEDs in simple pro-
jects. The Raspberry Pi 5 is connected to external electronic circuits and devices using its
GPIO (General Purpose Input Output) port connector. This is a 2.54 mm, 40-pin expansion
header, arranged in a 2 × 20 strip as shown in Figure 8.1. The I/O ports are numbered as
GPIO nn
● 114
The GPIO provides 26 general-purpose bidirectional I/O pins. Some of the pins have mul-
tiple functions. For example, pins 3 and 5 are the GPIO2 and GPIO3 input-output pins
respectively. These pins can also be used as the I²C bus SDA and SCL pins respectively.
Similarly, pins 9, 10, 11 and 19 can either be used as general-purpose input-output pins, or
as the SPI bus pins. Pins 8 and 10 are reserved for UART serial communication.
Two power outputs are provided: +3.3 V and +5.0 V. The GPIO pins operate at +3.3 V logic
levels (not like many other computer circuits that operate with +5 V). A pin can either be an
input or an output. When configured as an output, the pin voltage is either 0 V (logic 0) or
+3.3 V (logic 1). Raspberry Pi 5 is normally operated using an external power supply (e.g.
a mains adapter) with +5 V output. A 3.3 V output pin can supply up to 16 mA of current.
The total current drawn from all output pins should not exceed the 51 mA limit. Care should
be taken when connecting external devices to the GPIO pins, as drawing excessive currents
or short-circuiting a pin can easily damage your Raspberry Pi. The amount of current that
can be supplied by the 5 V pin depends on many factors, such as the current required by
the Pi itself, current taken by the USB peripherals, camera current, micro-HDMI port cur-
rent, and so on.
When configured as an input, a voltage above +1.7 V will be taken as logic 1, and a voltage
below +1.7 V will be taken as logic 0. Care should be taken not to supply voltages greater
than +3.3 V to any I/O pin, as large voltages can easily damage your Raspberry Pi. The
Raspberry Pi 5, like others in the family, has no overvoltage protection circuitry.
Block diagram: The block diagram of the project is shown in Figure 8.3
● 115
Circuit diagram: The circuit diagram of the project is shown in Figure 8.4. A small LED
is connected to port pin GPIO 17 (pin 11) of the Raspberry Pi 5 through a current limiting
resistor. The value of the current limiting resistor is calculated as follows:
The output high voltage of a GPIO pin is 3.3 V. The voltage across an LED is approximately
1.8 V. The current through the LED depends upon the type of LED used and the amount
of required brightness. Assuming that we are using a small LED, we can assume a forward
LED current of about 3 mA. Then, the value of the current limiting resistor is:
In Figure 8.4 the LED is operated in current sourcing mode where a high output from the
GPIO pin drives the LED. The LED can also be operated in current sinking mode, where
the other end of the LED is connected to +3.3 V supply and not to the ground. In current
sinking mode, the LED is turned ON when the GPIO pin is at logic low.
● 116
Program listing: The program is called LED.py and the listing is shown in Figure 8.6.
The program was written using the nano text editor. At the beginning of the program, the
gpiozero and the time modules are imported to the project. The rest of the program is
executed indefinitely in a while loop, where the LED is turned on and off with a one-second
delay between each output change. Press Ctrl+C to terminate the program.
#-------------------------------------------------------
#
# FLASHING LED
# ============
#
# In thisproject a small LED is connected to GPIO 17 of
# the Raspberry Pi 5. The program flashes the LED every
# second.
#
# Program: LED.py
# Date : October, 2023
# Author : Dogan Ibrahim
#--------------------------------------------------------
from gpiozero import LED # import gpiozero
from time import sleep # import time library
led = LED(17)
while True:
led.on() # turn ON LED
sleep(1) # wait 1 second
led.off() # turn OFF LED
sleep(1) # wait 1 second
If you wish to run the program from the GUI Desktop environment, you should use the
VNC Viewer to get into the GUI desktop screen (unless you have a monitor connected to
the Raspberry Pi 5 via a micro-HDMI cable). Then, click the Applications menu → Pro-
gramming → Thonny.
Click File and open file LED.py, or type in the program if it is not already in your default di-
rectory. Now, click Run to run the program. You should see the LED flashing every second.
To terminate the program, close the screen by clicking the STOP button.
● 117
Note: You can copy the programs from your Raspberry Pi 5 home directory to your PC
using the winSCP file copy program (available free of charge on the Internet).
Block diagram: The block diagram of the project is shown in Figure 8.7
Circuit diagram: The circuit diagram of the project is shown in Figure 8.8. Two small LEDs
are connected to port pins GPIO 17 (pin 11) and GPIO 27 (pin 13) of the Raspberry Pi 5
through current limiting resistors.
Program listing: The program is called alternate.py and the listing is shown in Fig-
ure 8.9. The program was written using the nano text editor. At the beginning of the
program, the gpiozero and the time modules are imported to the project. The rest of the
program is executed indefinitely in a while loop where the LEDs are turned on and off alter-
nately with one-second delay between each output. Press Ctrl+C to terminate the program.
● 118
#-------------------------------------------------------
#
# ALTERNATELY FLASHING LEDS
# =========================
#
# In thisproject two small LEDs is connected to GPIO 17 and
# GPIO 27 of the Raspberry Pi 5. The program flashes the LEDs
# alternately every second
#
# Program: alternate.py
# Date : October, 2023
# Author : Dogan Ibrahim
#--------------------------------------------------------
from gpiozero import LED
from time import sleep # import time library
while True:
led1.on() # Turn ON LED1
led2.off() # Turn OFF LED2
sleep(1) # Wait 1 second
led1.off() # Turn OFF LED1
led2.on() # Turn ON LED2
sleep(1) # Wait 1 second
Block diagram: The block diagram of the project is shown in Figure 8.10
● 119
Circuit diagram: The circuit diagram of the project is shown in Figure 8.11. The LEDs are
connected to 8 GPIO pins through 470 Ω current limiting resistors. The following 8 GPIO
pins are grouped as an 8-bit port, where GPIO 2 is configured as the LSB and GPIO 9 is
configured as the MSB:
MSB LSB
GPIO: 9 10 22 27 17 4 3 2
Pin no: 21 19 15 13 11 7 5 3
● 120
Program listing: The program is called LEDCNT.py and the listing is shown in Figure 8.14.
The program was written using the nano text editor. Inside the main program, a loop is
formed to execute forever and inside this loop the LEDs count up by one in binary. Variable
cnt is used as the counter. Function Port_Output is used to control the LEDs. This function
can take integer numbers from 0 to 255, and it converts the input number (x) into binary
using the built-in function bin. Then the leading '0b' characters are removed from the out-
put string b (bin function inserts characters '0b' to the beginning of the converted string).
Then, the converted string b is made up of 8 characters by inserting leading zeroes. The
string is then sent to the PORT bit by bit, starting from the least significant bit (GPIO 2)
position. The result is that the 8 LEDs count up in binary.
● 121
#-----------------------------------------------------------
#
# BINARY UP COUNTING LEDs
# =======================
#
# In this project 8 LEDs are connected to the following
# GPIO pins:
#
# 9 10 22 27 17 4 3 2
#
# The program groups these LEDs as an 8-bit port and then
# the LEDs count up in binary with one second delay between
# each output.
#
# Program: LEDCNT.py
# Date : October, 2023
# Author : Dogan Ibrahim
#------------------------------------------------------------
from gpiozero import LED
from time import sleep # import time library
#
# LED connections
#
PORT = [0] * 8
PORT[0] = LED(9)
PORT[1] = LED(10)
PORT[2] = LED(22)
PORT[3] = LED(27)
PORT[4] = LED(17)
PORT[5] = LED(4)
PORT[6] = LED(3)
PORT[7] = LED(2)
#
# This function sends 8-bit data (0 to 255) to the PORT
#
def Port_Output(x):
b = bin(x) # convert into binary
b = b.replace("0b", "") # remove leading "0b"
diff = 8 - len(b) # find the length
for i in range (0, diff):
b = "0" + b # insert leading os
● 122
PORT[i].on() # bit ON
else:
PORT[i].off() # bit OFF
return
#
# Main program loop. Count up in binary every second
#
cnt = 0
while True:
Port_Output(cnt) # send cnt to port
sleep(1) # wait 1 second
cnt = cnt + 1 # increment cnt
if cnt > 255:
cnt = 0
Recommended modifications: Modify the program such that the LEDs count down every
two seconds.
Modified Program
The program shown in Figure 8.14 can be modified and made more friendly by storing the
LED port numbers in a list. The modified program LEDCNT2.py is shown in Figure 8.15. In
this program, the LED port numbers are stored in list PORT. Then function Port_Output is
used as before to send the port data to the LEDs.
#-----------------------------------------------------------
#
# BINARY UP COUNTING LEDs
# =======================
#
# In this project 8 LEDs are connected to the following
# GPIO pins:
#
# 9 10 22 27 17 4 3 2
#
# The program groups these LEDs as an 8-bit port and then
# the LEDs count up in binary with one second delay between
# each output.
#
# Program: LEDCNT2.py
# Date : October, 2023
# Author : Dogan Ibrahim
#------------------------------------------------------------
from gpiozero import LED
● 123
#
# This function initializes the port list PORT[]
#
def Configure():
for i in range(8):
PORT[i] = LED(PORT[i])
#
# This function sends 8-bit data (0 to 255) to the PORT
#
def Port_Output(x):
b = bin(x) # convert into binary
b = b.replace("0b", "") # remove leading "0b"
diff = 8 - len(b) # find the length
for i in range (0, diff):
b = "0" + b # insert leading os
while True:
Port_Output(cnt) # send cnt to port
sleep(1) # wait 1 second
cnt = cnt + 1 # increment cnt
if cnt > 255:
cnt = 0
● 124
The block diagram and circuit diagram of the projects are the same as in Figure 8.10 and
Figure 8.11 respectively.
Program listing: The program is called XMAS.py and the listing is shown in Figure 8.16.
The program was written using the nano text editor. At the beginning of the program, the
random module and other required modules are imported to the program. Then, a loop
is formed to execute forever and inside this loop a random number is generated between
1 and 255, and this number is used as an argument to function Port_Output. The binary
pattern corresponding to the generated number is sent to the port, which turns the LEDs
ON or OFF randomly.
#-----------------------------------------------------------
#
# CHRISTMAS LIGHTS
# ================
#
# In this project 8 LEDs are connected to the Raspberry Pi 3
# and these LEDs flash randomly at 0.5 second intervals. The
# connections of the LEDs are to the following GPIO pins:
#
# 9 10 22 27 17 4 3 2
#
# The program groups these LEDs as an 8-bit port and then
# generates random numbers between 1 and 255 and turns the
# LEDs ON and OFF depending on the generated number.
#
# Program: XMAS.py
# Date : October, 2023
# Author : Dogan Ibrahim
#------------------------------------------------------------
from gpiozero import LED
from time import sleep # import time library
import random # import random library
#
# This function initializes the port list PORT[]
#
def Configure():
for i in range(8):
PORT[i] = LED(PORT[i])
#
# This function sends 8-bit data (0 to 255) to the PORT
#
● 125
def Port_Output(x):
b = bin(x) # convert into binary
b = b.replace("0b", "") # remove leading "0b"
diff = 8 - len(b) # find the length
for i in range (0, diff):
b = "0" + b # insert leading os
#
# Main program loop. Count up in binary every second
#
while True:
numbr = random.randint(1, 255) # generate a random number
Port_Output(numbr) # send cnt to port
sleep(0.5) # wait 0.5 second
Recommended modifications: Modify the program such that 10 LEDs can be connected
to the Raspberry Pi 5 and flashed randomly.
● 126
The block diagram and circuit diagram of the projects are the same as in Figure 8.10 and
Figure 8.11 respectively.
Program listing: The program is called rotate.py and the listing is shown in Figure 8.18.
The program was written using the nano text editor. Inside the main program, a loop is
formed to execute forever and inside this loop the variable rot is used as an argument to
the Port_Output function. This variable is shifted left at each iteration, and thus the LED
ON sequence is from left to right (from LSB to MSB). A one-second delay is inserted be-
tween each output.
#------------------------------------------------------------------
# ROTATING LEDs
# =============
#
# In this project 8 LEDs are connected to the Raspberry Pi 5.
# The LEDs rotate from LSB to MSB every second
#
# Program: rotate.py
# Date : October, 2023
# Author : Dogan Ibrahim
#--------------------------------------------------------------------
from gpiozero import LED
from time import sleep # import time library
#
# This function initializes the port list PORT[]
#
def Configure():
for i in range(8):
PORT[i] = LED(PORT[i])
#
# This function sends 8-bit data (0 to 255) to the PORT
#
def Port_Output(x):
b = bin(x) # convert into binary
b = b.replace("0b", "") # remove leading "0b"
diff = 8 - len(b) # find the length
for i in range (0, diff):
b = "0" + b # insert leading os
● 127
else:
PORT[i].off()
return
#
# Configure PORT s
#
Configure()
#
# Main program loop. Rotate the LEDs
#
rot = 1
while True:
Port_Output(rot)
sleep(1) # wait 1 second
rot = rot << 1 # shift left
if rot > 128: # at the end
rot = 1 # back to beginning
Block diagram: The block diagram of the project is shown in Figure 8.19.
Circuit diagram: The circuit diagram of the project is shown in Figure 8.20. The LEDs
are connected to 8 GPIO pins through 470 Ω current limiting resistors, as in the previous
project. The push-button switch is connected to GPIO 11 (pin 23) of the Raspberry Pi 5.
The push-button switch is connected through a 10 kΩ and a 1 kΩ resistor. When the switch
is not pressed, the input is at logic 1. When the switch is pressed, the input changes to
● 128
logic 0. Notice that the 1 kΩ resistor is used here for safety if the input channel is config-
ured as an output accidentally. If this is the case, without a resistor the output would be
short-circuited and this could damage the Raspberry Pi hardware.
● 129
Program listing: The program is called ButtonLED.py and the listing is shown in Fig-
ure 8.22. The program was written using the nano text editor. Module gpiozero is im-
ported with both LED and Button. button is assigned port GPIO 11. A loop is formed
to execute forever, and inside this loop the variable rot is used as an argument to the
Port_Output function. If the button is not pressed, then rot is shifted right and the LED
ON sequence is from left to right (from MSB to LSB). If, on the other hand, the button is
pressed, then the LED On sequence is from right to left (from LSB to MSB). A one-second
delay is inserted between each output.
#------------------------------------------------------------------
#
# ROTATING LEDs WITH PUSH-BUTTON
# ==============================
#
# In this project 8 LEDs are connected to the Raspberry Pi 5.
# In addition a push-button switch is connected to GPIO 11.
# Normally the output of the button is at logic 1 and goes to 0
# when the button is pressed. The LEDs rotate in one direction
# and when the button is pressed the direction of rotation
# is reversed. One second delay is inserted between each output
#
# Program: ButtonLED.py
# Date : October, 2023
# Author : Dogan Ibrahim
#--------------------------------------------------------------------
from gpiozero import LED, Button
● 130
#
# This function initializes the port list PORT[]
#
def Configure():
for i in range(8):
PORT[i] = LED(PORT[i])
#
# This function sends 8-bit data (0 to 255) to the PORT
#
def Port_Output(x):
b = bin(x) # convert into binary
b = b.replace("0b", "") # remove leading "0b"
diff = 8 - len(b) # find the length
for i in range (0, diff):
b = "0" + b # insert leading os
#
# Main program loop. Rotate the LEDs
#
rot = 1
while True:
Port_Output(rot)
sleep(1)
if button.is_pressed: # wait 1 second
rot = rot << 1 # shift left
if rot > 128: # at the end
rot = 1 # back to beginning
else:
rot = rot >> 1
● 131
if rot == 0:
rot = 128
Note that the following options are available for the Button function (see https://gpiozero.
readthedocs.io/en/stable/api_input.html):
wait_for_press
wait_for_release
held_time
hold_repeat
hold_time
is_held
is_pressed
value
when_held
when_pressed
when_released
Circuit diagram: The circuit diagram of the project is shown in Figure 8.23 where an ac-
tive buzzer is connected to GPIO 11 of the Raspberry Pi 5.
Morse Code: In Morse code, each letter is made up of dots and dashes. Figure 8.24 shows
the Morse code of all the letters in the English alphabet (this table can be extended by add-
ing the Morse code of numbers and punctuation marks). The following rules apply to the
timing of dots and dashes:
● 132
• The duration of a dot is taken as the unit time, and this determines the speed
of the transmission. Normally, the speed of transmission is quoted in words per
minute (wpm). The standard required minimum in Morse code communication
is 12 wpm.
• The duration of a dash is 3 unit times
• The time between each dot and dash is one unit time
• The time between the letters is 3 unit times
• The time between the words is 7 unit times
In this project, the Morse code is simulated at 10 wpm. Thus, the unit time is taken to be
1200/10 = 120 ms.
Letter Morse code
A: .-
B: -...
C: -.-.
D: -..
E: .
F: ..-.
G: --.
H: ....
I: ..
J: .---
K: -.-
L: .-..
M: --
N: -.
O: ---
P: .--.
Q: --.-
R: .-.
S: ...
T: -
U: ..-
V: ...-
W: .--
X: -..-
Y: -.--
Z: --..
● 133
Program listing: The program is called morse.py and the listing is shown in Figure 8.25.
The Morse code alphabet is stored in the list Morse_Code. The function DO_DOT imple-
ments a single dot with the duration of one unit time. Function DO_DASH implements a
single dash with a duration of three unit times. Function DO_SPACE implements a space
character with duration of seven unit times. The rest of the program is executed in a loop,
where a text is read from the keyboard and the buzzer sounds in such a way as to repre-
sent the Morse code of this text. The program terminates if the user enters the text QUIT.
You should run the program from the command mode as follows:
#-----------------------------------------------------------------
#
# MORSE CODE EXERCISER
# ====================
#
# This project can be used to learn the Morse code. A buzzer is
# connected to GPIO 17 of the Raspberry Pi 5.
#
# The program reads a text from the keyboard and then sounds the
# buzzer to simulate sending or receiving the Morse code of this
# text.
#
# In this project the Morse code speed is assumed to be 10 wpm,
# but can easily be changed by changing the parameter wpm.
#
# File : morse.py
# Date : October, 2023
# Author: Dogan Ibrahim
#-----------------------------------------------------------------
from gpiozero import LED
from time import sleep
Morse_Code = {
'A': '.-',
'B': '-...',
'C': '-.-.',
'D': '-..',
'E': '.',
● 134
'F': '..-.',
'G': '--.',
'H': '....',
'I': '..',
'J': '.---',
'K': '-.-',
'L': '.-..',
'M': '--',
'N': '-.',
'O': '---',
'P': '.--.',
'Q': '--.-',
'R': '.-.',
'S': '...',
'T': '-',
'U': '..-',
'V': '...-',
'W': '.--',
'X': '-..-',
'Y': '-.--',
'Z': '--..'
}
#
# This function sends a DOT (unit time)
#
def DO_DOT():
Buzzer.on()
sleep(unit_time)
Buzzer.off()
sleep(unit_time)
return
#
# This function sends a DASH ( 3*unit time)
#
def DO_DASH():
Buzzer.on()
sleep(3*unit_time)
Buzzer.off()
sleep(unit_time)
return
#
# This function sends inter-word space (7*unit time)
#
● 135
def DO_SPACE():
sleep(7*unit_time)
return
#
# Main program code
#
text = ""
while text != "QUIT":
text = input("Enter text to send: ")
if text != "QUIT":
for letter in text:
if letter == ' ':
DO_SPACE()
else:
for code in Morse_Code[letter.upper()]:
if code == '-':
DO_DASH()
elif code == '.':
DO_DOT()
sleep(unit_time)
sleep(3*unit_time)
sleep(2)
Recommended modification: An LED can be connected to the GPIO pin instead of the
buzzer so that the Morse code can be seen in visual form.
Block diagram: The block diagram of the project is shown in Figure 8.26.
● 136
Figure 8.27 shows the LEDs that should be turned ON to display the 6 dice numbers.
Circuit diagram: The circuit diagram of the project is shown in Figure 8.28. Here, 8 GPIO
pins are collected together to form a PORT. The following pins are used for the LEDs (there
are 7 LEDs, but 8 port pins are used in the form of a byte where the most significant bit
position is not used):
Bit 7 6 5 4 3 2 1 0
GPIO: 9 10 22 27 17 4 3 2
● 137
Table 8.1 gives the relationship between a dice number and the corresponding LEDs to be
turned ON to imitate the faces of a real dice. For example, to display number 1 (i.e. only
the middle LED is ON), you have to turn LED D3 ON. Similarly, to display number 4, you
have to turn ON D0, D2, D4 and D6.
The relationship between the required number and the data to be sent to the PORT to turn
on the correct LEDs is given in Table 8.2. For example, to display dice number 2, you have
to send hexadecimal 0x41 to the PORT. Similarly, to display number 5, we have to send
hexadecimal 0x5D to the PORT and so on.
1 0x08
2 0x41
3 0x49
4 0x55
5 0x5D
6 0x77
Program listing: The program is called dice.py and the listing is shown in Figure 8.29.
The bit pattern to be sent to the LEDs corresponding to each dice number is stored in hex-
adecimal format in a list called DICE_NO (see Table 8.2). GPIO 11 is configured as a button
pin, and the push-button switch is connected to this pin to simulate the 'throwing' of a dice.
The main program waits until a button is pressed. Then, a random number is generated
between 1 and 6 and stored in variable n. The bit pattern corresponding to this number is
found and sent to function Port_Output so that the required LEDs are turned on to repre-
sent the dice number. This process is repeated after 3 seconds of delay.
● 138
#------------------------------------------------------------------
#
# ELECTRONIC DICE WITH LEDs
# =========================
#
# This program is an electronic dice. GPIO 11 of Raspberry Pi 5
# is configured as a Button. When this button is pressed, a random
# dice number is generated between 1 and 6 and is displayed through
# the LEDs. 7 LEDs are mounted on the breadboard in the form of the
# face of a real dice. The following GPIO pins are used for the LEDs@
#
# Bit: 7 6 5 4 3 2 1 0
# GPIO: 10 22 27 17 4 3 2
#
# The following PORT pins are used to construct the dice:
#
# D0 D4
# D1 D3 D5
# D2 D6
#
# Program: dice.py
# Date : October, 2023
# Author : Dogan Ibrahim
#--------------------------------------------------------------------
from gpiozero import LED, Button
from time import sleep # Import time library
import random
#
# This function initializes the port list PORT[]
#
def Configure():
for i in range(8):
PORT[i] = LED(PORT[i])
#
# This function sends 8-bit data (0 to 255) to the PORT
#
def Port_Output(x):
b = bin(x) # convert into binary
b = b.replace("0b", "") # remove leading "0b"
diff = 8 - len(b) # find the length
● 139
#
# Main program loop. Rotate the LEDs
#
while True:
if button.is_pressed: # wait for buttonn
n = random.randint(1, 6) # generate a number
print(n)
pattern = DICE_NO[n]
Port_Output(pattern)
sleep(3) # wsit for 3 seconds
Port_Output(0) # turn OFF all LEDs
● 140
9.1 Overview
The I²C (or I2C) bus is commonly used in microcontroller-based projects. In this chapter,
you will be looking at the use of this bus on the Raspberry Pi 5. Some other interesting
projects are also given in this chapter. The aim is to make the reader familiar with the I²C
bus library functions and to show how they can be used in a real project. Before looking
at the details of the projects, it is worthwhile to look at the basic principles of the I²C bus.
Figure 9.1 shows the structure of an I²C bus with one master and three slaves.
Figure 9.1 I²C bus with one master and three slaves
Because the I²C bus is based on just two wires, there should be a way to address an indi-
vidual slave device on the same bus. For this reason, the protocol defines that each slave
device provides a unique slave address for the given bus. This address is usually 7-bits
wide. When the bus is free, both lines are HIGH. All communication on the bus is initiated
and completed by the master, which initially sends a START bit, and completes a transac-
tion by sending a STOP bit. This alerts all the slaves that some data is coming on the bus,
and all the slaves listen on the bus. After the start bit, 7 bits of unique slave address are
sent. Each slave device on the bus has its own address, and this ensures that only the ad-
dressed slave communicates on the bus at any time to avoid any collisions. The last sent bit
is a read/write bit such that if this bit is 0, it means that the master wishes to write to the
bus (e.g. to a register of a slave), if this bit is a 1, it means that the master wishes to read
from the bus (e.g. from the register of a slave). The data is sent on the bus with the MSB
bit first. An acknowledgement (ACK) bit takes place after every byte and this bit allows the
receiver to signal the transmitter that the byte was received successfully and as a result,
another byte may be sent. The ACK bit is sent at the 9th clock pulse.
● 141
• The master sends on the bus the address of the slave it wants to communicate
with
• The LSB is the R/W bit which establishes the direction of data transmission, i.e.
from mater to slave (R/W = 0), or from slave to master (R/W = 1)
• Required bytes are sent, each interleaved with an ACK bit, until a stop condition
occurs
Depending on the type of slave device used, some transactions may require a separate
transaction. For example, the steps to read data from an I²C compatible memory device
are:
• Master starts the transaction in write mode (R/W = 0) by sending the slave
address on the bus
• The memory location to be retrieved are then sent as two bytes (assuming
64Kbit memory)
• The master sends a STOP condition to end the transaction
• The master starts a new transaction in read mode (R/W = 1) by sending the
slave address on the bus
• The master reads the data from the memory. If reading the memory in
sequential format, then more than one byte will be read
• The master sets a stop condition on the bus
1.8 Kilo Ohm pull-up resistors are used from the I²C pins to +3.3 V. Notice that because
the I²C pins are pulled up to +3.3 V and Raspberry Pi 5 pins are not +5V compatible, it is
necessary to use voltage level converter circuits if the I²C LCD operates with +5V.
● 142
with +5 V where its SDA and SCL pins are pulled to +5 V. It is not a good idea to connect
the LCD directly to the Raspberry Pi, as it can damage its I/O circuitry. There are several
solutions here. One solution is to remove the I²C pull-up resistors on the LCD module. The
other option is to use an LCD which operates with +3.3 V. The other solution is to use a bidi-
rectional +3.3 V to +5 V logic level converter chip. In this project, you will use the TXS0102
bidirectional logic level converter chip like the one shown in Figure 9.2.
Note: Raspberry Pi 5 GPIO pins are claimed to be +5V tolerant as long as the RP1 module
is powered ON. But for safety, a logic-level converter is used in this project.
Block diagram: Figure 9.3 shows the block diagram of the project.
● 143
Figure 9.5 shows the front and back of the I²C based LCD. Notice that the LCD has a
small board mounted at its back to control the I²C interface. The LCD contrast is adjusted
through the small potentiometer mounted on this board. A jumper is provided on this board
to disable the backlight if required.
Program Listing: Before using the I²C pins of the Raspberry Pi, we have to enable the I²C
peripheral interface on the device. The steps for this are as follows:
Now you have to check that the I²C library is available on your Raspberry Pi 5. The steps
are as follows:
● 144
• Enter the following command. You should see the I²C tools (Figure 9.6):
• Connect your LCD to the Raspberry Pi 5 device and enter the following
command to check whether the LCD is recognized by the Raspberry Pi 5:
You should see a table similar to the one shown below. A number in the
table means that the LCD has been recognized correctly, and the I²C slave
address of the LCD is shown in the table. In this example, the LCD address
is 27:
1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- 27 -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
You should now install an I²C LCD library so that you can send commands and data to the
LCD. There are many Python libraries available for the I²C type LCDs. The one chosen here
is on GitHub from Dave Hylands. This library is installed as follows:
https://github.com/dhylands/python_lcd/tree/master/lcd
• Copy the following files to your home directory /home/pi using WinSCP:
I2c_lcd.py
lcd_api.py
• Check to make sure that the file is copied successfully. You should see the file
listed with the command:
pi@raspberrypi: ~ $ ls
● 145
You are now ready to write the program. Figure 9.7 shows the program listing (lcd.py). At
the beginning of the program, the LCD driver libraries lcd_api and i2c_lcd are imported to
the program. The heading SECONDS COUNTER is displayed at the top row (row 1) and the
program enters a loop. Inside this loop the variable cnt is incremented every second and
the total value of cnt is displayed on the LCD continuously in the following format:
SECONDS COUNTER
nn
#---------------------------------------------------------
# I2C LCD SECONDS COUNTER
# =======================
#
# In this program an I2C LCD is connected to the Raspberry Pi.
# The program counts up in seconds and displays on the LCD.
#
# At the beginning of the program the text SECONDS COUNTER is
# displayed
#
# Program: lcd.py
# Date : October 2017
# Author : Dogan Ibrahim
#----------------------------------------------------------
import time
from lcd_api import LcdApi
from i2c_lcd import I2cLcd
I2C_ADDR = 0x27
I2C_NUM_ROWS = 2
I2C_NUM_COLS = 16
mylcd = I2cLcd(1,I2C_ADDR,I2C_NUM_ROWS,I2C_NUM_COLS)
● 146
The I²C LCD library supports many functions. Some of the commonly used functions are
(see the LCD library documentation for more details):
The block diagram and circuit diagram are as in Figure 9.3 and Figure 9.4 respectively.
Program listing: Figure 9.8 shows the program listing (LCDtime.py). At the beginning
of the program, time, datetime, and I2cLCD modules are imported to the program. The
LCD is cleared, and the program enters a loop. Inside this loop, the current time is extract-
ed using the strftime() function and the current time is then displayed on the top row of
the LCD every second in the following format:
hh:mm:ss
#---------------------------------------------------------
# I2C LCD TIME DISPLAY
# =======================
#
# This program displays the current time on the LCD.
#
# Program: LCDtime.py
# Date : October 2017
# Author : Dogan Ibrahim
#----------------------------------------------------------
from time import sleep
from datetime import datetime
from lcd_api import LcdApi
from i2c_lcd import I2cLcd
I2C_ADDR = 0x27
● 147
I2C_NUM_ROWS = 2
I2C_NUM_COLS = 16
mylcd = I2cLcd(1,I2C_ADDR,I2C_NUM_ROWS,I2C_NUM_COLS)
mylcd.clear() # clear LCD
9.6 Project 3 – U
sing an I²C LCD – Display IP address of Raspberry
Pi 5
Description: In this project an I²C type LCD is connected to the Raspberry Pi 5 as in the
previous projects. The IP address of the Raspberry Pi 5 is displayed on the top row of the
LCD.
The block diagram and circuit diagram are as in Figure 9.3 and Figure 9.4 respectively.
Program listing: Figure 9.9 shows the program listing (LCDip.py). The IP address is ex-
tracted using the hostname command with the –I option. The IP address is then displayed
on the LCD in the following format:
192.168.3.196
#---------------------------------------------------------
#
# I2C LCD IP DISPLAY
# ==================
# This program displays the IP address on the LCD.
#
# Program: LCDip.py
# Date : October 2017
# Author : Dogan Ibrahim
#----------------------------------------------------------
from time import sleep
from subprocess import check_output
from lcd_api import LcdApi
from i2c_lcd import I2cLcd
● 148
I2C_ADDR = 0x27
I2C_NUM_ROWS = 2
I2C_NUM_COLS = 16
mylcd = I2cLcd(1,I2C_ADDR,I2C_NUM_ROWS,I2C_NUM_COLS)
mylcd.clear()
ip = check_output(["hostname", "-I"],encoding="utf-8").split()[0]
mylcd.putstr(str(ip))
while True:
pass
Circuit Diagram: The dual MCP3002 ADC chip is used in this project to provide analog
input capability to the Raspberry Pi 5. This chip has the following features:
● 149
In this project, the supply voltage and the reference voltage are set to +3.3 V. Thus, the
digital output code is given by:
Each quantization level corresponds to 3300/1024 = 3.22 mV. Thus, for example, input
data '00 0000001' corresponds to 3.22 mV, '00 0000010' corresponds to 6.44 mV and so
on.
The MCP3002 ADC has two configuration bits: SGL/DIFF and ODD/SIGN. These bits follow
the sign bit and are used to select the input channel configuration. The SGL/DIFF is used
to select single ended or pseudo-differential mode. The ODD/SIGN bit selects which chan-
nel is used in single-ended mode and is used to determine polarity in pseudo-differential
mode. In this project, we are using channel 0 (CH0) in single-ended mode. According to
the MCP3002 data sheet, SGL/DIFF and ODD/SIGN must be set to 1 and 0 respectively.
Figure 9.12 shows the circuit diagram of the project, where the voltage to be measured
is applied directly to the CH0 input of the ADC. MCP3002 operates with the SPI interface.
Raspberry Pi 5 GPIO SPI pins are:
● 150
SPI0:
MISO - pin 21
MOSI - pin 19
CE0 - pin 24
SCLK - pin 23
SPI1:
MISO - pin 35
MOSI - pin 38
CE1 - pin 11
SCLK - pin 40
Program listing: The SPI interface must be enabled on the Raspberry Pi 5 before using
the SPI functions. The steps are:
● 151
Figure 9.13 shows the program listing (voltmeter.py). The function get_adc_data is
used to read the analog data, where the channel number (channel_no) is specified in the
function argument as 0 or 1. Notice that we have to send the start bit, followed by the SGL/
DIFF and ODD/SIGN bits and the MSBF bit to the chip.
It is recommended to send leading zeroes on the input line before the start bit. This is often
done when using microcontroller-based systems that must send 8 bits at a time.
The following data can be sent to the ADC (SGL/DIFF = 1 and ODD/SIGN = channel_no) as
bytes with leading zeroes for more stable clock cycle. The general data format is:
For channel 0: 0000 0001 1000 0000 0000 0000 (0x01, 0x80, 0x00)
For channel 1: 0000 0001 1100 0000 0000 0000 (0x01, 0xC0, 0x00)
Notice that the second byte can be sent by adding 2 to the channel number (to make it 2
or 3) and then shifting 6 bits to the left as shown above to give 0x80 or 0xC0.
The chip returns 24-bit data (3 bytes) and we must extract the correct 10-bit ADC data
from these 24 bits. The 24-bit data is in the following format ('X' is don't care bit):
Assuming that the returned data is stored in 24-bit variable ADC, we have:
Thus, we can extract the 10-bit ADC data with the following operations:
Adding the low byte and the high byte, we get the 10-bit converted ADC data as:
DD DDDD DDDD
● 152
Function Description
open (0,0) Open SPI bus 0 using CE0
open (0,1) Open SPI bus 0 using CE1
close() disconnect the device from the SPI bus
writebytes([array of bytes]) Write an array of bytes to SPI bus device
readbytes(len) Read len bytes from SPI bus device
xfer2([array of bytes]) Send an array of bytes to the device with CEx asserted
at all times
xfer([array of bytes]) Send an array of bytes de-asserting and asserting CEx
with every byte transmitted
At the beginning of the program in Figure 9.13 an instance of the SPI is created. Function
get_adc_data reads the temperature from the sensor chip MCP3002 and returns a digital
value between 0 and 1023. This value is then converted into millivolts and is displayed on
the screen. Figure 9.14 shows an example output from the project where the input CH0 was
connected to GND or to +3.3 V.
#---------------------------------------------------------------
# VOLTMETER
# =========
#
# This is a voltmeter project. The voltage to be measured is applied
# to CH0 input of the MCP3002 ADC. The measured voltage is displayed
# on the screen using a print statement
#
# Program: voltmeter.py
# Date : October, 2023
# Author : Dogan Ibrahim
#----------------------------------------------------------------
import spidev
from time import sleep
#
# Create SPI instance and open the SPI bus
#
spi = spidev.SpiDev()
spi.open(0,0) # we are using CE0 for CS
spi.max_speed_hz = 4000
#
# This function returns the ADC data read from the MCP3002
#
def get_adc_data(channel_no):
ADC = spi.xfer2([1, (2 + channel_no) << 6, 0])
rcv = ((ADC[1] & 15) << 6) + (ADC[2] >> 2)
return rcv
● 153
#
# Start of main program. Read the analog temperature, convert
# into degrees Centigrade and display on the monitor every second
#
while True:
adc = get_adc_data(0)
mV = adc * 3300.0 / 1023.0 # convert to mV
print("Voltage = %5.2f mV" %mV) # display voltage in mV
sleep(1) # wait one second
Circuit Diagram: The circuit diagram of the project is shown in Figure 9.16. The LCD and
the MCP3002 are connected as in the previous projects.
● 154
Program listing: Figure 9.17 shows the program listing (LCDvolt.py). This program is
basically the same as the one in Figure 9.13, but here the output is sent to LCD instead of
being displayed on the screen. The data is displayed in the following format:
nnnn mV
#---------------------------------------------------------------
# VOLTMETER WITH LCD DISPLAY
# ==========================
#
# This is a voltmeter project. The voltage to be measured is applied
# to CH0 input of the MCP3002 ADC. The measured voltage is displayed
# on the LCD
#
# Program: LCDvolt.py
# Date : October, 2023
# Author : Dogan Ibrahim
#----------------------------------------------------------------
import spidev
from lcd_api import LcdApi
from i2c_lcd import I2cLcd
from time import sleep
#
# Create SPI instance and open the SPI bus
#
spi = spidev.SpiDev()
spi.open(0,0) # we are using CE0 for CS
spi.max_speed_hz = 4000
I2C_ADDR = 0x27
● 155
I2C_NUM_ROWS = 2
I2C_NUM_COLS = 16
mylcd = I2cLcd(1,I2C_ADDR,I2C_NUM_ROWS,I2C_NUM_COLS)
mylcd.clear()
#
# This function returns the ADC data read from the MCP3002
#
def get_adc_data(channel_no):
ADC = spi.xfer2([1, (2 + channel_no) << 6, 0])
rcv = ((ADC[1] & 15) << 6) + (ADC[2] >> 2)
return rcv
#
# Start of main program. Read the analog temperature, convert
# into degrees Centigrade and display on the monitor every second
#
while True:
adc = get_adc_data(0)
mV = adc * 3300.0 / 1023.0 # convert to mV
disp = str(mV)[:4] + " mV"
mylcd.move_to(0,0)
mylcd.putstr(disp)
sleep(2)
mylcd.clear()
Block Diagram: Figure 9.18 shows the block diagram of the project.
● 156
Circuit Diagram: The dual MCP3002 ADC chip is used in this project to provide analog
input capability to the Raspberry Pi. Figure 9.19 shows the circuit diagram of the project. A
TMP36DZ type analog temperature sensor chip is connected to CH0 of the ADC. TMP36DZ
is a 3-terminal small sensor chip with pins: Vs, GND, and Vo. Vs is connected to +3.3 V,
GND is connected to system ground, and Vo is the analog output voltage. The temperature
in degrees centigrade is given by:
CS, Dout, CLK, and Din pins of the ADC are connected to the SPI pins CE0, MISO, SCLK,
and MOSI pins of the Raspberry Pi 5 respectively.
Program listing: Figure 9.20 shows the Raspberry Pi Python program listing (program:
tmp36.py). The function get_adc_data is used to read the analog data, where the chan-
nel number (channel_no) is specified in the function argument as 0 or 1. Function get_
adc_data reads the temperature from the sensor chip MCP3002 and returns a digital value
between 0 and 1023. This value is then converted into millivolts, 500 is subtracted from it,
and the result is divided by 10 to find the temperature in degrees centigrade. The temper-
ature is displayed on the monitor every second.
● 157
#---------------------------------------------------------------
# ANALOG TEMPERATURE MEASUREMENT
# ==============================
#
# This is a thermometer project. Ambient temperature is read using
# an ADC and is then displayed on the screen every second
#
# Program: tmp36.py
# Date : October, 2023
# Author : Dogan Ibrahim
#----------------------------------------------------------------
import spidev
from time import sleep
#
# Create SPI instance and open the SPI bus
#
spi = spidev.SpiDev()
spi.open(0,0) # we are using CE0 for CS
spi.max_speed_hz = 4000
#
# This function returns the ADC data read from the MCP3002
#
def get_adc_data(channel_no):
ADC = spi.xfer2([1, (2 + channel_no) << 6, 0])
rcv = ((ADC[1] & 15) << 6) + (ADC[2] >> 2)
return rcv
#
# Start of main program. Read the analog temperature, convert
# into degrees Centigrade and display on the monitor every second
#
while True:
adc = get_adc_data(0)
mV = adc * 3300.0 / 1023.0 # convert to mV
Temperature = (mV - 500) / 10.0
print("Temperature = %5.2f C" %Temperature)
sleep(1) # wait one second
● 158
Block diagram: Figure 9.22 shows the block diagram of the project.
Circuit diagram: The circuit diagram of the project is shown in Figure 9.23. The ADC and
the sensor chip are connected as in the previous project.
Program listing: Figure 9.24 shows the program listing (LCDtmp36.py). The program is
very similar to the previous one, but here the temperature is displayed on LCD.
● 159
#---------------------------------------------------------------
# ANALOG TEMPERATURE MEASUREMENT - OUTPUT ON LCD
# =============================================
#
# This is a thermometer project. Ambient temperature is read using
# an ADC and is then displayed on LCD
#
# Program: LCDtmp36.py
# Date : October, 2023
# Author : Dogan Ibrahim
#----------------------------------------------------------------
import spidev
from time import sleep
from lcd_api import LcdApi
from i2c_lcd import I2cLcd
I2C_ADDR = 0x27
I2C_NUM_ROWS = 2
I2C_NUM_COLS = 16
#
# Create SPI instance and open the SPI bus
#
spi = spidev.SpiDev()
spi.open(0,0) # we are using CE0 for CS
spi.max_speed_hz = 4000
#
# This function returns the ADC data read from the MCP3002
#
def get_adc_data(channel_no):
ADC = spi.xfer2([1, (2 + channel_no) << 6, 0])
rcv = ((ADC[1] & 15) << 6) + (ADC[2] >> 2)
return rcv
#
# Start of main program. Read the analog temperature, convert
# into degrees Centigrade and display on the monitor every second
#
while True:
adc = get_adc_data(0)
mV = adc * 3300.0 / 1023.0 # convert to mV
Temperature = (mV - 500) / 10.0
● 160
Block Diagram: Figure 9.25 shows the block diagram of the project.
Circuit Diagram: The circuit diagram of the project is basic, and it consists of an LED and
a push-button switch. The LED and the button are connected to GPIO 17 and GPIO 3 re-
spectively. The button is connected using two resistors as shown in Figure 9.26.
● 161
Program listing: The program is called reaction.py and its listing is shown in Figure 9.27.
At the beginning of the program, the random library and other used libraries are imported
to the program. The program runs in a loop where the system time is recorded as soon as
the LED is turned ON. The program waits for the user to press the button, and the system
time is read again at this moment. The difference between this time and the first time is
displayed as the reaction time of the user. This process repeats after a random delay of
1 to 10 seconds. Notice that the floating-point function time.time() returns the time in
seconds since the epoch.
#----------------------------------------------------------
#
# REACTION TIMER
# ==============
#
# This is a reaction timer program. The user presses a button
# as soon as he/she see a light. The time between seeing the
# light and pressing the button is measured and is displayed
# in milliseconds as the reaction time of the user. The light
# comes ON after a random number of seconds between 1 and 10
# seconds.
#
# Program: reaction.py
# Date : October, 2023
# Author : Dogan Ibrahim
#-----------------------------------------------------------
from time import sleep
import random
from gpiozero import LED, Button
import time
● 162
Block Diagram: Figure 9.29 shows the block diagram of the project.
Circuit Diagram: The circuit diagram of the project, shown in Figure 9.30, is simple, and
it consists of an LED, a push-button switch, and an LCD. The LED and the button are con-
nected to GPIO 17 and GPIO 4 respectively.
● 163
Program listing: The program is called LCDreaction.py and its listing is shown in Fig-
ure 9.31. The program is basically the same as the one in Figure 9.27, but here the output
is sent to LCD.
#----------------------------------------------------------
#
# REACTION TIMER - OUTPUT TO LCD
# ==============================
#
# This is a reaction timer program. The user presses a button
# as soon as he/she see a light. The time between seeing the
# light and pressing the button is measured and is displayed
# on LCD in milliseconds as the reaction time of the user. The
# light comes ON after a random number of seconds between 1 and
# 10 seconds.
#
# Program: LCDreaction.py
# Date : October, 2023
# Author : Dogan Ibrahim
#-----------------------------------------------------------
from time import sleep
import random
from gpiozero import LED, Button
import time
from lcd_api import LcdApi
from i2c_lcd import I2cLcd
I2C_ADDR = 0x27
I2C_NUM_ROWS = 2
I2C_NUM_COLS = 16
● 164
Block Diagram: Figure 9.32 shows the block diagram of the project.
Circuit Diagram: As shown in Figure 9.33, the circuit diagram of the project is simple, and
it consists of an LDR, a 10 kΩ potentiometer, and a relay. The LDR is connected to GPIO 4,
and the relay to GPIO 17.
The resistance of an LDR increases as the light level falls. The response of a typical LDR
is shown in Figure 9.34. The LDR is connected as a resistive potential divider circuit. The
voltage across the LDR increases as the light level falls. At dark, logic 0 will be sent to the
Raspberry Pi, which in turn will activate the relay. When it is light, logic 1 will be sent to the
Raspberry Pi, which will deactivate the relay. The potentiometer can be adjusted so that the
relay is activated at the required light level. This process will require some trial and error.
● 165
Program listing: Figure 9.35 shows the program listing (program: dusklight.py). The
LDR is input and the relay is output. The program detects the voltage at its GPIO 4 pin and
if it at logic 0 (i.e. dark) then it deactivates the relay, otherwise the relay activated. The
potentiometer can be used to adjust the required light trigger level.
#------------------------------------------------------------
#
# DUSK LIGHT
# ==========
#
# In this project a light dependent resistor (LDR) is used to
# detect the ambient light level. When the light level falls
# below the required value, a relay is activated which turns
# ON the lights.
#
# The potentiometer can be used to adjust the triggering
# light level of the project.
#
● 166
# Program: dusklight.py
# Date : October, 2023
# Author : Dogan Ibrahim
#-------------------------------------------------------------
from gpiozero import LED, Button
while True:
if LDR.is_pressed:
RELAY.on() # At logic 0 (dark)
else:
RELAY.off() # At logic 1 (light)
Block diagram: Figure 9.36 shows the block diagram of the project.
Circuit Diagram: An ultrasonic sensor is used to sense the distance in front of the sensor.
The outputs of the ultrasonic sensors are +5 V and therefore are incompatible with the
inputs of Raspberry Pi 5. A resistive potential divider circuit is used to lower the voltage to
+3.3 V. The voltage at the output of the potential divider resistor is:
● 167
Vcc: +V power
Trig: Trigger input
Echo: Echo output
Gnd: Power ground
Therefore,
● 168
Figure 9.38 shows the principle of operation of the ultrasonic sensor module. For example,
if the time to receive the echo is 294 microseconds, then the distance to the object is cal-
culated as:
Figure 9.39 shows the circuit diagram of the project. The trig and echo pins of the sensor
are connected to GPIO 4 and GPIO 17 respectively. The echo output of the ultrasonic sensor
is connected to the Raspberry Pi 5 through a resistive potential divider circuit to drop the
voltage level to +3.3 V.
Program listing: Figure 9.40 shows the program listing (ultrasonic.py). At the beginning
of the program, module DistanceSensor of gpiozero is imported to the program. Then
the echo and trigger pins are defined. The remainder of the program runs in a loop where
the distance is measured and displayed on the screen. Figure 9.41 shows an example out-
put from the program.
● 169
#---------------------------------------------------------
# ULTRASONIC DISTANCE SENSOR
# ==========================
#
# This program uses a HC-SR04 type ultrasonic transmitter/receiver
# to measure the distance to an obstacle in-front of the sensor.
# The measured distance is displayed on the screen.
#
# Program: ultrasonic.py
# Date : October 2023
# Author : Dogan Ibrahim
#----------------------------------------------------------
from gpiozero import DistanceSensor
from time import sleep
while True:
print("Distanc (cm)= %6.2f" %(sensor.distance * 100))
sleep(1)
Block Diagram: Figure 9.42 shows the block diagram of the project.
● 170
Circuit Diagram: Figure 9.43 shows the circuit diagram. The trig and echo pins of the
Front ultrasonic sensor are connected to GPIO 4 and GPIO 17 respectively, as in the previ-
ous project. Similarly, the trig and echo pins of the rear ultrasonic sensor are connected to
GPIO 27 and GPIO 22 respectively. Echo outputs of the ultrasonic sensors are connected to
the Raspberry Pi 5 through resistive potential divider resistors to drop the voltage levels to
+3.3 V. The active buzzer is connected to GPIO 10 of the Raspberry Pi 5.
Program listing: Figure 9.44 shows the program listing (program parking.py). Module
DistanceSensor of gpiozero is imported to the program. If the distance of either sensor
to the objects is less than or equal to the Allowed_Distance (which is set to 10 cm) then
the buzzer is sounded to indicate that the vehicle is too close to objects (either at the front
or at the rear).
Since the parking sensor is to be operated away from a PC, it is necessary to auto start the
program when power is applied to the Raspberry Pi 5. The program name parking.py must
be included in file /etc/rc.local in the following format so that the program starts as soon
as the Raspberry Pi 5 starts after a power-up or after a reboot:
● 171
#----------------------------------------------------------------------
# PARKING SENSORS
# ===============
#
# This is a parking sensors project. Ultrasonic tranamitter/receiver
# sensors are attached to the front and rear of a vehicle. In addition
# an active buzzer is connected to the Raspberry Oi 5. The program senses
# the objects in the front and rear of the vehicle and sounds the buzzer
# if the vehicle is too close to the objects. In this project a distance
# less than 10cm is considered to be too close.
#
# File : parking.py
# Date : October, 2023
# Author: Dogan Ibrahim
#-----------------------------------------------------------------------
from gpiozero import DistanceSensor, LED
from time import sleep
Buzzer.off()
while True:
obstacle_f = sensorForward.distance * 100 # Forward distance
obstacle_r = sensorRear.distance * 100 # Rear distance
if obstacle_f <= Allowed_Distance or obstacle_r <= Allowed_Distance:
Buzzer.on()
else:
Buzzer.off()
After applying power, wait until the Raspberry Pi 5 boots, and the program should start
automatically. You should remove your Python program name from file /etc/rc.local after
testing and completing your project so that the program does not start every time you
restart your Raspberry Pi 5!
● 172
Program listing: Figure 9.45 shows the program listing (FadeLED.py). Function pulse()
of gpoizero is used to control the LED. The fade-in and fade-out times are set to 1 second
each.
#---------------------------------------------------------
#
# FADING LED
# ==========
# In this program an LED is connected to the Raspberry Pi 5.
# The brightness of the LED fades by using th PWMLED function
# of gpiozero
#
# Program: FadeLED.py
# Date : October, 2023
# Author : Dogan Ibrahim
#----------------------------------------------------------
from gpiozero import PWMLED
#
# Fade-in time and fade-out time are set to 1 second each
#
led.pulse(fade_in_time=1,fade_out_time=1)
while True:
pass
Block diagram: The block diagram of the project is shown in Figure 9.46.
● 173
Circuit diagram: Figure 9.47 shows the circuit diagram of the project. A passive buzzer is
connected to port GPIO 21 (pin 40) of the Raspberry Pi 5. A transistor switch can be used to
increase the voltage level of the buzzer (this can be omitted, and the buzzer can be directly
connected to GPIO 21 if desired). Any NPN bipolar transistor can be used in this project.
The + terminal of the buzzer can be connected to either +3.3 V or to +5V for higher output
from the buzzer.
Melodies
When playing a melody, each note is played for a certain duration and with a certain
frequency. In addition, a certain gap is necessary between two successive notes. The fre-
quencies of the musical notes starting from middle C (i.e. C4) are given below. The har-
monic of a note is obtained by doubling the frequency. For example, the frequency of C5 is
2 × 262 = 524 Hz.
Notes C4 C4# D4 D4# E4 F4 F4# G4 G4# A4 A4# B4
Hz 261.63 277.18 293.66 311.13 329.63 349.23 370 392 415.3 440 466.16 493.88
To play the tune of a melody, you need to know its musical notes. Each note is played for
a certain duration and there is a certain time gap between two successive notes. The next
thing we want is to know how to generate a sound with a required frequency and duration.
In this project, we will be generating the classic Happy Birthday melody, and thus you
need to know the notes and their durations. These are given in the table below, where the
durations are in units of 400 milliseconds (i.e. the values given in the table should be mul-
tiplied by 400 to give the actual durations in milliseconds).
Note C4 C4 D4 C4 F4 E4 C4 C4 D4 C4 G4 F4 C4 C4 C5 A4 F4 E4 D4 A4 B4 A4 F4 G4 F4
Duration 1 1 2 2 2 3 1 1 2 2 2 3 1 1 2 2 2 2 2 1 1 2 2 2 4
Program Listing: The program listing (program: Melody) is shown in Figure 9.48. The
notes and their durations are stored in two lists called Notes and Duration, respectively.
Before the main program loop, the durations of each tone are calculated and stored in the
array Duration so that the main program loop does not have to spend any time doing
● 174
these calculations. Inside the program loop, the melody notes are generated with the re-
quired durations. A small delay (100 ms) is introduced between each tone. The melody is
repeated after five seconds of delay. You can try higher notes for clearer sound, and use
speakers instead of a buzzer.
#---------------------------------------------------------
# PLAY A MELODY (Happy Birthday)
# ==============================
#
# This program plays the melody Happy Birthday through a buzzer
#
# Program: melody.py
# Date : October, 2023
# Author : Dogan Ibrahim
#----------------------------------------------------------
from gpiozero import TonalBuzzer
from gpiozero.tones import Tone
from time import sleep
t = TonalBuzzer(21)
Notes = ['C4','C4','D4','C4','F4','E4','C4','C4','D4','C4','G4',
'F4','C4','C4','C5','A4','F4','E4','D4','A4','B4','A4','F4','G4','F4']
Duration = [1,1,2,2,2,3,1,1,2,2,2,3,1,1,2,2,2,2,2,1,1,2,2,2,4]
length = len(Notes)
while True:
for i in range(length):
t.play(Notes[i])
sleep(Duration[i] * 0.4)
sleep(0.1)
t.stop()
sleep(5)
● 175
Chapter 10 • P
lotting Graphs with Python and
Raspberry Pi 5
10.1 Overview
In this chapter, you will be learning how to draw graphs using the Python programming
language. In addition, examples and projects are given on drawing graphs for simple elec-
tronic circuits.
You must import module matplotlib at the beginning of our programs before we can use
Matplotlib using the statement:
Perhaps the easiest way to learn how to use Matplotlib is to look at an example.
Notice that graphs can only be plotted in Desktop mode. If you are not using a directly con-
nected monitor, then you should start the VNC server on your Raspberry Pi and then start
the VNCViewer on your PC to get into the Desktop mode.
Example 1
Write a program to draw a line graph passing from the following (x, y) points:
x: 2 4 6 8
y: 4 8 12 16
Solution 1
The required program listing is shown in Figure 10.1 (program: graph1.py). This program
is simple. Function call plt.plot plots the graph with the specified x and y values. The graph
is shown on Desktop when statement plt.show() is executed. Start the program by en-
tering the following command in the Accessories → Terminal windows at the Desktop:
#----------------------------------------------
# SIMPLE LINE GRAPH
# =================
#
# This program draws a line graph passing from
# the following points:
● 176
#
# x = 2 4 6 8
# y = 4 8 12 16
#
# Author: Dogan Ibrahim
# File : graph1.py
# Date : October, 2023
#----------------------------------------------
import matplotlib.pyplot as plt
x = [2, 4, 6, 8]
y = [4, 8, 12, 16]
plt.plot(x, y)
plt.show()
Figure 10.2 shows the graph plotted by the program. Notice that at the bottom of the graph
we have several buttons to control the graph, such as zoom, save, etc.
You can add titles, axis labels, and grid to our graph using the following functions:
plt.xlabel(«X values»)
plt.ylabel(«Y values»)
plt.title("Simple X-Y Graph")
plt.grid(True)
● 177
Example 2
Write a program to draw a sine curve from 0 to 2π.
Solution 2
You have to use numpy arrays to store our data points before plotting. Figure 10.4 shows
the program listing (program: graph2.py).
● 178
#----------------------------------------------
# SINE GRAPH
# ==========
#
# This program draws a sine graph from 0 to 2pi
#
# Author: Dogan Ibrahim
# File : graph2.py
# Date : October, 2023
#----------------------------------------------
import matplotlib.pyplot as plt
import numpy as np
#
# Calculate the data points in np
#
x = np.arange(0, 2 * np.pi, 0.1)
y = np.sin(x)
#
# Now plot the graph
#
plt.plot(x, y)
plt.xlabel("X values")
plt.ylabel("Sin(X)")
plt.title("Sine Wave")
plt.grid(True)
plt.show()
● 179
Example 3
Draw the graph of the following function as x is varied from 0 to 4:
y = 2x2 + 3x + 2
Solution 3
Figure 10.6 shows the program listing (program: graph3.py). After calculating the x and
y values, the graph is drawn as shown in Figure 10.7.
#----------------------------------------------
# Function Graph
# ==============
#
# This program draws a graph of the function:
#
# y = 2x2 + 3x + 2 from x=0 to x = 4
#
# Author: Dogan Ibrahim
# File : graph3.py
# Date : October, 2023
#----------------------------------------------
import matplotlib.pyplot as plt
import numpy as np
#
# Calculate the data points in np
#
x = np.arange(0, 4, 0.1)
y = [(2 * i * i + 3 * i + 2) for i in x]
● 180
#
# Now plot the graph
#
plt.plot(x, y)
plt.xlabel("X values")
plt.ylabel("Y values")
plt.title("y=2x2 + 3x + 2")
plt.grid(True)
plt.show()
Example 4
This is an example of drawing two graphs on the same axes. Write a program to draw the
graphs of the following two functions as x is varied from 0 to 3:
y = x2 + 2
y = x2 + 4
Solution 4
Figure 10.8 shows the program listing (program: graph4.py). After calculating the x and
y values, the graphs are drawn as shown in Figure 10.9.
● 181
#----------------------------------------------
# Function Graph
# ==============
#
# This program draws a graph of the functions:
#
# y = x2 + 2
# y = x2 + 4 from x=0 to x = 3
#
# Author: Dogan Ibrahim
# File : graph4.py
# Date : October, 2023
#----------------------------------------------
import matplotlib.pyplot as plt
import numpy as np
#
# Calculate the data points in np
#
x = np.arange(0, 3, 0.1)
y1 = [(i * i + 2) for i in x]
y2 = [(i * i + 4) for i in x]
#
# Now plot the graph
#
plt.plot(x, y1, linestyle='solid')
plt.plot(x, y2, linestyle='dashed')
plt.xlabel("X values")
plt.ylabel("Y values")
plt.title("y=x2+2 and y=x2+4")
plt.grid(True)
plt.show()
● 182
To identify the individual graphs in a multi-graph drawing, you can plot each graph with a
different colour, or with different types of lines. Some examples are shown below:
or
plt.plot(x, y1, linestyle='solid')
plt.plot(x, y2, linestyle='dashed')
Figure 10.10 shows the graph in Figure 10.9 drawn with different line styles.
● 183
Example 5
In this example, you will use legends to identify multiple graphs in a multigraph drawing.
The functions to be drawn are the same as the ones given in the previous example.
Solution 5
Figure 10.11 shows the program listing (program: graph5.py). The Matplotlib function
label is used to identify the two graphs. Also, statement plt.legend() must be specified
to draw the legend.
#----------------------------------------------
# Function Graph
# ==============
#
# This program draws a graph of the functions:
#
# y = x2 + 2
# y = x2 + 4 from x=0 to x = 3
#
# In this program the graphs are identified
#
# Author: Dogan Ibrahim
# File : graph5.py
# Date : October, 2023
#----------------------------------------------
import matplotlib.pyplot as plt
import numpy as np
#
# Calculate the data points in np
#
x = np.arange(0, 3, 0.1)
y1 = [(i * i + 2) for i in x]
y2 = [(i * i + 4) for i in x]
#
# Now plot the graph
#
plt.plot(x, y1, linestyle='solid', label='x2+2')
plt.plot(x, y2, linestyle='dashed', label='x2+4')
plt.xlabel("X values")
plt.ylabel("Y values")
plt.title("y=x2+2 and y=x2+4")
plt.grid(True)
plt.legend()
plt.show()
● 184
Example 6
Write a program to draw a pie chart for the following data;
Solution 6
Figure 10.13 shows the program listing (program: graph6.py). The Pie chart is drawn with
equal aspect ratio, so that is a circle.
#----------------------------------------------
# Pie Chart
# =========
#
# This program draws a pie chart for the data:
#
# France=15%, Germany=20%,Italy=20%,UK=45%
#
# Author: Dogan Ibrahim
# File : graph6.py
# Date : October, 2023
#----------------------------------------------
import matplotlib.pyplot as plt
import numpy as np
● 185
x, chrt = plt.subplots()
chrt.pie(sizes, labels=labels)
chrt.axis('equal')
plt.show()
We can explode parts of the Pie chart by specifying the parts to be exploded. For example,
to explode the fourth item in our example, we can issue the statement:
The amount of explosion is determined by the value we specify. Also, the percentages of
each part can be written inside the Pie chart elements by using the statement:
Parts of the Pie chart can be shadowed if desired to give it a 3D effect. This can be done
using the statement:
shadow=True
The program shown in Figure 10.15 (program: graph7.py) makes use of the above fea-
tures, and the resulting Pie chart is shown in Figure 10.16.
● 186
#----------------------------------------------
# Pie Chart
# =========
#
# This program draws a pie chart for the data:
#
# France=15%, Germany=20%,Italy=20%,UK=45%
#
# Part UK is exploded in this graph.Also, the
# percentage of each part is written inside the
# corresponding parts and pats are shadowed
#
# Author: Dogan Ibrahim
# File : graph7.py
# Date : October, 2023
#----------------------------------------------
import matplotlib.pyplot as plt
import numpy as np
x, chrt = plt.subplots()
chrt.pie(sizes, labels=labels, explode=explode,\
autopct='%1.1f%%',shadow=True)
chrt.axis('equal')
plt.show()
● 187
Example 7
Write a program to draw a bar chart for the following data:
Solution 7
Figure 10.17 shows the program listing (program: graph8.py). After specifying the values
for each bar, the bar chart is drawn.
#----------------------------------------------
# Bar Chart
# =========
#
# This program draws a bar chart for the data:
# France=10, Italy=8,Germany=6,UK=2
#
# Author: Dogan Ibrahim
# File : graph8.py
# Date : October, 2023
#----------------------------------------------
import matplotlib.pyplot as plt
import numpy as np
● 188
You can plot a horizontal bar chart by replacing the statement plt.bar with plt.barh.
Background Information: RC circuits are used in many radio and communications cir-
cuits. A typical RC transient circuit consists of a resistor in series with a capacitor, as shown
in Figure 10.19. When the switch is closed, the voltage across the capacitor rises exponen-
tially with a time constant, T = RC.
Expressed mathematically, assuming that initially the capacitor is discharged, when the
switch is closed the voltage across the capacitor rises a given by the following formula:
(10.1)
Initially, the voltage across the capacitor is 0 V, and in steady state the voltage across the
capacitor becomes equal to Vin. The time constant is the time when the output voltage
rises to around 63.2% of its final value.
Program Listing: Figure 10.20 shows the program listing (program: RCrise.py). After dis-
playing the heading, the values of the input voltage Vin, and resistor and capacitor values
● 189
are read from the keyboard. The program then calculates the time constant as T=RC and
displays the time constant and also draws the time response of the circuit. The graph is
drawn as the time value (x-axis) changes from 0 to 6T, and 50 points are taken to draw the
graph. The time constant is also written on the graph at the point (Time constant, Vin/2).
The horizontal axis is in seconds, while the vertical axis is in volts.
#----------------------------------------------
# RC TRANSIENT RESPONSE
# =====================
#
# This program reads the R and C values and then
# calculates and displays the time conctant. Also,
# the time response of teh circuit is drawn
#
# Author: Dogan Ibrahim
# File : RCrise.py
# Date : October, 2023
#----------------------------------------------
import matplotlib.pyplot as plt
import numpy as np
import math
#
# Read Vin, R and C
#
Vin = float(input("Enter Vin in Volts: "))
R = float(input("Enter R in Ohms: "))
C = float(input("Enter C in microfarads: "))
C = C / 1000000.0
#
# Calculate and display time constant
#
T = R * C
F = 6.0 * T
N = F / 50.0
print("Time constant = %f seconds" %(T))
#
# Now plot the time response
#
x = np.arange(0, F, N)
y = [(Vin * (1.0 - math.exp(-i/T))) for i in x]
● 190
plt.plot(x, y)
plt.xlabel("Time (s)")
plt.ylabel("Capacitor Volts")
plt.title("RC Response")
plt.grid(True)
TC = "T="+str(T)+"s"
plt.text(T, Vin/2, TC)
plt.show()
Figure 10.21 shows an example graph displayed by the program. In this program, the fol-
lowing input values were used (see Figure 10.22):
Vin = 10 V
R = 100 Ω
C = 10 µF
● 191
(10.2)
Where Vo is the initial voltage across the capacitor (normally same as Vin) before s2 is
closed. Again, T=RC is known as the time constant of the circuit.
Program Listing: Figure 10.24 shows the program listing (program: RCfall.py). After dis-
playing the heading, the values of the initial voltage across the capacitor (Vo), the resistor
and the capacitor are read from the keyboard. The program then calculates the time con-
stant as T=RC and displays the time constant and draws the time response of the circuit.
The graph is drawn as the time value (x-axis) changes from 0 to 6T and 50 points are taken
to draw the graph. The time constant is also written on the graph at the point (Time con-
stant, Vo/2). The horizontal axis is in seconds, while the vertical axis is in volts.
#----------------------------------------------
# RC TRANSIENT RESPONSE
# =====================
#
# This program reads the R and C values and then
# calculates and displays the time constant. Also,
# the time response of the circuit is drawn as the
# capacitor is discharged
#
# Author: Dogan Ibrahim
# File : RCfall.py
# Date : October, 2023
#----------------------------------------------
import matplotlib.pyplot as plt
import numpy as np
import math
● 192
#
# Read Vo, R and C
#
Vo = float(input("Enter Initial Capacitor Voltage in Volts: "))
R = float(input("Enter R in Ohms: "))
C = float(input("Enter C in microfarads: "))
C = C / 1000000.0
#
# Calculate and display time constant
#
T = R * C
F = 6.0 * T
N = F / 50.0
print("Time constant = %f seconds" %(T))
#
# Now plot the time response
#
x = np.arange(0, F, N)
y = [(Vo * (math.exp(-i/T))) for i in x]
plt.plot(x, y)
plt.xlabel("Time (s)")
plt.ylabel("Capacitor Volts")
plt.title("RC Response")
plt.grid(True)
TC = "T="+str(T)+"s"
plt.text(T, Vo/2, TC)
plt.show()
Figure 10.25 shows an example graph displayed by the program. In this program, the fol-
lowing input values were used (see Figure 10.26):
● 193
(10.3)
Where, Vin is in volts, R in ohms, L in henries, and t in seconds. The time constant of this
circuit is given by T = L/R.
After the current reaches its steady state value, disconnecting the DC supply and shorting
the leads causes the current in the circuit to fall exponentially, given by the following for-
mula:
(10.4)
The transient response of RL circuits is similar to those of the RC circuits and therefore are
not covered further in this book.
● 194
Underdamped mode: This mode is identified when the following condition holds true:
(10.5)
When DC voltage is applied to the circuit, the current in the circuit is given by the following
formula:
(10.6)
Where,
(10.7)
(10.8)
When DC voltage is applied to the circuit, the current in the circuit is given by the following
formula:
(10.9)
Where,
(10.10)
(10.11)
● 195
When DC voltage is applied to the circuit, the current in the circuit is given by the following
formula:
(10.12)
Where,
(10.13)
Program Listing: Figure 10.28 shows the program listing (program: RLC.py). At the
beginning of the program a heading is displayed and then the values of the input voltage,
resistor, capacitor and the inductor are read and stored in variables Vin, R, C, and L re-
spectively. The program then finds out in which mode the circuit will be operating based
on the value of ξ. Then, three functions are used, one for each mode, to calculate and plot
the transient response of the circuit. The mode of the circuit is displayed on the graph at
the coordinate (3T, 0), where T = 2π/W. In all the graphs, 80 points are used to draw the
points from 0 to 6T.
#------------------------------------------------
# RLC TRANSIENT RESPONSE
# ======================
#
# This program reads the R,L,C values and then
# calculates and displays the transient response
#
# Author: Dogan Ibrahim
# File : RLC.py
# Date : October, 2023
#------------------------------------------------
import matplotlib.pyplot as plt
import numpy as np
import math
global x, y, z
def critically_damped():
global x,y
x = np.arange(0, F, N)
y = [Vin*((1/L) * i * math.exp(-i*w)) for i in x]
def underdamped():
global x,y,z
x = np.arange(0, F, N)
zeta = math.sqrt(1 - z*z)
y = [Vin*(1/(w*L*zeta)*(math.exp(-z*w*i))*math.sin(w*i*zeta)) for i in x]
● 196
def overdamped():
global x,y,z
x = np.arange(0, F, N)
y = [Vin*(1/(w*L*(math.sqrt(z*z-1))))*(math.exp(-z*w*i))*\
math.sinh(w*i*math.sqrt(z*z-1)) for i in x]
#
# Read Vin, R,C and L
#
Vin = float(input("Enter Vin in Volts: "))
R = float(input("Enter R in Ohms: "))
C = float(input("Enter C in microfarads: "))
C = C / 1000000.0
L = float(input("Enter L in millihenries: "))
L = L / 1000.0
w = math.sqrt(1/(L * C))
z = (R/2) * math.sqrt(C / L)
T = (2.0 * math.pi) / w
F = 6 * T
N = F / 80.0
#
# Find the mode of operation
#
mode = R - 2.0 * math.sqrt(L / C)
if abs(mode) < 0.01:
case = 2
md = "Critically Damped"
critically_damped()
elif mode < 0:
case = 1
md = "Underdamped"
underdamped()
elif mode > 0:
case = 3
md = "Overdamped"
overdamped()
#
# Now plot the time response
#
● 197
plt.plot(x, y)
plt.xlabel("Time (s)")
plt.ylabel("Current")
plt.title("RLC Response")
plt.grid(True)
plt.text(3*T,0, md)
plt.show()
Figure 10.29 shows a typical run of the program with the following values:
Vin = 10 V
R = 10 Ω
C = 100 µF
L = 200 µH
Block diagram: Figure 10.30 shows the block diagram of the project.
● 198
Circuit diagram: The project circuit diagram is shown in Figure 10.32. The module is
connected to Raspberry Pi SDA (pin 3) and SCL (pin 5) pins. +3.3 V power is applied from
pin 1.
● 199
The default address of the BME280 is 0x76. This can be confirmed by entering the following
command after the circuit is built (Figure 10.33):
i2cdetect –y 1
Figure 10.33 Checking the I²C bus for the sensor module
Program listing: Figure 10.34 shows the program listing (bme280.py). Before running
the program, it is necessary to load the BME280 library. The steps are:
At the beginning of the program, the BME280 sensor library is imported s above, Inside
the main program loop the temperature, atmospheric pressure, and humidity are read and
displayed on the screen every 5 seconds.
● 200
#-------------------------------------------------------------
# TEMPERATURE,ATMOSPHERIC PRESSURE AND HUMIDITY
# =============================================
#
# This program reads the ambient temperature, atmospheric
# pressure, and humidity using a BME280 sensor module. The
# readings are dislayed on the screen every 5 seconds
#
# Program: bme280.py
# Date : October, 2023
# Author : Dogan Ibrahim
#--------------------------------------------------------------
from time import sleep
from bme280pi import Sensor
● 201
The block diagram and circuit diagram of the project are the same as in Figure 10.30 and
Figure 10.32.
Program listing: Figure 10.36 shows the program listing (bme280plot.py). The sen-
sor data is collected for 60 seconds where the temperature, pressure and humidity are
stored in t[], p[], and h[]. The seconds are stored in tim[]. When the program runs,
the message Collecting data… is displayed. The collected data is plotted as shown in
Figure 10.37. Note that you can adjust the position of the graphs on the screen using the
horizontal arrow tool at the bottom of the screen.
#-------------------------------------------------------------
# PLOT TEMPERATURE,ATMOSPHERIC PRESSURE AND HUMIDITY
# ==================================================
#
# This program reads the ambient temperature, atmospheric
# pressure, and humidity using a BME280 sensor module. The
# readings are plotted on the Desktop
#
# Program: bme280plot.py
# Date : October, 2023
# Author : Dogan Ibrahim
#--------------------------------------------------------------
from time import sleep
from bme280pi import Sensor
import matplotlib.pyplot as plt
p = [0]*60
t=[0]*60
h=[0]*60
data = [0]*60
tim=[0]*60
print("Collecting data...")
for i in range(60):
data=sensor.get_data()
tim[i]=i
p[i] =int(data['pressure'])
t[i] = int(data['temperature'])
h[i] = int(data['humidity'])
● 202
sleep(0.1)
plt.figure()
plt.subplot(2, 2, 1)
plt.plot(tim,t)
plt.title("Temperature (C)")
plt.grid()
plt.subplot(2, 2, 2)
plt.plot(tim,p)
plt.title("Pressure (hPa)")
plt.grid()
plt.subplot(2, 2, 3)
plt.plot(tim,h)
plt.title("Relative Humidity (%)")
plt.grid()
plt.show()
● 203
Chapter 11 • W
aveform Generation – Using the
Digital-to-Analog Converter (DAC)
11.1 Overview
Waveform generators are important in many electronic communication applications. In this
chapter, you will be developing projects to generate various waveforms such as square,
sine, triangular, staircase, etc. by using an external DAC chip and programming the Rasp-
berry Pi 5. In this book, you will be using the popular MCP4921 DAC chip from Microchip.
• 12-bit operation
• 20 MHz clock support
• 4.5 μs settling time
• External voltage reference input
• 1× or 2× gain
• 2.7 to 5.5 V supply voltage
• -40ºC to +125ºC temperature range
In projects in this book, you will be operating the MCP4921 with a gain of one. As a result,
with a reference voltage of 3.3 V and 12-bit conversion data, the LSB resolution of the DAC
will be 3300/4096 = 0.8 mV
● 204
MOSI (or SDI): Master Out Slave In. This signal is output from the master and is input
to a slave
MISO: Master In Slave Out. This signal is output from a slave and input to a master
The SPI bus must be enabled using the raspi-config console command on the Raspberry
Pi before it can be used.
Block Diagram: Figure 11.2 shows the block diagram of the project. The output
● 205
Circuit Diagram: The circuit diagram of the project is shown in Figure 11.3. The output of
the DAC is connected to a PSCGU250 type digital oscilloscope.
Program Listing: Data is written to the DAC in 2 bytes. The lower byte specifies D0:D8 of
the digital input data. The upper byte consists of the following bits:
In normal operation, we will send the upper byte (D8:D11) of the 12-bit (D0:D11) input
data with bits D12 and D13 set to 1 so that the device is active, and the gain is set to 1x.
Then we will send the low byte (D0:D7) of the data. This means that 0x30 should be added
to the upper byte before sending it to the DAC.
● 206
Figure 11.4 shows the program listing (program: squaredac.py). GPIO 26 is used as the
CS pin. The frequency variable is set to 1000, which is the required frequency. Function
DAC sends the 12-bit input data to the DAC. This function has two parts. In the first part,
the HIGH byte is sent after adding 0x30 as described above. Function xfer2 is used to send
the data to the DAC. In the second part of the function, the LOW byte is extracted and is
sent to the DAC. Notice that we could have sent both the high byte and the low byte using
the same xfer2 function, as follows:
Variable ONvalue is set to 2000 × 4095/3300, which is the digital value corresponding to
2000 mV (i.e. 2 V, remember that the 12-bit DAC has 4095 steps, and the reference voltage
is set to 3300 mV). The OFFvalue is set to 0 V. Normally, the delay between the ON and
OFF times should have been equal to halfperiod. However, it was found by experiment
that the DAC routine takes about 0.2 ms (0.0002 second) and this changes the period and
consequently the frequency of the output waveform. Because of this, 2 mV is subtracted
from halfperiod as shown in Figure 13.9
#-----------------------------------------------------------------
# GENERATE SQUARE WAVEFORM
# ========================
#
# This program generates square waveform with the frequency 1kHz.
# In this program the MC4921 DAC chip is used to set the output
# peak voltage to 2V
#
# Author: Dogan Ibrahim
# File : squaredac.py
# Date : October, 2023
#-------------------------------------------------------------------
from gpiozero import LED
from time import sleep
import spidev # Import SPI
spi = spidev.SpiDev()
spi.open(0, 0) # Bus=0, device=0
spi.max_speed_hz = 3900000
● 207
#
# This function implements the DAC. The data in "data" is sent
# to the DAC
#
def DAC(data):
CS.off() # Enable CS
#
# Send HIGH byte
#
temp = (data >> 8) & 0x0F # Get upper byte
temp = temp + 0x30 # OR with 0x30
spi.xfer2([temp]) # Send to DAC
#
# Send LOW byte
#
temp = data & 0xFF # Get lower byte
spi.xfer2([temp]) # Send to DAC
CS.on() # Disable CS
try:
ONvalue = int(2000*4095/3300) # 2V output
OFFvalue = 0
while True:
DAC(ONvalue) # Send to DAC
sleep(halfperiod - 0.0002) # Wait
DAC(OFFvalue) # Send to DAC
sleep(halfperiod - 0.0002) # Wait
except KeyboardInterrupt:
pass
Figure 11.5 shows the output waveform generated by the program. Notice that the peak
output voltage is 2 V, as expected.
● 208
The block diagram and circuit diagram of the project are as in Figure 11.2 and Figure 11.3
Program Listing: Figure 11.6 shows the program listing (program: sawtooth.py). The
program is very similar to the one given in Figure 11.4.
#-----------------------------------------------------------------
# GENERATE SAWTOOTH WAVEFORM
# ==========================
#
# This program generates sawtooth waveform with 6 steps where each
# step has a width of 1ms
#
# Author: Dogan Ibrahim
# File : sawtooth.py
# Date : October, 2023
#-------------------------------------------------------------------
from gpiozero import LED
from time import sleep # Import time
import spidev # Import SPI
spi = spidev.SpiDev()
spi.open(0, 0) # Bus=0, device=0
spi.max_speed_hz = 3900000
● 209
#
# This function implements the DAC. The data in "data" is sent
# to the DAC
#
def DAC(data):
CS.off() # Enable CS
#
# Send HIGH byte
#
temp = (data >> 8) & 0x0F # Get upper byte
temp = temp + 0x30 # OR with 0x30
spi.xfer2([temp]) # Send to DAC
#
# Send LOW byte
#
temp = data & 0xFF # Get lower byte
spi.xfer2([temp]) # Send to DAC
CS.on() # Disable CS
try:
while True: # Do forever
i = 0
while i < 1.1:
DACValue = int(i*4095) # Value to send
DAC(DACValue) # Send to DAC
sleep(0.0007) # Wait
i = i + 0.2
except KeyboardInterrupt:
pass
An example output waveform taken from the oscilloscope is shown in Figure 11.7. Notice
that the time delay had to be adjusted experimentally to give the correct timing.
● 210
The block diagram and circuit diagram of the project are as in Figure 11.2 and Figure 11.3
Program Listing: Figure 11.8 shows the program listing (program: triangle.py). The
program is very similar to the one given in Figure 11.6.
#-----------------------------------------------------------------
# GENERATE TRIANGLE WAVEFORM
# ==========================
#
# This program generates triangle waveform
#
# Author: Dogan Ibrahim
# File : triangle.py
# Date : October, 2023
#-------------------------------------------------------------------
from gpiozero import LED
from time import sleep # Import time
import spidev # Import SPI
spi = spidev.SpiDev()
spi.open(0, 0) # Bus=0, device=0
spi.max_speed_hz = 3900000
CS = LED(26)
CS.on() # Disable CS
sample = 0
Inc = 0.05
● 211
CS.on() # Disable CS
try:
while True:
DACValue = int(sample*4095) # Value to send
DAC(DACValue) # Send to DAC
sleep(0.0001) # Wait
sample = sample + Inc # Next sample
if sample > 1.0 or sample < 0:
Inc = -Inc
sample = sample + Inc
except KeyboardInterrupt:
pass
An example output waveform taken from the oscilloscope is shown in Figure 11.9.
● 212
The shape of one period of the waveform to be generated is shown in Figure 11.10. Notice
that the waveform has a period of 20 ms.
● 213
The block diagram and circuit diagram of the project are as in Figure 11.2 and Figure 11.3
Program Listing: Figure 11.11 shows the program listing (program: arbit.py). The sam-
ple points of the waveform are stored in a list called wave. Variable sample indexes this
list and sends the sample values to the DAC. The time of each sample was specified to be
1 ms. It was found by experiment that a 0.8 ms delay gave the correct results because of
the delay in the DAC routine.
#-----------------------------------------------------------------
# GENERATE ARBITRARY WAVEFORM
# ===========================
#
# This program generates an arbitrary waveform whose sample points
# are defined in the program
#
# Author: Dogan Ibrahim
# File : arbit.py
# Date : October, 2023
#-------------------------------------------------------------------
from gpiozero import LED
from time import sleep # Import time
import spidev # Import SPI
spi = spidev.SpiDev()
spi.open(0, 0) # Bus=0, device=0
spi.max_speed_hz=3900000
#
# Waveform sample points
#
wave = [0,0.375,0.75,1.125,1.5,1.875,2.25,2.625,3,3,3,3,3,\
2.625,2.25,1.875,1.5,1.125,0.75,0.375,0]
#
# This function implements the DAC. The data in "data" is sent
# to the DAC
#
def DAC(data):
CS.off() # Enable CS
#
# Send HIGH byte
#
● 214
CS.on() # Disable CS
try:
while True:
DACValue = int(wave[sample]*4095/3.3) # Value to send
DAC(DACValue) # Send to DAC
sample = sample + 1 # Inc sample index
sleep(0.0008) # Wait
if sample == 20: # If 20 sampes
sample = 0
except KeyboardInterrupt:
pass
An example output waveform taken from the oscilloscope is shown in Figure 11.12.
● 215
The block diagram and circuit diagram of the project are as in Figure 11.2 and Figure 11.3
Program Listing: The frequency of the sine wave to be generated is 100 Hz. This wave
has a period of 10 ms, or 10,000 µs. If we assume that the sine wave will consist of
100 samples, then each sample should be output at 10,000/100 = 100 µs intervals. The
sample values will be calculated using the trigonometric sin function of Python.
where T is the period of the waveform and is equal to 100 samples. Thus, the sine wave is
divided into 100 samples and each sample is output at 100 µs. The above formula can be
rewritten as:
It is required that the amplitude of the waveform should be 1.5 V. With a reference voltage
of +3.3 V and a 12-bit DAC converter (0 to 4095 quantization levels), 1.5 V is equal to 1.5
× 4095/3.3, which is equal to 1861.3 (i.e. the amplitude). Thus, we will multiply our sine
function with the amplitude at each sample to give:
The D/A converter used in this project is unipolar and cannot output negative values.
Therefore, an offset is added to the sine wave to shift it so that it is always positive. The
offset should be larger than the absolute value of the maximum negative value of the sine
wave, which is 1861.3 when the sin function above is equal to 1.5. In this project, we are
adding a 1.5 V offset which corresponds to a decimal value of 1861.3 (i.e. the offset) at
the DAC output. Thus, for each sample, we will calculate and output the following value to
the DAC:
The sine waveform values for a period are obtained outside the program loop using the
following statement. The list sins contains all the 100 sine values of the waveform. The
reason for calculating these values outside the program loop is to minimize the time to
calculate the sin function:
for i in range(100):
sins[i] = int(offset + amplitude * sin(R*i)
● 216
Figure 11.13 shows the program listing (program: sine.py). Most parts of the program are
similar to the other waveform generation programs. Inside the program loop, samples of
the sine wave are sent to the DAC at each sample time.
#-----------------------------------------------------------------
# GENERATE SINE WAVEFORM
# ======================
#
# This program generates sine waveform with a period of 10ms. Both
# the amplitude and the offset of the waveform are set to 1.5V
#
# Author: Dogan Ibrahim
# File : sine.py
# Date : October, 2023
#-------------------------------------------------------------------
from gpiozero import LED
from time import sleep # Import time
import spidev # Import SPI
import math # Import math
spi = spidev.SpiDev()
spi.open(0, 0) # Bus=0, device=0
spi.max_speed_hz = 3900000
CS = LED(26)
CS.on() # Disable CS
sample = 0
T = 100
R = 0.0628
amplitude = 1861.3
offset = 1861.3
sins = [None]*101
#
# This function implements the DAC. The data in "data" is sent
# to the DAC
#
def DAC(data):
CS.off() # Enable CS
#
# Send HIGH byte
#
temp = (data >> 8) & 0x0F # Get upper byte
temp = temp + 0x30 # OR with 0x30
spi.xfer2([temp]) # Send to DAC
● 217
#
# Send LOW byte
#
temp = data & 0xFF # Get lower byte
spi.xfer2([temp]) # Send to DAC
CS.on() # Disable CS
#
# Generate the 100 sine wave samples and store in list sins
#
for i in range(100):
sins[i] = int(offset + amplitude*math.sin(R*i))
try:
while True:
DACValue = sins[sample] # Value to send
DAC(DACValue) # Send to DAC
sleep(0.0001) # Wait
sample = sample + 1 # Next sample
if sample == 100: # 100 samples?
sample = 0
except KeyboardInterrupt:
pass
An example output waveform taken from the oscilloscope is shown in Figure 11.14. Notice
that the frequency of the waveform is not very accurate because the delay function of Py-
thon is not accurate.
● 218
12.1 Overview
The Sense HAT is a small plug-in board developed by Raspberry Pi in collaboration with the
UK Space Agency and the European Space Agency (ESA). The board includes a number of
sensors and that's why it is called 'Sense'. The word 'HAT' stands for 'Hardware Attached on
Top' to indicate that the board is attached or plugged in on top of the Raspberry Pi. Sense
HAT gives the flexibility to carry out various environmental measurements using its built-in
sensors, and the board was specially developed for the Astro Pi Challenge and competition.
An emulator-based version of the Sense HAT is also available to enable students to carry
out experiments without having the physical board.
The Sense HAT board is normally plugged into the 40-way connector of the Raspberry Pi. To
interface external components to the Raspberry Pi in addition to the Sense HAT board, you
need to connect the Sense HAT to the Raspberry Pi using either a ribbon cable or jumper
wires so that other pins of the Raspberry Pi can be accessed. Additionally, if you are using
an active cooler on your Raspberry Pi 5 then it is not possible to connect the Sense HAT
to your board unless you use a ribbon cable or 2×20 pin header extension. Therefore, it is
useful to know which pins of the Sense HAT board are used by Raspberry Pi 5, and which
● 219
pins are free so that you can make connections to the Sense HAT using jumper wires.
In addition to the I²C control lines, the ATTINY88 microcontroller on the board can be
programmed via the SPI bus control lines (MOSI, MISO, SCK, CE0) provided on the board.
The following pins are used by the Sense HAT 40-way connector:
The Sense HAT board can be connected to your Raspberry Pi 5 using only the following 9
pins of the 40-way connector:
● 220
2 2 (+5 V) power
16 16 (GPIO23) joystick
18 18 (GPIO24) joystick
27 27 (ID_SD) EEPROM
28 28 (ID_SC) EEPROM
Note: You can also plug in the Sense HAT board directly on top of your Raspberry Pi 5
board instead of making the above connections provided the GPIO pins are available
(e.g. you are not using a Raspberry Pi active cooler)
Before developing a project using the Sense HAT board, the Sense HAT library must be
imported into your Python program and also the sense object must be created at the be-
ginning of the program. i.e. the following two statements must be included at the beginning
of your programs:
The remainder part of this chapter is devoted to developing simple projects with the Sense
HAT. In all the projects, the Sense HAT was connected to the Raspberry Pi 5 using jumper
wires as described earlier.
If you get an error message saying that the RPi-Sense FB device cannot be detected,
then do the following:
● 221
Notice that there are two versions of the Sense HAT board. Version 1.0 has no colour sen-
sor, while Version 2.0 has a colour sensor. You may get a warning message saying that it
failed to initialize the colour sensor if you are using Version 1.0.
You can also display a single letter using the statement: sense.show_letter, for example,
sense.show_letter("A"). Notice that the letter is displayed permanently.
In addition to displaying text in default mode, you can use the following options:
scroll_speed: This floating-point number changes the speed that the text scrolls. The
default value is 0.1. A higher number slows down the scroll speed.
text_colour: Used to change the text colour. The colour is specified as (Red, Green, Blue)
where each colour can take a value between 0 and 255, and we can mix the colours to
obtain any other colour. For example, (255, 0, 0) is red and so on.
back_colour: used to change the colour of the background. Colour is defined as in the
text_colour option.
In the following example, the same text as above is scrolled slowly, in red colour, with yel-
low background colour:
text_colour=[255,0,0], back_colour=[255,255,0])
Notice that in the above program, the text is displayed only once, but the background col-
our remains as yellow.
If, for example, you wish to repeat displaying the text, say every two seconds, then the re-
quired program is as shown in Figure 12.2 (program: txt.py). Notice how the continuation
line is used in Python. Run the program from the Console mode as:
#-----------------------------------------------------------
# Display Text
# ------------
#
# This program displays the text Sense HAT every 2 seconds.
● 222
while True:
sense.show_message("Sense HAT",scroll_speed=0.3,\
text_colour=[255,0,0],back_colour=[255,255,0])
time.sleep(2)
The sense.clear() statement can be used to turn OFF all the LEDs. This may be necessary
to ensure that all the LEDs are turned OFF at the beginning of a program. Similarly, a colour
can be passed to the clear statement to set all the LEDs to the same colour, such as:
red = (255, 0, 0)
sense.clear(red)
The brightness of the LED matrix can be changed by toggling the low_light statement. In
the following examples, the brightness is toggled:
sense.low_light = True
or
sense.low_light = False
The displayed text (or image) can be rotated by using the statement set_rotation(n)
where n is the rotation angle in degrees, and it can take the values of 0, 90, 180, 270. The
following statement rotates character s by 90 degrees and displays it on the LED matrix:
sense.set_rotation(90)
sense.show_letter("s")
Text (or image) can be flipped horizontally or vertically by using the statements flip_h or
flip_v respectively. In the following example, the character X is flipped horizontally and is
then displayed:
sense.flip_h
sense.show_letter("X")
● 223
Figure 12.3 shows the program listing (program: mult.py). Two integer random numbers
are generated between 1 and 99 and are stored in variables no1 and no2. Variable ques-
tion holds the question as a string and this is displayed in green colour as shown in the
following example:
25 × 10 =
The program waits for 10 seconds and after this time, the result 250 is displayed in red
colour. After 2 seconds, the LEDs are cleared, and the program continues displaying two
new numbers.
#-----------------------------------------------------------
# Multiplication Test
# -------------------
#
# This program displays two numbers between 1 and 99 and waits
# for 10 seconds until the user finds the correct answer. The
# correct answer is then displayed so that the user can check with
# his/her answer
#
# Author: Dogan Ibrahim
# File : mult.py
# Date : October, 2023
#------------------------------------------------------------
from sense_hat import SenseHat
sense = SenseHat()
import time
import random
spd = 0.2 # Scroll speed
red = (255, 0, 0) # Red colour
green = (0, 255, 0) # Green colour
try:
while True:
no1 = random.randint(1,99) # First number
no2 = random.randint(1, 99) # Second number
question = str(no1) + "x" + str(no2) + "="
● 224
except KeyboardInterrupt:
exit()
5x1=5
5x2=10
5x3=15
5x4=20
5x5=25
5x6=30
5x7=35
5x8=40
5x9=45
5x10=50
5x11=55
5x12=60
Figure 12.4 shows the program listing (program: timestab.py). Variable Tablefor stores
the number whose times table is required. A loop is formed which goes from 0 to 11. Inside
this loop, variable j takes on values from 1 to 12. Variable result stores the result of the
multiplication at each iteration of the loop. String variable disp stores the data to be dis-
played by the LED matrix at each iteration. Users can easily change the value of Tablefor
to generate times table for another number.
#-----------------------------------------------------------------
# Times Table
# -----------
#
# This program generates a times table. The table is selected at the
# beginning of the program by setting variable Tablefor.
#
● 225
try:
for k in range(12): # Do 0 to 11
j = k + 1 # 1 to 12
result = Tablefor * j
disp = str(Tablefor) + "x" + str(j) + "=" + str(result)
sense.show_message(disp, scroll_speed = spd, text_colour=(red))
time.sleep(1)
sense.clear()
except KeyboardInterrupt:
exit()
Figure 12.5 shows the program listing (program: thp.py). The program runs in a loop
every two seconds where the temperature, humidity, and pressure readings are displayed
on the scrolling LED. Notice that the readings are all in floating-point format, and the
round() function is used to configure them to have one digit after the decimal point.
#--------------------------------------------------------------
# TEMPERATURE,HUMIDITY & PRESSURE
# -------------------------------
#
# This program reads the temperature, humidity and pressure and
# displays on the scrolling LEDs. The data is displayed in the
# following format:
#
# T=nn.nC H=nn.n% P=nnnn.nmb
#
● 226
while True:
T = round(sense.get_temperature(), 1) # Get temperature
H = round(sense.get_humidity(), 1) # Get humidity
P = round(sense.get_pressure(), 1) # Get pressure
enviro = "T="+str(T)+ "C H="+str(H)+ "% P="+str(P)+"mb "
sense.show_message(enviro, scroll_speed = 0.2)
time.sleep(2)
You could also have displayed the data on the PC screen by running the following program
code. Figure 12.6 shows the output of the program:
You could also display the temperature or the humidity as integer variables on non-scrolling
LEDs by using the Disp function.
● 227
Block diagram: Figure 12.7 shows the block diagram of the project.
Circuit diagram: The circuit diagram of the project is shown in Figure 12.8, where the
buzzer is connected to port pin GPIO 4 of the Raspberry Pi 5. Both the buzzer and the Sense
HAT board are connected to the Raspberry Pi 5 using jumper wires.
● 228
Program listing: In this program, the library function created by the author, named
Disp() is used. This function has 3 arguments: number to be displayed, colour, and mode
(0 or 1, 1 to clear the display). This function is in a Python program called display.py,
which can be found on the web page of the book. Calling function Disp() display a number
without scrolling the display. Figure 12.9 shows the listing of program display.py. Make
sure that display.py is in the same directory as your main program.
#-------------------------------------------------------------
# FUNCTION TO DISPLAY NUMBERS
# ---------------------------
#
# This function displays a two-digit number on the LED matrix
# without scrolling the display. The number to be displayed and
# its colour are entered as the arguments of the function.The
# third parameter controls whether or not to clear the display
# before displaying the number. Setting this parameter to 1
# will clear the display
#
# Author: Dogan Ibrahim
# Date : October, 2023
# File : display.py
#------------------------------------------------------------
from sense_hat import SenseHat
sense = SenseHat()
● 229
[[0,1,1,0], # 0
[1,0,0,1],
[1,0,0,1],
[1,0,0,1],
[1,0,0,1],
[1,0,0,1],
[1,0,0,1],
[0,1,1,0]],
[[0,0,1,0], # 1
[0,1,1,0],
[0,0,1,0],
[0,0,1,0],
[0,0,1,0],
[0,0,1,0],
[0,0,1,0],
[0,1,1,1]],
[[0,1,1,0], # 2
[1,0,0,1],
[0,0,0,1],
[0,0,0,1],
[0,0,1,0],
[0,1,0,0],
[1,0,0,0,],
[1,1,1,1]],
[[1,1,1,1], # 3
[0,0,1,1],
[0,0,1,1],
[1,1,1,1],
[1,1,1,1],
[0,0,1,1],
[0,0,1,1],
[1,1,1,1]],
[[0,0,1,0], # 4
[0,1,1,0],
[1,1,1,0],
[1,0,1,0],
[1,1,1,1],
[0,0,1,0],
[0,0,1,0],
[0,0,1,0]],
[[1,1,1,1], # 5
● 230
[1,0,0,0],
[1,0,0,0],
[1,1,1,1],
[0,0,0,1],
[0,0,0,1],
[0,0,0,1],
[1,1,1,1]],
[[1,1,1,1], # 6
[1,0,0,0],
[1,0,0,0],
[1,1,1,1],
[1,0,0,1],
[1,0,0,1],
[1,0,0,1],
[1,1,1,1]],
[[1,1,1,1], # 7
[0,0,0,1],
[0,0,0,1],
[0,0,0,1],
[0,0,0,1],
[0,0,0,1],
[0,0,0,1],
[0,0,0,1]],
[[0,1,1,0], # 8
[1,0,0,1],
[1,0,0,1],
[1,1,1,1],
[1,0,0,1],
[1,0,0,1],
[1,0,0,1],
[0,1,1,0]],
[[1,1,1,1], # 9
[1,0,0,1],
[1,0,0,1],
[1,1,1,1],
[0,0,0,1],
[0,0,0,1],
[0,0,0,1],
[1,1,1,1]]
]
blank = [0,0,0]
● 231
blanks=[0,0,0,0]
Disp = [] # List to store patterns
if mode == 1:
sense.clear() # Clear LEDs
The program listing is shown in Figure 12.10 (program: tempcont.py). At the beginning
of the program, the modules used in the program are imported to the program. Buzzer
is assigned to number 4, which will correspond to GPIO 4. The set temperature value is
stored in the variable SetTemperature and is hard-coded as 24 in his example. The buzzer
is turned OFF at the beginning of the program. The remainder of the program runs in an
endless loop. Inside this loop, the ambient temperature is read from the Sense HAT and this
temperature is compared with the set point value. If the ambient temperature is less than
the set value, then the buzzer is turned ON and the ambient temperature is displayed in red
as non-scrolling. If, on the other hand, the ambient temperature is greater than the set val-
ue, then the buzzer is turned OFF and the ambient temperature is displayed in blue colour.
#-----------------------------------------------------------------------
# ON-OFF TEMPERATURE CONTROLLER
# -----------------------------
#
# This is an ON-OFF temperature control project. In this project
# a buzzer is connected to port pin GPIO 4 of the Raspberry Pi 5
# In addition to the Sense HAT. The Sense HAT is connected using
# jumper wires. The buzzer is turned ON if the ambient temperature
# is below the setpoint temperature. At the same time, the ambient
# temperature is displayed in red colour. If on the other hand the
● 232
while True:
T = int(sense.get_temperature_from_humidity()) # get temperature
if(T < SetTemperature): # T < setpoint?
Disp(T, red, 0) # display in red
Buzzer.on() # Buzzer ON
else:
Disp(T, blue, 0) # display in blue
Buzzer.off() # Buzzer OFF
The buzzer used in this project can easily be replaced with a relay and a heater can be
connected to the heater. The room temperature will then be controlled by the program.
● 233
Figure 12.11 shows the program listing (program: dice2.py). Here, two integer random
numbers are generated, converted into strings, and stored in variables no1 and no2. State-
ment show_message is used to scroll the generated numbers, where the speed is set to
0.05 and the text colour is set to red. The LED matrix shows the numbers as in the format:
32 24 66 24 etc. as shown in Figure 12.12.
#-----------------------------------------------------------
# Display Two Dice Numbers
# ------------------------
#
# This program displays two dice numbers every 5 seconds. The
# numbers are displayed in red
#
# Author: Dogan Ibrahim
# File : dice2.py
# Date : October 2023
#------------------------------------------------------------
from sense_hat import SenseHat
sense = SenseHat()
import time
import random
red = (255,0,0)
try:
while True:
no1 = str(random.randint(1,6))
no2 = str(random.randint(1,6))
no = no1 + no2
sense.show_message(no, scroll_speed=0.05, text_colour=(red))
time.sleep(5)
sense.clear()
time.sleep(1)
except KeyboardInterrupt:
exit()
● 234
Figure 12.13 shows the program listing (program: curtime.py). At the beginning of the
program, datetime is imported to the program in addition to the other libraries. The scroll-
ing speed is set to 0.15 and the text colour is set to blue. Current time is extracted from
the function datetime.now() and strftime function is used to extract only the hours,
minutes, and seconds. The time is updated and displayed every second using show_mes-
sage.
#--------------------------------------------------------------------
# Display Current Time
# ---------------------
#
# This program displays the current time every second on the following
# format:
# HH:MM:SS
#
# Author: Dogan Ibrahim
# File : curtime.py
# Date : October 2023
#---------------------------------------------------------------------
from sense_hat import SenseHat
sense = SenseHat()
import time
import datetime
● 235
while True:
TimeFormat = "%H:%M:%S"
msg = str(datetime.datetime.now().strftime(TimeFormat))
sense.show_message(msg,scroll_speed=spd, text_colour=(blue))
time.sleep(1)
The strftime() returns a formatted string representing data and time. Some examples are
given below:
Some other codes that can be used with strftime are (for more details, see link: https://
www.programiz.com/python-programming/datetime/strftime):
Figure 12.14 shows the program listing (program: dispnum.py). This program displays
the number 20 as an example. At the beginning of the program, the patterns for all the
numbers from 0 to 9 are defined. The two digits of the number are extracted and saved in
variables intno and remno. For example, if the number is 20, then intno and remno are
● 236
set to 2 and 0 respectively. The LEDs to be turned ON are then combined in a list called
Disp. The LED matrix is cleared just before displaying the number. The numbers are dis-
played in red colour. Figure 12.15 shows the number 20 displayed on the LED matrix.
#-------------------------------------------------------------
# DISPLAY NUMBERS
# ---------------
#
# This program displays a two-digit number on the LED matrix
# without scrolling the display. In this example number 20 is
# displayed
#
# Author: Dogan Ibrahim
# Date : October 2023
# File : dispnum.py
#------------------------------------------------------------
#
# Number patterns for all the numbers 0 to 9
#
numbers = [
[[0,1,1,0], # 0
[1,0,0,1],
[1,0,0,1],
[1,0,0,1],
[1,0,0,1],
[1,0,0,1],
[1,0,0,1],
[0,1,1,0]],
[[0,0,1,0], # 1
[0,1,1,0],
[0,0,1,0],
[0,0,1,0],
[0,0,1,0],
[0,0,1,0],
[0,0,1,0],
[0,1,1,1]],
[[0,1,1,0], # 2
[1,0,0,1],
[0,0,0,1],
[0,0,0,1],
[0,0,1,0],
● 237
[0,1,0,0],
[1,0,0,0,],
[1,1,1,1]],
[[1,1,1,1], # 3
[0,0,1,1],
[0,0,1,1],
[1,1,1,1],
[1,1,1,1],
[0,0,1,1],
[0,0,1,1],
[1,1,1,1]],
[[0,0,1,0], # 4
[0,1,1,0],
[1,1,1,0],
[1,0,1,0],
[1,1,1,1],
[0,0,1,0],
[0,0,1,0],
[0,0,1,0]],
[[1,1,1,1], # 5
[1,0,0,0],
[1,0,0,0],
[1,1,1,1],
[0,0,0,1],
[0,0,0,1],
[0,0,0,1],
[1,1,1,1]],
[[1,1,1,1], # 6
[1,0,0,0],
[1,0,0,0],
[1,1,1,1],
[1,0,0,1],
[1,0,0,1],
[1,0,0,1],
[1,1,1,1]],
[[1,1,1,1], # 7
[0,0,0,1],
[0,0,0,1],
[0,0,0,1],
[0,0,0,1],
[0,0,0,1],
[0,0,0,1],
● 238
[0,0,0,1]],
[[0,1,1,0], # 8
[1,0,0,1],
[1,0,0,1],
[1,1,1,1],
[1,0,0,1],
[1,0,0,1],
[1,0,0,1],
[0,1,1,0]],
[[1,1,1,1], # 9
[1,0,0,1],
[1,0,0,1],
[1,1,1,1],
[0,0,0,1],
[0,0,0,1],
[0,0,0,1],
[1,1,1,1]]
]
blank = [0,0,0]
blanks=[0,0,0,0]
Disp = [] # List to store patterns
no = 20 # Number to be displayed
● 239
Figure 12.16 shows the program listing (program: nums.py). The display function is
named Disp and is stored in a file called Display.py (Figure 12.9). The Function Disp has
three arguments. The first argument is the number to be displayed, the second argument
is the text colour of the display. The third parameter controls whether to clear the display
before displaying the number. Setting this parameter to 1 clears the display. At the begin-
ning of the program, the function Disp is imported into the program. You should make sure
that the Python program display.py is in the same directory as the main program nums.
py. The program creates a loop where variable j changes from 0 to 99. Function Disp is
called with j as the number and the colour is set to green. Therefore, the display shows the
numbers counting up every second from 0 to 99, without scrolling the display.
#-------------------------------------------------------------
# UP COUNTER
# ----------
#
# This program counts up from 0 to 99 every second and displays
# on the LED matrix without any scrolling
#
# Author: Dogan Ibrahim
# Date : October, 2023
# File : nums.py
#------------------------------------------------------------
from sense_hat import SenseHat
sense = SenseHat()
● 240
for j in range(100): # Do 0 to 99
Disp(j, (0,255,0), 1) # Display j
time.sleep(1) # 1 sec delay
Similarly, if we wish to enable only the gyroscope sensor, we have to use the statement:
x, y, z = sense.get_accelerometer_raw().values()
In the example code below, the acceleration in 3 dimensions is read and displayed continu-
ously. You should run this program and move your Sense HAT in three dimensions and see
the acceleration changing in each direction:
Rotating the Sense HAT will change the accelerometer x and y values between -1 and +1. If
it is placed upside down, the z value will change between -1 and +1. If any axis has ±1 G,
then we know that axis is pointing downwards.
● 241
If the board is rotated, then the acceleration will be 1 G maximum in any direction. If on
the other hand, the board is shaken then the acceleration will be greater than 1 G. In this
program, the acceleration in three dimensions is checked to determine when the board is
shaken and if so, a dice number is displayed for two seconds.
Figure 12.17 shows the program listing (program: shake.py). The dice numbers 1 to 6
are stored in list dice. Inside the program loop, the accelerometer values are read, and
then their absolute values are taken. If the acceleration exceeds 2 in any direction, i.e. if
the board is shaken, a dice number is chosen at random and displayed on the LED matrix
in red.
#--------------------------------------------------------------
# ACCELEROMETER BASED DICE
# ------------------------
#
# This program displays a dice number after the Sense HAT board
# is shaken. The accelerometer in 3 dimensions is used to determine
# when the board is shaken
#
# Author: Dogan Ibrahim
# Date : October, 2023
# File : shake.py
#--------------------------------------------------------------
from sense_hat import SenseHat
sense=SenseHat()
import time
import random
sense.clear()
while True:
x, y, z = sense.get_accelerometer_raw().values() # Read acc
x = abs(x) # x val
y = abs(y) # y val
z = abs(z) # z val
if x > 2 or y > 2 or z > 2:
sense.show_letter(random.choice(dice), text_colour = (255,0,0))
time.sleep(2)
sense.clear()
● 242
Figure 12.18 shows the program listing (program: shapes.py). The reason for using the
accelerometer in this project is because it is more reliable and gives consistent results. If
any axis has ±1 G, then we know that axis is pointing downwards. When the Sense HAT
board is tilted in its pitch axis, the LEDs in the x-direction are turned ON depending on
whether the tilt is in the positive or the negative direction (+G or –G). Similarly, when the
board is tilted in its roll axis, the LEDs in the y-direction are turned ON depending on wheth-
er the tilt is in the positive or the negative direction.
#--------------------------------------------------------------
# ACCELEROMETER BASED LED SHAPES
# -------------------------------
#
# In this program the accelerometer is used. The Sense HAT board
# is tilted in its pitch and roll axes to make shapes with LEDs
#
# Author: Dogan Ibrahim
# Date : October, 2023
# File : shapes.py
#--------------------------------------------------------------
from sense_hat import SenseHat
sense=SenseHat()
from time import sleep
sense.clear()
sense.set_pixel(3, 3, (255,0,0)) # Starting LED
x = 3
y = 3
while True:
X,Y,Z = sense.get_accelerometer_raw().values() # Read acc
X = round(X, 0) # X dir
Y = round(Y, 0) # Y dir
if X > 0:
x = x + 1
if x > 7: # If the end
x = 7
elif X < 0:
x = x - 1
● 243
if Y > 0:
y = y + 1
if y > 7: # If the end
y = 7
elif Y < 0:
y = y - 1
if y < 0: # If the end
y = 0
sense.set_pixel(x,y,(255,0,0)) # Display
sleep(1) # 1 sec delay
Figure 12.19 shows an example shape drawn by tilting the Sense Hat board.
● 244
13.1 Overview
Keypads are useful devices for entering data to microcontroller-based systems. They are
especially useful in portable applications where the user has to enter data or make a choice.
In this chapter, you will be learning to use a 4×4 keypad in your Raspberry Pi 5 projects.
The 4×4 Keypad: There are several types of keypads that can be used in microcontrol-
ler-based projects. In this project, a 4×4 keypad (see Figure 13.1) is used. This keypad has
keys for numbers 0 to 9 and the letters A, B, C, D, *, and #. The keypad is interfaced to the
processor with 8 wires with the names R1 to R4 and C1 to C4, representing the rows and
columns respectively of the keypad (see Figure 13.2).
● 245
The operation of the keypad is basic: the columns are configured as inputs, and they are
all set HIGH, and the rows are configured as outputs. The pressed key is identified by using
column scanning. Here, a row is forced LOW while the other rows are held HIGH. Then the
state of each column is scanned, and if a column is found to be LOW, then the intersection
of that column and row is the key pressed. This process is repeated for all the rows.
Circuit diagram: The circuit diagram of the project is shown in Figure 13.4. The 4×4 key-
pad is connected to the following GPIO pins of the Raspberry Pi 5. The column pins are held
high by using external 10 Kilo-ohm resistors to +3.3 V:
● 246
Figure 13.5 shows the pin configuration of the 4×4 keypad used in the project.
Program listing: Figure 13.6 shows the program listing (program: keypad.py). At the
beginning of the program, modules OutputDevice and InputDevice of gpiozero are im-
ported to the program. The row and column pins of the keypad are assigned to GPIO ports.
Rows are configured as outputs and columns as inputs. All the rows are set HIGH initially.
The Function GetChar() waits until a key is pressed and then returns the key to the calling
code. This function calls function ReadRow(). ReadRow() has two arguments: the row
● 247
number and the keypad characters on that row. The function scans the columns and if a
column is detected with LOW state, then the keypad character corresponding to the column
is returned by the function. The program calls GetChar() and displays the pressed key on
the screen.
#------------------------------------------------------------------
#
# 4 x 4 KEYPAD
# ============
#
# In this program a 4 x 4 keypad is connected to Raspberry Pi 5.
# the program displays the key pressed on the screen
#
# Program: keypad.py
# Date : October, 2023
# Author : Dogan Ibrahim
#--------------------------------------------------------------------
from gpiozero import OutputDevice,InputDevice
from time import sleep
#
# ROW pins
#
ROW1 = 4
ROW2 = 17
ROW3 = 27
ROW4 = 22
#
# COLUMN pins
#
COL1 = 10
COL2 = 9
COL3 = 11
COL4 = 0
#
# ROWS as outputs
#
row1 = OutputDevice(ROW1)
row2 = OutputDevice(ROW2)
row3 = OutputDevice(ROW3)
row4 = OutputDevice(ROW4)
row1.on()
row2.on()
row3.on()
● 248
row4.on()
#
# COLUMNS as inputs and (pulled HIGH in hardware)
#
col1 = InputDevice(COL1)
col2 = InputDevice(COL2)
col3 = InputDevice(COL3)
col4 = InputDevice(COL4)
#
# This function sets a row to 0 and then finds out which
# key is pressed on a column
#
def ReadRow(line, char):
x = 'E'
line.off()
if col1.value == 0:
x = char[0]
if col2.value == 0:
x = char[1]
if col3.value == 0:
x = char[2]
if col4.value == 0:
x = char[3]
line.on()
return x
#
# This function waits until a character is pressed on keypad
#
def GetChar():
r = 'E'
while r == 'E':
a = ReadRow(row1, ["1","2","3","A"])
b = ReadRow(row2, ["4","5","6","B"])
c = ReadRow(row3, ["7","8","9","C"])
d = ReadRow(row4, ["*","0","#","D"])
if a != 'E':
r = a
elif b !='E':
r = b
elif c != 'E':
r = c
elif d != 'E':
r = d
● 249
sleep(0.1)
return r
#------------------------------------------------------------------
# 4 x 4 KEYPAD FUNCTIONS
# ======================
#
# Import this file in your Python programs
#
# Program: keypadfuncs.py
# Date : October, 2023
# Author : Dogan Ibrahim
#--------------------------------------------------------------------
from gpiozero import OutputDevice,DigitalInputDevice
from time import sleep
#
# ROW pins
#
ROW1 = 4
ROW2 = 17
ROW3 = 27
ROW4 = 22
#
# COLUMN pins
#
COL1 = 10
COL2 = 9
COL3 = 11
COL4 = 0
● 250
#
# ROWS as outputs
#
row1 = OutputDevice(ROW1)
row2 = OutputDevice(ROW2)
row3 = OutputDevice(ROW3)
row4 = OutputDevice(ROW4)
row1.on()
row2.on()
row3.on()
row4.on()
#
# COLUMNS as inputs and (pulled HIGH in hardware)
#
col1 = DigitalInputDevice(COL1, bounce_time = 1)
col2 = DigitalInputDevice(COL2, bounce_time = 1)
col3 = DigitalInputDevice(COL3, bounce_time = 1)
col4 = DigitalInputDevice(COL4, bounce_time = 1)
#
# This function sets a row to 0 and then finds out which
# key is pressed on a column
#
def ReadRow(line, char):
x = 'E'
line.off()
if col1.value == 0:
x = char[0]
if col2.value == 0:
x = char[1]
if col3.value == 0:
x = char[2]
if col4.value == 0:
x = char[3]
line.on()
return x
#
# This function waits until a character is pressed on keypad
#
def GetChar():
r = 'E'
while r == 'E':
a = ReadRow(row1, ["1","2","3","A"])
b = ReadRow(row2, ["4","5","6","B"])
● 251
c = ReadRow(row3, ["7","8","9","C"])
d = ReadRow(row4, ["*","0","#","D"])
if a != 'E':
r = a
elif b !='E':
r = b
elif c != 'E':
r = c
elif d != 'E':
r = d
sleep(0.1)
return r
Figure 13.8 shows a program (keypadtest.py) that imports the keypad functions.
#------------------------------------------------------------------
#
# 4 x 4 KEYPAD TEST
# =================
#
# This program imports the keypad functions
#
# Program: keypadtest.py
# Date : October, 2023
# Author : Dogan Ibrahim
#--------------------------------------------------------------------
from keypadfuncs import GetChar
Block diagram: Figure 13.9 shows the block diagram of the project.
● 252
Circuit diagram: The circuit diagram is shown in Figure 13.10. The LCD is connected as
in the previous LCD-based projects. The keypad is connected as in the previous project. A
relay is connected to GPIO 21 (pin 40) of the Raspberry Pi 5.
Program listing: Figure 13.11 shows the program listing (lock.py). At the beginning of
the program, the LCD is initialized. The secret code is set to '1357'. The program then dis-
plays Code: and expects the user to enter the correct code. If the correct code is entered,
the message Door Opened is displayed and the relay is turned ON for 20 seconds. After
this time, the relay is deactivated. If the wrong code is entered, the message Error is dis-
played for 5 seconds and the user is asked to enter the correct code again.
● 253
#---------------------------------------------------------
#
# KEYPAD OPERATED LOCK
# ====================
# In this program a door (or a safe) is opened via a relay.
# The user is required to enter the correct secret code for
# the door to open. Once opened, the door stays open for
# 20 seconds
#
# Program: lock.py
# Date : October, 2023
# Author : Dogan Ibrahim
#----------------------------------------------------------
from time import sleep
from lcd_api import LcdApi
from i2c_lcd import I2cLcd
from keypadfuncs import GetChar
from gpiozero import OutputDevice
Relay = OutputDevice(21)
Relay.off()
I2C_ADDR = 0x27
I2C_NUM_ROWS = 2
I2C_NUM_COLS = 16
mylcd = I2cLcd(1,I2C_ADDR,I2C_NUM_ROWS,I2C_NUM_COLS)
while True:
mylcd.move_to(0,0)
mylcd.putstr("Code: ")
a = GetChar() # First no
b = GetChar() # Second no
c = GetChar() # Third no
d = GetChar() # Fourth no
● 254
Relay.on()
sleep(20)
Relay.off()
mylcd.clear()
else:
Relay.off()
mylcd.clear()
mylcd.putstr("Error")
sleep(5)
mylcd.clear()
Suggested modification: Modify the program in Figure 13.11 so that the lock is disabled
for ten minutes if the wrong code is entered three times.
● 255
14.1 Overview
Perhaps the two major features of the Raspberry Pi 5 are its Wi-Fi and Bluetooth communi-
cation capabilities. Raspberry Pi 5 is equipped with a dual-band 2.4 GHz 802.11ac wireless
LAN module and Bluetooth 5.0/Bluetooth Low Energy (BLE). Without such features, you
have to use external network-based hardware communication modules to communicate
over the Internet. Network communication is handled using either UDP or TCP type proto-
cols. In this chapter, you will be learning how to write Python programs using both the UDP
and TCP type protocols using the on-board Wi-Fi module.
TCP UDP
Slow Fast
● 256
Server
1. Create UDP socket
2. Bind the socket to server address
3. Wait until datagram packet arrives from the client
4. Process the datagram packet
5. Send a reply to the client, or close the socket
6. Go back to Step 3 (if not closed)
Client
1. Create UDP socket (and optionally Bind)
2. Send a message to the server
3. Wait until a response from the server is received
4. Process reply
5. Go back to step 2, or close the socket
Server
1. Create UDP socket
● 257
Client
1. Create UDP socket
2. Connect to the server
3. Send a message to the server
4. Wait until a response from the server is received
5. Process reply
6. Go back to step 2, or close the socket
14.3 Project 1 – S
ending a text message to a smartphone using
TCP/IP
Description: In this project, a TCP/IP-based communication is established with an Android
smartphone. The program reads text messages from the keyboard and sends to the smart-
phone. The aim of this project is to show how TCP/IP communication can be established
with an Android smartphone.
● 258
Block diagram: Figure 14.3 shows the project block diagram where the Raspberry Pi 5
and smartphone communicate over a Wi-Fi router.
Program listing: In this project, Raspberry Pi 5 is the server. Figure 14.4 shows the pro-
gram listing (tcpserver.py). At the beginning of the program, a TCP/IP socket is created
(sock.SOCK_STREAM) and is then bind to port 5000. The program listens for a connec-
tion. Notice that it is possible for the server to listen to multiple clients, but of course, it
can communicate with only one at any time. When the client makes a connection, this is
accepted by the server. The server then reads a message from the keyboard and sends it
to the client over the Wi-Fi link. Notice that the setsockopt() statement makes sure that
the program can be used again without having to wait for the socket timeout of 30 seconds.
#===============================================================
# SEND TEXT MESSAGES USING TCP/IP
# ===============================
#
# This is the TCP/IP server program. It receives text messages
# from the keyboard and sends to an Android smart phone over
# a Wi-Fi link
#
# Author: Dogan Ibrahim
# File : tcpserver.py
# Date : October, 2023
#==============================================================
● 259
import socket
yn = 'y'
while yn == 'y':
msg = input("Enter your message: ") # read a message
client.send(msg.encode('utf-8')) # send the message
Testing
There are many TCP apps available free of charge on the Internet for smartphones. In this
project, the TCP Client by JOY S.R.L. apps is used on an Android smartphone. This app is
available free of charge in the Play Store (see Figure 14.5).
● 260
• Run the Android apps and configure it as shown in Figure 14.6 (click the
settings icon at the top right hand of the screen), where 192.168.3.196 is the
IP address of the Raspberry Pi 5.
• Click the icon in the top left corner of the apps (disconnected) to connect to
Raspberry Pi 5 over TCP/IP.
• You should see a connection message on your Raspberry Pi screen and also the
IP address of the remote Android smartphone. Now enter a message and press
the Enter key. In this example, the message HELLO FROM RASPBERRY PI is
sent to the client (Figure 14.7). Figure 14.8 shows the message displayed on
the smartphone.
● 261
14.4 Project 2 – T
wo-way communication with the smartphone using
TCP/IP
Description: This project is similar to the previous one, but here two-way communication
is established between the Raspberry Pi 5 and the smartphone.
Program listing: Figure 14.9 shows the program listing (tcp2way.py). Here, port 5000 is
used as in the previous project. The program has been changed to send and receive mes-
sages from the smartphone. Socket function recv(byte count) sends a message over the
TCP/IP link to the connected node.
#===============================================================
# SEND/RECEIVE TEXT MESSAGES USING TCP/IP
# =======================================
#
# This is the TCP/IP server program. It receives text messages
# from the keyboard and sends to an Android smart phone over
# a Wi-Fi link
#
# Author: Dogan Ibrahim
# File : tcp2way.py
# Date : December, 2023
#==============================================================
import socket
yn = 'y'
try:
while yn == 'y':
msg = input("Enter your message: ") # read a message
msg = msg +"\n"
client.send(msg.encode('utf-8')) # send the message
msg = client.recv(1024)
print("Received message: ")
print(msg.decode('utf-8'))
● 262
except KeyboardInterrupt:
print("\nClosing connection to client")
sock.close()
Testing
You will be using the Android apps as in Figure 14.5. Start the Raspberry Pi 5 server pro-
gram and then exchange messages between the smartphone and Raspberry Pi. Example
communication is shown in Figure 14.10. In this example, Raspberry Pi sends message
Message from RASPBERRY PI. In return, Android smartphone sends the message mes-
sage from ANDROID.
Background Information: In this project, the Raspberry Pi 5 is the server and the PC
is the client. The programs on both sides are developed using the Python programming
language. Python 3.10 is used on the PC. If you do not have Python on your PC, you could
install it from the following website:
https://www.python.org/downloads/
● 263
#===============================================================
# SEND/RECEIVE TEXT MESSAGES USING TCP/IP
# =======================================
#
# This is the TCP/IP server program. It communicates with a PC
# running TCP/IP on the same port
#
# Author: Dogan Ibrahim
# File : tcppc.py
# Date : October, 2023
#==============================================================
import socket
import time
try:
while True:
msg = input("Enter your message: ") # read a message
● 264
msg = client.recv(1024)
print("Received message: ", msg.decode('utf-8'))
except KeyboardInterrupt:
print("\nClosing connection to client")
sock.close()
time.sleep(1)
PC Program Listing: The PC program listing is shown in Figure 14.13 (client.py). The
program creates a socket and connects to the server. Then, messages are exchanged be-
tween the client and the server.
#=============================================================
# TCP/IP CLIENT
# =============
#
# This is the client program on the PC.The program exchanges
# messages with the server on the Raspberry Pi 5
#
# Author: Dogan Ibrahim
# File : client.py
# Date : October, 2023
#=============================================================
import socket
import time
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.connect(("192.168.3.196", 5000))
try:
while True:
msg = sock.recv(1024)
print("Received message: ", msg.decode('utf-8'))
data = input("Enter message to send: ")
sock.send(data.encode('utf-8'))
except KeyboardInterrupt:
print("Closing connection to server")
sock.close()
time.sleep(1)
● 265
Note: You may find that after exiting the program, you may not be able to run it again.
This is because the socket stays open for about 30 seconds and the error message saying
that the Address is already in use may be displayed. You can check the state of the port
with the following command:
If the display includes the text ESTABLISHED, then it means that the socket has not been
closed properly, and you will have to restart your Zero 2 W to run the program again. If on
the other hand, you see the message with TIME_WAIT, then you should wait about 30
seconds before restarting the program.
Block diagram: Figure 14.15 shows the block diagram of the project.
● 266
The LED is connected to port pin GPIO 21 (pin 49) through a 470 Ohm current limiting
resistor.
Program Listing: Figure 14.16 shows the program listing (program: serverled.py). As
in the previous program, a socket is created and port 5000 is used. LED is assigned to
port GPIO pin 21, and turned OFF at the beginning of the program. The server waits for a
connection from the client and then accepts the connection and displays the message Con-
nected. It then waits to receive a command from the client. If the command is ON, then
the LED is turned ON. If, on the other hand, the command is OFF, then the LED is turned
OFF. Sending command X terminates the server connection and exits the program.
#==================================================================
# CONTROL LED FROM SMART PHONE
# ============================
#
# In this program TCP/IP is used where Raspberry Pi 5 is the server
# and smart phone is the client. An LED connected to Raspberry Pi 5
# GPIO 21 and is controlled from the smart phone
#
# Author: DOgan Ibrahim
# File : serverled.py
# Date : December, 2023
#===================================================================
import socket
from gpiozero import LED
from time import sleep
● 267
print("Closing connection")
GPIO.cleanup()
sock.close()
sleep(1)
The program can be tested using the Android apps TCP client (Figure 14.5) used in Pro-
ject 1. The server program started, then the client is started. Figure 14.17 shows sending
the ON command to turn ON the LED.
Suggestions: The LED in this project can be replaced, for example with a relay and elec-
trical equipment can be controlled remotely over Wi-Fi.
● 268
Program Listing: In this project, Raspberry Pi 5 is the server and the smartphone is the
client. Figure 14.18 shows the program listing (udpserver.py). At the beginning of the
program, a UDP socket is created (sock.SOCK_DGRAM) and is then bind to port 5000.
The server program then reads text messages sent from the smartphone and displays on
the screen. Messages sent by Raspberry Pi 5 are displayed on the smartphone.
#==========================================================
# SEND TEXT MESSAGES USING UDP
# ============================
#
# This is the UDP server program running on Raspberry Pi 5.
# The program exchanges text messages with an Android
# smart phone
#
# Author: Dogan Ibrahim
# File : udpserver.py
# Date : October, 2023
#==========================================================
import socket
try:
while True:
print()
print("Waiting for messages")
data, addr = sock.recvfrom(1024)
print(addr)
print("Received msg:", data.decode('utf-8'))
msg = input("Message to send: ")
sock.sendto(msg.encode('utf-8'), addr)
print("Message sent")
except KeyboardInterrupt:
print("\nClosing connection to client")
sock.close()
There are many UDP apps available free of charge for both Android and iOS smartphones.
In this project, UDP Sender/Receiver by JC Accounting & Innovative Technologies
Inc for Android smartphones is used (Figure 14.19).
● 269
• Start the smartphone apps and configure for the IP/Host and Port
• Write a message on mobile phone apps and click SEND. The message Hello
from Android was sent as an example (Figure 14.20)
● 270
The LED can easily be replaced with a relay, for example, to control electrical appliances
from a smartphone.
Program Listing: Figure 14.21 shows the program listing (udpled.py). As in the previous
program, a socket is created and the server waits to receive commands from a client to
control the LED. If the command is ON, then the LED is turned ON. If on the other hand,
the command is OFF, the LED is turned OFF. Command X terminates the server program.
● 271
#==================================================================
# CONTROL LED FROM SMART PHONE
# ============================
#
# In this program UDP is used where Zero 2 W is the server
# and smart phone is the client. An LED connected to the server
# and is controlled from the smart phone
#
# Author: DOgan Ibrahim
# File : udpled.py
# Date : October, 2023
#===================================================================
import socket
from gpiozero import LED
from time import sleep
led = LED(21)
led.off()
sock.close()
sleep(1)
The program can be tested using the UDP Sender/Receiver apps used in Figure 14.19.
● 272
• Write the command ON and press Send on the smartphone (Figure 14.22).
The LED should turn ON. Similarly, write OFF and the LED should turn OFF.
Sending X should terminate the Raspberry Pi 5 program.
● 273
At one edge of the board, there is the micro-USB B port for providing power to the board
and for programming the board. Next to the USB port, there is an on-board user LED that
can be used during program development. Next to this LED there is a button named as
BOOTSEL that is used during programming of the microcontroller as we will see in the next
chapters. Next to the processor chip, there are 3 holes where external connections can be
made to. These are used to debug your programs using Serial Wire Debug (SWD). At the
other edge of the board is the single-band 2.4 GHz Wi-Fi module (802.11n). Next to the
Wi-Fi module is the on-board antenna.
You will notice the following types of letters and numbers at the back of the board:
Some of the GPIO pins are used for internal board functions. These are:
● 274
Pico GPIO hardware is +3.3 V compatible, and it is therefore important to be careful not
to exceed this voltage when interfacing external input devices to the GPIO pins. +5 V to
+3.3 V logic converter circuits or resistive potential divider circuits must be used if it is
required to interface devices with +5 V outputs to the Pico GPIO pins.
Pico can be programmed using MicroPython or C/C++ languages. It is assumed that the
readers have Pico development boards with the MicroPython installed. It will also be useful
if the readers are familiar using Thonny with the Pico. A book entitled Raspberry Pi Pico W
and written by the author is available from Elektor and interested readers might consider
purchasing this book for developing Pico-based projects.
● 275
Block diagram: Figure 14.25 shows the block diagram of the project.
● 276
Circuit diagram: The circuit diagram of the project is shown in Figure 14.26 with the but-
ton and relay connected to the Pico and Raspberry Pi respectively.
Pico program listing: Figure 14.27 shows the Pico program listing (picoudp.py). At the
beginning of the program, LED is assigned to port GP2 and is turned OFF. The Function
Connect() is called to connect to the local Wi-Fi network. Then, a socket is created with
port number 2000 and IP address 192.168.3.21. When the Button is pressed, the program
sends 1 to the Raspberry Pi 5 so that the LED can be turned ON. This process is repeated
after a 1-second delay.
● 277
#----------------------------------------------------------
# RASPBERRY PI PICO W - RASPBERRY PI 5 COMMS
# ==========================================
#
# In this project a pushbutton is connected to GP2 of PICO W.
# Presingthe button sends a command to Raspberry Pi 5 to
# activate a relay. UDP protocol is used in this project
#
# Author: Dogan Ibrahim
# File : picoudp.py
# Date : October, 2023
#------------------------------------------------------------
from machine import Pin
import network
import socket
import utime
global wlan
#
# This function attempts to connect to Wi-Fi
#
def connect():
global wlan
wlan = network.WLAN(network.STA_IF)
while wlan.isconnected() == False:
print("Waiting to be connected")
wlan.active(True)
wlan.connect("TP-Link_6138_EXT", "24844604")
utime.sleep(5)
connect()
print("Connected")
UDP_PORT = 2000 # Port used
UDP_IP = "192.168.3.21" # Zero 2W IP
cmd = b"1" # Cmd to turn ON
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
while True:
while BUTTON.value() == 1: # Not pressed
pass
while BUTTON.value() == 0: # Not released
pass
sock.sendto(cmd, (UDP_IP, UDP_PORT)) # Send cmd
print("Command sent") # Message
utime.sleep(1) Wait 1 sec
● 278
Raspberry Pi 5 program listing: Figure 14.28 shows the Raspberry Pi 5 program listing
(RPiudp.py). At the beginning of the program the libraries used are imported, the relay
control output is configured at port GPIO 2 and is deactivated. Then a socket is created, and
the program binds to it with the Raspberry Pi 5 address. The program then waits to receive
a command from the Pico. The received command is stored in variable data and if it is 1,
then the relay is activated for 5 seconds. At the end of this time, the relay is deactivated
and the program repeats waiting for a command.
#=============================================================
# RASPBERRY PI PICO W - RASPBERRY PI 5 COMMS
# ==========================================
#
# This is the UDP server program running on Raspberry Pi 5.
# The program receives a command from PICO W and activates a
# relay connected to GPIO 2 for 5 seconds
#
# Author: Dogan Ibrahim
# File : RPiudp.py
# Date : October, 2023
#============================================================
from gpiozero import LED
import socket
from time import sleep
try:
while True:
data, addr = sock.recvfrom(1024) # GEt command
if data == b'1': # Command is 1?
RELAY.on() # Activate Relay
sleep(5) # 5 seconds delay
RELAY.off() # Deactivate Relay
● 279
• Run the Pico program in Thonny by clicking the green Run button. You should
see the message Connected when Pico connects to the local router.
• Push the button on Pico. The message Command sent will be displayed on Pico
terminal. A packet will be sent to Raspberry Pi 5 which will turn ON the LED for
5 seconds
Block diagram: The block diagram of the project is shown in Figure 14.29.
Circuit diagram: Figure 14.30 shows the circuit diagram. SCL and SDA pins of BME280
are connected to SDA (pin 3) and SCL (pin 5) of Raspberry Pi 5. The sensor is powered
from +3.3 V.
● 280
The Cloud
There are several cloud services that can be used to store data (for example SparkFun,
ThingSpeak, Cloudino, Bluemix etc.). In this project, the Thingspeak is used. This
is a free cloud service where sensor data can be stored and retrieved using simple HTTP
requests. Before using the Thingspeak we have to create an account on their website and
then log in to this account.
https://thingspeak.com/
Click Get Started For Free and create an account if you don't already have one. Then,
you should create a New Channel by clicking on New Channel. Fill in the form as shown
in Figure 14.31. Give the name Raspberry Pi 5 to the application, give a description, and
create two fields called Atmospheric Pressure and Temperature. You can optionally fill
in the other items as well if you wish.
Figure 14.31 Create a New Channel (only part of the form shown)
● 281
Click Save Channel at the bottom of the form. Your channel is now ready to be used with
your data. You will now see tabs with the following names. You can click on these tabs and
see the contents to make corrections if necessary:
• Private View: This tab displays private information about your channel where
only you can see.
• Public View: If your channel is public, use this tab to display selected fields and
channel visualizations.
• Channel Settings: This tab shows all the channel options you set at creation.
You can edit, clear, or delete the channel from this tab.
• API Keys: This tab displays your channel API keys. Use the keys to read from
and write to your channel.
• Data Import/Export: This tab enables you to import and export channel data.
You should click the API Keys tab and save your unique Write API and Read API keys
and unique Channel ID in a safe place, as you will need to use them in our program. The
API Keys and the Channel ID in this project were as in Figure 14.32.
Also, select the Public View and navigate to Sharing. You may select the option Share
channel view with everyone so that everyone can access your data remotely.
Program listing: In this program you will be using the BME280 library as in Chapter 10.6.
The steps to install the library are not repeated here.
After constructing the circuit, you should check to make sure that the BME280 is detected
by the Raspberry Pi 5. Enter the following command:
● 282
You should see the hardware address of the BME280 chip displayed as 76 (see Figure 14.33).
Figure 14.34 shows the program listing (Cloud.py). At the beginning of the program, the
libraries used are imported to the program. Thingspeak Write Key and Host Address are
defined. The main program loop starts with the while statement. Inside this loop, the IP
address of the Thingspeak website is extracted, and a connection is made to this site at
port 80. Then the atmospheric pressure and temperature readings are obtained from the
BMP280 module and are included in the path statement. The sock.send statement sends
an HTTP GET request to the ThingSpeak site and uploads the pressure and temperature
values. This process is repeated every 30 seconds.
Figure 14.35 shows the pressure and temperature data plotted by ThingSpeak. The Chart
Options can be clicked to change various parameters of the charts. For example, Fig-
ure 14.36 shows the temperature as a column display. In Figure 14.37 the pressure is
shown as a step graph. A title and X-axis label is added in Figure 14.38 to the pressure
graph. Figure 14.39 shows the current temperature displayed in a clock format (click Add
Widgets for this type of display). Figure 14.40 shows the current temperature in digital
format.
Because the Channel was saved as Public, you can view the graph from a web browser (see
Figure 14.41) by entering the Channel ID. In this project, the link to view the data graphs
from a web browser is:
https://api.thingspeak.com/channels/2304635
We can also export some or all of the fields in CSV format by clicking Export recent data
so that it can be analysed by external statistical packages such as Excel.
#-----------------------------------------------------------------------------
# ATMOSPHERIC PRESSURE AND TEMPERATURE ON THE CLOUD
# =================================================
#
# The ambient temperature and pressure sensor BMPE280 is connected to Raspberry
# Pi 5.The project reads the temperature and atmospheric pressure and sends
● 283
#
# Send data to Thingspeak. This function sends the temperature and
# humidity data to the cloud every 30 seconds
#
while True:
sock = socket.socket()
addr = socket.getaddrinfo("api.thingspeak.com",80)[0][-1]
sock.connect(addr)
data = sensor.get_data()
p = data['pressure'] # Pressure in haP
t = data['temperature'] # Temperature in C
path = "api_key="+APIKEY+"&field1="+str(p)+"&field2="+str(t)
sock.send(bytes("GET /update?%s HTTP/1.0\r\nHost: %s\r\n\r\n"
%(path,host),"utf8"))
sleep(5)
sock.close()
sleep(25)
● 284
● 285
● 286
● 287
15.1 Overview
In the last chapter, you have learned how to write programs to use the Wi-Fi and communi-
cate with other devices over the LAN using the UDP and TCP protocols. In this chapter, you
will develop programs for using the Bluetooth communication.
Raspberry Pi 5 supports both the Classic Bluetooth and Bluetooth Low Energy (BLE). BLE
is intended for reduced power applications while providing reasonable range. Most smart-
phones, including Android, iOS, Windows Phone, Blackberry, macOS and many others sup-
port the BLE. BLE uses the same 2.4 GHz radio frequency as the classic Bluetooth and
dual-mode devices, therefore can share the same single antenna. Classical Bluetooth can
handle large amounts of data quickly, whereas BLE has been developed to handle smaller
amounts of data.
Block diagram: Figure 15.1 shows the block diagram of the project.
● 288
Enabling Bluetooth
Before using your smartphone for Bluetooth applications, you must enable the Bluetooth
on it. Depending on the model of the smartphone you have, this is usually done from the
Settings menu.
Similarly, before using Bluetooth on your Raspberry Pi, you must enable it. There are two
ways you can enable Bluetooth on the Raspberry Pi 5: using the graphical desktop (GUI
mode), or using the Console mode.
• If you have a monitor connected directly to the Raspberry Pi 5 then skip the
next line
• Start the VNC server on your Raspberry Pi 5 and login using the VNC Viewer.
• Click on the blue Bluetooth icon on your Raspberry Pi 5 screen at the top right-
hand side, and turn Bluetooth ON, if it is not already ON. Then, select Make
Discoverable. You should see the Bluetooth icon flashing. Click Add Device
• You should now see the message Pairing Successfully on your Raspberry Pi 5
● 289
• Find the Bluetooth MAC address of your smartphone. For Android phones, the
steps are usually:
• Scroll down to see your Bluetooth address (e.g. Figure 15.3). In this
example, the MAC address was 50:50:A4:0F:62:3F
• Start the Bluetooth tool on your Raspberry Pi 5 from the command mode:
pi@raspberrypi:~ $ bluetoothctl
● 290
[bluetooth]# power on
[bluetooth]# agent on
[bluetooth]# default-agent
[bluetooth]# discoverable on
• Scan for nearby Bluetooth devices, you may have to wait several minutes:
[bluetooth]# scan on
• Enter command devices to see the nearby Bluetooth devices (see Figure 15.4).
You may have to wait a couple of minutes for the display to update. Make a
note of the MAC address of the device you wish to connect to (Android mobile
phone in this project) as we will be using this address to connect to the device.
An example is shown in Figure 15.4:
[Bluetooth]# devices
In this example, the author's smartphone is Galaxy A71 and the Bluetooth
MAC address is: 50:50:A4:0F:62:3F
● 291
You can find the Bluetooth MAC address of your Raspberry Pi 5 by entering the following
command:
You can change the Bluetooth broadcast name by the following command:
• Add –C at the end of the ExecStart= line. Also add another line after the
ExecStart line. The final two lines should look like:
ExecStart=/usr/libexec/bluetooth/bluetoothd -C
ExecStartPost=/usr/bin/sdptool add SP
● 292
Program listing: Figure 15.5 shows the program listing (bluetxt.py). Do not call your
program Bluetooth.py! The Bluetooth code is similar to TCP/IP code. At the beginning of
the program, modules socket, and Bluetooth are imported to the program. The program
then creates a Bluetooth socket, binds and listens on this socket, and then waits to accept
a connection. The remainder of the program is executed in a loop, where the program
issues the statement ClientSock.recv and waits to read data from the smartphone. The
received data is decoded and displayed on the screen. The user is then expected to send a
text message to the smartphone. This message is displayed on the smartphone's screen.
This process is repeated until stopped by the user.
#=======================================================
# BLUETOOTH COMMUNICATION
# =======================
#
# In this project text messages are exchanged with a smart
# phone using the Bluetooth protocol
#
# Author: Dogan Ibrahim
# File : bluetxt.py
# Date : October, 2023
#========================================================
import socket
import bluetooth
#
# Start of main program loop.Configure Bluetooth, create a
# port, listen for client connections, and accept connection
#
port = 1
ServerSock = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
ServerSock.bind(("", port))
ServerSock.listen(1)
ClientSock, addr = ServerSock.accept()
#
# Now receive text from smart phone and display
#
try:
while True:
data = ClientSock.recv(1024) # receive text
print("Received data: ", data.decode('utf-8'))
● 293
Testing
The project can be tested by the following steps:
• Make sure that Bluetooth is enabled on both the smartphone and Raspberry
Pi 5 and they are paired
• You can use the freely available Bluetooth apps on our smartphone to
communicate with the Raspberry Pi 5. In this project, the apps called
Bluetooth Terminal HC05 by mightyIT is used (Figure 15.6)
• Start the smartphone apps and select the paired Raspberry Pi 5 device (e.g.
raspberrypi)
• Enter a message in column Enter ASCII Command and press Send ASCII.
The message will be sent to the Raspberry Pi 5.
● 294
The following commands can be sent from the Android smartphone to control the LED:
Block diagram: Figure 15.8 shows the block diagram of the project.
● 295
Program Listing: Figure 15.9 shows the program listing of the project (blueled.py, do
not call your program Bluetooth.py!). The Bluetooth code is similar to TCP/IP code. The
LED port is defined and configured as output through the gpiozero module. The program
then creates a Bluetooth socket, binds and listens on this socket, and then waits to accept a
connection. The remainder of the program is executed in a loop, where the program issues
the statement ClientSock.recv and waits to read data from the smartphone. Note that
the smartphone app automatically appends carriage-return and line-feed characters to the
end of the data (i.e. \r\n)
#=======================================================
# LED CONTROL BY BLUETOOTH
# ========================
#
# In this project an LED is connected to GPIO 21.The LED
# LED is controlled by sending commands from an Android
# smart phone using a Bluetooth apps.
#
# Valid commands are:
# L1 Turn ON the LED
# L0 Turn OFF the LED
#
# Author: Dogan Ibrahim
# File : blueled.py
# Date : October, 2023
#========================================================
import socket
import bluetooth
from gpiozero import LED
#
# LED is at GPIO 21, configure as output and turn OFF
#
led = LED(21) # LED at port 21
led.off() # LED off
#
# Start of main program loop.Configure Bluetooth, create a
# port, listen for client connections, and accept connection
#
port = 1
ServerSock = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
ServerSock.bind(("", port))
ServerSock.listen(1)
ClientSock, addr = ServerSock.accept()
● 296
while True:
data = ClientSock.recv(1024) # receive command
if data == b'L1\r\n': # L1?
led.on() # turn ON LED
elif data == b'L0\r\n': # L0?
led.off() # turn OFF LED
Testing
The same Android app as in the previous project is used. The steps are:
• Make sure that the Bluetooth is enabled on both the smartphone and Raspberry
Pi 5 and that they are already paired
• Start the apps as before. To send command L1, enter L1 and click Send
ASCII. The LED should turn ON.
When you finish your project, don't forget to remove the above line from file /etc/rc.lo-
cal; otherwise the program will run every time your Raspberry Pi 5 is restarted. You should
also shut down your Raspberry Pi 5 orderly instead of just removing the power cable. The
command to shut down orderly is:
● 297
velop a project and learn how to connect a HC-06 type low-cost Bluetooth module to your
Arduino UNO and communicate with the Raspberry Pi 5.
• +3.3 V to +6 V operation
• 30 mA unpaired current (10 mA matched current)
• Built-in antenna
• Band: 2.40 GHz – 2.48 GHz
• Power level: +6 dBm
• Default communication: 9600 baud, 8 data bits, no parity, 1 stop bit
• Signal coverage: 30 feet
• Safety feature: Authentication and encryption
• Modulation mode: Gauss frequency shift keying
Block diagram: Figure 15.11 shows the block diagram of the project.
Circuit diagram: The circuit diagram is shown in Figure 15.12. The button is connected to
pin 2 of Arduino UNO through a pull-up resistor. The relay is connected to port GPIO 21 of
the Raspberry Pi 5. HC-06 is a serial device with TX and RX pins. Only the RX input of the
HC-06 is used, since in this project you only send data to the Bluetooth module. The output
pin voltage of the Arduino UNO is +5 V, but HC-06 is not 5-V compatible. Therefore, a resis-
● 298
tive voltage divider circuit is used to lower the Arduino voltage to +3.3 V. TX pin of HC-06 is
connected to pin 3 of Arduino UNO (pin 3 is configured as a software serial port in software)
• Construct the Arduino circuit (Figure 15.12) and apply power so that HC-06 can
be accessible. The red LED on HC-06 will be flashing to indicate that it is not
currently connected to any device.
pi@raspberrypi:~ $ bluetoothctl
[bluetooth]# power on
[bluetooth]# agent on
[bluetooth]# default-agent
[bluetooth]# discoverable on
• Scan for nearby Bluetooth devices, you may have to wait several minutes:
[bluetooth]# scan on
● 299
• Enter command devices to see the nearby Bluetooth devices. You may have to
wait several minutes for the display to update. You should see the HC-06 listed
with its MAC address.
[Bluetooth]# devices
In this example, the author's HC-06 was identified with the MAC address:
98:D3:91:F9:6C:19
• After finding its MAC address, you may get information about the HC-06 by
entering the following command:
Exit the Bluetooth tool by entering Ctrl+Z and then enter the following statement to make
a connection in command mode (enter your own HC-06 MAC address):
You should be connected now and the red LED on HC-06 should stop flashing. You are now
ready to develop your programs for the Arduino UNO and Raspberry Pi 5.
● 300
Serial port /dev/rfcomm0 is opened with the baud rate set to 9600 (default baud rate of
HC-06 is 9600) using the following statement:
data = ser.read()
If the received data is b'1' then the relay is activated for 5 seconds by the following state-
ments:
RELAY.on()
sleep(5)
RELAY.off()
#=======================================================
# RELAY CONTROL BY BLUETOOTH
# ==========================
#
# In this project a Relay is connected to GPIO 21.The
# Relay is controlled by sending command from an Arduino
# Uno using a Bluetooth apps.
#
# Valid command is: «1»
#
# Author: Dogan Ibrahim
# File : zeroprog.py
# Date : October, 2023
#========================================================
import serial
from time import sleep
from gpiozero import LED
#
# Relay is on GPIO 21, configure as output and turn OFF
#
RELAY = LED(21) # Relay at port 21
RELAY.off() # Relay off
#
# Attach to virtual serial port /dev/rfcomm0
#
ser = serial.Serial(port='/dev/rfcomm0', baudrate=9600)
● 301
while True:
data = ser.read() # receive comman
if data == b'1': # 1?
RELAY.on() # activate Relay
sleep(5) # 5 seconds
RELAY.off() # Relay OFF
Arduino UNO program: Figure 15.15 shows the Arduino Uno program (ardprog). A soft-
ware serial port is used in this program, where pin 3 is configured as the TX pin and pin 4
as the RX pin (RX is not used in this project). Button is then assigned to port 2. Inside the
setup() function, serial port baud rate is set to 9600 and Button is configured as an input
pin. Inside the main program loop, the program waits until the button is pressed and then
released. '1' is then sent to the HC-06, where Raspberry Pi 5 will turn ON the relay when
it receives this command.
/*================================================
ARDUINO UNO - RASPBERRY PI 5
============================
void setup()
{
MySerial.begin(9600); // Baud rate
pinMode(Button, INPUT); // Button is input
● 302
//
// MAin program looop
//
void loop()
{
while (digitalRead(Button) == 1); // Button not pressed
while (digitalRead(Button) == 0); // Button not released
MySerial.print("1"); // Send "1"
delay(1000);
}
Testing
• Press and release the button. The relay should turn ON for 5 seconds
Before you can send audio to a Bluetooth speaker, you have to have a program on the
Raspberry Pi 5 that can play audio files (e.g. MP3 files). In this project, we will be using the
popular VLC Media Player program on the Raspberry Pi 5. The steps to install VLC are:
• Wait until the VLC program is installed. You need to have MP3 files to test
the project. Download or copy some of your favourite MP3 music files to your
Raspberry Pi 5 (e.g. to the default home directory /home/pi or to a newly
created directory).
You now have to pair with the Bluetooth speaker and connect to it. We will do this from the
Desktop. The steps are:
● 303
• Click the Bluetooth icon at the top right-hand corner of Desktop and select to
turn ON Bluetooth
• Click on the Bluetooth icon and click Add Device to pair and add your
speaker, or if your speaker is already listed then click on it and click to Connect
(in the author's example, the Bluetooth speaker had the name BT-888). See
Figure 15.15.
• We are now connected to the speaker. The next thing to do is to direct our
audio output to the speaker. Right-click on the Volume icon at the top right-
hand corner of the Desktop and select your Bluetooth speaker name (e.g. BT-
888 in the author's case).
• Click Media → Quit to stop playing the music and exit from VLC.
Suggestion: You can create a Play List using the VLC Media Player and store your favourite
music files in this list. You can then play the list.
● 304
16.1 Overview
In this chapter, you will be developing various camera projects using the Raspberry Pi 5.
The early sections of the chapter describe how to install and use the camera in still picture
mode. In later sections, you will develop more interesting camera-based projects using the
Python programming language.
There are several Raspberry Pi camera modules. Version 1 was released in 2013, and it was
a 5-megapixel model, which is not available anymore from Raspberry Pi. This was followed
by Version 2, which was 8-megapixels and was released in 2016. The latest model Ver-
sion 3 has 12 megapixels and was released in 2023. Additionally, 12-megapixel high-qual-
ity cameras for use with external lenses with CS or M12 type mounting were released in
2020 and 2023 respectively. Raspberry Pi cameras are available as either visible-light-type
or infrared-type for night vision. All cameras can take high-resolution pictures along with
HD 1080p video, and they can all be controlled by software. See the following link for fur-
ther information on Raspberry Pi cameras:
ttps://www.raspberrypi.com/documentation/accessories/
h
camera.html#about-the-camera-modules
Note: The Raspberry Pi 5 camera socket is a 15-pin socket, where most of the Rasp-
berry Pi cameras have 22 pins. It may therefore be necessary to purchase a 15-pin to
22-pin cable to connect your camera to the Raspberry Pi 5 (see Figure 16.1).
● 305
• Pull up the plastic cable holder slider of the camera port gently by holding from
both ends. The cable holder slider will open
• Insert the 15-pin camera ribbon cable (with the connector side facing the white
side of the connector) into the cable holder
• Push down the plastic cable holder slider so that it locks and holds the cable
You should now be able to test your camera interface and carry out camera operations to
capture still images and video frames. Notice that you must be in Desktop GUI mode with a
monitor directly attached to Raspberry Pi 5 through the micro-HDMI cable to use the cam-
era. The author had problems using the camera remotely using his PC even though he was
in Desktop GUI mode. Also, the old camera commands raspistill, raspiyuv, raspivid, and
raspividyuv are now obsolete and cannot be used with the Raspberry Pi 5.
16.3.1 libcamera
libcamera is the new camera software which supports the four Raspberry Pi cameras:
V1: OV5647, V2: IMX219, V3: IMX708, and third-party sensors such as IMX290, IMX327,
OV9281, IMX378. The following libcamera commands are supported:
libcamera-hello: this command starts a camera preview and displays it on the screen for
5 seconds
libcamera-still: this is a more complex still camera command which emulates features of
the original old raspistill command
libcamera-raw: this command captures raw (unprocessed) frames directly from the cam-
era sensor
libcamera-hello: This command starts the camera and displays a preview window for
5 seconds. The –t <duration> option enables the user to select for how long the window
should be displayed, where <duration> is in milliseconds. For example, the following acti-
● 306
libcamera-hello –t 10000
libcamera-hello –t 0
Options
The following website displays all the options:
ttps://www.raspberrypi.com/documentation/computers/
h
camera_software.html#common-command-line-options
The options are in 3 groups: common options, still camera options, and video options.
Some options are:
Common options:
--help display help information
--version display the software version
--list-cameras list the cameras available for use
--camera select a camera to use
--config –c <filename> read camera options from file <filename>
--preview (--p) preview window settings <x,y,w,h>
--fullscreen (or --f) fullscreen preview
--n suppress the preview. This is very useful for quickly tak-
ing
images without preview
--info-text set window title bar to <text>
--shutter set the exposure time in microseconds
--awb set the AWB mode
--output specify the output filename to save the image
--o same as above
● 307
--encoding (or --e) set the image encoding (jpg, png, bmp, rgb, yuv420)
--raw (or --r) save raw file
Video options:
--quality (or --q) JPEG quality
--bitrate (or --b) H.264 bitrate
--codec encoder to use (h264, mjpeg, yuv420, libav)
--keypress (--k) toggle between recording and pausing
--split split multiple recordings into separate files
libcamera-hello --list
Figure 16.2 shows the available cameras.
● 308
Notice that there are several menu options when the image is displayed. Selecting the Edit
menu option, you can copy, flip horizontal, flip vertical, rotate clockwise, rotate anti-clock-
wise, etc. Selecting the View option, you can see in full screen, do a slideshow, zoom in,
zoom out, etc. Selecting the Go option, you can see the previous or the next image, or the
last image etc.
libcamera-jpeg –o test.jpg –t 5000 --width 640 --height 480 will display the preview
for 5 seconds, save the image in file test.jpg where the image will be in VGA format
libcamera-jpeg –o test.jpg –t 3000 --shutter 20000 --gain 1.5 will display the pre-
view for 3 seconds, set the shutter speed to 20 ms and gain to 1.5x
libcamera-still is similar to libcamera-jpeg, but it supports more of the legacy raspistill op-
tions. Some examples are:
libcamera-still –e bmp –o test.bmp saves the file as BMP format in file test.bmp
Required Commands: In time-lapse camera sessions, you usually have to store large
number of pictures taken at regular intervals. Before doing this, you have to know the size
of a picture, how often the pictures will be taken, and the space available on your storage
device (e.g. the Raspberry Pi SD card). The author has taken a number of 3280 × 2434
(8 megapixel) pictures of the same environment at different quality levels using the follow-
ing command:
● 309
Quality level (-q setting) Exact File size (bytes) Approximate file size (MB)
100 4,799,812 4.8
50 4,149,210 4.2
25 2,484,031 2.5
10 739,408 0.74
5 281,971 0.3
It was observed by the author that there was not much noticeable change in the visible
quality of the images at different quality levels. It is therefore recommended to take the
picture at say 10% quality level (option –q 10) where the size of a file is around 0.74 MB.
If f is how often we want to capture the images in minutes, and d is the total duration of
the capturing process in minutes, then the required storage is, s = 0.74d/f MB. During
this period, n = d/f images will be taken and also n files will be created. As an example, if
we want to capture images every minute for the duration of 10 minutes, then the required
storage will be s = 0.74 × 10/1 = 7.4 MB and 9 images will be taken with 9 files created.
The required commands to start the time-lapse in this project are as follows. Images will
be taken every minute for the duration of 10 minutes. A directory called mypics is created
and all the created image files are stored in this directory with the filenames starting with
Mypics and including a four-digit ascending number:
Figure 16.4 shows the files created in directory mypics. The image files are created with
the names such as Mypics0000.jpg, Mypics0001.jpg, Mypics0002.jpg, … etc.
pi@raspberrypi:~/mypics $ ls
Mypics0000.jpg Mypics0002.jpg Mypics0004.jpg Mypics0006.jpg Mypics0008.jpg
Mypics0001.jpg Mypics0003.jpg Mypics0005.jpg Mypicd0007.jpg
pi@raspberrypi:~/mypics $ ls
After all the still JPEG files have been created, you may want to join the files together and
create a video file. This can be done in several ways. In this section, we shall be using the
software called ffmpeg which is already installed on Raspberry Pi 5.
Now we can join our JPEG files together into a video file. Enter the following commands to
move to the directory where the files are, and then join the still image files to create the
video file Mytimelapse.mp4:
● 310
pi@raspberrypi:~ $ cd mypics
The above command takes all the input images, -i Mypics%04d.jpg. This will search
for the image with the lowest digit and sets that as the starting image. It will then incre-
ment that number by one and if the image exists, it will be added to the sequence. Option
-framerate 1 is used to define how fast the pictures are read in, in this case, one picture
per second. Omitting the frame rate will default to 25. -r 30 is the frame rate of the output
video. Again, if it defaults to 25 if not defined. The -c:v libx264 specifies the codec to use
to encode the video. x264 is a library used for encoding video streams into the H.264/
MPEG-4 AVC compression format.
You can play the output video (Mytimelapse.mp4) file by double-clicking on it and se-
lecting the VLC media player in your Desktop GUI. You can, if you wish, copy the created
video file to your PC after installing and using the file copy software called winSCP on your
PC. After the file is copied to your PC, you can play it using various video player software:
With the command crontab you can specify a list of tasks to be scheduled at specified
times of the day, and at specified days of the week. You should run crontab by entering the
following command:
pi@raspberrypi:~ $ crontab –e
The first time you run crontab you should be asked to select an editor. Select nano (op-
tion 1) as this is the easiest editor to use. crontab consists of six components for minutes,
hours, day of the month, month of the year, day of the week, and the command to be ex-
ecuted, organized as shown in Figure 16.5.
● 311
Some examples are given below (notice that you must give the full path to the script file):
As well as single numbers for each of the first 5 parameters, you can also use the following
special formats:
The crontab generator utility helps to generate a crontab table for the specified sched-
uling times. This utility can be accessed from the following website on your PC:
https://crontab-generator.org/
An example use of the crontab generator utility is shown in Figure 16.6 where the utility
is used to set the scheduling time to be every 5 minutes. The script file is set to /home/
pi/test.sh, which should be entered in the field Command to Execute at the lower part
of the screen. Then, click Generate Crontab Line. The required crontab command and
sample times that the script will run at are shown at the top of the crontab generator as
shown in Figure 16.7.
● 312
Figure 16.6 crontab generator utility set to one minute past every hour
Now, going back to our project, we wish to run a script file every minute to capture still im-
ages. The script is given the filename timelapse.sh. The crontab command for this project
should be as follows:
Notice that 2>&1 at the end of the script ensures that email messages are not sent after
the command is executed. Here, we redirect 2 (stderr) to 1 (stdout) and since the output
is redirected to a file, it will not generate emails of outputs. Exit from the crontab table by
pressing Ctrl followed by Y and return to save the new file.
The scheduled tasks can be listed with the following command. Enter the command, and
you should see your script file scheduled to run:
pi@raspberrypi:~ $ crontab –l
● 313
Next, we have to create the script file timelapse.sh in the folder mypics. This can be done
using the nano editor. The steps are:
• Enter the following lines into the blank file. Variable DATETIME will extract the
current data and time every time (every minute) the script runs. Date and
time-stamped images will then be taken and stored in files with extensions
.jpg. The images will be captured with 10% resolution (-q 10):
DATETIME=$(date +"%d-%m-%Y_%H%M%S")
libcamera-jpeg –q 10 –o /home/pi/mypics/$DATETIME.jpg
• Exit from the nano editor by pressing Ctrl X followed by Y and return to save
• Display the contents of the file to make sure that you have the correct lines in
the file:
• Make sure that your script file runs correctly. Enter the command: sh
timelapse.sh
• and you should see a new JPEG file with the filename containing the date and
time.
• You should now reboot your Raspberry Pi 5. The still images will be taken every
minute after your Raspberry Pi 5 starts. After taking all the necessary images,
don't forget to edit the crontab table and remove the timelapse.sh entry. Then
reboot your Raspberry Pi 5 (pi@raspberrypi:~/mypics $ sudo reboot) so that
no more images will be taken.
• Check folder mypics to make sure that you have the image files. You can use
the following command to list the files in the folder:
pi@raspberrypi:~/mypics $ ls
• After collecting all your images, you may want to join all the image files
together and create a video file as described earlier.
● 314
Video is recorded as raw H264 format, which is incompatible with many video players. The
resulting file can be played using the VLC media player program.
Note that this is an unpacked video bit stream, it is not wrapped in any kind of container
format (such as an MP4 file). The --save-pts option can be used to output frame times-
tamps so that the bit stream can subsequently be converted into an appropriate format
using a tool like mkvmerge.
Block Diagram: Figure 16.8 shows the block diagram of the project.
● 315
Circuit Diagram: The circuit diagram of the project is shown in Figure 16.9. The doorbell
button and the relay are connected to port pins GPIO 20 and GPIO 21 respectively.
Program listing: In this program, you will be using the OBEX Object Push in Raspberry
Pi 5 command mode to send pictures to your smartphone using Bluetooth. Before using
OBEX Object Push, you have to find out the MAC address and the channel number of your
smartphone. The steps on an Android phone are given below:
• You should see the Bluetooth MAC address listed. On the author's phone, the
MAC address was 50:50:A4:0F:62:3F, as shown in Figure 16.10
● 316
We now have to find the channel number for the Bluetooth communication. Enter the fol-
lowing command on your Raspberry Pi 5 and look for the channel number under section
Service Name: OBEX Object Push
Now, we have to install the OBEX software onto our Raspberry Pi 5. Enter the following
command:
We are now ready to develop our program (bell.py), which is shown in Figure 16.12. The
button and relay are initialized at the beginning of the program and os module is imported
since we want to run a shell command from within our Python program. The program then
enters an endless loop using the while statement. Inside this loop, the program waits until
the button is pressed. At this point, the camera takes a picture using a libcamera com-
mand and stores in a file called door.jpg. The relay is also activated for 5 seconds. The
picture is then sent to the smartphone using OBEX.
#------------------------------------------------------------------
#
# WHO IS AT MY DOOR
# =================
#
# In this program a camera, aa pushbutton switch and a relay are all
# connected to Raspberry Pi 5. The camera is positioned outside the
# door so that it can see whos is outside the door.Pressing the button
# activates the relay for 5 seconds and then takes a picture of the
# person outside the door and sends it to a smart phone over Bluetooth.
#
# Program: bell.py
# Date : October, 2023
● 317
while True:
sleep(1)
if button.is_pressed: # If button
relay.on() # Relay on for 5 secs
sleep(5)
relay.off()
os.system("obexftp --nopath --uuid none --noconn --bluetooth
50:50:A4:0F:62:3F --channel 12 -p door.jpg")
else:
relay.off()
Figure 16.13 shows how the program is run and its output on the screen. You should wait
for the file transfer to complete, since it may take some time. A confirmation message is
sent to the smartphone before the file transfer takes place. You should click the ACCEPT
button to receive the picture as shown in Figure 16.14.
● 318
● 319
● 320
M SCL 141
Matplotlib 176 Seconds counter 142
Melody maker 173 Security lock 252
Meminfo 32 Sense Hat 219
MIPI 14 Shutdown 22, 46
Morse code 132 Sine 99
Mv 41 Sine graph 179
Sine wave 215
N Sort 41
Nano 56 SPI bus 205
Netstat 266 SSD 14
Numbers 72 SSH 20
Static IP 24
O Strings 75
On-off temperature control 228 String functions 76
Operators 73 Super user 43
OS 15
Overdampled mode 195 T
T-cobbler 121
P TCP 256
Passwd 22, 33 Temperature sensor 156
PCIe 13 Terminal 54
Pie chart 185 Terminus 19
Plotting graphs 176 ThingSpeak 281
Potential divider 91 Thonny 66
Preferences 53 Tightvnc 23
Putty 20 Tightvncserver 23
Python 65 Tmp36 157
Top 44
R Triangle wave 211
Randint 103 Trigonometric functions 93
Random 74 Try 109
Raspberry Pi imager 28 Tuple variables 80
RC transient charging 189 Two dice numbers 233
RC transient discharging 191
Reaction timer 161 U
Recursive functions 106 UDP 256
Rename 41 Ultrasonic distance measurement 167
Reserved words 70 Uname 32, 48
RL transient 194 Up counter 240
Rmdir 42 Upgrade 33
Rotating LEDs 128 USB-C 13
User defined functions 93
S
Sawtooth wave 209 V
SCA 141 Variable names 69
● 321
Vi 61
VNC 23
Voltmeter 149
Volume control 55
W
While statement 85
WiFi 256
Wired network 26
Wireless LAN 29
● 322
Raspberry Pi 5
Essentials Raspberry Pi 5
Program, build, and master over 60 projects
Essentials
B u s = 0 , device=0
The Raspberry Pi 5 is the latest single-board computer from the Raspberry Pi
Program,) build, and master over 60 projects
#
spi.open(0, 0
Foundation. It can be used in many applications, such as in audio and
with
0000Python
0
video media centers, as a desktop computer, in industrial controllers,
robotics, and in many domestic and commercial applications. In addition
p e e d _ h z = 3 9
_s
spi.max
Prof Dogan Ibrahim has a BSc
to the well-established features found in other Raspberry Pi computers, (Hons) degree in Electronic
R I E D output
S
# GPIO26 is C
the Raspberry Pi 5 offers Wi-Fi and Bluetooth (classic and BLE), which Engineering, an MSc degree in
ED •
T
Automatic Control Engineering,
makes it a perfect match for IoT as well as in remote and Internet-based
CS = LED(26)
and a PhD degree in Digital Signal
• T
# Disable CESS T
control and monitoring applications. It is now possible to develop many Processing and Microprocessors.
real-time projects such as audio digital signal processing, real-time digital
CS.on()
filtering, real-time digital control and monitoring, and many other real-time Dogan has worked in many
operations using this tiny powerhouse. organizations and is a Fellow of
the Institution of Engineering
ta in „d
and Technology (IET) in UK as
a
The book starts with an introduction to the Raspberry Pi 5 computer well as a Chartered Electrical
D A C . T h e d
ements the
and covers the important topics of accessing the computer locally and Engineer. He has authored over
remotely. Use of the console language commands as well as accessing 100 technical books and over
u n c t i o n i m p l
and using the desktop GUI are described with working examples. The 200 technical articles on electronics,
# This f
# to the DAC
microprocessors, microcontrollers,
remaining parts of the book cover many Raspberry Pi 5-based hardware
and related fields. Dogan is a
projects using components and devices such as certified Arduino professional and
has many years of experience with
> LEDs and buzzers numerous types of microprocessors
:
def DAC(data) # Enable CS
> LCDs and microcontrollers.
> Ultrasonic sensors
>
>
Temperature and atmospheric pressure sensors
The Sense HAT
CS.off()
> Camera modules
#
yte
Example projects are given using Wi-Fi and Bluetooth modules to send # Send HIGH b
and receive data from smartphones and PCs, and sending real-time
# # Get upper
8) & 0x0F
temperature and atmospheric pressure data to the cloud.
> 0
temp = ( d a t a > # OR with 0x3
All projects given in the book have been fully tested for correct operation.
0x30
Only basic programming and electronics experience are required to follow Elektor International Media
temp = temp + # Send to DAC
mp])
spi.xfer2([te
the projects. Brief descriptions, block diagrams, detailed circuit diagrams, www.elektor.com
and full Python program listings are given for all projects described.
Readers can find the program listings on the Elektor Store website,
www.elektor.com (search for: book title).
#
Dogan Ibrahim