Professional Documents
Culture Documents
Raspberry Pi Pico Essentials - Program, Build, and Master Over 50 Projects With Micropython
Raspberry Pi Pico Essentials - Program, Build, and Master Over 50 Projects With Micropython
Raspberry Pi Pico Essentials - Program, Build, and Master Over 50 Projects With Micropython
Index
Raspberry Pi Pico
Essentials
Program, build, and master over 50 projects with
MicroPython and the RP2040 microprocessor
R I ErDe to smar
Send the temperatu
ED •
T
r o g r a m l o o p .
• T
Main p EST
Autorun
Smartphone
EEPROM
> 0 : B shed-DC GI2eCt the
ru
if n ( ) Hello World #! PWM
Bluetooth
r a t u r e
T = GetTempe nDsert T
UART
rd
Breadboa # ILE
str(T)
Tstr = "T=" +
RP2040
BME-280
7-segment
Length
Sensors
I2S
DAC & ADC
r ) ) #
n(Tst IoT
Tlen = str(le l e n + " \ r \ n " # AT c
END="+T
Dt = "AT+CIPS # Send to ESP
)
uart.write(Dt # Wait 2 sec
)
utime.sleep(2 # Send da
tr)
uart.write(Ts
Dogan Ibrahim
● 495
Raspberry Pi Pico Essentials
Program, build, and master over 50 projects with
MicroPython and the RP2040 microprocessor
Dogan Ibrahim
● This is an Elektor Publication. Elektor is the media brand of
Elektor International Media B.V.
PO Box 11, NL-6114-ZG Susteren, The Netherlands
Phone: +31 46 4389444
● All rights reserved. No part of this book may be reproduced in any material form, including photocopying, or
storing in any medium by electronic means and whether or not transiently or incidentally to some other use of this
publication, without the written permission of the copyright holder except in accordance with the provisions of the
Copyright Designs and Patents Act 1988 or under the terms of a licence issued by the Copyright Licencing Agency
Ltd., 90 Tottenham Court Road, London, England W1P 9HE. Applications for the copyright holder's permission to
reproduce any part of the publication should be addressed to the publishers.
● Declaration
The Author and the Publisher have used their best efforts in ensuring the correctness of the information contained
in this book. They do not assume, and hereby disclaim, any liability to any party for any loss or damage caused by
errors or omissions in this book, whether such errors or omissions result from negligence, accident or any other
cause.
Elektor is part of EIM, the world's leading source of essential technical information and electronics products for pro
engineers, electronics designers, and the companies seeking to engage them. Each day, our international team develops
and delivers high-quality content - via a variety of media channels (including magazines, video, digital media, and social
media) in several languages - relating to electronics design and DIY electronics. www.elektormagazine.com
●4
Content
Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
Chapter 3 • R
aspberry Pi Pico Simple Hardware Projects . . . . . . . . . . . . . . . . . . . 48
3.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
3.7 Project 6: Changing the LED flashing rate – using pushbutton interrupts . . . . . . . . 58
●5
Raspberry Pi Pico Essentials
3.8 Project 7: Alternately flashing red, green, and blue LEDs — RGB . . . . . . . . . . . . . 63
3.9 Project 8: Randomly flashing red, green, and blue LEDs — RGB . . . . . . . . . . . . . . 65
3.18 LCDs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
3.24 Project 22: Ultrasonic reverse parking aid with buzzer . . . . . . . . . . . . . . . . . . . 114
4.3 Project 2: Temperature measurement – using the internal temperature sensor . . 119
●6
Content
6.4 Project 1: Generate a 1000 Hz PWM waveform with 50% duty cycle . . . . . . . . . . 147
6.8 PROJECT 5: Measuring the frequency and duty cycle of a PWM waveform . . . . . . 152
7.3 Project 1: Sending the Raspberry Pi Pico internal temperature to an Arduino Uno 160
7.4 Project 2: Receiving and displaying numbers from the Arduino Uno . . . . . . . . . . 165
7.5 Project 3: Communicating with the Raspberry Pi 4 over the serial link . . . . . . . . 166
8.8 Project 5: Display BMP280 temperature and atmospheric pressure on an LCD . . . 196
●7
Raspberry Pi Pico Essentials
10.3 Project 2: Displaying the internal temperature on a smartphone using Wi-Fi . . . 212
11.3 Project 1: Controlling an LED from your smartphone using Bluetooth . . . . . . . . 217
12.3 Project 1: Generating squarewave signal with amplitude under +3.3 V . . . . . . . 226
12.9 Project 7: Generating an accurate sinewave signal using timer interrupts . . . . . 242
Chapter 13 • Automatic Program Execution after the Raspberry Pi Pico Boots . . 245
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248
●8
Preface
Preface
Traditionally, a computer was built using a microprocessor chip and many external support
chips. A microprocessor includes a Central Processing Unit (CPU), an Arithmetic and Logic
Unit (ALU), and timing and control circuitry — and as such it is not particularly useful on
its own. A microprocessor must be supported by many external chips such as memory,
input/output, timers, interrupt circuits etcetera, before it becomes a useful computer. The
disadvantage of this type of design was that the chip count was large, resulting in complex
design and wiring, and high power consumption.
A microcontroller on the other hand is basically a single chip computer including a CPU,
memory, input/output circuitry, timers, interrupt circuitry, clock circuitry, and several other
circuits and modules, all housed in a single silicon chip. Early microcontrollers were limited
in their capacities and speed and they consumed considerably more power. Most of the ear-
ly microcontrollers were 8-bit processors with clock speeds in the region of several MHz and
offered only hundreds of bytes of program and data memories. These microcontrollers were
traditionally programmed using the assembly languages of the target processors. 8-bit mi-
crocontrollers are still in common use, especially in small projects where large amounts of
memory or high speed are not the main requirements. With the advancement of chip tech-
nology we now have 32-bit and 64-bit microcontrollers with speeds in the region of several
GHz and offering several GB of memory space. Microcontrollers are nowadays programmed
using a high-level language such as C, C#, BASIC, PASCAL, JAVA, etc.
The Raspberry Pi Pico is based on the fast and very efficient dual-core ARM Cortex-M0+
RP2040 microcontroller chip running at up to 133 MHz. The chip incorporates 264 KB of
SRAM and 2 MB of Flash memory. What makes the Raspberry Pi Pico very attractive is its
large number of GPIO pins, and commonly used peripheral interface modules, such as SPI,
I2C, UART, PWM, plus fast and accurate timing modules.
Perhaps the biggest advantage of the Raspberry Pi Pico compared to other many microcon-
trollers in the marketplace is its very low cost, large memory, and fast and accurate timing
modules. At the time of writing this book the cost of a single unit was around $6.
Raspberry Pi Pico can easily be programmed using some of the popular high-level languag-
es such as MicroPython, or C/C++. There are many application notes, tutorials, and data-
sheets available on the Internet covering the use of the Raspberry Pi Pico.
●9
Raspberry Pi Pico Essentials
This book is an introduction to using the Raspberry Pi Pico microcontroller with the Micro-
Python programming language. The Thonny development environment (IDE) is used in all
the projects in the book, and readers are recommended to use this IDE. There are over
50 working and tested projects in the book, covering almost all aspects of the Raspberry
Pi Pico.
The following sub-headings are given for each project to make it easy to follow:
• Title
• Brief Description
• Aim
• Block Diagram
• Circuit Diagram
• Program Listing with full description
I hope your next microcontroller-based projects make use of the Raspberry Pi Pico, and this
book becomes useful in the development of your projects.
Dr Dogan Ibrahim
London, February, 2021
● 10
Chapter 1 • Raspberry Pi Pico Hardware
1.1 Overview
The Raspberry Pi Pico is a single-board microcontroller module developed by the Raspberry
Pi Foundation. This module is based on the RP2040 microcontroller chip. In this Chapter we
will be looking at the hardware details of the Raspberry Pi Pico microcontroller module in
some detail. From here on, we will be calling this microcontroller module "Pico" for short, in
for appreciation and recognition though of its official name: Raspberry Pi Pico.
At one edge of the board there is the micro-USB B port for supplying power to the board as
well as for programming it. Next to the USB port there is an on-board user LED that can be
used during program development. Next to this LED sits a button named as BOOTSEL that
is used during programming of the microcontroller as we will see in next Chapters. At the
other edge of the board, next to the Raspberry Pi logo, there are 3 connectors that can be
used for debugging your programs.
Figure 1.2 shows the back view of the Pico hardware module. Here, all the GPIO pins are
identified with letters and numbers. You will notice the following types of letters and num-
bers:
● 11
Raspberry Pi Pico Essentials
Some of the GPIO pins are used for internal board functions. These are:
● 12
Chapter 1 • Raspberry Pi Pico Hardware
The Pico's GPIO hardware is +3.3 V compatible and it is therefore important to be careful
not to exceed this voltage when interfacing external input devices to the GPIO pins. +5 V
to +3.3 V logic converter circuits or resistive potential divider circuits must be used if it is
required to interface devices with +5 V outputs to the Pico GPIO pins.
Figure 1.3 shows a resistive potential divider circuit that can be used to lower +5 V to +3.3 V.
● 13
Raspberry Pi Pico Essentials
An on-board SMPS is used to generate the +3.3 V to power the RP2040 from a range of
input voltages from 1.8 V to +5.5 V. For example, 3 alkaline size-AA batteries can be used
to provide +4.5 V to power the Pico.
The Pico can be powered in several ways. The simplest method is to plug the micro-USB
port into a +5 V power source, such as the USB port of a computer or a +5 V power adapt-
er. This will provide power to the VSYS input (see Figure 1.4) through a Schottky diode. The
voltage at the VSYS input is therefore VBUS voltage minus the voltage drop of the Schottky
diode (about +0.7 V). VBUS and VSYS pins can be shorted if the board is powered from an
external +5 V USB port. This will increase the voltage input slightly and hence reduce rip-
ples on VSYS. VSYS voltage is fed to the SMPS through the RT6150 which generates fixed
+3.3 V for the MCU and other parts of the board. VSYS is divided by 3, and is available at
analogue input port GPIO29 (ADC3) which can easily be monitored. GPIO24 checks the
existence of VBUS voltage and is at logic HIGH if VBUS is present.
Another method to power the Pico is by applying external voltage (+1.8 V to +5.5 V) to the
VSYS input directly (e.g., using batteries or external power supply). We can also use the
USB input and VSYS inputs together to supply power to Pico, for example to operate with
both batteries and the USB port. If this method is used, then a Schottky diode should be
used at the VSYS input to prevent the supplies from interfering with each other. The higher
of the voltages will power VSYS.
● 14
Chapter 1 • Raspberry Pi Pico Hardware
Figure 1.7 shows a simplified block diagram of the Pico hardware module. Notice that the
GPIO pins are directly connected from the microcontroller chip to the GPIO connector. GPIO
nos. 26-28 can be used either as digital GPIO or as ADC inputs. ADC inputs GPIO26-29
have reverse-biased diodes to 3 V and therefore the input voltage must not exceed 3V3 +
● 15
Raspberry Pi Pico Essentials
300 mV. Another point to note is that if the RP2040 is not powered, applying voltages to
GPIO26-29 pins may leak through the diode to the power supply (there is no problem with
the other GPIO pins and voltage can be applied when the RP2040 is not powered).
● 16
Chapter 1 • Raspberry Pi Pico Hardware
● 17
Raspberry Pi Pico Essentials
● 18
Chapter 1 • Raspberry Pi Pico Hardware
• piezo speaker
• 1.54-inch IPS LCD
• 4× buttons
• 2× half-bridge motor drives
• two breakout I2C sockets
• easy access to GPIO and ADC pins
• mini breadboard
• no soldering required
• Raspberry Pi Pico not supplied
● 19
Raspberry Pi Pico Essentials
• 4×4 keypad
• 16× APA102 RGB LEDs
• keypad connected via I2C I/O expander
• GPIO pins labelled
● 20
Chapter 1 • Raspberry Pi Pico Hardware
● 21
Raspberry Pi Pico Essentials
● 22
Chapter 2 • Raspberry Pi Pico Programming
2.1 Overview
At the time of writing this book, the Raspberry Pi Pico accepts programming with the fol-
lowing programming languages:
• C/C++
• MicroPython
• assembly language
Although the Pico by default is set up for use with the powerful and popular C/C++ lan-
guage, many beginners find it easier to use MicroPython, which is a version of the Python
programming language developed specifically for microcontrollers.
In this Chapter we will learn how to install and use the MicroPython programming language.
We will be using the Thonny text editor which has been developed specifically for Python
programs.
Many working and fully tested projects will be given in the next Chapters using MicroPython
with our Pico. Use of the C language will also be discussed in later Chapters with some
projects.
● 23
Raspberry Pi Pico Essentials
• In the File Manager window, you will see two files with the names
INDEX.HTM and INFO_UF2.TXT (Figure 2.2).
● 24
Chapter 2 • Raspberry Pi Pico Programming
• Click on the Getting started with MicroPython tab and click Download UF2
file to download the MicroPython firmware. You should see the downloaded
file at the bottom of the screen. This will take only a few seconds (Figure 2.4).
• Close your browser window by clicking on the cross icon located at the top right
corner.
• Open the File Manager by clicking on menu, followed by Accessories.
• Open the Downloads folder (under /home/pi) and locate the file
with the extension: .uf2. This file will have a name similar to:
micropython-20-Jan-2021.uf2 (Figure 2.5)
• Drag and drop this file to Raspberry Pi Pico's removable drive which is named:
RPI-RP2 (at the top left side of the screen – see Figure 2.5).
• After a while, the MicroPython firmware will be installed onto the internal
storage of Pico and the drive will disappear.
• Your Pico is now running MicroPython.
• Powering-down the Pico will not erase MicroPython from its memory.
● 25
Raspberry Pi Pico Essentials
• Click on the label Python at the bottom right-hand corner of Thonny (Figure
2.7).
• You should see the version number of your MicroPython displayed in the bottom
part of the screen where Shell is located (Figure 2.9).
● 26
Chapter 2 • Raspberry Pi Pico Programming
• We are now ready to write our simple program. Enter the following line in the
lower part of the screen where Shell sits. Program statements written in this
part of Thonny are executed online and immediately. This part is normally used
to test parts of a program. Enter:
you should see message Hello from Raspberry Pi Pico displayed as shown in
Figure 2.10.
Thonny's icons
At the top of the Thonny screen you will see a number of icons as shown in Figure 2.11.
The functions of these icons are described in this section (notice that plain letters are used
to identify the icons).
● 27
Raspberry Pi Pico Essentials
• Enter the program statements at the upper part of the screen as shown in
Figure 2.12.
• Click File followed by Save As and give a name to your program. e.g. First-
Prog. You have the option of storing the program either on your Raspberry Pi
or on the Pico. Click Raspberry Pi Pico to save it on the Pico (Figure 2.13).
Enter the name of your program (FirstProg) and click OK (notice that the file
is saved with the extension .py).
• Click the green arrow icon at the top of the screen (under Run) to run your
program. The output of the program will be displayed in the lower Shell part of
the screen as shown in Figure 2.14.
● 28
Chapter 2 • Raspberry Pi Pico Programming
• Click on drive RPI-RP2. You will see two files with the names INDEX.HTM and
INFO_UF2.TXT (see Figure 2.16).
● 29
Raspberry Pi Pico Essentials
• Click on the Getting started with MicroPython tab and click Download UF2
file to download the MicroPython firmware. You should see the downloaded
file at the bottom of the screen. This will take only a few seconds (Figure 2.18).
• Drag and drop this file to Raspberry Pi Pico's removable drive named:
RPI-RP2.
• After a while, the MicroPython firmware will be installed onto the internal stor-
age of Pico and the drive RPI-RP2 will disappear.
• Your Pico is now running MicroPython.
• Powering down the Pico will not erase MicroPython from its memory.
● 30
Chapter 2 • Raspberry Pi Pico Programming
• You should see an icon on the Desktop (Figure 2.21) of your PC. Double-click to
start Thonny.
● 31
Raspberry Pi Pico Essentials
• Click on the label Python at the bottom right-hand corner of the screen and
click to select MicroPyhton (Raspberry Pi Pico).
• You are now ready to write your programs.
• Enter the following statement at the lower part of the screen (in Shell):
In this book we will be using Thonny on the PC to write programs and to execute
them on the Raspberry Pi Pico.
Simple example programs are given in the remainder sections of this Chapter. The aim here
has been to review the basic Python programming concepts. However, this book does not
aim to teach Python programming. There are many books and tutorials on the Internet for
learning Python.
● 32
Chapter 2 • Raspberry Pi Pico Programming
Solution 1
The program is named Average and the program listing and an example run of the pro-
gram are shown in Figure 2.25. Function input is used to read the numbers in the form of
strings from the keyboard. These strings are then converted into floating point numbers
and stored in variables n1 and n2. The average is calculated by adding and then dividing
the numbers by two. The result is displayed on the screen.
Solution 2
The program is named Average10 and the program listing and an example run of the pro-
gram are shown in Figure 2.26. In this program a loop is constructed which runs from 0 to
9 (i.e. 10 times). Inside this loop the numbers are read from the keyboard, added to each
other, and stored in variable sum. The average is then calculated and displayed by dividing
sum by 10. Notice that a new-line is not printed after the print statements since the option
end = ' ' is used inside the print statement.
● 33
Raspberry Pi Pico Essentials
Solution 3
The program is named CylArea, and the program listing and an example run of the pro-
gram are shown in Figure 2.27. The surface area of a cylinder is given by:
Surface area = 2 × π × r × h
Where r and h are the radius and height of the cylinder respectively. In this program the
math library is imported so that function Pi can be used in the program. The surface area
of the cylinder is displayed after reading its radius and height.
● 34
Chapter 2 • Raspberry Pi Pico Programming
Example 4 — ºC to ºF conversion
In this example the program reads degrees Celsius from the keyboard and converts and
displays the equivalent degrees Fahrenheit.
Solution 4
The program is named CtoF and the program listing and an example run of the program
are shown in Figure 2.28. The formula to convert ºC to ºF is:
F = 1.8 × C + 32
● 35
Raspberry Pi Pico Essentials
Solution 5
The program is named CylAreaSurf and the program listing, and an example run of the
program are shown in Figure 2.29. The surface area and the volume of a cylinder are given
by:
Surface area = 2 × π × r × h
Volume = π × r2 × h
Where r and h are the radius and height of the cylinder respectively. Function Calc is used
to get the radius and height of the cylinder. The function returns the surface area and vol-
ume to the main program which are displayed on the screen.
Solution 6
The program is named Squares, and the program listing and an example run of the pro-
gram are shown in Figure 2.30. Notice that \t prints a tab so that the data can be tabulated
nicely.
● 36
Chapter 2 • Raspberry Pi Pico Programming
Solution 7
The program is named Sines, and the program listing and an example run of the program
are shown in Figure 2.31. It is important to notice that the arguments of the trigonometric
functions must be in radians and not in degrees.
● 37
Raspberry Pi Pico Essentials
Solution 8
The program is named Trig, and the program listing and an example run of the program
are shown in Figure 2.32.
Solution 9
The program is named TrigUser, and the program listing and an example run of the pro-
gram are shown in Figure 2.33.
● 38
Chapter 2 • Raspberry Pi Pico Programming
Solution 10
When a number of resistors are in series, then the resultant resistance is the sum of the
resistance of each resistor. When the resistors are in parallel, then the reciprocal of the
resultant resistance is equal to the sum of the reciprocal resistances of each resistor.
Figure 2.34 shows the program listing (program: Serpal). At the beginning of the program,
a heading is displayed, and the program enters a while loop. Inside his loop, the user is
prompted to enter the number of resistors in the circuit and whether they are connected
in series or in parallel. Function str converts a number into its equivalent string. e.g. num-
ber 5 is converted into string "5". If the connection is serial (mode equals to 's'), then the
value of each resistor is accepted from the keyboard and the resultant is calculated and
displayed on the screen. If on the other hand the connection is parallel (mode is equals to
'p'), then again the value of each resistor is accepted from the keyboard and the reciprocal
of the number is added to the total. When all the resistor values are entered, the resultant
resistance is displayed on the screen.
while yn == 'y':
N = int(input("\nHow many resistors are there?: "))
mode = input("Are the resistors series (s) or parallel (p)?: ")
● 39
Raspberry Pi Pico Essentials
mode = mode.lower()
#
# Read the resistor values and calculate the total
#
resistor = 0.0
if mode == 's':
for n in range(0,N):
s = "Enter resistor " + str(n+1) + " value in Ohms: "
r = int(input(s))
resistor = resistor + r
print("Total resistance = %d Ohms" %(resistor))
● 40
Chapter 2 • Raspberry Pi Pico Programming
Solution 11
The required program listing is shown in Figure 2.36 (program: Letters). A word is read
from the keyboard and stored in string variable word. Then the letters of this word are
displayed in reverse order. An example run of the program is shown in Figure 2.36.
Example 12 — Calculator
Write a calculator program to carry out the four simple mathematical operations of addi-
tion, subtraction, multiplication, and division on two numbers received from the keyboard.
Solution 12
The required program listing is shown in Figure 2.37 (program: Calc). Two numbers are
received from the keyboard and stored in variables n1 and n2. Then, the required math-
ematical operation is received and it is performed. The result, stored in variable result, is
displayed on the screen. The user is given the option of terminating the program.
any = 'y'
while any == 'y':
print("\nCalculator Program")
print("==================")
● 41
Raspberry Pi Pico Essentials
if op =="+":
result = n1 + n2
elif op == "-":
result = n1 - n2
elif op == "*":
result = n1 * n2
elif op == "/":
result = n1 / n2
print("Result = %f" %(result))
any = input("\nAny more (yn): ")
Example 13 — Dice
Write a program to simulate double dice, i.e. to display two random numbers between 1
and 6 every time it is run.
Solution 13
The required program listing is shown in Figure 2.39 (program: Dice). Here, the ran-
dom-number generator randint is used to generate random numbers between 1 and 6
when the Enter key is pressed. The program is terminated when letter x (or X) is entered.
● 42
Chapter 2 • Raspberry Pi Pico Programming
Solution 14
The program is named Sort, and its listing and an example run are shown in Figure 2.40.
Solution 15
The program is named Filew and its listing and an example run are shown in Figure 2.41.
● 43
Raspberry Pi Pico Essentials
The fie is opened in write (w) mode and the text is written in it using function write. Notice
here that fp is the file handle.
Solution 16
The program is named Filer, and its listing and an example run are shown in Figure 2.42.
The fie is opened in read (r) mode and its contents is displayed.
Solution 17
The program is named Cubes, and its listing an example run are shown in Figure 2.43.
● 44
Chapter 2 • Raspberry Pi Pico Programming
Solution 18
The program is named Times, and its listing and an example run are shown in Figure 2.44.
Solution 19
The program is named OddEven, and its listing and an example run are shown in Figure
2.45.
● 45
Raspberry Pi Pico Essentials
Solution 20
The program is named Conv, and its listing and an example run are shown in Figure 2.46.
Solution 21
The program is named AddMatrix, and its listing and an example run are shown in Figure
2.47.
● 46
Chapter 2 • Raspberry Pi Pico Programming
● 47
Raspberry Pi Pico Essentials
3.1 Overview
In this Chapter we will be developing simple hardware projects with the Raspberry Pi Pico,
using the Thonny text editor. The following sub-headings will be given for each project
where applicable:
• Title
• Description
• Aim
• Block Diagram
• Circuit Diagram
• Program Listing
• Suggestions for future work
All the programs in this Chapter have been developed using the Thonny on a PC, with the
Raspberry Pi Pico connected to the USB port of the PC.
Aim: The aim of this project is to make the reader familiar with some basic GPIO control
statements.
Program listing: Figure 3.1 shows the program listing (Program: LEDINT). At the be-
ginning of the program modules machine and utime are imported to the program. LED
is then assigned to port pin GP25 and it is configured as an output. The remainder of the
program runs in a loop forever, until stopped by the user. Inside this loop the LED is turned
ON by the statement LED.value(1). After a delay of one second the LED is turned OFF by
the statement LED.value(0). Function utime.sleep(n) creates n seconds of delay in the
program.
#---------------------------------------------------------
# FLASHING THE ON-BOARD LED
# =========================
#
# In this program the on-board LED (at GP25) is flashed
# every second
#
# Author: Dogan Ibrahim
# File : LEDINT.py
# Date : February, 2021
#----------------------------------------------------------
import machine
import utime
● 48
Chapter 3 • Raspberry Pi Pico Simple Hardware Projects
In Figure 3.1, import machine module imports other functions in addition to Pin. We can
simplify the program by importing only the Pin functions as shown in Figure 3.2 (Program:
LEDINT2). You may have to stop the program by selecting Run followed by Stop/Restart
backend before being able to save a new program while a program is already running on
Pico.
#---------------------------------------------------------
# FLASHING THE ON-BOARD LED
# =========================
#
# In this program the on-board LED (at GP25) is flashed
# every second. In this version only module Pin is imported
#
# Author: Dogan Ibrahim
# File : LEDINT2.py
# Date : February, 2021
#----------------------------------------------------------
from machine import Pin
import utime
The machine module supports the following functions (we will see in later Chapters how
to use these functions):
• Pin
• Timer
• ADC
● 49
Raspberry Pi Pico Essentials
Parameter value is valid only for Pin.OUT and Pin.OPEN_DRAIN modes and it specifies the
initial output pin value (if specified).
Parameter alt specifies an alternate function for the pin (port dependent). This parameter
is valid only for PIN.ALT and Pin.ALT_OPEN_DRAIN modes.
● 50
Chapter 3 • Raspberry Pi Pico Simple Hardware Projects
Aim: The aim of this project is to show how an external LED can be connected to the Pico.
Block diagram: Figure 3.3 shows the block diagram of the project.
Circuit diagram: The circuit diagram of the project is shown in Figure 3.4. The LED is
connected to port pin GP0 of Pico through a current-limiting resistor.
● 51
Raspberry Pi Pico Essentials
The required value of the current limiting resistor can be calculated as follows. In cur-
rent-sourcing mode, assuming the output HIGH voltage is +3.3 V, the voltage drop across
the LED is 2 V, and the current through the LED is 3 mA, the required value of the current
limiting resistor is:
Program listing: Figure 3.7 shows the program listing (Program: ExtFlash.py).
#---------------------------------------------------------
# FLASHING AN EXTERNAL LED
# ========================
#
# In this program an external LED is connected to port pin
# GP0 (pin 1). The LED is flashed every second
● 52
Chapter 3 • Raspberry Pi Pico Simple Hardware Projects
#
# Author: Dogan Ibrahim
# File : ExtFlash.py
# Date : February, 2021
#----------------------------------------------------------
from machine import Pin
import utime
Figure 3.8 shows the Fritzing diagram of the project built on a breadboard.
Program listing. Figure 3.9 shows the program listing (Program: SOS). At the beginning
of the program the dot, dash, and gap times are defined. Then a loop is formed using a
while statement. Inside this loop two for loops are formed, each iterating 3 times. The
● 53
Raspberry Pi Pico Essentials
first loop displays three dots, while the second loop displays three dashes. This process is
repeated after 2 seconds of delay.
#---------------------------------------------------------
# LED FLASHING SOS
# ================
#
# In this program an external LED is connected to port pin
# GP0 (pin 1). The LED flashes the SOS signal
#
# Author: Dogan Ibrahim
# File : SOS.py
# Date : February, 2021
#----------------------------------------------------------
from machine import Pin
import utime
● 54
Chapter 3 • Raspberry Pi Pico Simple Hardware Projects
Suggestions: You could easily replace the LED with a buzzer to make the SOS signal au-
dible. There are two types of buzzers: active and passive. Passive buzzers require an audio
signal to be sent to them and the frequency of the output signal depends on the frequency
of the supplied signal. Active buzzers are ON/OFF type devices producing audible sound
when activated. In his project we can use an active buzzer with a transistor switch (any
NPN type transistor can be used) as shown in Figure 3.10.
Aim: The aim of this project s to show how a timer can be used in a program.
The block diagram and circuit diagram of this project are the same as in Figure 3.3 and
Figure 3.4, respectively.
Program listing. Figure 3.11 shows the program listing (Program: LEDTimer). Here, a
timer is initialized which calls function Flash_LED twice (freq = 2.0) a second in a periodic
manner. Notice that the LED is flashed using the toggle function.
#---------------------------------------------------------
# LED FLASHING USING A TIMER
# ==========================
#
# In this program an external LED is connected to port pin
# GP0 (pin 1). The LED flashes every second using a timer
#
# Author: Dogan Ibrahim
# File : LEDTimer.py
# Date : February, 2021
#----------------------------------------------------------
from machine import Pin, Timer
● 55
Raspberry Pi Pico Essentials
tim = Timer()
def Flash_LED(timer):
global LED
LED.toggle()
Aim: The aim of this project is to show how multiple LEDs can be connected to the Pico.
Block diagram: Figure 3.12 shows the block diagram of the project.
Circuit diagram: The circuit diagram of the project is shown in Figure 3.13. The LEDs are
connected to port pins GP0 and GP1 through 470-ohm current limiting resistors.
● 56
Chapter 3 • Raspberry Pi Pico Simple Hardware Projects
Program listing: Figure 3.14 shows the program listing (Program: LED2).
#---------------------------------------------------------
# ALTERNATELY FLASHING LEDs
# =========================
#
# In this program two external LEDs are connected to pins
# GP0 (pin 1) and GP1 (pin 2). The LEDs flash alternately
# every 500ms
#
# Author: Dogan Ibrahim
# File : LED2.py
# Date : February, 2021
#----------------------------------------------------------
from machine import Pin
import utime
while True:
LED1.value(1)
LED2.value(0)
utime.sleep(0.5)
LED1.value(0)
LED2.value(1)
utime.sleep(0.5)
Figure 3.15 shows the Fritzing diagram of the project built on a breadboard.
● 57
Raspberry Pi Pico Essentials
Aim: The aim of this project is to show how pushbuttons can be connected to the Pico, and
how the state of a button can be read.
Block diagram: Figure 3.16 shows the block diagram of the project.
Circuit diagram: The circuit diagram of the project is shown in Figure 3.17. The LED is
connected through a 470-ohm current limiting resistor. The two pushbuttons are connected
through 10-kohm resistors. The default state of the pushbuttons is at logic 1, being pulled-
up through the resistors. Pressing a pushbutton changes its output state to logic 0.
● 58
Chapter 3 • Raspberry Pi Pico Simple Hardware Projects
Program listing: Figure 3.18 shows the program listing (Program: LEDrate). At the be-
ginning of the program LED is assigned to pin GP0, and pushbuttons Faster and Slower
are assigned to ports GP1 and GP2 respectively. The default flashing rate is set to one sec-
ond and is stored in variable dly. The program is external-interrupt-based. Pressing either
of the pushbuttons creates an interrupt. For example, the interrupt for pushbutton Faster
is configured using the following function call:
Faster.irq(handler=Flash_Faster, trigger=Faster.IRQ_FALLING)
Where Flash_Faster is the name of the interrupt service routine where dly is decrement-
ed. The interrupt is configured to happen on the falling edge of the pushbutton, i.e. when
the pushbutton is pressed (the normal state of the pushbuttons is at logic 1, being pulled-
up by resistors). Inside the interrupt service routine Flash_Faster variable dly is declared
as global so that it can be accessed. Its value is then decremented by 100ms (0.1 second).
The Interrupt service routine for pushbutton Slower is done similarly where the delay is
incremented by 100 ms each time the button is pressed.
The above values can be OR'ed together to trigger on multiple events. We can also spec-
ify the interrupt priority with the keyword priority, where higher values represent higher
priorities.
An interrupt wake parameter can be specified with the values None, machine.IDLE,
machine.SLEEP, or machine.DEEPSLEEP.
Additionally, a parameter called hard with the values of False or True can be specified.
If this parameter is set to True, then hardware interrupts are used which yields faster
response.
#---------------------------------------------------------
# CHANGE THE LED FLASHING RATE
# ============================
#
# In this program an external LED and two pushbuttons are
# connected to Pico. Pressing Faster flashes the LED faster,
# and pressing Slower flashes the LED slower
#
# Author: Dogan Ibrahim
# File : LEDrate.py
# Date : February, 2021
#----------------------------------------------------------
from machine import Pin
● 59
Raspberry Pi Pico Essentials
import utime
#
# This is the interrupt service routine. Whenever pushbutton
# Faster is pressed, the program jumps here and decrements
# delay to make the flashing faster
#
def Flash_Faster(Faster):
global dly
dly = dly - 0.1
#
# This is the interrupt service routine. Whenever pushbutton
# Slower is pressed, the program jumps here and increments
# delay to make the flashing slower
#
def Flash_Slower(Slower):
global dly
dly = dly + 0.1
#
# Configure the external interrupts
#
Faster.irq(handler=Flash_Faster,trigger=Faster.IRQ_FALLING)
Slower.irq(handler=Flash_Slower,trigger=Slower.IRQ_FALLING)
#
# Main program loop
#
while True:
LED.value(1) # LED ON
utime.sleep(dly) # Delay dly
LED.value(0) # LED OFF
utime.sleep(dly) # Delay dly
● 60
Chapter 3 • Raspberry Pi Pico Simple Hardware Projects
#---------------------------------------------------------
# CHANGE THE LED FLASHING RATE
# ============================
#
# In this program an external LED and two pushbuttons are
# connected to Pico. Pressing Faster flashes the LED faster,
# and pressing Slower flashes the LED slower
# In this modified version, internal pull-ups are used
#
# Author: Dogan Ibrahim
# File : LEDrate2.py
● 61
Raspberry Pi Pico Essentials
#
# This is the interrupt service routine. Whenever pushbutton
# Faster is pressed, the program jumps here and decrements
# delay to make the flashing faster
#
def Flash_Faster(Faster):
global dly
dly = dly - 0.1
#
# This is the interrupt service routine. Whenever pushbutton
# Slower is pressed, the program jumps here and increments
# delay to make the flashing slower
#
def Flash_Slower(Slower):
global dly
dly = dly + 0.1
#
# Configure the external interrupts
#
Faster.irq(handler=Flash_Faster,trigger=Faster.IRQ_FALLING)
Slower.irq(handler=Flash_Slower,trigger=Slower.IRQ_FALLING)
#
# Main program loop
#
while True:
LED.value(1) # LED ON
utime.sleep(dly) # Delay dly
LED.value(0) # LED OFF
utime.sleep(dly) # Delay dly
● 62
Chapter 3 • Raspberry Pi Pico Simple Hardware Projects
3.8 Project 7: Alternately flashing red, green, and blue LEDs — RGB
Description: This is a very simple project where an RGB LED is connected to the Raspberry
Pi Pico and the red, green, and blue colours are flashed alternately every 500 ms.
Aim: The aim of this project is to show how an RGB LED can be used in a Raspberry Pi Pico
project.
Background Information: As shown in Figure 3.22, the RGB LED is a 4-pin device which
incorporates Red, Green and Blue LEDs. Each colour LED is assigned a pin, where the fourth
pin is the ground. By activating different LEDs at different brightness, we can generate
many different colours. In this project a common cathode RGB LED is used. Notice that the
cathode pin of the RGB LED is the longer pin.
Block Diagram: Figure 3.23 shows the block diagram of the project.
Circuit Diagram: The circuit diagram of the project is shown in Figure 3.24. The Red,
Green, and Blue pins are connected to port pins GP0, GP1, and GP2 respectively through
470-ohm current limiting resistors.
● 63
Raspberry Pi Pico Essentials
Program Listing: The program is very simple and is shown in Figure 3.25 (program:
RGB). At the beginning of the program the RED, GREEN, and BLUE LEDs are assigned to
the 0, 1, and 2 port pins respectively, and the LED ports are configured as outputs. The
remainder of the program runs in an endless loop. Inside this loop the RED, GREEN, and
BLUE LEDs are turned ON and OFF with 0.5-second delay between each output.
#---------------------------------------------------------
# ALTERNATELY FLASHING RGB LED
# ============================
#
# In this program an RGB LED is connected to Pico.The three
# colours of the LED are flashed alternately every 500ms
#
# Author: Dogan Ibrahim
# File : RGB.py
# Date : February, 2021
#----------------------------------------------------------
from machine import Pin
import utime
Red.value(0)
Green.value(0)
Blue.value(0)
while True:
Red.value(1)
utime.sleep(0.5)
Red.value(0)
Green.value(1)
utime.sleep(0.5)
● 64
Chapter 3 • Raspberry Pi Pico Simple Hardware Projects
Green.value(0)
Blue.value(1)
utime.sleep(0.5)
Blue.value(0)
3.9 Project 8: Randomly flashing red, green, and blue LEDs — RGB
Description: In this project the RGB LEDs flash randomly, where the Red, Green, or the
Blue LEDs are randomly ON or OFF.
The block diagram and the circuit diagram are the same as in Figure 3.23 and 3.24, re-
spectively.
Program listing: Figure 3.27 shows the program listing (Program: RGB2). Random num-
bers are generated either as 0 or 1 for each colour, and these numbers are used either to
turn ON or OFF a colour LED.
#---------------------------------------------------------
# RANDOMLY FLASHING RGB LED
# =========================
#
# In this program an RGB LED is connected to Pico.The three
# colours of the LED are flashed randomly every 500ms
#
# Author: Dogan Ibrahim
# File : RGB2.py
# Date : February, 2021
#----------------------------------------------------------
from machine import Pin
import utime
● 65
Raspberry Pi Pico Essentials
import random
while True:
r = random.randint(0, 1)
g = random.randint(0, 1)
b = random.randint(0, 1)
Red.value(r)
utime.sleep(0.2)
Green.value(g)
utime.sleep(0.2)
Blue.value(b)
utime.sleep(0.2)
Block diagram: Figure 3.29 shows the block diagram of the project.
● 66
Chapter 3 • Raspberry Pi Pico Simple Hardware Projects
Circuit diagram: The circuit diagram of the project is shown in Figure 3.30. The LEDs are
connected to the Pico through 470-ohm current limiting resistors.
Program listing. Figure 3.31 shows the program listing (Program: ROTATE).
#---------------------------------------------------------
# ROTATING LEDs
# =============
#
# In this program 4 LEDs are connected to Pico. The LEDs
# display pattern of rotating to the left
#
# Author: Dogan Ibrahim
# File : Rotate.py
# Date : February, 2021
#----------------------------------------------------------
from machine import Pin
import utime
● 67
Raspberry Pi Pico Essentials
while True:
LED1.value(1)
utime.sleep(0.5)
LED1.value(0)
LED2.value(1)
utime.sleep(0.5)
LED2.value(0)
LED3.value(1)
utime.sleep(0.5)
LED3.value(0)
LED4.value(1)
utime.sleep(0.5)
LED4.value(0)
#---------------------------------------------------------
# ROTATING LEDs
# =============
#
# In this program 4 LEDs are connected to Pico. The LEDs
# display pattern of rotating to the left
#
# Author: Dogan Ibrahim
# File : Rotate2.py
# Date : February, 2021
#----------------------------------------------------------
from machine import Pin
import utime
● 68
Chapter 3 • Raspberry Pi Pico Simple Hardware Projects
for i in range(4):
L[i].value(1) # LED ON
utime.sleep(0.5) # Wait 0.5 second
L[i].value(0) # LED OFF
Aim: The aim of this project is to show how a group of port pins can be combined and
accessed as a parallel port.
Block diagram: Figure 3.35 shows the block diagram of the project.
● 69
Raspberry Pi Pico Essentials
Circuit diagram: The circuit diagram of the project is shown in Figure 3.36. The LEDs are
connected to the Pico through 470-ohm current limiting resistors.
Program listing. Figure 3.37 shows the program listing (Program: LEDCount). All 8 GPIO
ports used in the project are configured as outputs using the function Configure_Port.
Notice that the Configure_Port function is general, and the list DIR sets the directions of
the GPIO pins. An "O" sets as an output and an "I" sets as an input. Then, a loop is formed
to execute forever and inside this loop the LEDs count up by one in binary. Variable cnt is
used as the counter. Function Port_Output is used to control the LEDs. This function can
take integer numbers from 0 to 255 and it converts the input number (x) into binary using
the built-in function bin. Then the leading "0b" characters are removed from the output
string b (bin function inserts characters "0b" to the beginning of the converted string).
Then, the converted string b is made up of 8 characters by inserting leading 0s. The string
is then sent to the PORT bit by bit, starting from the most-significant bit position.
#---------------------------------------------------------
# BINARY COUNTING 8 LEDs
# ======================
#
# In this program 8 LEDs are connected to Pico. The LEDs
● 70
Chapter 3 • Raspberry Pi Pico Simple Hardware Projects
#
# This function configures the port pins as outputs ("0") or
# as inputs ("I")
#
def Configure_Port():
for i in range(0, 8):
if DIR[i] == "0":
L[i] = Pin(PORT[i], Pin.OUT)
else:
L[i] = Pin(PORT[i], Pin.IN)
return
#
# This function sends 8-bit data (0 to 255) to the PORT
#
def Port_Output(x):
b = bin(x) # convert into binary
b = b.replace("0b", "") # remove leading "0b"
diff = 8 - len(b) # find the length
for i in range (0, diff):
b = "0" + b # insert leading os
#
# Configure PORT to all outputs
#
Configure_Port()
● 71
Raspberry Pi Pico Essentials
#
# Main program loop. Count up in binary every second
#
cnt = 0
while True:
Port_Output(cnt) # send cnt to port
utime.sleep(1) # wait 1 second
cnt = cnt + 1 # increment cnt
if cnt > 255:
cnt = 0
Aim: The aim of this project is to show how to generate random numbers between 1 and
255 and then shows how to use these numbers to turn the individual LEDs ON and OFF
randomly.
● 72
Chapter 3 • Raspberry Pi Pico Simple Hardware Projects
The block diagram and circuit diagram of the project are given in Figure 3.35 and Figure
3.36 respectively.
Program listing: The program is called XMAS and the listing is shown in Figure 3.39. All
the 8 GPIO ports used in the project are configured as outputs using the function Config-
ure_Port as in the previous project. Then, a loop is formed to execute forever and inside
this loop a random number is generated between 1 and 255, and this number is used as
an argument to function Port_Output. The binary pattern corresponding to the generated
number is sent to the port which turns the LEDs ON or OFF in a random manner.
#---------------------------------------------------------
# CHRISTMAS LIGHTS
# ================
#
# In this program 8 LEDs are connected to Pico. The LEDs
# flash randomly
#
# Author: Dogan Ibrahim
# File : XMAS.py
# Date : February, 2021
#----------------------------------------------------------
from machine import Pin
import utime
import random
#
# This function configures the port pins as outputs ("0") or
# as inputs ("I")
#
def Configure_Port():
for i in range(0, 8):
if DIR[i] == "0":
L[i] = Pin(PORT[i], Pin.OUT)
else:
L[i] = Pin(PORT[i], Pin.IN)
return
#
# This function sends 8-bit data (0 to 255) to the PORT
#
def Port_Output(x):
b = bin(x) # convert into binary
● 73
Raspberry Pi Pico Essentials
#
# Configure PORT to all outputs
#
Configure_Port()
#
# Main program loop. Count up in binary every second
#
while True:
numbr = random.randint(1, 255) # generate a random number
Port_Output(numbr) # send cnt to port
utime.sleep(0.25) # wait 250ms
Aim: The aim of this project is to show how a dice can be constructed with 7 LEDs.
Block diagram: The block diagram of the project is shown in Figure 3.40.
● 74
Chapter 3 • Raspberry Pi Pico Simple Hardware Projects
Figure 3.41 shows the LEDs that should be turned ON to display the 6 dice numbers.
Circuit diagram: The circuit diagram of the project is shown in Figure 3.42. Here, 8 GPIO
pins are collected together to form a PORT. There are 7 LEDs, but 8 port pins are used in
the form of a byte where the most-significant bit position is not used.
Table 3.1 gives the relationship between a dice number and the corresponding LEDs to be
turned ON to imitate the faces of a real dice. For example, to display number 1 (i.e. only
the middle LED is ON), we have to turn LED D3 ON. Similarly, to display number 4, we have
to turn ON D0, D2, D4 and D6.
1 D3
2 D1, D5
3 D1, D3, D5
● 75
Raspberry Pi Pico Essentials
The relationship between the required number and the data to be sent to the PORT to turn
on the correct LEDs, is given in Table 3.2. For example, to display dice number 2, we have
to send hexadecimal 0x22 to the PORT. Similarly, to display number 5, we have to send
hexadecimal 0x5D to the PORT and so on.
1 0x08
2 0x22
3 0x2A
4 0x55
5 0x5D
6 0x77
Program listing: The program is called DICE and the listing is shown in Figure 3.43. LED
port pins are declared as a list in variable PORT and they are configured as outputs by
using function Configure_Port. The bit pattern to be sent to the LEDs corresponding to
each dice number is stored in hexadecimal format in a list called DICE_NO (see Table 3.2).
GP15 is configured as an input pin and the pushbutton switch is connected to this pin
to simulate the "throwing" of a dice. The state of the pushbutton is checked in the main
program and when the button is pressed, function DICE is called to display a dice number
between 1 and 6 for 3 seconds. After this time, all the LEDs are turned OFF to indicate that
the program is ready to generate a new dice number. List DICE_NO is indexed to find the
LEDs that should be turned ON, and the required bit pattern is sent to the PORT to display
the dice number.
#---------------------------------------------------------
# DICE PROGRAM
# ============
#
# In this program 7 LEDs are connected to Pico to simlate
# a dice. When a pushbutton is pressed the LEDs display a
# dice number between 1 and 6
#
# Author: Dogan Ibrahim
# File : DICE.py
# Date : February, 2021
#----------------------------------------------------------
from machine import Pin
import utime
import random
● 76
Chapter 3 • Raspberry Pi Pico Simple Hardware Projects
#
# This function configures the LED ports as outputs
#
def Configure_Port():
for i in range(0, 8):
L[i] = Pin(PORT[i], Pin.OUT)
#
# This function sends 8-bit data (0 to 255) to the PORT
#
def Port_Output(x):
b = bin(x) # convert into binary
b = b.replace("0b", "") # remove leading "0b"
diff = 8 - len(b) # find the length
for i in range (0, diff):
b = "0" + b # insert leading os
#
# The program jumps here after the button is pressed
#
def DICE():
n = random.randint(1, 6) # generate a random number
pattern = DICE_NO[n] # find the pattern
Port_Output(pattern) # turn ON required LEDs
utime.sleep(3) # wait for 3 seconds
Port_Output(0) # turn OFF all LEDs
return
#
# Configure PORT to all outputs
#
Configure_Port()
#
# Main program loop, check if Button is pressed
#
● 77
Raspberry Pi Pico Essentials
while True:
if Button.value() == 0: # Button pressed?
DICE() # Call DICE
pass # Do nothing
Block diagram: Figure 3.44 shows the block diagram of the project.
Circuit diagram: The circuit diagram of the project is shown in Figure 3.45, where 7 LEDs
are connected to the Pico through current-limiting resistors. The button is connected to
GP15. Normally the output of the button is at logic 1 and goes to logic 0 when the button
is pressed.
Program listing: Figure 3.46 shows the program listing (Program: LuckyDay). At the
beginning of the program, all the 8 LED GPIO pins are combined into a single port and is
● 78
Chapter 3 • Raspberry Pi Pico Simple Hardware Projects
#---------------------------------------------------------
# LUCKY DAY OF THE WEEK
# =====================
#
# In this program 7 LEDs are connected to Pico where each
# LED represents a day of the week. Pressing a button
# turns ON one of the LEDs randomly and this corresponds to
# your lucky day of the week
#
# Author: Dogan Ibrahim
# File : LuckyDay.py
# Date : February, 2021
#----------------------------------------------------------
from machine import Pin
import utime
import random
#
# This function configures the LED ports as outputs
#
def Configure_Port():
for i in range(0, 8):
L[i] = Pin(PORT[i], Pin.OUT)
#
# This function sends 8-bit data (0 to 255) to the PORT
#
def Port_Output(x):
b = bin(x) # convert into binary
b = b.replace("0b", "") # remove leading "0b"
diff = 8 - len(b) # find the length
for i in range (0, diff):
b = "0" + b # insert leading os
● 79
Raspberry Pi Pico Essentials
if b[i] == "1":
L[i].value(1)
else:
L[i].value(0)
return
#
# Configure PORT to all outputs
#
Configure_Port()
#
# Main program loop, check if Button is pressed
#
print("Press the Button to display your lucky number...")
random.seed(utime.ticks_ms())
Aim: The aim of this project is to show how a mini reed switch module can be used togeth-
er with a 7-colour flashing LED module to create a silent door alarm.
Sensors used: Two sensor modules are used in this project: The KY-021 mini reed switch
module, and the KY-034 7-colour flashing LED module. Figure 3.47 shows a picture of the
KY-021 module. This is a 3-pin module with the connections GND, +V, and Signal. The
GND and +V pins are connected to the ground and power pins of the processor, respective-
ly. The Signal pin can be connected to any general-purpose input/output pin. An on-board
10 kohm resistor is connected between the +V and the S pins as shown in Figure 3.47.
● 80
Chapter 3 • Raspberry Pi Pico Simple Hardware Projects
Figure 3.48 shows a picture of the KY-034 7-colour LED module. This is a 3-pin module
where two GND pins are connected together. The other pin is the Signal pin. A 10 kohm
resistor is connected to on-board pin V but is not used here. The module generates 7-col-
ours when the Signal pin is connected.
● 81
Raspberry Pi Pico Essentials
The 7-colour LED module has a built-in chip that controls the LED so that it flashes and
cycles through 7 colours when power is applied to the LED. The operating voltage of the
module is +3.3 V to +5 V. The module has pink, yellow, and green high brightness lights.
The Flash module generates light of high brightness. By setting the LED ON and OFF with
different durations we can get interesting flashing effects.
Block Diagram: The block diagram of the project is shown in Figure 3.50.
Circuit Diagram: The circuit diagram of the project is shown in Figure 3.51 for the case
when the door is closed. Here, GP0 and GP1 of the Pico are connected to the KY-021 reed
switch and KY-034 7-colour LED, respectively. The reed switch output is pulled HIGH
through a pull-up resistor and because the magnet is near the reed switch when the door is
closed. As shown in Figure 3.52, this pin goes to logic HIGH when the door is opened (i.e.
when the reed switch contacts open). The LED module is connected to the Pico through a
470-ohm current limiting resistor.
● 82
Chapter 3 • Raspberry Pi Pico Simple Hardware Projects
Program Listing: The program listing (ReedDoor) is shown in Figure 3.53. At the begin-
ning of the program, the connections to KY-021 and KY-034 are defined, where GP0 and
GP1 are configured as input and output respectively. The remainder of the program runs in
an endless loop. Inside this loop, the state of the reed switch is checked and if it is at logic
HIGH then it is assumed that the reed switch contacts are open i.e. the door is opened. As
a result of this, the 7-color LED is activated to give visual indication that the door is opened.
#---------------------------------------------------------
# DOOR ALARM WITH 7-COLOUR FLASHING LED
# =====================================
#
# In this program a reed switch is connected as an input and
# a 7-colour flashing LED is connected as an output. The LED
# flashes when the door is opened
#
# Author: Dogan Ibrahim
# File : ReedDoor.py
# Date : February, 2021
#----------------------------------------------------------
from machine import Pin
LED.value(0)
while True:
door = ReedSwitch.value()
if door == 1:
LED.value(1)
else:
LED.value(0)
● 83
Raspberry Pi Pico Essentials
7-Segment LED Displays: Displaying data is one of the fundamental output activities of
any microcontroller system. For example, displays are used to show the sensor data such
as the temperature, humidity, pressure etc. There are several types of display devices that
can be used in microcontroller-based systems. LCDs and 7-segment displays are probably
two of the most used display devices. There are several types of LCDs, such as text-based
LCD, graphics LCDs, colour LCDs, touch screen LCDs, etc. Most 7-segment displays are
used to display numeric or alphanumeric values, and they can have one or more digits.
One-digit displays can only display numbers from 0 to 9. Two-digit displays can display
numbers from 0 to 99, three-digit displays numbers from 0 to 999, and so on. In this pro-
ject a two-digit 7-segment display is used.
As shown in Figure 3.54, a 7-segment LED display basically consists of 7 LEDs connected
such that numbers from 0 to 9 and some (basic) letters can be displayed. The display seg-
ments are identified by letters from a through g. Figure 3.55 shows the segment names of
a typical 7-segment display.
● 84
Chapter 3 • Raspberry Pi Pico Simple Hardware Projects
Figure 3.56 shows how numbers from 0 to 9 can be obtained by turning ON or OFF different
segments of the display.
In a common-anode configuration, the anode terminals of all the LEDs are connected to-
gether as shown in Figure 3.58. This common point is then normally connected to the
● 85
Raspberry Pi Pico Essentials
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 3.59 for a 2-digit multiplexed LED
display), the LED segments of all the digits are tied together and the common pins of each
digit is turned ON separately by the microcontroller. By displaying each digit for several
milliseconds, the brain cannot differentiate that the digits are not ON all the time. This
way we can multiplex any number of 7-segment displays together. For example, to display
number 57, we have to send 5 to the first digit and enable its common pin. After a few
milliseconds, number 7 is sent to the second digit and the common point of the second digit
is enabled. When this process is repeated continuously the user sees as if both displays are
ON continuously.
Some manufacturers provide multiplexed multi-digit displays in single packages. For exam-
ple, we can purchase 2-, 4-, or 8-digit multiplexed displays in a single package. The display
used in this project is the DC56-11EWA which is a red, 0.56-inch height, common-cath-
ode two-digit multiplexed display with 18 pins, where the pin configuration is shown in
Table 3.3. Basically, this display can be controlled from the microcontroller as follows:
● 86
Chapter 3 • Raspberry Pi Pico Simple Hardware Projects
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
Block Diagram: Figure 3.61 shows the block diagram of the project.
● 87
Raspberry Pi Pico Essentials
Circuit Diagram: The circuit diagram of the project is shown in Figure 3.62. In this project,
the following pins of the Raspberry Pi Pico are used to interface with the 7-segment LED
display:
a 0 1
b 1 2
c 2 4
d 3 5
e 4 6
f 5 7
g 6 9
E1 8 (via transistor) 11
E2 7 (via transistor) 10
7-segment display segments are driven from the port pins through 470-ohm current-lim-
iting resistors. Digit-enable pins E1 and E2 are driven from port pins GP8 and GP7 respec-
tively through two BC108 NPN transistors (any other NPN transistor can be used here),
used as switches. The collectors of these transistors drive the segment digits. The seg-
ments are enabled when the base of the corresponding transistor is set to logic 1. Notice
that the following pins of the display are connected together 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.
● 88
Chapter 3 • Raspberry Pi Pico Simple Hardware Projects
Program Listing: Before driving the display, we must know the relationship between the
numbers to be displayed and the corresponding segments to be turned ON. This is shown
below.
0 1,1,1,1,1,1,0
1 0,1,1,0,0,0,0
2 1,1,0,1,1,0,1
3 1,1,1,1,0,0,1
4 0,1,1,0,0,1,1
5 1,0,1,1,0,1,1
6 1,0,1,1,1,1,1
7 1,1,1,0,0,0,0
8 1,1,1,1,1,1,1
9 1,1,1,1,0,1,1
Figure 3.63 shows the program listing (program: SevenCount). At the beginning of the
program the connections between the LED segments and the GPIO pins are defined in list
variable LED_Segments. Also the connections between the LED digits and the GPIO pins
are defined in list variable LED_Digits. These GPIO pins are then configured as outputs
and are all cleared to 0. Variable count is initialized to zero at the beginning of the pro-
gram. Function Refresh is called periodically by the timer and this function refreshes the
display to display the value of variable count. The display digits are refreshed every 10 ms.
● 89
Raspberry Pi Pico Essentials
If the number to be displayed is less than 10 then a 0 is inserted in front of the number so
that the numbers 0 to 9 are displayed as 00 to 09. Variable count is incremented by one
every second.
#---------------------------------------------------------
# 2-DIGIT 7-SEGMENT COUNTER
# =========================
#
# In this program a 2-digit 7-segment display is connected
# to the Pico. The program counts up every second
#
# Author: Dogan Ibrahim
# File : SevenCount.py
# Date : February, 2021
#----------------------------------------------------------
from machine import Pin, Timer
import utime
tim = Timer()
LED_Segments = [6, 5 ,4, 3, 2, 1, 0]
LED_Digits = [8, 7]
L = [0]*7
D = [0, 0]
#
# LED bit pattern for all numbers 0-9
#
LED_Bits ={
‘0’:(1,1,1,1,1,1,0), # 0
‘1’:(0,1,1,0,0,0,0), # 1
‘2’:(1,1,0,1,1,0,1), # 2
‘3’:(1,1,1,1,0,0,1), # 3
‘4’:(0,1,1,0,0,1,1), # 4
‘5’:(1,0,1,1,0,1,1), # 5
‘6’:(1,0,1,1,1,1,1), # 6
‘7’:(1,1,1,0,0,0,0), # 7
‘8’:(1,1,1,1,1,1,1), # 8
‘9’:(1,1,1,1,0,1,1)} # 9
● 90
Chapter 3 • Raspberry Pi Pico Simple Hardware Projects
#
# Refresh the 7-segment display
#
def Refresh(timer): # Thread Refresh
global count
cnt = str(count) # into string
if len(cnt) < 2:
cnt = "0" + cnt # Make sure 2 digits
for dig in range(2): # Do for 2 digits
for loop in range(0,7):
L[loop].value(LED_Bits[cnt[dig]][loop])
D[dig].value(1)
utime.sleep(0.01)
D[dig].value(0)
#
# Configure PORT to all outputs
#
Configure_Port()
#
# Main program loop. Start the periodic timer and counting
#
tim.init(freq=50, mode=Timer.PERIODIC, callback=Refresh)
Modified program
In the program shown in Figure 3.63, numbers under 10 are displayed with a leading 0
(e.g. 05). We can remove the leading zero by blanking all the segments of the left-hand
digit if the number is less than 10. The number five, for example, is displayed as 5 and not
as 05. The modified program listing (program: SevenCount2) is shown in Figure 3.64.
Here, list LED_Bits is modified by adding a blank line where all the segment bits are set to
0. Additionally, a blank character is inserted to the front of string cnt if the number is less
than 10 so that the leading digit is blanked.
● 91
Raspberry Pi Pico Essentials
#---------------------------------------------------------
# 2-DIGIT 7-SEGMENT COUNTER
# =========================
#
# In this program a 2-digit 7-segment display is connected
# to the Pico. The program counts up every second.
# In this version of the program leading zero is omitted
#
# Author: Dogan Ibrahim
# File : SevenCount.py
# Date : February, 2021
#----------------------------------------------------------
from machine import Pin, Timer
import utime
tim = Timer()
LED_Segments = [6, 5 ,4, 3, 2, 1, 0]
LED_Digits = [8, 7]
L = [0]*7
D = [0, 0]
#
# LED bit pattern for all numbers 0-9
#
LED_Bits ={
‘ ‘:(0,0,0,0,0,0,0), # Blank
‘0’:(1,1,1,1,1,1,0), # 0
‘1’:(0,1,1,0,0,0,0), # 1
‘2’:(1,1,0,1,1,0,1), # 2
‘3’:(1,1,1,1,0,0,1), # 3
‘4’:(0,1,1,0,0,1,1), # 4
‘5’:(1,0,1,1,0,1,1), # 5
‘6’:(1,0,1,1,1,1,1), # 6
‘7’:(1,1,1,0,0,0,0), # 7
‘8’:(1,1,1,1,1,1,1), # 8
‘9’:(1,1,1,1,0,1,1)} # 9
● 92
Chapter 3 • Raspberry Pi Pico Simple Hardware Projects
#
# Refresh the 7-segment display
#
def Refresh(timer): # Thread Refresh
global count
cnt = str(count) # into string
if len(cnt) < 2:
cnt = " " + cnt # Make sure 2 digits
for dig in range(2): # Do for 2 digits
for loop in range(0,7):
L[loop].value(LED_Bits[cnt[dig]][loop])
D[dig].value(1)
utime.sleep(0.01)
D[dig].value(0)
#
# Configure PORT to all outputs
#
Configure_Port()
#
# Main program loop. Start the periodic timer and counting
#
tim.init(freq=50, mode=Timer.PERIODIC, callback=Refresh)
● 93
Raspberry Pi Pico Essentials
milliseconds, number '7' is sent to the second digit and the common point of the second
digit is enabled, and so on. When this process is repeated continuously, the user perceives
both displays as ON continuously.
The display used in this project is the DC56-11EWA, which is a red 0.56-inch height com-
mon-cathode two-digit multiplexed display having 18 pins, where the pin configuration is
shown in Table 3.3. Two such display modules are used to construct a 4-digit display. Each
module has its own E1 and E2 enable pins.
In a multiplexed display application, the segment pins of corresponding segments are con-
nected together. For example, pins 11 and 16 are connected as the common a segment.
Similarly, pins 15 and 10 are connected as the common b segment and so on.
Block Diagram: Figure 3.66 shows the block diagram of the project.
Circuit Diagram: The circuit diagram of the project is shown in Figure 3.67. In this project,
the following pins of the Raspberry Pi Pico are used to interface with the 7-segment LED
display:
● 94
Chapter 3 • Raspberry Pi Pico Simple Hardware Projects
a 0 1
b 1 2
c 2 4
d 3 5
e 4 6
f 5 7
g 6 9
E1 7 (via transistor) 10
E2 8 (via transistor) 1
E1 9 (via transistor) 12
E2 10 (via transistor) 14
The 7-segment display segments are driven from the port pins through 470-ohm current
limiting resistors. Digit-enable pins E1, E2 of the first module and E1, E2 of the second
module are driven from port pins GP7, GP8, GP9, and GP10 respectively through four
BC108 NPN transistors used as switches (any other NPN, small-signal transistor can be
used here). 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 that the fol-
lowing pins of the display are interconnected 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.
● 95
Raspberry Pi Pico Essentials
Program Listing: Figure 3.68 shows the program listing (Program: SevenCount4). At
the beginning of the program, the modules used in the program are imported. The program
is very similar to the one with 2 digits. Here, the list LED_Digits contains 4 numbers which
are the digit-enable pins of the four 7-segment LED modules. Function Refresh is very
similar to the function with 2 digits, except that here we had to make sure that the number
to be displayed (count) consists of 4 digits. If the number is less than 4 digits, spaces are
inserted in front of it to blank the display for these digit positions. Notice that 'digit count'
runs from 0 to 4 and not from 0 to 2 which was the case with the 2-digit display. The delay
between the digit-enables is reduced to 5 ms since we have 4 digits, and quicker refreshing
is required. Variable count starts from 0 at the beginning of the program by default. It is
incremented by 1 every second. When the count reaches 10000 it is reset back to 0.
#---------------------------------------------------------
# 4-DIGIT 7-SEGMENT SECONDS COUNTER
# =================================
#
# In this program a 4-digit 7-segment display is connected
# to the Pico. The program counts up every second.
# In this version of the program leading zero is omitted
#
# Author: Dogan Ibrahim
# File : SevenCount4.py
# Date : February, 2021
#----------------------------------------------------------
from machine import Pin, Timer
import utime
tim = Timer()
LED_Segments = [6, 5 ,4, 3, 2, 1, 0]
LED_Digits = [7, 8, 9, 10]
L = [0]*7
D = [0, 0, 0, 0]
#
# LED bit pattern for all numbers 0-9
#
LED_Bits ={
‘ ‘:(0,0,0,0,0,0,0), # Blank
‘0’:(1,1,1,1,1,1,0), # 0
‘1’:(0,1,1,0,0,0,0), # 1
‘2’:(1,1,0,1,1,0,1), # 2
‘3’:(1,1,1,1,0,0,1), # 3
‘4’:(0,1,1,0,0,1,1), # 4
‘5’:(1,0,1,1,0,1,1), # 5
‘6’:(1,0,1,1,1,1,1), # 6
‘7’:(1,1,1,0,0,0,0), # 7
● 96
Chapter 3 • Raspberry Pi Pico Simple Hardware Projects
‘8’:(1,1,1,1,1,1,1), # 8
‘9’:(1,1,1,1,0,1,1)} # 9
#
# This function configures the LED ports as outputs
#
def Configure_Port():
for i in range(0, 7):
L[i] = Pin(LED_Segments[i], Pin.OUT)
#
# Refresh the 7-segment display
#
def Refresh(timer): # Thread Refresh
global count
cnt = str(count) # into string
if len(cnt) == 3: # 3 digits?
cnt = " " + cnt # Make sure 4 digits
elif len(cnt) == 2: # 2 digits?
cnt = " " + cnt # MAke sure 4 digits
elif len(cnt) == 1: # 1 digit?
cnt = " " + cnt # MAke sure 4 digits
for dig in range(4): # Do for 4 digits
for loop in range(0,7):
L[loop].value(LED_Bits[cnt[dig]][loop])
D[dig].value(1)
utime.sleep(0.005)
D[dig].value(0)
#
# Configure PORT to all outputs
#
Configure_Port()
#
# Main program loop. Start the periodic timer and counting
#
tim.init(freq=50, mode=Timer.PERIODIC, callback=Refresh)
● 97
Raspberry Pi Pico Essentials
3.18 LCDs
In microcontroller-based systems we usually want to interact with the system — for exam-
ple, to enter a parameter, to change the value of a parameter, or to display the output of
a measured variable. Data is usually entered to a system using a switch, a small keypad,
or a full-blown keyboard. Data is usually displayed using an indicator such as one or more
LEDs, 7-segment displays, or LC (liquid-crystal) type displays. LCDs have the advantages
that they can display alphanumeric as well as graphical data. Some LCDs have 40 or more
character lengths with the capability to display data on several lines. Some other LCDs can
be used to display graphical images (graphical LCDs, or simply GLCDs), such as animation.
Some displays are available in single- or multi-colour, while others incorporate backlighting
so that they can be viewed in dimly lit conditions.
LCDs can be connected to a microcontroller either in parallel form or through the I2C inter-
face. Parallel LCDs (e.g. the Hitachi HD44780) are connected using more than one data line
and several control lines, and the data gets transferred in parallel form. 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 it is slower since the data is transferred in two stages. I2C based LCDs on the
other hand are connected to a microcontroller using only 2 wires, carrying 'data' and 'clock'.
I2C-based LCDs are in general much easier to use and require less wiring, but they cost
more than the parallel ones. In this Chapter we will be learning to use both parallel and I2C
based LCDs in projects.
The programming of LCDs is a complex task and requires a good understanding of the in-
ternal operations of the LCD controllers, including knowledge of their exact timing require-
ments. Fortunately, there are several libraries that can be used to simplify the use of both
parallel and serial LCDs.
● 98
Chapter 3 • Raspberry Pi Pico Simple Hardware Projects
1 VSS Ground
2 VDD + ve Supply
3 VEE Contrast
4 RS Register Select
5 R/W Read/Write
6 E Enable
7 D0 Data bit 0
8 D1 Data bit 1
9 D2 Data bit 2
10 D3 Data bit 3
11 D4 Data bit 4
12 D5 Data bit 5
13 D6 Data bit 6
14 D7 Data bit 7
VSS (pin 1) and VDD (pin 2) are the Ground and Power Supply pins. The supply voltage
should be +5 V.
VEE is pin 3 and this is the contrast control pin used to adjust the contrast of the display.
The arm of a 10-kohm 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 in order to write commands or
character data to the LCD module. When this pin is HIGH, character data or status infor-
mation can be read from the module. This pin is normally connected permanently LOW so
that commands or character data can be sent to the LCD module.
● 99
Raspberry Pi Pico Essentials
Enable (E) is pin 6 which is used to initiate the transfer of commands or data between the
LCD module and the 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 the 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 less I/O lines are required to communicate with the LCD. The 4-bit
mode is slower, however, since the data is transferred in two stages. In this book we shall
be using the 4-bit interface only.
Pins 15 and 16 are for background brightness control. To enable the background bright-
ness, a 220-ohm resistor should be connected from pin 15 to +5 V supply, and 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 connect-
ed to ground. This mode uses 6 GPIO port pins of the microcontroller:
In the next section we will be creating an LCD library of functions that can be used to send
data and text to standard HD44780 type character LCDs.
Aim: The aim of this project is to develop a library of functions that can be used to control
LCDs. These functions can be used in projects to send text and numbers to LCDs.
Block diagram: Figure 3.70 shows the block diagram of the project.
Circuit diagram: The circuit diagram of the project is shown in Figure 3.71. The LCD is
connected to the Pico using 4 data wires (D4 – D7) and 2 control wires (E and R/S). The
connections between the LCD and Pico are as follows:
● 100
Chapter 3 • Raspberry Pi Pico Simple Hardware Projects
R/S GP0
E GP1
D4 GP2
D5 GP3
D6 GP4
D7 GP5
Program listing: Figure 3.72 shows the functions listing (Program: LCD). The connections
between the LCD and the Pico are defined at the beginning and these can be changed if
desired. The remainder of the functions should not be changed for proper control of the
LCD. These functions implement the initialization and control of the LCD.
lcd_init: this is the LCD initialization function and must be called first before any
other functions are called;
lcd_clear: clears the LCD;
lcd_home: homes the cursor (top left position);
lcd_cursor_blink: enables blinking cursor;
lcd_cursor_on: enables visible cursor;
lcd_cursor_off: disables visible cursor;
lcd_puts(s): displays string s;
lcd_putch(c): displays character c;
lcd_goto(col,row): positions the cursor at the specified column and position. (0,
0) is the left corner of the LCD. First row is row 0, second row is row 1 and so on.
● 101
Raspberry Pi Pico Essentials
#--------------------------------------------------
# PARALLEL LCD FUNCTIONS
# ======================
#
# These functions initialize and control the LCD
#
# Author: Dogan Ibrahim
# File : LCD
# Date : February 2021
#--------------------------------------------------
from machine import Pin
import utime
EN = Pin(0, Pin.OUT)
RS = Pin(1, Pin.OUT)
D4 = Pin(2, Pin.OUT)
D5 = Pin(3, Pin.OUT)
D6 = Pin(4, Pin.OUT)
D7 = Pin(5, Pin.OUT)
PORT = [2, 3, 4, 5]
L = [0,0,0,0]
def Configure():
for i in range(4):
L[i] = Pin(PORT[i], Pin.OUT)
def lcd_strobe():
EN.value(1)
utime.sleep_ms(1)
EN.value(0)
utime.sleep_ms(1)
if mode == 0:
● 102
Chapter 3 • Raspberry Pi Pico Simple Hardware Projects
d = c
else:
d = ord(c)
for i in range(4):
b = d & 1
L[i].value(b)
d = d >> 1
RS.value(mode)
lcd_strobe()
utime.sleep_ms(1)
RS.value(1)
def lcd_clear():
lcd_write(0x01, 0)
utime.sleep_ms(5)
def lcd_home():
lcd_write(0x02, 0)
utime.sleep_ms(5)
def lcd_cursor_blink():
lcd_write(0x0D, 0)
utime.sleep_ms(1)
def lcd_cursor_on():
lcd_write(0x0E, 0)
utime.sleep_ms(1)
def lcd_cursor_off():
lcd_write(0x0C, 0)
utime.sleep_ms(1)
def lcd_puts(s):
l = len(s)
for i in range(l):
lcd_putch(s[i])
def lcd_putch(c):
lcd_write(c, 1)
● 103
Raspberry Pi Pico Essentials
address = address + c - 1
lcd_write(0x80 | address, 0)
def lcd_init():
Configure()
utime.sleep_ms(120)
for i in range(4):
L[i].value(0)
utime.sleep_ms(50)
L[0].value(1)
L[1].value(1)
lcd_strobe()
utime.sleep_ms(10)
lcd_strobe()
utime.sleep_ms(10)
lcd_strobe()
utime.sleep_ms(10)
L[0].value(0)
lcd_strobe()
utime.sleep_ms(5)
lcd_write(0x28, 0)
utime.sleep_ms(1)
lcd_write(0x08, 0)
utime.sleep_ms(1)
lcd_write(0x01, 0)
utime.sleep_ms(10)
lcd_write(0x06, 0)
utime.sleep_ms(5)
lcd_write(0x0C, 0)
utime.sleep_ms(10)
#================= END OF LCD FUNCTIONS =======================
Displaying text
The following statement displays text Hello from PICO (these statements must follow the
LCD functions given in Figure 3.72).
lcd_init()
lcd_puts('Hello from PICO')
Aim: The aim of this project is to show how numeric data can be displayed on the LCD.
● 104
Chapter 3 • Raspberry Pi Pico Simple Hardware Projects
The block diagram and circuit diagram of the project are as in Figure 3.70 and Figure 3.71.
Program listing: The program is named LCDCount. The following statements must follow
the LCD functions given in Figure 3.72.
lcd_init()
count = 0
while True:
lcd_goto(0, 0)
cntstr = str(count)
lcd_puts(cntstr)
count = count + 1
utime.sleep(1)
We can now import library LCD into our LCD based programs. For example, the program
given in this project can be written as shown in Figure 3.73 (Program: LCDCount2). Notice
that all the LCD functions must be preceded with word LCD.
#--------------------------------------------------------
# LCD SECONDS COUNTER
# ===================
#
# This program counts up every secon and displays on LCD
#
# Author: Dogan Ibrahim
# File : LCDCount2.py
# Date : February 2021
#----------------------------------------------------------
import LCD
import utime
LCD.lcd_init()
count = 0
while True:
LCD.lcd_goto(0, 0)
cntstr = str(count)
● 105
Raspberry Pi Pico Essentials
LCD.lcd_puts(cntstr)
count = count + 1
utime.sleep(1)
Block diagram: Figure 3.74 shows the block diagram of the project.
Circuit diagram: The circuit diagram of the project is shown in Figure 3.75. The LCD is
connected as in the previous project. The LED and the pushbutton are connected to GP16
and GP17 respectively. An internal pull-up resistor is used at pin GP17, obviating the use
of an external resistor.
● 106
Chapter 3 • Raspberry Pi Pico Simple Hardware Projects
Program listing: Figure 3.76 shows the program listing (Program: Reaction). At the
beginning of the program the LCD module, machine, utime, and the random module are
all imported to the program. Button and LED are assigned to port pins GP17 and GP16
respectively. GP17 is pulled-up internally so that the state of this pin is logic 1 by default,
and goes to logic 0 when the pushbutton is pressed. LCD library is then initialized by calling
function lcd_init.
At the beginning of the main program the LED is turned OFF, and the program enters a
while loop. Inside this loop the LCD is cleared, and a random number is generated between
3 and 10. This value is used to delay turning the LED ON so that the user does not know
when the LED is going to be lit. At this point the LED is turned ON, a timer is started, and
the button interrupt is enabled. The interrupt is configured to be activated on the falling
edge of the pushbutton output (i.e. when the pushbutton is pressed). The main program
then waits until the interrupt is serviced (i.e. while the flag is 0).
The program jumps to function MyButton as soon as the pushbutton is pressed. At the be-
ginning of this program further interrupts are disabled by setting handler = None. Inside
this function, the LED is turned OFF and the timer is stopped. The elapsed time is calculated
by subtracting the current time from the time when the LED was turned ON. This time is
converted into string and stored in variable ReactionStr and is displayed in the second
row of the LCD in milliseconds. The text Reaction Time: is displayed at the first row of the
LCD. As an example, if the reaction time is 500 ms, it is displayed in the following format:
Reaction Time:
500
Variable flag is then set to 1 so that the main program continues. At the same time the LCD
is cleared. The game restarts as soon as the LCD is cleared.
#--------------------------------------------------------
# REACTION TIMER
# ==============
#
# This is a reaction timer program which measures the
# reaction of the user and displays on the LCD in ms.
# For a fast reaction time, the user should press the
# pushbutton as soon as the LED is lit
#
# Author: Dogan Ibrahim
# File : Reaction.py
# Date : February 2021
#----------------------------------------------------------
import LCD
from machine import Pin
import utime
import random
● 107
Raspberry Pi Pico Essentials
#
# This is the interrupt service routine. The progra jumps
# here as soon as the pushbutton is pressed
#
def MyButton(pin):
global flag
Button.irq(handler = None)
LED.value(0)
TmrEnd = utime.ticks_ms()
ReactionTime = utime.ticks_diff(TmrEnd, TmrStart)
ReactionStr = str(ReactionTime)
flag = 1
LCD.lcd_puts("Reaction Time:")
LCD.lcd_goto(0, 1)
LCD.lcd_puts(ReactionStr)
utime.sleep(3)
#
# Start of MAIN program
#
LED.value(0)
while True:
flag = 0
LCD.lcd_clear()
rnd = random.randint(3, 10)
utime.sleep(rnd)
LED.value(1)
TmrStart = utime.ticks_ms()
Button.irq(handler=MyButton, trigger = Pin.IRQ_FALLING)
while flag == 0:
pass
Aim: The aim of this project is to show how the ultrasonic sensor module can be used in a
project to measure distance.
● 108
Chapter 3 • Raspberry Pi Pico Simple Hardware Projects
Ultrasonic sensors
In this project the popular HC-SR04 ultrasonic transmitter-receiver module is used (Fig-
ure 3.77). The basic features of this sensor module are:
• Operating voltage: 5V
• Operating current: 2 mA
• Detection distance: 2 – 450 cm
• Input trigger signal: 10 µs TTL
• Sensor angle: 15 degrees or less
The basic principle of operation of the HC-SR04 ultrasonic sensor module is as follows (see
Figure 3.78):
the duration of the echo signal is calculated, and this is proportional to the distance to the
target.
The distance to the object is calculated as follows.
● 109
Raspberry Pi Pico Essentials
The speed of sound is 343 m/s, or 0.0343 cm/µs at 20 ºC air temperature.
Therefore,
For example, if the duration of the echo signal is 294 microseconds then the distance to the
object is calculated as follows:
Block Diagram: Figure 3.79 shows the block diagram of the project.
Circuit Diagram: Figure 3.80 shows the project circuit diagram. Notice that the sensor op-
erates at +5 V and its output is not compatible with the Raspberry Pi Pico input. A resistive
potential divider circuit is used to lower the sensor voltage to +3.3 V.
● 110
Chapter 3 • Raspberry Pi Pico Simple Hardware Projects
Program listing: Figure 3.81 shows the program listing (Program: Ultrasonic). At the
beginning of the program, trig and the echo pins are configured. Inside the main program
loop, a trigger pulse is sent for 10 microseconds and the program waits to receive the echo
signal. After receiving the echo signal its duration is calculated and stored in the variable
named Duration. Assuming that the speed of sound in air is 343 m/s (at air temperature
20 ºC), the distance to the object is calculated and stored in variable distancecm. This
value is then displayed on the LCD as shown in Figure 3.81.
#----------------------------------------------------------
# ULTRASONIC DISTANCE MESUREMENT
# ==============================
#
# In this project a HC-SR04 type ultrasonic sensor module is
# connected to the Raspberry Pi Pico. The program displays
# distance to an object in-front of the sensor
#
# Author: Dogan Ibrahim
# File : Ultrasonic.py
# Date : February 2021
#------------------------------------------------------------
from machine import Pin
import utime
import LCD
● 111
Raspberry Pi Pico Essentials
while True:
trig.value(0)
utime.sleep_us(5) # Wait until settled
Aim: The aim of this project is to show how the ultrasonic sensor module can be used to
make a stadiometer
Block diagram: Figure 3.83 shows the block diagram of the project. The person whose
height is to be measured stands below the stadiometer.
● 112
Chapter 3 • Raspberry Pi Pico Simple Hardware Projects
Circuit diagram: The circuit diagram of the project is identical to the one in Figure 3.80.
Program listing: Figure 3.84 shows the program listing (Program: Stadiometer). At the
beginning of the program the height of the stadiometer is specified (H = 200 cm). The
program then calculates the distance between the sensor and the top of the head of the
person (h) The height of the person is given by H – h.
#----------------------------------------------------------
# PERSON HEIGHT MEASUREMENT (STADIOMETER)
# =======================================
#
# In this project a HC-SR04 type ultrasonic sensor module is
# connected to the Raspberry Pi Pico. The program measures the
# height of a person
#
# Author: Dogan Ibrahim
# File : Stadiometer.py
# Date : February 2021
#------------------------------------------------------------
from machine import Pin
import utime
import LCD
while True:
trig.value(0)
● 113
Raspberry Pi Pico Essentials
Aim: The aim of this project is to show how the ultrasonic sensor module can be used to
help reverse-park our car.
Block Diagram: Figure 3.85 shows the block diagram of the project.
Circuit diagram: The circuit diagram of the project is shown in Figure 3.86. The circuit is
basically same as Figure 3.80, but there is no LCD. Also an active buzzer is added to port
pin GP18 of the Raspberry Pi Pico.
● 114
Chapter 3 • Raspberry Pi Pico Simple Hardware Projects
Program listing: Figure 3.87 shows the program listing (Program: Parking). After finding
the distance to the obstacle, the program creates a delay value depending on the distance
of the obstacle. As the car gets closer to the obstacle, this delay value is made smaller,
causing the buzzer to sound faster (more frequently) to alert the driver that the car is get-
ting close to the obstacle. If on the other hand the car gets further away from the obstacle,
the delay is made larger so that the buzzer sounds slower (less frequently) to inform the
driver that the obstacle is not very close.
#----------------------------------------------------------
# ULTRASONIC REVERSE CAR PARKING AID
# ==================================
#
# In this project a HC-SR04 type ultrasonic sensor module is
# connected to the Raspberry Pi Pico. Additionally, a buzzer
# is connected. The project sounds the buzzer as the car gets
# near an obstacle.The buzzer sounds faster as the car gets
# nearer an object
#
# Author: Dogan Ibrahim
# File : Parking.py
# Date : February 2021
#------------------------------------------------------------
from machine import Pin
import utime
● 115
Raspberry Pi Pico Essentials
while True:
trig.value(0)
utime.sleep_us(5) # Wait until settled
#
# Now sound the buzzer accordingly.The sounding should be faster
# as the car gets neareer the object.This is done by changing the
# delay in the duration of the sound
#
● 116
Chapter 4 • Using Analogue-To-Digital Converters (ADCs)
4.1 Overview
Most sensors in real life are analogue, supplying analogue output voltages or currents
which are proportional to the measured variable. Without using ADCs, such sensors cannot
be directly connected to digital computers. In this Chapter we will learn how to use the ADC
channels of the Raspberry Pi Pico.
Most ADCs for general purpose applications are 8-bits or 10-bits wide, although some
higher-grade professional ones are 16 or even 32-bit wide. The conversion time of an ADC
is one of its important specifications. This is the time taken for the ADC to convert an an-
alogue input into digital. The smaller the conversion time, the better. Some cheaper ADCs
give the converted digital data in serial format, while some more expensive, professional
ones provide parallel digital outputs.
The Raspberry Pi Pico has 5 ADC channels. Four of them are at pins GP26, GP27, GP28, and
GP29 — known as analogue channels 0, 1, 2, and 3. The first 3 channels are available at the
GPIO pins, and the 4th one can be used to measure the VSYS voltage of the board. There is
also a built-in ADC channel 4 which is connected internally to a temperature sensor.
The Pico's ADC has a resolution of 12 bits, thus converting an analogue input voltage into
4096 (0 to 4095) levels. MicroPython however transforms the output into a 16-bits number,
ranging from 0 to 65535.
The reference voltage of the ADC used on the Pico is +3.3 V. Using such an ADC, the reso-
lution is 3300 mV / 65535 = 0.050 mV per bit, or 50 μV/bit. Therefore, an analogue input
voltage of 0.050 mV gives digital output of 00000000 0000001, 0.1mV gives 00000000
00000010, and so on.
In this Chapter we will develop several projects using the ADC offered by the Pico.
Aim: The aim of this project is to show how the Pico ADC channels can be used to read
analogue input voltage.
Circuit diagram: Figure 4.1 shows the circuit diagram of the project. In this project, the
voltage to be measured is applied to analogue input GP26 (pin 31, channel 0). You must
make sure that the input voltage does not exceed +3.3 V. If it is required to measure higher
voltages, then you can use resistive potential divider circuits at the input of the ADC.
● 117
Raspberry Pi Pico Essentials
Program listing: Figure 4.2 shows the program listing and sample output from the pro-
gram (Program: Voltmeter). At the beginning of the program module ADC of 'machine' is
imported to the program and variable AnalogIn is assigned to analogue input channel 0.
The conversion factor is then defined as 3300 / 65535. The value read from the analogue
channel must be multiplied by this number in order to calculate the actual value of the
measured voltage. The remainder of the program runs in a loop where the input voltage is
read, converted to millivolts, and then displayed on the PC screen.
● 118
Chapter 4 • Using Analogue-To-Digital Converters (ADCs)
#--------------------------------------------------------
# VOLTMETER
# =========
#
# This is a voltmeter project. The voltage to me measured
# is applied to GP26 (pin 31) of the Pico
# This version of the program displays the measured voltage
# on the LCD
#
# Author: Dogan Ibrahim
# File : VoltLCD.py
# Date : February 2021
#----------------------------------------------------------
from machine import ADC
import utime
import LCD
Aim: The aim of this project is to show how the internal temperature sensor can be used
to measure the temperature.
Circuit diagram: The circuit diagram of the project is same as in Figure 3.71.
Program listing: The internal temperature sensor is connected to ADC channel 4. The
data read is converted into degrees Celsius using the following formula:
● 119
Raspberry Pi Pico Essentials
The program listing is shown in Figure 4.4 (Program: TempInt). The program reads the
data from ADC channel 4, converts it into volts, and then applies the above formula to con-
vert into degrees Celsius. The calculated value is then displayed on the LCD. The program
repeats every second. You can check that the temperature will increase if you touch the
processor with the tip of your finger.
#--------------------------------------------------------
# TEMPERATURE MEASUREMENT
# =======================
#
# This program measures the temperature using the internal
# temperature sensor of the Pico and displyas on LCD
#
# Author: Dogan Ibrahim
# File : TempInt.py
# Date : February 2021
#----------------------------------------------------------
from machine import ADC
import utime
import LCD
Aim: The aim of this project is to show how an external analogue temperature can be used
to measure the external temperature.
Block Diagram: Figure 4.5 shows the block diagram of the project.
● 120
Chapter 4 • Using Analogue-To-Digital Converters (ADCs)
Circuit diagram: The circuit diagram of the project is shown in Figure 4.6. In this pro-
ject a TMP36 type temperature sensor chip is used (Figure 4.7) and it's connected to ADC
channel 0. This chip provides analogue output voltage proportional to the measured tem-
perature. The relationship between the measured temperature and the output voltage is
given by:
T = (Vo – 500) / 10
Where T is the measured temperature in degrees Celsius, and Vo is the sensor output volt-
age in millivolts.
● 121
Raspberry Pi Pico Essentials
Program listing: Figure 4.8 shows the program listing (Program: TMP36). The sensor
voltage is read in on ADC channel 0. This voltage is then converted into millivolts, the
temperature is calculated in degrees Celsius, and gets displayed on the LCD every second.
Notice that the output data is formatted so that only the first 5 digits of string Temp are
displayed. As an example, the temperature is displayed in the following format:
nn.mm
#--------------------------------------------------------
# TEMPERATURE MEASUREMENT
# =======================
#
# This program measures the temperature using an external
# TMP36 type temperature sensor chip
#
# Author: Dogan Ibrahim
# File : TMP36.py
# Date : February 2021
#----------------------------------------------------------
from machine import ADC
import utime
import LCD
● 122
Chapter 4 • Using Analogue-To-Digital Converters (ADCs)
In this project, an ON/OFF type simple control system is designed. ON/OFF temperature
control systems commonly use relays to turn the heater ON or OFF depending on the set-
point temperature and the measured temperature. If the measured temperature is below
the set-point value, then the relay is activated which turns the heater ON. If on the other
hand the measured temperature is above the set-point value, then the relay is de-activated
to turn OFF the heater so that the temperature is lowered.
The project employs a type TMP36 sensor chip in conjunction with a heater and an LED, to
control the temperature of a small room. The heater is turned ON by the relay if the meas-
ured room temperature (RoomTemp) is below the setpoint temperature (SetTemp), and
it is turned OFF if it is above the setpoint value. The LED turns ON if the room temperature
is below the set point value to indicate that the heater is ON. This process is repeated every
3 seconds.
The aim: The aim of this project is to show how an ON/OFF temperature controller system
can be designed using a low-cost temperature sensor chip with the Raspberry Pi Pico.
Block diagram: Figure 4.9 shows the block diagram of the project.
Circuit diagram: The circuit diagram of the project is shown in Figure 4.10. TMP36 sensor
chip is connected to analogue channel 0 as in the previous project. The LED is connected
to GP16 through a 470-ohm current-limiting resistor. The Relay is connected to GP17 and
is activated when a logic 1 (+3.3V) is applied to it. The connections between the Raspberry
Pi Pico ports and various components are as follows:
GP16 LED
GP17 Relay
● 123
Raspberry Pi Pico Essentials
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
ENDIF
Wait 3 seconds
ENDDO
END
Program listing: Figure 4.12 shows the program listing (Program: ONOFF). The desired
temperature is set to 24 ºC and is stored in variable SetTemp. The LED and Relay are
assigned to GP16 and GP17 respectively, which are configured as outputs and are turned
OFF at the beginning of the program.
Inside the program loop, the room temperature (RoomTemp) is read and compared with
the desired temperature (SetTemp). If the room temperature is below the desired value
then both the heater and the LED are turned ON, otherwise they are both turned OFF. This
process is repeated after 3 seconds of delay.
● 124
Chapter 4 • Using Analogue-To-Digital Converters (ADCs)
#----------------------------------------------------------
# ON-OFF TEMPERATURE CONTROLLER
# =============================
#
# This is an ON-OFF temperature controller program. The
# project consists of a temperature sensor, an LED and a
# heater. The heater and the LED are turned ON if the room
# temperature (RoomTemp) is below the desired value (SetTemp)
#
# Author: Dogan Ibrahim
# File : ONOFF.py
# Date : February 2021
#------------------------------------------------------------
from machine import ADC, Pin
import utime
Block diagram: Figure 4.13 shows the block diagram of the project.
● 125
Raspberry Pi Pico Essentials
Circuit diagram: The circuit diagram of the project is shown in Figure 4.14. The LCD is
connected to the Pico as in the previous LCD based projects. The TMP36, LED, and the Re-
lay are connected as in the previous project.
Program listing: Figure 4.15 shows the program listing (Program: ONOFFLCD). The
program is very similar to the one given in Figure 4.12. Here, additionally the desired tem-
perature and the room temperature are displayed in the following format, where the room
temperature is updated continuously at every 3 seconds:
● 126
Chapter 4 • Using Analogue-To-Digital Converters (ADCs)
#----------------------------------------------------------
# ON-OFF TEMPERATURE CONTROLLER
# =============================
#
# This is an ON-OFF temperature controller program. The
# project consists of a temperature sensor, an LED and a
# heater. The heater and the LED are turned ON if the room
# temp (RoomTemp) is below the desired value (SetTemp)
#
# An LCD is used to display the desired temperature at the
# top row, and room temperature at bottom row
#
# Author: Dogan Ibrahim
# File : ONOFFLCD.py
# Date : February 2021
#------------------------------------------------------------
from machine import ADC, Pin
import utime
import LCD
● 127
Raspberry Pi Pico Essentials
Block diagram: Figure 4.16 shows the block diagram of the project.
● 128
Chapter 4 • Using Analogue-To-Digital Converters (ADCs)
Circuit diagram: The circuit diagram of the project is shown in Figure 4.19. A 10-kohm
fixed resistor is used in the resistive potential divider circuit. The voltage across this resistor
is measured using channel 0 of the ADC.
Program listing: Figure 4.20 shows the program listing (Program: LDR) together with
output data. The program reads the analogue voltage across the fixed resistor. Notice that
there is no need to know the absolute voltage. We can just use the digital value of the
voltage (0 to 65535) read (r in this program). This value should be calibrated to give the
intensity of the light in Lux.
● 129
Raspberry Pi Pico Essentials
Calibration
A light-intensity meter is required to calibrate the readings. Measurements should be made
at different light levels and a table should be created to list the lux readings of the meter
and the corresponding output from the ADC. Then, a formula can be derived that describes
the relationship between the light level and the ADC readings. Alternatively, this table can
be indexed for a given ADC reading in order to find the corresponding light level. Interpo-
lation can be applied for values between two readings.
Circuit diagram: The circuit diagram of the project is shown in Figure 4.21. A fixed resistor
(10 kohm) is used in series with the unknown resistor. The program measures the voltage
across the fixed resistor and then calculates the value of the unknown resistor (Rx).
● 130
Chapter 4 • Using Analogue-To-Digital Converters (ADCs)
Program listing: Figure 4.22 shows the program listing (Program: Ohmmeter). If RF is
the fixed resistance and Rx is the unknown resistance, assuming the circuit is supplied from
+3.3 V (3300 mV), the voltage at the output of the fixed resistor will be:
Where V is in millivolts, and RF and Rx are in kilo-ohms. As Rx changes from, say, 1 kΩ to
1 MΩ, the voltage across the fixed resistor will change from:
V = 33000 / 11 = 3000 mV
into
We can easily measure these voltages with the ADC. Therefore, the resistance measure-
ment range of our ohmmeter is well below 1 kΩ and above 1 MΩ.
Rx = 3300 × RF / V – RF
Remembering that the ADC resolution is 65535 steps and RF = 10 kΩ, we can write:
Rx = 655350 / Vm – RF
● 131
Raspberry Pi Pico Essentials
The voltage across the fixed resistor is read 5 times, and the value is averaged for higher
accuracy.
#--------------------------------------------------------------
# OHMMETER
# ========
#
# In this project the value of an unknown resistor is measured
#
# Author: Dogan Ibrahim
# File : Ohmmeter.py
# Date : February 2021
#-------------------------------------------------------------
from machine import ADC
import utime
RF = 10 # RF = 10K
LDRin = ADC(0) # ADC channel 0
● 132
Chapter 4 • Using Analogue-To-Digital Converters (ADCs)
Block diagram: Figure 4.24 shows the block diagram of the project.
Circuit diagram: The circuit diagram of the project is shown in Figure 4.25. Two TMP36
type temperature sensor chips are used, one connected to channel 0 (external sensor) and
the other one connected to channel 1 (internal sensor) of the ADC. The LCD is connected
to the Pico as in the previous LCD-based projects.
Program listing: Figure 4.26 shows the program listing (Program: MultiTmp). The ex-
ternal temperature sensor is named ExtTemp and gets assigned to channel 0. The internal
● 133
Raspberry Pi Pico Essentials
temperature is named IntTemp and assigned to channel 1 of the ADC. Inside the pro-
gram loop, the temperature of each channel is read, converted into degrees Celsius, and
displayed on the LCD in the following format (top row displays the external temperature,
bottom row displays the internal temperature):
#------------------------------------------------------------
# EXTERNAL AND INTERNAL TEMPERATURE MEASUREMENT
# =============================================
#
# This program measures the external and internal temperatures
# using two TMP36 type temperature sensor chips. Both external
# and internal temperatures are displayed on the LCD
#
# Author: Dogan Ibrahim
# File : MultiTmp.py
# Date : February 2011
#-------------------------------------------------------------
from machine import ADC
import utime
import LCD
● 134
Chapter 4 • Using Analogue-To-Digital Converters (ADCs)
Aim: The aim of this project is to show how the temperature of an NTC thermistor temper-
ature sensor can be read, as well as learn to use an LCD in a project.
Background information: In this project, the type KY-013 analogue output NTC thermis-
tor temperature sensor module is used. NTC thermistors are semiconductor devices whose
resistances are inversely proportional to the temperature. Thus, as the temperature rises,
their resistance falls and vice versa. As shown in Figure 4.27, this is a 3-pin module with
the following pin assignment:
GND
+V
S (analogue output)
The sensor module is internally connected to a 10-kohm resistor as shown in the Figure to
form a potential divider circuit. The voltage across the thermistor is read using an analogue
port of the processor. This voltage is proportional to the temperature where the temper-
ature is calculated using the well-known Steinhart-Hart equation. Different thermistors
have different Steinhart-Hart coefficients, and it is required to know these coefficients in
order to calculate the temperature of the thermistor used. For the KY-013, these coefficients
are specified by the manufacturer as follows (your coefficients may be slightly different!):
c1 = 0.001129148
c2 = 0.000234125
c3 = 0. 0000000876741
Assuming the resistor is series with the thermistor, R1 = 10 kΩ (i.e. R1 = 10000 ohms),
and a 16-bit ADC is used (0 to 65535 quantization levels) to read the thermistor voltage,
the temperature is calculated as follows (see Figure 4.27).
First, calculate the resistance of the thermistor. From the potential divider circuit, the out-
put voltage Vo is given by:
● 135
Raspberry Pi Pico Essentials
R2 = Vo × R1 / (V – Vo) (2)
With a 16-bit ADC, if Raw is the raw value read by the ADC then the actual physical voltage
read, Vo, is given by:
or,
T = log(R2) (7)
We will be using the above equations to calculate the temperature. Notice that the above
calculations are only for a 10-kΩ resistor. You should check to make sure that you have the
correct resistor installed on the KY-013 sensor module. Notice that the reading is very
sensitive to the resistor as well as to the thermistor parameters c1, c2, c3.
Block diagram: Figure 4.28 shows the block diagram of the project.
● 136
Chapter 4 • Using Analogue-To-Digital Converters (ADCs)
Circuit diagram: The circuit diagram of the project is shown in Figure 4.29. The sensor is
connected to channel 0 of the ADC (GP26, pin 31). The LCD is connected as in the previous
projects using LCD.
Program listing: Figure 4.30 shows the program listing (Program: Thermistor). At the
beginning of the program variable Thermistor is assigned to channel 0 of the ADC and the
LCD is initialized. Main program runs in a loop every 2 seconds. The thermistor data is read
into variable Raw and then function Temperature is called to calculate the temperature. The
LCD is cleared, heading Temperature (C) is displayed at the top row, and the temperature
reading is formatted and displayed at the bottom row of the LCD in degrees Celsius in the
following format:
● 137
Raspberry Pi Pico Essentials
#------------------------------------------------------------
# THERMISTOR TEMPERATURE MEASUREMENT
# ==================================
#
# This program measures the ambient temperature using a
# low-cost NTC thermistor module (KY-013). The readings are
# displayed on the LCD
#
# Author: Dogan Ibrahim
# File : Thermistor.py
# Date : February 2021
#-------------------------------------------------------------
from machine import ADC
import utime
import math
import LCD
#
# Calculate the temperature using Steinhart-Hart equation
#
def Temperature(RawValue):
c1 = 0.001129148
c2 = 0.000234125
c3 = 0.0000000876741
R1 = 10000.0
ADC_Res = 65535.0
R2 = R1 / ((ADC_Res/RawValue - 1))
T = math.log(R2)
Tmp = 1.0 / (c1 + (c2 + (c3 * T * T)) * T)
Temp = Tmp - 273.15
return Temp
● 138
Chapter 4 • Using Analogue-To-Digital Converters (ADCs)
Note: We could also use the modified form of the Steinhart-Hart equation (known as the B
parameter equation) if the parameters c1, c2, c3 are not known. The modified equation is:
1 / T = 1 / T0 + 1 / B (log(R / R0))
where
● 139
Raspberry Pi Pico Essentials
5.1 Overview
The filing system of the Raspberry Pi Pico enables us to manipulate files in memory, which
includes creating new files, reading from files, and writing to files. In this Chapter we will
learn how to log the temperature data to files.
Aim: The aim of this project is to show how the temperature data (or any other data) can
be saved in a file.
Block diagram: Figure 5.1 shows the block diagram of the project.
Circuit diagram: The circuit diagram is shown in Figure 5.2. TMP36 temperature sensor
chip is connected to analogue channel 0 (GP26, pin 31).
● 140
Chapter 5 • Data Logging
Program listing: Figure 5.3 shows the program listing (Program: LogTemp). At the be-
ginning of the program, modules ADC of machine and utime are imported to the program.
A new file is created (i.e. opened in write w mode) with the name Temp.txt and the head-
ing Ambient Temperature, followed by a 'newline' character is written to the file. The
remainder of the program runs in a for loop which is iterated 30 times. Inside this loop the
temperature is read from TMP36, converted into degrees Celsius, and then saved in the file
with the relative seconds. At the end of the loop, the file is closed, and the message Data
has been written to file… is displayed on the screen.
#--------------------------------------------------------
# LOGGING THE TEMPERATURE DATA
# ============================
#
# This program measures the temperature using an external
# temperature sensor chip and logs the data every second
# for 30 seconds (i.e. 30 records)
#
# Author: Dogan Ibrahim
# File : LogTemp.py
# Date : February 2021
#----------------------------------------------------------
from machine import ADC
import utime
● 141
Raspberry Pi Pico Essentials
The contents of the file can be displayed by on the Thonny screen by clicking File, followed
by Open. Select Raspberry Pi Pico, and then click on file Temp.txt to display it as shown
in Figure 5.4. Notice that it is important that you close a file after you finished writing to it,
otherwise the data may not be saved securely. Also, by default a file is always opened in
read mode as a text file. Files can also be opened in binary mode using the options rb and
wb for read and write operations, respectively.
Figure 5.4: Contents of file Temp.txt (only part of the file is shown).
Aim: The aim of this project is to show how a file can be opened and its contents read and
displayed on the PC screen.
Program listing: Figure 5.5 shows the program listing (Program: ReadTemp). At the be-
ginning of the program, file Temp.txt is opened in read r mode. Function file.read is then
used to read the data from the file and display (print) it in the Thonny screen.
Figure 5.5 shows the program and the data displayed on the Thonny screen.
● 142
Chapter 5 • Data Logging
Function read() reads the entire contents of a file. If we want to read a line, we use the
function readline(). An example is given below which reads and displays the first 3 lines of
file Temp.txt (notice that an additional newline character is added to the end of each line):
Ambient Temperature
1 25.18
2 25.18
● 143
Raspberry Pi Pico Essentials
6.1 Overview
A digital form of Pulse Width Modulation (PWM; also written as pulsewidth modulation) is
commonly used to drive heavy loads such as motors, actuators, heaters, and so on. As we
shall see in this Chapter, PWM is basically a positive-going squarewave whose pulsewidth
can be changed. By changing the pulsewidth, we can effectively change the average value
of the voltage supplied to the load.
The duty cycle D of a PWM waveform is defined as the ratio of the ON time to its period.
Expressed mathematically,
D = TON / T
● 144
Chapter 6 • Pulse Width Modulation (PWM)
By varying the duty cycle between 0% and 100% we can effectively control the average
voltage supplied to the load between 0 and Vp.
The average value of the voltage applied to the load can be calculated by considering a gen-
eral PWM waveform shown in Figure 1. The average value A of waveform f(t) with period T
and peak value ymax and minimum value ymin is calculated as:
or,
or,
As it can be seen from the above equation, the average value of the voltage supplied to
the load is directly proportional to the duty cycle of the PWM waveform and by varying the
duty cycle we control the average load voltage. Figure 6.2 shows the average voltage for
different values of the duty cycle.
It is interesting to notice that with correct lowpass filtering, the PWM can be used as a DAC
if the MCU does not have a DAC channel. By varying the duty cycle we can effectively vary
the average analogue voltage supplied to the load.
● 145
Raspberry Pi Pico Essentials
The PWM channels can be accessed by one of two methods. For example, channel PW-
M_A[0] connected to port pin GP0 can be accessed as:
import machine
ch = machine.PWM(machine.Pin(0))
or as
The frequency of the PWM waveform can be set using the following statement. For exam-
ple, to set the frequency to 1000 Hz:
ch.freq(1000)
● 146
Chapter 6 • Pulse Width Modulation (PWM)
The duty cycle can be set between 0% and 100% by setting it from 0 to 65535. The duty
cycle can be set using the following statement. For example, to set the duty cycle to 50%:
ch.duty_u16(32767)
6.4 Project 1: Generate a 1000 Hz PWM waveform with 50% duty cy-
cle
Description: In this project, we create a PWM waveform with a frequency of 1000 Hz and
a duty cycle of 50%.
Aim: The aim of this project is to show how we can use the PWM functions.
Circuit diagram: In this project, port pin GP0 is used and an oscilloscope is connected to
this pin to observe the waveform.
Program listing: The program listing is very simple. and it is given below.
Figure 6.4 shows the generated waveform on the oscilloscope. Here, the horizontal axis
was 0.5ms/division and the vertical axis was 1 V/division. Clearly the period of the gener-
ated waveform is 1 ms (freq = 1000 Hz), duty cycle 50%, and the amplitude is about 3 V.
● 147
Raspberry Pi Pico Essentials
Note: The author has generated clean and correct PWM waveforms to up to several MHz
without any appreciable noise.
Aim: The aim of this project is to show how the PWM can be used in a project.
The block diagram and the circuit diagram of this project are as in Figure 3.3 and Figure
3.4 respectively.
Program listing: Figure 6.5 shows the program listing (Program: LEDfade). The frequen-
cy is set to 1000 Hz so that the LED light is steady (i.e. not flashing). As the duty cycle is
increased from 0% to 100%, the LED brightness increases gradually.
#----------------------------------------------------------
# CHANGING THE BRIGHTNESS OF AN LED
# =================================
#
# In this program and LED is connected to port pin GP0. The
# brightness of the LED is changed continuously by changing
# duty cycle of the voltage waveform from 0% to 100%
#
# Author: Dogan Ibrahim
# File : LEDfade.py
# Date : February 2011
#------------------------------------------------------------
from machine import Pin, PWM
import utime
i = 0
while True: # Do forever
ch.duty_u16(i) # Change duty cycle
utime.sleep_ms(300) # Delay 300ms
i = i + 5000 # Increment i
if i > 65535:
i = 0
● 148
Chapter 6 • Pulse Width Modulation (PWM)
Block Diagram: Figure 6.6 shows the block diagram of the project. A motor driver (MOS-
FET) and a potentiometer are connected to the microcontroller.
The DC motor In this project, is controlled using PWM waveforms as in the previous pro-
ject. By varying the potentiometer arm, the analogue voltage read by the microcontroller
is varied and this in turn changes the PWM duty cycle of the voltage applied to the motor,
thus causing the motor speed to change.
Circuit diagram: The circuit diagram of the project is shown in Figure 6.7. The potentiom-
eter is connected to channel 0 of the ADC (GP26, pin 31). The motor is connected to GP17
(pin 22) through an IRL540 type MOSFET switch. It is recommended to use an external
power supply for the motor.
● 149
Raspberry Pi Pico Essentials
Program listing: Figure 6.8 shows the program listing (Program: Motor). The data read
from the ADC varies between 0 and 65535 as the potentiometer arm is fully moved from
one side to the other side. This data is used to change the duty cycle from 0% to 100%.
#----------------------------------------------------------
# CHANGING THE MOTOR SPEED
# ========================
#
# In this project a brushed DC motor is connected to the
# Pico.Additionally, a potentiometer is conencted to channel
# 0 of the ADC.Varying the potentiometer changes the motor speed
#
# Author: Dogan Ibrahim
# File : Motor.py
# Date : February 2021
#------------------------------------------------------------
from machine import Pin, PWM, ADC
Block diagram: Figure 6.9 shows the block diagram of the project.
● 150
Chapter 6 • Pulse Width Modulation (PWM)
Circuit diagram: The circuit diagram of the project is given in Figure 6.10. The potenti-
ometer arm is connected to channel 0 of the ADC (GP0). The LCD is connected as in the
previous LCD projects. Output PWM waveform is available at port pin GP16, pin 21).
Program listing: Figure 6.11 shows the program listing (Program: FreqGen). At the be-
ginning of the program, Pot is assigned to ADC channel 0; LCD is initialized and a message
'Frequency(Hz)' is displayed at the top row of the LCD. Inside the program loop the value
of Pot is read and this is used to set the frequency of the PWM waveform. The duty cycle
is set to 50%.
#----------------------------------------------------------
# FREQUENCY GENERATOR
# ===================
#
# In this project a potentiometer is connected to channel 0
# of the Pico. Also, an LCD is connected. The program generates
# PWM waveforms of different frequencies as the potentiometer
● 151
Raspberry Pi Pico Essentials
# arm is moved
#
# Author: Dogan Ibrahim
# File : FreqGen.py
# Date : February 2011
#------------------------------------------------------------
from machine import Pin, PWM, ADC
import LCD
import utime
Row 1: Frequency(Hz)
Row 2: nnnnnnn
Circuit diagram: The PWM waveform whose frequency and duty cycle is to be asserted
is applied to port GP17 (pin 22). Make sure that the voltage is not greater than +3.3 V,
otherwise you may damage the input circuitry of your Pico.
● 152
Chapter 6 • Pulse Width Modulation (PWM)
Program listing: Figure 6.12 shows the program listing (Program: MeasPWM). The pro-
gram measures the Mark (i.e. logic 1) and Space (i.e. logic 0) timings of the PWM input
waveform in microseconds. The duty cycle and the frequency are then calculated as follows:
#----------------------------------------------------------
# MEASURE THE FREQUENCY AND DUTY CYCLE
# ====================================
#
# In this project a PWM wave is applied to the PIco. The
# frequency and duty cycle of this wave are measured and
# displayed on the Thonny screen.
#
# Author: Dogan Ibrahim
# File : MeasFreq.py
# Date : February 2021
#------------------------------------------------------------
from machine import Pin
import utime
while True:
if PWMin.value() == 0: # Wait while 1
break
Tmr1End = utime.ticks_cpu() # End
while True:
if PWMin.value() == 1: # Wait while 0
break
● 153
Raspberry Pi Pico Essentials
Aim: The aim of this project is to show how various tones can be generated to create a
simple melody.
Block diagram: The block diagram of the project is shown in Figure 6.14.
Circuit diagram: Figure 6.15 shows the circuit diagram of the project. A passive buzzer
is connected to port GP0 (pin 1) of the Raspberry Pi Pico. A transistor switch is used to in-
crease the voltage level of the buzzer (this can be omitted, and the buzzer can be directly
connected to GP0 if desired. This however will give low output from the buzzer). Almost
any old NPN, small-signal, bipolar transistor can be used in this project. The + terminal of
the buzzer can be connected to either +3.3 V or to +5 V for higher output from the buzzer.
● 154
Chapter 6 • Pulse Width Modulation (PWM)
Melodies
When playing a melody each note is played for a certain duration and with a certain fre-
quency. In addition, a certain gap is necessary between two successive notes. The frequen-
cies 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 × 262
= 524 Hz.
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
certain duration and there is a certain time gap between two successive notes. The next
thing we want is to know how to generate a sound with a required frequency and duration.
In this project, we will be generating the classic Happy Birthday melody and thus we need
to know the notes and their durations. These are given in the table below where the dura-
tions are in units of 400 milliseconds (i.e. the values given in the table should be multiplied
by 400 to give the actual durations in milliseconds).
Note C4 C4 D4 C4 F4 E4 C4 C4 D4 C4 G4 F4 C4
Duration 1 1 2 2 2 3 1 1 2 2 2 3 1
Duration 1 2 2 2 2 2 1 1 2 2 2 4
Program Listing: The program listing (program: Melody) is shown in Figure 6.16. The
frequencies and durations of the melody are stored in two arrays called frequency and
duration respectively. Before the main program loop the durations of each tone are calcu-
lated and stored in array Durations so that the main program loop does not have to spend
time to do these calculations. Inside the program loop, the melody frequencies are gener-
ated with the required durations. Notice that the tone output is stopped by setting the duty
cycle to 0. A small delay (100 ms) is introduced between each tone. The melody is repeated
● 155
Raspberry Pi Pico Essentials
after 3 seconds of delay. You can try higher harmonics of the notes for clearer sound. For
example, in Figure 6.16 the frequencies are multiplied by 2 to play the second harmonics.
#---------------------------------------------------------------
# MELODY MAKER - PLAY HAPPY BIRTHDAY
# ==================================
#
# In this project a buzzer is connected to port pin GP0
# which is configured as a PWM output. The program plays the
# melody Happy Birthday
#
# Author: Dogan Ibrahim
# File : Melody.py
# Date : February 2021
#------------------------------------------------------------
from machine import Pin, PWM
import utime
for k in range(MaxNotes):
Durations[k] = 400 * duration[k]
● 156
Chapter 6 • Pulse Width Modulation (PWM)
● 157
Raspberry Pi Pico Essentials
7.1 Overview
Serial communication is a simple means of sending data across long distances quickly and
reliably. The most seen serial communication method is based on the RS-232 standard. In
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.
RS-232 serial communication is a form of asynchronous data transmission where data is
sent character-by-character. Each character is preceded with a start bit, seven or eight data
bits, an optional parity bit, and one or more stop bits. The most commonly used format is
eight data bits, no parity bit and one stop bit (8N1). Therefore, a data frame consists of 10
bits. With a Baud rate of 9600, we can transmit and receive 960 characters every second.
The least significant data bit is transmitted first, and the most significant bit is transmitted
last.
In standard RS-232 communication, logic high is defined to be at –12 V, and a logic 0 is at
+12 V. Figure 7.1 shows how character "A" (ASCII binary pattern 0010 0001) is transmitted
over a serial line. The signal line is normally idle at –12 V. 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.
IDLE
START 1 0 0 0 0 0 1 0 STOP
In serial communication 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 synchronization, such as CTS, DTR, and so on. Some sys-
tems use software synchronization techniques where a special character (XOFF) is used to
tell the sender to stop sending, and another character (XON) is used to tell the sender to
recommence transmission. RS-232 devices are connected to each other using two types of
connectors: 9-way connector, and 25-way connector. Table 7.1 shows the TX, RX, and GND
pins of each types of connectors. The connectors used in RS232 serial communication are
shown in Figure 7.2.
9-pin connector
Pin Function
2 Transmit (TX)
3 Receive (RX)
5 Ground (GND)
● 158
Chapter 7 • Serial Communication (UART)
25-pin connector
Pin Function
2 Transmit (TX)
3 Receive (RX)
7 Ground (GND)
As described above, RS-232 voltage levels are at ±12 V. On the other hand, microcontroller
input/output ports typically operate at 0 to +5 V voltage levels. It is therefore necessary
to translate the voltage levels before a microcontroller can be connected to an RS-232
compatible device. Thus, the output signal from the microcontroller has to be converted
into ±12 V, and the input from an RS-232 device must be converted into 0 to +5 V 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 7.3. This particular device
requires four external 1-μF capacitors for its operation.
● 159
Raspberry Pi Pico Essentials
Nowadays, serial communication is done using standard TTL logic levels instead of ±12 V,
where logic 1 is +5 V (or greater than +3 V) and logic 0 is 0 V. A serial line is idle when the
voltage is at +5 V. The start bit is identified on the High-to-Low transition of the line, i.e.
the transition from +5 V to 0 V.
In this Chapter we will develop a program to communicate between the Raspberry Pi Pico
and an Arduino Uno microcontroller. Also, a program to communicate with a Raspberry Pi 4.
Aim: The aim of this project is to show how serial data can be sent to another device.
Block diagram: Figure 7.5 shows the block diagram of the project.
● 160
Chapter 7 • Serial Communication (UART)
Circuit diagram: The circuit diagram of the project is shown in Figure 7.6. TX0 pin (at
GP0) of the Raspberry Pi Pico is connected to pin 2 of the Arduino (this pin will be config-
ured as a soft serial input in the Arduino program).
Raspberry Pi Pico program listing: Figure 7.7 shows the program listing (Program:
SerTemp). At the beginning of the program variable AnalogIn is assigned to ADC channel
4 which is where the internal temperature sensor is connected to. UART 0 is then initialized
at port GP0 with the speed of 9600 Baud. Inside the program loop the internal temperature
is read, converted into degrees Celsius and finally sent to UART using function write. The
data is sent with 2 digits before, and 2 digits after the decimal point. Also, the text Degrees
C, followed by a 'newline' character ('\n') is sent.
Where id is the UART port number (e.g. 0 for TX0, RX0). By default, the number of bits is
8, parity is None, and stop bits is 1. If we are using GP0 with 9600 Baud, we can write the
second statement as:
● 161
Raspberry Pi Pico Essentials
import machine
uart=machine.UART(id=0,baudrate=9600,bits=8,parity=None,stop=1 )
We can then use the following functions to send and receive data:
#----------------------------------------------------------
# SERIAL LINK - SEND TEMPERATURE READING TO ARDUINO
# =================================================
#
# This project reads the internal temperature and sends it
# to Arduino Uno over a serial link at 9600 Baud
#
# Author: Dogan Ibrahim
# File : SerTemp.py
# Date : February 2021
#------------------------------------------------------------
from machine import ADC, UART
import utime
Figure 7.8 shows the program listing (Program: SerTemp2) where library machine is im-
ported to the program.
● 162
Chapter 7 • Serial Communication (UART)
#----------------------------------------------------------
# SERIAL LINK - SEND TEMPERATURE READING TO ARDUINO
# =================================================
#
# This project reads the internal temperature and sends it
# to Arduino Uno over a serial link at 9600 Baud.
# This version of the program imports machine
#
# Author: Dogan Ibrahim
# File : SerTemp2.py
# Date : February 2021
#------------------------------------------------------------
import machine
import utime
uart=machine.UART(id=0,baudrate=9600,bits=8,parity=None,stop=1 )
Arduino Uno program listing: Figure 7.9 shows the Arduino Uno program listing (Pro-
gram: Temp.c). The soft serial library is included at the beginning of the program and pins
2 and 3 are assigned to soft UART RX and TX, respectively. Inside the setup routine the
baud rate of the monitor and the soft serial port are configured to 9600. Inside the main
program loop the program waits until data arrives from the Raspberry Pi Pico. The data is
received until and including a 'newline' character. The temperature data is then displayed
on the Arduino IDE monitor as shown in Figure 7.10. Make sure that the Arduino IDE moni-
tor Baud rate is set to 9600.
/***********************************************************
* TEMPERATURE DISPLAY
* ===================
* This program reads the analog temperature data from the
* Raspberry Pi Pico over teh serial link and then displays
* this data on the Arduino IDE monitor
● 163
Raspberry Pi Pico Essentials
*
* Author: Dogan Ibrahim
* Date : February, 2020
* File : Temp.c
***********************************************************/
#include <SoftwareSerial.h>
SoftwareSerial MySerial(2, 3); // RX, TX
String Temp;
char ch;
void setup()
{
Serial.begin(9600); // Monitor speed 9600
MySerial.begin(9600); // Soft serial speed 9600
}
void loop()
{
if(MySerial.available() > 0) // Data available?
{
ch = MySerial.read();
Temp.concat(ch);
if(ch == ‘\n’)
{
Serial.print("Temperature = ");
Serial.print(Temp); // Display data
Temp="";
}
}
}
Figure 7.9: Arduino Uno program: Temp.
● 164
Chapter 7 • Serial Communication (UART)
7.4 Project 2: Receiving and displaying numbers from the Arduino Uno
Description: In this project we will be using a Raspberry Pi Pico and an Arduino Uno mi-
crocontroller as in the previous project. The program receives numbers counting up every
second from the Arduino and displays them on the Thonny screen.
Aim: The aim of this project is to show how serial data can be received from another de-
vice.
Circuit diagram: Figure 7.11 shows the circuit diagram of the project. RX0 pin (at GP1)
of the Raspberry Pi Pico is connected to pin 3 of the Arduino (this pin will be configured as
a soft serial output in the Arduino program).
Raspberry Pi Pico program listing: Figure 7.12 shows the program listing (Program:
SerRecv) together with the received data. At the beginning of the program UART 0 is ini-
tialized to 9600 Baud. The program loop receives data from the UART using function read-
line. The received data is decoded and displayed on the Thonny string.
Figure 7.12: Raspberry Pi Pico program: SerRecv and sample received data.
● 165
Raspberry Pi Pico Essentials
Arduino Uno program listing: Figure 7.13 shows the Arduino Uno program listing (Pro-
gram: Numbers.c). The soft serial library is included at the beginning of the program and
pins 2 and 3 are assigned to soft UART RX and TX respectively. Inside the setup routine
the Baud rate of the soft serial port is set to 9600. Variable cnt is incremented inside the
program loop, converted into string, and is sent to UART every 10 seconds.
/***********************************************************
* SEND NUMBERS TO RASPBERRY PICO
* ==============================
* This program sends numbers to the Rspberry Pi Pico over
* the serial link. These numbers are displayed by the Pico
*
* Author: Dogan Ibrahim
* Date : February, 2020
* File : Numbers.c
***********************************************************/
#include <SoftwareSerial.h>
SoftwareSerial MySerial(2, 3); // RX, TX
String Temp;
int cnt = 0;
char buffer[5];
void setup()
{
MySerial.begin(9600); // Soft serial speed 9600
}
void loop()
{
cnt = cnt + 1; // Increment cnt
itoa(cnt, buffer, 10); // Convert to string
MySerial.println(buffer);
delay(10000); // 10 seconds delay
}
Figure 7.13: Arduino Uno program: Numbers.c.
Aim: The aim of this project is to show how the Raspberry Pi Pico and Raspberry Pi 4 can
communicate over a serial link.
● 166
Chapter 7 • Serial Communication (UART)
Block diagram: Figure 7.14 shows the block diagram of the project.
In 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. Models earlier
than model 3 use this port for Bluetooth. Instead, a serial port is created in software (/
dev/ttyS0).
● 167
Raspberry Pi Pico Essentials
Circuit diagram: The circuit diagram of the project is shown in Figure 7.15. UART 0 of the
Pico (at GP0 and GP1) is connected to the UART of Raspberry Pi 4.
Raspberry Pi Pico program listing: Figure 7.16 shows the program listing (Program:
PicotoPi4) together with the received data. At the beginning of the program, UART 0 is
initialized to 9600 Baud. The program loop receives data from the UART using function
readline. The received data is decoded and displayed on the Thonny string. This is repeat-
ed after a 5-second delay.
Raspberry Pi 4 program listing: Figure 7.17 shows the Raspberry Pi 4 program listing
(Program: Pi4toPico.py). The program initializes the serial port, receives a message from
the Raspberry Pi Pico, and sends back a different message. The Baud rate is set to 9600.
● 168
Chapter 7 • Serial Communication (UART)
#---------------------------------------------------------------
# RASPBERRY PI 4 TO RASPBERRY PI PICO SERIAL COMMS
# ------------------------------------------------
#
# This program receives a number from the Raspberry Pi Pico,
# increments teh number and sends it back to the Pico
#
# Author: Dogan Ibrahim
# File : Pi4toPico.py
# Date : February, 2021
#---------------------------------------------------------------
import RPi.GPIO as GPIO # Import RPi library
from RPLCD.i2c import CharLCD # Import LCD library
import time # Import time library
import serial # Import srial
port = "/dev/serial0" # Serial port
GPIO.setwarnings(False)
#
# Receive the GPS coordinates and display on the LCD
#
ser = serial.Serial(port,baudrate=9600,timeout=100)
while True:
data = ser.readline() # Read a line
ser.write(b’Hello back\n’)
print(data)
time.sleep(5)
● 169
Raspberry Pi Pico Essentials
8.1 Overview
The I2C bus is commonly used in microcontroller-based projects. In this Chapter we shall be
looking at the use of this bus on the Raspberry Pi Pico. The aim is to make the reader fam-
iliar with the 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.
Figure 8.1 shows an I2C bus structure with one master and three slaves.
Figure 8.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 indi-
vidual slave device on the same bus. For this reason, the protocol defines that each slave
device provides a unique slave address for the given bus. This address is usually 7-bits
wide. When the bus is free, both lines are HIGH. All communication on the bus is initiated
and completed by the master which initially sends a START bit, and completes a transaction
by sending STOP bit. This alerts all the slaves that some data is coming on the bus and all
the slaves listen on the bus. After the start bit, 7 bits of a unique slave address are sent.
Each slave device on the bus has its own 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 read/
write bit such that if this bit is 0, it means that the master wishes to write to the bus (e.g.
to a register of a slave). If this bit is a 1, it means that the master wishes to read from the
bus (e.g. from the register of a slave). The data is sent on the bus with the MSB bit first.
An acknowledgement (ACK) bit takes is suffixed after every byte, allowing the receiver to
● 170
Chapter 8 • The I2C Bus Interface
signal to the transmitter that the byte was received successfully, and another byte may be
sent. The ACK bit is sent at the 9th clock pulse.
The communication over the I2C bus is described in the following sequence.
• The master sends on the bus the address of the slave it wants to communicate
with.
• The LSB is the R/W bit which establishes the direction of data transmission, i.e.
from mater to slave (R/W = 0), or from slave to master (R/W = 1).
• Requested bytes are sent, each interleaved with an ACK bit, until a stop condi-
tion occurs.
Depending on the type of slave device used, some transactions may require separate trans-
action. For example, the steps to read data from an I2C compatible memory device are
given below.
• 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
64 Kbit 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 sequen-
tial format, then more than one byte will be read.
• The master sets a stop condition on the bus.
● 171
Raspberry Pi Pico Essentials
In the remainder of this Chapter we will be developing projects using the I2C bus.
The aim: The aim of this project is to show how the I2C bus can be used in Raspberry Pi
Pico projects.
Block diagram: The block diagram of the project is shown in Figure 8.3.
● 172
Chapter 8 • The I2C Bus Interface
The MCP23017
The MCP23017 is a 28-pin chip with some features listed below. Its pin configuration is
shown in Figure 8.4.
Pin Description
VSS Ground
● 173
Raspberry Pi Pico Essentials
The MCP23017 is addressed using pins A0 to A2. Table 8.2 shows the address selection. In
this project the 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 is 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) as 0x40.
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
The MCP23017 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 IO-
CON.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 correspond-
ing port pin(s) as output(s). Similarly, setting a bit to 1 in these registers make the cor-
responding port pin(s) input(s). GPIOA and GPIOB register addresses are 0x12 and 0x13
respectively. This is shown in Figure 8.5.
Figure 8.6 shows the circuit diagram of the project. Notice that I2C pins of the port ex-
pander are connected to pins GP8 (I2C0 SDA) and GP9 (I2C0 SCL) of the Raspberry Pi Pico
and are pulled-up using 10-kohm 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.
● 174
Chapter 8 • The I2C Bus Interface
More information on the MCP23017 chip can be obtained from the datasheet:
http://docs-europe.electrocomponents.com/webdocs/137e/0900766b8137eed4.pdf
Program listing: Figure 8.7 shows the program listing (Program: MCP23017). The Rasp-
berry Pi Pico supports the following I2C functions:
● 175
Raspberry Pi Pico Essentials
At the beginning of the program, the I2C module is imported to the program and the I2C
interface is defined by specifying the SDA and SCL pin connections to the Pico. Function
i2c.scan() is called to display the I2C slave devices on the bus, and the following was
displayed:
Then the MCP23017 I2C device address, register GPIOA address, and the I/O direction
IODIRA address are defined. List conf stores the IODIRA register address and 0 so that
MCP23017 PORTA is set to output mode. List buff1 stores the GPIOA register address and
what the output should be set to (1 to turn ON the LED). Similarly, buff2 stores the GPIOA
register address and what the output should be set to (0 to turn OFF the LED). Inside the
main program loop the LED is flashed every second.
#----------------------------------------------------------
# I2C PORT EXPANDER
# =================
#
# In this project the MCP23017 port expander chip is used.
# An LED is connected to port pin GPA0 of the port expander
# and this LED is flashed every second
#
# Author: Dogan Ibrahim
# File : MCP23017.py
# Date : February 2021
#------------------------------------------------------------
from machine import Pin,I2C
import utime
i2c.writeto(Device_Address, bytearray(conf))
while True:
i2c.writeto(Device_Address, bytearray(buff1))
utime.sleep(1)
i2c.writeto(Device_Address, bytearray(buff0))
● 176
Chapter 8 • The I2C Bus Interface
utime.sleep(1)
The program can be modified so that the memory functions of i2c are used. The modified
program listing (Program: MCP23017-2) is shown in Figure 8.8.
#----------------------------------------------------------
# I2C PORT EXPANDER
# =================
#
# In this project the MCP23017 port expander chip is used.
# An LED is connected to port pin GPA0 of the port expander
# and this LED is flashed every second
#
# This version of the program uses the i2c memory functions
#
# Author: Dogan Ibrahim
# File : MCP23017-2.py
# Date : February 2021
#------------------------------------------------------------
from machine import Pin,I2C
import utime
while True:
i2c.writeto_mem(Device_Address, MCP_GPIOA_REG, b’1’)
utime.sleep(1)
i2c.writeto_mem(Device_Address, MCP_GPIOA_REG, b’0’)
utime.sleep(1)
● 177
Raspberry Pi Pico Essentials
The aim: The aim of this project is to show how an I2C based EEPROM memory can be
programmed using the Raspberry Pi Pico.
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:
1 0 1 0 A2 A1 A0 R/W
WP is the write protection pin. If this pin is tied to Ground, writing is enabled. If connected
to Vcc then the write operations have no effect.
Circuit diagram
The circuit diagram of the project is shown in Figure 8.10. In this project, I2C pins GP8
(I2C0 SDA) and GP9 (I2C0 SCL) of Raspberry Pi Pico are used. A0, A1 and A2 are connect-
ed to ground so that the device address is 0xA0. Also, the write protect pin WP is tied to
ground. The SDA and SCL pins are pulled-up using 10-kohm resistors.
● 178
Chapter 8 • The I2C Bus Interface
Before going into details of the memory write and read operations, it is worthwhile to learn
how this is done.
Memory-write operation
As an example, assume that we want to write byte 0x25 into memory location 0x0250.
Figure 8.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
and they are sent sequentially with the higher byte sent first over the bus. Then, the data
byte 0x25 is sent (this is called Byte Writing since only one byte is written to memory).
Notice that we can send multiple bytes (this is 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 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 actually 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 that 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:
● 179
Raspberry Pi Pico Essentials
Page 1: 0 – 63
Page 2: 64 – 127
Page 3: 128 – 191
Page 4: 192 – 255
Page 5: 256…….
Notice that the data sent 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 completed successfully.
Memory-read operation
Memory-read operations are slightly more complex. There are 3 types of reads: current
address read, random read, and sequential read. Random read mode is probably the most
commonly used mode where the master can access any memory location in a random
manner.
As an example, assume that we want to read the byte at memory location 0x0250 (where
0x25 was stored in Figure 8.11). Figure 8.12 shows the read steps in detail. To perform
a Random Read, the memory address must be sent first. This is done by an I2C device
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.
In Sequential Read operation, an internal address pointer is incremented automatically
after each read operation. This allows the entire memory contents to be read easily.
Program listing: Figure 8.13 shows the program listing (Program: EEPROM). In this pro-
gram the device address of the EEPROM chip was found to be 80 (hexadecimal 0x50). In-
side the main program, a list wmsg is defined and is pre-loaded with the data 1357 which
is the data to be written to the EEPROM memory. Also, another list called rmsg is declared
which will be loaded with the data read from the memory chip. The program then calls func-
tion Write to write the contents of list wmsg to the memory chip, starting from address
● 180
Chapter 8 • The I2C Bus Interface
0x10000. Function Read 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 read-
ing a byte of data. Sequential read operation is done by the program where the memory
address pointer is incremented automatically to point to the next location.
Function: Write
This function has 3 arguments:
memloc: starting memory address where the data will be stored to
data: the data to be stored
addrsize: size of the address
Function: Read
memloc: This function has two arguments: starting memory address where the
data will be read from
len: Number of bytes to read
addrsize: size of the address
#----------------------------------------------------------
# I2C EEPROM READ/WRITE
# =====================
#
# In this project a 24LC256 type I2C EEPROM memory chip is
# connected to the Raspberry Pi Pico. The program writes and
# then reads from the memory
#
# Author: Dogan Ibrahim
# File : EEPROM.py
# Date : February 2021
#------------------------------------------------------------
from machine import Pin,I2C
import utime
len = 4
● 181
Raspberry Pi Pico Essentials
#
# This function reads len bytes starting from specified memory
# address memloc (16 bits)
#
def Read(memloc, len):
data = [0]*4
data = i2c.readfrom_mem(Device_Address, memloc, 4,addrsize=16)
return(data)
#
# This function writes the data to starting from the specified
# memory address memloc (16 bits)
#
def Write(memloc, data,len):
i2c.writeto_mem(Device_Address, memloc, data, addrsize = 16)
utime.sleep_ms(10)
#
# Display the data read starting from address 0x1000
#
print("Data read is: %c%c%c%c\n" %(rmsg[0],rmsg[1],rmsg[2],rmsg[3]))
The aim: The aim of this project is to show how the temperature sensor chip TMP102 can
be used in a program.
The TMP102
The TMP102 is an I2C compatible, highly accurate temperature sensor chip with a built-in
thermostat with the following basic features:
● 182
Chapter 8 • The I2C Bus Interface
TMP102 is a 6-pin chip as shown in Figure 8.14. the pin descriptions are:
● 183
Raspberry Pi Pico Essentials
A Pointer Register select various registers in the chip as shown in Table 8.1. The upper
6 bits of this register are 0s.
P1 P0 Register Selected
0 1 Configuration register
1 0 TLOW register
1 1 THIGH register
Table 8.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 8.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
● 184
Chapter 8 • The I2C Bus Interface
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
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, the Alert pin becomes ac-
tive-High.
The default device address is 0x48. TMP102 is available as a module (breakout module)
as shown in Figure 8.15. The temperature register address is 0x00 and this should be sent
after sending the device address. This is then followed with a read command where 2 bytes
are read from the TMP102. These 2 bytes contain the temperature data.
• 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 resends 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: Figure 8.16 shows the block diagram of the project.
● 185
Raspberry Pi Pico Essentials
Circuit diagram: The circuit diagram of the project is shown in Figure 8.17. On-chip
pull-up resistors are available on the TMP102 I2C bus lines, hence there is no need to use
external pull-up resistors.
Program listing: Figure 8.18 shows the program listing (Program: TMP102). At the be-
ginning 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 and calls function Read every second. Read reads
the temperature from TMP102, converts it into positive (or negative) degrees Celsius and
then returns the reading to the main program. The two bytes read are combined to form
the 12-bit temperature data in variable temp. If the temperature is negative, then 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 displayed on the Thonny screen as a floating point number.
Table 8.4 shows the data output format of the temperature. Let us look at two examples:
● 186
Chapter 8 • The I2C Bus Interface
This is negative temperature. The complement is 0001 10001111, and adding 1 gives 0001
10010000 = 400 decimal. The temperature works out as: 400 × 0.0625 = 25, i.e. –25 ºC
50 001100100000 320
#----------------------------------------------------------
# TMP102 TEMPERATURE SENSOR
# =========================
#
# In this project a TMP102 type I2C compatible temperature
# sensor chip is connected to Raspberry Pi Pico. The temperature
# readings are displayed on the Thonny screen.
#
# Author: Dogan Ibrahim
# File : TMP102.py
# Date : February 2021
#------------------------------------------------------------
from machine import Pin,I2C
import utime
#
# This function reads the temperature, extracts degrees Celius
# and returns the temperature to the main calling program
#
def Read():
data = [0, 0]
LSB = 0.0625
data = i2c.readfrom_mem(Device_Address, PointerReg, 2)
temp = (data[0] << 4) | (data[1] >> 4)
● 187
Raspberry Pi Pico Essentials
#
# Main program reads and displays the temperature every second
#
while True:
Temperature = Read()
print("Temperature = %+5.2f" %Temperature)
utime.sleep(1)
The aim: The aim of this project is to show how the BMP280 chip can be used in a program.
The BMP280
The BMP280 (Figure 8.20) is an I2C compatible highly accurate temperature and atmos-
pheric pressure sensor chip having the following basic features:
● 188
Chapter 8 • The I2C Bus Interface
Block diagram: Figure 8.21 shows the block diagram of the project.
Circuit diagram: The BMP280 can be operated either in I2C or in SPI mode. In this project
we are using the I2C mode. The circuit diagram of the project is shown in Figure 8.22. I2C
pins GP8 (SDA) and GP9 (SCL) of the Raspberry Pi Pico are connected to the corresponding
SDA and SCL pins of the BMP280.
● 189
Raspberry Pi Pico Essentials
https://github.com/ControlEverythingCommunity/BMP280/blob/master/Python/
BMP280.py
This program reads the temperature and pressure from the BMP280 chip whose I2C ad-
dress is 118 (0x76).
Figure 8.23 shows the program listing (Program: ReadBMP280) where the temperature
and pressure readings are displayed on the Thonny screen. The I2C address is also dis-
played on the screen.
#----------------------------------------------------------
# BMP280 TEMPERATURE AND PRESSURE SENSOR
# ======================================
#
# In this project the BMP280 temperature and pressure sensor
# chip is used and the readings are displayed on the screen
# every 5 seconds
#
# Author: Dogan Ibrahim
# File : ReadBMP280.py
# Date : February 2021
#------------------------------------------------------------
from machine import Pin,I2C
import utime
import utime
● 190
Chapter 8 • The I2C Bus Interface
# Pressure coefficents
dig_P1 = b1[7] * 256 + b1[6]
dig_P2 = b1[9] * 256 + b1[8]
if dig_P2 > 32767 :
dig_P2 -= 65536
dig_P3 = b1[11] * 256 + b1[10]
if dig_P3 > 32767 :
dig_P3 -= 65536
dig_P4 = b1[13] * 256 + b1[12]
if dig_P4 > 32767 :
dig_P4 -= 65536
dig_P5 = b1[15] * 256 + b1[14]
if dig_P5 > 32767 :
dig_P5 -= 65536
dig_P6 = b1[17] * 256 + b1[16]
if dig_P6 > 32767 :
dig_P6 -= 65536
dig_P7 = b1[19] * 256 + b1[18]
if dig_P7 > 32767 :
dig_P7 -= 65536
dig_P8 = b1[21] * 256 + b1[20]
if dig_P8 > 32767 :
dig_P8 -= 65536
dig_P9 = b1[23] * 256 + b1[22]
if dig_P9 > 32767 :
● 191
Raspberry Pi Pico Essentials
dig_P9 -= 65536
utime.sleep(0.5)
● 192
Chapter 8 • The I2C Bus Interface
#
# Main program, read and siaplay the temperature and pressure
#
while True:
T,P = BMP280()
print("Temperature in Celsius : %.2f C" %T)
print("Pressure : %.2f hPa \n" %P)
utime.sleep(5)
• Use the Thonny to save the function given in Figure 8.25 with the name
bmp280.py on your Raspberry Pi Pico.
import machine
import utime
def BMP280():
i2c = machine.I2C(0, scl=machine.Pin(9), sda=machine.Pin(8), freq=100000)
# BMP280 address, 0x76(118)
# Read data back from 0x88(136), 24 bytes
b1 = i2c.readfrom_mem(0x76, 0x88, 24)
● 193
Raspberry Pi Pico Essentials
# Pressure coefficents
dig_P1 = b1[7] * 256 + b1[6]
dig_P2 = b1[9] * 256 + b1[8]
if dig_P2 > 32767 :
dig_P2 -= 65536
dig_P3 = b1[11] * 256 + b1[10]
if dig_P3 > 32767 :
dig_P3 -= 65536
dig_P4 = b1[13] * 256 + b1[12]
if dig_P4 > 32767 :
dig_P4 -= 65536
dig_P5 = b1[15] * 256 + b1[14]
if dig_P5 > 32767 :
dig_P5 -= 65536
dig_P6 = b1[17] * 256 + b1[16]
if dig_P6 > 32767 :
dig_P6 -= 65536
dig_P7 = b1[19] * 256 + b1[18]
if dig_P7 > 32767 :
dig_P7 -= 65536
dig_P8 = b1[21] * 256 + b1[20]
if dig_P8 > 32767 :
dig_P8 -= 65536
dig_P9 = b1[23] * 256 + b1[22]
if dig_P9 > 32767 :
dig_P9 -= 65536
utime.sleep(0.5)
● 194
Chapter 8 • The I2C Bus Interface
#----------------------------------------------------------
# BMP280 TEMPERATURE AND PRESSURE SENSOR
# ======================================
#
# In this project the BMP280 temperature and pressure sensor
# is connected to the Raspberry Pi Pico. The temperature and
# pressure readings are displayed every 5 seconds on the
# Thonny screen
#
# In this version of the program the BMP280 code is imported
# as a module
#
# Author: Dogan Ibrahim
# File : ReadBMP280-2.py
# Date : February 2021
#------------------------------------------------------------
● 195
Raspberry Pi Pico Essentials
while True:
T,P = bmp280.BMP280()
print("Temperature in Celsius : %.2f C" %T)
print("Pressure : %.2f hPa \n" %P)
utime.sleep(5)
Block diagram: Figure 8.27 shows the block diagram of the project.
Circuit diagram: The circuit diagram of the project is shown in Figure 8.28.
● 196
Chapter 8 • The I2C Bus Interface
Program listing: Figure 8.29 shows the program listing (Program: TempPres). At the be-
ginning of the program modules bmp280, utime, I2C, and LCD are imported to the program
and the LCD is initialized. Inside the program loop the temperature and pressure readings
are displayed on the top and bottom rows of the LCD respectively.
#----------------------------------------------------------
# DISPLAY BMP280 TEMPERATURE AND PRESSURE READINGS ON LCD
# =======================================================
#
# In this project a BMP280 temperature and pressure sensor
# module is connected to Raspberry Pi Pico. The readings
# are displayed on LCD
#
# Author: Dogan Ibrahim
# File : TempPres.py
# Date : February 2021
#------------------------------------------------------------
from machine import Pin,I2C
import utime
import bmp280
import LCD
LCD.lcd_init()
while True:
T,P = bmp280.BMP280() # Read T and P
Temp = "T=" + str(T)[:5] + " C" # Format T
Press = "P=" + str(P)[:6] + " hPa" # Format P
LCD.lcd_clear() # Clear LCD
LCD.lcd_puts(Temp) # Display Temperature
LCD.lcd_goto(0, 1) # At 0, 1
LCD.lcd_puts(Press) # Display Pressure
utime.sleep(5) # Wait 5 seconds
● 197
Raspberry Pi Pico Essentials
9.1 Overview
In this Chapter we shall be developing projects using the SPI bus (serial Peripheral Inter-
face) with the Raspberry Pi Pico. The SPI bus is commonly a widely used protocol to connect
sensors and many 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 communica-
tion with the slaves and controls all the activity on the bus.
Figure 9.1 shows an SPI bus example with one master and 3 slaves. The SPI bus uses 3
signals: clock (SCK), data in (SDI, or RX), and data out (SDO, or TX). SDO of the master
is connected to the SDIs of the slaves, and SDOs of the slaves are connected to the SDI of
the master. The master generates the 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 the slaves cannot
communicate with each other. It is important to note that only one slave can be active
at any time since there is no mechanism to identify the slaves. Thus, slave devices have
enable lines (e.g. CS or CE) which are normally controlled by the master. A typical commu-
nication sequence between a master and several slaves is given below.
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
projects in this Chapter the Raspberry Pi is the master and one or more slaves are con-
nected to the bus. Transactions over the SPI bus are started by enabling the SCK line.
The master then asserts the SSEL line Low so that data transmission can begin. The 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 trans-
ferred, then the process is repeated. Data exchange is complete when the master stops
sending clock pulses and deselects the slave device.
● 198
Chapter 9 • The SPI Bus Interface
The master and the slave must agree on the clock polarity and phase on the line, which are
known as the SPI bus modes. These two settings go by the names '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 gets 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 gets output on the rising edge. For CPHA =
1, data is captured on the rising edge of the clock and gets shifted out on the falling edge.
● 199
Raspberry Pi Pico Essentials
In the remaining sections of this Chapter we will be developing a project using the SPI bus.
The aim: The aim of this project is to show how the SPI bus can be used in Raspberry Pi
Pico based projects.
Block diagram: The block diagram of the project is same as in Figure 8.3, but the
MCP23017 chip is replaced with the MCP23S17.
The MCP23S17
The MCP23S17 is a 28-pin chip with some interesting features:
● 200
Chapter 9 • The SPI Bus Interface
The pin configuration is shown in Figure 9.3, which is same as the pin configuration of
MCP23017, but SPI pins are used instead of I2C pins.
Pin Description
VSS Ground
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. IO-
CON.HAEN = 0) and A2 = A1 = A0 = 0. and the chip is addressed with 0x40. As such, we
● 201
Raspberry Pi Pico Essentials
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. 16 such chips can be connected (8 to CE0 and
8 to CE1), corresponding to 16 × 16 = 256 I/O ports. Figure 9.4 and Figure 9.5 show the
addressing format. The address pins should be externally biased even if disabled.
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 correspond-
ing port pin(s) as output(s). Similarly, setting a bit to 1 in these registers make the cor-
responding port pin(s) input(s). GPIOA and GPIOB register addresses are 0x12 and 0x13
respectively. This is shown in Figure 9.6.
Further information on the MCP23S17 chip can be obtained from the Microchip Inc data
sheet at the following web site:
● 202
Chapter 9 • The SPI Bus Interface
http://ww1.microchip.com/downloads/en/DeviceDoc/20001952C.pdf
Circuit diagram: Figure 9.7 shows the circuit diagram of the project. SPI0 pins at GP3
(SPI0 TX) and GP2 (SPI0 SCK) are used to interface to the chip. CS is controlled separately
and in this project GP26 is used as the CS pin. SPI0 RX pin is not used in this project since
there is no input from the MCP23S17.
Program listing: Figure 9.8 shows the program listing (Program: MCP23S17). The pro-
gramming 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 PORTA pins
are outputs. This register has address 0x0. Then, we should program bit 0 of PORTA (pin:
GPIOA) where the LED is connected to. The address of register GPIOA is 0x12.
At the beginning of the program the SPI interface signals between the Raspberry Pi Pico
and MCP23S17 are defined. The required addresses of the MCP23S17 and the CS connec-
tion are then defined, and CS is initially set to 1 so that the MCP23S17 chip command mode
is disabled (CS must be controlled separately).
Function Configure configures PORTA as output. Function Send sends data to the specified
port register (RegAddr) so that the required pin is at logic 1 or 0. Data is either 0 or 1.
When 1, the LED is turned ON, and when 0 the LED is turned OFF. The main program runs
in a loop and calls function Send every second to flash the LED.
● 203
Raspberry Pi Pico Essentials
#----------------------------------------------------------
# SPI BUS PORT EXPANDER
# =====================
#
# In this project the SPI bus compatible MCP23S17 chip is used
# to add 16 more ports to Raspberry Pi Pico.An LED is connected
# to pin GPA0 of the expander and the LED is flashed every
# second
#
# Author: Dogan Ibrahim
# File : MCP23S17.py
# Date : February 2021
#------------------------------------------------------------
from machine import Pin,SPI
import utime
spi = SPI(0,sck=spi_sck,mosi=spi_tx,miso=spi_rx,baudrate=100000)
#
# This function configures PORTA as output
#
def Configure():
buff = [0, 0, 0]
buff[0] = Device_Address
buff[1] = MCP_IODIRA
buff[2] = 0
CS.value(0)
spi.write(bytearray(buff))
CS.value(1)
#
# This function sends data to register RegAddr
#
def Send(RegAddr, data):
buff = [0, 0, 0]
buff[0] = Device_Address
● 204
Chapter 9 • The SPI Bus Interface
buff[1] = RegAddr
buff[2] = data
CS.value(0)
spi.write(bytearray(buff))
CS.value(1)
#
# Main program reads and displays the temperature every second
#
while True:
Configure()
while True:
Send(MCP_GPIOA, 1) # LED ON
utime.sleep(1) # 1 second delay
Send(MCP_GPIOA, 0) # LED OFF
utime.sleep(1) # 1 second delay
sck, mosi, and miso are the SPI pins and they can be assigned to GPIO pins using the Pin
functions (see Figure 9.8).
● 205
Raspberry Pi Pico Essentials
10.1 Overview
In this Chapter we shall be developing projects using a Wi-Fi link to establish communica-
tion between the Raspberry Pi Pico and a smartphone.
Aim: The aim of this project is to showcase the use the Wi-Fi connectivity on the Raspberry
Pi Pico.
Pico Wi-Fi connectivity: The Raspberry Pi Pico has no built-in Wi-Fi module and as such it
cannot be connected to a Wi-Fi network without interfacing it to an external Wi-Fi module.
Perhaps the easiest and the cheapest way of providing Wi-Fi capability to the Pico is by
using an ESP-01 processor board. This is a tiny board (see Figure 10.1), measuring only
2.7 cm × 1.2 cm, and based on the ESP8266 processor chip, and costing around $3 USD.
The ESP-01 has the following motivating features:
ESP-01 communicates with the host processor through its TX and RX serial port pin. It is
an 8-pin board with pin names as follows:
● 206
Chapter 10 • Wi-Fi with the Raspberry Pi Pico
The ESP-01's pins are not standard breadboard-compatible, so an adaptor is required if the
board is to be attached to a breadboard (see Figure 10.2).
Circuit Diagram: Figure 10.4 shows the circuit diagram of the project. The Raspberry Pi
Pico's UART 0 TX and RX pins are used to communicate with the ESP-01.
● 207
Raspberry Pi Pico Essentials
Program Listing: Figure 10.5 shows the program listing (program: Picowifi). Inside the
setup routine serial communication speed is set to 115200 which is the default Baud rate
for ESP-01, and the LED is configured as output and turned OFF. Function ConnectToWiFi
is called to connect to the local Wi-Fi router. AT-style commands are used to configure the
ESP-01 to connect to the Wi-Fi router.
The remainder of the program runs in an endless loop formed using a while statement.
Inside this loop, data is received from the smart mobile phone and the LED is controlled ac-
cordingly. Commands LON and LOFF turn the LED ON and OFF, respectively. Data packets
are received from the smartphone using the readline function. Function find looks for a
substring in a string and returns a non-zero value if the substring is found. The find func-
tion is used because the data received from the mobile device is in the following format:
+ID0,n: data (e.g. +ID0,3:LON) where 0 is the link ID and n is the number of characters
received. Using the function find we can easily search for the strings LON or LOFF in the
received data packet.
Function ConnectToWiFi sends the following commands to the ESP-01 to connect to the
Wi-Fi network:
● 208
Chapter 10 • Wi-Fi with the Raspberry Pi Pico
#----------------------------------------------------------
# USING WI-FI
# ===========
#
# In this project a ESP-01 chip is connected to the Raspberry
# Pi Pico. This chip is used to connect the Pico to the Wi-Fi
#
# Author: Dogan Ibrahim
# File : Picowifi.py
# Date : February 2021
#------------------------------------------------------------
from machine import Pin, UART
import utime
uart = UART(0, baudrate=115200,rx=Pin(1),tx=Pin(0))
#
# Send AT commands to ESP-01 to connect to local WI-Fi
#
def ConnectToWiFi():
uart.write("AT+RST\r\n")
utime.sleep(5)
uart.write("AT+CWMODE=1\r\n")
utime.sleep(1)
uart.write(‘’’AT+CWJAP="BTHomeSpot-XNH","49345xyzpq"\r\n’’’)
utime.sleep(5)
uart.write("AT+CPIMUX=0\r\n")
utime.sleep(3)
uart.write(‘’’AT+CIPSTART="UDP","0.0.0.0",5000,5000,2\r\n’’’)
utime.sleep(3)
ConnectToWiFi()
#
# Main program loop
#
while True:
buf = uart.readline() # Read data
dat = buf.decode(‘UTF-8’) # Decode
n = dat.find("LON") # Includes LON?
● 209
Raspberry Pi Pico Essentials
if n > 0:
LED.value(1) # LED ON
n = dat.find("LOFF") # Includes OFF?
if n > 0:
LED.value(0) # LED OFF
Notice that small delays are used after each command. Command AT+CWJAP requires a
longer delay. The program can easily be modified such that the delays can be removed and
the responses from the ESP-01 can be checked. This way, as soon as the correct response
is received, the program can continue. You may have to hardware-reset the ESP-01 by
powering it down and up again before you run the program.
You should install a UDP Server app on your Android mobile phone before starting the test
with the smartphone. There are many freely available UDP apps in the Play Store. The
one installed and used in this project is called the UDP/TCP Widget by K.J.M as shown in
Figure 10.7.
● 210
Chapter 10 • Wi-Fi with the Raspberry Pi Pico
• Click the MESSAGE menu item and select Text (UTF-8) as the Format, and
enter command LON to turn ON the LED. Select LF\n as the Terminator and
click the OK symbol (check symbol), as shown in Figure 10.9.
• Now, click the SEND button (Figure 10.10) to send the command to the Rasp-
berry Pi Pico. You should see the message Packet Sent displayed at the top of
your Android screen temporarily.
● 211
Raspberry Pi Pico Essentials
Notice that the IP address of the ESP-01 can be obtained by scanning all the devices on the
local Wi-Fi router. For example, the Android app called Who Uses My WiFi – Network
Scanner by Phuongpn can be used to see the IP addresses of all the devices connected
to your router. The ESP-01 is listed as shown in Figure 10.11 (IP: 192.168.1.160), listed
with the name Espressif.
● 212
Chapter 10 • Wi-Fi with the Raspberry Pi Pico
Aim: The aim of this project is to show how two-way communication can be established
with a smartphone over the Wi-Fi link.
Block Diagram: Figure 10.12 shows the block diagram of the project.
Circuit Diagram: The circuit diagram of the project is same as in Figure 10.4.
Program Listing: The program listing is shown in Figure 10.13 (program: Temptowifi).
Function ConnectToWiFi is called to connect to the local Wi-Fi router as in the previous
program. Inside the main program loop, the program waits to receive command T? and
when this command is received, function GetTemperature is called and the Raspberry Pi
Pico's internal temperature is read and stored in variable T in the main program. String var-
iable Tstr stores string T= followed by the value of the temperature as a string. The length
of this string is stored in variable Tlen. Sending data through the Wi-Fi UDP link involves
sending command AT+CIPSEND to ESP-01, followed by the number of bytes to be sent
(i.e. the length of the data). The actual data is then sent after a short delay.
#----------------------------------------------------------
# SEND TEMPERATURE TO SMART PHONE
# ===============================
#
# In this project a ESP-01 chip is connected to the Raspberry
# Pi Pico. Internal temperature of the Raspberry Pi Pico is
# sent to the smart phone
#
# Author: Dogan Ibrahim
# File : Temptowifi.py
# Date : February 2021
#------------------------------------------------------------
from machine import Pin, UART, ADC
import utime
● 213
Raspberry Pi Pico Essentials
def GetTemperature():
V = AnalogIn.read_u16()
V = V * Conv
Temp = 27 - (V - 0.706) / 0.001721
return Temp
#
# Send AT commands to ESP-01 to connect to local WI-Fi
#
def ConnectToWiFi():
uart.write("AT+RST\r\n")
utime.sleep(5)
uart.write("AT+CWMODE=1\r\n")
utime.sleep(1)
uart.write(‘’’AT+CWJAP="BTHomeSpot-XNH","49345axyzw"\r\n’’’)
utime.sleep(5)
uart.write("AT+CPIMUX=0\r\n")
utime.sleep(3)
uart.write(‘’’AT+CIPSTART="UDP","192.168.1.199",5000,5000,2\r\n’’’)
utime.sleep(3)
ConnectToWiFi()
#
# Main program loop. Send the temperature to smart phone
#
while True:
buf = uart.readline() # Read data
dat = buf.decode(‘UTF-8’) # Decode
n = dat.find("T?") # T? received?
if n > 0:
T = GetTemperature() # Get the temperature
Tstr = "T=" + str(T) # Insert T=
Tlen = str(len(Tstr)) # Length
Dt = "AT+CIPSEND="+Tlen + "\r\n" # AT command to send
uart.write(Dt) # Send to ESP-01
● 214
Chapter 10 • Wi-Fi with the Raspberry Pi Pico
Alternatively, we can use a suitable UDP client/server program to test the program. One
such program for Android-running smartphones is the TCP/UDP Client app from Digit
Mund as shown in Figure 10.15. Figure 10.16 shows the startup screen of this app on an
Android smartphone. Enter the Raspberry Pi Pico IP address, Port number, Protocol,
and click the menu button REQUEST.
● 215
Raspberry Pi Pico Essentials
An example run of the program on the app is shown in Figure 10.17, where command T? is
sent to the Raspberry Pi Pico and the temperature is received and displayed on the Android
screen.
● 216
Chapter 11 • Bluetooth with the Raspberry Pi Pico
11.1 Overview
Bluetooth is one of the most popular means of exchanging data wirelessly over short dis-
tances. Nowadays, many electronic devices such as smartphones, laptops, iPads, games,
gadgets, portable health monitoring devices, and so on, are all equipped with Bluetooth
modules. Bluetooth is used by many people to share picture and music files using their
smartphones.
Bluetooth is a paired communication protocol where both devices must enable their Blue-
tooth links and use then use the same key to connect to each other. When the connection
is established, the data can be sent both ways. There is no need to worry about line-of-
sight between the devices since the communication is based on radio waves, albeit with
limited range.
Sometimes the pairing between devices may fail. You should pay attention to the following
points for successful pairing between the devices.
L1 Turn LED ON
L0 Turn LED OFF
Aim: The aim of this project is to showcase the use of a low-cost serial Bluetooth module
with the Raspberry Pi Pico.
● 217
Raspberry Pi Pico Essentials
• +3.3 V to +6 V operation
• 30 mA unpaired current (10 mA matched current)
• Built-in antenna
• Band: 2.40 GHz – 2.48 GHz
• Power level: +6 dBm
• Default communication: 9600 baud, 8 data bits, no parity, 1 stop bit
• Signal coverage 10 m (30 ft) approx.
• Safety features: authentication and encryption
• Modulation mode: Gaussian frequency-shift keying
Block Diagram: Figure 11.2 shows the block diagram of the project.
Circuit Diagram: Figure 11.3 shows the project circuit diagram. The RXD and TXD pins
of the Bluetooth module are connected to UART 0 pins GP0 (TX) and GP1 (RX) of the
Raspberry Pi Pico, respectively. The LED is connected to GP16 (pin 21) through a 470-ohm
current-limiting resistor.
● 218
Chapter 11 • Bluetooth with the Raspberry Pi Pico
Program listing: Check out Figure 11.4 (program: BlueLED). At the beginning of the
program the hardware UART interface is set to baud rate 9600, which is the default speed
of the HC-06. The LED is configured as an output and turned OFF. The remainder of the
program runs in an endless loop. Inside this loop data (commands) are received from the
Bluetooth device using a function call to readline. The data read is stored in list buf. The
program then controls the LED based on the received command. For example, L1 turns the
LED ON, L0 turns it OFF, and so on.
#----------------------------------------------------------
# BLUETOOTH COMMUNICATION
# =======================
#
# In this project a HC-06 type serial Bluetooth module and
# and LED are connected to the Raspberry Pi Pico. The LED
# is controlled by sending commands from a Bluetooth
# compatible smart phone.
#
# Author: Dogan Ibrahim
# File : BlueLED.py
# Date : February 2021
#------------------------------------------------------------
from machine import Pin, UART
import utime
#
# Main program loop. Receive a command and control the LED
#
● 219
Raspberry Pi Pico Essentials
while True:
buf = uart.readline() # Read data
dat = buf.decode(‘UTF-8’) # Decode
if dat[0] == ‘L’ and dat[1] == ‘1’: # L1?
LED.value(1) # LED ON
elif dat[0] == ‘L’ and dat[1] == ‘0’: # L0?
LED.value(0) # LED OFF
● 220
Chapter 11 • Bluetooth with the Raspberry Pi Pico
We can modify the program in Figure 11.5 by sending a confirmation to the smartphone
when there is change in the LED status. The required modifications are shown below:
while True:
buf = uart.readline() # Read data
dat = buf.decode('UTF-8') # Decode
if dat[0] == 'L' and dat[1] == '1': # L1?
LED.value(1) # LED ON
uart.write("LED is ON") # Send confirmation
elif dat[0] == 'L' and dat[1] == '0': # L0?
LED.value(0) # LED OFF
uart.write("LED is OFF") # Send confirmation
For example, as shown in Figure 11.7, the message LED is ON is displayed on the screen
after the command L1 is sent.
● 221
Raspberry Pi Pico Essentials
Aim: The aim of this project is to showcase data being sent from the Raspberry Pi Pico to
a smartphone at regular intervals.
Block Diagram: Figure 11.8 shows the block diagram of the project.
Circuit Diagram: Figure 11.9 shows the project circuit diagram. RXD and TXD pins of the
Bluetooth module are connected to UART 0 pins GP0 (TX) and GP1 (RX) of Raspberry Pi
Pico respectively.
Program listing: The program listing of the project is shown in Figure 11.10 (program:
BlueTemp). At the beginning of the program the hardware UART interface is set to baud
rate 9600, which is the default speed of the HC-06 module. The Function GetTemperature
returns the internal temperature of the Raspberry Pi Pico. Inside the main program loop the
temperature is read and sent to the smartphone every 10 seconds. Figure 11.11 shows the
temperature displayed on a smartphone using the Bluetooth Controller app described in
the previous section.
● 222
Chapter 11 • Bluetooth with the Raspberry Pi Pico
#----------------------------------------------------------
# SEND TEMPERATURE TO SMART PHONE
# ===============================
#
# In this project a HC-06 type serial Bluetooth module is
# connected to the Raspberry Pi Pico. Internal temperature
# readings are sent to a smart phone every 10 seconds
#
# Author: Dogan Ibrahim
# File : BlueTemp.py
# Date : February 2021
#------------------------------------------------------------
from machine import Pin, UART, ADC
import utime
def GetTemperature():
V = AnalogIn.read_u16()
V = V * Conv
Temp = 27 - (V - 0.706) / 0.001721
return Temp
#
# Send the temperature to smart phone
#
while True:
T = GetTemperature()
Temp = "T=" + str(T) + "\r\n"
uart.write(Temp)
utime.sleep(10)
● 223
Raspberry Pi Pico Essentials
● 224
Chapter 12 • Using Digital-to-Analogue Converters (DACs)
12.1 Overview
DACs are used to convert digital signals into analogue form. Such converters have many
applications in digital signal processing (DSP) and digital control applications. For exam-
ple, we can generate waveforms by writing programs and then 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 some other device operating with analogue voltages to our
Raspberry Pi Pico.
The Raspberry Pi Pico has no built-in ADC converter and consequently an external DAC chip
must be used to output analogue signals. In this Chapter we will be learning how to use a
popular DAC (the MCP4921) chip with our Raspberry Pi Pico to generate some simple signal
waveforms.
• 12-bit operation
• 20 MHz clock support
• 4.5 μs settling time
• external voltage reference input
• 1× or 2× gain, with control
• 2.7 V to 5.5 V supply voltage
• –40 ºC to +125 ºC temperature range
● 225
Raspberry Pi Pico Essentials
In this project we will be operating the MCP4921 with a gain of 1 (i.e. unity). As a result,
with a reference voltage of 3.3 V and 12-bit conversion data, the LSB resolution of the DAC
will be 3300 mV / 4096 = 0.8 mV.
Aim: The aim of this project is to show how a DAC chip can be interfaced to a Raspberry
Pi Pico.
Block Diagram: Figure 12.2 shows the block diagram of the project.
Circuit Diagram: The circuit diagram of the project is shown in Figure 12.3. Pins GP3
(SPI0 TX) and GP2 (SPIO SCK) are connected to MCP4921 pins SDI and SCK, respectively.
The CS of the MCP4921 is controlled separately from GP16 (pin 21). The output of the DAC
is connected to the oscilloscope.
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:
● 226
Chapter 12 • Using Digital-to-Analogue Converters (DACs)
In normal operation, we will send the upper byte (D8:D11) of the 12-bit (D0:D11) input
data with bits D12 and D13 set to 1 so that the device is active, and the gain is set to 1×.
Then we will send the low byte (D0:D7) of the data. This means that 0x30 should be added
to the upper byte before sending it to the DAC.
Program listing: Figure 12.4 shows the program listing (program: Square). Since we
are using a DAC with the reference voltage set to +3.3 V (3300 mV), and 12-bit wide data
(i.e. 4096 steps), the required digital value to set the output voltage to 2 V is given by
ONvalue, where:
The OFF value of the signal (OFFvalue) is set to 0 V. Function DAC configures the DAC so
that 2 V is output from it. First the HIGH byte (in buff[0]) is put into buffer buff, followed
by the LOW byte (in buff[1]):
The durations of the ON and OFF times are set to 1 ms. However, it was found by the
experiments that the DAC routine takes some time and because of this, the period and
consequently the frequency of the output waveform are not very accurate. The ON and
OFF times are slightly bigger than 1 ms. Readers can experiment to adjust the delay to get
exactly 1 ms if required.
#----------------------------------------------------------
# GENERATE SQUARE WAVE SIGNAL WITH AMPLITUDE +2V
# ==============================================
#
# In this project a MCP4921 type DAC chip is connected to the
# Raspberry Pi Pico.The program generates a square wave signal
# with frequency f=500Hz, 50% duty cycle (ON and OFF tiems equal
# and each 1ms), and 2V amplitude
#
# Author: Dogan Ibrahim
# File : Square.py
# Date : February 2021
#------------------------------------------------------------
from machine import Pin, SPI
● 227
Raspberry Pi Pico Essentials
import utime
spi = SPI(0,sck=spi_sck,mosi=spi_tx,miso=spi_rx,baudrate=100000)
CS = Pin(16, Pin.OUT) # CS
CS.value(1) # Disable chip
def DAC(data):
buff = [0, 0]
buff[0] = (data >> 8) & 0x0F # HIGH byte
buff[0] = buff[0] + 0x30
buff[1] = data & 0xFF # LOW byte
CS.value(0) # Enable MCP4921
spi.write(bytearray(buff)) # Send to SPI bus
CS.value(1) # DIsable MCP4921
#
# Main program
#
while True:
DAC(ONvalue)
utime.sleep_ms(1000)
DAC(OFFvalue)
utime.sleep_ms(1000)
Figure 12.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 1 ms/
division and the vertical axis was 1 V/division. The peak output voltage is 2 V as expected.
● 228
Chapter 12 • Using Digital-to-Analogue Converters (DACs)
#----------------------------------------------------------
# GENERATE SQUARE WAVE SIGNAL WITH AMPLITUDE +2V
# ==============================================
#
# In this project a MCP4921 type DAC chip is connected to the
# Raspberry Pi Pico.The program generates a square wave signal
# with frequency f=500Hz, 50% duty cycle (ON and OFF tiems equal
# and each 1ms), and 2V amplitude
#
# This version of the program uses timer interrupts
#
# Author: Dogan Ibrahim
# File : Square2.py
# Date : February 2021
#------------------------------------------------------------
from machine import Pin, SPI, Timer
#import utime
● 229
Raspberry Pi Pico Essentials
spi = SPI(0,sck=spi_sck,mosi=spi_tx,miso=spi_rx,baudrate=100000)
CS = Pin(16, Pin.OUT) # CS
CS.value(1) # Disable chip
tim = Timer()
flag = 0
#
# Timer interrupt service routine
#
def DAC(timer):
global flag, Onvalue, OFFvalue
global CS
buff = [0, 0]
if flag == 0:
data = ONvalue
flag = 1
else:
data = OFFvalue
flag = 0
buff[0] = (data >> 8) & 0x0F # HIGH byte
buff[0] = buff[0] + 0x30
buff[1] = data & 0xFF # LOW byte
CS.value(0) # Enable MCP4921
spi.write(bytearray(buff)) # Send to SPI bus
CS.value(1) # DIsable MCP4921
#
# Main program
#
tim.init(freq = 1000, mode = Timer.PERIODIC, callback = DAC)
Figure 12.7 shows the new output. Clearly, the period of the waveform is exactly 2 ms (i.e.
frequency of exactly 500 Hz).
● 230
Chapter 12 • Using Digital-to-Analogue Converters (DACs)
Program listing: Figure 12.8 shows the program listing (Program: FixedV). Function
'Voltage' converts the voltage into digital value for 12 bits and returns it to the main pro-
gram.
#----------------------------------------------------------
# GENERATE FIXED VOLTAGES
# =======================
#
# In this project a MCP4921 type DAC chip is connected to the
# Raspberry Pi Pico.The program generates fixed voltages with
# amplitues 0, 1, and 2V and the delay between each output
# being 100ms
#
# Author: Dogan Ibrahim
# File : FixedV.py
# Date : February 2021
#------------------------------------------------------------
from machine import Pin, SPI
import utime
spi = SPI(0,sck=spi_sck,mosi=spi_tx,miso=spi_rx,baudrate=100000)
● 231
Raspberry Pi Pico Essentials
CS = Pin(16, Pin.OUT) # CS
CS.value(1) # Disable chip
def Voltage(V):
Amplitude = int(V * 4095 / 3300)
return Amplitude
def DAC(data):
buff = [0, 0]
buff[0] = (data >> 8) & 0x0F # HIGH byte
buff[0] = buff[0] + 0x30
buff[1] = data & 0xFF # LOW byte
CS.value(0) # Enable MCP4921
spi.write(bytearray(buff)) # Send to SPI bus
CS.value(1) # DIsable MCP4921
#
# Main program
#
while True:
DAC(Voltage(0))
utime.sleep_ms(100)
DAC(Voltage(1000))
utime.sleep_ms(100)
DAC(Voltage(2000))
utime.sleep_ms(100)
DAC(Voltage(3000))
utime.sleep_ms(100)
● 232
Chapter 12 • Using Digital-to-Analogue Converters (DACs)
The block diagram and circuit diagram are as in Figure 12.2 and Figure 12.3, respectively.
Program listing: Figure 12.10 shows the program listing (Program: Sawtooth). Func-
tion 'Voltage' converts the voltage into digital value for 12 bits and returns it to the main
program. Notice that as described earlier, the timing of the generated signal is not very
accurate and timer interrupts can be used to generate accurate output.
#----------------------------------------------------------
# GENERATE SAWTOOTH WAVEFORM
# ==========================
#
# In this project a MCP4921 type DAC chip is connected to the
# Raspberry Pi Pico.The program generates sawtooth waveform
# having 10 steps
#
# Author: Dogan Ibrahim
# File : Sawtooth.py
# Date : February 2021
#------------------------------------------------------------
from machine import Pin, SPI
import utime
● 233
Raspberry Pi Pico Essentials
spi = SPI(0,sck=spi_sck,mosi=spi_tx,miso=spi_rx,baudrate=100000)
CS = Pin(16, Pin.OUT) # CS
CS.value(1) # Disable chip
def Voltage(V):
Amplitude = int(V * 4095 / 3300)
return Amplitude
def DAC(data):
buff = [0, 0]
buff[0] = (data >> 8) & 0x0F # HIGH byte
buff[0] = buff[0] + 0x30
buff[1] = data & 0xFF # LOW byte
CS.value(0) # Enable MCP4921
spi.write(bytearray(buff)) # Send to SPI bus
CS.value(1) # DIsable MCP4921
#
# Main program
#
k = 0.0
while True:
DAC(int(Voltage(k*3300)))
utime.sleep_ms(2)
k = k + 0.1
if k == 1.0:
k = 0.0
Figure 12.11 shows the generated output waveform. Here, the horizontal axis was 10 ms/
division, and the vertical axis, 1 V/division.
● 234
Chapter 12 • Using Digital-to-Analogue Converters (DACs)
Program listing: Figure 12.12 shows the program listing (Program: Triangle). Function
'Voltage' converts the voltage into digital value for 12 bits and returns it to the main pro-
gram.
#----------------------------------------------------------
# GENERATE TRIANGLE WAVEFORM
# ==========================
#
# In this project a MCP4921 type DAC chip is connected to the
# Raspberry Pi Pico.The program generates triangle waveform
#
# Author: Dogan Ibrahim
# File : Triangle.py
# Date : February 2021
#------------------------------------------------------------
from machine import Pin, SPI
import utime
spi = SPI(0,sck=spi_sck,mosi=spi_tx,miso=spi_rx,baudrate=100000)
CS = Pin(16, Pin.OUT) # CS
CS.value(1) # Disable chip
● 235
Raspberry Pi Pico Essentials
def Voltage(V):
Amplitude = int(V * 4095 / 3300)
return Amplitude
def DAC(data):
buff = [0, 0]
buff[0] = (data >> 8) & 0x0F # HIGH byte
buff[0] = buff[0] + 0x30
buff[1] = data & 0xFF # LOW byte
CS.value(0) # Enable MCP4921
spi.write(bytearray(buff)) # Send to SPI bus
CS.value(1) # DIsable MCP4921
#
# Main program
#
while True:
k = 0.0
while k < 1.0: # Going up
DAC(int(Voltage(k*3300)))
utime.sleep_ms(1)
k = k + 0.1
k = 1.0
while k > 0.0: # Going down
DAC(int(Voltage(k*3300)))
utime.sleep_ms(1)
k = k - 0.1
Figure 12.13 shows the generated output waveform. Notice again that as described earlier,
the timing of the generated signal is not very accurate and timer interrupts can be used to
generate accurate output.
● 236
Chapter 12 • Using Digital-to-Analogue Converters (DACs)
0 0 11 1.6
1 0.2 12 1.6
2 0.4 13 1.4
3 0.6 14 1.2
4 0.8 15 1.0
5 1.0 16 0.8
6 1.2 17 0.6
7 1.4 18 0.4
8 1.6 19 0.2
9 1.6 20 0.0
10 1.6
● 237
Raspberry Pi Pico Essentials
Aim: The aim of this project is to demonstrate how an arbitrary waveform can be gener-
ated.
The block diagram and circuit diagram are as in Figure 12.2 and Figure 12.3, respectively.
Program listing: Figure 12.15 shows the program listing (Program: Arbitrary). The volt-
age samples are stored in list Waveform. Inside the main program, a loop runs from 0 to
20 (inclusive), gets the required voltage amplitude at every sample and calls the DAC to
generate the required sample.
#----------------------------------------------------------
# GENERATE ARBITRARY WAVEFORM
# ===========================
#
# In this project a MCP4921 type DAC chip is connected to the
# Raspberry Pi Pico.The program generates an arbitarry waveform
# whose characteristics are defined in the text
#
# Author: Dogan Ibrahim
# File : Arbitrary.py
# Date : February 2021
#------------------------------------------------------------
from machine import Pin, SPI
import utime
import math
spi = SPI(0,sck=spi_sck,mosi=spi_tx,miso=spi_rx,baudrate=100000)
CS = Pin(16, Pin.OUT) # CS
CS.value(1) # Disable chip
Waveform = [0.0,0.2,0.4,0.6,0.8,1.0,1.2,1.4,1.6,1.6,1.6,1.6,1.6,
1.4,1.2,1.0,0.8,0.6,0.4,0.2,0.0]
def Voltage(V):
Amplitude = int(V * 4095 / 3.3)
return Amplitude
def DAC(data):
buff = [0, 0]
buff[0] = (data >> 8) & 0x0F # HIGH byte
buff[0] = buff[0] + 0x30
buff[1] = data & 0xFF # LOW byte
● 238
Chapter 12 • Using Digital-to-Analogue Converters (DACs)
#
# Main program
#
while True:
for k in range(21):
DAC(int(4095*Waveform[k]/3.3))
utime.sleep_ms(1)
Figure 12.16 shows the generated output waveform. Notice again that as described earlier,
the timing of the generated signal is not very accurate and timer interrupts can be used to
generate accurate output.
Program listing: Since the required frequency is 50 Hz, the period is 20 ms or 20,000 μs.
If we assume that the sinewave will consist of 100 samples, then each sample must be
output at 20,000 / 100 = 200 μs.
● 239
Raspberry Pi Pico Essentials
where, T is the period of the waveform and is equal to 100 samples. Count is a variable
that ranges from 0 to 100 and is incremented by 1, PeaktoPeak is the peak-to-peak am-
plitude, and Offset is the DC offset (this is necessary because the sinewave has negative
values, but the DAC only outputs positive values and therefore we have to shift the sine-
wave up by a DC offset).
The sum of Offset and Amplitude voltage must not be greater than +3.3 V, being the max-
imum output voltage the DAC can deliver, hence:
The sinewave is divided into 100 samples and each sample is output at 200 μs intervals.
The sine formula can be written as follows:
Therefore, at each sample, we will calculate and output the above value to the DAC.
Figure 12.17 shows the program listing (Program: Sine). At the beginning of the program
the peak-to-peak amplitude and the offset are defined and converted into digital values for
the DAC. The sine values are calculated outside the program loop and stored in list sins in
order to save time. Inside the main program the sine samples are sent to the DAC and are
then output.
#----------------------------------------------------------
# GENERATE SINE WAVEFORM
# ======================
#
# In this project a MCP4921 type DAC chip is connected to the
# Raspberry Pi Pico.The program generates a sine waveform with
# the specifications given in the text
#
# Author: Dogan Ibrahim
# File : Sine.py
# Date : February 2021
#------------------------------------------------------------
from machine import Pin, SPI
import utime
import math
● 240
Chapter 12 • Using Digital-to-Analogue Converters (DACs)
spi = SPI(0,sck=spi_sck,mosi=spi_tx,miso=spi_rx,baudrate=100000)
CS = Pin(16, Pin.OUT) # CS
CS.value(1) # Disable chip
R = 0.0628
T = 100
Conv = 4095.0 / 3.3
PeaktoPeak = 1.4 * Conv # 1.4V
ReqDCoffset = 1.0 * Conv # 1.6V
def DAC(data):
buff = [0, 0]
buff[0] = (data >> 8) & 0x0F # HIGH byte
buff[0] = buff[0] + 0x30
buff[1] = data & 0xFF # LOW byte
CS.value(0) # Enable MCP4921
spi.write(bytearray(buff)) # Send to SPI bus
CS.value(1) # DIsable MCP4921
#
# Main program
#
sins=[0]*101
while True:
for k in range(101):
value = sins[k]
DAC(int(value))
utime.sleep_us(200)
Figure 12.18 shows the generated output waveform. Here, the horizontal axis was 20 ms/
division, and the vertical axis was 1 V/division. The offset and the peak-to-peak amplitude
of the waveform are correct, but as described earlier the timing of the generated signal is
not very accurate and timer interrupts can be used to generate accurate output.
● 241
Raspberry Pi Pico Essentials
Program listing: Figure 12.19 shows the program listing (Program: Sineint).
#----------------------------------------------------------
# GENERATE SINE WAVEFORM
# ======================
#
# In this project a MCP4921 type DAC chip is connected to the
# Raspberry Pi Pico.The program generates a sine waveform with
# the specifications given in the text
#
# This program uses timer interrupts for accurate timings
#
# Author: Dogan Ibrahim
# File : Sineint.py
# Date : February 2021
#------------------------------------------------------------
from machine import Pin, SPI, Timer
import utime
import math
● 242
Chapter 12 • Using Digital-to-Analogue Converters (DACs)
tim = Timer()
spi_sck = Pin(2) # SCK pin at GP2
spi_tx = Pin(3) # TX pin at GP3
spi_rx = Pin(0) # RX pin at GP0 (not used)
spi = SPI(0,sck=spi_sck,mosi=spi_tx,miso=spi_rx,baudrate=100000)
CS = Pin(16, Pin.OUT) # CS
CS.value(1) # Disable chip
R = 2 * 3.14159/50
T = 100
Conv = 4095.0 / 3.3
PeaktoPeak = 1.4 * Conv # 1.4V
ReqDCoffset = 1.0 * Conv # 1.6V
k = 0
def DAC(timer):
global k, CS, sins
buff = [0, 0]
k = k + 1
if k == 50:
k = 0
data = int(sins[k])
buff[0] = (data >> 8) & 0x0F # HIGH byte
buff[0] = buff[0] + 0x30
buff[1] = data & 0xFF # LOW byte
CS.value(0) # Enable MCP4921
spi.write(bytearray(buff)) # Send to SPI bus
CS.value(1) # DIsable MCP4921
#
# Main program
#
sins=[0]*101
Figure 12.20 shows the output waveform. Here, the horizontal axis was10 ms/division and
the vertical axis was 1 V/division. Clearly, the period of the waveform is exactly 20 s as
required, the offset is 1 V and the peak-to-peak amplitude is 1.4 V.
● 243
Raspberry Pi Pico Essentials
● 244
Chapter 13 • Automatic Program Execution after the Raspberry Pi Pico Boots
There may be applications where we may want to start a program automatically after the
Raspberry Pi Pico boots. Perhaps the easiest way to learn how this is done is to give a very
simple example. The program shown in Figure 13.1 flashes an LED connected to port pin
GP6 every second. We will configure the Raspberry Pi Pico so that the LED starts flashing
immediately after the Pico boots.
#----------------------------------------------------------
# RUNNING A PROGRAM AUTOMATICALLY AFTER REBOOT
# ===========================================
#
# In some applications we may want to run a program
# automatically after reboot.This is done easily by saving
# the program with the name "main.py". This very simple
# program flashes an LED connected to GP16 automatically
# after the Raspberry Pi Pico boots.
#
# Author: Dogan Ibrahim
# File : main.py
# Date : February 2021
#------------------------------------------------------------
from machine import Pin
import utime
• Give a name to your program and run it to make sure that there are no errors,
and it runs as expected (in this case, the LED flashes every second).
• Stop the program by clicking menu item Run in Thonny, followed by Stop/Re-
start backend.
• Click File followed by Save as, then click Raspberry Pi Pico (Figure 13.2) to
save the file in the Raspberry Pi Pico memory.
● 245
Raspberry Pi Pico Essentials
• Reboot your Raspberry Pi Pico and you should see the LED flashing as soon as
the Pico boots.
• You can stop the program out of Thonny by clicking Run, followed by Stop/
Restart backend.
• You should either remove or rename file main.py if you do not want it to start
automatically.
That's it! From now on, you can make your Raspberry Pi Pico auto-execute a suitable pro-
gram, immediately after booting.
● 246
Appendix A • Bill of Components
• 1× Raspberry Pi Pico
• 1× ESP-01 *
• 1× Arduino UNO *
• 1× Raspberry Pi 4 *
● 247
Raspberry Pi Pico Essentials
Index E
EEPROM memory 177
Symbols echo 111
7-segment 84 ESP-01 206
24LC256 177 external temperature 133
A F
Accessories 25 Feather RP2040 17
accurate sinewave 242 File processing 43
Active buzzers 55 Flash memory 12, 16
ADC3 14 Frequency generator 150
ADC inputs 15
Arbitrary periodic waveform 237 H
Arduino UNO 13 HC-06 217
atmospheric pressure 188 HC-SR04 109
HD44780 98
B
BC108 88 I
Binary-counting 69 I2C bus 170
Bluetooth 217 I2C pins 171
Bluetooth Controller 220 import machine 49
BMP280 188 INDEX.HTM 24, 29
Bootloader 16 INFO_UF2.TXT 24
BOOTSEL 11, 23, 29 internal temperature sensor 119
brushed DC motor 149
K
C keypad 20
Calculator 41 KY-013 135
common-anode 85 KY-021 80
common-cathode 85 KY-034 80
Cortex-M0+ 11
cosine 38 L
CPHA 199 LDR 128
CPOL 199 light intensity 128
current-sinking 52
current-sourcing 52 M
machine 48
D magnetic field 81
DACs 225 matrices 46
Data Logging 140 MCP23S17 200
DC56-11EWA 87 MCP4921 225
dice 74 Melody 154
Dice 42 Memory-read 180
distance measurement 108 Memory-write 179
Door alarm 80 MicroMod M.2 connector 20
micro-USB 11
● 248
Index
● 249
Raspberry Pi Pico Essentials
● 250
books
books
Raspberry Pi Pico Essentials
Raspberry Pi Pico
Essentials
Program, build, and master over 50 projects with
MicroPython and the RPi ‘Pico’ microprocessor
The Raspberry Pi Pico is a high-performance microcontroller module
designed especially for physical computing. Microcontrollers differ from
single-board computers, like the Raspberry Pi 4, in not having an operating
system. The Raspberry Pi Pico can be programmed to run a single task very Prof. Dr. Dogan Ibrahim has a
efficiently within real-time control and monitoring applications requiring BSc, Hons. degree in Electronic
speed. The ‘Pico’ as we call it, is based on the fast, efficient, and low-cost Engineering, an MSc degree in
Automatic Control Engineering,
dual-core ARM Cortex-M0+ RP2040 microcontroller chip running at up to
and a PhD degree in Digital Signal
133 MHz and sporting 264 KB of SRAM, and 2 MB of Flash memory. Besides Processing.
its large memory, the Pico has even more attractive features including a
vast number of GPIO pins, and popular interface modules like ADC, SPI, Dogan has worked in many
I2C, UART, and PWM. To cap it all, the chip offers fast and accurate timing industrial organizations before
he returned to academic life. He
modules, a hardware debug interface, and an internal temperature sensor.
is the author of over 70 technical
books and has published over 200
The Raspberry Pi Pico is easily programmed using popular high-level langua- technical articles on electronics,
ges such as MicroPython and or C/C++. This book is an introduction to microprocessors, microcontrollers,
using the Raspberry Pi Pico microcontroller in conjunction with the Micro- and related fields.
Python programming language. The Thonny development environment
(IDE) is used in all the projects described. There are over 50 working and
tested projects in the book, covering the following topics:
> Installing the MicroPython > Datalogging projects
on Raspberry Pi Pico using a > PWM, UART, I2C, and SPI
Raspberry Pi or a PC projects
> Timer interrupts and external > Using Wi-Fi and apps to
interrupts communicate with smartphones
> Analogue-to-digital converter > Using Bluetooth and apps to
(ADC) projects communicate with smartphones
> Using the internal temperature > Digital-to-analogue converter
sensor and external tempera- (DAC) projects
ture sensor chips
All projects given in the book have been fully tested and are working. Elektor International Media BV
Only basic programming and electronics experience is required to follow www.elektor.com
the projects. Brief descriptions, block diagrams, detailed circuit diagrams,
and full MicroPython program listings are given for all projects described.
Readers can find the program listings on the Elektor web page created to
support the book.
● 496