C Programming On Raspberry Pi
C Programming On Raspberry Pi
books books
C Programming on
C Programming
Dogan Ibrahim
Dogan Ibrahim
an Elektor Publication
● This is an Elektor Publication. Elektor is the media brand of
Elektor International Media B.V.
78 York Street
London W1H 1DP, UK
Phone: (+44) (0)20 7692 8344
© Elektor International Media BV 2021
First published in the United Kingdom 2021
● 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 Licensing Agency Ltd, 90 Tottenham Court Road, London, England W1P 9HE.
Applications for the copyright holder's written permission to reproduce any part of this publication should be
addressed to the publishers. The publishers 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.
● ISBN: 978-3-89576-431-8
● EISBN: 978-3-89576-432-5
● EPUB: 978-3-89576-433-2
● Preface
The Raspberry Pi 4 is the latest credit-card sized computer that can be used in many
applications, such as audiovisual media centers, desktop computers, industrial control,
robotics, and many more domestic and commercial applications. In addition to the many
features found in other versions of Raspberry Pi, The Pi 4 also offers Wi-Fi and Bluetooth,
making it highly desirable in remote and internet-based control and monitoring applications.
The Raspberry Pi has traditionally been programmed using Python. Although Python is
a very powerful language, many programmers may not be familiar with using it. The C
language is probably the most commonly used programming languages. All embedded
microcontrollers can be programmed using the C language these days. The C language
is taught in all technical colleges and universities - almost all engineering students are
familiar with the use of this language in their projects.
This book is about using C with Raspberry Pi to develop various hardware-based projects.
Two of the most popular C libraries, wiringPi and pigpio are used.
The book starts with an introduction to the C language and most students and newcomers
will find this chapter invaluable. Many projects are provided in the book, including using
Wi-Fi and Bluetooth to establish communication with smartphones.
The book includes many sensors and hardware-based projects. Both wiringPi and pigpio
libraries are used in all projects. Complete program listings are given with full explanations.
All projects given in the book have been fully tested and work. The following sub-headings
are used in the projects where applicable:
• Project title
• Project description
• Aim of the project
• Block diagram
• Circuit diagram
• Program listing
wiringPi and pigpio program listings of all Raspberry Pi projects developed in the book are
available on the Elektor website. Readers can download and use these programs in their
projects. Alternatively, they can modify the supplied programs to suit their applications.
I hope readers find this book helpful and enjoy reading it.
●6
Table of Contents
Table of Contents
● Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
●7
C Programming on Raspberry Pi
3.2.17 ● Unions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
3.2.18 ● Pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
3.3 ● Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
●8
Table of Contents
Chapter 7 ● I2C Bus Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201
7.1 ● Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201
7.2 ● The I2C Bus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201
7.3 ● Project 1 – Port expander . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
7.4 ● Project 2 – EEPROM memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
7.5 ● Project 3 – TMP102 temperature display . . . . . . . . . . . . . . . . . . . . . . . . . . . 216
7.6 ● Project 4 – I2C LCD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
7.7 ● Project 5 – Using the pigpio library with I2C – TMP102 temperature display . . . 237
7.8 ● Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
●9
C Programming on Raspberry Pi
12.13 ● Support for other chips and add-on boards . . . . . . . . . . . . . . . . . . . . . . . 310
12.14 ● Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310
● 10
Table of Contents
● Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 374
● 11
C Programming on Raspberry Pi
1.1 ● Overview
In this chapter, we will learn how to install the latest operating system (Raspbian Buster)
on the Raspberry Pi 4. We will also learn the different ways that Python can be used to
develop applications. Notice the installation process given below applies to all Raspberry Pi
models unless otherwise specified.
Raspbian Buster is the latest operating system for the Raspberry Pi. This section provides
the steps necessary for installing this operating system on a new blank SD card, ready to
use with Raspberry Pi 4. You will need a micro SD card with a capacity of at least 8GB (16
GB is preferable) before installing the new operating system.
The steps to install the Raspbian Buster operating system are as follows:
• Download the Buster image to a folder on your PC (e.g. C:\RPIBuster) from the
following link by clicking the Download ZIP under section Raspbian Buster with
desktop and recommended software (see Figure 1.1). At the time of writing this
book, the file was called: 2020-02-13-raspbian-buster-full.img. You may have to
use the Windows 7Zip software to unzip the download due to some features not being
supported by older zip software.
https://www.raspberrypi.org/downloads/raspbian/
● 12
Chapter 1 ● Installing the Operating System on Raspberry Pi
• Put the blank micro SD card into the card slot of your computer. You may need an
adapter to do this.
• Download Etcher to your PC to flash the disk image. The link is (see Figure 1.2):
https://www.balena.io/etcher/
• Double click to open Etcher and then click Select image. Select the Raspbian Buster
file you downloaded and unzipped.
• Click Select target and select the micro SD card.
• Click Flash (see Figure 1.3). This may take several minutes, wait until it is finished.
The program will then validate and unmount the micro SD card. You can remove your
micro SD card after it is unmounted.
● 13
C Programming on Raspberry Pi
Your micro SD card now has been loaded with the Raspberry Pi operating system. The
various options now are as follows:
If you are making a direct connection to your Raspberry Pi using a monitor and keyboard,
just insert the SD card into the card slot and power-up your Raspberry Pi. After a short
while, you will be prompted to enter the login details. The default values are username: pi,
password: raspberry.
You can now start using your Raspberry Pi either in command mode or in desktop mode. If
you are in command mode, enter the following command to start the GUI mode:
pi@raspberrypi:~ $ startx
• Move down to Boot Options and press Enter to select (Figure 1.4).
• Select Desktop / CLI and then select Desktop Autologin to boot automatically into
GUI mode.
• Click OK and accept to reboot the system. The system will be in GUI mode next time
it reboots.
• You can change your selections to boot in command mode if you wish by selecting
Console in Boot Options.
You may now want to connect your Raspberry Pi to the internet either to access it remotely
from a PC or to use the internet. If your Raspberry Pi is equipped with an ethernet port
(e.g. Raspberry Pi 2/3/4), you can directly connect to your Wi-Fi router using an ethernet
cable. You can find the IP address of your connection by entering the command: ifconfig in
command mode.
Alternatively, you may want to connect your Raspberry Pi to Wi-Fi and access it remotely.
● 14
Chapter 1 ● Installing the Operating System on Raspberry Pi
• Move down to Interface Options and select SSH and enable it.
• If you are in GUI mode, click the Wi-Fi icon at the top right hand of the screen and
enable Wi-Fi. Note the IP address allocated automatically to your Raspberry Pi.
• You can now remotely access your Raspberry Pi using terminal emulation software,
such as Putty (see Section 1.4 and 1.5).
If you do not have a suitable monitor and keyboard to directly connect to your Raspberry Pi,
you will have to use a networked connection and remotely access your Raspberry Pi using a
PC. There are two options: connection using an Ethernet cable, and connection over
Wi-Fi.
https://notepad-plus-plus.org/downloads/v7.8.5/
https://www.advanced-ip-scanner.com
• Run the software and look for your Raspberry Pi. You do not have to install the software
to run it. Click Run portable version, and then Scan. As shown in Figure 1.5, the IP
address of the author’s Raspberry Pi was 191.168.1.202.
● 15
C Programming on Raspberry Pi
• You can now use Putty to log in to your Raspberry Pi (see Section 1.4 and 1.5)
Alternatively, you can find the IP address of your Raspberry Pi by opening the command
prompt on your PC with administrator privilege (by right-clicking to accepting to run as an
administrator) and then inputting the command: ping raspberrypi.home as shown in
Figure 1.6.
It is also possible to find the IP address of your Raspberry Pi using your smartphone. Many
apps can be used to find out who is currently using your Wi-Fi router. e.g. Who’s On My
Wi-Fi – Network Scanner by Magdalm.
Connection using Wi-Fi: This is the preferred method to access your Raspberry Pi and is
the one used by the author. Here, as described in Chapter 1, the Raspberry Pi can be placed
anywhere you like within the range of the Wi-Fi router and is easily accessed from your PC
using Putty (see Section 1.4 and 1.5).
https://notepad-plus-plus.org/downloads/v7.8.5/
● 16
Chapter 1 ● Installing the Operating System on Raspberry Pi
country=GB
update_config=1
ctrl_interface=/var/run/wpa_supplicant
network={
scan_ssid=1
ssid="MySSID"
psk="MyPassword"
}
• Copy the file (save) to the boot folder on your SD card with the name: wpa_
supplicant.conf.
• Insert the SD card back into your Raspberry Pi and power-up the device.
• Use Advanced Ip Scanner or one of the methods described earlier to find out the IP
address of your Raspberry Pi.
• Log in to your Raspberry Pi remotely using Putty on your PC (see Section 1.3 and 1.4).
• After logging in, you are advised to change your password for security reasons. You
should also run sudoraspi-config from the command line to enable VNC, I2C, and
SPI as they are useful interface tools that can be used in your future GPIO based work.
It is much easier to remotely access the Raspberry Pi over the internet: for example
using a PC rather than connecting a keyboard, mouse, and display to it. Before being able
to remotely access the Raspberry Pi, we have to enable SSH by entering the following
command in a terminal session (if you have followed the steps given earlier, SSH is already
enabled and you can skip the following command):
Go to the configuration menu and select Interface Options. Go down to P2 SSH and
enable SSH. Click <Finish> to exit the menu.
You should also enable VNC so the Raspberry Pi Desktop can be accessed graphically over
the internet. This can be done by entering the following command in a terminal session:
Go to the configuration menu and select Interface Options. Go down to P3 VNC and
enable VNC. Click <Finish> to exit the menu. At this stage you may want to shut down or
restart your Raspberry Pi by entering one of the following commands in command mode:
● 17
C Programming on Raspberry Pi
https://www.putty.org/
Simply double click to run it and the Putty startup screen will be displayed. Click SSH and
enter the Raspberry Pi IP address, then click Open (see Figure 1.7). The message shown in
Figure 1.8 will be displayed the first time you access the Raspberry Pi. Click Yes to accept
this security alert.
● 18
Chapter 1 ● Installing the Operating System on Raspberry Pi
You will be prompted to enter the username and password. Notice the default username
and password are:
username: pi
password: raspberry
You now have a terminal connection with the Raspberry Pi and can type in commands,
including the sudo privileged administrative commands.
passwd
You can use the cursor keys to scroll up and down through the commands you’ve previously
entered in the same session. You can also run programs although not graphical programs.
By default, the Putty screen background is black with white foreground characters. The
author prefers to have white background with black foreground characters, with the
character size set to 12 points bold. The steps to configure the Putty with these settings
are given below. Notice that in this example these settings are saved with the name RPI4
so that they can be recalled whenever the Putty is restarted:
• Restart Putty.
• Select SSH and enter the Raspberry Pi IP address.
• Click Colours under Window.
• Set the Default Foreground and Default Bold Foreground colours to black (Red:0,
● 19
C Programming on Raspberry Pi
Green:0, Blue:0).
• Set the Default Background and Default Bold Background to white (Red:255,
Green:255, Blue:255).
• 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 11.
• Select Session and give a name to the session (e.g. RPI4) and click Save.
• Click Open to open the Putty session with the saved configuration.
• Next time you re-start the Putty, select the saved session and click Load followed by
Open to start a session with the saved configuration.
You can control your Raspberry Pi via Putty, and run programs on it from your Windows
PC. This however will not work with graphical programs because Windows doesn’t know
how to represent the display. As a result of this, for example, we cannot run any graphical
programs in the Desktop mode. We can get round this problem using some extra software.
Two popular software used for this purpose are: VNC (Virtual Network Connection), and
Xming. Here, we shall be learning how to use the VNC.
VNC consists of two parts: VNC Server and the VNC Viewer. VNC Server runs on the
Raspberry Pi, and the VNC Viewer runs on the PC. VNC server is already installed on your
Raspberry Pi and is enabled as described in Section 1.3 using raspi-config.
The steps to install and use VNC Viewer on your PC are given below:
• There are many VNC Viewers available, but the recommended one is TightVNC which
can be downloaded from the following web site:
https://www.tightvnc.com/download.php
• Download and install TightVNC for your PC. You will have to choose a password during
the installation.
• Enter the following command:
pi@raspberrypi:~ $ vncserver :1
• Start TightVNC Viewer on your PC and enter the Raspberry Pi IP address (see Figure
1.9) followed by :1. Click Connect to connect to your Raspberry Pi.
● 20
Chapter 1 ● Installing the Operating System on Raspberry Pi
When we are using the Raspberry Pi with a Wi-Fi router, the IP address is automatically
allocated by the router. It is possible that every time we start the Raspberry Pi, the Wi-Fi
router will give the Pi another IP address. This makes it difficult to log in as we have to find
the new IP address before we log in.
We can give our Raspberry Pi a static IP address so that every time it starts, the same IP
● 21
C Programming on Raspberry Pi
address is allocated from the Wi-Fi router. The IP address is given by the DHCP protocol
running on the Wi-Fi router.
Before setting a static IP address, we have to decide what this address will be, and also
make sure that no other devices on our network use this address. We can check this by
logging in to the Wi-Fi router or by displaying the devices on our network using an app on
a smartphone.
You should see the text active: (running) displayed as shown in Figure 1.11 (only part of
the display is shown). Enter Ctrl+C to exit from the display.
• We now need to find the IP address (Default Gateway) and the Domain Name Server
address of our router. This can easily be obtained either from our Wi-Fi router or PC.
The steps to obtain these addresses from a PC are:
• Go to Control Panel on your Windows 10 PC.
• Click Network and Sharing Centre.
• Click Internet as shown in Figure 1.12.
• Click Details. You will see a screen similar to the one shown in Figure 1.13 where you
● 22
Chapter 1 ● Installing the Operating System on Raspberry Pi
can see the Default Gateway and DNS server addresses. In this example, they are
both: 191.168.1.254.
• You will have to edit the following file: /etc/dhcpcd.conf using a text editor such as
nano. Although you may not be familiar with nano, follow the instructions given here
(nano is described in a later chapter).
• Go to the end of the file using the down arrow key and enter the following lines:
interface wlan0
static ip_address=191.168.1.120/24
static routers=191.168.1.254
staticdomain_name_servers=191.168.1.254
interface eth0
static ip_address=191.168.1.120/24
static routers=191.168.1.254
static domain_name_servers=191.168.1.254
In this example, we chose a static IP address of 191.168.1.120 after making sure there are
no other devices on our network with the same IP address. The suffix /24 is an abbreviation
of the subnet mask 255.255.255.0. You have to make sure you only change the last digit of
the IP address. i.e. choose an address in the form 191.168.1.x. wlan0 is for the Wi-Fi link,
and eth0 is for the Ethernet link.
• Reboot your Raspberry Pi and it should come up with the IP address set as required
● 23
C Programming on Raspberry Pi
1.8 ● Summary
In this chapter, we learned how to install the latest Raspberry Pi operating system on an SD
card, and also how to start using the Raspberry Pi remotely. The instructions provided apply
to all versions of Raspberry Pi. Additionally, setting a static IP address for your Raspberry
Pi is demonstrated.
In the next chapter, we will look at various Raspberry Pi program development tools.
● 24
Chapter 2 ● Raspberry Pi Program Development
2.1 ● Overview
In the last chapter, we learned how to install Raspbian Buster on a Raspberry Pi SD card. In
this chapter, we will learn how to develop programs using Raspberry Pi 4. We will develop
a very simple example project and learn how to use Python and C. Although Python is not
the topic of this book, it will be used in a simple project so that readers can compare Python
with C programming.
A text editor is a very useful tool for creating program source files. Raspberry Pi supports
several text editors including vi, nano, etc. In this section, we will introduce nano which is
normally run from the command line.
As an example, suppose we wish to create a text file called myfile.txt and insert the
following lines into the file:
• Start nano
• Enter the above text into the file (see Figure 2.1). You should see several control codes
at the bottom of the screen.
● 25
C Programming on Raspberry Pi
• Enter Ctrl+X followed by the letter Y to save the file. You should now see the file listed
in your directory if you enter the command:
pi@raspberrypi:~ $ ls myfile.txt
myfile.txt
pi@raspberrypi:~ $
• Let us now edit the file we just created to learn some of the editor commands. Restart
nano as above by specifying the filename.
• Let us search for text starting with the word simple: press Ctrl+W and type simple
and press Enter (see Figure 2.2). You should see the cursor moving to the start of the
word simple. Delete simple and change it to difficult.
• Let us replace the word third with fourth: press Ctrl+\ and type third, and then
fourth when Replace with: is displayed. Press Enter. The message Replace this
instance? will be displayed. Type Y. You should see that the word third is replaced
with fourth.
• Let us delete the second line of text: Move the cursor to the second line and enter
Ctrl+K. You should see all the text on the second line is deleted.
• To recall the line just deleted, enter Ctrl+U.
• To get help on using nano, enter Ctrl+G. An example help screen is shown in Figure
2.3. Enter Ctrl+N to display the next page, and Ctrl+P to display the previous page.
Enter Ctrl+X to close the help screen.
● 26
Chapter 2 ● Raspberry Pi Program Development
As a summary, some of the more useful nano shortcuts are given below:
Ctrl+J: Justify.
In this chapter, we will develop a simple project using both Python and C which will display
the message Hello From Raspberry Pi 4 on your PC screen. This project aims to show
how a project can be created and then run on Raspberry Pi.
As described below, there are four methods we can employ to create and run Python
programs on Raspberry Pi:
● 27
C Programming on Raspberry Pi
Using this method, we will log in to our Raspberry Pi remotely using SSH and create and run
our program interactively in command mode. This method is excellent for small programs.
The steps are as follows:
• Log in to your Raspberry Pi 4 using SSH (or through a connected monitor and keyboard).
• On the command prompt, enter python3. You should see the Python command mode
which is identified by the following three characters: >>>.
• Type the program:
• The text required will be displayed interactively on the screen as shown in Figure 2.5.
Enter Ctrl+Z to exit Python.
In this method, we will log in to our Raspberry Pi using SSH as before and then create a
Python file. A Python file is simply a text file with the extension .py. We can use a text
editor, e.g. nano to create our file. In this example, a file called hello.py is created using
nano. Figure 2.6 shows the contents of hello.py. This figure also shows how to run the file
using Python 3. Notice the program is run by entering the command:
Using this method, we will log in to our Raspberry Pi in desktop mode using VNCViewer (if
we do not have a monitor directly connected) and create and run our program in GUI mode.
We will be using Thonny which is used to create, debug, and run Python 3 programs.
● 28
Chapter 2 ● Raspberry Pi Program Development
Thonny is an easy to use tool which is only available for Python 3. The nice thing about
Thonny is that it formats code while it is entered from the terminal. For example, all
statements in the body of a while loop are automatically and correctly indented.
• Click Applications menu, then Programming, and select Thonny Python IDE as
shown in Figure 2.7
• The Thonny startup screen will be displayed as shown in Figure 2.8. The screen has two
parts: The program is written in the upper part. The lower part is the shell where the
results of the program are displayed. We can also run Python 3 commands interactively
in the lower part of the screen. In the upper part, we have the usual menu items found
in most GUI type displays. Menu option File is used to create a new file, open an
existing file, close, save, or print a file. Menu option Edit is used to undo, cut, paste,
select, find, replace, and so on. Option View is used to enable us to view files, heap,
notes, stack, variables, and so on. Menu option Run is used to run or debug a program.
Menu option Device is used to soft reboot, upload a current script as main script, and
so on. Menu option Tools is used to manage packages, manage plug-ins, configure
Thonny, and so on. Finally, the Help menu option is used to get help on using Thonny.
● 29
C Programming on Raspberry Pi
• Click File and save your program by giving it a name. You do not have to specify the
file extension as this is automatically added by Thonny.
• Click Run and you should see the program output on the lower part of the screen as
shown in Figure 2.10.
● 30
Chapter 2 ● Raspberry Pi Program Development
Thonny provides the option to debug a program, where we can single-step through a
program and display the variables as the program is stepped through. As an example, let
us debug the program given in Figure 2.9. The steps are:
In this method, we will use Mu to create and run our Python example program. Mu is a very
easy to use Python editor and Integrated Development Environment (IDE) for beginners.
Mu is installed by default with the Raspbian Buster operating system and can be started by
clicking the Applications Menu, followed by Programming and then Mu (see Figure 2.11).
● 31
C Programming on Raspberry Pi
• Enter Mu in the search box and click on Mu. Click Apply to install the software (Figure
2.13).
● 32
Chapter 2 ● Raspberry Pi Program Development
Mu can also be installed from the command line using the command:
Figure 2.14 shows the startup screen of Mu where the statement to display the message
Hello Form Raspberry Pi 4 is entered.
The menu options are listed on the top of the screen. Click Run to execute the program. The
result will be displayed on the bottom part of the screen as shown in Figure 2.15.
Interested readers can learn how to use other menu options but this is outside the scope
of this book.
● 33
C Programming on Raspberry Pi
Which Method?
The choice of method depends upon the size and complexity of the program we wish to
develop. Small programs can be interactively run without creating a program file. Larger
programs can be created as Python files by using either nano in command mode. Thonny
and Mu can be used to create programs in Desktop GUI mode. Python beginners should
find Mu easy to use.
Programming Raspberry Pi in C is the main topic of this book. We will use nano to create
our C source programs. The programs should have the file extensions .c. Figure 2.16 shows
the program listing our simple project (Program: msg.c).
#include <stdio.h>
int main(void)
{
printf("Hello From Raspberry Pi 4\n");
}
Figure 2.16 Program: msg.c
The header file stdio.h is included at the beginning of the program. The message is printed
using the printf statement. A new-line is printed at the end of the text using the \n keyword.
The program is compiled by entering the following command. Here, gcc is the C compiler,
-o option specifies that the next word (i.e. hello) is the output filename:
pi@rasberrypi:~$ ./hello
Hello From Raspberry Pi 4
pi@raspberrypi:~ $
Notice ./ specifies the file is in our current directory, which is by default /home/pi.
Alternatively you could enter the following command to run the program:
pi@raspberrypi:~ $ /home/pi/hello
Hello From Raspberry Pi 4
pi@raspberrypi:~ $
• If the output option –o is not specified, the compiler creates the executable file
● 34
Chapter 2 ● Raspberry Pi Program Development
• Option –S generates an assembly code listing of the program. In the following example,
the assembly listing is stored in file msg.s:
• Option –save-temps creates executable file (a.out), assembly file, compile file, and
list file:
• Option –l links with the specified library. In the following example, the code is linked
with a library called wiringPi:
• Option –v displays all the steps gcc takes while compiling the program:
• Option @ can be used to read the compiler options from a file. For example, assume
MyOptions contains the lines:
-Wall –o MyOutputFile
Then, program msg.c can be compiled with the above options as:
2.6 ● Summary
In this chapter, we learned how to develop Python 3 and C programs using several
methods. The choice of method for Python depends entirely on the user. In this book, we
are interested in developing programs using C. Therefore, the remainder of this book is
about the C language and its use with Raspberry Pi.
● 35
C Programming on Raspberry Pi
In the next chapter, we will make an introduction to C. Readers who are familiar with C can
skip most sections.
● 36
Chapter 3 ● C Programming for Raspberry Pi
3.1 ● Overview
In this chapter we will be look at the basic principles of programming using C. There are
hundreds of books, tutorials and application notes on programming using C and therefore
this chapter is not intended to teach C programming in detail.
3.2.1 ● Variables
As we have seen earlier, printf is used to display data and text on the screen. Data can be
inputted from the keyboard using the scanf statement. An example is given below.
Example 3.1
Write a program to read the base and height of a triangle and then calculate and display
its area.
Solution 3.1
/*-----------------------------------------------------------
AREA OF A TRIANGLE
==================
● 37
C Programming on Raspberry Pi
int main(void)
{
float Base, Height, Area;
printf("\nArea of a Triangle\n\n");
printf("Enter base: ");
scanf("%f", &Base);
printf("Enter Height: ");
scanf("%f", &Height);
Area = Base * Height / 2.0;
printf("Area = %f\n", Area);
return 0;
}
Figure 3.1 Program: TriangleArea.c
At the beginning of the program, variables Base, Height and Area are declared as floating-
point variables. The program then displays the heading Area of a Triangle. New lines are
printed before and after displaying this heading. The text Enter base: is displayed and the
user is requested to enter the base of the triangle which is stored in variable Base. Notice
that scanf requires the memory address of the variable to store the data. Then height is
requested from the user. The area of the triangle is calculated and displayed on screen.
Figure 3.2 shows an example run of the program.
We can change the number of decimal places using the %f statement. The general format
of this statement is:
%n.df where n is the total length of the number to be displayed and d is the
number
● 38
Chapter 3 ● C Programming for Raspberry Pi
For example, to display area with one digit after the decimal point, we can use the statement:
Some other example output formats are (assuming the number to be displayed is 62.0):
%4.2 62.40
%5.2 62.40
%6.3 62.400
%c character
%d integer number
%s string
%u unsigned decimal integer
%lu unsigned decimal long integer
%o octal number
%x, %X hexadecimal number
%e exponential number
Example 3.2
In this example, we will again calculate the area of a triangle but its base and height will
be entered on the same line.
Solution 3.2
/*-----------------------------------------------------------
AREA OF A TRIANGLE
==================
● 39
C Programming on Raspberry Pi
int main(void)
{
float Base, Height, Area;
printf("\nArea of a Triangle\n\n");
printf("Enter base and height: ");
scanf("%f %f", &Base, &Height);
Area = Base * Height / 2.0;
printf("Area = %6.3f\n", Area);
return 0;
}
Figure 3.3 Program: TriangleArea2.c
This program is very similar to the one provided in Example 1, but scanf is used to read
both the base and height of the triangle with a space separating the two entries. Figure 3.4
shows an example run of the program.
3.2.3 ● Comparison
3.2.4 ● Operators
x + y addition
x – y subtraction
x * y multiplication
x / y division
x % y remainder of x/y
x & y bitwise AND
x | y bitwise OR
● 40
Chapter 3 ● C Programming for Raspberry Pi
x ^ y bitwise exclusive OR
~x complement
!x logical NOT
x << y bit shift left
x >> y bit shift right
Flow control statements constitute very important statements in all programming languages.
These statements enable programmers to form conditional program executions, selections,
and iterations (loops).
Conditional statements
if…else
The if…else block of statements are the main conditional statements. The general format
of an if…else block is:
if(condition is true)
{
execute these statements
…………………………
…………………………
}
else
● 41
C Programming on Raspberry Pi
{
execute these statements
………………………….
………………………….
}
If there is only one statement inside an if block, there is no need to use a curly bracket:
if(condition is true)
execute a single statement;
Example 3.3
Write a program to read two numbers from the keyboard and calculate their average. If
the average is greater than 10, display Average is greater than 10. If on the other hand
the average is less than 10, display Average is less than 10. If on the other hand, the
average is equal to 10, display Average is 10.
Solution 3.3
Figure 3.5 shows the program listing (Program: Average.c). The program reads two
floating-point numbers into variables no1 and no2. The average is calculated and stored in
variable average. A message is then displayed depending on whether the average is equal
to 10, greater than 10, or less than 10. Figure 3.6 shows an example run of the program.
/*-----------------------------------------------------------
AVERAGE OF 2 NUMBERS
====================
int main(void)
{
float no1, no2, average;
printf("\nAverage of two numbers\n\n");
printf("Enter two numbers: ");
● 42
Chapter 3 ● C Programming for Raspberry Pi
return 0;
}
Figure 3.5 Program: Average.c
switch
The switch statement is another conditional statement that is used to test a variable
against several conditions, and do different things for each condition. The general format of
the switch statement is as follows:
switch (variable)
{
condition 1: do some statements
condition 2: do some statements
condition 3: do some statements
default: do some statements
}
Notice that default is optional and if none of the conditions are satisfied, the statements
under default are executed.
Example 3.4
● 43
C Programming on Raspberry Pi
Solution 3.4
Figure 3.7 shows the required program (Program: calculator.c). The function scanf is
used to read the two numbers and the required operation on the same line. A switch
statement is used to perform the required calculation. Notice the conditions are specified
using the case statement followed by the condition. If for example, the user entered +,
the two numbers added together and the sum is stored in variable result, which is then
displayed. The break statements make sure that the switch block terminates after the
contents of a condition are executed.
/*-----------------------------------------------------------
SIMPLE CALCULATOR
=================
int main(void)
{
float no1, no2, result;
char oper;
switch(oper)
{
case ‘+’:
result = no1 + no2;
break;
case ‘-’:
result = no1 - no2;
break;
case ‘*’:
result = no1 * no2;
break;
case ‘/’:
result = no1 / no2;
break;
}
● 44
Chapter 3 ● C Programming for Raspberry Pi
while
This flow control statement is usually used in loops (repetition). The statements inside the
curly brackets are executed as long as the condition is true. Notice if the condition does not
become true inside the curly brackets, the loop is executed forever. Also, if the condition is
false on entry to the loop, the statements inside the loop are never executed. The general
format of this statement is as follows:
while(condition is true)
{
execute these statements
}
Example 3.5
Solution 3.5
The total resistance of resistors connected in series is calculated by adding up the values of all
the resistors. Figure 3.9 shows the required program listing (Program: SerialResistors.c).
At the beginning of the program, the user is asked to enter the number of resistors
connected in series and this is stored in variable no. A while loop is then formed and inside
this loop, the user is asked to enter the value of each resistor. The total resistance is stored
in the variable Total which is displayed on the screen.
● 45
C Programming on Raspberry Pi
/*-----------------------------------------------------------
SERIALLY CONNECTED RESISTORS
=============================
int main(void)
{
int no, k, R, Total;
k = 1;
Total = 0;
● 46
Chapter 3 ● C Programming for Raspberry Pi
Figure 3.10 shows an example run of the program with three resistors connected in series.
do...while
This statement is similar to the while statement, but the statements inside the loop are
executed at least once. This is because the condition to exit the loop is tested at the end of
the loop. The general format of this statement is as follows:
do
{
execute these statements
}while(condition is true)
Example 3.6
Repeat Example 3.5, but this time use the do…while statement for the loop.
Solution 3.6
Figure 3.11 shows the program listing (Program: SerialResistors2.c). As you can see,
the condition to terminate the loop is tested at the end of the loop. An example run of the
program is the same as in Figure 3.10.
/*-----------------------------------------------------------
SERIALLY CONNECTED RESISTORS
=============================
● 47
C Programming on Raspberry Pi
int main(void)
{
int no, k, R, Total;
k = 1;
Total = 0;
do
{
printf("Enter resistance (Ohms) of Resistor %d: ", k);
scanf("%d", &R);
Total = Total + R;
k++;
}while(k <= no);
for
The for loop is probably one of the most commonly used iteration statements. The general
format of this statement is:
Example 3.7
Repeat Example 3.5, but this time use the for statement for the loop.
Solution 3.7
Figure 3.12 shows the program listing (Program: SerialResistors3.c). As you can see, in
this program, the for loop runs from 1 to 3 inclusive. An example run of the program is the
same as in Figure 3.10.
● 48
Chapter 3 ● C Programming for Raspberry Pi
/*-----------------------------------------------------------
SERIALLY CONNECTED RESISTORS
=============================
int main(void)
{
int no, k, R, Total;
Total = 0;
Example 3.8
Write a program to display a table of the squares of integer numbers from 1 to 10.
Solution 3.8
The required program listing (Program: squares.c) is shown in Figure 3.13. A loop is
formed using a for statement and inside this loop, integer numbers from 1 to 10 are
tabulated with their corresponding squares.
● 49
C Programming on Raspberry Pi
/*----------------------------------------------------
TABLES OF SQUARES
=================
int main(void)
{
int k;
printf("\nTABLE OF SQUARES");
printf("\n================\n");
return 0;
}
● 50
Chapter 3 ● C Programming for Raspberry Pi
Example 3.9
Write a program to display a table of the trigonometric function sine, cosine, and tangent
from 0º to 20º.
Solution 3.9
The required program listing (Program: trig.c) is shown in Figure 3.15. The math library
header file <math.h> is included at the beginning of the program. When using the
trigonometric functions, the angles must be entered in radians. The program converts
degrees in variable k into radians in variable rad and this variable is used in the trigonometric
functions.
/*-----------------------------------------------------------
TABLE OF TRIGONOMETRIC FUNCTIONS
================================
List of the table of trigonometric functions 0-20 Degrees
int main(void)
{
int k;
float rad,s,c,t, Pi = 3.14159;
return 0;
}
Figure 3.15 Program trig.c
● 51
C Programming on Raspberry Pi
Figure 3.16 shows an example run of the program. Notice the program must be compiled
with the option –lm when the mathematical functions are used.
In some looping applications, we may want to exit the loop before the condition is satisfied.
The break statement is used to terminate a loop. Similarly, the continue statement ignores
the statements after it and the program moves to the beginning of the loop and continues
from there. Examples are given below.
Example 3.10
Write a program to display the squares of integer numbers from 1 to 10 as in Example 3.8.
Stop the display after 5 iterations.
Solution 3.10
The required program listing (Program: squares2.c) is shown in Figure 3.17. Notice how
the break statement is used to terminate the for loop.
● 52
Chapter 3 ● C Programming for Raspberry Pi
/*-----------------------------------------------------------
TABLES OF SQUARES
=================
int main(void)
{
int k;
printf("\nTABLE OF SQUARES");
printf("\n================\n");
return 0;
}
Figure 3.17 Program squares2.c
Example 3.11
Write a program to display the squares of integer numbers from 1 to 10 as in Example 3.8.
Skip the table for number 5.
● 53
C Programming on Raspberry Pi
Solution 3.11
The required program listing (Program: squares3.c) is shown in Figure 3.19. Notice how
the continue statement is used to skip number 5 inside the for loop.
/*-----------------------------------------------------------
TABLES OF SQUARES
=================
int main(void)
{
int k;
printf("\nTABLE OF SQUARES");
printf("\n================\n");
return 0;
}
Figure 3.19 Program: squares3.c
● 54
Chapter 3 ● C Programming for Raspberry Pi
3.2.8 ● Arrays
During program development, there is usually a need to record related items of data of the
same type. For example, we may want to save the heights of students in a classroom. In
such applications, it is easy to use arrays to store related data items.
An array has a type and name. For example, an integer called age with 5 elements can be
defined as follows:
intager[5];
Each element of the array is unique. The index of the array always starts from 0 and goes
up the defined value minus 1. Therefore, in the above definition, array age has 5 elements
where each element can be accessed as follows:
age[0]
age[1]
age[2]
age[3]
age[4]
The contents of an array element can be changed by specifying its index and assigning
new data to it. In the following example, the second element of the array is changed to 10:
age[1] = 10;
Example 3.12
It is required to find the maximum age of students in a class. Write a program to read the
number of students and their ages, and calculate and display the maximum age in the
classroom.
● 55
C Programming on Raspberry Pi
Solution 3.12
The required program listing (Program: ages.c) is shown in Figure 3.21. At the beginning,
the number of students is read and stored in variable no. The program then reads the
ages and stores them in array age using a for loop. A second for loop is used to find the
maximum age which is then displayed.
/*--------------------------------------------------------
MAXIMUM AGE OF STUDENTS
=======================
int main(void)
{
int k, no, maxage = 0;
int age[50];
return 0;
}
Figure 3.21 Program ages.c
● 56
Chapter 3 ● C Programming for Raspberry Pi
Notice it is not necessary to specify the length of the string as this is calculated by the
compiler. The above statement creates a character array having 5 elements including the
NULL character at the end. The characters are stored in the array as shown below:
Notice the specified array size is greater than the number of elements in the array. Here, the
compiler allocates additional space at the end of the array so extra text can be appended
in the future. The keyword BUFSIZ can be used when an array is declared if the length
of array is not known. BUFSIZ sets the array size to the maximum value allowed by the
compiler.
The name of an array is also its address in memory. Therefore, when it is required to enter
the address of an array, we can simply enter its name, or specify its address by using the
& sign in front of its first element. e.g. as &name[0].
Strings can be printed using the %s qualifier of the printf example as shown in the following
example.
● 57
C Programming on Raspberry Pi
Example 3.13
Write a program to read the name of a person and display it on the screen.
Solution 3.13
The required program listing (Program: name.c) is shown in Figure 3.23. The user entered
name is read by scanf and stored in character array name and then displayed on the
screen.
/*--------------------------------------------------------
NAME
====
int main(void)
{
char name[30];
return 0;
}
Figure 3.23 Program name.c
Notice that even though we entered the name as John Smith, it is displayed as John
only. This is because the scanf function terminates while reading a text when white space
is encountered. The solution to this problem is to use the fgets function to read text with
white spaces, or to change the scanf function as follows so that the text is read until the
● 58
Chapter 3 ● C Programming for Raspberry Pi
scanf("%[^\n]%*c", name);
Example 3.14
Write a program to read the name and age of a person and then display it on the screen.
Solution 3.14
The required program listing (Program: nameage.c) is shown in Figure 3.25. User entered
name and age are read by scanf functions and stored in the character array name and
variable age respectively. They are then displayed on the screen.
/*--------------------------------------------------------
NAME AND AGE
============
int main(void)
{
char name[30];
int age;
return 0;
}
Figure 3.25 Program nameage.c
● 59
C Programming on Raspberry Pi
Example 3.15
Write a program to read the name and age of a person and display it on the screen. Use
the gets function to read the name.
Solution 3.15
The required program listing (Program: nameage2.c) is shown in Figure 3.27. User
entered name is read using the fgets function. Age is read by the scanf function. They are
then displayed on the screen.
Where name is the name of the character array to receive the string data, size is the
number of characters to read, and stdin the standard input port. fgets will terminate when
the specified number of characters are read or when it encounters the Enter character.
A newline character is added to the end of fgets before the NULL terminator. In most
applications, we want to remove this newline character. In Figure 3.27, the newline
character is replaced with the string terminator NULL character. Here, len gives the length
(number of characters) of the string, excluding the NULL terminator.
/*--------------------------------------------------------
NAME AND AGE
============
int main(void)
{
● 60
Chapter 3 ● C Programming for Raspberry Pi
char name[30];
int age, len;
return 0;
}
Figure 3.27 Program nameage2.c
C supports a large number of arithmetic functions. The header file <math.h> must be
included at the beginning of your program before using these functions. Also, the program
must be compiled with the option: -lm. In this section, we will look at some of the commonly
used arithmetic functions.
● 61
C Programming on Raspberry Pi
Example 3.16
Solution 3.16
The required program listing (Program: powers.c) is shown in Figure 3.28. The program
makes use of the built-in arithmetic function pow() to calculate the powers of 2. This
function returns a floating-point variable. This is converted into an integer and displayed.
/*----------------------------------------------------
TABLE OF POWERS OF 2
====================
Table of powers of 2 from 0 to 16
int main(void)
{
int k, d;
float p;
return 0;
}
Figure 3.28 Program powers.c
● 62
Chapter 3 ● C Programming for Raspberry Pi
String functions are very helpful when one is required to manipulate strings. A list of some
of the commonly used string functions is given in this section. The header file <string.h>
must be included at the beginning of your program before using these functions. Examples
of using some of the commonly used string functions are given in this section.
strcmp: This function compares two strings and returns an integer as follows:
Example 3.17
Write a program to show how string functions strlen, strcpy, and strcmp can be used in
a program.
● 63
C Programming on Raspberry Pi
Solution 3.17
Figure 3.30 shows the program listing (Program: lencmp.c). String a is initialised with text
John Smith, and a blank string with the name b is created. The program copies string a to
string b and displays the contents of string b. The length of string a is then displayed on the
screen. The remainder of the program shows how the string compare function can be used.
/*------------------------------------------------------------
strlen and strcmp
int main(void)
{
char a[]="John Smith";
char b[BUFSIZ];
strcpy(b, a);
printf("My name is %s\n", b);
printf("Length of my name is %d characters\n", strlen(a));
printf("%d\n",strcmp("Smith", "Smith"));
printf("%d\n",strcmp("Smith", "Smit"));
printf("%d\n",strcmp("Smit", "Smith"));
printf("%d\n",strcmp("Smith", "Smiti"));
printf("%d\n",strcmp("Smith", "John"));
return 0;
}
Figure 3.30 Program lencmp.c
● 64
Chapter 3 ● C Programming for Raspberry Pi
strcat: This function concatenates one string to the end of another string.
strchr: This function searches a string for the first occurrence of a specified character.
Example 3.18
Write a program to show how the string functions strcat, strchr, and toupper can be used
in a program.
Solution 3.18
Figure 3.32 shows the program listing (Program: catchr.c). The program concatenates
string John Smith to array c. Function strchr is used to check if this text contains character
S and a message is displayed. The text is then converted into upper case letters and
displayed on the screen.
/*------------------------------------------------------------
strcat, strchr and toupper
int main(void)
{
char a[]="John";
char b[] = " Smith";
● 65
C Programming on Raspberry Pi
char c[BUFSIZ];
char u[BUFSIZ];
int i;
//
// Using strcat
//
strcat(c, a);
strcat(c, b);
printf("My name is %s\n", c);
//
// Using strchr
//
if(strchr(c, ‘S’) != 0)
printf("S is found in string %s\n", c);
else
printf("String %s does not contain S\n", c);
//
// Using toupper
//
for(i = 0; i < strlen(c); i++)
{
u[i] = toupper(c[i]);
}
printf("Upper case of %s is %s\n", c, u);
return 0;
}
Figure 3.32 Program catchr.c
Example 3.19
Write a program to show how the string functions strcat and strcpy can be used in a
program.
● 66
Chapter 3 ● C Programming for Raspberry Pi
Solution 3.19
Figure 3.34 shows the program listing (Program: cpy.c). The program forms string John-
Smith and displays it on the screen.
/*------------------------------------------------------------
strcpy and strcat
int main(void)
{
char a[]="John";
char b[] = "Smith";
char c[] = "-";
char d[BUFSIZ];
//
// Using strcpy
//
strcpy(d, a); // d=John
strcat(d, c); // d=John-
strcat(d, b); // d=John-Smith
printf("My name is %s\n", d);
return 0;
}
Figure 3.34 Program cpy.c
My name is John-Smith
Several useful macros are available that can be used to test various characters. The header
file <ctype.h> must be included at the beginning of the program before these macros can
be used.
● 67
C Programming on Raspberry Pi
Example 3.20
Write a program to show how the character macros isalpha and isdigit can be used in a
program.
Solution 3.20
Figure 3.35 shows the program listing (Program: tmacro.c). The user is prompted to enter
a character. The program checks the entered character and displays the message You
entered a digit, or You entered alpha character, depending on what type of character
the user enters. The program runs in a loop and the user can continue by entering y or Y
to the prompt Continue (y.n)? :.
/*------------------------------------------------------------
Character macros
int main(void)
{
char ch, yn = ‘Y’;
while(yn == ‘Y’)
{
printf("\nEnter a character: ");
scanf("%c%*c", &ch);
● 68
Chapter 3 ● C Programming for Raspberry Pi
It is important to note that scanf reads the entered data and the newline character stays in
the input buffer. As a result, when more than one scanf is used in a program, the second
scanf will read the newline character left in the input buffer and the program will not
read the user data. We can use scanf("%c%*c") as shown in the program to read two
characters and ignore the last one (in this case the newline \n).
Although scanf can be used to read numeric data from the keyboard, it can glitch if the
user enters alphabetic data when numeric data is expected. Functions atoi and atof can be
used to read integer and floating-point data from the keyboard. An example is given below.
Example 3.21
Write a function to read integer numbers from the keyboard. Calculate and display the
average of these numbers.
● 69
C Programming on Raspberry Pi
Solution 3.21
Figure 3.37 shows the program listing (Program: numeric.c). At the beginning of the
program, the user inputs how many numbers are to be entered. These numbers are then
read using the fgets function and their average is calculated and displayed on the screen.
/*------------------------------------------------------------
Using the function atoi
int main(void)
{
char buff[50];
int num, number, k;
float Total = 0.0;
return 0;
}
Figure 3.37 Program numeric.c
An example run of the program is shown in Figure 3.38. Notice we can use the atof function
to read floating-point numbers.
● 70
Chapter 3 ● C Programming for Raspberry Pi
It is easier to develop large programs by breaking them down into smaller, manageable
sections. Functions are used for this purpose. Functions are also used when a certain group
of operations are to be repeated in a program. For example, if it is required to calculate
the average of some numbers at different places of a program, it is easier to write the
averaging code as a function and call this function in the main program whenever it is
required.
The type of a function can be one of the valid variable types, such as char, int, float, etc.
The function returns the specified type of variable to the calling program. We can use the
void keyword if the function does not return any data to the calling program. The function
name is a valid C variable name. The parameters inside the bracket are optional and
depend on the application. The return keyword is optional and the data to be returned to
the main program must be specified after the return statement.
A function is called from the main program by specifying its name followed by a set of
brackets. Any arguments used must be specified inside the brackets. Some examples are
given below.
Example 3.22
Write a function to calculate the area of a triangle. The base and height of the triangle are
to be read from the keyboard and passed as arguments to the function.
Solution 3.22
The required program listing (Program: Func1.c) is shown in Figure 3.39. The base
● 71
C Programming on Raspberry Pi
and height of the triangle are read from the keyboard and passed to the function called
TriangleArea. The function returns the calculated area which is then displayed by the main
program.
/*------------------------------------------------------------
Example use of a function
int main(void)
{
float base, height, area;
printf("\nAREA OF A TRIANGLE");
printf("\nEnter the base and height of the triangle: ");
scanf("%f %f", &base, &height);
area = TriangleArea(height, base);
printf("\nArea = %f\n", area);
return 0;
}
Figure 3.39 Program Func1.c
● 72
Chapter 3 ● C Programming for Raspberry Pi
Example 3.23
Write a program using two functions, Area and Circumference, to calculate the area
and circumference of a circle respectively. The radius of the circle should be read from the
keyboard.
Solution 3.23
Figure 3.41 shows the program listing (Program: circle.c). The main program reads the
radius of the circle and calls the two functions to calculate the area and the circumference
of the circle. Here, #define is known as a pre-processor macro. In this example, Pi is
replaced with the value 3.14159 during the compilation time wherever it appears in the
program. #include is another pre-processor macro.
/*------------------------------------------------------------
Circle and Area of a circle
float Area(float r)
{
float area;
area = Pi * r * r;
return(area);
}
float Circumference(float r)
{
float circ;
circ = 2 * Pi * r;
return(circ);
}
int main(void)
{
float radius, area, circ;
char buff[BUFSIZ];
● 73
C Programming on Raspberry Pi
return 0;
}
Figure 3.41 Program circle.c
Function prototyping
In some programs, the definition of a function may not be visible to the compiler during
compilation time. This will occur if a function is used before it is declared. In such
applications, we must declare the name of the function and its arguments at the beginning
of the program. The function can then be declared before or after the main program. Figure
3.43 shows how function prototypes can be declared and the two functions can be used
after the main program (Program: circle2.c)
/*------------------------------------------------------------
Circle and Area of a circle
float Area(float);
● 74
Chapter 3 ● C Programming for Raspberry Pi
float Circumference(float);
int main(void)
{
float radius, area, circ;
char buff[BUFSIZ];
return 0;
}
float Area(float r)
{
float area;
area = Pi * r * r;
return(area);
}
float Circumference(float r)
{
float circ;
circ = 2 * Pi * r;
return(circ);
}
Figure 3.43 Declaring function prototypes
Example 3.24
Write a program to read 5 integer numbers into an array. Then call a function to calculate
the sum of these numbers and return the sum to the calling program where the sum is
then displayed.
● 75
C Programming on Raspberry Pi
Solution 3.24
Figure 3.44 shows the program listing (Program: arrayfunc.c). The main program reads
five integer numbers and calls function Sum to calculate their sum. Function Sum receives
the array in its argument and adds up all its elements and stores them in local variable Tot
which is then returned to the calling program.
/*------------------------------------------------------------
Passing an Array to a Function
int main(void)
{
int k, Total;
char buff[BUFSIZ];
int numbers[5];
printf("\nSum of 5 numbers...\n");
for(k = 1; k <= 5; k++)
{
printf("Enter number %d: ", k);
numbers[k-1] = atoi(fgets(buff, 5, stdin));
}
Total = Sum(numbers);
printf("\nSum = %d\n", Total);
return 0;
}
Figure 3.44 Program arrayfunc.c
● 76
Chapter 3 ● C Programming for Raspberry Pi
Example 3.25
Write a program to read text from the keyboard and pass it to a function where it will be
displayed on the screen.
Solution 3.25
Figure 3.46 shows the required program (Program: strfunc.c). The main program reads
the text entered by the user and calls function PrntStr to display this string on the screen.
/*------------------------------------------------------------
Passing text to a function
int main(void)
{
char txt[BUFSIZ];
● 77
C Programming on Raspberry Pi
return 0;
}
Figure 3.46 Program strfunc.c
File processing functions enable us to write and read data on a Raspberry Pi SD card. By
default, data is written and read from the default user folder which is: /home/pi.
fopen open a file for reading/writing (a file must be opened before accessing it)
fprintf print data to a file
fgets read data from a file
fscanf read data from a file
fputs write data to a file
fclose close a file (an open file must always be closed when finished working
with it)
• r Opens a file in read mode and sets pointer to the first character in the file. It returns
NULL if a file does not exist.
• w Opens a file in write mode. It returns NULL if a file could not be opened. If the file
does not exist then a new file is created. If a file exists, data is overwritten.
• a Opens a file in append mode. If the file does not exist then a new file is created. It
returns NULL if a file couldn’t be opened.
• r+ Opens a file for read and write mode and sets pointer to the first character in the
file. This mode is also called the update mode
• w+ opens a file for read and write mode and sets pointer to the first character in the
file. If a file does not exist then a new one is created
• a+ Opens a file for read and write mode and sets pointer to the end of the file for
appending. A new file is created if it does not exist. Data can be appended to the end
of the file, but the existing data cannot be modified.
• wb Opens the file in binary write mode
It is always good programming practice to check whether a file can be opened before
reading or writing to it. Some file processing examples are given below. Also, a file must
always be closed when we finish working on it.
● 78
Chapter 3 ● C Programming for Raspberry Pi
Example 3.26
Create a new file called squares.txt in the default directory and write the squares of the
integer numbers from 1 to 5 to the file.
Solution 3.26
Figure 3.47 shows the program listing (Program: fsquares.c). A file pointer must be
declared before a file can be accessed. In this example, the file pointer is called fl. The
program checks to make sure that squares.txt can be opened on the SD card. If the file
cannot be opened, a message is displayed and the program terminates by calling function
exit(0). A for loop is then formed and the integer numbers and their squares are written
to the file using the fprintf statement.
/*----------------------------------------------------
TABLES OF SQUARES
=================
Write the table of squares from 1 to 5 to a file
Author: Dogan Ibrahim
File : fsquares.c
Date : December 2020
-----------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int k;
FILE *fl;
● 79
C Programming on Raspberry Pi
Example 3.27
This example writes the squares of integer numbers from 1 to 5 to squares.txt as in the
previous example. Here, fputs can be used to write to the file.
Solution 3.27
/*----------------------------------------------------
TABLES OF SQUARES
=================
int main(void)
{
int k;
FILE *fl;
● 80
Chapter 3 ● C Programming for Raspberry Pi
return 0;
}
Figure 3.49 Program fsquares2.c
Example 3.28
Write a program to read the contents of squares.txt created in the previous example and
display it on the screen.
Solution 3.28
Figure 3.50 shows the program listing (Program: fdisp.c). The program opens squares.
txt in read mode. A while loop is used to read characters from the file using getc until the
end-of-file (EOF) is reached. Function putchar displays the characters read from the file
on the screen.
/*----------------------------------------------------
READING DATA FROM A FILE
========================
int main(void)
{
int c;
FILE *fl;
● 81
C Programming on Raspberry Pi
c = getc(fl);
while(c != EOF)
{
putchar(c);
c = getc(fl);
}
fclose(fl);
return 0;
}
Figure 3.50 Program fdisp.c
3.2.16 ● Structures
Structures are used when we want to group and manipulate related but usually different
types of data. For example, we may want to group somebody’s personal data, such as
name, age, height, weight, and so on. Structures are very efficient in such applications and
make programming easy.
A structure is defined using the keyword struct, followed by the name of the structure. The
body of the structure contains the elements of the structure. An example structure is shown
below which can be used to store the details of a person:
struct person
● 82
Chapter 3 ● C Programming for Raspberry Pi
{
char name[20]
char surname[20];
int age;
float height;
float weight;
};
It is important to realise that the above is only a template that does not occupy any space
in memory. A variable of type struct with the above template can be defined using a
statement as follows. Here, variable p1 is of type struct and occupies space in memory
(notice p1 is the variable, not the person):
We can also define the template and at the same time define the variables to be used. An
example is shown below:
struct person
{
char name[20]
char surname[20];
int age;
float height;
float weight;
}p1, p2, p3;
In the above statements, a structure named person is created with three variables p1, p2,
and p3 where these variables occupy space in memory.
The elements of a structure can be accessed by specifying the variable name, followed by
a comma, and the name of the element. Some examples are given below:
p1.age = 25;
p1.height = 162.0;
The size of a structure is the number of bytes occupied by a structure. The keyword sizeof
can be used to find the size of a structure variable as shown below:
sizeof(p1);
p1 = p2;
● 83
C Programming on Raspberry Pi
struct person
{
char name[20]
char surname[20];
int age;
float height;
float weight;
}p1 = {"John", "Smith", 25, 162, 62};
Example 3.29
Write a program to read the name, surname, age, height, and weight of a variable and
store them in a structure. Display the details on the screen.
Solution 3.29
Figure 3.52 shows the program listing (Program: struct.c). A structure is created with
variable p1. Function scanf is used to read the personal details and these are stored in the
structure. The printf function then displays the personal details.
/*----------------------------------------------------
Person Details
==============
struct person
{
char name[10];
char surname[10];
int age;
float height;
float weight;
● 84
Chapter 3 ● C Programming for Raspberry Pi
}p1;
int main(void)
{
printf("\nEnter name surname age height weight: ");
scanf("%s %s %d %f %f", &p1.name,&p1.surname,&p1.age,&p1.height,&p1.weight);
return 0;
}
Figure 3.52 Program struct.c
3.2.17 ● Unions
Unions are similar to structures, but in a union, all members share common storage. Unions
are declared similar to structures. An example union declaration is shown below. Here, the
same memory locations are used to store multiple data types. The memory allocated to the
union is large enough to hold the largest member of the union. In the example below, the
union occupies 20 bytes of memory space:
union Data
{
int i;
float j;
char name[20];
}MyData;
As with the structures, the sizeof function can be used to find the size of a union. The union
members are accessed as in the structures.
An example is given below which shows how the union can be used in a program.
● 85
C Programming on Raspberry Pi
Example 3.30
Write a program to store some data in a union, and display the contents.
Solution 3.30
Figure 3.54 shows the program listing (Program: union.c). The union stores an integer,
floating-point number, and string. Figure 3.55 shows the output of the program. Notice
that the contents of the integer and floating-point variables are corrupted. This is because
all three variables share the same memory location and loading data to the string has
corrupted the contents of the other two variables.
/*----------------------------------------------------
Unions
======
union Data
{
char name[20];
int j;
float k;
}p1;
int main(void)
{
p1.j = 20;
p1.k = 12.5;
strcpy(p1.name, "Raspberry Pi");
return 0;
}
Figure 3.54 Program union.c
● 86
Chapter 3 ● C Programming for Raspberry Pi
Figure 3.56 shows the corrected program (Program: union2.c) with the output shown in
Figure 3.57.
/*----------------------------------------------------
Unions
======
This example program shows how a union can be used
Author: Dogan Ibrahim
File : union2.c
Date : December 2020
-----------------------------------------------------*/
#include <stdio.h>
#include <string.h>
union Data
{
char name[20];
int j;
float k;
}p1;
int main(void)
{
p1.j = 20;
printf(" j: %d\n", p1.j);
p1.k = 12.5;
printf(" k: %f\n", p1.k);
return 0;
}
Figure 3.56 Program union2.c
● 87
C Programming on Raspberry Pi
3.2.18 ● Pointers
Pointers are very important parts of the C programming language. A pointer holds the
address of a variable in memory, or it points to the address of a variable. A pointer is
defined by specifying its type, followed by the * character and the name of the pointer:
char *ptr;
In the above example, ptr is a character pointer. Similarly, we can have an integer pointer
called p as:
int *p;
We can initialise a pointer with the address of a variable as shown below. Here, character
variable c is assigned value Z. p is defined as a character pointer and it is initialised with
the address of c. i.e. p points to the address of variable c:
char c = ‘Z’;
char *p = &c;
The above assignments are illustrated in Figure 3.58, where it is assumed character j is at
address 200.
The indirection operator * can be used to assign values to the memory address pointed to
by a pointer. For example, the contents of location 200 in Figure 3.58 can be changed to
‘Y’ by the statement:
*p = ‘Y’;
int a = 10;
int b;
int *p = &a;
● 88
Chapter 3 ● C Programming for Raspberry Pi
b = *p; // b = a
*p = *p + 2; // a = a + 2
*p = *p * *p // a = a * a
(*p)++; // a++
Pointer arithmetic
Strings can be created using character pointers as shown below. Here, pointer p has the
address of the first character (R) of the string. Notice the string is automatically terminated
with a NULL character:
Example 3.31
Write a function to calculate the length of a string from the first principles using pointers.
Solution 3.31
The required program listing is shown in Figure 3.59 (Program: mystrlen.c). Function
mstrlen has one argument as a character pointer which points to the string of which the
length is required. The contents of the string are compared to the string terminator (NULL
character) and a count is incremented until the string terminator is found. The count is then
returned to the calling program. The main program calls the function as shown in the figure
/*----------------------------------------------------
STRING LENGTH
=============
● 89
C Programming on Raspberry Pi
int main(void)
{
int len;
return 0;
}
Figure 3.59 Program mystrlen.c
Example 3.32
Write a function to copy one string to another from the first principles using pointers.
Solution 3.32
The required program listing is shown in Figure 3.60 (Program: mystrcpy.c). Function
mstrcpy copies the characters in the source string to the destination string, each time
incrementing both pointers to point to the next character location. The main program
displays the text:
Dest: Raspberry Pi
/*----------------------------------------------------
STRING COPY
===========
● 90
Chapter 3 ● C Programming for Raspberry Pi
File : mystrcpy.c
Date : December 2020
-----------------------------------------------------*/
#include <stdio.h>
int main(void)
{
int len;
mstrcpy(Dest, MyString);
printf("Dest: %s\n", Dest);
return 0;
}
Figure 3.60 Program mystrcpy.c
Example 3.33
Write a function to concatenate one string to another from the first principles using pointers.
Solution 3.32
The required program listing is shown in Figure 3.61 (Program: mystrcat.c). Inside
function mstrcat, pointer p is set to the end of the destination string. A while loop is then
used where the source string is appended to the end of the destination string. The program
displays the following text:
Raspberry Pi Computer
/*------------------------------------------------------------
STRING CONCATENATION
===================
● 91
C Programming on Raspberry Pi
File : mystrcat.c
Date : December 2020
-------------------------------------------------------------*/
#include <stdio.h>
do // Concatenate
{
*p++ = *s++;
}while(*s != ‘\0’);
int main(void)
{
char MyString[BUFSIZ] = "Raspberry Pi";
char Comp[] = " Computer";
mstrcat(MyString, Comp);
printf("%s\n", MyString);
return 0;
}
Figure 3.61 Program mystrcat.c
Accessing arrays
Accessing array elements using pointers is very easy. We can initially set a pointer to the
address of the array and increment the pointer to access the following elements of the
array. An example is given below.
Example 3.34
Write a program to initialise an array at compilation time and display the elements of the
array using pointers.
Solution 3.34
The required program listing is shown in Figure 3.62 (Program: parray.c). Integer array
Numbers is initialised with 7 numbers. Integer pointer ptr is loaded with the address of
● 92
Chapter 3 ● C Programming for Raspberry Pi
array Numbers. A for loop is formed to display the elements of the array. Notice the
pointer is incremented in the loop to access the elements of the array. When the program
is run, the following is displayed:
1 3 5 7 9 11 13
/*------------------------------------------------------------
ARRAY ACCESS
============
int main(void)
{
for(k = 0; k < nums; k++)
{
printf("%d ", *(ptr+k));
}
return 0;
}
Figure 3.62 Program parray.c
Array elements are usually passed to function by reference and functions use these values.
A function cannot modify the variables passed in arguments unless the addresses of these
variables are passed to the function. Pointers can be used to pass the addresses of variables
to functions so the function can modify these variables. Some examples are given below.
Example 3.35
Write a program to pass two variables to a function by reference. The function should
increment the values of these variables. On return from the function, the main program
● 93
C Programming on Raspberry Pi
Solution 3.35
Figure 3.63 shows the program listing (Program: byref.c). Function Temp has integer
pointers as its argument, and thus expects the addresses of two integers. The function
increments the value of each argument. The main program initialises variables a and b to
10 and 20 respectively. The contents of a and b are then displayed as follows. Notice both
variables are incremented by one:
a = 11 b = 21
/*------------------------------------------------------------
PASSING ARGUMENTS TO A FUNCTION
===============================
int main(void)
{
int a = 10;
int b = 20;
Temp(&a, &b);
printf("a = %d b = %d\n", a,b);
return 0;
}
Figure 3.63 Program byref.c
Example 3.36
● 94
Chapter 3 ● C Programming for Raspberry Pi
Solution 3.36
Figure 3.64 shows the program listing (Program: convupper.c). Function UpperCase
receives the address of the string and converts it to upper case by calling the built-in
function toupper. The string is then displayed by the main program as follows:
MY RASPBERRY PI COMPUTER
/*------------------------------------------------------------
CONVERT A STRING TO UPPER CASE
==============================
int main(void)
{
char MyString[] = "my Raspberry Pi computer";
UpperCase(MyString);
printf("%s\n", MyString);
return 0;
}
Figure 3.64 Program convupper.c
Arrays of pointers
A common use of an array of pointers is with strings. Here, each entry in the array is a
string and is pointed to by the array indexes. As an example, consider the following array
of pointers:
● 95
C Programming on Raspberry Pi
In the above declaration, names[0] points to string John, names[1] points to string
James, names[2] points to string Mark, and so on. An example is given below.
Example 3.37
Write a program to show how the array of pointers can be used. Declare a function to
change an array element.
Solution 3.37
Figure 3.65 shows the program listing (Program: apointers.c). An array of pointers is
declared in the main program with 5 names. Function Chng changes the third element of
this array from Jane to Susan. The program displays the following:
John
Smith
Susan
Mark
Mary
/*------------------------------------------------------------
ARRAY OF POINTERS
=================
int main(void)
{
char *names[5] = {"John", "Smith", "Jane", "Mark", "Mary"};
int k;
Chng(names);
● 96
Chapter 3 ● C Programming for Raspberry Pi
return 0;
}
Figure 3.65 Program apointers.c
Example 3.38
Solution 3.38
Figure 3.66 shows the program listing (Program: apointers2.c). In this program, an
array called numbers is initialised with 5 integer numbers. Pointer ptr is declared with 5
elements. A for loop is created and the pointer elements are set to point to the addresses
of the array elements. Another for loop is created to display the contents of the array
elements. The program displays the following output:
numbers[0] = 10
numbers[1] = 20
numbers[3] = 30
numbers[4] = 40
numbers[5] = 50
/*------------------------------------------------------------
ARRAY OF POINTERS
=================
#define max 5
int main(void)
{
int numbers[max] = {10, 20, 30, 40, 50};
int *ptr[max];
int k;
● 97
C Programming on Raspberry Pi
return 0;
}
Figure 3.66 Program apointer2.c
Function pointers
Function pointers are used to point to functions and not data. They can be used in menu
type applications. An example is given below.
Example 3.39
Write a program to operate on two numbers. The required operations are: add, subtract,
multiply and divide. Use function pointers as a MENU in your program.
Solution 3.39
The required program listing is shown in Figure 3.67 (Program: apointers3.c). At the
beginning of the program, a function pointer called ptr is created to point to functions Add,
Subtract, Multiply, and Divide. The user is prompted to enter two numbers, separated
with a space. Four functions are used for addition, subtraction, multiplication, and division.
Then a MENU is created with four options and the user is requested to enter a choice. A
function is then called based on the user’s choice using the function pointer.
/*------------------------------------------------------------
FUNCTION POINTERS
================
● 98
Chapter 3 ● C Programming for Raspberry Pi
int main(void)
{
float x, y;
void (*ptr[])(float, float) = {Add,Subtract,Multiply,Divide};
int choice;
printf("\n MENU\n");
printf(" ====\n");
printf("0: Add\n");
printf("1: Subtract\n");
printf("2: Multiply\n");
printf("3: Divide\n");
printf("\n Choice?: ");
scanf("%d", &choice);
(*ptr[choice])(x, y);
return 0;
}
Figure 3.67 Program apointers3.c
● 99
C Programming on Raspberry Pi
3.3 ● Summary
In this chapter, we learned the basic programming features of C. Readers who are not
familiar with C can refer to many articles, books, and tutorials available on the internet.
In the next chapter, we will look at the different ways of programming the Raspberry Pi
using C.
● 100
Chapter 4 ● Hardware Programming using C
4.1 ● Overview
The main theme of this book is the development of projects using the C language on
Raspberry Pi. Several C compilers can be used with the Raspberry Pi. In this chapter, we
will briefly look at these compilers by developing a very simple project. In the remaining
chapters of the book, the chosen compiler will be used to developing various hardware-
based projects.
Before going into the details of C compilers and hardware interfaces, it is worthwhile looking
at the Raspberry Pi 4 GPIO connector. This connector is a 40-pin dual-in-line 2.54mm
wide connector as shown in Figure 4.1. Other recent Raspberry Pi models have similar
connectors with almost the same pin configurations.
When the GPIO connector is on the far side of the board, the pins at the bottom, starting
from the left of the connector are numbered as 1, 3, 5, 7, and so on. The ones at the top
are numbered as 2, 4, 6, 8, and so on.
The GPIO provides 26 general purpose bi-directional I/O pins. Some of the pins have
multiple functions. For example, pins 3 and 5 are the GPIO2 and GPIO3 input-output pins
respectively. These pins can also be used as the I2C bus, I2C SDA, and I2C SCL pins
● 101
C Programming on Raspberry Pi
Two power outputs are provided: +3.3V and +5.0V. The GPIO pins operate at +3.3V logic
levels (not like many other computer circuits that operate with +5V). A pin can either be an
input or an output. When configured as an output, the pin voltage is either 0V (logic 0) or
+3.3V (logic 1). Raspberry Pi 4 is normally operated using an external power supply (e.g. a
mains adapter) with +5V output and minimum 2A current capacity. A 3.3V output pin can
supply up to 16mA of current. Total current drawn from all output pins should not exceed
the 51mA 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 Pi. The amount
of current that can be supplied by the 5V pin depends on many factors such as the current
required by the Pi itself, current taken by the USB peripherals, camera current, HDMI port
current, and so on.
When configured as an input, a voltage above +1.7V will be taken as logic 1, and a voltage
below +1.7V will be taken as logic 0. Care should be taken to not supply voltages greater
than +3.3V to any I/O pin as large voltages can easily damage your Pi. For example, the
output pin of an Arduino must not be connected directly to a Raspberry Pi input pin as it
can easily damage input circuitry. Similarly, although connecting a Raspberry Pi output pin
to an Arduino input pin is safe, the output voltage level of the Raspberry Pi may not be high
enough to drive the Arduino input circuitry when it is at logic 1. In such circumstances, a
voltage level converter circuit should be used to convert from either 5V to 3.3V logic levels,
or from 3.3V to 5V. An example logic level converter circuit is shown in Figure 4.2.
Loads requiring small currents such as LEDs can be connected directly to the GPIO pins
through current limiting resistors. LEDs are available in different sizes. Small LEDs draw a
few milliamperes of current, while larger LEDs require about 15mA to be bright. The voltage
drop across an LED again depends on the type of LED used. In most cases, we can assume
a voltage drop of around 2V. LEDs can be either connected in current source or current sink
mode as described below.
● 102
Chapter 4 ● Hardware Programming using C
In this mode (see Figure 4.3), the LED is turned ON when the output port is at logic 1 and
is turned OFF when at logic 0. Assuming 4mA LED current and 2V voltage drop across the
LED, the required current limiting resistor is calculated as:
The nearest physical value is 330 Ohm. Choosing a smaller resistor will make the LED
brighter. Similarly, a larger resistor will make the LED dimmer.
In this mode (see Figure 4.4), the LED is turned ON when the output port is at logic 0 and
is turned OFF when at logic 1. Assuming 4mA LED current, 2V voltage drop across the LED,
and 0.1V output low voltage of the Raspberry Pi, the current limiting resistor required is
calculated as:
Loads requiring currents in the order of several hundreds of milliamperes can be connected
to the Raspberry Pi through a transistor switch. Bipolar transistors are suited to lower
● 103
C Programming on Raspberry Pi
currents, while MOSFET transistors are more suitable for higher currents. Figure 4.5 shows
a bipolar transistor switch with the load connected to the collector circuit. Here, the load
is activated when the transistor is ON, i.e. when the output of the Raspberry Pi is at
logic 1 (i.e. when the transistor is switched ON). A 1K base resistor is suitable for most
applications. If the load is inductive, a diode should be used as shown in Figure 4.6 to
protect the transistor from back emf.
Figure 4.7 shows a MOSFET based circuit that is suitable for larger currents, usually in the
range of hundreds of milliamperes. Again, the load is activated when the output of the
Raspberry Pi is at logic 1.
● 104
Chapter 4 ● Hardware Programming using C
In applications where the load operates with large voltages and currents, it is recommendable
to use relays to switch the loads ON and OFF. Either semiconductor or contact-based
physical relays can be used in circuits. Relays are also available as modules with built-in
transistors making them easier to use in microcontroller applications. Figure 4.8 shows
such a relay module with 4 onboard relays. Alternatively, a transistor circuit can be used to
switch the relay ON and OFF.
Description: This is a very simple project where an LED is connected to port pin GPIO 2
(physical pin 3). The project flashes the LED every second.
Aim: This project aims to show the various compilers available for use with the Raspberry
Pi.
Block diagram: Figure 4.9 shows the block diagram of the project.
● 105
C Programming on Raspberry Pi
Circuit diagram: The circuit diagram of the project is shown in Figure 4.10.
pigpio is one of the popular libraries (see link: http://abyz.me.uk/rpi/pigpio/) that is used
to develop projects on Raspberry Pi. The pigpio library should be installed before it is used.
The steps to install the latest version are:
wget https://github.com/joan2937/pigpio/archive/master.zip
unzip master.zip
cd pigpio-master
make
sudo make install
A program should be compiled and run as follows (assuming the program name is temp.c):
Figure 4.11 shows the program listing (Program: gpioflash.c). At the beginning of the
program, header file pigpio.h is included in the program and led is defined as 2 (i.e. GPIO
2). The GPIO is initialised by calling function gpioInitialise. The led port is then configured
● 106
Chapter 4 ● Hardware Programming using C
as OUTPUT. The remainder of the program runs in a while loop. Inside this loop, the led
is turned ON and OFF with a one-second delay between each output.
/*--------------------------------------------------------
FLASHING LED
============
#define led 2
int main(void)
{
gpioInitialise();
gpioSetMode(led, PI_OUTPUT);
while(1)
{
gpioWrite(led,1);
time_sleep(1.0);
gpioWrite(led,0);
time_sleep(1.0);
}
}
Figure 4.11 Program gpioflash.c
wiringPi is another popular C library for the Raspberry Pi. It has been developed mainly
for Arduino users and it has a similar format. wiringPi is pre-installed with the Raspbian
operating system.
● 107
C Programming on Raspberry Pi
gpio –v
wget https://project-downloads.drogon.net/wiringpi-latest.deb
sudo dpkg –iwiringpi-latest.deb
wiringPi programs should be compiled and run as follows (Assuming the program name is
temp.c):
Figure 4.12 shows the program listing (Program: blink.c). Notice the GPIO numberings are
different in WiringPi, and GPIO 2 corresponds to 8. At the beginning of the program, header
file wiringPi.h is included in the program, and led is defined as 8. WiringPi library is then
initialised by calling function wiringPiSetup. The led port is configured as OUTPUT using
the pinMode function. Users familiar with Arduino programming will notice the wiringPi
library uses the same functions. A while loop is then formed. Inside this loop, the led is
flashed with a one-second delay between each output.
/*-------------------------------------------------------------
FLASHING LED
============
#define led 8
int main(void)
{
wiringPiSetup();
pinMode(led, OUTPUT);
● 108
Chapter 4 ● Hardware Programming using C
while(1)
{
digitalWrite(led, LOW);
delay(1000);
digitalWrite(led, HIGH);
delay(1000);
}
}
Figure 4.12 Program blink.c
A list of the wiringPi GPIO port numbers is shown in Table 4.1 (this table can be displayed
by entering the command: gpioreadall):
It is possible to use the GPIO numbering scheme with the wiringPi programs by changing
function wiringPiSetup() to wiringPiSetupGpio(). It is left to the user to decide whether
to use wiringPi or GPIO numbering. In this book, all figures are based on GPIO numbering.
Some projects use wiringPi numbering, while some others use GPIO numbering, so readers
are familiar with both numbering schemes.
● 109
C Programming on Raspberry Pi
• bcm2835
• ArduPi
• Direct register control
The use of the above libraries/compilers are more restrictive and complicated. Interested
readers can get further information from the following link:
https://elinux.org/RPi_GPIO_Code_Samples#bcm2835_library
In this book, we will be using both pigpio and wiringPi in the Raspberry Pi projects where
appropriate. It is left to the readers to pick the library they wish to use.
Geany is a user-friendly GUI text editor using Scintilla and GTK with IDE features. It is
an ideal text editor for developing programs using wiringPi or pigpio C libraries. Geany is
distributed free of charge with Raspbian.
Geany is available in desktop mode and can be started by clicking Applications menu ->
Programming ->Geany Programmer’s Editor (see Figure 4.13).
The startup menu includes most of the usual menu items found in most applications.
Programs are written in the middle part of the screen. The bottom part is the status panel
where error and other messages are displayed.
The program shown in Figure 4.12 (blink.c) is loaded (click File -> Open and select
● 110
Chapter 4 ● Hardware Programming using C
blink.c after making sure you are in the home directory) to Geany to illustrate how the IDE
can be used. Figure 4.14 shows the program loaded to Geany.
/*-------------------------------------------------------------
FLASHING LED
============
#define led 8
int main(void)
{
wiringPiSetup();
pinMode(led, OUTPUT);
while(1)
{
digitalWrite(led, LOW);
delay(1000);
digitalWrite(led, HIGH);
delay(1000);
}
}
Figure 4.14 Program blink.c
The IDE environment should be configured before compiling and running a program. This
is done with the following steps (see Figure 4.15):
• Click OK.
● 111
C Programming on Raspberry Pi
We are now ready to build and run our program. Click the icon: Build the current file
and make sure there are no errors. Now click the icon: Run or view the current file to
execute the program. You should observe the LED flashing as required.
The Geany editor is very useful during program development as it includes numerous useful
editing features, such as Cut, Copy, Paste, Find, Find Next, Replace, Build, Zoom in, Zoom
out, auto-indentation, status display, and many others. Readers are recommended to use
Geany to develop wiringPi or pigpio projects.
In simple projects where there is no external hardware, we can simply use the Raspberry
Pi board as it is and only software development is then required. Most projects however are
more complex and require additional external components, such as LEDs, motors, displays,
keypads, etc. The developer then has the task of making sure that the hardware is set up
correctly and is working before any software development is started. If the hardware is not
set up correctly, time will be wasted trying to develop software. Hardware development
may require additional skills such as familiarity with interfacing and correctly using various
electronic components in microcontroller-based systems.
While developing hardware-based projects on the Raspberry Pi, we have to make connections
to the 40-pin male type GPIO connector. This can be done easily using female-male type
jumper leads. One side of the jumper lead can be connected to the GPIO connector, while
the other can be connected to a breadboard so external components can easily be interfaced
with the Raspberry Pi. It is recommended by the author to use a 40-way ribbon cable with
a T-connector to bring all GPIO pins to the breadboard for easy access. Figure 4.16 shows
such a connector which is available on the internet.
● 112
Chapter 4 ● Hardware Programming using C
4.7 ● Summary
In this chapter, we learned how to use two of the most popular C libraries for programming
Raspberry Pi using C. In the next chapter, we will be developing Raspberry Pi projects using
wiringPi and pigpio.
● 113
C Programming on Raspberry Pi
5.1 ● Overview
In this chapter, we will develop Raspberry Pi projects using the C programming language.
wiringPi and pigpio libraries will be used where applicable.
Description:
In this project, four LEDs are connected to four GPIO ports. The LEDs are turned ON and
OFF in a rotating manner where only one LED is ON at any given time. i.e. the required LED
pattern is as shown in Figure 5.1.
The LED ON and OFF times are 500 ms and 100 ms respectively.
Aim:
This project aims to show how an array and a for loop can be used in a program to control
multiple devices (LEDs) connected to GPIOs.
Block diagram:
The block diagram of the project is shown in Figure 5.2. LED1 to LED4 are connected to
GPIO ports 27, 17, 3, and 2 respectively.
● 114
Chapter 5 ● Hardware Projects using C
Circuit diagram:
The circuit diagram of the project is shown in Figure 5.3. The LEDs are connected to the
port pins through 470 Ohm current limiting resistors.
Program listing:
wiringPi
The wiringPi program listing of the project is very simple and is shown in Figure 5.4
(Program:RotateLEDs.c).
● 115
C Programming on Raspberry Pi
/*------------------------------------------------------------------
ROTATE LEDS
===========
In this program 4 LEDs are connected to GPIO ports 27, 17, 3 and 2
through 470 Ohm resistors. The program turns ON the LEDs in a
rotating manner. The ON and OFF times are chosen as 500ms and 100ms
respectively.
//
// Configure ports as outputs and turn OFF LEDs
//
void Configure()
{
char k;
for(k = 0; k < 4; k++)
{
pinMode(LEDs[k], OUTPUT);
digitalWrite(LEDs[k], OFF);
}
}
//
// Start of MAIN program
//
int main(void)
{
char j;
wiringPiSetup(); // Initialize wiringPi
Configure(); // Configure ports
//
// Now rotate the LEDs
//
while(1) // Endless loop
{
for(j = 0; j < 4; j++)
{
● 116
Chapter 5 ● Hardware Projects using C
The GPIO pins 27, 17, 3, and 2 correspond to wiringPi pins 2, 0, 9, and 8. At the beginning
of the program, an array called LEDs is set up to store port numbers of the LEDs used in the
project. Then, the GPIO ports where the LEDs are connected are configured as output ports
and the LEDs are turned OFF to begin with. Inside the main program, a for loop is set up to
turn the LEDs connected to GPIO ports ON and OFF. ON and OFF times are chosen as 500
ms and 100 ms respectively so that a pleasant rotating LED effect is displayed. You should
compile and run the program as follows (unless you are using the Geany IDE):
pigpio
The pigpio program of the project is shown in Figure 5.5 (Program: RotateLEDs2.c). The
program is the same as the wiringPi version with a few small modifications. You should
compile and run the program as follows:
/*------------------------------------------------------------------
ROTATE LEDS
===========
In this program 4 LEDs are connected to GPIO ports 27, 17, 3 and 2
through 470 Ohm resistors. The program turns ON the LEDs in a
rotating manner. The ON and OFF times are chosen as 500ms and 100ms
respectively.
● 117
C Programming on Raspberry Pi
#define ON 1
#define OFF 0
//
// Configure ports as outputs and turn OFF LEDs
//
void Configure()
{
char k;
for(k = 0; k < 4; k++)
{
gpioSetMode(LEDs[k], PI_OUTPUT);
gpioWrite(LEDs[k], OFF);
}
}
//
// Start of MAIN program
//
int main(void)
{
char j;
gpioInitialise(); // Initialize pigpio
Configure(); // Configure ports
//
// Now rotate the LEDs
//
while(1) // Endless loop
{
for(j = 0; j < 4; j++)
{
gpioWrite(LEDs[j], ON); // LED ON
time_sleep(0.5);
gpioWrite(LEDs[j], OFF); // LED OFF
time_sleep(0.1);
}
}
}
Figure 5.5 Program RotateLEDs2.c
Suggestions:
You should increase the LED number to 8 and modify program 5.4 accordingly.
● 118
Chapter 5 ● Hardware Projects using C
Description:
In this project, 4 LEDs are connected to the ESP32 DevKitC as in the previous project. The
LEDs are turned ON and OFF randomly to give a pleasant visual effect.
Aim:
This project aims to show how the random number generator function can be used in a
program.
Block diagram:
Circuit diagram:
Program Listing:
wiringPi
The program listing of the project is very simple and shown in Figure 5.6 (Program:
Christmas.c).
/*------------------------------------------------------------------
CHRISTMAS LIGHTS
================
In this program 4 LEDs are connected to GPIO ports 27, 17, 3 and 2
through 470 Ohm resistors. The program turns ON/OFF the LEDs in a
random manner.
● 119
C Programming on Raspberry Pi
//
// Configure ports as outputs and turn OFF LEDs
//
void Configure()
{
char k;
for(k = 0; k < 4; k++)
{
pinMode(LEDs[k], OUTPUT);
digitalWrite(LEDs[k], OFF);
}
}
//
// Display the random pattern
//
void Display(unsigned int No)
{
digitalWrite(LEDs[3], (No & 8) >> 3);
digitalWrite(LEDs[2], (No & 4) >> 2);
digitalWrite(LEDs[1], (No & 2) >> 1);
digitalWrite(LEDs[0], (No & 1));
}
//
// Start of MAIN program
//
int main(void)
{
char j;
unsigned int ran;
wiringPiSetup();
Configure();
while(1)
{
ran=rand() % 15;
Display(ran);
delay(200);
}
}
Figure 5.6 Program Christmas.c
At the beginning of the program, an array called LEDs is set up to store the port numbers
of the LEDs used in the project. Function Configure is called to configure the LED ports as
● 120
Chapter 5 ● Hardware Projects using C
outputs. A random number is generated and is set to be between 0 and 15 and stored in the
variable ran. Function Display is then called to extract the bits of this number and turn the
appropriate LED ON or OFF. Function Display receives an integer number between 1 and
15 and extracts the bits of this number. For example, if the number is 12 (binary 1100),
the left two LEDs (LED1 and LED2) are turned ON.
Modified program
The program given in Figure 5.6 can be made more efficient by modifying the function
Display. The new program listing is shown in Figure 5.7 (Program:Christmasmod.c).
Here, function Display has two arguments: No is the number to be displayed as a binary
bit pattern on the LEDs, and L the width of the number in bits. Bits are extracted from the
number and are then sent to the LEDs to turn the correct LED ON and OFF. The program
runs in an endless loop, where a random number is generated between 0 and 15 and
stored in the variable ran. Function Display is then called as Display(ran, 4) to turn the
appropriate LEDs ON and OFF. Notice the width of the number is 4-bits (there are 4 LEDs).
/*------------------------------------------------------------------
CHRISTMAS LIGHTS
================
In this program 4 LEDs are connected to GPIO ports 27, 17, 3 and 2
through 470 Ohm resistors. The program turns ON/OFF the LEDs in a
random manner.
//
// Configure ports as outputs and turn OFF LEDs
//
void Configure()
{
char k;
for(k = 0; k < 4; k++)
{
● 121
C Programming on Raspberry Pi
pinMode(LEDs[k], OUTPUT);
digitalWrite(LEDs[k], OFF);
}
}
//
// Display the random pattern
//
void Display(unsigned int No, unsigned int L)
{
unsigned int j, i, m, p, r;
m = L - 1;
for(i = 0; i < L; i++)
{
j = 1;
for(p = 0; p < m; p++)j = 2*j; // Power of 2
r = No & j;
if(r > 0)r = 1;
digitalWrite(LEDs[i], r);
m--;
}
}
//
// Start of MAIN program
//
int main(void)
{
char j;
unsigned int ran;
wiringPiSetup();
Configure();
while(1)
{
ran=rand() % 15;
Display(ran, 4);
delay(200);
}
}
Figure 5.7 ProgramChristmasmod.c
You can use GPIO numbering in this program by changing the following two statements:
● 122
Chapter 5 ● Hardware Projects using C
pigpio
The pigpio program of the project is shown in Figure 5.8 (Program: Christmasmod2.c).
The program is the same as the wiringPi version with a few small modifications.
/*------------------------------------------------------------------
CHRISTMAS LIGHTS
================
In this program 4 LEDs are connected to GPIO ports 27, 17, 3 and 2
through 470 Ohm resistors. The program turns ON/OFF the LEDs in a
random manner.
#define OFF 0
#define ON 1
//
// Configure ports as outputs and turn OFF LEDs
//
void Configure()
{
char k;
for(k = 0; k < 4; k++)
{
gpioSetMode(LEDs[k], PI_OUTPUT);
gpioWrite(LEDs[k], OFF);
}
}
//
// Display the random pattern
● 123
C Programming on Raspberry Pi
//
void Display(unsigned int No, unsigned int L)
{
unsigned int j, i, m, p, r;
m = L - 1;
for(i = 0; i < L; i++)
{
j = 1;
for(p = 0; p < m; p++)j = 2*j; // Power of 2
r = No & j;
if(r > 0)r = 1;
gpioWrite(LEDs[i], r);
m--;
}
}
//
// Start of MAIN program
//
int main(void)
{
char j;
unsigned int ran;
gpioInitialise();
Configure();
while(1)
{
ran=rand() % 15;
Display(ran, 4);
time_sleep(0.2);
}
}
Figure 5.8 Program Christmasmod2.c
Suggestions
The number of LEDs can be increased by connecting more in series and in parallel and
placed for example on a Christmas tree.
● 124
Chapter 5 ● Hardware Projects using C
Description:
In this project, 8 LEDs are connected to the Raspberry Pi. The program counts up from 0
to 255 where the count is displayed on the 8 LEDs in binary format.
Aim:
This project aims to show how any 8 port pins can be grouped and treated as an 8-bit
output port.
Block diagram:
The block diagram of the project is shown in Figure 5.9. The LEDs are connected to the
following GPIO port pins:
Circuit Diagram:
The circuit diagram of the project is shown in Figure 5.10. 8 LEDs are connected to GPIO
● 125
C Programming on Raspberry Pi
Program listing:
wiringPi
/*------------------------------------------------------------------
BINARY UP COUNTER
=================
In this program 8 LEDs are connected to GPIO ports through current
limiting resistors. The program counts up in binary every 500ms.
//
● 126
Chapter 5 ● Hardware Projects using C
//
// Display data on ports
//
void Display(unsigned int No, unsigned int L)
{
unsigned int j, i, m, p, r;
m = L - 1;
for(i = 0; i < L; i++)
{
j = 1;
for(p = 0; p < m; p++)j = 2*j; // Power of 2
r = No & j;
if(r > 0)r = 1;
digitalWrite(LEDs[i], r);
m--;
}
}
//
// Start of MAIN program
//
int main(void)
{
char j, count = 0;
wiringPiSetup();
Configure();
while(1)
{
Display(count, 8);
if(count == 255)
count = 0;
else
● 127
C Programming on Raspberry Pi
count++;
delay(500);
}
}
Figure 5.11 Program listing
At the beginning of the program, an array called LEDs is set up to store the port numbers of
the LEDs used in the project. The variable count is initialised to zero. Function Configure is
called to configure the ports as outputs. Inside the main program function Display is called
and count is sent as the argument. This function extracts the bits of count and turns the
appropriate LEDs ON or OFF. Number 8 is also sent to function Display as an argument
since there are 8 LEDs (i.e. the width of the number is 8 bits). The LEDs count up in binary
from 0 to 255 continuously with a 500ms delay between each count. The LED counting
pattern should be as shown in Figure 5.12.
You can use GPIO numbering in this program by changing the following two statements:
pigpio
The pigpio program of the project is shown in Figure 5.13 (Program: Counter2.c). The
program is the same as the wiringPi version with a few small modifications.
● 128
Chapter 5 ● Hardware Projects using C
/*------------------------------------------------------------------
BINARY UP COUNTER
=================
In this program 8 LEDs are connected to GPIO ports through current
limiting resistors. The program counts up in binary every 500ms.
#define OFF 0
#define ON 1
int LEDs[] = {11, 9, 10, 22, 27, 17, 3, 2}; // GPIO 11,9,10,22,27,17,3,2
//
// Configure ports as outputs and turn OFF LEDs
//
void Configure()
{
char k;
for(k = 0; k < 8; k++)
{
gpioSetMode(LEDs[k], PI_OUTPUT);
gpioWrite(LEDs[k], OFF);
}
}
//
// Display data on ports
//
void Display(unsigned int No, unsigned int L)
{
unsigned int j, i, m, p, r;
m = L - 1;
for(i = 0; i < L; i++)
{
j = 1;
for(p = 0; p < m; p++)j = 2*j; // Power of 2
r = No & j;
if(r > 0)r = 1;
● 129
C Programming on Raspberry Pi
gpioWrite(LEDs[i], r);
m--;
}
}
//
// Start of MAIN program
//
int main(void)
{
char j, count = 0;
gpioInitialise();
Configure();
while(1)
{
Display(count, 8);
if(count == 255)
count = 0;
else
count++;
time_sleep(0.5);
}
}
Figure 5.13 Program Counter2.c
Description:
In this project, 8 LEDs are connected to the Raspberry Pi as in the previous project. Also, a
push-button switch (or simply a button) is connected to GPIO pin 14. When the button is
not pressed, the program counts up, and when the button is pressed, the program counts
down.
Aim:
This project aims to show how a push-button switch can be connected to the Raspberry Pi
and how the port can be configured as an input.
Block diagram:
The block diagram of the project is shown in Figure 5.14. The LEDs and the button are
connected to the following GPIO port pins:
● 130
Chapter 5 ● Hardware Projects using C
Circuit diagram:
The circuit diagram of the project is as in Figure 5.15. 8 LEDs are connected to GPIO ports
through 470 Ohm current limiting resistors. Notice the button can be connected in two
different ways to a GPIO port. In Figure 5.16, the output of the button is at logic 1 and goes
to logic 0 when the button is pressed. In Figure 5.17, the output of the button is at logic 0
and goes to logic 1 when the button is pressed. In this example, the second method is used.
Thus, the GPIO pin is normally at logic 0 and goes to logic 1 when the button is pressed.
● 131
C Programming on Raspberry Pi
Program listing:
wiringPi
The program listing of the project is shown in Figure 5.18 (Program: UpDown.c).
● 132
Chapter 5 ● Hardware Projects using C
/*------------------------------------------------------------------
BINARY UP/DOWN COUNTER
======================
In this program 8 LEDs are connected to GPIO ports through current
limiting resistors. Additionally, a button is used. The program counts
up/down in binary every 500ms. By default it counts up. When the
button is pressed it counts down as long as the button is kept pressed
//
// Configure LED ports as outputs,turn OFF LEDs. Also configure the
// Button port as input
//
void Configure()
{
char k;
for(k = 0; k < 8; k++)
{
pinMode(LEDs[k], OUTPUT);
digitalWrite(LEDs[k], OFF);
}
pinMode(Button, INPUT);
}
//
// Display data on ports
//
void Display(unsigned int No, unsigned int L)
{
unsigned int j, i, m, p, r;
m = L - 1;
for(i = 0; i < L; i++)
● 133
C Programming on Raspberry Pi
{
j = 1;
for(p = 0; p < m; p++)j = 2*j; // Power of 2
r = No & j;
if(r > 0)r = 1;
digitalWrite(LEDs[i], r);
m--;
}
}
//
// Start of MAIN program. When the button is not pressed,increment
// count. When the button is pressed, cound down from the last value
//
int main(void)
{
char j, count = 0;
char Button_State;
wiringPiSetup();
Configure();
while(1)
{
Display(count, 8);
Button_State = digitalRead(Button);
if(Button_State == UP)
{
if(count == 255)
count = 0;
else
count++;
}
else if(Button_State == DOWN)
{
if(count == 0)
count = 255;
else
count--;
}
delay(500);
}
}
Figure 5.18 Program UpDown.c
● 134
Chapter 5 ● Hardware Projects using C
At the beginning of the program, an array called LEDs is set up to store the port numbers
of the LEDs used in the project. Name Button is assigned to GPIO port 14, and names
UP and DOWN are assigned to 0 and 1 respectively. Global variable count is initialised to
zero. The GPIO ports where the LEDs are connected are then configured as output ports,
and the GPIO port where the Button is connected is configured as an input port. Inside the
main program, function Display is called and count is sent as the argument. The state of
the Button is then read: if the Button is not pressed (Button_State equal to UP) then an
UP count is performed. If on the other hand the Button is pressed, (Button_State equal
to DOWN) a DOWN count is performed. Notice variable count is reset at the end of the
counts. i.e. during an up count when the count reaches 255 it is reset to 0 on the next cycle.
Similarly, on a down count when the count reaches 0, it is reset to 255 on the next cycle.
You can use GPIO numbering in this program by changing the following two statements:
pigpio
The pigpio program of the project is shown in Figure 5.19 (Program: UpDown2.c). The
program is the same as the wiringPi version with a few small modifications.
/*------------------------------------------------------------------
BINARY UP/DOWN COUNTER
======================
In this program 8 LEDs are connected to GPIO ports through current
limiting resistors. Additionally, a button is used. The program counts
up/down in binary every 500ms. By default it counts up. When the
button is pressed it counts down as long as the button is kept pressed
#define OFF 0
#define ON 1
#define Button 14
#define UP 0
#define DOWN 1
● 135
C Programming on Raspberry Pi
//
// Configure LED ports as outputs,turn OFF LEDs. Also configure the
// Button port as input
//
void Configure()
{
char k;
for(k = 0; k < 8; k++)
{
gpioSetMode(LEDs[k], PI_OUTPUT);
gpioWrite(LEDs[k], OFF);
}
gpioSetMode(Button, PI_INPUT);
}
//
// Display data on ports
//
void Display(unsigned int No, unsigned int L)
{
unsigned int j, i, m, p, r;
m = L - 1;
for(i = 0; i < L; i++)
{
j = 1;
for(p = 0; p < m; p++)j = 2*j;
// Power of 2
r = No & j;
if(r > 0)r = 1;
gpioWrite(LEDs[i], r);
m--;
}
}
//
// Start of MAIN program. When the button is not pressed,increment
// count. When the button is pressed, cound down from the last value
//
int main(void)
{
char j, count = 0;
char Button_State;
gpioInitialise();
Configure();
● 136
Chapter 5 ● Hardware Projects using C
while(1)
{
Display(count, 8);
Button_State = gpioRead(Button);
if(Button_State == UP)
{
if(count == 255)
count = 0;
else
count++;
}
else if(Button_State == DOWN)
{
if(count == 0)
count = 255;
else
count--;
}
time_sleep(0.5);
}
}
Figure 5.19 Program UpDown2.c
Description:
This is a simple dice project based on LEDs and a push-button switch. The LEDs are
organised to simulate the look of the faces of real dice. When the push-button switch
is pressed, a random number is generated between 1 and 6 and displayed on the LEDs.
Normally the LEDs are all OFF to indicate that the system is ready to generate a new dice
number. After 3 seconds the LEDs turn OFF again.
Aim:
Block diagram:
● 137
C Programming on Raspberry Pi
As shown in Figure 5.21, the LEDs are organised such that when they turn ON, they indicate
the numbers as in a real dice. The operation of the project is as follows: Normally the LEDs
are all OFF to indicate that the system is ready to generate a new dice number. Pressing
the switch generates a random dice number between 1 and 6 and displays on the LEDs for
3 seconds. After 3 seconds the LEDs turn OFF again.
Circuit diagram:
The circuit diagram of the project is shown in Figure 5.22. 7 LEDs are connected to GPIO
pins 9, 10, 22, 27, 17, 3 and 2 through 470 Ohm current limiting resistors. The connection
is as follows:
The push-button switch is connected to GPIO pin 14 through a 10K pull-down resistor so
the button output is at logic 0 and goes to logic 1 when the button is pressed.
● 138
Chapter 5 ● Hardware Projects using C
Program listing:
The relationship between the required number and the LEDs to be turned ON is shown in
Table 5.1. For example, to display number 1, only LED D4 must be turned ON. Similarly, to
display number 3, LEDs D2, D4, D6 must be turned ON, and so on.
wiringPi
The program listing of the project is shown in Figure 5.23 (Program: Dice.c).
/*------------------------------------------------------------------
DICE WITH LEDs
==============
In this program 7 LEDs are connected in the form of a dice face to
GPIO ports through current limiting resistors. Additionally, a button
is used. Pressing the button displays a dice number between 1 and 6.
The number is displayed for 3 seconds.
● 139
C Programming on Raspberry Pi
File : Dice.c
Date : December 2020
--------------------------------------------------------------------*/
#include <wiringPi.h>
#include <stdlib.h>
#define D1 13
#define D5 0
#define D2 12
#define D6 9
#define D4 2
#define D3 3
#define D7 8
//
// Configure LED ports as outputs,turn OFF LEDs. Also configure the
// Button port as input
//
void Configure()
{
char k;
for(k = 0; k < 7; k++)
{
pinMode(LEDs[k], OUTPUT);
digitalWrite(LEDs[k], OFF);
}
pinMode(Button, INPUT);
}
//
// Display data on ports
//
void All_Off()
{
char i;
for(i = 0; i < 7; i++)digitalWrite(LEDs[i], LOW);
}
//
// Start of MAIN program
● 140
Chapter 5 ● Hardware Projects using C
//
int main(void)
{
int dice;
wiringPiSetup();
Configure();
while(1)
{
All_Off();
while(digitalRead(Button) == 0);
dice = (rand() % 6) + 1; // 1 to 6
switch(dice)
{
case 1: // Dice 1?
digitalWrite(D4, HIGH);
break;
case 2: // Dice 2?
digitalWrite(D2, HIGH);
digitalWrite(D6, HIGH);
break;
case 3: // Dice 3?
digitalWrite(D2, HIGH);
digitalWrite(D4, HIGH);
digitalWrite(D6, HIGH);
break;
case 4: // Dice 4?
digitalWrite(D1, HIGH);
digitalWrite(D3, HIGH);
digitalWrite(D5, HIGH);
digitalWrite(D7, HIGH);
break;
case 5: // Dice 5?
digitalWrite(D1, HIGH);
digitalWrite(D3, HIGH);
digitalWrite(D4, HIGH);
digitalWrite(D5, HIGH);
digitalWrite(D7, HIGH);
break;
case 6: // Dice 6?
digitalWrite(D1, HIGH);
digitalWrite(D2, HIGH);
digitalWrite(D3, HIGH);
digitalWrite(D5, HIGH);
digitalWrite(D6, HIGH);
digitalWrite(D7, HIGH);
● 141
C Programming on Raspberry Pi
break;
}
delay(3000);
}
}
Figure 5.23 Program Dice.c
At the beginning of the program, Button is assigned to GPIO port 14. Similarly, LEDs D1,
D2, D3, D4, D5, D6, D7 are assigned to GPIO ports 9, 10, 22, 27, 17, 3, and 2 respectively
(notice wiringPi port numbers are different). In function Configure, all LEDs are configured
as outputs and the Button is configured as an input. Function All_Off turns OFF all the
LEDs.
The main program is executed in an endless loop. Inside this loop, all the LEDs are turned
OFF to start with. The program then waits until the Button is pressed. When the button is
pressed a random number is generated between 1 and 6 (rand() % 6 generates random
integer numbers between 0 and 5 and 1 is added to these numbers so that the numbers
are between 1 and 6). A switch statement is then used to turn ON the appropriate LEDs
depending upon the generated number. The program displays the generated number for 3
seconds. After this time, the above process is repeated.
You can use GPIO numbering in this program by changing the following two statements:
● 142
Chapter 5 ● Hardware Projects using C
Modified program:
The program given in Figure 5.23 can be made shorter and more efficient if we define a
two-dimensional array to store the LEDs that must be turned ON to display a given dice
number. Figure 5.25 shows the modified program (Program: Dicemod.c). At the beginning
of this program, a two-dimensional array called Numbers is created to store the port
numbers (in wiringPi format) that must be turned ON to display a given number. Here, each
row is terminated with 99 and the first row is not used since its index is 0, but dice numbers
are between 1 and 6.
intNumbers[][7] = {
{0,99}, // Dummy
{2,99}, // Display 1
{12, 9,99}, // Display 2
{12, 2, 9,99}, // Display 3
{13, 0, 3, 8,99}, // Display 4
{13, 0, 3, 8, 2,99}, // Display 5
{13, 0, 12, 9, 8, 3,99} // Display 6
};
As before, function Configure configures the LED ports as outputs and the Button port as
an input. Function All_OFF turns OFF all the LEDs. Inside the main program, a while loop
is formed which runs until the program is stopped by the user. A random integer number
between 1 and 6 is then generated and stored in variable dice. A while loop is formed to
find the number of elements in the required Numbers array for row dice. This number is
stored in variable nlen. The ports specified by row dice of array Numbers are then turned
ON. The number is displayed for 3 seconds and after this time, all LEDs are turned OFF and
the program repeats.
/*------------------------------------------------------------------
DICE WITH LEDs
==============
In this program 7 LEDs are connected in the form of a dice face to
GPIO ports through current limiting resistors. Additionally, a button
is used. Pressing the button displays a dice number between 1 and 6.
The number is displayed for 3 seconds.
● 143
C Programming on Raspberry Pi
//
// Configure LED ports as outputs,turn OFF LEDs. Also configure the
// Button port as input
//
void Configure()
{
char k;
for(k = 0; k < 7; k++)
{
pinMode(LEDs[k], OUTPUT);
digitalWrite(LEDs[k], OFF);
}
pinMode(Button, INPUT);
}
//
// Display data on ports
//
void All_Off()
{
char j;
for(j = 0; j < 7; j++)digitalWrite(LEDs[j], LOW);
}
//
// Start of MAIN program
//
int main(void)
{
int dice, i,nlen;
wiringPiSetup();
● 144
Chapter 5 ● Hardware Projects using C
Configure();
while(1)
{
All_Off(); // All OFF
while(digitalRead(Button) == 0); // Wait button
dice = (rand() % 6) + 1; // 1 to 6
i = 0;
nlen = 0;
delay(3000);
}
}
Figure 5.25 Program Dicemod.c
pigpio
The pigpio program of the project is shown in Figure 5.26 (Program: Dice2.c). The program
is the same as the wiringPi version with a few small modifications.
/*------------------------------------------------------------------
DICE WITH LEDs
==============
In this program 7 LEDs are connected in the form of a dice face to
GPIO ports through current limiting resistors. Additionally, a button
is used. Pressing the button displays a dice number between 1 and 6.
The number is displayed for 3 seconds.
● 145
C Programming on Raspberry Pi
#define OFF 0
#define ON 1
#define Button 14
//
// Configure LED ports as outputs,turn OFF LEDs. Also configure the
// Button port as input
//
void Configure()
{
char k;
for(k = 0; k < 7; k++)
{
gpioSetMode(LEDs[k], PI_OUTPUT);
gpioWrite(LEDs[k], OFF);
}
gpioSetMode(Button, PI_INPUT);
}
//
// Display data on ports
//
void All_Off()
{
char j;
for(j = 0; j < 7; j++)gpioWrite(LEDs[j], OFF);
}
//
// Start of MAIN program
//
int main(void)
{
int dice, i,nlen;
gpioInitialise();
● 146
Chapter 5 ● Hardware Projects using C
Configure();
while(1)
{
All_Off(); // All OFF
while(gpioRead(Button) == 0); // Wait button
dice = (rand() % 6) + 1; // 1 to 6
i = 0;
nlen = 0;
while(Numbers[dice][i] != 99) // No of elements
{
nlen++;
i++;
}
time_sleep(3);
}
}
Figure 5.26 Program Dice2.c
Description:
In this project, an RGB LED is used to generate different colours of light, just like a colour
wand.
Aim:
This project aims to show how an RGB LED can be used in a program to generate different
colours.
Block diagram:
● 147
C Programming on Raspberry Pi
Circuit diagram:
The circuit diagram of the project is as shown in Figure 5.28. The R, G, and B LED pins
are connected to GPIO pins 17, 27, and 22 of the Raspberry Pi (wiringPi pins 0, 2, 3)
respectively through 470 Ohm current limiting resistors.
The project can be built into a wand and used in games, in a flower vase, or an aquarium.
Figure 5.29 shows a typical RGB LED. Notice the component has 4 legs where the longest
leg is the common pin (cathode or anode).
● 148
Chapter 5 ● Hardware Projects using C
Program listing:
wiringPi
The program listing of the project is very simple and shown in Figure 5.30 (Program:RGB.c).
/*------------------------------------------------------------------
RGB LED
=======
In this program an RGB LED is connected to the Raspberry Pi. The
LED changes colours every 200 ms which gives a nice visual effect.
#define R 0 // GPIO 17
#define G 2 // GPIO 27
#define B 3 // GPIO 22
//
// Configure LED ports as outputs
//
void Configure()
{
pinMode(R, OUTPUT); // Red port
pinMode(G, OUTPUT); // Green port
pinMode(B, OUTPUT); // Blue por
}
//
// Start of MAIN program
//
int main(void)
{
int Red, Green, Blue;
wiringPiSetup();
Configure();
while(1)
{
Red = rand() % 2; // Between 0,1
● 149
C Programming on Raspberry Pi
At the beginning of the program, the GPIO pins where Red, Green and Blue pins are
connected, are defined as R, G, and B respectively. These port pins are then configured
as outputs. The remainder of the program runs in an endless loop where inside this loop
random numbers are generated between 0 and 1 (notice that when using the rand function,
the lower bound is included, but the upper bound is excluded) for all three colours and the
generated numbers are sent to the corresponding ports. Thus, for example, if number 1 is
generated for the Red port, red is turned ON, and so on.
You can use GPIO numbering in this program by changing the following two statements:
#define R 17
#define G 27
#define B 22
and
wiringPiSetupGpio()
pigpio
The pigpio program of the project is shown in Figure 5.31 (Program: RGB2.c). The program
is the same as the wiringPi version with a few small modifications.
/*------------------------------------------------------------------
RGB LED
=======
In this program an RGB LED is connected to the Raspberry Pi. The
LED changes colours every 200 ms which gives a nice visual effect.
● 150
Chapter 5 ● Hardware Projects using C
#include <pigpio.h>
#include <stdlib.h>
#define R 17 // GPIO 17
#define G 27 // GPIO 27
#define B 22 // GPIO 22
//
// Configure LED ports as outputs
//
void Configure()
{
gpioSetMode(R, PI_OUTPUT); // Red port
gpioSetMode(G, PI_OUTPUT); // Green port
gpioSetMode(B, PI_OUTPUT); // Blue por
}
//
// Start of MAIN program
//
int main(void)
{
int Red, Green, Blue;
gpioInitialise();
Configure();
while(1)
{
Red = rand() % 2; // Between 0,1
Green = rand() %2; // Between 0,1
Blue = rand() %2; // Between 0,1
Suggestions:
In the program described in Figure 5.30 and 5.31, the delay time is set to 200 ms. Try
changing this time and see its effects.
● 151
C Programming on Raspberry Pi
Description:
In this project, an LED is connected to Raspberry Pi. The program changes the brightness
of the LED by changing the voltage applied to it using PWM.
Aim:
This project aims to show how PWM type waveform can be generated in a program and how
this waveform can be effectively used to vary the voltage applied to an LED.
Circuit diagram:
The circuit diagram of the project is as shown in Figure 4.10. An LED is connected to GPIO
port 2 through a 470 Ohm current limiting resistor.
Program listing:
wiringPi
The fading of the LED is done by applying a PWM waveform to the LED and changing the
duty cycle of this waveform, effectively changing the average voltage applied to the LED.
Figure 5.32 shows a typical PWM waveform. The duty cycle is defined as the ratio of the
ON time to the period:
or
Thus for example, when the duty cycle is 0%, ON time is 0, and when the duty cycle is
100% the OFF time is 0.
● 152
Chapter 5 ● Hardware Projects using C
The following header file must be included at the beginning of the program:
#include <softPwm.h>
Also, the library file pthread must be included during the compile time. For example, if the
program name is test.c, the program can be compiled as follows:
This creates a software-controlled PWM pin. You can use any GPIO pin. Pin numbering
will be that of the wiringPiSetup() function. The basic pulse unit is 100 microseconds.
Therefore, as an example, softPwmCreate(LED, 0, 200) creates a PWM waveform with
a period of T = 20 ms (200 x 100 microseconds = 20 ms).
The following function updates the PWM value on the specified pin:
The value indicates how long the pulse will be ON. For example, assuming the above
softPwmCreate values, softPwmWrite(LED, 100) means the PWM ON time will be
for 100 x 100 microseconds = 10 ms. This corresponds to 50% duty cycle (i.e. 10 ms
ON time + 10 ms OFF time with 20 ms period). Similarly, using the above settings,
softPwmWrite(LED, 200) will correspond to 20 ms ON time, i.e. 100% duty cycle.
In this project, the period of the PWM waveform is set to 50 Hz (20 ms). The waveform
ON time is varied from 0% to 100% with the softPwmWrite value changing from 0 to
200 as described above.
At the beginning of the program, LED is assigned to 8 which corresponds to GPIO 2. Two
for loops are formed. Inside the first for loop, the PWM ON time is varied from 0 to 200
(i.e. 0 to 20 ms = 100% duty cycle). A 25 ms delay is used between each output change,
therefore, with 200 iterations, it takes 200 x 25 ms = 5000ms or 5 seconds for the LED
to go from OFF to full brightness. Inside the second for loop, the brightness of the LED is
decreased from full brightness to full OFF at the same rate.
The program listing of the project is very simple and shown in Figure 5.33 (Program:
FadeLED.c). The program was compiled as follows:
● 153
C Programming on Raspberry Pi
/*----------------------------------------------------------------
CHANGING LED BRIGHTNESS
=======================
In this program an LED is connected to GPIO 2. THe brightness of
the LED is changed using PWM waveform
//
// Configure LED port as output
//
void Configure()
{
pinMode(LED, OUTPUT); // LED output
digitalWrite(LED, LOW); // LED OFF
}
//
// Start of MAIN program
//
int main(void)
{
int k;
wiringPiSetup();
Configure();
softPwmCreate(LED, 0, 200); // PWM T=20ms
while(1)
{
for(k = 0; k <= 200; k++) // Increase brightness
{
softPwmWrite(LED, k);
delay(25); // 25ms delay
}
● 154
Chapter 5 ● Hardware Projects using C
{
softPwmWrite(LED, k);
delay(25); // 25ms delay
}
}
}
Figure 5.33 Program FadeLED.c
You can use GPIO numbering in this program by changing the following two statements:
#define LED 2
and
wiringPiSetupGpio()
Note: The author measured the output waveform and the correct PWM waveform is gen-
erated for up to several kHz. Above about 4 kHz, the generated waveform is not accurate
but you should be able to use it for many applications.
pigpio
The pigpio program of the project is shown in Figure 5.34 (Program: FadeLED2.c). In
this program, the PWM frequency is set to 50Hz and the duty cycle is changed from 0% to
100%. pigpio provides the following functions to generate and modify a PWM waveform:
gpioPWM(PWM port, duty cycle): Start PWM. Duty cycle ranges from 0 (0%) to 255
(100%)
gpioGetPWMdutycycle(PWM port): Return the PWM duty cycle
gpioSetPWMrange(PWM port, user range): Set the duty cycle range
gpioGetPWMrange(PWM port): Return the set duty cycle range
gpioSetPWMfrequency(PWM port, frequency): Set the PWM frequency
gpioGetPWMfrequency(PWM port): Return the PWM frequency
Two for loops are used in the program. The first loop increases the duty cycle every 50 ms
from 0% to 100%. The second for loop decreases the duty cycle from 100% to 0%.
/*----------------------------------------------------------------
CHANGING LED BRIGHTNESS
=======================
In this program an LED is connecte dto GPIO 2. THe brightness of
the LED is changed using PWM waveform
● 155
C Programming on Raspberry Pi
------------------------------------------------------------------*/
#include <pigpio.h>
#define LED 2
//
// Configure LED port as output
//
void Configure()
{
gpioSetMode(LED, PI_OUTPUT); // LED output
gpioWrite(LED, 0); // LED OFF
}
//
// Start of MAIN program
//
int main(void)
{
int k;
gpioInitialise();
Configure();
gpioSetPWMfrequency(LED, 50); // Set to 50Hz
while(1)
{
for(k = 0; k <= 255; k++) // Increase brightness
{
gpioPWM(LED, k);
time_sleep(0.025); // 25ms delay
}
● 156
Chapter 5 ● Hardware Projects using C
Description:
In this project, a passive buzzer is connected to GPIO port pin 2 (wiringPi pin 8) of the
Raspberry Pi. The buzzer generates sound with frequencies randomly changing between
100 Hz and 1 kHz.
Aim:
This project aims to show how a passive buzzer can be connected to a Raspberry Pi and
how, with different frequencies, sound can be generated using a buzzer.
Circuit diagram:
There are two types of buzzers: Passive and Active. Passive buzzers require an AC signal
in the audible frequency range to operate. Active buzzers on the other hand have built-in
oscillators that generate fixed frequency sound when logic 1 is applied to them, just like
turning ON and LED. The frequency of an active buzzer can be changed by the ON/OFF
frequency of the applied 1/0 logic signal. In this project, a passive buzzer is used and a
PWM signal with different frequencies is applied to the buzzer. Figure 5.36 shows the circuit
diagram of the project.
● 157
C Programming on Raspberry Pi
Program listing:
wiringPi
The program listing of the project is very simple and shown in Figure 5.37
(Program:RandomBuzzer.c).
/*----------------------------------------------------------------
RANDOM BUZZER
=============
In this program a passive buzzer is connected to the Raspberry Pi.
The program generates random numbers between 100 and 5000 and uses
these numbers to set the frequency of a PWM waveform which is sent
to the buzzer. The duty cycle is set to 50%
//
// Configure LED port as output
//
void Configure()
{
pinMode(Buzzer, OUTPUT); // LED output
digitalWrite(Buzzer, LOW); // LED OFF
}
//
// Start of MAIN program. Generate random numbers between 10 and 100
// which correspond to PWM periods 1 ms and 10 ms (i.e. frequencies
// 1 kHz and 100 HZ and send to the buzzer every 250 ms.
//
int main(void)
{
int freq, duty;
● 158
Chapter 5 ● Hardware Projects using C
while(1)
{
freq = rand() % 91; // Between 0-90
freq = freq + 10; // Between 10-100
duty = freq / 2; // Duty cycle
softPwmCreate(Buzzer, 0, freq); // Frequency
softPwmWrite(Buzzer, duty); // Duty cycle
delay(250); // 250ms delay
}
}
Figure 5.37 Program RandomBuzzer.c
In this project, the duty cycle of the PWM waveform is set to 50%, and the frequency
is changed between 100 Hz and 1 kHz. A random number is used to generate random
numbers between 10 and 100. These numbers are used to set the frequency of the PWM
waveform. A 250 ms delay is used between each output. Notice with 10, the period of the
PWM waveform is 10 x 100μs = 1 ms (1 kHz). With 100 the period is 100 x 100μs = 10 ms
(100 Hz). In this program, GPIO numbering is used.
pigpio
/*----------------------------------------------------------------
RANDOM BUZZER
=============
In this program a passive buzzer is connecte dto the RAspberry Pi
and random numbers are generated between 100 and 1000 to correspond
to frequencies. PWM waveforms are generated with these frequencies
and sent to the buzzer LED.
#define Buzzer 2
//
// Configure LED port as output
● 159
C Programming on Raspberry Pi
//
void Configure()
{
gpioSetMode(Buzzer, PI_OUTPUT); // Buzzer output
gpioWrite(Buzzer, 0); // Buzzer OFF
}
//
// Start of MAIN program. Generate PWM waveforms with 100 Hz to
// 1000 Hz and send to the buzzer
//
int main(void)
{
int freq;
gpioInitialise();
Configure();
while(1)
{
freq = rand() % 901; // 0 - 900
freq = 100 + freq; // 100 - 1000
gpioPWM(Buzzer, 128); // Duty = 50%
gpioSetPWMfrequency(Buzzer, freq);
time_sleep(0.25);
}
}
Figure 5.38 Program RandomBuzzer2.c
Suggestion:
In Figures 5.37 and 5.38, only the frequency is randomly changed. Modify the program to
change the duty cycle and observe the difference.
Description:
In this project, a DHT11 temperature and relative humidity sensor chip is used to get
ambient temperature and relative humidity. The readings are displayed every 5 seconds
on screen.
Aim:
This project aims to show how the popular DHT11 relative humidity and temperature sensor
chip can be programmed using C on a Raspberry Pi.
● 160
Chapter 5 ● Hardware Projects using C
Block diagram:
Circuit diagram:
In this project, the DHT11 relative humidity and temperature sensor chip is used. The
standard DHT11 is a 4-pin digital output device (only 3 pins are used) as shown in Figure
5.40, having pins +V, GND, and Data. The Data pin must be pulled-up to +V through
a 10K resistor. The chip uses a capacitive humidity sensor and thermistor to measure
ambient temperature. Data output is available from the chip approx. every second. The
basic features of the DHT11 are:
• 3 to 5V operation.
• 2.5mA current consumption (during a conversion).
• Temperature reading in the range 0-50ºC with an accuracy of ±2ºC.
• Humidity reading in the range 20-80% with 5% accuracy.
• Breadboard compatible with 0.1-inch pin spacing.
In this example, the DHT11 module with a built-in 10K pull-up resistor, available from
Elektor, is used. This is a 3-pin device with a pin layout shown in Figure 5.41.
● 161
C Programming on Raspberry Pi
Figure 5.42 shows the circuit diagram of the project. The data output of the DHT11 is
connected to pin GPIO 2 (wiringPi pin 8) of the Raspberry Pi.
The DHT11 sensor chip operates through a single data pin. Data is extracted by applying
accurate timing pulses to the chip. 5 bytes (40 bits) of data is received from the chip, 2
bytes of humidity data(1-byte integral, 1-byte decimal), 2 bytes of temperature data (1-
byte integral, 1 byte decimal), 1-byte of checksum data.
The procedure to extract temperature and humidity is as follows (MCU is the Raspberry Pi
here):
• After the chip is powered up, we should wait one second for the chip to settle down.
• The MCU sets the data pin LOW for a minimum of 18 milliseconds.
• The MCU sets the data pin HIGH and waits for 40 microseconds.
• DHT11 lowers the data pin for 80 microseconds.
• DHT11 sets the data pin HIGH for 80 microseconds (Figure 5.43).
• Now, data transmission starts between the DHT11 and MCU.
• LOW data is identified with 50 microseconds of LOW, followed by 26-28 microseconds
of HIGH data
• HIGH data is identified with 50 microseconds of LOW, followed by 70 microseconds of
● 162
Chapter 5 ● Hardware Projects using C
Program listing:
wiringPi
The program listing of the project is shown in Figure 5.45 (Program: dht11.c). The program
uses GPIO numbering, not wiringPi numbering.
/*------------------------------------------------------------------
DHT11 TEMPERATURE AND HUMIDITY
==============================
● 163
C Programming on Raspberry Pi
#include <stdio.h>
#define DHT_PIN 2
//
// This function waits for and edge change. If there is no edge
// change in 255 microseconds then the function returns 1, otherwise
// it returns 0
//
int WaitEdge(int mode)
{
int counter = 0;
while(digitalRead(DHT_PIN) == mode)
{
counter++;
delayMicroseconds(1);
if(counter == 255)return 1;
}
return 0;
}
//
// This function reads the temperature and humidity from DHT11
// and returns the readings to the calling program
//
void Read_DHT11(int *T, int *H)
{
char res, i, state, counter,indx = 0;
int data[5];
res = WaitEdge(0);
res = res +WaitEdge(1);
i = 0;
while(i < 80 && res == 0)
{
counter = 0;
if(WaitEdge(0) == 1)break;
● 164
Chapter 5 ● Hardware Projects using C
while(digitalRead(DHT_PIN) == HIGH)
{
counter++;
delayMicroseconds(1);
if(counter == 255)break;
}
data[indx/8] <<= 1;
if(counter > 28)data[indx/8] |= 1;
indx++;
i++;
}
//
// Check the Checksum
//
if((indx >= 40) && (data[4] ==
((data[0]+data[1]+data[2]+data[3]) & 0xFF)))
{
*T = data[2]; // T = data[2].data[3]
*H = data[0]; // H = data[0].data[1]
}
}
//
// Start of MAIN program
//
int main(void)
{
int Temp, Hum;
wiringPiSetupGpio();
delay(1000);
while(1)
{
Read_DHT11(&Temp, &Hum);
printf("T=%d C H=%d %%\n", Temp, Hum);
delay(5000); // 5s delay
}
}
Figure 5.45 Program dht11.c
Function Read_DHT11 reads temperature and humidity from the DHT11 chip. At the
beginning of this function, integer array data is initialised with 5 elements. This array is
used to store temperature, humidity, and checksum data. This array is cleared to 0, pin
● 165
C Programming on Raspberry Pi
DHT_11 is configured as an output and the chip is initialised by sending the correct pulses
with the correct timings. The main program runs in a while loop. Here, a counter variable
is used to measure the HIGH time of the signal received from the chip. counter counts up
every second. If the time becomes 255, data reading is cancelled since it is not possible
to wait 255 microseconds. The data bit received is then stored in the index of array data,
pointed to by variable indx. indx is a bit counter and when it reaches modulo 8, a byte
of data is loaded into data. At the end of function Read_DHT11, the program checks the
checksum and if it is valid, temperature and humidity are returned to the calling program.
The arguments to the function are passed as addresses of variables. Notice only the integral
parts of the data are returned and the decimal parts are discarded for simplicity. Function
WaitEdge waits for an edge change of input data (from LOW to HIGH, or from HIGH to
LOW). If there is no change within 255 microseconds, the function returns 1, otherwise, 0
is returned to the calling program.
The main program calls function Read_DHT11 by passing the addresses of variables Temp
and Hum. These variables are loaded with current temperature and humidity data which is
displayed on the PC screen. An example output from the program is shown in Figure 5.46.
We can easily create a library of the functions used to read temperature and humidity in
Figure 5.45. This makes the main program only a few lines long where it calls the functions.
The library can be linked to our main program during compilation phase. The steps are
given below:
● 166
Chapter 5 ● Hardware Projects using C
• Create the main program (Program: dht11main.c) which consists of a few lines of
code as shown in Figure 5.47.
• Create a file containing the DHT11 functions (File: dht11func.c) as shown in Figure
5.48
• Compile the functions program (this will create the compiled file dht11func.o):
gcc –c dht11func.c
• Create a library, e.g. with the name libdht11 (this will create library file libdht11.a):
ar –cvq libdht11.a dht11func.o
• Compile and link the main program (this will create executable file dht11main):
gcc –o dht11main dht11main.c –lwiringPi libdht11.a
sudo ./dht11main
/*------------------------------------------------------------------
MAIN PROGRAM
============
#define DHT_PIN 2
int WaidEdge(int);
void Read_DHT11(int*, int*);
//
// Start of MAIN program
//
int main(void)
{
int Temp, Hum;
wiringPiSetupGpio();
delay(1000);
while(1)
● 167
C Programming on Raspberry Pi
{
Read_DHT11(&Temp, &Hum);
printf("T=%d C H=%d %%\n", Temp, Hum);
delay(5000); // 5s delay
}
}
Figure 5.47 Program dht11main.c
/*------------------------------------------------------------------
DHT11 FUNCTIONS
===============
#define DHT_PIN 2
//
// This function waits for and edge change. If there is no edge
// change in 255 microseconds then the function returns 1, otherwise
// it returns 0
//
int WaitEdge(int mode)
{
int counter = 0;
while(digitalRead(DHT_PIN) == mode)
{
counter++;
delayMicroseconds(1);
if(counter == 255)return 1;
}
return 0;
}
//
// This function reads the temperature and humidity from DHT11
// and returns the readings to the calling program
//
void Read_DHT11(int *T, int *H)
{
char res, i, state, counter,indx = 0;
int data[5];
● 168
Chapter 5 ● Hardware Projects using C
res = WaitEdge(0);
res = res +WaitEdge(1);
i = 0;
while(i < 80 && res == 0)
{
counter = 0;
if(WaitEdge(0) == 1)break;
while(digitalRead(DHT_PIN) == HIGH)
{
counter++;
delayMicroseconds(1);
if(counter == 255)break;
}
data[indx/8] <<= 1;
if(counter > 28)data[indx/8] |= 1;
indx++;
i++;
}
//
// Check the Checksum
//
if((indx >= 40) && (data[4] ==
((data[0]+data[1]+data[2]+data[3]) & 0xFF)))
{
*T = data[2]; // T = data[2].data[3]
*H = data[0]; // H = data[0].data[1]
}
}
Figure 5.48 File dht11func.c
Note: you can use the following command to display the contents of library libdht11.a
ar –t libdht11.a
● 169
C Programming on Raspberry Pi
pigpio
The pigpio program of the project is shown in Figure 5.49 (Program: dht11-2.c). This is
very similar to the program given in Figure 5.45. You can compile and run the program as
follows:
/*------------------------------------------------------------------
DHT11 TEMPERATURE AND HUMIDITY
==============================
#define DHT_PIN 2
//
// This function waits for and edge change. If there is no edge
// change in 255 microseconds then the function returns 1, otherwise
// it returns 0
//
int WaitEdge(int mode)
{
int counter = 0;
while(gpioRead(DHT_PIN) == mode)
{
counter++;
gpioDelay(1);
if(counter == 255)return 1;
}
return 0;
}
//
● 170
Chapter 5 ● Hardware Projects using C
res = WaitEdge(0);
res = res +WaitEdge(1);
i = 0;
while(i < 80 && res == 0)
{
counter = 0;
if(WaitEdge(0) == 1)break;
while(gpioRead(DHT_PIN) == 1)
{
counter++;
gpioDelay(1);
if(counter == 255)break;
}
data[indx/8] <<= 1;
if(counter > 28)data[indx/8] |= 1;
indx++;
i++;
}
//
// Check the Checksum
//
if((indx >= 40) && (data[4] ==
((data[0]+data[1]+data[2]+data[3]) & 0xFF)))
{
*T = data[2]; // T = data[2].data[3]
*H = data[0]; // H = data[0].data[1]
}
}
● 171
C Programming on Raspberry Pi
//
// Start of MAIN program
//
int main(void)
{
int Temp, Hum;
gpioInitialise();
time_sleep(1);
while(1)
{
Read_DHT11(&Temp, &Hum);
printf("T=%d C H=%d %%\n", Temp, Hum);
time_sleep(5); // 5s delay
}
}
Figure 5.49 Program dht11-2.c
Description:
In this project, a DHT11 type sensor chip is used together with a heater, active buzzer,
and an LED to control the temperature of a small room. The heater is turned ON by the
relay if the room temperature measured (RoomTemp) is below the set-point temperature
(SetTemp). It turns OFF if it is above the set-point value. The buzzer sounds if the room
temperature is equal to or greater than the MaxTemp which is a preset danger value.
SetTemp and MaxTemp are entered from the keyboard.
Aim:
This project aims to show how an ON/OFF temperature control system can be designed
using a DHT11 sensor chip with Raspberry Pi.
● 172
Chapter 5 ● Hardware Projects using C
Block diagram:
Circuit diagram:
The circuit diagram of the project is shown in Figure 5.51. In this project, GPIO pin
numbering is used. LEDs are connected through 470 Ohm current limiting resistors. The
active buzzer is directly connected to the Raspberry Pi. The Relay is activated when logic
1 (+3.3V) is applied to it. The connections between the Raspberry Pi ports and various
components are as follows:
3 Buzzer
17 LED
22 Relay
● 173
C Programming on Raspberry Pi
The operation of the project is described in Figure 5.52 as a PDL (Program Description
Language).
BEGIN
Read the set temperature (SetTemp)
Read the maximum temperature (MaxTemp)
DO FOREVER
Read the room temperature (RoomTemp)
IF SetTemp > RoomTemp THEN
Activate relay
LED ON
ELSE
Deactivate relay
LED OFF
IF RoomTemp >= MaxTemp THEN
Activate Buzzer
ENDIF
ENDIF
Wait 2 seconds
ENDDO
END
Figure 5.52 PDL of the project
● 174
Chapter 5 ● Hardware Projects using C
Program listing:
wiringPi
Figure 5.53 shows the program listing (Program: ONOFF.c). The author logged in to the
Raspberry Pi using Putty over an SSH link. At the beginning of the program, the connections
between the Raspberry Pi and DHT11, LED, buzzer, and relay are defined. This program
uses the VT100 cursor control codes with a Putty terminal emulation program to display
the set temperature, room temperature, and heater status. Using cursor control codes has
the advantage that data is displayed at fixed points of the screen and does not scroll, hence
it is much easier to see. For example, printing esc[2J clears the screen. esc[H homes the
cursor to the top left-hand of the screen. esc[3;4H positions the cursor at line 3, column 4
of the screen, and so on. A full list of the cursor control codes is available at the link:
https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797
The functions that read temperature and humidity from the DHT11 sensor chip are the
same as in the previous examples. In this project, humidity data is not used, even though
it is returned by the DHT11. Inside the main program, room temperature is read and
stored in variable RoomTemp. If SetTemp is greater than RoomTemp, the room has not
reached the desired temperature and both the relay and the LED are turned ON. Activating
the relay turns ON the heater. If on the other hand, SetTemp is less than RoomTemp,
the room has reached the desired temperature and both the LED and relay are turned OFF.
If room temperature goes above the specified maximum value, the buzzer is sounded to
signal an alarm condition. SetTemp, RoomTemp, and alarm status are displayed as in
Figure 5.54. This figure is updated every 5 seconds.
/*------------------------------------------------------------------
ON-OFF TEMPERATURE CONTROL
==========================
● 175
C Programming on Raspberry Pi
#include <wiringPi.h>
#include <stdio.h>
#define ON HIGH
#define OFF LOW
//
// This function waits for and edge change. If there is no edge
// change in 255 microseconds then the function returns 1, otherwise
// it returns 0
//
int WaitEdge(int mode)
{
int counter = 0;
while(digitalRead(DHT_PIN) == mode)
{
counter++;
delayMicroseconds(1);
if(counter == 255)return 1;
}
return 0;
}
//
// Configure ports as input/output and turn OFF output ports
//
void Configure()
{
pinMode(LED, OUTPUT);
pinMode(Relay, OUTPUT);
pinMode(Buzzer, OUTPUT);
digitalWrite(LED, OFF);
digitalWrite(Relay, OFF);
digitalWrite(Buzzer, OFF);
}
● 176
Chapter 5 ● Hardware Projects using C
//
// This function reads the temperature and humidity from DHT11
// and returns the readings to the calling program
//
void Read_DHT11(int *T, int *H)
{
char res, i, state, counter,indx = 0;
int data[5];
res = WaitEdge(0);
res = res +WaitEdge(1);
i = 0;
while(i < 80 && res == 0)
{
counter = 0;
if(WaitEdge(0) == 1)break;
while(digitalRead(DHT_PIN) == HIGH)
{
counter++;
delayMicroseconds(1);
if(counter == 255)break;
}
data[indx/8] <<= 1;
if(counter > 28)data[indx/8] |= 1;
indx++;
i++;
}
//
// Check the Checksum
//
if((indx >= 40) && (data[4] ==
((data[0]+data[1]+data[2]+data[3]) & 0xFF)))
{
*T = data[2]; // T = data[2].data[3]
*H = data[0]; // H = data[0].data[1]
}
● 177
C Programming on Raspberry Pi
//
// Start of MAIN program
//
int main(void)
{
int RoomTemp, Hum, SetTemp, MaxTemp;
wiringPiSetupGpio();
Configure();
delay(1000);
while(1)
{
Read_DHT11(&RoomTemp, &Hum);
if(SetTemp > RoomTemp)
{
digitalWrite(Relay, ON);
digitalWrite(LED, ON);
}
else
{
digitalWrite(Relay, OFF);
digitalWrite(LED, LOW);
if(RoomTemp >= MaxTemp)
digitalWrite(Buzzer, ON);
}
printf("%s%s ON-OFF TEMPERATURE CONTROLLER\n"
,clr, home);
printf("%sSet Temperature = %d\n", to34,SetTemp);
printf("%sRoom Temperature = %d\n", to330,RoomTemp);
if(SetTemp > RoomTemp)
printf("%sHEATER = ON\n", to620);
else
printf("%sHEATER = OFF\n", to620);
delay(5000); // 5s delay
}
}
Figure 5.53 Program ONOFF.c
● 178
Chapter 5 ● Hardware Projects using C
pigpio
The pigpio program of the project is very similar to the program given in Figure 5.52. It is
left as an exercise for the reader to develop it.
In an ON-OFF type temperature control system, room temperature fluctuates around the
setpoint value as shown in Figure 5.55. A fixed stable room temperature can be obtained
using a PID type controller.
5.12 ● Summary
In the next chapter, we will learn how to use an LCD in our Raspberry Pi projects.
● 179
C Programming on Raspberry Pi
6.1 ● Overview
LCDs can be connected to a microcontroller in parallel or through I2C. Parallel LCDs (e.g.
Hitachi HD44780) are connected using more than one data line and several control lines.
The data is transferred in parallel. It is common to use either 4 or 8 data lines and two
or more control lines. Using a 4 wire connection saves I/O pins but is slower due to data
being transferred in two stages. I2C based LCDs on the other hand are connected to a
microcontroller using only 2 wires, data, and a clock. In general, I2C based LCDs are much
easier to use and require less wiring. However, they cost more than parallel types. In this
chapter, we will be using 4 wire connections to LCDs.
Although there are several types of LCDs, the HD44780 is one of the most popular LCD
modules currently used in industry and by hobbyists (Figure 6.1). This module is an
alphanumeric monochrome display and comes in different sizes. Modules with 16 columns
are popular in most small applications, but other modules with 8, 20, 24, 32, or 40 columns
are also available. Although most LCDs have two lines (or rows) as standard, it is possible
to purchase models with 1 or 4 lines. LCDs are available with standard 14-pin connectors,
although 16-pin modules are also available, providing terminals for backlighting. Table
6.1 gives the pin configuration and corresponding functions of a 16-pin LCD module. A
summary of the pin functions is given below:
● 180
Chapter 6 ● LCD Projects
VSS (pin 1) and VDD (pin 2) are the ground and power supply pins. The power supply should
be +5V.
VEE is pin 3 and this is the contrast control pin used to adjust the contrast of the display. The
arm of a 10K potentiometer is normally connected to this pin and the other two terminals
of the potentiometer are connected to the ground and power supply pins. The contrast of
the display is adjusted by rotating the potentiometer arm.
Pin 4 is the Register Select (RS) and when this pin is LOW, data transferred to the display
is treated as commands. When RS is HIGH, character data can be transferred to and from
the display.
Pin 5 is the Read/Write (R/W) line. This pin is pulled LOW to write commands or character
data to the LCD module. When the pin is HIGH, character data or status information can be
read from the module. This pin is normally connected permanently LOW so commands and
● 181
C Programming on Raspberry Pi
Enable (E) is pin 6 which is used to initiate the transfer of commands or data between
the LCD module and microcontroller. When writing to the display, data is transferred only
on the HIGH to LOW transition of this pin. When reading from the display, data becomes
available after the LOW to HIGH transition of the enable pin and this data remains valid as
long as the enable pin is at logic HIGH.
Pins 7 to 14 are the eight data bus lines (D0 to D7). Data can be transferred between the
microcontroller and LCD module using either a single 8-bit byte or as two 4-bit nibbles.
In the latter case, only the upper four data lines (D4 to D7) are used. 4-bit mode has the
advantage that four fewer I/O lines are required to communicate with the LCD. 4-bit mode
is slower however due to the data being transferred in two stages. In this book, we will use
the 4-bit interface.
Pins 15 and 16 are for background brightness control. To enable background brightness,
a 220 Ohm resistor should be connected from pin 15 to +5V supply. Pin 16 should be
connected to ground.
In 4-bit mode, the following pins of the LCD are used. The R/W line is permanently connected
to ground. This mode uses 6 GPIO port pins of the microcontroller:
The libraries allow the control of 1, 2, and 4-line LCDs that are based on the Hitachi
HD44780 or compatible controllers. More than one LCD can be connected to Raspberry
Pi. LCDs usually operate with +5V. There is no problem connecting them to Raspberry Pi
GPIO pins because the display never writes data back to the Raspberry Pi (R/W pin is tied
to GND).
Description:
In this project, an LCD is connected to Raspberry Pi. The program displays text Raspberry
Pi at row 0 (first row), column 2 of the LCD. Also, text Computer is displayed at row 1
(second row), column 4 of the display.
Aim:
This project aims to show how an LCD can be connected to Raspberry Pi, and be programmed
using C.
● 182
Chapter 6 ● LCD Projects
Circuit diagram:
Figure 6.2 shows the circuit diagram of the project. The LCD is connected in 4–bit mode
as follows:
Contrast is adjusted using a 10K potentiometer. The LCD background is lit by connecting
pin 16 to ground and pin 15 to +5V through a 180 Ohm resistor.
Program listing:
wiringPi
The following header files must be included at the beginning of the program (see link:
http://wiringpi.com/dev-lib/lcd-library/) :
● 183
C Programming on Raspberry Pi
#include <wiringPi.h>
#include <lcd.h>
The connections between the Raspberry Pi and LCD must be defined using the following
function (assuming 4-bit operation):
lcd = lcdInit(rows, cols, 4, RS, E,D4, D5, D6, D7, 0, 0, 0, 0) ;
Where rows and cols are the number of rows and columns respectively, the next is the
number of bits used for the data interface (4-bit in this project), the remaining are the
pins of the LCD. Notice only 4 data pins (D4-D7) are used. The function returns a handle
(e.g. lcd) which is used in reference to LCD functions.
Some commonly used LCD functions supported by the LCD library are: lcdHome
(handle): home the cursor
lcdPosition(handle, x, y): position the cursor at column x, row y. (0, 0) is the top left-
hand corner of the LCD
lcdCharDef(handle, index, char data[8]): this function allows the user to define 8-byte
custom characters to represent a 5x8 array of pixels. Up to 8 custom characters (pointed to
by the index argument) can be stored in LCD memory. Only the lower 5 bits are used in the
character definition. The custom character created can be displayed using the lcdPutchar
function call. Examples are given in later sections of this chapter.
Figure 6.3 shows the program listing (Program: LCDText.c). GPIO pin numbering is used in
this program. At the beginning of the program, the connections between Raspberry Pi and
the LCD are defined as in Figure 6.2. Inside the main program function, wiringPiSetupGpio
is called to initialise wiringPi and also to set the pin numbering mode to GPIO. Function
lcdInit is then called to initialise the LCD library with 2 rows, 16 columns, 4-bit mode,
and the pin connections as required. The LCD is cleared, the cursor is positioned at row 0,
column 2, and the text Raspberry Pi is displayed. The cursor is then positioned at row 1,
column 4, and the text Computer is displayed.
● 184
Chapter 6 ● LCD Projects
(see: http://wiringpi.com/dev-lib/lcd-library/)
/*------------------------------------------------------------------
DISPLAY TEXT ON LCD
===================
//
// Connections between Raspberry Pi and LCD
//
#define D4 2
#define D5 3
#define D6 17
#define D7 27
#define RS 22
#define E 10
//
// Start of MAIN program
//
int main(void)
{
int lcd;
wiringPiSetupGpio();
lcd = lcdInit(2, 16, 4, RS, E, D4, D5, D6, D7, 0, 0, 0, 0);
lcdClear(lcd);
lcdPosition(lcd, 2, 0);
lcdPuts(lcd, "Raspberry Pi");
lcdPosition(lcd, 4, 1);
lcdPuts(lcd, "Computer");
}
Figure 6.3 Program LCDText.c
The program is compiled and run as follows (Notice the two libraries used):
● 185
C Programming on Raspberry Pi
Raspberry Pi
Computer
Description:
This is a second counter project, which counts up every second and displays on the LCD.
The data is displayed as follows:
Aim:
This project aims to show how text and numeric data can be displayed on the LCD.
Circuit diagram:
Program listing:
wiringPi
Figure 6.4 shows the program listing (Program: LCDSeconds.c). At the beginning of the
program, the connections between Raspberry Pi and LCD are defined as in the previous
project. The variable count is initialised to 0 and is then incremented every second and
displayed on the LCD using function lcdPrintf.
/*------------------------------------------------------------------
LCD SECONDS COUNTER
===================
● 186
Chapter 6 ● LCD Projects
#include <wiringPi.h>
#include <lcd.h>
//
// Connections between Raspberry Pi and LCD
//
#define D4 2
#define D5 3
#define D6 17
#define D7 27
#define RS 22
#define E 10
//
// Start of MAIN program
//
int main(void)
{
int lcd, count = 0;
wiringPiSetupGpio();
lcd = lcdInit(2, 16, 4, RS, E, D4, D5, D6, D7, 0, 0, 0, 0);
lcdClear(lcd);
lcdPosition(lcd, 0, 0);
lcdPuts(lcd, "SECONDS:");
while(1)
{
lcdPosition(lcd, 0, 1);
count++;
delay(1000);
lcdPrintf(lcd, "%d",count);
}
}
Figure 6.4 Program LCDSeconds.c
Description:
In this project, we will create an up arrow as a custom character and display it on the LCD.
Aim:
The project aims to show how a custom character can be created and displayed on the LCD.
● 187
C Programming on Raspberry Pi
Circuit diagram:
Program listing:
wiringPi
There are several free of charge programs available on the internet that can be used
to create characters for LCDs. The one used by the author is mikroElektronika’s GLCD
Font Generator (link: https://www.mikroe.com/glcd-font-creator). You should install this
program on your PC. The steps to create our character are as follows:
00100
01110
10101
00100
00100
00100
00100
00100
We have to store the pixel data in an array so that we can use it in a program. For example,
we can declare an array called arrow as follows:
● 188
Chapter 6 ● LCD Projects
char arrow[8] = {
0b00100,
0b01110,
0b10101,
0b00100,
0b00100,
0b00100,
0b00100,
0b00100
};
Figure 6.6 shows the program listing (Program: LCDcustom1.c). Function DisplayCustom
is called from the main program and displays the up arrow. Notice the index ranges from 0
to 7. It is the memory index where the custom character is saved.
/*------------------------------------------------------------------
DISPLAY CUSTOM CHARACTER
========================
//
// Connections between Raspberry Pi and LCD
//
#define D4 2
#define D5 3
#define D6 17
#define D7 27
#define RS 22
#define E 10
int lcd;
//
// Define the custom character (up arrow)
//
char arrow[8] = {
0b00100,
● 189
C Programming on Raspberry Pi
0b01110,
0b10101,
0b00100,
0b00100,
0b00100,
0b00100,
0b00100
};
//
// Display the custom character
//
void DisplayCustom(void)
{
lcdCharDef(lcd, 0, arrow);
lcdClear(lcd);
lcdPutchar(lcd, 0);
delay(5000);
}
//
// Start of MAIN program
//
int main(void)
{
wiringPiSetupGpio();
lcd = lcdInit(2, 16, 4, RS, E, D4, D5, D6, D7, 0, 0, 0, 0);
DisplayCustom();
}
Figure 6.6 Program LCDcustom1.c
Description:
In this project we will create four custom characters: an up arrow, down arrow, left arrow,
and a right arrow as custom characters and display them on the LCD.
Aim:
The project aims to show how multiple custom characters can be created and displayed on
the LCD.
● 190
Chapter 6 ● LCD Projects
Circuit diagram:
Program listing:
wiringPi
The GPIO numbering scheme is used in this program (as opposed to the wiringPi numbering
scheme). The custom characters are created using the GLCD Font Editor as in the previous
project. Figure 6.7 shows the custom characters together with their pixel definitions.
The program listing (Program: LCDcustom2.c) is shown in Figure 6.8. The four custom
characters are defined at the beginning of the program. Function DisplayCustom saves
the character arrays uparrow, downarrow, leftarrow, and rightarrow in indexes 0, 1,
2, and 3 respectively. The arrows are hen displayed with a one-second delay between each
output. The result is four arrows displayed next to each other (up, down, left, and right).
/*------------------------------------------------------------------
DISPLAY MULTIPLE CUSTOM CHARACTERS
==================================
● 191
C Programming on Raspberry Pi
//
// Connections between Raspberry Pi and LCD
//
#define D4 2
#define D5 3
#define D6 17
#define D7 27
#define RS 22
#define E 10
int lcd;
//
// Define the custom characters (up arrow)
//
char uparrow[8] = {
0b00100,
0b01110,
0b10101,
0b00100,
0b00100,
0b00100,
0b00100,
0b00100
};
char downarrow[8] = {
0b00100,
0b00100,
0b00100,
0b00100,
0b00100,
0b10101,
0b01110,
0b00100
};
char leftarrow[8] = {
0b00000,
0b00100,
0b01000,
0b11111,
0b01000,
0b00100,
0b00000,
0b00000
● 192
Chapter 6 ● LCD Projects
};
char rightarrow[8] = {
0b00000,
0b00100,
0b00010,
0b11111,
0b00010,
0b00100,
0b00000,
0b00000
};
//
// Display the custom character
//
void DisplayCustom(void)
{
lcdCharDef(lcd, 0, uparrow);
lcdCharDef(lcd, 1, downarrow);
lcdCharDef(lcd, 2, leftarrow);
lcdCharDef(lcd, 3, rightarrow);
lcdClear(lcd);
lcdPutchar(lcd, 0);
delay(1000);
lcdPutchar(lcd, 1);
delay(1000);
lcdPutchar(lcd, 2);
delay(1000);
lcdPutchar(lcd, 3);
delay(5000);
}
//
// Start of MAIN program
//
int main(void)
{
wiringPiSetupGpio();
lcd = lcdInit(2, 16, 4, RS, E, D4, D5, D6, D7, 0, 0, 0, 0);
DisplayCustom();
}
Figure 6.8 Program LCDcustom2.c
● 193
C Programming on Raspberry Pi
Description:
In this project, current date and time are displayed on the LCD. Data is displayed on the top
row, while time is displayed on the bottom row.
Aim:
This project shows how current date and time can be extracted and displayed on the LCD.
Circuit diagram
Program listing:
wiringPi
Figure 6.9 shows the program listing (Program: LCDDateTime.c). The program reads the
current date and time, formats them using function strftime and stores them in character
arrays CurrentDate and CurrentTime respectively. The cursor is set to the top row and
the current date is displayed. Similarly, the cursor is set to the bottom row and the current
time is displayed. The format of the display is as shown in the following example;
22-12-2020
10:20:45
/*------------------------------------------------------------------
DISPLAY TEXT ON LCD
===================
dd-mm-yyyy
hh:mm:ss
● 194
Chapter 6 ● LCD Projects
//
// Conenctions between Raspberry Pi and LCD
//
#define D4 2
#define D5 3
#define D6 17
#define D7 27
#define RS 22
#define E 10
//
// Start of MAIN program
//
int main(void)
{
int lcd;
char CurrentDate[16], CurrentTime[12];
struct tm* timeinfo;
time_t timer;
wiringPiSetupGpio();
lcd = lcdInit(2, 16, 4, RS, E, D4, D5, D6, D7, 0, 0, 0, 0);
lcdClear(lcd);
while(1)
{
time(&timer);
timeinfo = localtime(&timer);
lcdPosition(lcd, 0, 0);
lcdPuts(lcd, CurrentDate);
lcdPosition(lcd, 0, 1);
lcdPuts(lcd, CurrentTime);
delay(1000);
}
}
Figure 6.9 Program LCDDateTime.c
● 195
C Programming on Raspberry Pi
Description:
In this project, a DHT11 temperature and humidity sensor chip is used. Ambient temperature
and humidity are displayed on the top and bottom rows of the LCD respectively.
Aim:
This project aims to show how temperature and humidity data can be displayed on the LCD.
Block diagram:
Circuit diagram:
The circuit diagram of the project is shown in Figure 6.11. The LCD is connected to the
Raspberry Pi as in the previous project. The DHT11 sensor is connected to GPIO 9.
● 196
Chapter 6 ● LCD Projects
Program listing:
wiringPi
Figure 6.12 shows the program listing (Program: LCDTH.c). In this program, GPIO pin
numbering is used. The part of the program that reads the temperature and humidity is as
in Figure 5.45. Additionally, the data is displayed on the LCD.
/*------------------------------------------------------------------
DISPLAY TEMPERATURE AND HUMIDITY ON LCD
=======================================
In this program a DHT11 sensor chip and an LCD are connected to the
Raspberry Pi. The program displays the temperature and humidity on
the LCD
//
// Connections between Raspberry Pi and LCD
//
#define D4 2
#define D5 3
#define D6 17
#define D7 27
#define RS 22
#define E 10
//
// DHT11 data pin (GPIO 9)
//
#define DHT_PIN 9
//
// This function waits for and edge change. If there is no edge
// change in 255 microseconds then the function returns 1, otherwise
// it returns 0
//
int WaitEdge(int mode)
● 197
C Programming on Raspberry Pi
{
int counter = 0;
while(digitalRead(DHT_PIN) == mode)
{
counter++;
delayMicroseconds(1);
if(counter == 255)return 1;
}
return 0;
}
//
// This function reads the temperature and humidity from DHT11
// and returns the readings to the calling program
//
void Read_DHT11(int *T, int *H)
{
char res, i, state, counter,indx = 0;
int data[5];
res = WaitEdge(0);
res = res +WaitEdge(1);
i = 0;
while(i < 80 && res == 0)
{
counter = 0;
if(WaitEdge(0) == 1)break;
while(digitalRead(DHT_PIN) == HIGH)
{
counter++;
delayMicroseconds(1);
if(counter == 255)break;
}
data[indx/8] <<= 1;
if(counter > 28)data[indx/8] |= 1;
indx++;
● 198
Chapter 6 ● LCD Projects
i++;
}
//
// Check the Checksum
//
if((indx >= 40) && (data[4] ==
((data[0]+data[1]+data[2]+data[3]) & 0xFF)))
{
*T = data[2]; // T = data[2].data[3]
*H = data[0]; // H = data[0].data[1]
}
}
//
// Start of MAIN program
//
int main(void)
{
int Temp, Hum, lcd;
wiringPiSetupGpio();
delay(1000);
lcd = lcdInit(2, 16, 4, RS, E, D4, D5, D6, D7, 0, 0, 0, 0);
while(1)
{
Read_DHT11(&Temp, &Hum);
lcdClear(lcd);
lcdPosition(lcd, 0, 0); // row 0, col 0
lcdPrintf(lcd, "T = %d C", Temp);
lcdPosition(lcd, 0, 1); // row 1, col 0
lcdPrintf(lcd, "H = %d %%", Hum);
delay(5000); // 5s delay
}
}
Figure 6.12 Program LCDTH.c
T = 22 C
H = 58 %
● 199
C Programming on Raspberry Pi
6.9 ● Summary
In this chapter, we learned how to use LCDs with Raspberry Pi while programming using
the wiringPi library and C language.
The key topic of the next chapter is the I2C (or I2C) interface and corresponding library.
● 200
Chapter 7 ● I2C Bus Interface
7.1 ● Overview
The I2C (or I2C) bus is commonly used in microcontroller based projects. In this chapter, we
will look at the use of this bus on Raspberry Pi. The aim is to make the reader familiar with
I2C bus library functions and to show how they can be used in a real project. Before looking
at the details of the project, it is worthwhile to look at the basic principles of the I2C bus.
The I2C bus is one of the most frequently used microcontroller communication protocols
for communicating with external devices such as sensors and actuators. The I2C bus is
a single master, multiple slave bus, and can operate on standard mode: 100 Kbit/s, full
speed: 400Kbit/s, fast mode: 1 Mbit/s, and high speed: 3.2 Mbit/s. The bus consists of two
open-drain wires, pulled-up with resistors:
Figure 7.1 shows the structure of an I2C bus with one master and three slaves.
Figure 7.1 I2C bus with one master and three slaves
Because the I2C bus is based on just two wires, there should be a way to address an
individual 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
transaction by sending STOP bit. This alerts all slaves that data is coming on the bus. After
the start bit, 7 bits of unique slave address is sent. Each slave device on the bus has an
address and this ensures that only the addressed slave communicates on the bus at any
time to avoid any collisions. The last sent bit is the read/write bit. If this bit is 0, the master
wishes to write to the bus (e.g. to a register of a slave). If it is 1, 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 acknowledgment (ACK) bit takes place after every byte and this bit allows the
● 201
C Programming on Raspberry Pi
receiver to signal to the transmitter that the byte was received successfully, resulting in
another byte being sent. ACK bit is sent at the 9th clock pulse.
• 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
master 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 I2C 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, more than one byte will be read.
• The master sets a stop condition on the bus
Before using any I2C device we have to enable I2C in our Raspberry Pi configuration. The
steps are:
Before using the I2C pins of the Raspberry Pi, we have to make sure the I2C device
connected to Raspberry Pi is recognised by the Raspberry Pi I2C bus. Build your circuit
and enter the following command on the command line and ensure the I2C address of the
connected device is displayed:
● 202
Chapter 7 ● I2C Bus Interface
Description:
A simple project is given in this section to show how I2C functions can be used in a
program. In this project, the I2C bus compatible Port Expander chip (MCP23017) is used
to give an additional 16 I/O ports to the Raspberry Pi. This is useful in some applications
where a large number of I/O ports are required. In this project, an LED is connected to
MCP23017 port pin GPA0 (pin 21) and the LED is flashed ON and OFF every second so the
operation of the program can be validated. A 470 Ohm current limiting resistor is used in
series with the LED.
Aim:
This project aims to show how the I2C bus can be used in Raspberry Pi projects.
Block diagram:
The MCP23017
The MCP23017 is a 28-pin chip with the following features. Pin configuration is shown in
Figure 7.3:
● 203
C Programming on Raspberry Pi
Pin Description
GPA0-GPA7 Port A pins
GPB0-GPB7 Port B pins
VDD Power supply
VSS Ground
SDA I2C data pin
SCL I2C clock pin
RESET Reset pin
A0-A2 I2C address pins
Table 7.1 MCP23017 pin descriptions
The MCP23017 is addressed using pins A0 to A2. Table 7.2 shows the address selection. In
this project, address pins are connected to ground, thus the address of the chip is 0x20.
The chip address is 7 bits wide with the low bit set or cleared depending on whether we
wish to read data from the chip or write data to the chip respectively. Since in this project
we will be writing to the MCP23017, the low bit should be 0, making the chip byte address
(also called the device opcode) 0x40.
● 204
Chapter 7 ● I2C Bus Interface
A2 A1 A0 Address
0 0 0 0x40
0 0 1 0x21
0 1 0 0x22
0 1 1 0x23
1 0 0 0x24
1 0 1 0x25
1 1 0 0x26
1 1 1 0x27
Table 7.2 Selecting address of the MCP23017
The MCP23017 chip has 8 internal registers that can be configured for its operation. The
device can be operated either in 16-bit mode or two 8-bit mode by configuring bit IOCON.
BANK. On power-up, this bit is cleared which selects the two 8-bit mode by default.
The I/O direction of the port pins are controlled with registers IODIRA (at address
0x00) and IODIRB (at address 0x01). Clearing a bit to 0 in these registers makes the
corresponding port pin(s) as output(s). Similarly, setting a bit to 1 in these registers makes
the corresponding port pin(s) input(s). GPIOA and GPIOB register addresses are 0x12 and
0x13 respectively. This is shown in Figure 7.4.
Figure 7.5 shows the circuit diagram of the project. Notice the I2C pins of the port expander
are connected to pins GPIO 2 (SDA) and GPIO 3 (SCL) of the Raspberry Pi and are pulled-
up using 10K resistors as required by the I2C specifications. The LED is connected to
port pin GPA0 of the MCP23017 (pin 21). The address select bits of the MCP23017 are all
connected to ground.
● 205
C Programming on Raspberry Pi
More information on the MCP23017 chip can be obtained from the datasheet:
https://ww1.microchip.com/downloads/en/devicedoc/20001952c.pdf
Program listing:
wiringPi
The header file <wiringPiI2C.h> must be included at the beginning of the program and
the program must be linked with the library: -lwiringPi.
wiringPi support the following I2C functions (for full details, see link:
http://wiringpi.com/reference/i2c-library/ ):
wiringPiI2CSetup(devID): this function initialises the I2C bus with the specified device
address (use i2cdetect to find out this address). An integer filehandle is returned (or -1 if
an error is detected)
wiringPiI2CReadReg8(handle, reg) ;
wiringPiI2CReadReg16(handle, reg) ;
● 206
Chapter 7 ● I2C Bus Interface
After building the circuit, the device address was checked and was found to be ox20 as
shown in Figure 7.6.
GPIO pin numbering is used in this program. Figure 7.7 shows the program listing
(Program: I2Cexpander.c). The wiringPi library supports the MCP23017 chip directly and
therefore there is no need to use the I2C functions to communicate with the chip. The
header file <mcp23017.h> must be included at the beginning of the program. The chip
is then initialised by calling function mcp23017Setup. This function has two arguments:
pinBase and DEVICE_ADDRESS. The pinBase must be above 64. This number is used to
address the I/O ports of the chip. The chip has 16 I/O ports (GPIOA and GPIOB). pinBase+1
corresponds to port pin GPA0, pinBase+2 corresponds to port pin GPA1, and so on. For
example, if the pinBase is set to 100, the I/O pins are addressed as follows:
100 GPA0
101 GPA1
102 GPA2
…………….
107 GPA7
108 GPB0
109 GPB1
……………..
114 GPB7
In this project, the DEVICE_ADDRESS of the chip is 0x20. The program configures all 8
ports GPA0 – GPA7 to outputs and then turns ON and OFF port pin GPA0 every second. You
can compile and run the program as follows:
● 207
C Programming on Raspberry Pi
/*------------------------------------------------------------------
MCP23017 I2C LED FLASH
======================
//
// Start of MAIN program
//
int main(void)
{
int i;
wiringPiSetupGpio();
mcp23017Setup(100, DEVICE_ADDRESS);
The program given in Figure 7.7 uses the built-in MCP23017 library. The program listing
shown in Figure 7.8 (Program: I2Cexpander2.c) uses the I2C functions. At the beginning
of the program, header file <wiringPiI2C.h> is included in the program. The MCP23017
device address is defined as 0x20. The GPIOA register address and IODIRA port direction
register address are defined as 0x12 and 0 respectively (see Figure 7.4). The I2C bus is
initialized by calling function wiringPiI2CSetup which returns integer handle. All 8 GPA0
● 208
Chapter 7 ● I2C Bus Interface
– GPA7 port pins are configured as outputs by setting all bits of IODIRA to 0. Inside the
while loop, function send is called to turn the LED ON and OFF every second. Notice that
sending 1 to register GPIOA turns the LED ON, and sending 0 turns it OFF.
/*------------------------------------------------------------------
MCP23017 I2C LED FLASH
======================
//
// This function sends data to the specified register
//
void send(int fd, int reg, int data)
{
wiringPiI2CWriteReg8(fd, reg, data);
}
//
// Start of MAIN program. Initialize the MCP23017 and send 1 and 0
// to flash the LED
//
int main(void)
{
int handle;
wiringPiSetupGpio();
handle = wiringPiI2CSetup(DEVICE_ADDRESS);
send(handle, MCP_IODIRA_REG, 0); // GPA0-7 outputs
while(1)
{
● 209
C Programming on Raspberry Pi
Description:
In this project, we will be using the I2C bus compatible 24LC256 type EEPROM memory
chip and write characters ABCD to memory locations starting from address 0x1000 of
memory. The data is then read from these locations and displayed on the PC screen to
confirm write/read operation has been successful.
Aim:
This project aims to show how an I2C based EEPROM memory can be programmed using
Raspberry Pi and the C programming language.
24LC256 memory
The 24LC256 is a 32K x 8 (256 Kbit) EEPROM memory chip manufactured by Microchip
Technology Inc. The chip can operate from 1.7V to 5.5V, having a standby current of 1μA
and write current of 3mA. The chip can operate from 100kHz to up to 1MHz. A hardware
write protect pin is provided to disable writing to the chip. The 24LC256 is capable of both
random and sequential reads up to 256K boundary. The device has a page write capability
of up to 64 bytes of data. The device has 32768 addresses, ranging from 0x0000 to 0x7FFF
Figure 7.9 shows the pin layout of the chip.
A0, A1, and A2 are used to set the LSB bits of the device I2C address. As shown below, the
upper 4 bits of the device address are fixed at 1010 and the LSB bit is the R/W bit:
● 210
Chapter 7 ● I2C Bus Interface
WP is the write protection pin. If this pin is tied to the ground, writing is enabled. If
connected to Vcc then the write operations have no effects.
Circuit diagram:
The circuit diagram of the project is shown in Figure 7.10. In this project, I2C pins GPIO 2
and GPIO 3 of Raspberry Pi are used. A0, A1 and A2 are connected to ground so that the
device address is 0xA0. Also, the write-protect pin WP is tied to ground.
Before going into the details of the memory write and read operations, it is worthwhile to
learn how this is done.
As an example, assume that we want to write byte 0x25 into memory location 0x0250.
Figure 7.11 shows the write steps in detail. First of all, the START bit is sent on the bus,
followed by the device address which is assumed to be 0xA0, with the LSB bit set to 0 to
indicate that we wish to do a write operation. The memory address 0x0250 is then split
into upper and lower bytes as 0x02 and 0x50. They are sent sequentially with the higher
byte sent first over the bus. Then, data byte 0x25 is sent (this is called Byte Writing
since only one byte is written to memory). Notice we can send multiple bytes (called Page
Writing where up to 64 bytes can be written sequentially. There are 512 pages and each
page is 64 bytes long) in the same transaction (an internal address counter is incremented
automatically after a byte is sent). The write operation is terminated with the STOP bit.
Notice that ACK bit is sent by the EEPROM between the byte transfers. After a byte write
● 211
C Programming on Raspberry Pi
command, the internal address counter will point to the address location following the one
that was just written. Page write operations are limited to writing bytes within a single
physical page (64 bytes), regardless of the number of bytes being written. Physical page
boundaries start at addresses that are integer multiples of the page buffer size and end at
addresses that are integer multiples of page size -1. If a page write command attempts to
write across a physical page boundary, the result is the data wraps around to the beginning
of the current page (overwriting data previously stored there), instead of being written to
the next page. It is, therefore, necessary for the application software to prevent page write
operations that would attempt to cross a page boundary (e.g. when writing long strings
care should be taken when crossing a page boundary). Some of the page boundaries in
bytes are:
Page 1: 0 – 63
Page 2: 64 – 127
Page 3: 128 – 191
Page 4: 192 – 255
Page 5: 256…….
Notice the data sent to the EEPROM is stored in a temporary buffer since a whole page
consisting of 64 bytes is refreshed after every write operation. It is therefore important to
detect when a write operation has been successfully completed.
Memory read operations are slightly more complex. There are 3 types of reads: current
address, random, and sequential. Random read mode is probably the most commonly used
mode where the master can randomly access any memory location.
As an example, assume we want to read the byte at memory location 0x0250 (where 0x25
was stored in Figure 7.11). Figure 7.12 shows the read steps in detail. To perform Random
Read, the memory address must be sent first. This is done by I2C sending the memory
address to the 24LC256 as part of a write operation (R/W bit set to ‘0’). Once the memory
address is sent, the master generates a START condition following the ACK. This terminates
the write operation, but not before the internal address counter is set. The master then
issues the slave address again, but with the R/W bit set to a 1. The 24LC256 will then
issue an ACK and transmit the 8-bit data word. The master will not acknowledge the
transfer, though it generates a STOP condition, which causes the EEPROM to discontinue
transmission. After a random read command, the internal address counter will point to the
address location following the one that was just read.
● 212
Chapter 7 ● I2C Bus Interface
Program listing:
After connecting the memory chip to the Raspberry Pi, you should check the I2C device
address of the chip by entering the command:
In this project, the device address was found to be 0x50. The program listing is shown in
Figure 7.13 (Program: EEPROM.c). Inside the main program, a character array wmsg
is defined and pre-loaded with characters ABCD. Also, another character array called
rmsg is declared which will be loaded with the data read from the memory chip. Function
wiringPiI2CSetup is called and the device address is specified. The program then calls
function Write to write the contents of array wmsg to the memory chip, starting from
address 0x10000. Function Read then reads 4 bytes of data from the same memory
locations and stores them in array wmsg. This data is then displayed on the PC screen.
Page writing is used in this program where the memory address increments automatically
after writing or reading a byte of data. Function Write has three arguments: the starting
memory location where the data will be stored (memloc), the pointer to the character array
which contains the data to be written to the memory (*data), and the length (number of
bytes) of the data to be written (len). The starting memory address is broken into its
higher and lower bytes and is stored in arrays addr[0] and addr[1] respectively. A for
loop is then formed to write the data pointed to by*data to the memory chip. At each
iteration, variable memdata is loaded with the data to be written to memory. Function
wiringPiI2CWriteReg16 sends the high address byte, followed by a 2-byte variable
(msd) which consists of the low address byte and the byte to be written to memory, which
is shifted left by 8 bits. Therefore, the upper byte of this 2-byte data contains the byte to
be written, and the lower byte contains the low address byte of the memory location. Notice
function wiringPiI2CWriteReg16 has three arguments: the first is the handle, the second
the register address, and the third is 2-bytes of data. Here, the high address is used for the
second argument, and the 2-byte data is used for the third argument. It is necessary to
insert a small delay (about 10ms) after data is written to the memory chip.
Sequential read is done by the program where the memory address pointer is incremented
automatically to point to the next location. Function Read also has three arguments: the
● 213
C Programming on Raspberry Pi
starting memory location where the data will be read from (memloc), the pointer to the
character array where the data read will be stored (*memdata), and the length (len) of
data (number of bytes to read from the memory chip). As with the Write function, the
address is broken down into its higher (addr[0]) and lower (addr[1]) bytes. The starting
address of the memory is specified by calling function wiringPiI2CWriteReg8. The high
address is used as the register address. The low address is used as the data byte. A for loop
is then formed to read 4 characters from the memory chip. The data bytes read are stored
in a character array pointed to by *memdata (i.e. rmsg in main program).
/*---------------------------------------------------------------------
EEPROM MEMORY READ/WRITE
========================
int handle;
//
// This function reads bytes from the memory. The data is returned
// in memdata
//
void Read(int memloc, char *memdata, int len)
{
int i, addr[2];
char data;
● 214
Chapter 7 ● I2C Bus Interface
memdata++;
}
}
//
// This function writes data to the memory
//
void Write(int memloc, char *data, int len)
{
int i, msd, addr[2];
char memdata;
//
// Start of MAIN program. The data in character array wmsg is written
// to the memory. Data read from the memory is stored in array rmsg
//
int main(void)
{
char wmsg[] = {‘A’, ‘B’, ‘C’, ‘D’};
char rmsg[5];
wiringPiSetupGpio();
handle = wiringPiI2CSetup(DEVICE_ADDRESS);
● 215
C Programming on Raspberry Pi
The program can be compiled and run using the following commands:
When the program is run, the data ABCD will be displayed on the screen.
Description:
In this project, the I2C compatible TMP102 temperature sensor chip is used. Ambient
temperature is read every second and then displayed on the PC screen.
Aim:
This project aims to show how the TMP102 temperature sensor chip can be used in a
program.
The TMP102
The TMP102 is a highly accurate I2C temperature sensor chip with a built-in thermostat. It
has the following basic features:
The TMP102 is a 6-pin chip as shown in Figure 7.14. The pin descriptions are:
● 216
Chapter 7 ● I2C Bus Interface
A Pointer Register selects various registers in the chip as shown in Table 7.1. The upper
6 bits of this register are 0s.
● 217
C Programming on Raspberry Pi
P1 P0 Register Selected
Temperature register
0 0
(read-only)
0 1 Configuration register
1 0 TLOW register
1 1 THIGH register
Table 7.1 Pointer register bits
Table 7.2 shows the temperature register bits in normal mode (EM = 0).
BYTE 1:
D7 D6 D5 D4 D3 D2 D1 D0
T11 T10 T9 T8 T7 T7 T5 T4
BYTE 2:
D7 D6 D5 D4 D3 D2 D1 D0
T3 T2 T1 T0 0 0 0 0
Table 7.2 Temperature register bits
Table 7.3 shows the configuration register bits. The power-up default bit configuration is
shown in the table.
BYTE 1:
D7 D6 D5 D4 D3 D2 D1 D0
OS R1 R0 F1 F0 POL TM SD
0 1 1 0 0 0 0 0
BYTE 2:
D7 D6 D5 D4 D3 D2 D1 D0
CR1 CR0 AL EM 0 0 0 0
1 0 1 0 0 0 0 0
Table 7.3 Configuration register bits
The Polarity bit (POL) allows the user to adjust the polarity of the Alert pin output. If set
to 0 (default), the Alert pin becomes active low. When set to 1, it becomes active high.
The default device address is 0x48 as shown in Figure 7.15. TMP102 is available as a
module (breakout) as shown in Figure 7.16. The temperature register address is 0x00 and
should be sent after sending the device address. This is then followed by a read command
where 2 bytes are read from the TMP102. These 2 bytes contain the temperature data.
● 218
Chapter 7 ● I2C Bus Interface
• Master sends the device address 0x48 with the R/W set to 0.
• Device responds with ACK.
• Master sends the temperature register address 0x00.
• Device responds with ACK.
• Master re-sends device address 0x48 with the R/W bit set to 1.
• Master reads upper byte of temperature data.
• Device sends ACK.
• Master reads lower byte of temperature data.
• Device sends ACK.
• Master sends stop condition on the bus.
Block diagram:
● 219
C Programming on Raspberry Pi
Circuit diagram:
The circuit diagram of the project is shown in Figure 7.18. On-chip pull-up resistors are
available on the TMP102 I2C bus lines.
Program listing:
Figure 7.19 shows the program listing (Program: TMP102.c). In this program, GPIO pin
numbering is used. Port pins GPIO 2 and 3 I2C of Raspberry Pi are used as in the previous
program. At the beginning of the program, the I2C address of TMP102 and the Pointer
register addresses are defined. The Pointer register is set to 0 to select the temperature
register.
The program runs inside a while loop. Here, the temperature is read from TMP102 and
stored in integer arrays buf[0] and buf[1]. These two bytes are then combined to form
the 12-bit temperature data in variable Temp. If the temperature is negative, it is in 2’s
complement form and its complement is taken and 1 is added to find the true negative
value. By multiplying Temp with the LSB, we find the temperature in degrees centigrade.
The temperature is then displayed on the PC screen as a floating-point number.
The above process is repeated after a one-second delay. Table 7.4 shows the data output
format of the temperature. Let us look at two examples:
● 220
Chapter 7 ● I2C Bus Interface
/*---------------------------------------------------------------------
TMP102 I2C TEMPERATURE SENSOR
=============================
//
// Start of MAIN program, read the 12-bit temperature, format as
// required (if negative) and display
//
int main(void)
● 221
C Programming on Raspberry Pi
{
int handle, Temp, buf[2];
float temperature, LSB = 0.0625;
wiringPiSetupGpio();
handle = wiringPiI2CSetup(DeviceAddress);
while(1)
{
wiringPiI2CWrite(handle, PointerReg);
buf[0] = wiringPiI2CRead(handle);
buf[1] = wiringPiI2CRead(handle);
Temp = (buf[0] << 4) | (buf[1] >> 4);
● 222
Chapter 7 ● I2C Bus Interface
Description:
In this project, we will be using an I2C based LCD with Raspberry Pi. The text Raspberry Pi
will be displayed on the LCD.
Aim:
This project aims to show how an I2C based LCD can be used with Raspberry Pi when
programming in C.
Circuit diagram:
I2C based LCDs usually consist of a PCF8574 type 8-bit I/O expander chip connected on the
back of a standard HD44780 type parallel LCD. The LCD is controlled in 4-bit mode by the
PCF8574 chip through standard SDA and SCL I2C lines. Figure 7.21 shows the front and
back views of a PCF8574 based I2C LCD. A small pot is provided on the back for adjusting
the contrast of the LCD.
The circuit diagram of the LCD is shown in Figure 7.22. The connections between the LCD
and PCF8574 chip are as follows:
● 223
C Programming on Raspberry Pi
PCF8574 LCD
P0 R/S
P1 R/W
P2 E
P3 LCD backlight
P4 D4
P5 D5
P6 D6
P7 D7
Internal pull-up resistors are used on the LCD module. Therefore there is no need to
connect external pull-up resistors. The backlight of the LCD is controlled from pin P3 of the
PCF8574. Setting P3 to logic 1 turns the LCD backlight ON.
Figure 7.23 shows the circuit diagram of the project where the SDA and SCL pins of the
PCF8574 expander chip are connected to port pins GPIO 2 (SDA) and 3 (SCL) of Raspberry
Pi.
● 224
Chapter 7 ● I2C Bus Interface
Program listing:
Before developing the program, it is worthwhile to look at the basic operation of the PCF8574
expander chip. The chip has 8 digital outputs called P0 – P7, two I2C control inputs SDA and
SCL, and three device address inputs called A0 – A2. It can operate from +2.5V to +6V. The
device address is the logical OR of 0x20 with (A2 A1 A0). In Figure 7.22, all address inputs
A0, A1, A2 are connected to +5V through 10K resistors and therefore, the device address
is 0x20 | 7 = 0x27. Figure 7.24 shows the chip as identified by Raspberry Pi.
wiringPi directly supports the PCF8574 chip making programming the chip very easy.
The header file <pcf8574.h> must be included at the beginning of the program. Data is
outputted from the chip using standard digitalWrite functions. The chip is initialised by
calling function pcf8574Setup with two arguments: an index number and device address.
The index number is used while accessing the output port pins. For example, if the index
is initialised as 100, then digitalWrite(100, data) will send the data (0 or 1) to port P0,
digitalWrite(101, data) will send the data to port pin P1 and so on.
The LCD must be initialised with the correct sequence before it can be used. The details of
this initialisation sequence is beyond the scope of this book. It can be found at many sites
on the internet. The basic initialisation details are provided below.
● 225
C Programming on Raspberry Pi
The LCD can operate in either command or data mode, selected by pin RS. When RS is
0, command mode is selected and any data sent to the LCD is treated as a command.
Examples of commands are: clearing the LCD, homing the cursor, and moving the cursor to
the required column and row. Examples of data are displaying text or numbers on the LCD.
Figure 7.25 shows the program listing (Program: I2CLCD.c). GPIO pin numbering is used
in this program. The main program simply calls function lcd_puts to display the text
Raspberry Pi. At the beginning of the program, the connections between the LCD and the
PCF8574 expander chip are defined. PCF is the index used here. PCF+0 is set to index port
pin P0 (LCD RS pin), PCF+1 to index P1 (LCD RW pin), PCF+2 to index P2 (LCD E pin),
and so on.
The LCD program consists of several functions. Function lcd_init must be called before any
other LCD function is used. This function initialises the LCD to operate with 4-bits of data
mode. Function lcd_strobe sends a pulse to the LCD so the given command is accepted.
This pulse consists of setting the E pin to logic 1 for a very short time and then setting
it back to 0. Function lcd_write writes either a command or data to the LCD. The first
argument is the command or data to be written. The second argument specifies whether
this is a command (if 0), or data (if 1). The command or data byte is sent as two nibbles
where the upper nibble is sent first, followed by the lower.
The other functions are used in command mode and have the following definitions:
lcd_home: set the cursor to the home position (top left pixel).
lcd_goto: move the cursor to the specified column, row. (0, 0) is the top-left pixel. The top
row is 0, and the bottom row is 1. Column 0 is the first column at the left.
● 226
Chapter 7 ● I2C Bus Interface
/*---------------------------------------------------------------------
I2C LCD
=======
int handle;
void lcd_strobe(void);
d = c;
for(i = 0; i < 4; i++)
{
● 227
C Programming on Raspberry Pi
b = d & 1;
digitalWrite(PCF+4+i, b);
d = d >> 1;
}
digitalWrite(RS, mode);
lcd_strobe();
delay(0.1);
digitalWrite(RS, HIGH);
}
//
// This function send strobe pulse to LCD
//
void lcd_strobe(void)
{
digitalWrite(E, HIGH);
delay(0.1);
digitalWrite(E, LOW);
delay(0.1);
}
//
// This function clears the LCD
//
void lcd_clear(void)
{
lcd_write(0x01, 0);
delay(5);
}
//
// This function homes the cursor
//
void lcd_home(void)
{
lcd_write(0x02, 0);
delay(5);
}
//
// This function sets cursor blinking ON
//
void lcd_cursor_blink_on()
{
lcd_write(0x0D, 0);
delay(1);
● 228
Chapter 7 ● I2C Bus Interface
//
// This function sets cursor blinking OFF
//
void lcd_cursor_blink_off()
{
lcd_write(0x0C, 0);
delay(1);
}
//
// This function sets cursor ON
//
void lcd_cursor_on()
{
lcd_write(0x0E, 0);
delay(1);
}
//
// This function sets cursor OFF
//
void lcd_cursor_off()
{
lcd_write(0x0C, 0);
delay(1);
}
//
// This function displays string
//
void lcd_puts(const char *s)
{
while(*s) lcd_write(*s++, 1);
}
//
// This function displays a character
//
void lcd_putch(unsigned char c)
{
lcd_write(c, 1);
}
//
● 229
C Programming on Raspberry Pi
//
// This function initializes the LCD
//
void lcd_init(void)
{
char i;
delay(120);
for(i = 0; i < 8; i++)digitalWrite(PCF+i, 0);
delay(50);
digitalWrite(D4, 1); digitalWrite(D5, 1);
lcd_strobe();
delay(10);
lcd_strobe();
delay(10);
lcd_strobe();
delay(10);
digitalWrite(D4, 0);
lcd_strobe();
delay(5);
lcd_write(0x28, 0); //28
delay(1);
lcd_write(0x08,0); //0f
delay(1);
lcd_write(0x01,0);
delay(10);
lcd_write(0x06,0);
delay(5);
lcd_write(0x0C,0);
delay(10);
digitalWrite(LED, 1);
}
//
● 230
Chapter 7 ● I2C Bus Interface
pcf8574Setup(PCF, DeviceAddress);
lcd_init();
lcd_clear();
lcd_home();
lcd_cursor_blink_off();
lcd_cursor_on();
lcd_goto(0,0);
// lcd_putch(‘B’);
lcd_puts("at x,y");
// while(1);
}
Figure 7.25 Program I2CLCD.c
There are many situations where we may want to use the I2C LCD in our projects. It will be
easier if we put all the LCD functions in a library and link this library with our main program
so that we don’t have to include the LCD source code in our program. Such an approach
will make our programs very tidy and easy to follow.
The steps to put the LCD functions in a library are given below:
• Create the main program (Program: LCDmain.c) which consists of a few lines of code
as shown in Figure 7.26. This program simply displays text on the LCD.
• Create a file that contains the LCD functions (File: lcdfunc.c) as shown in Figure 7.27
• Compile the functions program (this will create the compiled file lcdfunc.o):
gcc –c lcdfunc.c
• Create a library, e.g. with the name liblcd (this will create the library file liblcd.a):
ar –cvq liblcd.a lcdfunc.o
• Include header file lcdinc.h at the beginning of the main program LCDmain.c program
(Figure 7.28). Make sure that the lcdinc.h file is in your default directory.
• Compile and link the main program (this will create executable file LCDmain):
● 231
C Programming on Raspberry Pi
sudo ./LCDmain
/*---------------------------------------------------------------------
I2C LCD
=======
//
// Start of MAIN program.
//
int main(void)
{
wiringPiSetupGpio();
pcf8574Setup(PCF, DeviceAddress);
lcd_init();
lcd_clear();
lcd_goto(0,5);
lcd_puts("Elektor");
}
Figure 7.26 Program LCDmain.c
/*---------------------------------------------------------------------
I2C LCD FUNCTIONS
=================
● 232
Chapter 7 ● I2C Bus Interface
void lcd_strobe(void);
d = c;
for(i = 0; i < 4; i++)
{
b = d & 1;
digitalWrite(PCF+4+i, b);
d = d >> 1;
}
digitalWrite(RS, mode);
lcd_strobe();
delay(0.1);
digitalWrite(RS, 1);
}
//
// This function send strobe pulse to LCD
//
void lcd_strobe(void)
{
digitalWrite(E, 1);
delay(0.1);
digitalWrite(E, 0);
● 233
C Programming on Raspberry Pi
delay(0.1);
}
//
// This function clears the LCD
//
void lcd_clear(void)
{
lcd_write(0x01, 0);
delay(5);
}
//
// This function homes the cursor
//
void lcd_home(void)
{
lcd_write(0x02, 0);
delay(5);
}
//
// This function sets cursor blinking ON
//
void lcd_cursor_blink_on(void)
{
lcd_write(0x0D, 0);
delay(1);
}
//
// This function sets cursor blinking OFF
//
void lcd_cursor_blink_off(void)
{
lcd_write(0x0C, 0);
delay(1);
}
//
// This function sets cursor ON
//
void lcd_cursor_on(void)
{
lcd_write(0x0E, 0);
delay(1);
● 234
Chapter 7 ● I2C Bus Interface
//
// This function sets cursor OFF
//
void lcd_cursor_off(void)
{
lcd_write(0x0C, 0);
delay(1);
}
//
// This function displays string
//
void lcd_puts(const char *s)
{
while(*s) lcd_write(*s++, 1);
}
//
// This function displays a character
//
void lcd_putch(unsigned char c)
{
lcd_write(c, 1);
}
//
// This function positions cursor at col,row. Top left is 0,0
//
void lcd_goto(int col, int row)
{
char address, c;
c = col + 1;
if(row == 0)address = 0;
if(row == 1)address = 0x40;
address += c - 1;
lcd_write(0x80 | address, 0);
}
//
// This function initializes the LCD
//
void lcd_init(void)
{
char i;
● 235
C Programming on Raspberry Pi
delay(120);
for(i = 0; i < 8; i++)digitalWrite(PCF+i, 0);
delay(50);
digitalWrite(D4, 1); digitalWrite(D5, 1);
lcd_strobe();
delay(10);
lcd_strobe();
delay(10);
lcd_strobe();
delay(10);
digitalWrite(D4, 0);
lcd_strobe();
delay(5);
lcd_write(0x28, 0); //28
delay(1);
lcd_write(0x08,0); //0f
delay(1);
lcd_write(0x01,0);
delay(10);
lcd_write(0x06,0);
delay(5);
lcd_write(0x0C,0);
delay(10);
digitalWrite(LED, 1);
}
Figure 7.27 File lcdfunc.c
/*-------------------------------------
Author: Dogan Ibrahim
Date : December 2020
File : lcdinc.h
--------------------------------------*/
int handle;
void lcd_strobe(void);
void lcd_write(unsigned char, int);
void lcd_clear(void);
void lcd_home(void);
void lcd_cursor_blink_on(void);
void lcd_cursor_blink_off(void);
void lcd_cursor_on(void);
void lcd_cursor_off(void);
void lcd_puts(const char*);
void lcd_putch(unsigned char);
void lcd_goto(int, int);
void lcd_init(void);
Figure 7.28 File lcdinc.h
● 236
Chapter 7 ● I2C Bus Interface
Note: you can use the following command to display the contents of library liblcd.a.
ar –t liblcd.a
7.7 ● Project 5 – Using the pigpio library with I2C – TMP102 temperature display
Description:
In this project, the pigpio library is used to read the temperature from the TMP102
temperature sensor chip. Temperature is displayed on the PC screen.
Aim:
This project aims to show how the TMP102 temperature sensor chip can be used in a pigpio
program.
Block diagram:
Circuit diagram:
Program listing:
The pigpio library supports many I2C functions. A list of commonly used I2C functions are
described below (see link for all functions and their details:
http://abyz.me.uk/rpi/pigpio/cif.html#i2cOpen ):
i2cWriteWordData: this function writes two bytes (16-bits) to the specified register.
i2cReadWordData: this function reads two bytes (16-bits) from the specified register.
● 237
C Programming on Raspberry Pi
i2cReadBlockData: this function reads 4 bytes (32-bits) data from the specified register.
Figure 7.29 shows the program listing (Program: TMP102pigpio.c). At the beginning of
the program, the I2C bus is initialised by calling function i2cOpen. The I2C bus we are
using is Bus 1, corresponding to GPIO 2 (SDA) and 3 (SCL). Bus 0 corresponds to GPIO 0
(SDA) and 1(SCL). The function returns a handle that is used when other I2C functions are
called. Inside the main program loop, temperature register TempReg is addressed, and
the high and low bytes of temperature are then read into buf[0] and buf[1]. The physical
temperature is then calculated as described in Section 7.5 and displayed on the PC screen.
This process is repeated every second.
/*---------------------------------------------------------------------
TMP102 I2C TEMPERATURE SENSOR
=============================
● 238
Chapter 7 ● I2C Bus Interface
gpioInitialise();
handle = i2cOpen(I2CBus, DeviceAddress, 0);
while(1)
{
i2cWriteByte(handle, TempReg);
buf[0] = i2cReadByte(handle);
buf[1] = i2cReadByte(handle);
7.8 ● Summary
In this chapter, we learned how to use I2C functions with wiringPi and pigpio libraries.
Several working projects are provided in the chapter with full hardware and software details.
In the next chapter, we will focus on the topic of the SPI bus.
● 239
C Programming on Raspberry Pi
8.1 ● Overview
In the last chapter, we learned how to interface I2C devices to our Raspberry Pi and develop
projects using C.
In this chapter, we will be developing projects using the SPI bus (serial Peripheral Interface)
with the Raspberry Pi. The SPI bus is one of the commonly used protocols to connect sensors
and other devices to microcontrollers. The SPI bus is a master-slave type bus protocol. In
this protocol, one device (the microcontroller) is designated as the master, and one or more
other devices (usually sensors) are designated as slaves. In a minimum bus configuration,
there is one master and only one slave. The master establishes communication with the
slaves and controls all activity on the bus.
Figure 8.1 shows an SPI bus example with one master and three slaves. The SPI bus uses
three signals: clock (SCK), data in (SDI), and data out (SDO). The SDO of the master is
connected to the SDIs of the slaves. SDOs of the slaves are connected to the SDI of the
master. The master generates SCK signals to enable data to be transferred on the bus. In
every clock pulse, one bit of data is moved from master to slave, or from slave to master.
The communication is only between a master and a slave, and slaves cannot communicate
with each other. It is important to note that only one slave can be active at any one
time because there is no mechanism to identify slaves. Thus, slave devices have enable
lines (e.g. CS or CE) which are normally controlled by the master. Typical communication
between a master and several slaves is as follows:
Figure 8.1 SPI bus with one master and three slaves
The SPI signal names are also called MISO (Master in, Slave out), and MOSI (Master out,
Slave in). Clock signal SCK is also called SCLK and the CS is also called SSEL. In the SPI
● 240
Chapter 8 ● SPI Bus Interface
projects in this chapter, the Raspberry Pi is the master and one or more slaves are connected
to the bus. Transactions over the SPI bus are started by enabling the SCK line. The master
then asserts the SSEL line LOW so data transmission can begin. Data transmission involves
two registers, one in the master and one in the slave device. Data is shifted out from the
master into the slave with the MSB bit first. If more data is to be transferred, the process
is repeated. Data exchange is complete when the master stops sending clock pulses and
deselects the slave device.
Both the master and slave must agree on clock polarity and phase on the line, both of which
are known as SPI bus modes. These two settings are named Clock Polarity (CPOL) and
Clock Phase (CPHA) respectively. CPOL and CPHA can have the following values:
When CPOL = 0, the active state of the clock is 1, and its idle state is 0. For CPHA = 0,
data is captured on the rising clock, and data is shifted out on the falling clock. For CPHA
= 1, data is captured on the falling edge of the clock and is shifted out on the rising edge
of the clock.
When CPOL = 1, the active state of the clock is 0, and its idle state is 1. For CPHA = 0,
data is captured on the falling edge of the clock and is output on the rising edge. For CPHA
= 1, data is captured on the rising edge of the clock and is shifted out on the falling edge.
When creating an SPI bus variable, we have to specify the GPIO pins for MOSI, MISO, and
SCLK.
There are two SPI modules on the Raspberry Pi 4. The following are the GPIO pins for these
● 241
C Programming on Raspberry Pi
modules:
SPI0 has two chip enable pins: CE0 and CE1. SPI1 has three: CE0, CE1, and CE2. By
default, SPI1 is not enabled and Raspberry Pi allows you to use SPI0 with chip select pins
CE0 and CE1. SPI1 can be enabled with a dtoverlay configured in /boot/config.txt. For
example:
dtoverlay=spi1-3cs
ls /dev/spidev*
Description:
A simple project is given in this section to show how the SPI functions can be used in a
program. This project is very similar to the port expander project 1, given in section 7.3.
In this project, the I2C compatible chip MCP23017 was used. In this project, the SPI bus
compatible port expander chip MCP23S17 is used to give additional 16 I/O ports to the
Raspberry Pi. The operation of the MCP23S17 is identical to the operation of MCP23017,
except the MCP23S17 uses the SPI bus. In this project, an LED is connected to MCP23S17
port pin GPA0 and the LED is flashed ON and OFF every second. A 470 Ohm current limiting
resistor is used in series with the LED.
● 242
Chapter 8 ● SPI Bus Interface
Aim:
This project aims to show how the SPI bus can be used in Raspberry Pi-based projects.
Block diagram:
The block diagram of the project is the same as in Figure 7.2, but the MCP23017 chip is
replaced with MCP23S17.
The MCP23S17
The MCP23S17 is a 28 pin chip with the following features. The pin configuration is shown
in Figure 8.2, which is the same as the pin configuration of MCP23017, but SPI pins are
used instead of I2C pins:
● 243
C Programming on Raspberry Pi
Pin Description
GPA0-GPA7 Port A pins
GPB0-GPB7 Port B pins
VDD Power supply
VSS Ground
SI SPI MOSI data pin
SCK SPI clock pin
SO SPI MISO data pin
CS SPI SSEL chip enable pin
A0-A2 I2C address pins
RESET Reset pin
INTA Interrupt pin
INTB Interrupt pin
Table 8.1 MCP23S17 pin descriptions
The MCP23S17 is a slave SPI device. The slave address contains four upper fixed bits
(0100) and three user-defined hardware address bits (pins A2, A1, and A0) with the read/
write bit filling out the control byte. These address bits are enabled/disabled by control
register IOCON.HAEN. By default, the user address bits are disabled at power-up (i.e.
IOCON.HAEN = 0) and A2 = A1 = A0 = 0 and the chip is addressed with 0x40. As such,
we can use two MCP23S17 chips on SPI0 by connecting one CS bit to CE0, and the other
one to CE1 and addressing both chips with 0x40. By setting bit HAEN to 1, we can change
the addresses of the devices in multiple MCP23S17 based applications (e.g. more than 2)
by connecting the A2, A1, and A0 accordingly. Sixteen such chips can be connected (8 to
CE0 and 8 to CE1), corresponding to 16x16 = 256 I/O ports. Figures 8.3 and 8.4 show the
addressing format. The address pins should be externally biased even if disabled.
● 244
Chapter 8 ● SPI Bus Interface
Like the MCP23017, the MCP23S17 chip has 8 internal registers that can be configured for
its operation. The device can either be operated in 16-bit mode or in two 8-bit mode by
configuring bit IOCON.BANK. On power-up, this bit is cleared which chooses the two 8-bit
mode by default.
The I/O direction of the port pins are controlled with registers IODIRA (at address
0x00) and IODIRB (at address 0x01). Clearing a bit to 0 in these registers makes the
corresponding port pin(s) as output(s). Similarly, setting a bit to 1 in these registers makes
the corresponding port pin(s) input(s). GPIOA and GPIOB register addresses are 0x12 and
0x13 respectively. This is shown in Figure 8.5.
Further information on the MCP23S17 chip can be obtained from the Microchip Inc datasheet
on the following web site:
http://ww1.microchip.com/downloads/en/DeviceDoc/20001952C.pdf
Circuit diagram:
Figure 8.6 shows the circuit diagram of the project. SPI0 pins GPIO 10, GPIO 11, and GPIO
8 are used for the SPI interface.
● 245
C Programming on Raspberry Pi
Program listing:
wiringPi
wiringPi includes the MCP23S17 chip library which makes programming the chip very easy.
The header file <mcp23s17.h> must be included at the beginning of the program. The SPI
bus must be initialised using the following function:
Base is an index that is used to identify the port pins and it must be greater than 64. CE
is the chip enable pin used (0 for CE0 i.e. we are using GPIO 8, and 1 for CE1, i.e. we are
using GPIO 7), address is the address of the chip (0 in this project). The pinMode and
digitalWrite functions can then be used to configure and access the port pins. For example,
if Base = 100, then digitalWrite(100, 1) will set GPA0 to logic 1, digitalWrite(101, 1)
will set GPA1 to logic 1 and so on.
Figure 8.7 shows the program listing (Program: SPILED.c). Notice that in this project, the
SPI bus is initialised as:
Pin GPA0 (index = 100) is configured as an output and a while loop is formed. Inside this
loop, this port is set to logic 1, and then to logic 0 with a one-second delay between each
output.
● 246
Chapter 8 ● SPI Bus Interface
/*------------------------------------------------------------------
MCP23S17 SPI LED FLASH
======================
#define CE 0
#define Base 100
//
// Start of MAIN program
//
int main(void)
{
wiringPiSetupGpio();
mcp23s17Setup(Base, CE, 0); // Use CE0
pinMode(Base, OUTPUT); // LED output
while(1)
{
digitalWrite(Base, LOW); // LED OFF
delay(1000); // 1 second
digitalWrite(Base, HIGH); // LED ON
delay(1000); // 1 second
}
}
Figure 8.7 Program: SPILED.c
You can compile and run the program by entering the following commands:
Modified program:
The program given in Figure 8.7 uses the built-in MCP23S17 functions. We can also program
the MCP23S17 from the first principles by making direct SPI function calls. This is useful to
know as we can program any other SPI bus-based chip using these principles.
● 247
C Programming on Raspberry Pi
The header file <wiringPiSPI.h>must be included at the beginning of the program. The
wiringPi library supports the following SPI functions:
• wiringPiSPISetup: This function initialises the SPI bus. The function has two
arguments: the first is the SPI channel number, and the second is the SPI speed.
Raspberry Pi 4 has two SPI channels: 0, and 1. The SPI speed is an integer in the range
of 500,000 to 32,000,000 Hz. The function returns a handle that is used to reference
the initialised SPI channel. A -1 is returned if the SPI channel cannot be initialized.
The programming of the MCP23S17 chip is as follows (notice that not all SPI devices require
device addresses):
First of all, we have to program the I/O direction register IODIRA to 0 so that PORT A pins
are outputs. This register has address 0x0. We should then program bit 0 of PORT A (pin
GPIOA) where the LED is connected. The address of register GPIOA is 0x12.
Figure 8.8 shows the program listing (Program: SPILED2.c). At the beginning of the
program, the device and register addresses are defined. channel is set to 0 since CS of
MCP23S17 is connected to pin CE0 of the Raspberry Pi. Inside the main program, function
wiringPiSPISetup is called to set the channel number and the speed on the SPI bus. This
function returns a handle which is used in other SPI function calls.
Two functions are used in the program: configure sets register IODIRA so PORT A pins
are outputs. Function send sends a byte (0 or 1) to register GPIOA of MCP23S17 so the
LED is turned ON or OFF as required. You can compile and run the program by entering the
following commands:
● 248
Chapter 8 ● SPI Bus Interface
/*------------------------------------------------------------------
MCP23S17 SPI LED FLASH
======================
int handle;
//
// This function configures the MCP23S17. I/O direction for PORTA
// is set as output
//
void configure()
{
char buff[3];
buff[0]=SPI_Address;
buff[1] = MCP_IODIRA;
buff[2] = 0;
wiringPiSPIDataRW(handle, buff, 3);
}
//
// This function sends data to port GPIOA
//
void send(char RegAddr, char data)
{
char buff[3];
buff[0]=SPI_Address;
buff[1] = RegAddr;
buff[2] = data;
wiringPiSPIDataRW(handle, buff, 3);
● 249
C Programming on Raspberry Pi
//
// Start of MAIN program
//
int main(void)
{
wiringPiSetupGpio();
handle = wiringPiSPISetup(channel, 1000000);
configure();
while(1)
{
send(0x12, 0); // GPIOA (LED ) ON
delay(1000); // 1 sec delay
send(0x12, 1); // GPIOA (LED) OFF
delay(1000); // 1 sec delay
}
}
Figure 8.8 Program SPILED2.c
pigpio
The pigpio library version of the program is similar to Figure 8.8, except the SPI functions
are different. pigpio supports many SPI functions. Some commonly used functions are
described below - see link for a list of all functions and their details:
http://abyz.me.uk/rpi/pigpio/pdif2.html#spi_open
spiOpen: this function opens the SPI channel. The channel number (0 or 1) must be
specified. A handle is returned by the function
spiWrite: this function writes the specified number of bytes to the SPI bus device
spiRead: this function reads the specified number of bytes from the SPI bus device
spiXfer: This function transfers a specified number of bytes to the SPI device. Simultaneously,
a specified number of bytes are received from the SPI device
Figure 8.9 shows the pigpio program listing (Program: SPILED3.c). At the beginning of
the channel used (0 for CE0), and the MCP23S17 registers are defined. As in the previous
program, there are two functions in the program: configure configures the MCP23S17 I/O
direction register. send sends data to the MCP23S17. You can compile and run the program
by entering the following commands:
● 250
Chapter 8 ● SPI Bus Interface
/*------------------------------------------------------------------
MCP23S17 SPI LED FLASH
======================
//
// This function configures the port direction register IODIRA
//
void configure()
{
char buff[3];
buff[0] = SPI_Address;
buff[1] = MCP_IODIRA;
buff[2]=0x0;
spiWrite(handle, buff,3);
}
//
// This function sends data to port register GPIOA
//
void send(char RegAddr, char data)
{
char buff[3];
buff[0] = SPI_Address;
buff[1] = RegAddr;
● 251
C Programming on Raspberry Pi
buff[2] = data;
spiWrite(handle, buff,3);
}
//
// Start of MAIN program
//
int main(void)
{
gpioInitialise();
while(1)
{
send(MCP_GPIOA, 0);
time_sleep(1);
send(MCP_GPIOA, 1);
time_sleep(1);
}
}
Figure 8.9 Program SPILED3.c
8.4 ● Summary
In this chapter, we learned how to interface and use SPI bus devices with Raspberry Pi
projects.
In the next chapter, we will be focusing on the important topic of using Analogue-to-Digital
converters (ADCs) in our Raspberry Pi projects.
● 252
Chapter 9 ● Using Analogue to Digital Converters (ADCs)
9.1 ● Overview
Most sensors, in reality, are analogue and give output voltages or currents which are
proportional to a measured variable. Such sensors cannot be directly connected to digital
computers without using ADCs. In this chapter, we will learn how to connect an analogue
temperature sensor chip to our Raspberry Pi and how to program the Raspberry Pi using
the wiringPi and pigpio libraries.
Most microcontroller systems have ADC modules. Unfortunately, the Raspberry Pi has no
ADC modules and because of this, we have to use an external ADC chip to read external
analogue voltages and convert them into digital. Most ADCs used in general purpose
applications are 8 or 10-bits wide, although some higher-grade professional ones are 16 or
even 32-bit. The conversion time of an ADC is one of its important specifications. This is the
time taken for the ADC to convert an analogue input into digital. The smaller the conversion
time the better. Some cheaper ADCs give converted digital data in serial format, while
some more expensive professional ones provide parallel digital outputs. In this chapter, we
will be using a 10-bit serial output ADC with a reference voltage of +3.3V. When using such
an ADC, the resolution is 3300mV/1024 = 3.22mV per bit. Therefore, an analogue input
voltage of 3.22mV gives a digital output of 00 00000001. 6.44mV gives 00 00000010,
9.66mV gives 00 00000011, and so on.
Description:
In this project, an analogue temperature sensor chip is used to measure and display ambient
temperature every second on a PC screen. The Raspberry Pi does not have any analogue-
to-digital converters (ADC) on-board, so an external ADC chip is used in this project.
Aim:
This project aims to show how an external ADC chip can be connected to a Raspberry Pi and
how temperature can be read and displayed on a monitor using an analogue temperature
sensor chip.
Block Diagram:
● 253
C Programming on Raspberry Pi
Circuit Diagram:
The dual MCP3002 ADC chip is used in this project to provide analogue input capability to
the Raspberry Pi. The chip has the following features:
The MCP3002 is a successive approximation 10-bit ADC with an on-chip sample and hold
amplifier. The device is programmable to operate as either a differential input pair or as
dual single-ended inputs. The device is offered in an 8-pin package. Figure 9.2 shows the
pin configuration of the MCP3002.
● 254
Chapter 9 ● Using Analogue to Digital Converters (ADCs)
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 channel
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 datasheet, SGL/DIFF and ODD/SIGN must be set to 1 and 0 respectively.
Figure 9.3 shows the circuit diagram of the project. A TMP36DZ type analogue 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.3V, GND is connected to system ground, and
Vo is the analogue output voltage. Temperature in degrees centigrade is given by:
The CS, Dout, CLK, and Din pins of the ADC are connected to SPI pins CE0, MISO, SCLK,
and MOSI of the Raspberry Pi respectively.
Program listing:
wiringPi
Figure 9.4 shows the program listing (Program: tmp36.c). Inside the main program,
function get_adc_data is used to read the analogue data between 0 and 1023, where the
channel number (AdcChan) is specified in the function argument as 0 or 1. 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 temperature is displayed on the monitor
every second.
● 255
C Programming on Raspberry Pi
Notice we have to send the start bit, followed by the SGL/DIFF and ODD/SIGN bits and the
MSBF bit to the chip. SGL/DIFF must be set to 1 for single-ended operation, ODD/SIGN
must be set to 0 to select channel 0, MSBF bit set to 1 if the data is expected to come in
MSB bit first format. If MSBF is set to 0 then the data is expected to come in LSB bit first
(see datasheet: https://ww1.microchip.com/downloads/en/DeviceDoc/21294E.pdf). It is
recommendable 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 to configure it to receive from channel 0 with
LSB first: (SGL/DIFF = 1, ODD/SIGN = 0, MSBF = 0) as bytes with leading zeroes for more
stable clock cycle. The general data format is:
0000 000S DCM0 0000 0000 0000
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 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.
Since we sent 3 bytes (24 bits) to the chip, the chip returns 24-bit data (3 bytes) and we
must extract the correct 10-bit ADC data from the 24-bit data. When looking at the timing
diagram in Figure 9.5, we can see that since we sent 0000 0001 where 1 is the start bit,
the data is returned from the chip starting from clock pulse 13 (SGL/DIIF + ODD/SIGN +
MSBF + NULL return = 12). The 24-bit data returned is therefore 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:
By adding the low and high byte, we get the 10-bit converted ADC data as:
● 256
Chapter 9 ● Using Analogue to Digital Converters (ADCs)
DD DDDD DDDD
You must enable the SPI interface on your Raspberry Pi in the configuration menu. The
steps are:
/*------------------------------------------------------------------
ANALOGUE TEMPERATURE SENSOR
=========================
int handle;
//
// Read analogue temperature and return to calling program
//
int get_adc_data(int AdcChan)
{
char buff[3];
int rcv;
buff[0] = 0x01;
buff[1] = (2 + AdcChan) << 6;
buff[2] = 0x0;
● 257
C Programming on Raspberry Pi
//
// Start of MAIN program
//
int main(void)
{
float mv, Temp;
int adc;
wiringPiSetupGpio();
handle = wiringPiSPISetup(channel, 1000000);
while(1)
{
adc = get_adc_data(0); // Read CH0
mv = adc * 3300.0 / 1023.0; // Conv to mv
Temp = (mv - 500.0) / 10.0; // Conv to T
printf("Temperature = %5.2f\n", Temp); // Print
delay(1000); // Wait
}
}
Figure 9.4 Program listing tmp36.c
● 258
Chapter 9 ● Using Analogue to Digital Converters (ADCs)
pigpio
The pigpio version of the program is shown in Figure 9.7 (Program: tmp36-2.c). This
version of the program is very similar to the wiringPi version. Function get_adc_data
receives temperature data from the chip as in the previous program. Two buffers are used:
bufftx and buffrx. bufftx is filled with the start bit, SGL/DIIF, ODD/SIGN, and MSBF. The
data returned by the chip is stored in buffer buffrx. Temperature is extracted and returned
to the calling program.
/*------------------------------------------------------------------
ANALOGUE TEMPERATURE SENSOR
=========================
int handle;
//
// Read analogue temperature and return to calling program
● 259
C Programming on Raspberry Pi
//
int get_adc_data(int AdcChan)
{
char bufftx[3], buffrx[3];
int rcv;
bufftx[0] = 0x01;
bufftx[1] = (2 + AdcChan) << 6;
bufftx[2] = 0x0;
spiXfer(handle, bufftx, buffrx, 3);
rcv = ((buffrx[1] & 15) << 6) + (buffrx[2] >> 2);
return rcv;
}
//
// Start of MAIN program
//
int main(void)
{
float mv, Temp;
int adc;
gpioInitialise();
handle = spiOpen(channel, 1000000, 0);
while(1)
{
adc = get_adc_data(0); // Read CH0
mv = adc * 3300.0 / 1023.0; // Conv to mv
Temp = (mv - 500.0) / 10.0; // Conv to T
printf("Temperature = %5.2f\n", Temp); // Print
time_sleep(1); // Wait
}
}
Figure 9.7 Program tmp36-2.c
9.3 ● Summary
In this chapter, we learned how to use an Analogue-to-Digital converter chip with Raspberry
Pi. A project is provided which uses the analogue temperature sensor chip with the wiringPi
and pigpio libraries.
● 260
Chapter 10 ● Using Digital-to-Analogue Converters (DACs)
10.1 ● Overview
DACs are used to convert digital signals into analogue form. Such converters have many
applications in digital signal processing and digital control applications. For example, we
can generate waveforms by writing programs and convert these waveforms into analogue
forms and output them from our digital computer. We also need DACs if we want to interface
a speaker or other device operating with analogue voltages to a Raspberry Pi.
The Raspberry Pi has no built-in ADC converter and therefore an external DAC chip must
be used to output analogue signals. In this chapter, we will learn how to use a popular DAC
(the MCP4921) chip with Raspberry Pi to generate simple signal waveforms.
Before using the MCP4921, it is worthwhile to look at its features and operation in some
detail. MCP4921 is a 12-bit DAC operating with the SPI bus interface. Figure 10.1 shows the
pin layout of this chip. The basic features are (for more details see the link:
http://ww1.microchip.com/downloads/en/DeviceDoc/21897B.pdf ):
• 12-bit operation
• 20MHz clock support
• 4.5μs settling time
• External voltage reference input
• Unity or 2x Gain control
• 1x or 2x gain
• 2.7 to 5.5V supply voltage
• -40ºC to +125ºC temperature range
● 261
C Programming on Raspberry Pi
In this project, we will be operating the MCP4921 with a gain of 1. As a result, with a
reference voltage of 3.3V and 12-bit conversion data, the LSB resolution of the DAC will be
3300mV / 4096 = 0.8mV
10.3 ● Project 1 - Generating square wave signal with any peak voltage
Description:
In this project, we will be using the DAC to generate a square wave signal with the frequency
of 500Hz (Period = 2ms), and a 50% duty cycle (i.e. ON time = 1ms, OFF time = 1ms).
The output voltage will be a 2V peak (notice this could not be achieved without using a DAC
since the output HIGH voltage of a pin is +3.3V).
Aim:
This project aims to show how a DAC chip can be interfaced with a Raspberry Pi.
Block Diagram:
Circuit Diagram:
The circuit diagram of the project is shown in Figure 10.3. The output of the DAC is
connected to an oscilloscope.
● 262
Chapter 10 ● Using Digital-to-Analogue Converters (DACs)
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. Gain is set to 1x. We then
send the low byte (D0:D7) of data. This means that 0x30 should be added to the upper
byte before sending it to the DAC.
Program listing:
wiringPi
Figure 10.4 shows the program listing (program: squaredac.c). Since we are using a DAC
with reference voltage set to +3.3V (3300mV), and 12-bit wide data (i.e. 4096 steps), the
required digital value to set the output voltage to 2V is given by ONvalue, where:
The OFF value of the signal (OFFvalue) is set to 0V. Function DAC configures the DAC so
that 2V is output from it. First the HIGH byte (in buff[0]) is put into buffer buff, followed
by the LOW byte (in buff[1]):
● 263
C Programming on Raspberry Pi
The duration of the ON and OFF times is set to 1ms. It was found by the experiments
that the DAC routine takes about 0.2ms (0.0002 seconds), and also the delay function of
Raspberry Pi is not very accurate. Because of this, the period and consequent frequency of
the output waveform are not very accurate. ON and OFF times are slightly bigger than 1ms.
Readers can experiment to adjust the delay to get exact 1ms if required.
/*------------------------------------------------------------------
GENERATING SQUARE WAVE SIGNAL USING DAC
=======================================
int handle;
//
// Send data to the DAC chip, HIGH byte first
//
void DAC(int data)
{
char buff[2];
int rcv;
//
// Start of MAIN program
//
int main(void)
{
int ONvalue, OFFvalue;
● 264
Chapter 10 ● Using Digital-to-Analogue Converters (DACs)
ONvalue = (int)(2000*4095/3300);
OFFvalue = 0;
wiringPiSetupGpio();
handle = wiringPiSPISetup(channel, 1000000);
while(1)
{
DAC(ONvalue); // ON value
delay(1); // 1ms delay
DAC(OFFvalue); // OFF value
delay(1); // 1ms delay
}
}
Figure 10.4 Program: squaredac.c
Figure 10.5 shows the output waveform generated by the program. This waveform was
captured using a PCSGU250 type digital oscilloscope. The horizontal axis was set to 1ms/
division. The vertical axis was 1V/division. Peak output voltage is 2V as expected.
pigpio
The pigpio version of the program listing is shown in Figure 10.6 (Program: squaredac2.c).
This program is very similar to the wiringPi version, except function spiOpen is used to
initialise the SPI bus and function spiSend is used to send data to the SPI device. It was
observed by the author that the period of the waveform was slightly more accurate with
this version of the program (see Figure 10.7).
● 265
C Programming on Raspberry Pi
/*------------------------------------------------------------------
GENERATING SQUARE WAVE SIGNAL USING DAC
=======================================
int handle;
//
// Send data to the DAC chip, HIGH byte first
//
void DAC(int data)
{
char buff[2];
int rcv;
//
// Start of MAIN program
//
int main(void)
{
int ONvalue, OFFvalue;
ONvalue = (int)(2000*4095/3300);
OFFvalue = 0;
gpioInitialise();
handle = spiOpen(channel, 1000000, 0);
while(1)
● 266
Chapter 10 ● Using Digital-to-Analogue Converters (DACs)
{
DAC(ONvalue); // ON value
time_sleep(0.001); // 1ms delay
DAC(OFFvalue); // OFF value
time_sleep(0.001); // 1ms delay
}
}
Figure 10.6 Program squaredac2.c
Description:
In this project we will be using the DAC to generate a sawtooth wave signal with the
following specifications:
Circuit Diagram:
● 267
C Programming on Raspberry Pi
Program Listing:
wiringPi
Figure 10.8 shows the program listing (program: sawtooth.c). The program is very similar
to the one given in Figure 10.4. Function DAC sends data to the DAC converter. Inside the
main program loop, variable i is incremented from 0 to 1.0 in steps of 0.1, and a 0.1ms
delay is inserted between each output.
/*------------------------------------------------------------------
GENERATING SAWTOOTH WAVE SIGNAL USING DAC
=========================================
int handle;
//
// Send data to the DAC chip, HIGH byte first
//
void DAC(int data)
{
char buff[2];
//
// Start of MAIN program
//
int main(void)
{
● 268
Chapter 10 ● Using Digital-to-Analogue Converters (DACs)
float i;
int val;
wiringPiSetupGpio();
handle = wiringPiSPISetup(channel, 1000000);
while(1)
{
i = 0.0;
while(i < 1.1)
{
val = (int)(i * 4095);
DAC(val);
i = i + 0.1;
delay(0.1);
}
}
}
Figure 10.8 Program: sawtooth.c
An example output waveform taken from the oscilloscope is shown in Figure 10.9. In this
figure, the horizontal axis was 0.5ms/division. The vertical axis was 1V/division.
pigpio
The pigpio version of the program listing is shown in Figure 10.10 (Program: sawtooth2.c).
● 269
C Programming on Raspberry Pi
This program is very similar to the wiringPi version, except function spiOpen is used to
initialise the SPI bus and function spiSend is used to send data to the SPI device. The
author observed that the waveform is not as accurate as the one in Figure 10.9.
/*------------------------------------------------------------------
GENERATING SAWTOOTH WAVE SIGNAL USING DAC
=========================================
int handle;
//
// Send data to the DAC chip, HIGH byte first
//
void DAC(int data)
{
char buff[2];
//
// Start of MAIN program
//
int main(void)
{
float i;
int val;
gpioInitialise();
● 270
Chapter 10 ● Using Digital-to-Analogue Converters (DACs)
while(1)
{
i = 0.0;
while(i < 1.1)
{
val = (int)(i * 4095);
DAC(val);
i = i + 0.1;
time_sleep(0.0001);
}
}
}
Figure 10.10 Program sawtooth2.c
10.5 ● Summary
In this chapter, we learned how to use DAC converters in our Raspberry Pi projects using
both wiringPi and pigpio libraries.
● 271
C Programming on Raspberry Pi
11.1 ● Overview
Serial communication is a simple means of sending data over long distances quickly and
reliably. The most commonly used serial communication method is based on the RS232
standard. Using this standard, data is sent over a single line from a transmitting device
to a receiving device in bit-serial format at a pre-specified speed, also known as the Baud
rate, or the number of bits sent each second. Typical Baud rates are 4800, 9600, 19200,
38400, etc.
In standard RS232 communication, logic high is defined as -12V. Logic 0 is at +12V. Figure
11.1 shows how character "A" (ASCII binary pattern 0010 0001) is transmitted over a serial
line. The line is normally idle at -12V. The start bit is first sent by the line going from high
to low. Then eight data bits are sent, starting from the least significant bit. Finally, the stop
bit is sent by raising the line from low to high.
In a serial connection, a minimum of three lines are used for communication: transmit
(TX), receive (RX), and ground (GND). Some high-speed serial communication systems use
additional control signals for synchronisation, such as CTS, DTR, and so on. Some systems
use software synchronisation techniques where a special character (XOFF) is used to tell
the sender to stop sending. Another character (XON) is used to tell the sender to re-start
transmission. RS232 devices are connected using two types of connector: a 9-way, and 25-
way. Table 11.1 shows the TX, RX, and GND pins of each type of connector. The connectors
used in RS232 serial communication are shown in Figure 11.2.
● 272
Chapter 11 ● Using Serial Communication
9-pin connector
Pin Function
2 Transmit (TX)
3 Receive (RX)
5 Ground (GND)
25-pin connector
2 Transmit (TX)
3 Receive (RX)
7 Ground (GND)
Table 11.1 Minimum pins required for RS232 serial communication
As described above, RS232 voltage levels are ±12V. On the other hand, microcontroller
input-output ports operate at 0 to +5V voltage levels. It is therefore necessary to translate
the voltage levels before a microcontroller can be connected to an RS232 compatible device.
Thus, the output signal from the microcontroller has to be converted into ±12V, and the
input from an RS232 device must be converted into 0 to +5V before it can be connected
to a microcontroller. This voltage translation is normally done using special RS232 voltage
converter chips. One such popular chip is the MAX232. This is a dual converter chip having
the pin configuration as shown in Figure 11.3. This particular device requires four external
1μF capacitors for its operation.
● 273
C Programming on Raspberry Pi
Nowadays, serial communication is done using standard TTL logic levels instead of ±12V,
where logic 1 is +5V (or greater than +3V) and logic 0 is 0V. A serial line is idle when
voltage is at +5V. The start bit is identified on the high-to-low transition of the line, i.e. the
transition from +5V to 0V.
The Raspberry Pi has two built-in UARTs: a PL011 and a mini UART. They are implemented
using different hardware blocks and have slightly different characteristics. Since both are
3.3V devices, extra care must be taken when connecting to other serial communication
lines operating at higher voltages (e.g. +5V).
By default, on the Raspberry Pi 4, the primary UART (serial0) is assigned to the Linux
console. Using the serial port for other purposes requires this default configuration to be
changed. On startup, systemd checks the Linux kernel command line for any console
entries and will use the console defined therein. To stop this behaviour, the serial console
setting needs to be removed from the command line. This is done as follows:
● 274
Chapter 11 ● Using Serial Communication
On Raspberry Pi 3 and 4, the serial port (/dev/ttyS0) is routed to two pins GPIO14 (TXD)
and GPIO15 (RXD) on the header. This port is stable and of good quality. Earlier models
than the 3 use this port for Bluetooth. Instead, a serial port is created in software (/dev/
ttyS0).
Description:
In this project, the Raspberry Pi is connected to an Arduino Uno through its TXD and RXD
pins. The Raspberry Pi sends the message Hello Arduino, this is Raspberry Pi. Arduino
receives and displays this message on its serial monitor and responds with the message
Hello Raspberry Pi, I am OK which is displayed on the Raspberry Pi PC screen.
Aim:
This project aims to show how the serial port of the Raspberry Pi can be used for 2-way
communication.
Block diagram:
● 275
C Programming on Raspberry Pi
Circuit diagram:
The circuit diagram of the project is shown in Figure 11.5. In this project, software serial
ports of the Arduino UNO are used. The input voltage levels of the Raspberry Pi are not
compatible with the output voltage levels of the Arduino. A resistive potential divider circuit
consisting of 1K and 2K resistors is used to lower the output HIGH voltage of the Arduino
to +3.3V.
Program listing:
wiringPi
The header file <wiringSerial.h> must be included at the beginning of the program. The
library supports the following serial communication functions (see link:
http://wiringpi.com/reference/serial-library/ ):
serialOpen: This function opens and initialises the serial port. The baud rate and device
must be specified in the arguments. The read timeout is set to 10 seconds by default. The
function returns a file descriptor handle.
serialClose: This function closes an open serial port. The file descriptor handle must be
specified as an argument to the function
serialPutchar: This function sends the single-byte passed as the second argument. The
first argument is the file descriptor handle.
serialPuts: This function sends a NULL-terminated string to the serial device. The first
argument is the file descriptor handle. The second argument is a pointer to the string.
serialPrintf: This function is similar to printf. The first argument is the file descriptor
handle, while other arguments are as in the printf function
serialDataAvail: This function returns the number of characters available in the receive
buffer. The file descriptor handle is the only argument of this function
● 276
Chapter 11 ● Using Serial Communication
serialGetchar: This function reads a single character from the serial device. The function
has only one argument which is the file descriptor handle.
serialFlush: This function discards all received data, thus clearing the receive buffer. The
file descriptor handle must be specified as the only argument of the function
In some applications, we may want to set the communications parameters and not use
the default ones. This is done by including the header file <termios.h>. There are many
options available (see link for all options:
https://pubs.opengroup.org/onlinepubs/007908799/xsh/termios.h.html). Some commonly
used options are as follows:
Baud rate: B1200, B2400, B4800, B9600, B19200, B38400, B57600, B115200, B230400,
B460800, B500000, B576000, B921600, B1000000, B1152000, B1500000, B2000000,
B2500000, B3000000, B3500000, B4000000
For example, to set the port to 9600 Baud, 8-bit data, even parity, ignore parity errors (fd
is the file descriptor handle):
structtermiosoptions ;
tcgetattr(fd, &options); // Read options
options.c_cflag = B9600 | CS8 | CLOCAL | CREAD, PARENB;
options.c_iflag = IGNPAR;
tcsetattr(fd, &options); // Set options
Where c_cflag are the control modes, c_oflag are the output modes, c_iflag the input
modes, and c_lflag the local modes.
The Raspberry Pi program listing is given in Figure 11.6 (Program: RPIserial.c). At the
beginning of the program, function serialOpen is called with the device name set to /dev/
ttyS0 with the Baud rate set to 9600. The message Hello Arduino, this is Raspberry
Pi is then sent to the Arduino using the serialPrintf function. The program then waits to
receive a reply message from the Arduino and displays the received message on the PC
screen.
Arduino UNO
The Arduino UNO program listing is shown in Figure 11.7 (Program: ARDUINOserial.c).
● 277
C Programming on Raspberry Pi
The program uses the software serial library where I/O pins 6 and 7 are configured as RX
and TX pins and named as MySerial. Inside the setup routine, the Baud rate of both the
serial monitor and the software serial line are set to 9600. Inside the program loop, the
program waits until data is available from the serial port. When data is available, it is read
until a carriage return character is detected. The received data is displayed on the serial
monitor of the Arduino. The program then sends the message Hello Raspberry Pi, I am
OK to the Raspberry Pi which is displayed on the Raspberry Pi PC screen.
/*------------------------------------------------------------------
SENDING AND RECEIVING SERIAL DATA
=================================
This program sends the text "Hello Arduino, this is Raspberry Pi" to
the Arduino UNO. This message is displayed on Arduino UNO serial
monitor. Arduino replies with the text "Hello Raspberry Pi, I am
OK" which is displayed on the RAspberry Pi PC screen
int handle;
//
// Start of MAIN program
//
int main(void)
{
char *device="/dev/ttyS0";
wiringPiSetupGpio();
handle = serialOpen(device, 9600);
serialPrintf(handle, "Hello Arduino, this is Raspberry Pi\n");
while(1)
{
printf("%c", serialGetchar(handle));
}
serialClose(handle);
}
Figure 11.6 Program RPIserial.c
● 278
Chapter 11 ● Using Serial Communication
/*--------------------------------------------------------
* SERIAL INTERFACE TO RASPBERRY PI
* ================================
* This program receuves a message from Raspberry Pi and
* then replies with another message
*
* Author: Dogan Ibrahim
* File : ARDUINOserial
* DAte : December 2020
*-------------------------------------------------------*/
#include <SoftwareSerial.h>
SoftwareSerial MySerial(6, 7); // RX, TX
//
// Set Baud rates
//
void setup()
{
Serial.begin(9600); // Serial monitor
MySerial.begin(9600); // Software serial
}
//
// Receive msg from Raspberry Pi and reply
//
void loop()
{
char c = 0;
//
// Send reply to Raspberry Pi
//
MySerial.println("Hello Raspberry Pi, I am OK");
while(1);
}
Figure 11.7 ARDUINOserial.c
● 279
C Programming on Raspberry Pi
Figure 11.8 shows both the PC screen and Arduino serial monitor screen.
pigpio
serOpen: This function opens the serial port (first argument) and specifies Baud rate
(second argument). The third argument must be set to 0. A handle is returned by the
function. Valid Baud rates are: 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400,
4800, 9600, 19200, 38400, 57600, 115200, or 230400.
serClose: This function closes the serial port. The handle must be specified as the argument.
serWriteByte: This function writes a byte to the serial port. The first argument is the
handle. The second argument is the byte to be written.
serReadByte: This function reads and returns a byte. The handle must be specified in the
argument
serWrite: This function writes several bytes to the serial port. The first argument is the
handle. The second is the character buffer that holds the data. The last is the byte count.
serRead: This function reads the specified number of bytes and stores them in the buffer.
serDataAvailable: This function returns the number of bytes available in the receive
buffer. The handle must be specified as the argument.
The pigpio version of the Raspberry Pi program is shown in Figure 11.9 (Program:
RPIserial2.c). The program is similar to the one given in Figure 11.8 but pigpio serial
functions are used. Data is sent to the Arduino a byte at a time using function serWriteByte.
When data is available from the Arduino, it is read and displayed on the PC screen using
● 280
Chapter 11 ● Using Serial Communication
/*------------------------------------------------------------------
SENDING AND RECEIVING SERIAL DATA
=================================
This program sends the text "Hello Arduino, this is Raspberry Pi" to
the Arduino UNO. This message is displayed on Arduino UNO serial
monitor. Arduino replies with the text "Hello Raspberry Pi, I am
OK" which is displayed on the RAspberry Pi PC screen
int handle;
//
// Start of MAIN program
//
int main(void)
{
char i, c = 0;
char *device="/dev/ttyS0";
char buff[] = "Hello Arduino, this is Raspberry Pi\n";
gpioInitialise();
handle = serOpen(device, 9600, 0);
do
{
c = buff[i];
serWriteByte(handle, c);
i++;
}while(c != ‘\n’);
while(1)
{
if(serDataAvailable(handle))
printf("%c", serReadByte(handle));
}
● 281
C Programming on Raspberry Pi
serClose(handle);
}
Figure 11.9 Program RPIserial2.c
11.4 ● Summary
In this chapter, we learned how to use the serial communication port of the Raspberry Pi.
An example project is given where the Raspberry Pi communicates with the Arduino UNO.
In the next chapter, we will focus on various other useful and important functions of wiringPi
and pigpio libraries.
● 282
Chapter 12 ● Other Useful Functions wiringPi
12.1 ● Overview
In the last chapter we learned how to interface serial devices to our Raspberry Pi and
program the serial port using wiringPi and pigpio libraries.
The wiringPi library includes some very useful additional functions. In this chapter, we will
look at how to use these functions in simple projects.
Description:
External interrupts are very important features of all microcontrollers as they enable the
processor to quickly respond to external events. When an external interrupt occurs, the
processor stops whatever it is doing and jumps to the Interrupt Service Routine (ISR) to
service the interrupt. After interrupt processing is finished, control returns back to the main
program.
This is an event counter project, where pin GPIO 2 is used as the event input. An event
is said to occur if the pin goes from HIGH to LOW. When an event occurs, a counter is
incremented and the total count is displayed on a PC monitor. In this project, a button is
used to simulate the event occurring on GPIO 2.
Circuit diagram:
Figure 12.1 shows the circuit diagram of the project. A button is connected to GPIO 2. The
button state is at logic 1 and goes to 0 when the button is pressed.
Program listing:
The wiringPi library provides the following function for handling external interrupts on GPIO
pins:
● 283
C Programming on Raspberry Pi
Here, pin is the pin used for external interrupt. edgeType specifies how the interrupt will
be recognised on the pin. Valid options are: INT_EDGE_FALLING, INT_EDGE_RISING,
INT_EDGE_BOTH and INT_EDGE_SETUP. The specified function will be called whenever
an external interrupt is detected. If another interrupt occurs while servicing the current
one, the new interrupt will be saved and will be handled when the current one is completed.
The ISR has full access to all program global variables, and filehandles, etc.
Figure 12.2 shows the program listing (Program: EventInt.c). Inside the main program,
function wiringPiISR is called and external interrupts are initialised on pin Button with
falling edge detection. The ISR function is named MyISR. Inside this routine, variable count
is incremented by one and flag is set to 1. The flag variable is used in the main program
loop to detect if an interrupt has occurred. Contact bouncing is minimised by waiting until
the Button is released and by introducing a short delay after the Button action.
/*------------------------------------------------------------------
EXTERNAL INTERRUPT EVENT COUNTER
================================
//
// tHis is the interrupt service routien. The value of count is
//incremente dby one in this routine
//
void MyISR()
{
count++; // Increment count
flag = 1; // Set flag
● 284
Chapter 12 ● Other Useful Functions wiringPi
//
// Start of MAIN program
//
int main(void)
{
wiringPiSetupGpio();
count = 0;
flag = 0;
pullUpDnControl(Button, PUD_UP);
wiringPiISR(Button, INT_EDGE_FALLING, &MyISR);
while(1)
{
if(flag == 1)
{
flag = 0;
printf("count = %d\n", count);
while(digitalRead(Button) == 0);
delay(20);
}
}
}
Figure 12.2 Program EventInc.c
Modified program:
The circuit diagram given in Figure 12.1 can be simplified by removing the pull-up resistor
and pulling-up the pin in software. The wiringPi function, pullUpDnControl is used to pull-
up/down an I/O pin in software. The first argument of this function is the pin name. The
second number specifies pull-up (PUD_UP) or pull-down (PUD_DOWN). The modified
circuit diagram and program listing (Program: EventInc2.c) are shown in Figures 12.4
and 12.5 respectively.
● 285
C Programming on Raspberry Pi
/*------------------------------------------------------------------
EXTERNAL INTERRUPT EVENT COUNTER
================================
//
// This is the interrupt service routine. The value of count is
//incremented by one in this routine.
//
void MyISR()
{
count++; // Increment count
flag = 1; // Set flag
}
//
// Start of MAIN program
● 286
Chapter 12 ● Other Useful Functions wiringPi
//
int main(void)
{
wiringPiSetupGpio();
count = 0;
flag = 0;
while(1)
{
if(flag == 1)
{
flag = 0;
printf("count = %d\n", count);
while(digitalRead(Button) == 0);
delay(20);
}
}
}
Figure 12.5 Program EventInc2.c
Description:
The tone library of wiringPi can be used to generate a software-controlled square wave
signal on any pin of the Raspberry Pi with a maximum frequency of 5kHz (5000Hz). The
frequency of the generated tone is not very accurate and can be used to generate tones on
a piezo sounder (or a passive buzzer).
Block diagram:
● 287
C Programming on Raspberry Pi
Circuit diagram:
The circuit diagram of the project is shown in Figure 12.7. A passive buzzer is connected
to pin GPIO 2.
Program listing:
The header file <softTone.h> must be included at the beginning of the program in addition
to <wiringPi.h>. The following functions are provided:
softToneCreate: This function creates a software-controlled tone pin. The pin number
must be specified as the argument of the function.
softToneWrite (int pin, intfreq): This function generates tone with the specified
frequency. The first argument of the function is the pin number. The second is the frequency
in Hz. Notice the tone is played until the frequency is set to 0.
The program must be compiled using the lpthread library in addition to the lwiringPi
library.
Figure 12.8 shows the program listing (Program: tone1.c). The program is very simple as
it calls the wiringPi functions to generate a 1kHz signal. The program can be compiled and
run as follows:
● 288
Chapter 12 ● Other Useful Functions wiringPi
/*------------------------------------------------------------------
GENERATE 1kHz SQUARE WAVE TONE
==============================
//
// Start of MAIN program
//
int main(void)
{
wiringPiSetupGpio();
softToneCreate(Buzzer);
softToneWrite(Buzzer, frequency);
while(1)
{
}
}
Figure 12.8 Program tone1.c
Figure 12.9 shows the generated waveform on an oscilloscope. It is clear that the frequency
of the waveform is accurate. In this figure, the horizontal axis was 0.5ms/division and the
vertical was 1V/division.
● 289
C Programming on Raspberry Pi
12.4 ● Project 3 – Using the tone library – sweep frequency tone generation
Description:
In this project we will generate tones from 100Hz to 1000Hz in steps of 50Hz, incremented
every 500ms. The output is repeated every 5 seconds.
The block diagram and circuit diagram of the project are as in Figures 12.6 and 12.7
respectively.
Program listing:
Figure 12.10 shows the program listing (Program: tonesweep.c). The starting and ending
frequencies are set by FreqStart and FreqEnd respectively. Frequency is incremented by
FreqStep which is set to 50.
/*------------------------------------------------------------------
GENERATE TONES FROM 100Hz to 1000Hz
===================================
● 290
Chapter 12 ● Other Useful Functions wiringPi
#include <softTone.h>
wiringPiSetupGpio();
softToneCreate(Buzzer);
while(1)
{
while(freq < FreqEnd)
{
softToneWrite(Buzzer, freq);
freq = freq + FreqStep;
delay(500);
}
freq = 100;
delay(5000);
}
}
Figure 12.10 Program tonesweep.c
12.5 ● Project 4 – Using the tone library – reading the frequency from the keyboard
Description:
In this project, a buzzer is connected to Raspberry Pi pin GPIO 2 as in the previous projects
in this chapter. The user is prompted to enter the frequency of the tone. The frequency
entered is generated by the program. Entering 0 terminates the program and tone.
The block diagram and circuit diagram of the project are as in Figures 12.6 and 12.7
respectively.
Program listing:
Figure 12.11 shows the program listing (Program: tone2.c). Functions fgets and atoi are
used to read the frequency from the user. The maximum frequency is 5000Hz. Entering 0
terminates the program.
● 291
C Programming on Raspberry Pi
/*------------------------------------------------------------------
GENERATE TONE WITH KEYBOARD FERQUENCY
=====================================
//
// Start of MAIN program
//
int main(void)
{
int freq;
char buff[50];
wiringPiSetupGpio();
softToneCreate(Buzzer);
while(1)
{
printf("\n\nEnter frequency (0 to exit - Max 5000Hz): ");
freq = atoi(fgets(buff,10,stdin));
if(freq == 0)break;
printf("Generating tone at freq = %d Hz", freq);
softToneWrite(Buzzer, freq);
}
softToneWrite(Buzzer, 0);
delay(1000);
printf("End of program\n");
}
Figure 12.11 Program tone2.c
● 292
Chapter 12 ● Other Useful Functions wiringPi
Description:
This project shows how tones with different frequencies can be generated and sent to a
passive buzzer device. The project shows how the simple Happy Birthday melody can be
played on the buzzer.
Aim:
This project aims to show how various tones can be generated to create a simple melody.
The block diagram and circuit diagram of the project are as in Figures 12.6 and 12.7
respectively.
Melodies
When playing a melody, each note is played for a certain duration and with a defined
frequency. Also, a particular gap is necessary between two successive notes. The frequencies
of the musical notes starting from middle C (i.e. C4) are given below. The harmonic of a
note is obtained by doubling the frequency. For example, the frequency of C5 is 2 x 262 =
524Hz.
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, we need to know its musical notes. Each note is played for a
certain duration and there is a particular 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 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 multiplied by
400 to give actual durations in milliseconds).
● 293
C Programming on Raspberry Pi
Note C4 C4 D4 C4 F4 E4 C4 C4 D4 C4 G4 F4 C4 C4 C5
Duration 1 1 2 2 2 3 1 1 2 2 2 3 1 1 2
A4 F4 E4 D4 A4# A4# A4 F4 G4 F4
2 2 2 2 1 1 2 2 2 4
Program Listing:
The program listing (program: Melody.c) is shown in Figure 12.13. The frequencies and
durations of the melody are stored in two arrays, frequency and duration. Before the
main program loop, the duration of each tone is calculated and stored in array Duration
so that the main program loop does not have to spend any time to do these calculations.
Inside the program loop, the melody frequencies are generated with the required durations.
Notice the tone output is stopped by setting the frequency to 0. A small delay (100ms) is
introduced between each tone. The melody is repeated after 3 seconds of delay. You can
compile and run the program as follows:
/*------------------------------------------------------------------
MELODY GENERATOR - HAPPY BIRTHDAY
=================================
//
// Melody frequencies
//
int frequency[MaxNotes] = {262,262,294,262,349,330,262,262,294,262,
392,349,262,262,524,440,349,330,294,466,
466,440,349,392,349};
● 294
Chapter 12 ● Other Useful Functions wiringPi
//
// Melody durations
//
int duration[MaxNotes] = {1,1,2,2,2,3,1,1,2,2,2,3,1,1,2,2,2,2,
2,1,1,2,2,2,3};
//
// Start of MAIN program
//
int main(void)
{
int k;
float Durations[MaxNotes];
wiringPiSetupGpio();
softToneCreate(Buzzer);
//
// Play the melody. Generate tones at the required frequencies and
// send them to the buzzer. Insert the correct durations between
// each freqency
//
while(1)
{
for(k = 0; k < MaxNotes; k++)
{
softToneWrite(Buzzer, frequency[k]);
delay(Durations[k]);
softToneWrite(Buzzer, 0);
delay(100);
}
delay(3000);
}
}
Figure 12.13 Program Melody.c
Modify the program given in Figure 12.13 by changing the duration between notes and see
its effects. How can you make the melody run quicker? Also, replace the buzzer with an
audio amplifier and speaker for higher quality and louder output.
● 295
C Programming on Raspberry Pi
wiringPi provides the following timing functions (for full details, see:
http://wiringpi.com/reference/timing/ ):
millis: This function returns a 32-bit number representing the number of milliseconds since
the program called the wiringPiSetup function.
micros: This function returns a 32-bit number representing the number of microseconds
since the program called the wiringPiSetup function.
delay: This function pauses the program for the specified number of milliseconds. Notice
the delay could be longer. The delay is a 32-bit integer and is passed as an argument to
the function.
delayMicroseconds: This function pauses the program for the specified number of
microseconds. Notice the delay could be longer. The delay is a 32-bit integer and is passed
as an argument to the function.
wiringPi provides support for multi-tasking (or multi-threading) which enables the
programmer to create new processes (functions inside a main program) that run
concurrently.
piThreadCreate: This function creates a thread which is a function in the main program.
This newly created function runs concurrently with the main program. The thread name
must be passed as an argument to the function. Multitasking has many applications in
many fields. Perhaps the best-known application is in refreshing multi-digit 7-segment
displays.
PI_THREAD(MyThread)
{
Body of the thread function
}
A thread is started from the main program by using function call piThreadCreate and
passing the thread name as the argument.
Some synchronisation can be established in a program using the piLock and piUnlock
functions. The argument to these functions are key numbers 0 to 3 used by a thread to
prevent access to variables.
● 296
Chapter 12 ● Other Useful Functions wiringPi
A simple example project is given in the next section using 3 threads to flash 3 LEDs at
different rates.
Description:
In this project, 3 LEDs named LEDA, LEDB, and LEDC are connected to the Raspberry Pi.
Block diagram:
Circuit diagram:
The circuit diagram of the project is shown in Figure 12.15. LEDA, LEDB, and LEDC are
connected to GPIO 16, GPIO 20, and GPIO 21 respectively through 470 Ohm resistors.
● 297
C Programming on Raspberry Pi
Program listing:
The program listing (Program: MultiLED.c) is shown in Figure 12.16. At the beginning of
the program, the connections of the three LEDs are defined. There are three threads in this
program named: ThreadLEDA, ThreadLEDB, and ThreadLEDC. ThreadLEDA flashes
LEDA every second. ThreadLEDB flashed LEDB every 500ms. ThreadLEDC flashes LEDC
every 250ms.
Main program configures LEDA, LEDB, and LEDC as outputs and creates the three threads
so they start running concurrently. Notice the main program must not terminate, otherwise,
all threads created by the main program will also terminate.
/*------------------------------------------------------------------
3 LEDs FLASHING AT DIFFERENT RATES
==================================
In this program 3 LEDs are connecte dto Raspberry Pi. The LEDs flash
at different rates since they are controlled by different threads
//
// This thread flashes LEDA every second
//
PI_THREAD(ThreadLEDA)
{
while(1)
{
digitalWrite(LEDA, HIGH);
delay(1000);
digitalWrite(LEDA, LOW);
delay(1000);
}
}
//
// This thread flashes LEDB every 500ms
//
● 298
Chapter 12 ● Other Useful Functions wiringPi
PI_THREAD(ThreadLEDB)
{
while(1)
{
digitalWrite(LEDB, HIGH);
delay(500);
digitalWrite(LEDB, LOW);
delay(500);
}
}
//
// This thread flashes LEDC every 250ms
//
PI_THREAD(ThreadLEDC)
{
while(1)
{
digitalWrite(LEDC, HIGH);
delay(250);
digitalWrite(LEDC, LOW);
delay(250);
}
}
//
// Start of MAIN program
//
int main(void)
{
int t1, t2, t3;
wiringPiSetupGpio();
● 299
C Programming on Raspberry Pi
Description:
In this project, a 7-segment 2-digit multiplexed LED display is used as a counter to count
up every second from 0 to 99. Multi-digit 7-segment displays require continuous refreshing
of their digits so that the human eye sees the digits as steady and non-flashing. The
general technique used is to enable each digit for a short time (e.g. 10ms) so that the
human eye sees both digits ON at any time. This process requires the digits to be enabled
alternately and continuously. As a result, the processor cannot perform any other tasks
and is busy refreshing the digits. One technique used in non-multitasking systems is to use
timer interrupts and refresh digits in the timer interrupt service routines. In this project, we
will be employing a multitasking approach to refreshing the display digits.
Aim:
This project aims to show how the digits of a multiplexed 2-digit 7-segment LED display
can be refreshed in a task, while another task sends data to the display to count up from
0 to 99 in seconds.
7-segment LED displays are frequently used in electronic circuits to show numeric or
alphanumeric values. As shown in Figure 12.17, a 7-segment LED display consists of 7
LEDs connected so that numbers 0 to 9 and some letters can be displayed. Segments
are identified by letters from a to g. Figure 12.18 shows the segment names of a typical
7-segment display.
● 300
Chapter 12 ● Other Useful Functions wiringPi
Figure 12.19 shows how numbers 0 to 9 can be obtained by turning ON different segments
of the display.
7-segment LED displays are available in two different configurations: common cathode
and common anode. As shown in Figure 12.20, in common cathode configuration, all
cathodes of all segment LEDs are connected to ground. The segments are turned ON by
applying a logic 1 to the required segment LED via current limiting resistors. In common
cathode configuration, the 7-segment LED is connected to the microcontroller in current
sourcing mode.
In a common anode configuration, the anode terminals of all the LEDs are connected
● 301
C Programming on Raspberry Pi
as shown in Figure 12.21. This common point is normally then connected to the supply
voltage. A segment is turned ON by connecting its cathode terminal to logic 0 via a current
limiting resistor. In common anode configuration, the 7-segment LED is connected to the
microcontroller in current sinking mode.
In multiplexed LED applications (for example, see Figure 12.22 for a 2-digit LED), the LED
segments of all digits are tied together and the common pins of each digit are turned ON
separately by the microcontroller. By displaying each digit for several milliseconds, the eye
can not differentiate that digits are not ON all the time. This way we can multiplex any
number of 7-segment displays. For example, to display number 53, we have to send 5 to
the first digit and enable its common pin. After a few milliseconds, number 3 is sent to the
second digit and the common point of the second digit is enabled. When this process is
repeated, the user sees it as if both displays are continuously ON.
● 302
Chapter 12 ● Other Useful Functions wiringPi
• Disable digit 1.
• Send the segment bit patter for digit 2 to segments a to g.
• Enable digit 2.
• Wait for a few milliseconds.
• Disable digit 2.
• Continuously repeat the above process.
Pin no Segment
1,5 e
2,6 d
3,8 c
14 digit 1 Enable
17,7 g
15,10 b
16,11 a
18,12 f
13 digit 2 Enable
4 decimal Point1
9 decimal Point 2
Table 9.1 Pin configuration of DC56-11EWA dual display
Block Diagram:
● 303
C Programming on Raspberry Pi
Circuit Diagram:
The circuit diagram of the project is shown in Figure 12.25. In this project, the following
pins of the Raspberry Pi are used to interface with the 7-segment display:
7-segment display segments are driven from the port pins through 470 Ohm current limiting
resistors. Digit enable pins E1 and E2 are driven from port pins GPIO 22 and 24 respectively
through two BC108 type NPN transistors (any other NPN transistor can be used here), used
as switches. The collectors of these transistors drive the segment digits. The segments are
enabled when the base of the corresponding transistor is set to logic 1. Notice the following
pins of the display are connected to form a multiplexed display:
16 and 11, 15 and 10, 3 and 8, 2 and 6, 1 and 5, 17 and 7, 18 and 12.
● 304
Chapter 12 ● Other Useful Functions wiringPi
Program Listing:
Before driving the display, we have to know the relationship between the numbers to be
displayed and the corresponding segments to be turned ON. This is shown in Table 9.2.
GPIO ports 21, 20, 16, 12, 7, 8, 25 are collected together to form an 8-bit port (top bit not
used), and display data is sent to this port. For example, to display number 3 we have to
send the hexadecimal number 0x4F to the port which turns ON segments a,b,c,d, and g.
Similarly, to display number 9, we have to send the hexadecimal number 0x6F to the port
which turns ON segments a,b,c,d,f, and g.
● 305
C Programming on Raspberry Pi
Figure 12.26 shows the program listing (program: Sevenseg.c). The program consists of the
main program and a thread running concurrently. The thread is named as ThreadRefresh
and this refreshes the display. The thread is started from the main program by calling the
piThreadCreate function. Inside the main program, variable cnt is incremented every
second. When it reaches 100, it resets to 0.
ThreadRefresh displays the contents of variable Cnt on the 7-segment 2-digit display.
The bit pattern corresponding to each digit (i.e. Table 9.2) is stored in an array called data.
Initially, both digits are disabled by setting both E1 and E22 to 0. The MSD digit of the Cnt
is extracted and E2 is enabled if the count is greater than 9 so this digit is displayed. If cnt
is less than 10, the left digit is blanked. After a delay of 10ms, the LSD digit is extracted
and E2 disabled. E1 is enabled so this digit is displayed. Each digit is displayed for 10
milliseconds so the eye sees the digits as if they are enabled at the same time.
Function Configure configures the used GPIO pins as outputs and sets them to 0. In this
program, function send sends 7-bit data to the port which is made up of the 7 GPIO port
names stored in array segs.
/*------------------------------------------------------------------
2-DIGIT 7-SEGMENT COUNTER
=========================
//
// Define GPIO pins used for the display
//
int segs[] = {21, 20, 16, 12, 7, 8, 25};
//
// Define 7-segment display bit patterns
//
int data[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F};
#define E1 23 // Digit E1
#define E2 24 // Digit E2
● 306
Chapter 12 ● Other Useful Functions wiringPi
int cnt = 0;
//
// This function sends a byte of data to the display
//
void send(unsigned int No, unsigned int L)
{
unsigned int j, i, m, p, r;
m = L - 1;
for(i = 0; i < L; i++)
{
j = 1;
for(p = 0; p < m; p++)j = 2*j; // Power of 2
r = No & j;
if(r > 0)r = 1;
digitalWrite(segs[i], r);
m--;
}
}
//
// Configure the GPIO ports as outputs and turn them OFF
//
void Configure()
{
char k;
for(k = 0; k < 7; k++)
{
pinMode(segs[k], OUTPUT);
digitalWrite(segs[k], LOW);
pinMode(E1, OUTPUT);
pinMode(E2, OUTPUT);
digitalWrite(E1, LOW);
digitalWrite(E2, LOW);
}
}
//
// This thread refreshes the display. If the count is less than 10
// then the left digit is blanked
//
PI_THREAD(ThreadRefresh)
{
unsigned int LSD, MSD;
● 307
C Programming on Raspberry Pi
while(1)
{
if(cnt > 9)
{
MSD = cnt / 10;
send(data[MSD], 7);
digitalWrite(E2, HIGH);
}
delay(10);
digitalWrite(E2, LOW);
LSD = cnt % 10;
send(data[LSD], 7);
digitalWrite(E1, HIGH);
delay(10);
digitalWrite(E1, LOW);
}
}
//
// Start of MAIN program. Increment count every second
//
int main(void)
{
int t1;
wiringPiSetupGpio();
Configure(); // Configure
while(1) // Do Forever
{
cnt++; // Increment count
if(cnt == 100)cnt = 0; // If 100...
delay(1000); // 1 sec delay
}
}
Figure 12.26 Program Sevenseg.c
● 308
Chapter 12 ● Other Useful Functions wiringPi
pwmSetMode: This function sets the PWM mode as either balanced or as mark/space. The
mode must be passed as an argument to the function. Valid values are PWM_MODE_BAL
and PWM_MODE_MS.
pwmSetRange: This function sets the range register in the PWM generator (default value
is 1024). The range must be passed as an argument to the function.
pwmSetClock (int divisor): This function sets the divisor value for the PWM clock. It
must be passed as an argument to the function.
The GPIO utility is a command-line utility that can be used to test the GPIO pins. In addition
to testing the GPIO pins, this utility has many other useful applications (for full details, see:
https://projects.drogon.net/raspberry-pi/wiringpi/the-gpio-utility/).
Some examples of using the GPIO utility from the command-line are given below.
where option –g causes the pin to be recognised as BCM_GPIO numbering, rather than
wiringPi pin numbering. For example, to set pin GPIO 2 (physical pin number 3) as an
output input the command:
To read the state of all pins and display them as a table (see Figure 12.27):
● 309
C Programming on Raspberry Pi
wiringPi provides direct support for the following chips and add-on boards - see
http://wiringpi.com/
12.14 ● Summary
In this chapter, we looked at the other useful functions of the wiringPi library and have
developed several projects with these functions on Raspberry Pi.
In the next chapter, we will look at other useful functions of the pigpio library.
● 310
Chapter 13 ● Other Useful Functions - pigpio
13.1 ● Overview
In the last chapter, we learned how to use various practical functions of the wiringPi library.
In this chapter, we will be using some practical functions of the pigpio library.
Description:
This project is similar to Project 1 in chapter 12, where an external interrupt is generated
every time an event occurs. An event is said to occur if the pin goes from HIGH to LOW.
When an event occurs, a counter is incremented and the total count is displayed on the PC
monitor.
Circuit diagram:
Program listing:
gpioSetISRFunc: This function calls a function when an external interrupt is detected. The
function has three arguments: the first argument is the GPIO pin number. The second is the
edge which has the valid values: RISING_EDGE, FALLING_EDGE, or EITHER_EDGE.
The third is a timeout value in milliseconds. Setting this argument to 0 disables the timeout.
The last argument is the function to be called when the external interrupt occurs.
Figure 13.1 shows the program listing (Program: ExtInt.c). Function gpioSetISRFunc is
called with the edge set to FALLING_EDGE so that external interrupt is detected when
the button is pressed. The ISR function is called Trigger where the count variable is
incremented by one. The main program displays the total value of count when it changes.
/*------------------------------------------------------------------
EXTERNAL INTERRUPT EVENT COUNTER
================================
In this program a button is connected to GPIO 2. The normal state
of the button is 1. When the button is pressed an external interrupt
is generated which increments a variable. This variable is displayed
on the PC screen.
Author: Dogan Ibrahim
File : ExtInt.c
● 311
C Programming on Raspberry Pi
#define Button 2
int count = 0;
int flag;
//
// This is the ISR which increment count
//
void Trigger()
{
count++;
flag = 1;
}
//
// Start of MAIN program
//
int main(void)
{
gpioInitialise();
gpioSetMode(Button, PI_INPUT);
flag = 0;
gpioSetISRFunc(Button, FALLING_EDGE,0,Trigger);
while(1)
{
if(flag == 1)
{
flag = 0;
printf("Count = %d\n", count);
while(gpioRead(Button) == 0);
time_sleep(0.01);
}
}
}
Figure 13.1 Program ExtInt.c
● 312
Chapter 13 ● Other Useful Functions - pigpio
13.3 ● Timing
The pigpio library provides the following timing functions (for full details see the link:
http://abyz.me.uk/rpi/pigpio/cif.html#gpioHardwareRevision ):
gpioDelay: This function pauses the program for the specified number (32-bit integer) of
microseconds. The actual delay is returned by the function.
gpioTick: This function returns the current system tick as a 32-bit integer.
gpioTime: This function returns the current system time. The function has three arguments:
The first argument is the timetype (0=relative, 1=absolute). The second is the pointer to
an integer which holds the seconds. The last argument is the pointer to an integer which
holds the microseconds. Absolute time is the seconds and microseconds since the Epoch
(1st January, 1970). Relative time is the number of seconds and microseconds since the
library was started.
gpioSleep: This function sleeps for specified seconds and microseconds. The first argument
is the timetype (0=relative, 1=absolute). The second is an integer that specifies the seconds
to sleep. The last is an integer which specifies the number of microseconds to sleep.
time_sleep: As we have seen before, this function delays the execution for the specified
number of seconds which is a double type variable.
An example program is shown in Figure 13.2 (Program: timing.c) which shows how to use
the timing functions.
/*------------------------------------------------------------------
EXAMPLES OF VARIOUS TIMING FUNCTIONS
====================================
int main(void)
{
● 313
C Programming on Raspberry Pi
gpioInitialise();
printf("Delay for 10000 microseconds\n");
gpioDelay(10000);
Timer interrupts are generated by the internal timers of microcontrollers. For example, a
timer can be programmed to generate interrupts at regular intervals. In such applications,
the program jumps to the timer interrupt service routine to execute the required function
code. Another very common application of timer interrupts is to refresh multi-digit
● 314
Chapter 13 ● Other Useful Functions - pigpio
Two simple projects are given in the following sections to show where we can use timer
interrupts.
Description:
In this project, an LED is connected to GPIO 2 pin of the Raspberry Pi through a 470 Ohm
current limiting resistor. The program uses timer interrupts to flash the LED every 500ms.
Program listing:
The pigpio library supports the following function to create timer interrupts (for full details,
see: http://abyz.me.uk/rpi/pigpio/cif.html#gpioSetTimerFunc ):
Figure 13.4 shows the program listing (Program: timint.c). The main program calls
function gpioSetTimerFunc to create a timer interrupt which interrupts the processor
every 500ms. Timer 0 is used in this project. The ISR function is called MyLED. Inside the
ISR, the state of the LED is read and is toggled so if it is ON, it is turned OFF, and if it is
OFF, it is turned ON.
/*------------------------------------------------------------------
TIMER INTERRUPT - FLASHING LED
==============================
#define LED 2
//
// This is the timer interrupt service routine
//
● 315
C Programming on Raspberry Pi
void MyLED(void)
{
if(gpioRead(LED) == 1)
gpioWrite(LED, 0);
else
gpioWrite(LED, 1);
}
//
// Start of main program. Timer 0 is configured to interrupt
// at every 500ms. The ISR function is named MyLED
//
int main(void)
{
gpioInitialise();
gpioSetMode(LED, PI_OUTPUT);
while(1);
}
Figure 13.4 Program timint.c
Description:
Aim:
This project aims to show how timer interrupts can be used to refresh a multi-digit
7-segment LED display.
Block diagram:
Circuit diagram:
● 316
Chapter 13 ● Other Useful Functions - pigpio
Program listing:
Figure 13.5 shows the program listing (Program: Sevensegtim.c). The program
consists of the main program and a timer interrupt service routine function (ISR). The
ISR function is named MyISR and is configured in the main program by calling function
gpioSetTimerFunc. The timer interrupt interval is set to 10 milliseconds which is the
7-segment display refresh time. Function Configure configures the used GPIO ports as
OUTPUTS.
Inside the MyISR function, a flag is used to determine whether to refresh the MSD digit or
the LSD digit. If flag = 0, the MSD digit is refreshed, otherwise the LSD digit is refreshed.
If the number to be displayed is less than 10, the MSD digit is blanked, so for example
number 7 is displayed as 7 and not 07. The bit pattern corresponding to each digit (i.e.
Table 9.2) is stored in an array called data. Function send sends 7-bit data to the port
which is made up of the seven GPIO port names stored in array segs.
/*------------------------------------------------------------------
2-DIGIT 7-SEGMENT COUNTER - TIMER INTERRUPT
===========================================
//
// Define GPIO pins used for the display
//
int segs[] = {21, 20, 16, 12, 7, 8, 25};
//
// Define 7-segment display bit patterns
//
int data[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F};
#define E1 23 // Digit E1
#define E2 24 // Digit E2
int cnt = 0;
int flag = 0;
● 317
C Programming on Raspberry Pi
//
// This function sends a byte of data to the display
//
void send(unsigned int No, unsigned int L)
{
unsigned int j, i, m, p, r;
m = L - 1;
for(i = 0; i < L; i++)
{
j = 1;
for(p = 0; p < m; p++)j = 2*j; // Power of 2
r = No & j;
if(r > 0)r = 1;
gpioWrite(segs[i], r);
m--;
}
}
//
// Configure the GPIO ports as outputs and turn them OFF
//
void Configure()
{
char k;
for(k = 0; k < 7; k++)
{
gpioSetMode(segs[k], PI_OUTPUT);
gpioWrite(segs[k], 0);
gpioSetMode(E1, PI_OUTPUT);
gpioSetMode(E2, PI_OUTPUT);
gpioWrite(E1, 0);
gpioWrite(E2, 0);
}
}
//
// This is the timer ISR. The program jumps to this function every 10ms
//
void MyISR(void)
{
unsigned int LSD, MSD;
if(flag == 0)
{
● 318
Chapter 13 ● Other Useful Functions - pigpio
flag = 1;
gpioWrite(E1, 0);
if(cnt > 9)
{
MSD = cnt / 10;
send(data[MSD], 7);
gpioWrite(E2, 1);
}
}
else
{
gpioWrite(E2, 0);
LSD = cnt % 10;
send(data[LSD], 7);
gpioWrite(E1, 1);
flag=0;
}
}
//
// Start of MAIN program. Increment count every second
//
int main(void)
{
gpioInitialise();
Configure(); // Configure
while(1) // Do Forever
{
cnt++; // Increment count
if(cnt == 100)cnt = 0; // If 100...
time_sleep(1); // 1 sec delay
}
}
Figure 13.5 Program Sevensegtim.c
Description:
In this project, three LEDs named LEDA, LEDB, and LEDC are connected to the Raspberry
● 319
C Programming on Raspberry Pi
Pi as in project 5 (Section 12.9). The LEDs flash concurrently at the following rates:
The block and circuit diagrams are as in Figure 12.14 and Figure 12.15 respectively.
Program listing:
The pigpio library supports the following functions for multi-thread applications (for full
details, see link: http://abyz.me.uk/rpi/pigpio/cif.html#gpioStartThread ).
gpioStartThread: This function starts a new thread. The first argument is the thread
function name. The second is a pointer to user data. The function returns a pointer to
thread if successful, otherwise NULL is returned.
gpioStopThread: This function cancels a thread. The argument points to the thread to be
cancelled.
The program listing (Program: MultiLED2.c) is shown in Figure 13.6. At the beginning of
the program, the connections of the three LEDs are defined. There are three threads in this
program named: ThreadLEDA, ThreadLEDB, and ThreadLEDC. ThreadLEDA flashes
LEDA every second. ThreadLEDB flashed LEDB every 500ms, and ThreadLEDC flashes
LEDC every 250ms.
The main program configures LEDA, LEDB, and LEDC as outputs and creates the three
threads so they start running concurrently. The threads run for 30 seconds. After this, the
threads are stopped and the program terminates.
/*------------------------------------------------------------------
3 LEDs FLASHING AT DIFFERENT RATES
==================================
In this program 3 LEDs are connected to Raspberry Pi. The LEDs flash
at different rates since they are controlled by different threads
● 320
Chapter 13 ● Other Useful Functions - pigpio
//
// This thread flashes LEDB every 500ms
//
void *ThreadLEDB(void *arg)
{
while(1)
{
gpioWrite(LEDB, 1);
time_sleep(0.5);
gpioWrite(LEDB, 0);
time_sleep(0.5);
}
}
//
// This thread flashes LEDC every 250ms
//
void *ThreadLEDC(void *arg)
{
while(1)
{
gpioWrite(LEDC, 1);
time_sleep(0.25);
gpioWrite(LEDC, 0);
time_sleep(0.25);
}
}
//
// Start of MAIN program
● 321
C Programming on Raspberry Pi
//
int main(void)
{
pthread_t *p1, *p2, *p3;;
gpioInitialise();
gpioStopThread(p1); // Stop p1
time_sleep(1);
gpioStopThread(p2); // Stop p2
time_sleep(1);
gpioStopThread(p3); // Stop p3
}
Figure 13.6 Program MultiLED2.c
13.8 ● Project 5 – Hardware PWM- generate 1kHz PWM wave with hardware
Description:
Program listing:
pigpio provides the following function for generating PWM signals in hardware (for further
details, see: http://abyz.me.uk/rpi/pigpio/cif.html#gpioHardwarePWM ).
gpioHardwarePWM: This function takes three arguments and generates PWM signal. The
first argument is the GPIO pin number. The second is the PWM frequency (in Hz, 0 is OFF),
last argument is the PWM duty cycle (0 for 0%, to 1000000 for 100%).
The following GPIO pins are available for the hardware PWM on Raspberry Pi 4:
● 322
Chapter 13 ● Other Useful Functions - pigpio
is used, the frequency is set to 1000Hz, and the duty cycle to 50%.
/*------------------------------------------------------------------
HARDWARE PWM
============
This program generates 1kHz PWM waveform using the Hardware PWM
//
// Start of MAIN program. Set the frequency to 1kHz, duty 50%
//
int main(void)
{
int duty;
gpioInitialise();
The output from the program is shown in Figure 13.8 on an oscilloscope. In this figure, the
horizontal axis is 500μs/division. The vertical axis is 2V/division.
● 323
C Programming on Raspberry Pi
pigpio supports the following file handling operations (for details see:
http://abyz.me.uk/rpi/pigpio/cif.html#fileOpen ):
• File opening.
• File closing.
• Read bytes from a file.
• Write bytes to a file.
• Seek a position within a file.
• List file that matches a pattern.
13.10 ● Waves
pigpio supports many functions for creating and manipulating waveforms (for details see:
http://abyz.me.uk/rpi/pigpio/cif.html#gpioWaveClear ).
13.11 ● picscope
pigpio supports a logic analyser that can be used to show the state of selected GPIO pins in
real-time (for details see: http://abyz.me.uk/rpi/pigpio/piscope.html). The steps to install
picscope are:
pi@raspberrypi:~ $ sudopigpiod
pi@raspberrypi:~ $ wget abyz.me.uk/rpi/pigpio/piscope.tar
pi@raspberrypi:~ $ tar xvf piscope.tar
pi@raspberrypi:~ $ cd PISCOPE
pi@raspberrypi:~/PICSCOPE make hf
pi@raspberrypi:~/PICSCOPE make install
Make sure you are in desktop mode of your Raspberry Pi (if you are using SSH, start
a desktop session using a VNCserver/VNCViewer session. Open a terminal session in
desktop mode, and start picscope to run in the background:
pi@raspberrypi:~$ picscope&
You should see a display as in Figure 13.9 which shows the state of each pin in real-time.
You can use the arrow keys to change the time scale of the display. Samples can be saved
if required. In Figure 13.9, pin GPIO 2 (or SDA) was toggled a few times and this is clearly
shown on the display.
● 324
Chapter 13 ● Other Useful Functions - pigpio
13.12 ● pigpiod
pigpio supports a utility called pigpiod which launches the pigpio library as a daemon.
After launching the library, it runs in the background and accepts commands from pipe and
socket interfaces (for details see: http://abyz.me.uk/rpi/pigpio/pigpiod.html).
13.13 ● Summary
In this chapter we learned how to use various practical functions of the pigpio library with
Raspberry Pi.
In the next chapter, we will be developing projects using Wi-Fi to communicate with a
smartphone.
● 325
C Programming on Raspberry Pi
14.1 ● Overview
In the last chapter we learned how to use various practical functions of the pigpio library.
In this chapter we will learn how to communicate over a Wi-Fi link using the UDP protocol.
Communication over a Wi-Fi link is in the form of client and server. Sockets are used to
send and receive data packets. Server-side usually waits for a connection from the clients
and once it is made, two-way communication can start. Two protocols are mainly used for
sending and receiving data packets over a Wi-Fi link: UDP and TCP. TCP is a connection-based
protocol that guarantees the delivery of packets. Packets are given sequence numbers and
the receipt of all the packets is acknowledged to avoid them arriving in the wrong order. As
a result of this confirmation, TCP is usually slow but is reliable as it guarantees the delivery
of packets. UDP on the other hand is not connection-based. Packets do not have sequence
numbers and as a result, there is no guarantee they will arrive at their destination. UDP has
less overhead than TCP and as a result, is faster. Table 14.1 lists some of the differences
between the TCP and UDP protocols.
TCP UDP
Packets have sequence numbers and
There is no delivery acknowledgment
delivery of every packet is acknowledged
Slow Fast
No packet loss Packets may be lost
Large overhead Small overhead
Requires more resources Requires fewer resources
Connection based Not connection based
More difficult to program Easier to program
Examples: HTTP, HTTPS, FTP Examples: DNS, DHCP, Computer games
Table 14.1 TCP and UDP packet communications
Server
● 326
Chapter 14 ● Communication Over Wi-Fi
Client
Description:
In this project, UDP communication is used to receive and send data to/from an Android
smartphone. In this project, Raspberry Pi is the server and the Android smartphone is the
client
Aim:
This project aims to show how UDP communication can be established between a Raspberry
Pi and an Android smartphone
● 327
C Programming on Raspberry Pi
Block diagram:
Figure 14.2 shows the block diagram of the project. The Raspberry Pi and Android
smartphone communicate over a Wi-Fi router link.
Program listing:
The program listing is shown in Figure 14.3 (Program: MyServer.c). At the beginning of
the program, the required header files are included in the program. The message Hello
from Raspberry Pi is stored in character array msg. A UDP type socket is then created
by calling the socket function and saving the handle in the sock variable. Details of the
server computer (Raspberry Pi) are then given where the address is set to INADDR_ANY
so any other computer on the same network with the port number set to 5000 will establish
communication with the Raspberry Pi. The server computer details are then bound to the
specified port by calling function bind.
The remainder of the program runs in a loop. Inside this loop, function recvfrom is called
to wait to receive a data packet from the client computer (Android smartphone). Notice
this is a blocking call and the function will wait until data is received from the client. The
program terminates if character x is received from the client computer. A NULL character is
added to the received data and is displayed on the PC screen of the Raspberry Pi as a string
using the printf function. An integer variable called count is converted into character and
added to the end of character array msg. This is sent to the client computer. The first time
in the loop, the client computer will display Hello from Raspberry Pi 1. The second time,
the client computer will display Hello from Raspberry Pi 2 and so on. The socket is closed
just before the program terminates. The program can be compiled and run as follows:
● 328
Chapter 14 ● Communication Over Wi-Fi
/*------------------------------------------------------------------
RASPBERRY PI - ANDROID SMARTPHONE COMMUNICATION
===============================================
This is UDP program. The program receives and then sends messages to
a smartphone over the UDP socket. Program terminates when character x
is sent from the smartphone
//
// Start of MAIN program
//
int main(void)
{
int sock, len, num, count = 1;
char buffer[BUFFSIZE];
struct sockaddr_in serveraddr, clientaddr;
char msg[26] = "Hello from Raspberry Pi ";
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = INADDR_ANY;
serveraddr.sin_port = htons(Port);
bind(sock,(struct sockaddr *)&serveraddr, sizeof(serveraddr));
while(1)
{
num = recvfrom(sock, buffer, BUFFSIZE,MSG_WAITALL,
( struct sockaddr *)&clientaddr, &len);
if(buffer[0] == ‘x’)break;
buffer[num] = ‘\0’;
● 329
C Programming on Raspberry Pi
printf("%s\n",buffer);
sprintf(&msg[24], "%d",count);
count++;
sendto(sock, &msg, strlen(msg), MSG_CONFIRM,
(struct sockaddr *)&clientaddr, len);
}
close(sock);
}
Figure 14.3 MyServer.c
There are many UDP apps available on the Play Store free of charge. In this project, the
UDP Terminal by mightyIT is used (see Figure 14.4). Enter the port number and IP
address of your Android smartphone and click Start Terminal as shown in Figure 14.5. An
example run of the program is shown in Figure 14.6, where both the smartphone and PC
screen are shown.
● 330
Chapter 14 ● Communication Over Wi-Fi
Note: you can find the IP address of your Raspberry Pi by using the ifconfig command.
Description:
Aim:
This project aims to show how the temperature reading can be sent to an Android
smartphone over a Wi-Fi link using the UDP protocol.
Block diagram:
Figure 14.7 shows the block diagram of the project. In this project, a TMP102 module is
used (see Figure 7.16).
● 331
C Programming on Raspberry Pi
Circuit diagram:
The circuit diagram of the project is as shown in Figure 7.18. On-chip pull-up resistors are
available on the TMP102 I2C bus lines. I2C bus lines SDA and SCL pins of the TMP102 are
connected to GPIO 2 and 3 respectively.
Program listing:
Figure 14.8 shows the program listing (Program: TMP102UDP.c). In this program,
the wiringPi library and GPIO pin numbering is used. The program is in two parts: the
function that reads the temperature from the TMP102 and the main program that sends
the temperature reading to the Android smartphone. Function ReadTemperature reads
the temperature from the TMP102 sensor module and returns it to the main program as
a floating-point number (see Section 7.5 for details). The main program runs in a loop
and waits to receive commands from the Android smartphone. If the received command
is character x, the program terminates and the message End of program is sent to the
smartphone. If the command is T, function ReadTemperature is then called. Temperature
is converted into integer and stored in variable temperature. This is then converted into a
string and stored in array msg. Character C (Centigrade) is then added to the end of msg
and is sent and displayed on the Android smartphone. If the user command is anything
other than x or T, the error message Error – expected T or x is sent and displayed on the
Android screen. You can compile and run the program as follows:
● 332
Chapter 14 ● Communication Over Wi-Fi
/*------------------------------------------------------------------
SENDING TEMPERATURE TO ANDROID SMART PHONE
==========================================
//
// UDP includes and defines
//
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#define Port 5000
#define BUFFSIZE 1024
int handle;
//
// THis function reads the temperature from TMP102 and returns to
// the calling main program as a floating point number
//
float ReadTemperature()
{
int Temp, buf[2];
float temperature, LSB = 0.0625;
● 333
C Programming on Raspberry Pi
wiringPiI2CWrite(handle, PointerReg);
buf[0] = wiringPiI2CRead(handle);
buf[1] = wiringPiI2CRead(handle);
Temp = (buf[0] << 4) | (buf[1] >> 4);
//
// Start of MAIN program. Read the temperature and send to Android
// smartphone when request character T is received
//
int main(void)
{
int sock, len, num, temperature;
char buffer[BUFFSIZE];
struct sockaddr_in serveraddr, clientaddr;
char msg[17] = "Temperature = ";
char error[] = "Error - expected T or x";
char endofprog[] = "End of program";
wiringPiSetupGpio();
handle = wiringPiI2CSetup(DeviceAddress);
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = INADDR_ANY;
serveraddr.sin_port = htons(Port);
bind(sock,(struct sockaddr *)&serveraddr, sizeof(serveraddr));
while(1)
{
num = recvfrom(sock, buffer, BUFFSIZE,MSG_WAITALL,
( struct sockaddr *)&clientaddr, &len);
if(buffer[0] == ‘x’)break;
● 334
Chapter 14 ● Communication Over Wi-Fi
if(buffer[0] == ‘T’)
{
temperature = (int)ReadTemperature();
sprintf(&msg[14], "%d", temperature);
msg[16] = ‘C’;
sendto(sock, &msg, strlen(msg), MSG_CONFIRM,
(struct sockaddr *)&clientaddr, len);
}
else
sendto(sock, &error, strlen(error), MSG_CONFIRM,
(struct sockaddr *)&clientaddr, len);
}
An example display on the Android smartphone is shown in Figure 14.9. In this example,
the commands T, T, r, T, x.
● 335
C Programming on Raspberry Pi
Description:
In this project, UDP communication is used to receive and send data to an Android
smartphone. Raspberry Pi is the client and the Android smartphone is the server.
Aim:
This project aims to show how UDP communication can be established between a Raspberry
Pi and Android smartphone.
Block diagram:
The block diagram is the same as in Figure 14.7, but Raspberry Pi is the client and the
Android smartphone is the server.
Program listing:
/*------------------------------------------------------------------
RASPBERRY PI - ANDROID SMARTPHONE COMMUNICATION
===============================================
This is UDP program. The program receives and then sends messages to
a smartphone over the UDP socket. Program terminates when character x
is sent from the smartphone
//
// Start of MAIN program
● 336
Chapter 14 ● Communication Over Wi-Fi
//
int main(void)
{
int sock, len, num;
char buffer[BUFFSIZE];
struct sockaddr_in serveraddr;
char msg[] = "Hello from Raspberry Pi";
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = INADDR_ANY;
serveraddr.sin_port = htons(Port);
while(1)
{
sendto(sock, &msg, strlen(msg), MSG_CONFIRM,
(struct sockaddr *)&serveraddr, sizeof(serveraddr));
Description:
In this project, a TMP102 temperature sensor chip (see Section 14.5) is connected to
a Raspberry Pi. The ambient temperature reading is sent continuously to an Android
smartphone every 5 seconds with the date and time.
Aim:
This project aims to show how the temperature reading can be sent with time stamping to
an Android smartphone over a Wi-Fi link using the UDP protocol.
Block diagram:
● 337
C Programming on Raspberry Pi
Circuit diagram:
The circuit diagram of the project is as shown in Figure 7.18. On-chip pull-up resistors are
available on the TMP102 I2C bus lines. I2C bus lines SDA and SCL pins of the TMP102 are
connected to GPIO 2 and 3 respectively.
Program listing:
Figure 14.11 shows the program listing (Program: TMP102UDP2.c). In this program,
the wiringPi library and GPIO pin numbering is used. The program is in two parts: the
function that reads the temperature from the TMP102 and the main program that sends
the temperature reading to the Android smartphone. Function ReadTemperature reads
the temperature from the TMP102 sensor module and returns it to the main program as a
floating-point number (see Section 14.5 for details). The main program runs in a loop. It
reads the temperature and the current date and time. Function strcat is used to combine
the date and time with the temperature reading. Letter C (Centigrade) is then appended to
the resulting string. Function sendto sends this data every 5 seconds to the client which is
the Android smartphone.
/*------------------------------------------------------------------
SENDING TEMPERATURE TO ANDROID SMART PHONE
==========================================
//
// UDP includes and defines
//
#include <netinet/in.h>
● 338
Chapter 14 ● Communication Over Wi-Fi
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#define Port 5000
int handle;
//
// THis function reads the temperature from TMP102 and returns to
// the calling main program as a floating point number
//
float ReadTemperature()
{
int Temp, buf[2];
float temperature, LSB = 0.0625;
wiringPiI2CWrite(handle, PointerReg);
buf[0] = wiringPiI2CRead(handle);
buf[1] = wiringPiI2CRead(handle);
Temp = (buf[0] << 4) | (buf[1] >> 4);
//
// Start of MAIN program. Read the temperature and send to Android
// smartphone when request character T is received
//
int main(void)
{
int sock, len, num, temperature;
struct sockaddr_in serveraddr, clientaddr;;
struct tm tm_now;
char timbuff[100];
char tmp[50];
● 339
C Programming on Raspberry Pi
wiringPiSetupGpio();
handle = wiringPiI2CSetup(DeviceAddress);
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = INADDR_ANY;
serveraddr.sin_port = htons(Port);
bind(sock,(struct sockaddr *)&serveraddr, sizeof(serveraddr));
clientaddr.sin_family=AF_INET;
clientaddr.sin_addr.s_addr=inet_addr("192.168.1.219");
clientaddr.sin_port=htons(Port);
while(1)
{
time_t now = time(NULL);
localtime_r(&now, &tm_now);
strftime(timbuff,sizeof(timbuff),"%d-%m-%Y %H:%M:%S",&tm_now);
temperature = (int)ReadTemperature();
sprintf(&tmp[0], "%d", temperature);
strcat(timbuff, " ");
strcat(timbuff, tmp);
strcat(timbuff, "C");
sendto(sock, timbuff, strlen(timbuff), MSG_CONFIRM,
(struct sockaddr *)&clientaddr, len);
delay(5000);
}
}
Figure 14.11 Program TMP102UDP2.c
In this project, the Android app UDP RECEIVE and SEND by Wezzi Studios is used (see
Figure 14.12) to receive and display the UDP packets. This app is available free of charge
on the Play Store.
● 340
Chapter 14 ● Communication Over Wi-Fi
Figure 14.13 shows the data packets received by the Android app.
Description:
In this project, we will be developing a web server application to control two LEDs connected
to the Raspberry Pi.
Aim:
This project aims to show how a web server application can be developed.
Block diagram:
● 341
C Programming on Raspberry Pi
Circuit diagram:
The circuit diagram of the project is shown in Figure 14.15. LED0 and LED1 are connected to
GPIO 21 and 20 of the Raspberry Pi through 470 Ohm current limiting resistors respectively.
A web server is a program that uses HTTP (Hypertext Transfer Protocol) to serve web pages
to users in response to their requests. These requests are forwarded by HTTP clients. By
using the HTTP server/client pair, we can control any device connected to a web server
processor over the web.
Figure 14.16 shows the structure of a web server/client setup. In this figure, the Raspberry
Pi is the webserver and the PC (or a laptop, tablet, or mobile phone) is the web client. The
device to be controlled is connected to the webserver processor. In this example, we have
● 342
Chapter 14 ● Communication Over Wi-Fi
two LEDs connected to a Raspberry Pi. The operation of the system is as follows:
• The web server is in listen mode, listening for requests from the web client.
• The web client makes a request to the web server by sending a HTTP request.
• In response, the webserver sends a HTTP code to the web client which is activated
by the web browser by the user on the web client and is shown as a form on the web
client screen.
• The user sends a command (e.g. ticks a button on the web client form to turn ON an
LED) and this sends a code to the webserver so that the webserver can carry out the
required operation.
In this program, a laptop with the IP address 192.168.1.199 is used as the web client. The
Raspberry Pi with the IP address 192.168.1.202 is used as the webserver.
Program listing:
Figure 14.21 shows the complete program (Program: WEBSERVER.c). At the beginning of
the program, the library header files required are included in the program. Notice the port
number is set to 80 which is the default HTTP port number. LED0 and LED1 are assigned to
21 and 20 which are the GPIO port numbers respectively.
The program then defines the HTML code that is to be sent to the web client when a request
● 343
C Programming on Raspberry Pi
comes from it. This code is stored in character array html. When executed by the web
browser (e.g. Internet Explorer) on the web client, the display in Figure 14.17 is shown on
the client screen. Notice that newline characters (\n) are used at the end of each line. Also
the string continuation character (\) is used at the end of each line. Therefore, the entire
HTML code is stored in character array html. A heading is displayed at the centre of the
screen and buttons are displayed on the left-hand side. Two pairs of buttons are displayed:
one pair to turn LED0 ON/OFF and another to turn LED1 ON/OFF. The ON buttons are green
and the OFF are red.
Function configure configures the GPIO ports as outputs and turns both LEDs OFF.
The web server program is based on TCP protocol where the communication is connection
based and is reliable. Figure 14.18 shows how TCP communication is done between a
server and client. In this program, Raspberry Pi is the server.
● 344
Chapter 14 ● Communication Over Wi-Fi
When the link is accepted by the web browser, the Html page is sent to the browser which
is displayed as shown in Figure 14.17. When a button is clicked on the client, a command
is sent to the Raspberry Pi in addition to some other data. Here, we are only interested in
the actual command sent. The following commands are sent to the Raspberry Pi for each
button pressed:
The received data is stored in a character array called buffer which is appended with a
NULL character to make it a string. The program searches the received command to see if
any of the above commands are present in the received data. The following code is used
to search the received data and activate an LED:
if(strstr(buffer,"LED0=ON"))digitalWrite(LED0, HIGH);
if(strstr(buffer,"LED0=OFF"))digitalWrite(LED0, LOW);
if(strstr(buffer,"LED1=ON"))digitalWrite(LED1, HIGH);
if(strstr(buffer,"LED1=OFF"))digitalWrite(LED1, LOW);
If for example, the user clicks on LED0 ON, string LED0=ON will be detected in the data
and LED0 will be turned ON.
In this project, the IP address of the Raspberry Pi was 192.168.1.202. The procedure to
test the system is as follows:
• Google Chrome
• Internet Explorer
• Microsoft Edge
Figures 14.19 and 14.20 show the commands sent to the webserver when the LED0 ON
● 345
C Programming on Raspberry Pi
button is clicked, and also when the LED0 OFF button is clicked.
/*------------------------------------------------------------------
RASPBERRY PI - WEB SERVER APPLICATION
=====================================
#define Port 80
#define BUFFSIZE 1024
//
// LED connections
//
#define LED0 21
#define LED1 20
//
// The HTML code. This code will display two buttons on user’s
// device which can be clicked to control the LEDs
//
char html[] ="<!DOCTYPE html>\n \
<html>\n \
<body>\n \
<center><h1>Raspberry Pi LED ON/OFF</h1></center>\n \
● 346
Chapter 14 ● Communication Over Wi-Fi
//
// COnfigure LED0 and LED1 as outputs and turn them OFF
//
void Configure()
{
pinMode(LED0, OUTPUT);
pinMode(LED1, OUTPUT);
digitalWrite(LED0, LOW);
digitalWrite(LED1, LOW);
}
//
// Start of MAIN program. Inside the main program we send the
// HTML file so that it is displayed on user’s device. The user
// clicks the buttons to control the LEDs. We control the LEDs
// depending upon the key click. Variabl request holds the request
// and we search this string to see which LED should be turned
// ON/OFF. The contents of request is of the form (for example, to
// turn OFF LED0): "/?LED0=OFF", or similarly, to turn LED1 ON:
// "/?LED1=ON"
//
int main(void)
{
int sock, len, num, cli,flag = 1;
char buffer[BUFFSIZE];
struct sockaddr_in serveraddr, clientaddr;
wiringPiSetupGpio();
Configure();
bzero(&serveraddr, sizeof(serveraddr));
● 347
C Programming on Raspberry Pi
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = INADDR_ANY;
serveraddr.sin_port = htons(Port);
bind(sock,(struct sockaddr *)&serveraddr, sizeof(serveraddr));
listen(sock, 5);
cli = accept(sock, NULL,NULL);
//
// Get reply from the HTTP and process it, send the html page
//
while(1)
{
num = recv(cli, buffer, sizeof(buffer),0);
buffer[num] = ‘\0’;
if(strstr(buffer,"LED0=ON"))digitalWrite(LED0, HIGH);
if(strstr(buffer,"LED0=OFF"))digitalWrite(LED0, LOW);
if(strstr(buffer,"LED1=ON"))digitalWrite(LED1, HIGH);
if(strstr(buffer,"LED1=OFF"))digitalWrite(LED1, LOW);
cli = accept(sock,NULL,NULL);
send(cli,html,sizeof(html),0);
}
}
Figure 14.21 Program WEBSERVER.c
Notice Port 80 may be used by other programs on your Raspberry Pi. As a result, your
project may not work. You can find out the ports and the programs that use these ports by
entering the command sudo netstat –tlnpu as shown in Figure 14.22 (only part of the
display is shown here).
● 348
Chapter 14 ● Communication Over Wi-Fi
You can stop the programs using Port 80 as follows (with reference to Figure 14.22):
Run the sudonetstat -tlnpu command again you should check to make sure that no other
programs are using port 80.
14.9 ● Summary
In this chapter, we learned how to communicate with other devices over Wi-Fi. Several
example projects are given in the chapter to show how we can communicate with an
Android smartphone, and also how a web server application can be developed.
● 349
C Programming on Raspberry Pi
15.1 ● Overview
Bluetooth has become one of the most commonly used technologies to establish
communication between various devices. Bluetooth is used to transfer data, pictures,
and messages between mobile devices. All current mobile phones, laptop computers, and
tablets are equipped with Bluetooth communication modules. The advantage of Bluetooth
is that it can be used anywhere, at any time since it does not operate through a router
like a Wi-Fi device. Any two Bluetooth compatible devices can establish communication
anywhere on earth, even on a mountain top. Additionally, Bluetooth is an easy means of
transferring data, such as pictures between different devices. The range of present-day
Bluetooth devices is comparable to and even longer than most Wi-Fi routers.
In this chapter, we will learn how Bluetooth can be used with a Raspberry Pi to establish
communication with other Bluetooth compatible devices, such as smartphones (an Android
phone is used in this chapter).
Description:
In this project, we develop a program to receive and send messages to an Android mobile
phone over the Bluetooth link.
Aim:
This project aims to show how Bluetooth can be used to establish communication with a
Raspberry Pi.
Block diagram:
● 350
Chapter 15 ● Bluetooth Communication
Program listing:
In this project, we are assuming that Bluetooth is enabled on your Raspberry Pi and is
already paired with your Android mobile phone. Before developing your program, you will
need to install the Bluetooth library on your Raspberry Pi. This can be done by entering the
following command on your Raspberry Pi while in command mode:
To be able to access the Raspberry Pi from a mobile phone app, make the following changes
to your Raspberry Pi from the command line:
• Add –C at the end of the ExecStart= line. Also, add another line after ExecStart. The
final two lines should look like this:
ExecStart=/usr/lib/bluetooth/bluetoothd -C
ExecStartPost=/usr/bin/sdptool add SP
In this project, we will send and receive messages from an Android smartphone. We,
therefore, need an application on our smartphone where we can send/receive data through
Bluetooth to our Raspberry Pi. There are many free of charge applications on the Play
Store. The one used by the author is called Serial Bluetooth Terminal by Kai Morich (see
Figure 15.2).
● 351
C Programming on Raspberry Pi
Figure 15.3 shows the program listing (Program: BlueEx.c). The program is based on
sockets and is organised as a server, listening for, and then making a connection. Functions
read and write are used to read and to send data to the smartphone respectively. The data
received by the Raspberry Pi is displayed on a PC screen. The fixed message Hello from
Raspberry Pi is sent to the smartphone every time a new message is received. Sending the
x character from the smartphone terminates the link.
/*------------------------------------------------------------------
Bluetooth Communication
=======================
//
// Start of MAIN program
//
int main(void)
{
struct sockaddr_rc rpi_addr, remoteaddr;
char buffer[1024];
char msg[] = "Hello from Raspberry Pi";
int sock,cli,num,len;
sock = socket(AF_BLUETOOTH,SOCK_STREAM,BTPROTO_RFCOMM);
rpi_addr.rc_family = AF_BLUETOOTH;
rpi_addr.rc_bdaddr = *BDADDR_ANY;
rpi_addr.rc_channel = (uint8_t) 1;
//
// Receive message from smartphone, display, reply
//
● 352
Chapter 15 ● Bluetooth Communication
while(1)
{
memset(buffer, ‘\0’, 1023);
num = read(cli, buffer, sizeof(buffer));
if(buffer[0] == ‘x’)break;
printf("%s\n",buffer);
• Enable Bluetooth on your smartphone, scan for nearby devices, and make sure it is
paired with the Raspberry Pi.
• Compile and run the Raspberry Pi program:
• Click the third menu button on the top right to connect to the Raspberry Pi over
Bluetooth. You should see two parts of the icon joined together.
• The messages Connecting to raspberrypi… and Connected will be displayed on
the apps.
• Enter a message and click the right arrow. For example, enter Hello from Android.
● 353
C Programming on Raspberry Pi
You should see this message displayed on the PC screen. The smartphone will display
message Hello from Raspberry Pi (Figure 15.5).
Description:
In this project, we will control two LEDs connected to a Raspberry Pi using Bluetooth.
Block diagram:
● 354
Chapter 15 ● Bluetooth Communication
Circuit diagram:
The circuit diagram of the project is as shown in Figure 14.15. LED0 and LED1 are
connected to GPIOs 21 and 20 of the Raspberry Pi through 470 Ohm current limiting
resistors respectively.
Program listing:
Figure 15.7 shows the program listing (Program: BlueLED.c). The LEDs are controlled by
entering the following commands on the smartphone:
Function Configure configures the LED ports as outputs and turns OFF both LEDs. Packets
received from the smartphone are stored in the character array, buffer. Function strstr is
used to determine what the user commands are. The LEDs are then turned ON and OFF as
required. The program can be compiled and run as follows:
/*------------------------------------------------------------------
Bluetooth Communication
=======================
In this program two LEDs are connected to Raspberry Pi. The LEDs
are controlled from a smartphone over the Bluetooth link
Author: Dogan Ibrahim
File : BlueLED.c
Date : January 2021
--------------------------------------------------------------------*/
#include <wiringPi.h>
#include <unistd.h>
#include "bluetooth/bluetooth.h"
#include <bluetooth/rfcomm.h>
#include <sys/socket.h>
#define LED0 21
#define LED1 20
//
// Configure the LEDs as outputs and turn them OFF
//
● 355
C Programming on Raspberry Pi
void Configure()
{
pinMode(LED0, OUTPUT);
pinMode(LED1, OUTPUT);
digitalWrite(LED0, LOW);
digitalWrite(LED1, LOW);
}
//
// Start of MAIN program
//
int main(void)
{
struct sockaddr_rc rpi_addr, remoteaddr;
char buffer[1024];
char msg[] = "Hello from Raspberry Pi";
int sock,cli,num,len;
wiringPiSetupGpio();
Configure();
sock = socket(AF_BLUETOOTH,SOCK_STREAM,BTPROTO_RFCOMM);
rpi_addr.rc_family = AF_BLUETOOTH;
rpi_addr.rc_bdaddr = *BDADDR_ANY;
rpi_addr.rc_channel = (uint8_t) 1;
//
// Receive message from smartphone, display, reply
//
while(1)
{
memset(buffer, ‘\0’, 1023);
num = read(cli, buffer, sizeof(buffer));
if(buffer[0] == ‘x’)break;
if(strstr(buffer, "0=ON"))digitalWrite(LED0, HIGH);
if(strstr(buffer, "0=OFF"))digitalWrite(LED0, LOW);
if(strstr(buffer, "1=ON"))digitalWrite(LED1, HIGH);
if(strstr(buffer, "1=OFF"))digitalWrite(LED1, LOW);
}
close(cli);
}
Figure 15.7 Program BlueLED.c
● 356
Chapter 15 ● Bluetooth Communication
Figure 15.8 shows the command entered on the smartphone to turn LED1 ON.
● 357
C Programming on Raspberry Pi
16.1 ● Overview
Many applications may require the automatic commencing of a program as soon as the
Raspberry Pi starts up. This can be achieved using several techniques. Perhaps the easiest
method is to use file /etc/rc.local. The program called MyProg.c is compiled into MyProg
and is required to commence automatically just after a system startup:
• Go to the end of the file and enter the following statements before exit 0. The &
character at the end of the command runs the program as a background process. This
is required if the program is in a loop, otherwise, the startup will never complete:
sudo/home/pi/./MyProg&
Do not forget to edit the file /etc/rc.local and remove the statement to start the program
if it is not required anymore.
There are many applications where we may want to run programs automatically at regular
intervals. These include backup operations, time synchronisation, and running a process in
the future.
Running tasks at regular intervals is managed by the crontab command. This consists of a
set of tables (crontab tables) and crondeamon. The deamon is started by the init process
at system startup. It wakes up every minute and checks the crontab tables to determine if
there are any tasks scheduled to run.
To create a crontab table, use the crontab command with the –e option. This opens the
vi editor (unless another editor is specified in the environment variable). Each crontab
contains 6 fields. The values in the fields can have fixed, a range, or a list of values
separated by commas:
• Minute (0 - 59).
• Hour (0 - 23).
• Day of the month (1 – 31).
• Month of the year (1 – 12. It can also be specified as Jan, Feb, Mar, and so on).
● 358
Chapter 16 ● Automatically Running Programs on Startup
• Day of the week (0 – 6, where 0=Sunday, it can also be Mon, Tue, Wed, etc).
• String (command) to be executed.
A * character in the digit position means every. Ranges of numbers are specified by
separating them with a hyphen and the specified range is inclusive. For example, 9-12 for
an Hour entry specifies execution at hours 9, 10, 11, and 12.
Skips of numbers in ranges can be specified by adding character / after the range. For
example, 0-12/2 in the Hours field specifies execution every other hour i.e. at hours 0, 2,
4, 6, 8, 10.
By using a combination of * and /, we can specify steps. For example, */2 in the Hours field
specifies every two hours.
Instead of the first five fields, we can specify special strings as follows:
String Meaning
@reboot run once at startup
@yearly run once every year ("0 0 1 1*")
@monthly run once every month ("0 0 1 * *")
@weekly run once a week ("0 0 * * 0")
@daily run once a day ("0 0 * * *")
@hourly run once an hour ("0 * * * *")
Multiple commands can be entered on a line and such commands must be separated with
&& characters.
2. @daily <command1>&&<command2>
Run command 1 and command 2 daily.
3. 30 0 * * */home/pi/mycron.sh
Run at 12:30 daily.
4. 0 4 12 * * /home/pi/mycrob.sh
Run at 4 a.m. on the 12th of every month.
5. ***** /home/pi/mycron.sh
Run every minute.
● 359
C Programming on Raspberry Pi
6. 0 4 15-21 * 1 /home/pi/mycron.sh
Run every month at 4 a.m. on Mondays, and the days between 15-21. Notice the day of the
month and week are used with no restrictions (no *) and therefore this is an "or" condition
- both will be executed.
7. 0 11,16* * * /home/pi/mycron.sh
Run every day at 11:00 and 16:00 hours
8. 0 11-14 * * * /home/pi/mycron.sh
Run every day during the hours 11 a.m. -2 p.m. (i.e. 11 a.m., 12 a.m., 1 p.m., 2 p.m.)
By default, crontab sends the job to the user who scheduled the job. If you don’t want any
mail to be sent, you should specify the following line in the crontab:
MAIL=""
Any outputs in a scheduled process are usually logged in files. For example, to run mycron.
sh daily and send the output to daily.txt, enter the following command:
Instead of editing the crontab file directly, you can also add the entries to a cron-file first
and then install them to cron using the crontab command and specify the filename. An
example is given below:
This will install mycron.sh to our crontab, which will also remove any old cron entries. The
created crontab is stored in directory /etc/spool/cron/<user>
In all the examples above, we specified the absolute path of the script file that should be
executed. We can specify this path in the PATH environment variable in the crontab and
enter the filename. An example is given below where the absolute path to the file is /
home/pi/mycron.sh.
PATH=/home/pi
@daily mycron.sh
● 360
Chapter 16 ● Automatically Running Programs on Startup
If the script or command we wish to run requires privilege, it should be prefixed with the
sudo command.
Example
It is required to run myscript.sh every minute. Assume this script file has the following
line of command:
date>> /home/pi/myfile
Schedule this event using the crontab command. Send the output from the command to
myfile.
Solution
First of all, create the myscript.sh file and type in the above command. The default editor
is nano. Save the file (Ctrl+X, followed by Y and Enter) and exit the editor. Next, give the
file execute permission by entering the following command:
The steps for using the crontab command to schedule this event are given below:
• Run the crontab command with the –e flag. You should see the crontab editor screen
as in Figure 16.1
pi@raspberrypi:~ $ crontab –e
● 361
C Programming on Raspberry Pi
* * * * * /home/pi/myscript.sh
Ctrl+X
Y
<Enter>
• The commands in the myscript.sh will now be executed every minute and the output
will be sent to myfile. We can verify that the commands are executed by looking at the
contents of myfile after a few minutes:
• You can stop the scheduling by deleting the line entered by command crontab –e
The crontab –l command displays a list of the scheduled tasks (if there are any):
pi@raspberrypi:~ $ crontab –l
All scheduled tasks can be deleted (if there are any) using the crontab –r command:
pi@raspberrypi:~ $ crontab –r
pi@raspberrypi:~ $ crontab –l
nocrontab for pi
pi@raspberrypi:~ $
The –i option can be added to the delete command to confirm the delete action.
Crontab generator
An online tool called Crontab Generator (available free of charge on the internet) can be
used to easily generate crontab entries. This tool is available on the following website:
https://crontab-generator.org/
Figure 16.2 shows part of the Crontab Generator. An example is given to show how to use
this tool.
● 362
Chapter 16 ● Automatically Running Programs on Startup
Example
It is required to run the script file myscript.sh every day at 11:00 a.m. and 4:00 p.m.
Solution
● 363
C Programming on Raspberry Pi
• Click Save output to file and enter myfile so the output will be stored in file myfile.
• Click the button Generate Crontab Line.
• You should see the generated line as shown in Figure 16.4, which is:
• The tool also displays sample dates and times that the script file will be scheduled to
run. It is clear from Figure 16.4 that the script file myscript.sh will run at 11:00 a.m.
and 4:00 p.m. every day.
● 364
Chapter 16 ● Automatically Running Programs on Startup
• You should copy the above line to the end of the crontab table by entering the command
crontab –e as discussed earlier.
● 365
C Programming on Raspberry Pi
17.1 ● Overview
The Internet of Things (IoT) has recently become one of the popular topics in embedded
applications. In IoT based applications, we usually want to send sensor data to the cloud
so it can be accessed from anywhere. Several cloud services can be used to store data
(for example SparkFun, Thingspeak, Cloudino, Bluemix). In this project, Thingspeak
is used. This is an open-source, free, cloud service where sensor data can be stored and
retrieved using simple HTTP requests over the internet. ThingSpeak enables the creation
of sensor logging applications, location tracking applications, and a social network of things
with status updates. ThingSpeak was originally launched by ioBridge in 2010 as a service
to support IoT applications. ThingSpeak has integrated support with MATLAB.
In this chapter, we will be developing an interesting network-based application. Here, the
system will get ambient temperature and humidity from the DHT11 sensor and then store
this data on the cloud every minute so it can be accessed from anywhere.
Description:
In this chapter, we will be using the DHT11 temperature and humidity sensor chip and send
the readings to the cloud every minute.
Block Diagram:
● 366
Chapter 17 ● Sending Data to the Cloud
Circuit diagram:
The circuit diagram of the project is the same as in Figure 5.42. The output of the DHT11
is connected to port GPIO 2 of Raspberry Pi.
Before using the ThingSpeakCloud service, we need to create an account on the website
and then log in. Create a new account by providing your email address and password
through the following link:
https://thingspeak.com/users/sign_up
You should get an email to verify and activate your account. Following this, click Continue
and you should get a successful sign-up notice as shown in Figure 17.2. You should agree
to the terms and conditions.
You should then create a New Channel by clicking on New Channel. Fill in the form as
shown in Figure 17.3. Give the name TempandHum to the application and create two
channels called Temperature and Humidity. You can give Tags to the channels (separate
tags with commas) for easy identification if you wish so they are not identified as field1
and field2. You can also include geographical data and video files if you wish.
● 367
C Programming on Raspberry Pi
Figure 17.3 Create a New Channel (only part of the form shown)
Click Save Channel at the bottom of the form. Your channel is now ready to be used with
your data. You will now see two charts with the labels as shown in Figure 17.4. One for the
temperature display and one for humidity.
You should see tabs at the top of the screen 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 which only
you can see.
• Public View: If your channel is public, use this tab to display selected fields and
channel visualisations.
• Channel Settings: This tab shows all channel options 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.
● 368
Chapter 17 ● Sending Data to the Cloud
You need an API key and a channel number before you start using the ThingSpeak Cloud
service. API keys are unique to users and should not be given to other people. To get an
API key, you should click the API Keys tab and save your Write API and Read API keys
and the Channel ID in a safe place. In this project, we will be using only the Write API key.
The Write API Key and Channel Number used in this project were (the API key has been
modified for security reasons):
ChannelNumber = 1278451
Program Listing:
We are now ready to write our program to send ambient temperature and humidity readings
to the ThingSpeak Cloud. The program listing is shown in Figure 17.5 (Program: Cloud.c).
The program uses the wiringPi library for the GPIO. GPIO numbering is used in the program.
The libdht11.a library function developed in Chapter 5 (see Figure 5.47 and Figure 5.48) is
used to read temperature and humidity from the DHT11. Communication with ThingSpeak
is by use of the HTTP protocol with TCP packets. Since we are using the HTTP protocol,
you will have to free port 80 on your Raspberry Pi. This is done in Section 14.8 using the
command to find the programs using port 80: sudonetstat –tlnpu, and then command
sudo killprogramID to stop the programs using port 80.
At the beginning of the program, the URL of the ThingSpeak service is defined. Port is
assigned to 80, and the output pin of the DHT11 is assigned to 2 (i.e. GPIO 2 of the
Raspberry Pi). The main program calls function Send. Complete processing is performed
inside this function. Character arrays msg to msg5 store the data to be sent to ThingSpeak.
The complete data string is in the following format:
GET /update?key=QAAHT5XIK3ZB8736&field1=Data1&field2=Data2
HTTP/1.0\r\nHost: api.thingspeak.com\r\n\r\n
Where Data1 and Data2 are the data fields field1 and field2 respectively (i.e. the
temperature and humidity data respectively). In this program, temperature and humidity
data is loaded in msg2 and msg4 respectively after it is read from the DHT11.
● 369
C Programming on Raspberry Pi
BEGIN
Initialise variables
Create a TCP socket
Get the IP address of the Thingspeak Cloud Service
Create and load the TCP structure
Connect to Thingspeak
Call Read_DHT11 to read the temperature and humidity
Load the temperature and humidity into msg2 and msg4 respectively
Send data to Thingspeak
Return
END
/*------------------------------------------------------------------
SENDING TEMPERATURE AND HUMIDITY TO THE CLOUD
=============================================
This is a Cloud based program using the Thingspeak Cloud Service. The
ambient temperature and humidity are read using a DHT11 sensor. The
data is sent to the Thingspeak cloud and plotted in real time
int WaitEdge(int);
void Read_DHT11(int*, int*);
//
// This function connects to Thingspeak Cloud Service and then reads
// and sends the aambient temperature and humidity to the Cloud where
// it is plotted in real time
//
● 370
Chapter 17 ● Sending Data to the Cloud
void Send()
{
int sock,Temp,Hum;
struct sockaddr_in serveraddr;
struct hostent *ServerDetail;
char msg1[] = "GET /update?key=R1RZZTHF262M1W56&field1=";
char msg2[3];
char msg3[] = "&field2=";
char msg4[3];
char msg5[] = " HTTP/1.0\r\nHost: api.thingspeak.com\r\n\r\n";
wiringPiSetupGpio();
delay(1000);
ServerDetail=gethostbyname(URL_OF_THINGSPEAK);
bzero((char *)&serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
bcopy((char *)ServerDetail->h_addr,
(char *)&serveraddr.sin_addr.s_addr,
ServerDetail->h_length);
serveraddr.sin_port = htons(Port);
//
// Connect to Thingspeak Cloud Service, read the temperature and
// humidity into msg2 and msg4
//
connect(sock, (struct sockaddr*)&serveraddr, sizeof(serveraddr));
Read_DHT11(&Temp, &Hum);
sprintf(msg2, "%d", Temp);
sprintf(msg4, "%d", Hum);
//
// Send the data to Thingspeak Cloud Service
//
write(sock, msg1, strlen(msg1));
write(sock, msg2, strlen(msg2));
write(sock, msg3, strlen(msg3));
write(sock, msg4, strlen(msg4));
write(sock, msg5, strlen(msg5));
delay(2000);
close(sock);
}
//
// Main program. Call function Send to send the readings to Cloud
● 371
C Programming on Raspberry Pi
// every minute
//
int main(void)
{
while(1)
{
Send();
delay(60000);
}
}
Figure 17.5 Program Cloud.c
The graphs can be configured using the menu options on the top right-hand side of the
graphs. For example, by clicking option Field1 Chart (first option) on the temperature
graph displays the graph shown in Figure 17.7.
Clicking option Field 1 Chart 1 Options (third option) on the temperature graph displays
● 372
Chapter 17 ● Sending Data to the Cloud
graph options. As shown in Figure 17.8, graph titles, etc. can be changed.
The Data Import/Export option at the top of the screen can be used to import or export
data, for example to Excel.
The data can be accessed from a web browser by specifying the channel number. The
channel must be public to access it from anywhere. Users without a licence can share a
channel with up to three users (see menu option Sharing). The web command to access
a channel is:
https://api.thingspeak.com/channels/YOUR_CHANNEL_ID
where, for example, in this project, the channel id is: 1278451. Therefore, the link to the
data in this example project is:
https://api.thingspeak.com/channels/1278451
At the time of writing this book, it was not possible to configure the graphs, for example,
to change vertical or horizontal axes or the starting date of the graphs. A separate graph
with the required starting date (and time) can be plotted using the following web link where
the channel number and starting date are specified (see the ThingSpeak web site for more
details):
http://api.thingspeak.com/channels/1278451/charts/1?start=2021-12-31
● 373
C Programming on Raspberry Pi
● Index
Symbols
A
ADCs 9, 252, 253
Advanced Ip Scanner 17
Android smartphone 10, 327, 328, 330, 341, 349, 351, 352
Arduino Uno 9, 275
Arithmetic functions 7, 61
Arrays 7, 55, 95
ASCII 57, 184, 272
Auto increment/decrement operators 7, 41
C
Character macros 7, 67, 68
command mode 14, 17, 28, 34, 226, 257, 351
comparison operators 40
crontab 358, 359, 360, 361, 362, 365
Crontab generator 362
current sinking mode 103, 302
current source mode 103
D
DACs 9, 260, 261
dhcpcd 22, 23
DHT11 160, 168, 170, 171, 178, 196, 367, 371
do…while 47
E
EEPROM 9, 210, 211, 212, 213, 214, 215, 216
ESP32 DevKitC 119
Etcher 13
Ethernet cable 15
event counter 9, 10, 283, 284, 286, 311
external interrupts 9, 10, 283, 284, 311
F
File processing 8, 78
Flow control 7, 41
Function prototyping 74
● 374
● Index
H
HD44780 8, 180, 181, 182, 223
Hitachi HD44780 180, 182
HTTP Web server 342
I
I2C Bus 9, 201
I2C LCD 9, 223, 224, 227, 231, 232
L
LCD functions 184, 231
Logical operators 7, 41
M
MCP23017 203, 204, 205, 206, 207, 243, 245, 310
Memory read 212
Memory write 211
Memory write operation 211
Mu 31, 32, 33, 34
multi-tasking 296
multi-threading 296
N
NULL character 57, 60, 89, 328, 345
O
Operators 7, 40
P
pigpiod 10, 325
pigpio library 8, 9, 106, 237, 238, 250, 251, 315, 326
Pointers 8, 88, 89, 93
PrntStr 77, 78
Putty 7, 15, 16, 17, 18, 19, 20, 175, 257
PWM 10, 152, 153, 154, 155, 157, 158, 159, 160, 308, 309, 322, 323
R
Raspbian Buster 7, 12, 13, 25, 31
return statement 71
RS232 272, 273
S
sawtooth wave signal 9, 267, 268, 270
scanf 37, 38, 40, 43, 44, 59, 60, 84, 85, 178
● 375
C Programming on Raspberry Pi
T
TCP/IP 10, 326
Temperature control 172
ThingSpeak 366, 367, 369, 372, 373
Thonny 28, 29, 30, 31, 34
TMP102 9, 216, 217, 218, 219, 220, 332, 333,
tone library 9, 287, 290, 291, 293
U
UDP protocol 326, 331, 337
Unions 8, 85, 86, 87
V
VNC 17, 20
W
Web Server application 10, 341
while statement 47
● 376
books
books books
C Programming on
C Programming
Program listings of all Raspberry Pi projects developed in this book are Elektor International Media BV
available on the Elektor website. Readers can download and use these www.elektor.com
programs in their projects. Alternatively, they can customize them to suit
their applications.
Dogan Ibrahim