MicroPython for Microcontrollers: Projects with Thonny-IDE, uPyCraft-IDE, and ESP32 9783895764370

The "Python" programming language has enjoyed an enormous upswing in recent years. Not least, various single-b

1,762 138 10MB

English Pages 229 Year 2021

Report DMCA / Copyright

DOWNLOAD PDF FILE

Table of contents :
Content
Notices and Disclaimers
Demo Programs Download Archive
Chapter 1 • Introduction
1.1 Python, C, or Arduino?
1.2 Requirements
Chapter 2 • A Variety of ESP Boards
2.1 Commissioning and function test
2.2 ESP32 on battery power
Chapter 3 • Programming and Development Environments
3.1 Installing the uPyCraft IDE
3.2 MicroPython for the ESP32
3.3 "Hello World" for the controller
3.4 For professionals: Working with esptool
3.5 Thonny — a Python-IDE for beginners
3.6 Working with Thonny
3.7 Working with files
3.8 Troubleshooting tips for the Thonny IDE
Chapter 4 • First Steps in Programming
4.1 Never without: Comments
4.2 The Print() statement
4.3 Indentations and blocks
4.4 The hardware under control: digital inputs and outputs
4.5 Time control and sleep
4.6 Important values: variables and constants
4.7 Numbers and types of variables
4.8 Converting number types
4.9 Little Big Data: Arrays
4.10 Operators
4.11 With format, please: appealing text and data output
4.12 Characters in chains: strings
Chapter 5 • The Controller in Practical Use
5.1 LED flasher as alarm system simulator
5.2 Useful in an emergency: automatic SOS signal
Chapter 6 • Program Structures
6.1 Conditions and loops
6.2 Running lights and airport lighting
6.3 Electronic rainbow: RGB LED in use
6.4 SOS compact-style
6.5 Trial and error: try and except
Chapter 7 • Analogue-Signal Generation
7.1 Pulsewidth modulation
7.2 For romantic evenings: heartbeat simulator
7.3 Light alarm clock for a relaxed wake-up
7.4 Mood-Light with multicolour LED
7.5 Clean and smooth: analogue values from the DAC
7.6 Output of time-dependent voltages
7.7 For interesting curves: An arbitrary function generator
Chapter 8 • Interrupts and Timers
8.1 Disruption wanted: Interrupts
8.2 Automatic night light
8.3 Masters of Time: Timers
8.4 A multifunctional flashing light
Chapter 9 • Using Sensors
9.1 Acquisition of measurement and sensor values
9.2 Precise recording of voltages: a DIY voltmeter
9.3 Linearity correction
9.4 Linearization by limitation of the value range
9.5 Linearization of the ADC input by means of compensation polunomial
9.6 Voltage measurement
9.7 Cross-interferences: side effects in sensor technology
9.8 Touching permitted: capacitive touch sensors
9.9 Well chilled or overheated: temperature sensors provide clarity
9.10 Digital temperature recording for error-free data transmission
9.11 The DS18×20 One-Wire sensor
9.12 Data power: multi-sensor array with the DS18x20 thermal sensor
9.13 In full view: optical sensors
9.14 For film and photo professionals: electronic luxmeter
9.15 Electronic bats: distance measurement with ultrasound
9.16 No more dents and scratches: distance warning device for garages
9.17 Optimum indoor climate for flora and fauna
9.18 "Trust me ...": sensor comparison
9.19 Air pressure and altitude measurement
9.20 Detecting magnetic fields with the Hall sensor
9.21 Alarm detectors monitor door and gate
Chapter 10 • Display Technology and Small-Size Screens
10.1 Graphical representations
10.2 OLED display as data plotter
10.3 The exact time please: digital clock with OLED display
10.4 Not just for athletes: a stopwatch
10.5 Just touch: stop watch with sensor keys
10.6 Great climate with the BME280 sensor!
Chapter 11 • LED Matrices and Large Displays
11.1 LED matrix in action
11.2 Running scripts and animated graphics
Chapter 12 • Physical Computing: Servos bring movement into play
12.1 A servo tester
12.2 Mega-display servo thermometer
Chapter 13 • RFID and Wireless Data Transmission
13.1 Reading cards and chips
13.2 Contactless and secure: RFID lock
Chapter14 • MicroPython and the Internet of Things (IoT)
14.1 For modern detectives: a network scanner
14.2 Connected but no cables: WLAN
14.3 Switch and control with the web server
14.4 The WLAN web server in action
14.5 Reading out sensor data via WLAN
14.6 Recording environmental parameters: WLAN Thermo/Hygrometer
Chapter 15 • Simple and Good: The MQTT Protocol
15.1 MQTT via ThingSpeak
Chapter 16 • Sending Data to the Internet via ThingSpeak
16.1 Rain or storm? Virtual weather station available worldwide
16.2 Graphical representation of data in ThingSpeak
16.3 Data for the smartphone with the ThingView app
16.4 Against unwanted visitors: Optical room surveillance
Chapter 17 • Micropower Techniques and Sleep Modes
17.1 Saving power protects the environment: low-power technologies
17.2 Disabling unnecessary consumers
17.3 Weather station with battery or solar operation
Chapter 18 • Bus Systems for Efficient Communication
18.1 Basics and applications of the I²C bus
18.2 The SPI bus
18.3 The members of the SPI family
18.4 Controlling SD and µSD cards via SPI
Chapter 19 • Building Circuits with Components and Breadboards
19.1 Breadboards
19.2 Wire jumpers and jumper cables
19.3 Resistors
19.4 Light-emitting diodes (LEDs)
19.5 Capacitors and electrolytic capacitors
Chapter 20 • Troubleshooting
Chapter 21 • Hardware Resources
Chapter 22 • List of Figures
Chapter 23 • Bill of Materials
Index
Recommend Papers

MicroPython for Microcontrollers: Projects with Thonny-IDE, uPyCraft-IDE, and ESP32
 9783895764370

  • 0 0 0
  • Like this paper and download? You can publish your own PDF file online for free in a few minutes! Sign Up
File loading please wait...
Citation preview

books

MicroPython for Microcontrollers Projects with Thonny-IDE, uPyCraft-IDE, and ESP32

Günter Spanner

MicroPython for Microcontrollers Projects with Thonny-IDE, uPyCraft-IDE, and ESP32

● Dr Günter Spanner

● 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.

● British Library Cataloguing in Publication Data

A catalogue record for this book is available from the British Library

● ISBN 978-3-89576-436-3 Print

ISBN 978-3-89576-437-0 eBook ISBN 978-3-89576-438-7 ePub

● © Copyright 2021: Elektor International Media B.V. Translation: Carmen Jacquemijns Editor: Jan Buiting Prepress Production: D-Vision, Julian van den Berg

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 Notices and Disclaimers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 Demo Programs Download Archive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 Chapter 1 • Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 1.1 Python, C, or Arduino? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 1.2 Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 Chapter 2 • A Variety of ESP Boards . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 2.1 Commissioning and function test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 2.2 ESP32 on battery power . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 Chapter 3 • P  rogramming and Development Environments . . . . . . . . . . . . . . . . . . 19 3.1 Installing the uPyCraft IDE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 3.2 MicroPython for the ESP32 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 3.3 "Hello World" for the controller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 3.4 For professionals: Working with esptool . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 3.5 Thonny — a Python-IDE for beginners . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 3.6 Working with Thonny . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 3.7 Working with files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 3.8 Troubleshooting tips for the Thonny IDE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 Chapter 4 • First Steps in Programming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 4.1 Never without: Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 4.2 The Print() statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 4.3 Indentations and blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 4.4 The hardware under control: digital inputs and outputs . . . . . . . . . . . . . . . . . . . . 45 4.5 Time control and sleep . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 4.6 Important values: variables and constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 4.7 Numbers and types of variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 4.8 Converting number types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 4.9 Little Big Data: Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 4.10 Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 4.11 With format, please: appealing text and data output . . . . . . . . . . . . . . . . . . . . . . . 55 4.12 Characters in chains: strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 Chapter 5 • The Controller in Practical Use . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 5.1 LED flasher as alarm system simulator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60

●5

MicroPython for Microcontrollers 5.2 Useful in an emergency: automatic SOS signal . . . . . . . . . . . . . . . . . . . . . . . . . . 61 Chapter 6 • Program Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 6.1 Conditions and loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 6.2 Running lights and airport lighting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 6.3 Electronic rainbow: RGB LED in use . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66 6.4 SOS compact-style . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 6.5 Trial and error: try and except . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 Chapter 7 • Analogue-Signal Generation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 7.1 Pulsewidth modulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 7.2 For romantic evenings: heartbeat simulator . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 7.3 Light alarm clock for a relaxed wake-up . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 7.4 Mood-Light with multicolour LED . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 7.5 Clean and smooth: analogue values from the DAC . . . . . . . . . . . . . . . . . . . . . . . 76 7.6 Output of time-dependent voltages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 7.7 For interesting curves: An arbitrary function generator . . . . . . . . . . . . . . . . . . . . 78 Chapter 8 • Interrupts and Timers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 8.1 Disruption wanted: Interrupts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 8.2 Automatic night light . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82 8.3 Masters of Time: Timers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 8.4 A multifunctional flashing light . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 Chapter 9 • Using Sensors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90 9.1 Acquisition of measurement and sensor values . . . . . . . . . . . . . . . . . . . . . . . . . 90 9.2 Precise recording of voltages: a DIY voltmeter . . . . . . . . . . . . . . . . . . . . . . . . . . 92 9.3 Linearity correction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 9.4 Linearization by limitation of the value range . . . . . . . . . . . . . . . . . . . . . . . . . . . 96 9.5 Linearization of the ADC input by means of compensation polynomial . . . . . . . . . . 97 9.6 Voltage measurement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 9.7 Cross-interferences: side effects in sensor technology . . . . . . . . . . . . . . . . . . . . 101 9.8 Touching permitted: capacitive touch sensors . . . . . . . . . . . . . . . . . . . . . . . . . 102 9.9 Well chilled or overheated: temperature sensors provide clarity . . . . . . . . . . . . . 105 9.10 Digital temperature recording for error-free data transmission . . . . . . . . . . . . . 108 9.11 The DS18×20 One-Wire sensor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108

●6

Content 9.12 Data power: multi-sensor array with the DS18x20 thermal sensor . . . . . . . . . . 110 9.13 In full view: optical sensors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112 9.14 For film and photo professionals: electronic luxmeter . . . . . . . . . . . . . . . . . . . 113 9.15 Electronic bats: distance measurement with ultrasound . . . . . . . . . . . . . . . . . . 115 9.16 No more dents and scratches: distance warning device for garages . . . . . . . . . 119 9.17 Optimum indoor climate for flora and fauna . . . . . . . . . . . . . . . . . . . . . . . . . . 121 9.18 "Trust me ...": sensor comparison . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125 9.19 Air pressure and altitude measurement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126 9.20 Detecting magnetic fields with the Hall sensor . . . . . . . . . . . . . . . . . . . . . . . . 129 9.21 Alarm detectors monitor door and gate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130 Chapter 10 • Display Technology and Small-Size Screens . . . . . . . . . . . . . . . . . . 132 10.1 Graphical representations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135 10.2 OLED display as data plotter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138 10.3 The exact time please: digital clock with OLED display . . . . . . . . . . . . . . . . . . 140 10.4 Not just for athletes: a stopwatch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 10.5 Just touch: stop watch with sensor keys . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145 10.6 Great climate with the BME280 sensor! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148 Chapter 11 • LED Matrices and Large Displays . . . . . . . . . . . . . . . . . . . . . . . . . . . 150 11.1 LED matrix in action . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152 11.2 Running scripts and animated graphics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153 Chapter 12 • Physical Computing: Servos Bring Movement into Play . . . . . . . . . 155 12.1 A servo tester . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155 12.2 Mega-display servo thermometer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158 Chapter 13 • RFID and Wireless Data Transmission . . . . . . . . . . . . . . . . . . . . . . . 161 13.1 Reading cards and chips . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162 13.2 Contactless and secure: RFID lock . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164 Chapter 14 • MicroPython and the Internet of Things (IoT) . . . . . . . . . . . . . . . . 167 14.1 For modern detectives: a network scanner . . . . . . . . . . . . . . . . . . . . . . . . . . . 168 14.2 Connected but no cables: WLAN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169 14.3 Switch and control with the web server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172 14.4 The WLAN web server in action . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176 14.5 Reading out sensor data via WLAN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177

●7

MicroPython for Microcontrollers 14.6 Recording environmental parameters: WLAN Thermo/Hygrometer . . . . . . . . . . 179 Chapter 15 • Simple and Good: The MQTT Protocol . . . . . . . . . . . . . . . . . . . . . . . 183 15.1 MQTT via ThingSpeak . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185 Chapter 16 • Sending Data to the Internet via ThingSpeak . . . . . . . . . . . . . . . . . 190 16.1 Rain or storm? Virtual weather station available worldwide . . . . . . . . . . . . . . . 190 16.2 Graphical representation of data in ThingSpeak . . . . . . . . . . . . . . . . . . . . . . . 194 16.3 Data for the smartphone with the ThingView app . . . . . . . . . . . . . . . . . . . . . . 195 16.4 Against unwanted visitors: Optical room surveillance . . . . . . . . . . . . . . . . . . . 196 Chapter 17 • Micropower Techniques and Sleep Modes . . . . . . . . . . . . . . . . . . . . 199 17.1 Saving power protects the environment: low-power technologies . . . . . . . . . . . 199 17.2 Disabling unnecessary consumers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200 17.3 Weather station with battery or solar operation . . . . . . . . . . . . . . . . . . . . . . . 201 Chapter 18 • Bus Systems for Efficient Communication . . . . . . . . . . . . . . . . . . . 202 18.1 Basics and applications of the I²C bus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202 18.2 The SPI bus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207 18.3 The members of the SPI family . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210 18.4 Controlling SD and µSD cards via SPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210 Chapter 19 • Building Circuits with Components and Breadboards . . . . . . . . . . . 212 19.1 Breadboards . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213 19.2 Wire jumpers and jumper cables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214 19.3 Resistors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215 19.4 Light-emitting diodes (LEDs) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216 19.5 Capacitors and electrolytic capacitors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217 Chapter 20 • Troubleshooting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219 Chapter 21 • Hardware Resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220 Chapter 22 • List of Figures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221 Chapter 23 • Bill of Materials . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225 Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226

●8

Notices and Disclaimers

Notices and Disclaimers 1. The circuits in this book are for educational purposes only. 2. The circuits in this book may only be operated with batteries and/or tested, double insulated safety power supplies. Insulation faults of a simple power supply unit can lead to life-threatening voltages on non-insulated components. 3. Powerful LEDs can cause eye damage. Never look directly into an LED! 4. Neither the Author or the Publisher accept any liability for damage resulting from the construction of the described projects, or attempts to do so. 5. Electronic circuits can emit electromagnetic interference radiation. Since neither the Publisher or the Author have any influence on the user's skills in assembling, operating, and controlling electronic circuits, the user alone is responsible for compliance with the relevant emission limit values.

●9

MicroPython for Microcontrollers

Demo Programs Download Archive The demo programs mentioned in this book can downloaded free of charge as a single archive file (.zip) from the book resources web page: www.elektor.com/micropython-for-microcontrollers If a program from the download archive file appears to differ from the version described in the book, the downloaded version should be used as it may reflect updates made by the author since printing the book.

● 10

Chapter 1 • Introduction

Chapter 1 • Introduction The introduction of the ESP32 chip from Espressif Systems marks a new generation of microcontrollers, which offer excellent performance, Wi-Fi, and Bluetooth functionality at an unrivalled price. These features have taken the maker scene by storm. The most diverse applications and projects in the areas of Internet of Things (IoT) and home automation can be implemented easily and cost-effectively. The ESP32 is as easy to program as the classic Arduino boards. In comparison, however, the ESP32 also offers, among other things: • Larger flash and SRAM memory • Much higher CPU speed • Integrated Wi-Fi / WLAN • Bluetooth functionality • More GPIO pins • Extensive interface functionality • Analogue/digital converter with higher resolution • Digital/analogue converter • Security and encryption functions For these reasons, it can be considered the most promising successor to Arduino. The term "Arduino killer" is often used in this context. This book introduces the programming of modern single-chip systems (Systems on Chip — SoCs). In addition to the technical background, the focus is on the programming language Python, especially in its variant "MicroPython". Basic relationships between electronics and electrical engineering will only be dealt with to the extent that it is essential for the design of the circuits and experiments. The "hardware" for getting started can be kept very simple anyway. At first, only a controller board and some light emitting diodes as well as suitable series resistors are required. The PC or laptop required for programming the chip should be available in every household. The appropriate programming environment can be downloaded free of charge from the internet. When working with a MicroPython programming environment, however, the first problems quickly arise. A good introduction can therefore lead to excellent performances. Python has experienced an enormous upswing in recent years. Various single-board systems like the Raspberry Pi have especially contributed to its popularity. But Python has also found widespread use in other areas such as artificial intelligence or machine learning. Hence it is a logical choice to use Python or the variant MicroPython for the application in SoCs, too. However, we will not restrict ourselves to a mere introduction to the programming language. In many cases, the learned programming skills are put into practice together with electronic circuitry. The fully described projects are all suitable for use in laboratories or in everyday life. In addition to the educational effect, the pleasure of assembling complete and useful devices is therefore also in the foreground. Through the use of laboratory plug-in boards, circuits of all kinds can be realised with little effort. The testing

● 11

MicroPython for Microcontrollers

and trial of applications thus becomes an educational pleasure. Due to the various applications such as weather stations, digital voltmeters and function generators, the presented projects are also ideally suited for internships or study courses in the natural sciences or in science and technology lessons.

1.1 Python, C, or Arduino? For beginners, the Arduino programming environment is one of the easiest places to program the ESP32. Behind this interface is the Arduino version of C, as well as C++. These two programming languages have been popular for years for the development of embedded systems. The Arduino version of C made it even easier to get started. In addition, one of the largest technology communities in the world developed for this purpose. With new libraries, software fixes and board support, problems could usually be solved quickly. However, the restriction that Arduino-C only works in its designated environment is not insignificant. Especially for the development of more extensive projects, useful and important functions are missing. Therefore, Arduino-C remained mostly limited to hobby and beginner projects. MicroPython is relatively new. The user community is growing, and more and more platforms are supported. MicroPython is essentially a slim version of Python, one of the most popular programming languages in the world. Therefore, specific problems can be dealt with not only in MicroPython communities. In fact, general Python forums are increasingly contributing to solving MicroPython issues. In addition to community support, MicroPython also has certain features that put it well above the class of the Arduino. One of these features is the so-called REPL function. REPL stands for "Read-Evaluate-Print Loop". This allows programs and code sections to be executed quickly. Compiling or uploading is not necessary. In this way, parts of a code can be tested quickly and efficiently during development. MicroPython contains a very compact implementation of the Python interpreter. It requires only 256 KB flash memory and 16 KB RAM. Nevertheless the interpreter is designed for maximum compatibility with the standard Python. Syntax and language range correspond largely to Python version 3.4, so experienced Python programmers should be able to find their way around immediately. In addition, a few language elements beyond the standard are defined, which keep the memory requirements low and increase the execution speed.

1.2 Requirements In order to work successfully with this book, the following requirements should be met: • Secure handling of the Windows operating system; • Basic knowledge of any programming language such as C, Java or similar; • Basic knowledge in the field of electronics, especially in the area of "current — voltage — resistance" is assumed. For specialized knowledge in the field of electronics, please refer to the extensive technical literature, especially from Elektor, through their books, magazines, and kits. The hardware

● 12

Chapter 1 • Introduction

structure was deliberately kept simple, as the focus should be on programming with MicroPython. Nevertheless, different components and parts are required. Explanations can be found in the individual chapters in which the components are used first. In addition, the last sections of the book explain some basic components such as resistors or light emitting diodes. You can consult these if there are any unclarities concerning individual components. Further requirements are • a PC or laptop with USB interface, • the Windows 10 operating system, • internet access. It is also useful to employ an active USB hub between the computer and the controller. This has the advantage that it guarantees a certain protection for the PC. The hub should have its own 5 V power supply through a separate power supply unit. Then the PC or laptop is best protected against short-circuits behind the hub, as it is very unlikely that a short circuit will "blow through" an active hub to the USB port of the computer.

● 13

MicroPython for Microcontrollers

Chapter 2 • A Variety of ESP Boards The ESP32 is a modern and extremely powerful microcontroller. In addition to a high clock frequency and the extensive internal functional units, the chip has integrated Wi-Fi and Bluetooth. The controller was developed by Espressif Systems, a Chinese company based in Shanghai, and is enjoying increasing popularity. The performance features of the ESP far exceed the well-known Arduino boards in terms of price and performance. As the ESP32 is only available as an SMD chip, a so-called break-out board (BoB) or development board is required if the controller is to be used in a non-professional environment. In the meantime, a virtually unmanageable variety of different versions is available on the market. The best-known versions are: Board

Pins

Buttons

LiPo Charger

ESP32-PICO-KIT

34

EN and BOOT

no

JOY-iT NodeMCU

30

EN and BOOT

no

ESP32 DEV KIT DOIT

30/36

EN and BOOT

no

Adafruit HUZZAH32

28

RESET

yes

ESP32 Thing

40

EN and BOOT

yes

LOLIN32

40

EN and BOOT

no

Node-ESP-Board

38

EN and BOOT

no

The following image shows just three different versions:

Figure 2.1: ESP32 boards (PICO-KIT, Node-ESP and NodeMCU). These boards have the necessary prerequisites to operate the ESP controller on a solderless plug-in board or breadboard. Frequently, in addition to the controller, other components such as pushbuttons, a Li-ion battery charger, or various LEDs are mounted on the boards

● 14

Chapter 2 • A Variety of ESP Boards

available. This means that initial tests and experiments can be carried out without external circuitry. The following section summarizes the most important data about ESP32. The overview should only provide a first impression. A deeper understanding of the individual features and functions is then provided in the relevant sections in the book. Processor: 160 / 240 MHz Tensilica LX6 dual-core microprocessor Memory: 520 KByte SRAM / 16 MByte Flash memory Power supply: 2.2 V to 3.6 V Power consumption: Standard: approx. 50 - 70 mA Wi-Fi mode: approx. 80 - 170 mA Deep sleep mode: approx. 2.5 µA Ambient temperature: –40 °C to +125 °C Inputs/Outputs (GPIOs): 32 general purpose ports with PWM Function and timer logic Wi-Fi: 802.11 b/g/n/e/i Network throughput: 135 MBit/s (via UDP protocol) Receiver sensitivity: –98 dBm Bluetooth: V4.2 BR/EDR and BLE Bluetooth functionality: Classic and Bluetooth Low Energy (with integrated antenna) Sensors: Hall sensor 10× capacitive touch sensor Interfaces: 3× UART with flow control via hardware 3x SPI interfaces CAN bus 2.0 controller 2× I2S and 2xI2C interfaces 18 analogue inputs with 12-bit analogue-to-digital converters 2 analogue outputs with 10-bit digital-to-analogue converters Infrared (IR) (TX/RX) Motor PWM LED-PWM with up to 16 channels Interface for external SPI flash memory for up to 16 MB SD card hardware Security: Wi-Fi: WFA, WPA/WPA2 and WAPI Secure Boot Flash Encryption Cryptographic Hardware Acceleration Elliptic Curve Cryptography (ECC) Random Number Generator (RNG) The ESP32-PICO-KIT is usually employed for the application examples in this book. Alternatively the ESP32 DEV KIT or another board can be used. The variant used is mentioned explicitly in each case. In principle, however, the various boards are largely compatible. They differ mainly in size and in pin arrangement order. Figure 2.2. shows the PICO-KIT with its functional units and connections.

● 15

MicroPython for Microcontrollers

Figure 2.2: ESP32 PICO-KIT board. The breakout boards are best suited as experimental and development boards. Via the port connections, electronic components such as LEDs, temperature sensors or even smaller actuators such as R/C model servos can be connected directly. The Pico Kit board has the following features, among others: • ESP controller with two 32-bit cores • Fast Wi-Fi and WLAN interface (up to 150 MBit/s) • ADC & DAC functionality • Touch Sensor Unit • Host Controller for SD/SDIO/MMC • SDIO/SPI Controller • EMAC and PWM unit for controlling LEDs and motors • UART, SPI, I²C and I²S interfaces • Infrared remote-control controller • GPIO Interface • Bluetooth/Bluetooth LE (4.2) • USB-to-Serial-Chip for access via USB interface

2.1 Commissioning and function test As soon as a board is available, it should be subjected to an initial functional test. For this purpose, a USB cable is connected to a PC or laptop and the micro-USB socket of the board. If present, a USB hub should already be connected in between. On most boards, an LED will light up when connected to a powered USB port. If, contrary to expectations, this so-called "power-on" LED does not light up, the USB connection should be disconnected immediately. In this way you can prevent a possible short circuit from causing major damage. For further troubleshooting, helpful hints are given in the corresponding chapter at the end of the book. ESP boards should always be operated in a solderless plug-in board (see Figure 2.3). However, if you do work without a breadboard, make sure that the base used is not conductive,

● 16

Chapter 2 • A Variety of ESP Boards

otherwise short circuits between the pins may occur. Next to the ESP board itself, this can even destroy the USB port of the PC.

Figure 2.3: ESP board plugged into a breadboard.

2.2 ESP32 on battery power In most cases, an ESP board is supplied with power via the Micro-USB socket. Since the controller is connected to a PC or laptop during program creation anyway, no additional power supply is required. If a direct data exchange with the PC is no longer necessary, the board can also be supplied by a USB power supply. This should be able to supply at least 1,000 mA (1 A; 1 amp) of current output to avoid unwanted voltage drops. In addition, there is a certain amount of reserve power to operate some LEDs, displays or sensors. Even without a USB connection, the board can send and receive data via Wi-Fi and Bluetooth. In order to achieve complete independence from power and data cables, the module then only needs to be powered by (rechargeable) batteries. Some boards have a Lithium-Ion (Li-Ion) battery connector for this purpose (see Figure 2.4). There, suitable cells can be connected directly via the standard plug. An internal voltage regulation then ensures that the controllers are optimally supplied. In addition, a connected battery is charged as soon as the board is connected to a live USB socket. For this application, cells with a capacity of about 1,500 mAh or more are suitable. Smaller batteries below 300 mAh should not be used, as they could be overcharged by the integrated charge controller. With a typical power consumption of approx. 50 mA, the 1,500 mAh variant can achieve an operating time of around 30 hours, i.e. just over a day. When using the controller's sleep functions, even considerably longer operating times can be achieved.

● 17

MicroPython for Microcontrollers

Single cell LiPo (Lithium Polymer) or Lithium-Ion batteries provide sufficient power for the ESP32. However, their voltage of 3.7 to 4.2 V, depending on the state of charge, is too high for the ESP32. It is therefore regulated down via an internal module. As working with Li-ion batteries is always associated with a certain degree of danger, the following information should not be omitted: • Lithium-Ion batteries react sensitively to incorrect charging currents or voltages. Under certain circumstances there is even a risk of fire or explosion. • Each user is responsible for their own construction and operation of the project. • Neither the Publisher nor the Author assumes any liability.

Figure 2.4: NodeESP board in battery mode.

● 18

Chapter 3 • Programming and Development Environments

Chapter 3 • P  rogramming and Development Environments Unlike the situation with, say, an Arduino system, there are several Integrated Developing Environments (IDEs) available for working with MicroPython. In principle, you can write programs with all IDEs and load them onto the controller. The two most widespread programming environments are currently: • µPyCraft • Thonny Both have their own specific advantages and disadvantages. The differences lie mainly in the different procedures for developing and managing program code for the application projects. The first variant called µPyCraft offers a comparatively simple interface for MicroPython development on the ESP32 controller. It works with simple graphic elements and resembles text-oriented operating systems. The handling of the individual functions is easy to understand and working with the different menus is easy to learn. Thonny, on the other hand, has a fully graphical interface in Windows style. The IDE is very popular among makers, especially because it is available under the Raspbian operating system on the Raspberry Pi. Many Raspberry Pi users are therefore already very familiar with Thonny. The IDEs stand for the most important operating systems such as • Windows PC • Mac OS X • Linux Ubuntu which are available free of charge on the internet. If problems occur during installation or use of either system, the other version can be used as an alternative programming system. The version to choose depends of course on the personal inclinations and habits of the user.

3.1 Installing the uPyCraft IDE Before installing uPyCraft IDE, the latest version of Python 3.7.X should be installed on the computer you are using. If it is not, the installation can be done according to the following instructions: 1. Download the installation file from the Python download page at: www.python.org/downloads

● 19

MicroPython for Microcontrollers

2. After the download operation, a file named python-3.7.X.exe should reside on your computer. Double-clicking on the file starts the installation. 3. Select "Add Python 3.7 to PATH" and click the "Install Now" button. 4. The installation process is completed after a few seconds and the message "Setup was successful" is displayed. The window can then be closed. Now the uPyCraft IDE for Windows can be downloaded from https://github.com/DFRobot/uPyCraft as a file called uPyCraft_V1.x.exe. After clicking on this .exe file, the uPyCraft-IDE will open:

Figure 3.1: uPyCraft-IDE After the IDE is installed on the computer, the ESP32 firmware can be loaded onto the chip. The current version of the MicroPython firmware for the ESP32 can be found at http://micropython.org/download#esp32 There you scroll to the section "ESP32 modules". After clicking the link to "Generic ESP32 module" you will get to the download page of the ESP32-BIN file. This will look as follows: esp32-idf3-20191220-v1.12.bin Now you can start the uPyCraft-IDE. Under Tools -> Serial

● 20

Chapter 3 • Programming and Development Environments

select the ESP32-COM port, here as COM5:

Figure 3.2: Selecting the port. If the ESP32 board is connected to the computer but the ESP32 port does not appear in the uPyCraft IDE, the appropriate USB driver may be missing. In this case, the driver must be reinstalled. A corresponding driver can be found under https://www.silabs.com/products/development-tools/software/usb-to-uartbridge-vcp-drivers Afterwards you can follow Tools -> Board Next, the option "esp32" must be selected:

Figure 3.3: Selecting the board type Now the MycroPython interpreter can be written onto the ESP32 using Extras -> Burn Firmware

● 21

MicroPython for Microcontrollers

The appropriate options are: • board: esp32 • burn_addr: 0x1000 • erase_flash: yes • com: COMX (here COM5, see above) Under "USERS", select the downloaded ESP32-BIN file, as shown in Figure 3.4.

Figure 3.4: The parameters for flashing the firmware If all settings are correctly selected, the "BOOT / FLASH" button on the ESP32 board must be pressed on some board variants. As soon as the "EraseFlash" process begins, the key can be released. After a few seconds, the firmware should have flashed onto the ESP32 board. However, in many cases the download will start without pressing the buttons. If the "EraseFlash" display does not start or an error message is displayed, repeat the steps described above. Also press the "BOOT / FLASH" key again to ensure that ESP32 enters the flash mode.

3.2 MicroPython for the ESP32 With a few exceptions, all features and functions of Python are also available in MicroPython. The biggest difference is that the micro version was designed for use on single-chip systems and therefore the classic routines required only for the PC are missing. For this reason MicroPython does not contain the complete standard library, but only the parts relevant for microcontrollers. Therefore, all modules required for accessing the used hardware are available. With the corresponding libraries you can therefore easily access the GPIO pins. Especially for the ESP32 there are also modules available to support network connections (Wi-Fi) and Bluetooth. In particular, the following boards are supported: • ESP32 • ESP8266 • PyBoard • Teensy 3.X • WiPy - Pycom

● 22

Chapter 3 • Programming and Development Environments

Although not all functions of the ESP controller are fully available in MicroPython as of yet, the libraries contain the most important commands and routines. Therefore many projects and applications can be implemented smoothly. In addition, the implementation of the missing features is progressing rapidly, so that even this small beauty flaw will be quickly eliminated. Once the MicroPython firmware has been installed on the ESP32, you can also easily return to the Arduino IDE, for example. To do this, simply load the new C code with the IDE onto the controller. A special deletion procedure is not necessary. However, if you want to use MicroPython again afterwards, the MicroPython firmware must be flashed again.

3.3 "Hello World" for the controller Unlike AVR controllers, such as those used in the Arduino system, the ESP32 can accommodate a complete file system. The first generations of controllers were programmed in either Assembler or C. The program code was therefore created and compiled in a development environment. Then only the finished "machine code" was transferred to the controller. The memory of the target system therefore always contained exactly one program. In contrast, when programming in MicroPython, several programs can be stored on the ESP32 chip. These can then be processed directly by the interpreter that is also available on the system. The file system can be managed directly with the uPyCraft-IDE. It is therefore advisable to familiarise yourself with the IDE a little more closely before loading the first application program onto the ESP. The development environment contains, similar to many other programming tools, the following components (see also Figure 3.1) 1. 2. 3. 4.

Folders and files Editor MicroPython Shell / Terminal Tools

In the left sub-window ("Folders and files"), the files currently stored on the ESP board are visible in the device folder ("device"). As soon as the board is connected to uPyCraft-IDE via a serial connection, all saved files will be loaded when opening the device folder. Directly after the installation of the Python interpreter only a "boot.py" file is visible here. To execute the application code, a main.py file should also be created. You can create a main.py file using: file → new This creates a new file ("untitled"). Through the floppy disk icon in the "Tools" window this file can be saved locally under the name "main.py" on the ESP chip.

● 23

MicroPython for Microcontrollers

Figure 3.5: Creating a new file "main.py". The following two files are now in the device folder: • boot.py: executed every time the board is rebooted • main.py: main script for the application code The SD folder follows under the device folder. This folder is intended for accessing files stored on an SD card. Some ESP-32 boards have an SD card slot. If a µSD card is inserted here, the files on the card appear in the "sd" folder. The uPy_lib folder follows below. Here the integrated IDE library files are shown. Here you can find different files directly after the installation of the MicroPython interpreter. These are provided as standard libraries.

Figure 3.6: Standard libraries in the uPy_lib folder. The last folder contains the so-called "workSpace". This is a directory for saving application files. The files displayed here are stored on the computer connected via the interface. All active files should be stored there. When uPycraft is used for the first time, it is therefore recommended that a suitable working directory called "workSpace" be created and then used consistently for working with the controller. In the Editor area (2) the code for the .py application programs is created. The Editor opens a new tab for each file.

● 24

Chapter 3 • Programming and Development Environments

The section below the Editor area is the "MicroPython Shell/Terminal" (3) All commands entered here are immediately executed by the ESP board. In addition, the terminal also displays information about the status of a running program. Any syntax errors in the current program or error messages during uploading, etc., appear here. With the symbols in the "Tools" area at the far right of the main window (4), tasks can be executed quickly and directly. The buttons have the following functions: • New File: Creates a new file in the editor • Open File: Opens a file on the computer • Save File: Saves a file • Download and run: Upload code to the ESP board and run it • Stop: Ends code execution. This corresponds to entering CTRL + C in the shell • Connect/Disconnect: Connect or disconnect the serial interface. The serial port can be selected under Tools -> Serial • Undo: undoes the last change in the code editor • Redo: Repeat last change in code editor • Syntax check: Checks the syntax of the current code • Clear: Deletes the shell / terminal window messages In order to become familiar with writing a program and executing code on the ESP32, a short Python program will be developed and executed below, which makes a LED flash. The first step is to establish communication with the ESP board: 1. Select the current board via Tools -> Board 2. In Tools -> Port select the COM-Port to which the ESP-Board is connected 3. The Connect button then establishes serial communication with the ESP32 module 4. After a successful connection to the board, ">>>" is displayed in the shell window. Now a print command can be entered to test whether the communication is working correctly: >>> print ('test') The answer Test >>> appears in the terminal window. When the message is displayed, everything is OK. Otherwise, check that serial communication with the board is established and that the MicroPython firmware has been flashed successfully to the board.

● 25

MicroPython for Microcontrollers

Now a LED flashing script can be created. The following steps are required for this: 1. The following program is entered into the Editor window of the file main.py, which was created above: from machine import Pin from time import sleep led = Pin(2, Pin.OUT) while True: led.value(not led.value()) sleep(1)

2. By clicking on the "Stop" button, a script that may still be running can be stopped 3. With a click on the button "Download And Run" the script is written to the controller 4. The shell window should now show the message "download ok".

Figure 3.7: Successful download of the first program. Now the integrated LED of the ESP32 board should flash every second. This means that the first Python program was successfully transferred to the controller and executed immediately.

● 26

Chapter 3 • Programming and Development Environments

Figure 3.8: Internal LED at port 02 in action. Some boards do not have an integrated LED. In this case, an LED including series resistor must be connected to the controller (see, for example, Figure 4.6 and Figure 4.7). Further details and information on the flashing program and on connecting external LEDs can be found in Section 4.4.

3.4 For professionals: Working with esptool If problems occur with the µPyCraft-IDE or if other reasons stop you from using it, you can also load the MicroPython firmware onto the controller with the help of a utility called esptool. It is then even possible to transfer programmes to the controller via a terminal such as PUTTY or TeraTerm. However, this method already requires some in-depth knowledge of the command line interface or the device manager. This procedure is therefore less recommended for beginners. Nevertheless, the method will be described here, as it also provides further insights into the handling of the controller programming. In addition, the methods presented here can also be easily transferred to Linux or UNIX systems. In order to work with esptool, Python 3.7.X or a newer Python installation should be installed on the System System. The current version of esptool can then be downloaded to the computer via a terminal window using pip install esptool With some Python installations, this instruction may cause an error message to appear. In this case, the following instructions may lead to the destination: pip3 install esptool python -m pip install esptool pip2 install esptool

● 27

MicroPython for Microcontrollers

Now the esptool file should be installed in the standard directory for executable files. To access the controller, its serial port number must be known. This can be found in the Device Manager:

Figure 3.9: The COM port of the ESP32 in the Device Manager. In the figure, the port number is COM3, for example. This allows the following command to be executed in the terminal window: esptool --port COM3 flash_id This provides information about the ESP32 system connected to that port:

Figure 3.10: Information about ESP32. The lines ... Detecting chip type... ESP32 Chip is ESP32-PICO-D4 (revision 1) Features: WiFi, BT, Dual Core, Embedded Flash

● 28

Chapter 3 • Programming and Development Environments

Crystal is 40MHz MAC: d8:a0:1d:40:54:14 ... Device: 4016 Detected flash size: 4MB

thus provide important information about the chip type, the board, the available interfaces, the crystal frequency and the available flash memory. Now you can use the instruction esptool --port COM3 erase_flash to erase the flash memory of the chip.

Figure 3.11: Successful erasing of the flash memory. This clears the way for uploading the MicroPython firmware. The download of the firmware from the internet was already described in the last chapters. The command for the upload is esptool --port COM3 --baud 460800 write_flash -fm dio 0x1000 C:\Users\Documents\workSpace\esp32-xxxxxxxx-vx.x.x.bin Of course, the correct path where the esp32-20xxxxxx- vx.x.x.bin file is located must again be specified here. After a few seconds, the upload should be finished:

● 29

MicroPython for Microcontrollers

Figure 3.12: Upload of the firmware is completed. Now you can contact the ESP via PUTTY or TeraTerm. The baud rate must be set to 115200:

Figure 3.13: MicroPython reports to the TeraTerminal. A first Python program can already be loaded via the terminal, for example: from machine import Pin import time p23 = Pin(23, Pin.OUT) while True: p23.value(1) time.sleep(1) p23.value(0) time.sleep(.1)

● 30

Chapter 3 • Programming and Development Environments

Figure 3.14: Programming via TeraTerminal. After the program has been transmitted, an LED connected to port 23 should flash at a 1-second rate. The console offers the usual help system, which can provide useful information if necessary:

Figure 3.15: Help function in the terminal.

● 31

MicroPython for Microcontrollers

3.5 Thonny — a Python-IDE for beginners Thonny is a good alternative to uPyCraft. Although even this programming environment is not yet completely bug-free, you can generally work well with it. In addition, the system is constantly being updated and improved, so this flaw will also be eliminated in the foreseeable future. Thonny is also available for all common operating systems. Under Raspbian for Raspberry Pi it is even installed by default. The installation is relatively simple, so there should be hardly any problems in the installation process. A prerequisite for working with Thonny is that the MicroPython firmware has already been loaded onto the ESP32. For beginners, the use of the µPyCraft-IDE is recommended. Experts can also use esptool (see last chapter) to bypass the µPyCraft-IDE completely. The examples in this book were created with Thonny 3.2. In principle, future versions should be compatible with it. However, in case of unexpected problems, you should return to the version mentioned above. The appropriate package can be downloaded from https://thonny.org When the download is complete, you can run the installation file. Now you only have to follow the assistant until the installation process is finished. Afterwards the Thonny-IDE can be opened.

Figure 3.16: The Thonny-IDE after start-up. Now the ESP32 board can be connected to the computer. To test the installation, Thonny must be configured for the MicroPython interpreter. In addition, the board used must be selected. The following steps are necessary for this: 1. Run → Interpreter opens the following window:

● 32

Chapter 3 • Programming and Development Environments

Figure 3.17: The options window in Thonny. 2. In the first selection window, select "MicroPython" (generic). 3. The COM interface of the ESP32 must be entered under Port. Now the Thonny-IDE should be connected to the board and the shell window should show the prompt ">>>". Alternatively the option "Try automatic recognition" can be selected. However, this does not work reliably with all boards. Finally, the help() command is entered into the shell. This will return a welcome message and some information: Welcome to MicroPython on the ESP32! For generic online docs please visit http://docs.micropython.org/ For access to the hardware use the ‚machine' module: import machine pin12 = machine.Pin(12, machine.Pin.OUT) pin12.value(1) pin13 = machine.Pin(13, machine.Pin.IN, machine.Pin.PULL_UP) print(pin13.value()) i2c = machine.I2C(scl=machine.Pin(21), sda=machine.Pin(22)) i2c.scan() i2c.writeto(addr, b'1234') i2c.readfrom(addr, 4) Basic WiFi configuration: import network

● 33

MicroPython for Microcontrollers

sta_if = network.WLAN(network.STA_IF); sta_if.active(True) sta_if.scan()

# Scan for available access points

sta_if.connect("", "") # Connect to an AP sta_if.isconnected()

# Check for successful connection

Control commands: CTRL-A

-- on a blank line, enter raw REPL mode

CTRL-B

-- on a blank line, enter normal REPL mode

CTRL-C

-- interrupt a running program

CTRL-D

-- on a blank line, do a soft reset of the board

CTRL-E

-- on a blank line, enter paste mode

For further help on a specific object, type help(obj) For a list of available modules, type help('modules')

The installation and commissioning of Thonny has thus been successfully completed. The hardware functions can now be activated via shell instructions. First of all the machine module can be imported: >>> from machine import Pin Then, an LED connected to port 23 can be switched on via >>> led = Pin(23, Pin.OUT).value(1) Alternatively, the standard LED available on most boards can be used. Via >>> led = Pin(23, Pin.OUT). value(0) the corresponding LED is switched off again.

3.6 Working with Thonny In the Thonny-IDE there are several different sections, among which are the editor and the MicroPython shell or terminal: • In the editor area, code is created and edited. Multiple files can be opened, with a new tab available for each file. • In the MicroPython shell, commands are entered that are to be executed immediately by the ESP card. The terminal also provides information about the status of an executed program, indicates errors related to uploading, syntax errors, print messages, etc. Other useful tabs are also available. These can be configured in the View menu. The "Variables" tab in particular can often be used to great advantage. It shows all variables of a program and their current values.

● 34

Chapter 3 • Programming and Development Environments

In order to become familiar with writing programs and executing code on the ESP32, the already known script is used again, which makes the integrated LED of an ESP32 board or an external LED blink. At first a main.py file is created on the board: 1. When Thonny starts for the first time, the editor shows a file without title. This file is saved as main.py. For this purpose, the file is saved via file → save as renamed to main.py and saved on the board ("Micro Python Device"). 2. Now a tab named "main.py" is available. 3. The following code is entered here: from machine import Pin import time p23 = Pin(23, Pin.OUT) while True: p23.value(1) time.sleep(1) p23.value(0) time.sleep(.1)

The code is available in the download package for this book and can be used initially via copy and paste. Later it is explained how files can be copied directly from the PC to the controller. Via the green arrow or run → run current script or by pressing function key F5, the code is transmitted to the controller. The following information is output to the shell: MicroPython v1.9.4 on 2018-05-11; ESP32 module with ESP32 Type "help()" for more information. >>> %Run -c $EDITOR_CONTENT

When the ESP is restarted, first the boot.py and then the main.py is executed. If boot.py is not present, it is started immediately with main. So the program should become active immediately after uploading, and the LED on the selected port (No. 23 in the example above) should blink.

● 35

MicroPython for Microcontrollers

With some board variants, it may also be necessary to press the ESP EN / RESET key.

3.7 Working with files To upload a file with a unique name to the ESP using the Thonny IDE, the following steps are required: • Creating a new file • Save the file on the computer with the exact name, for example "blink.py". The file can be opened as a new tab in the "This Computer" subwindow. It can then be opened via the menu file → save as on which ESP can be saved under its name ("blink.py") The second selection "MicroPython device" must be selected in the query (see figure).

Figure 3.18: Query when saving The file is now uploaded to the board and appears in the sub-window "Files". From there it can now be started with the green arrow key or F5. Accordingly, it is also possible to download files from the chip to the computer by selecting "This Computer". Other commands for deleting or renaming files etc. are also found in the "file" menu.

3.8 Troubleshooting tips for the Thonny IDE In the current section some error messages of the Thonny-IDE will be discussed. The corresponding problems are usually relatively easy to solve: • In many cases, restarting ESP with the integrated EN/RST key is already successful. • Within the Thonny-IDE, communication problems between PC and chip can often be solved by pressing the "Stop / Restart Backend" button (or CTRL-F2). Otherwise, the following tips may help:

● 36

Chapter 3 • Programming and Development Environments

Error 1: No connection to the board. In this case, the error messages are displayed: ========================= RESTART ========================= Unable to connect to COM4 Error: could not open port 'COM4': FileNotFoundError(2, 'The system cannot find the file specified.', None, 2)

or: ========================= RESTART ========================= Could not connect to REPL. Make sure your device has suitable firmware and is not in bootloader mode! Disconnecting.

or: ========================= RESTART ========================= Lost connection to the device (EOF).

In this case it is often helpful to interrupt the USB connection to the module and then re-establish it. You should also check whether the correct serial port is set under Run -> Select Interpreter This error could also indicate that the serial port is already being used by another program such as a serial terminal or the Arduino IDE. If this is the case, make sure that all programs that may be communicating serially with the ESP card are closed. Then the Thonny IDE should be restarted. Error 2: Thonny IDE does not answer or gives an internal error. After closing and re-opening the active window, you should be able to continue working normally. If there are repeated crashes, the whole Thonny-IDE should be restarted. Error 3: Thonny IDE no longer responds to the "Stop / Restart Backend" key. After pressing the button "Stop / Restart Backend" you should wait a few seconds. The ESP needs time to restart and restore serial communication with Thonny. If the "Stop" button is clicked several times or very quickly one after the other, the ESP module does not have enough time to restart properly. This may cause the Thonny IDE to crash. Error 4: Problem when restarting the ESP card, running a new script or opening the serial port.

● 37

MicroPython for Microcontrollers

If the following error message appears: Brownout detector was triggered

or if there are continued reboots, or if the information: ets Jun 8 2016 00:22:57 rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) configsip: 0, SPIWP:0xee clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 mode:DIO, clock div:2 load:0x3fff0018,len:4 load:0x3fff001c,len:4732 load:0x40078000,len:7496 load:0x40080400,len:5512

is displayed, this may indicate a hardware problem. This is often caused by one of the following problems: • USB cable of poor quality, • USB cables too long, • The ESP board has a defect, e.g. a bad solder joint, • Faulty computer USB connection, • The computer's USB port does not supply enough power. In these cases, the use of a high quality and shortest possible USB cable will help. Changing to a different USB socket on the PC can also be helpful. For laptops, an active USB hub with its own external power supply should be used. This way you are no longer dependent on the performance of the laptop USB power supply. If the problems persist or other strange error messages appear, it is recommended to update the ESP board with the latest version of the MicroPython firmware. This will at least prevent errors that have already been corrected from making work more difficult. Error 5: No connection between PC and ESP32. It may happen that the controller is too loaded to establish a USB connection. In this case, clicking the button "Stop/ Restart Backend" several times may bring the desired success. However, this repeated clicking should take place at certain intervals (see above). When running a script that uses Wi-Fi, switches to sleep mode, or performs multiple tasks in parallel, it is recommended that you try to establish communication three or four times. If this is still not possible, the ESP should be flashed again with the current MicroPython firmware.

● 38

Chapter 4 • First Steps in Programming

Chapter 4 • First Steps in Programming Python has been one of the most frequently used programming languages for several years. One of the reasons for this is that it was very simply designed and is therefore easy to learn. The development of MicroPython makes the programming of microcontroller systems comparatively simple and straightforward. This makes the programming language also very suitable for beginners in the world of embedded systems. The developers of MicroPython have set themselves the goal of making the programming of digital electronics as easy as possible. In this way, the largest possible circle of users can be addressed. Python programs can be found in the hobby area as well as in education or scientific use. But professional developers too, increasingly work with Python. In the IT industry, numerous market leaders such as Google or Amazon have been using Python for their software developments for a long time. In addition, freely available modules and libraries such as MatPlotLib, NumPy, SciKit or SciPy provide extensive possibilities. These range from scientific data analysis to machine learning and artificial intelligence. MicroPython was developed as a slim version of Python 3. Since the language has to be interpreted, it is generally slower than compiled systems. MicroPython was designed to work as efficiently as possible on small embedded systems. Therefore it can also be run on microcontrollers which are much slower clocked and have much less memory than typical personal computers. A disadvantage of classical Python programming is that low-level controls are very difficult to implement. For this reason, the classic Python variants are used rather secondary in hardware-related programming. This shortcoming is largely eliminated by MicroPython. Based on the standard, the Micro version is also strongly based on Python 3 in its syntax. In addition there are virtual machines and the associated libraries. If one compares the two most popular programming languages in the microcontroller environment, one finds that Python is more often preferred over C/C++. In the rankings of the most popular programming languages, Python more and more often reaches the first place. The competitor C/C++, on the other hand, is increasingly being relegated to lower ranks. The reason for this development is mainly based on the following advantages of Python: • Python is very beginner-friendly due to its simple language structure. • Various internet forums support the programmer with tutorials and example codes. • There are extensive libraries available. Beginners usually find solutions to their problems quickly in the forums. In other languages this form of mutual support is not as pronounced.

● 39

MicroPython for Microcontrollers

In C, programming is done via control registers, pointers and other structures and instructions that are often difficult to understand. The firmware for the target controller must be programmed, compiled and finally transferred to the controller with a programming device. MicroPython integrates all these steps. With a simple mouse click, users can control low-level hardware such as LEDs, displays, or motors. The acquisition of analogue voltage values or working with SD cards becomes child's play with the appropriate libraries. Integrated memory cleaning and a dynamic allocation process enables efficient memory management in Python. This means that you hardly need to resort to pointers or similar constructs, which are usually difficult for beginners to penetrate. The often-cryptic C-symbols like x++, etc. as well as the complex variable declaration represent a hurdle for the beginner which should not be underestimated. Python is known for its simplicity and the excellent readability of the code. Since MicroPython was developed as a "light version" for microcontroller applications, not all libraries and functions of standard Python are supported. Nevertheless, you can easily switch to the micro version if you are already familiar with Python. Only a few syntactical structures or instructions are not available or applicable in MicroPython. Python is interpreted. This means that the original program code is processed directly by the target processor. Compilation is therefore not necessary. Python therefore offers the possibility to execute a program once written on a wide variety of systems. For this purpose, only a corresponding interpreter must be installed. One of the biggest advantages of Python code is its comprehensive compatibility. Python programs can be executed on classic computers under Windows, MacOS or Linux as well as on small single-board systems such as the Raspberry Pi or comparable microsystems. Especially the use on the "RPi" (German: "Raspi") has also contributed to the increasing popularity of Python. With new powerful controllers such as ESP32, it has now even become possible to use Python efficiently and conveniently in this area as well. Firmly integrated constructs ensure that programs can be easily developed on both a small and large scale. Python is therefore excellently scalable. The possible encapsulation of data and program code in clear, usable modules, i.e. objects, makes Python an object-oriented programming language. C++ is generally used nowadays, especially in hardware-oriented programming. Classical Python variants were not well suited for this purpose until now. With MicroPython this gap is now closed. C++ includes client applications as well as powerful server applications, device drivers and embedded driver components. The area of application ranges from system software to application programming. Since Python is a relatively new programming language compared to C, it has not yet found universal use in all areas of information technology. However, it can be seen that Python is gaining ground in practically all areas. The main disadvantage of Python is certainly its comparatively low processing speed. Here compiled languages like C can clearly show their advantages. Fast control loops or real-time systems, vehicle controls and safety enquiries can be realised much easier and safer in C.

● 40

Chapter 4 • First Steps in Programming

Since these areas of application hardly play a role for non-professional users, though, the speed disadvantage is hardly significant. Python has also gained special importance in the highly topical field of artificial intelligence (AI). Through extensive libraries such as NumPi, SciPi etc. and distributions such as Anaconda, Python has become the most popular programming language by far. All doors are therefore open for the experienced Python user. From hardware-related controller programming to AI applications — with Python there are no limits to intuition and creativity. In this chapter the basics of MicroPython will be compiled. You should have a functional programming environment available, because the commands and instructions are always illustrated with practical examples. These can then be immediately tested directly on the target hardware, i.e. the ESP32. This does not remain a purely theoretical programming course, but the knowledge acquired can be immediately put into practice.

4.1 Never without: Comments Explanatory comments are important in any programming language. This is the only way to know months or years later what a certain program section does, without having to delve into old details over and over again. It is not necessary to comment each program line individually. Experienced coders should be able to understand individual instructions without comment. Only in the case of special constructs or unusual or innovative lines of code is a single line comment recommended. For subprograms or whole logical program sections on the other hand, a short explanation of how they work should not be missing. Simple comments will be introduced with the # sign. They begin with # and end with the end of the line: >>> print("hello ESP32") # this is a comment hello ESP32

Multi-line comments can also be marked with a triple double-quate (") character ("""). The same character string then ends the comment: """ first comment line second comment line """ In practice this may look like this: ''' This is a multi-line comment. Prints "hello world". '''

● 41

MicroPython for Microcontrollers

print("hello world")

Alternatively, the commentary function can be used in Thonny. It allows to mark several lines as comments at the same time with the # (hash) sign.

Figure 4.1: Comment function in Thonny. The commentary function is also very suitable for commenting-out certain parts of the program. If, for example, when testing a more extensive code, certain sections are not to be executed on a trial basis, these can be marked with comment signs. The lines are then no longer observed by the interpreter. This makes a time-consuming deletion and later reinsertion of the program sections unnecessary. Comments help beginners in particular to gain a better understanding of the program structure. From the technical point of view the interpreter ignores all comments, i.e. they have no influence on the program flow.

4.2 The Print() statement Information can be output to the terminal using the print() instructions. The command can be executed directly in the terminal:

Figure 4.2: Print command in the console. On the other hand, it is used in programs to output text-based information:

● 42

Chapter 4 • First Steps in Programming

Figure 4.3: Print command as program instruction. print () can contain several strings divided by ",": >>> print("hello", "world!") hello world!

The print() statement performs a line break by default. With end = "" this can be suppressed: print("hello", end=" ") print("world")

and leads to the following result: hello world

The following two illustrations illustrate the print instruction versions again in the ThonnyIDE:

Figure 4.4: Print command as program instruction in Thonny.

● 43

MicroPython for Microcontrollers

Figure 4.5: Print command in the Thonny console.

4.3 Indentations and blocks MicroPython distinguishes different blocks by indentation. It is not necessary to use curly braces ("{}") or similar. This is one of the main differences to most other languages like C, Pascal, Basic etc. The advantage of this method is that one is practically forced to a certain degree of program structure. if True: # block 01 print ("True") else: # block 02 print ("False")

The number of spaces for indentations is variable, but the same block must always maintain the same number of spaces for indentations. Otherwise, an error message is displayed: if True: print ("Answer") print ("True") else: print ("Answer") print ("False")

# The different indentation will lead to a runtime error.

This leads to the following message: >>> %Run -c $EDITOR_CONTENT Traceback (most recent call last): File "", line 6 IndentationError: unexpected indent

● 44

Chapter 4 • First Steps in Programming

In conditions and loops, blocks are formed in an identical way.

4.4 The hardware under control: digital inputs and outputs Unlike programming on a PC or a laptop, MicroPython usually focuses on direct access to hardware functions. Especially the control of individual input/output pins (I/O pins or GPIO for General Purpose Input Output) is of central importance. To test the instructions in practice, all you need to do is connect an LED with a series resistor to the ESP32. The following figure shows the corresponding wiring diagram:

Figure 4.6: Circuit diagram for LED at port 25. The structure of the circuit on a breadboard looks like this:

Figure 4.7: LED hooked up on port 25. On the software side, a digital pin must first be initialized. For this purpose, a variable is created which corresponds to the pin. This is not just a pin number, but a complete object that knows all aspects of the pin. To use pins, the class "Pin" must be imported from the module "machine". From machine import Pin

● 45

MicroPython for Microcontrollers

After that, the initialisation of a single pin can already be done: led = Pin(25, Pin.OUT)

The number 25 is the GPIO number. This is usually found as a printed circuit board number near the corresponding pin. The instruction defines the pin as an output.

Figure 4.8: Pin numbers here (here 25 and 26) on the ESP board. Now the pin can be used: led.value(1)

This sets the I/O port to "1", i.e. it now carries a voltage of 3.3 V. If everything is connected correctly, the LED on port 25 will light up after the command is executed via the console. Resetting the pin to "0" (0 volts) will carry out the following instruction: led.value(0)

Together with the sleep instruction (see also the following chapter) from the time module you can now program a LED flasher (blink_simple.py): # blink_simple.py from machine import Pin from time import sleep led = Pin(25, Pin.OUT) while True: led.value(1) sleep(1) led.value(0) sleep(1)

Due to the wait instruction sleep(1)

the LED now flashes at one-second intervals, i.e. with a period of two seconds or a frequency of 0.5 hertz.

● 46

Chapter 4 • First Steps in Programming

Each I/O pin can also be used as a digital input. The corresponding initiation is carried out via: pin_in = Pin(25, Pin.IN)

This allows the level applied to the pin to be detected, i.e. 0 for 0 V and 1 for 3.3 V. An open input, i.e. a pin without any wiring does not provide a reliable result. Interference signals such as 50 Hz interference, WLAN or radio frequencies can change the level randomly. To prevent this, so-called pull-up or pull-down resistors are necessary. With the ESP32 these can even be switched on internally. Using pin_in = Pin(2, Pin.IN, Pin.PULL_UP)

ensures that an unconnected input carries a high signal. Accordingly, button_pin = Pin(2, Pin.IN, Pin.PULL_DOWN)

carries a low signal on an open input. With the following program the functions can be tested: # read_pin_25.py from machine import Pin from time import sleep pin_in = Pin(25, Pin.IN, Pin.PULL_DOWN) while(True): print(pin_in()) sleep(1)

In the circuit diagram the structure looks like this:

Figure 4.9: Capturing voltage levels.

● 47

MicroPython for Microcontrollers

In the hardware setup, a piece of wire can be used to test the circuit, which is connected to GND or 3.3 V:

Figure 4.10: Hardware structure for reading voltage levels Depending on whether the wire bridge is connected to GND (0 V) or 3V3, the value 0 or 1 appears in the terminal. If the input is open, 0 (for pull-down) or 1 (for pull-up) is displayed in the terminal. ATTENTION: Under no circumstances should the input be connected to 5 V. This could lead to the destruction of the chip. The pins of the ESP32 may only be controlled with a maximum of 3.3 V! The 1-kΩ resistor is used to protect the input. This reduces the chances of unintentionally applied excessive voltages causing damage. Still, you should always avoid applying voltages above 3.3 V to an ESP32 pin.

4.5 Time control and sleep In the example of the flashing LED, the delay instruction has already been used. This is contained in the "time" module and is controlled by import time

With the statement time.sleep(seconds)

a fixed delay time in seconds can be set. Alternatively, only the sleep command itself can be imported: from time import sleep

● 48

Chapter 4 • First Steps in Programming

Then the instruction can be shortened to sleep(seconds)

Although the command can also be used for fractions of a second, for very short delays it is recommended to use time.sleep_ms(milliseconds)

because it has a better precision for small times. The disadvantage of these functions is that they work obstructively. This means that the controller cannot carry out any other tasks during the waiting period because it is busy counting processor cycles. An alternative is to use interrupts or other programming techniques. Details are given in later chapters. The following two routines are available for time queries: time.ticks_ms() time.ticks_us()

They indicate the current system runtime in milli- or microseconds. A classic application is the measurement of program runtimes. With the following code it can be shown, for example, that mathematical operations require a certain amount of time: # runtime.py import time import math

while(True): start = time.ticks_us() # x = math.exp(math.sin(22.5)) stop = time.ticks_us() print(stop-start)

If the comment sign is removed before the calculation, the displayed processing speed increases from approx. 100,050 µs to 100,170 µs. The calculation time for the formula is therefore around 120 µs.

● 49

MicroPython for Microcontrollers

4.6 Important values: variables and constants In Python it is particularly easy to create variables. It is not necessary to specify the data type of the variable during the assignment. This is a major difference to other languages. There, variables must always be explicitly initialised with a certain type (e.g. int a =...) Variables can also be used in the console: >>> a = 17 >>> print(a) 17

The following rules apply to the assignment of variable names: • The variable name should only contain numbers, letters and underscores. • The first character of a variable name must be a letter or underscore. • The variable name is case-sensitive. Variables can be assigned values of different types. The types in MicroPython include numbers, strings, lists, dictionaries, tuples, etc. With type() the data type of variables and constants can be checked, e.g. >>> a = 17 >>> print(type(a)) 3

%

Modulo (rest of the division)

11 % 3 ==> 2

**

Exponent

2 ** 3 ==> 8

The logical operators "not", "and" and "or" are also available in MicroPython: a

not a

True

False

False

True

● 53

MicroPython for Microcontrollers

a

b

a and b

a or b

True

True

True

True

True

False

False

True

False

True

False

True

False

False

False

False

The bit operators are represented in Python by the following instructions: & | ^ ~

Bitwise Bitwise Bitwise Bitwise

AND - operation OR - logic operation XOR - logic operation NOT

The shift operators can also be used: > Move bits

to the left to the right

The following examples illustrate the application: >>> a = 0b1010 >>> b = 0b1100 >>> bin(a&b) ‚0b1000' >>> a = 0b1010 >>> bin(a>> H >>> ytho

An existing string can be "updated" by assigning a variable to another string, possibly again. The new value can be linked to its previous value or to a completely different string. For example var = 'Hello World!' print ("Updated String : ", var[:6] + 'Python')

yields the result >>> Updated String : Hello Python

An important point when working with strings are the "escape characters". The following table contains a list of these escape or non-printable characters, which can be displayed with backslash notation.

● 58

Character

Function Effect

\b

Backspace

Backward step

\n

Newline

Line break

\r

Carriage return

Carriage return

\s

Space

Space

\t

Tab

Tabulator

Chapter 4 • First Steps in Programming

For example, the statement >>> print("Hello \n World")

yields the result >>> Hello World

● 59

MicroPython for Microcontrollers

Chapter 5 • The Controller in Practical Use Now that you are familiar with some important programming basics, it's time for the first practical applications. In addition to output to the console, LEDs in particular will be used as indicators for port statuses. This already allows for some interesting applications to be realized. For these examples, either the integrated LEDs of the individual boards can be used, or external LEDs. The on-board LEDs are usually connected to port 02. This is especially the case with the NodeMCU board. The Node-ESP board even has a multicolour LED of three colours connected to ports 00, 02 and 04. The Pico kit does not have an integrated LED. In this case you have to switch to external LEDs (see Figures 4.6 or 4.7.) Do not forget the series resistor.

5.1 LED flasher as alarm system simulator A flashing LED was already implemented in section 4.4. In contrast to permanently lit displays, flashing lights attract attention. Flashing therefore often draws attention to an exception or a dangerous situation. For example, a permanently lit LED on a freezer usually indicates that the unit is working properly. If the LED starts flashing, this is usually an indication that the temperature inside no longer corresponds to the setpoint. The same applies to battery-powered appliances. A lit LED indicates a full battery. If the LED starts flashing, only a small amount of power is left. For alarm systems, a flashing or flashing LED indicates that the device is activated. An LED in flashing mode can therefore be used as an alarm system simulator. Variations of such devices are actually used in practice. They can, for example, be installed in a vehicle. They cannot be distinguished from a real, armed alarm system and will deter at least some opportunistic thieves from breaking in. The corresponding program can be found again in the program package with the book. # Alarmsimulator.py from machine import Pin from time import sleep led = Pin(2, Pin.OUT) while True: led.value(1) sleep(.1) led.value(0) sleep(5)

The only difference to the flashing program is that the values in the sleep() instructions have been changed to 0.1 or 5. This turns the regular flashing into a short flashing. As soon as the new program has been loaded, the LED flashes briefly every five seconds and the alarm system simulator is ready for use.

● 60

Chapter 5 • The Controller in Practical Use

5.2 Useful in an emergency: automatic SOS signal Another interesting application is an automatic SOS beacon. This can even save lives in emergency situations. In order to emit the familiar SOS signal, an LED must first flash three short flashes, then three long flashes and finally three short flashes again. This signal sequence should be permanently repeated. The code for the alarm system simulator can easily be changed so that the LED sends the desired signal: # SOS.py from machine import Pin from time import sleep led = Pin(2, Pin.OUT) while True: # "S" led.value(1) sleep(.1) led.value(0) sleep(.5) led.value(1) sleep(.1) led.value(0) sleep(.5) led.value(1) sleep(.1) led.value(0) sleep(1) # "O" led.value(1) sleep(.4) led.value(0) sleep(.5) led.value(1) sleep(.4) led.value(0) sleep(.5) led.value(1) sleep(.4) led.value(0) sleep(1)

● 61

MicroPython for Microcontrollers

# "S" led.value(1) sleep(.1) led.value(0) sleep(.5) led.value(1) sleep(.1) led.value(0) sleep(.5) led.value(1) sleep(.1) led.value(0) sleep(1) sleep(2)

This is certainly not the most elegant method of generating an SOS signal. However, this program demonstrates that even without extensive knowledge of the Python programming language, you can realise useful projects of your own. Section 6.4 shows how such a program can be implemented much more efficiently. Nevertheless, the program fulfils its purpose. If a particularly bright LED is used, the circuit can be quite useful in situations such as distress at sea or in the mountains.

● 62

Chapter 6 • Program Structures

Chapter 6 • Program Structures No programming language can do without control structures. MicroPython provides branch and loop instructions for this purpose. The example of SOS signal generation has already shown that many identical or similar sequences must often be repeated in programming. Loops offer a much more elegant method for this purpose, rather than to simply repeat instructions in the code. If decisions have to be made, branching instructions are necessary. These allow a program to react correctly to different situations. In contrast to other programming languages, MicroPython has a very extensive functionality when it comes to loops. This will be explained in the following sections.

6.1 Conditions and loops In a branch, a condition is defined in the program by the keywords "if" and "else". Depending on whether this condition is true or false, the program will continue at different points. So the program returns Temperature = 2 if temperature < 3: print("Risk of frost" ) else: print("No danger of frost")

it will result in the output >>> Risk of frost

If, instead, it is set that Temperature = 17, the output will be >>> No danger of frost

The result after the keyword "if" returns a Boolean expression. This can be either true or false. If the expression is true, the statements are executed directly after the if-line. These statements must be indented so that it is clear which statements belong to the if-block. Note that the Boolean expressions in the if-line must end with a colon. The "else" statements are only executed if the if-query is incorrect. Loops are used to repeat instructions. With loops, code blocks can be executed several times. The execution is continued until a given condition is fulfilled. Two types of loops are available in MicroPython:

● 63

MicroPython for Microcontrollers

• while loops • for loops If you want to output numbers from 1 to 10 to the console, the following while loop can be used: number=1 while number amplitude: dac1.write(255) else: dac1.write(0)

a rectangle function can also be generated simultaneously. The complete MicroPython program for this looks like this: # sinus_square_generator.py from math import sin, pi from machine import DAC from machine import Pin dac0 = DAC(Pin(25))

● 78

Chapter 7 • Analogue-Signal Generation

dac1 = DAC(Pin(26)) offset = 128 amplitude = 127 bufferlength = 100 # create a buffer containing a sine-wave buf = bytearray(100) for n in range(len(buf)): buf[n] = offset + int(amplitude * sin(2*pi*n/len(buf))) while 1: for i in range(len(buf)): dac0.write(buf[i]) if buf[i] > amplitude: dac1.write(255) else: dac1.write(0)

The voltage curves at pins 25 and 26 can again be viewed with an oscilloscope:

Figure 7.5: ESP32 as a sine/rectangle generator. The DACs can be used for a wide range of applications such as audio output, sound generation or digital synthesizers. Special waveforms can also be generated in this way: # sinus_square_generator.py from math import sin, pi from machine import DAC from machine import Pin dac0 = DAC(Pin(25))

● 79

MicroPython for Microcontrollers

offset = 128 amplitude = 127 buffferlength = 100 # create a buffer containing a sine-wave buf = bytearray(buffferlength) for n in range(len(buf)): buf[n] = offset + int(amplitude * sin(2*pi*n/len(buf))) # insert special values buf[25] = offset buf[75] = offset while 1: for i in range(len(buf)): dac0.write(buf[i])

The program supplies a "disturbed" sinusoidal signal, which briefly drops to 0 V when the peak voltage is reached. Such a signal is needed if you want to test special amplifiers or filters. With such a signal it can be tested whether the circuits react correctly to these waveforms.

Figure 7.6: Impure sinewave signal.

● 80

Chapter 8 • Interrupts and Timers

Chapter 8 • Interrupts and Timers In the microcontroller environment, temporary interruptions of a running program are referred to as interrupts. They are used to execute an often time-critical process. Typical applications are alarm messages or the safety shutdown of components and machine parts. If, for example, a generator is monitored electronically, an excess temperature signal from a sensor must be reacted to immediately. Time delays due to a momentarily high processor load can have catastrophic consequences in this case and are therefore not tolerable. Interrupts are also required for the use of timers. Here, the hardware units in the controller set specific time intervals. If these have expired, an interrupt is triggered. This enables a very precise timing to be achieved, independent of the load on the main processor core. Typical applications are clocks and time controls of all kinds. The precision of the timers ultimately depends only on the accuracy of the processor crystal. Since a precision in the 1/1000th range can be achieved without problems, timers are used in many practical applications.

8.1 Disruption wanted: Interrupts Interrupts are used when it is necessary to react quickly to unforeseeable or irregular events. If the status change is detected at an interruptible pin, a separate hardware unit in the controller triggers an interrupt event. Thus it is not necessary to constantly monitor the corresponding pin via a query routine. After the interrupt has been triggered, a predefined function can be called which reacts to the event appropriately. When an interrupt occurs, the processor stops executing the main program to execute the interrupt routine. Only when this has been executed does it return to the main program. The following figure illustrates this process:

Figure 8.1: Interrupts. So interrupt routines run quasi-parallel to the main program. But this is not a real parallel processing. The processor rather processes the main program and the interrupt routine one after the other.

● 81

MicroPython for Microcontrollers

Interrupt routines should therefore be as short as possible, i.e. their processing should take as little time as possible. Within an interrupt routine no time-consuming calculations should be made or extensive program loops etc. should be processed.

8.2 Automatic night light This section explains how to configure interrupts in MicroPython. As an example, a push button is read out. This button is supposed to switch on an LED for a specified period of time. Afterwards the LED should go out automatically. Applications for this circuit would be, for example, automatic bathroom or stairwell lighting. But such circuits are also used for interior lighting in vehicles. With a bright white LED, the ESP board can also be used as an automatic bedside lamp. Figure 8.2 shows the circuit diagram. For more information about the hardware timers of ESP32, please refer to the next chapter.

Figure 8.2: Schematic of an automatic night light. For the use of interrupts as well, the machine module is first imported again and then used to access the hardware-related functions: from machine import Pin

In addition, the sleep methods are needed because a waiting period is required later in the program: from time import sleep

A variable is used to query whether a key has been pressed. This variable is defined globally because it gets modified in the interrupt handling function. It is sufficient if it can assume the Boolean values True or False. The initialization is done with False: key_pressed = False

● 82

Chapter 8 • Interrupts and Timers

In case of an interrupt the following routine should be run: def interrupt_handler(pin): global key_pressed key_pressed = True

This function is called each time a key is pressed. The interrupt_handle function has an input parameter (pin) in which an object of class Pin is passed if the interrupt occurs. The parameter specifies at which pin the interrupt was triggered. If only one interrupt pin is used, this information is not needed. However, if multiple interrupts can trigger the same interrupt handling function, it may be of interest which GPIO triggered the interrupt. In the example the interrupt_handler changes the variable key_pressed to True. Since the processing time of an interrupt function should be kept as short as possible, functions such as sleep() or print() should be avoided, if possible. The instructions to be executed when the interrupt occurs should therefore be in the main program. In order for a variable to be used both within the function and in the entire code, it must be declared as "global". Otherwise the switching of the LED would not work, because the variable change would only have an effect within the function, but not in the main program. By writing led = Pin(25, Pin.OUT) button = Pin(4, Pin.IN) the pins for the LED and the button are defined. The instruction button.irq(trigger=Pin.IRQ_RISING, handler=handle_interrupt)

causes an interrupt to be triggered whenever the key is pressed. The "trigger" parameter can have the following values: • IRQ_RISNING: Trigger on rising edge • IRQ_FALLING: Trigger on falling edge If the interrupt is triggered, the controller jumps to the interrupt handler routine and the variable key_pressed is set to True. After returning to the main program, the message "Interrupt detected!" is displayed. In addition, it is reported at which pin the interrupt was triggered. The LED is then switched on for the specified period and then switched off again. Finally key_pressed is set to False again and the controller is available for the next interrupt. The complete program looks like this:

● 83

MicroPython for Microcontrollers

# LED_interrupt.py from machine import Pin from time import sleep timeOn=3 key_pressed=False def handle_interrupt(pin): global key_pressed key_pressed=True led = Pin(25, Pin.OUT) button1 = Pin(4, Pin.IN) button1.irq(trigger=Pin.IRQ_RISING, handler=handle_interrupt) while True: if key_pressed: print('Interrupt detected') led.value(1) sleep(timeOn) led.value(0) key_pressed = False

In this example the already known sleep() command is used to keep the LED on for three seconds. At this point, however, a timer application would be the better solution. How and why timers are used is shown in the next section.

8.3 Masters of Time: Timers Timers can be used for a variety of tasks. Among the most common applications are • the periodic calling of a function, • the counting of events, • the generation of PWM signals. Each timer consists of two 16-bit channels that can be linked to form a 32-bit timer. The operating mode must be configured for each timer, but the period or frequency can be selected independently for each channel. With the callback method, the timer event can call a python function. In this way, the following program makes an LED flash: # LED_timer.py import machine led = machine.Pin(25, machine.Pin.OUT) timer = machine.Timer(0)

● 84

Chapter 8 • Interrupts and Timers

def handleInterrupt(timer): led.value(not led.value()) timer.init(period=1000, mode=machine.Timer.PERIODIC, callback=handleInterrupt)

The difference from the classic flashing program with sleep() function is that the controller is not blocked by the use of a timer function. During the execution of the sleep() function, the processor core is only busy counting clock cycles. The core cannot perform any other tasks beyond that. Thus the sleep() function is "obstructive". For the timers, on the other hand, there are separate hardware units available that do not burden the main processor core. The fact that the processor core remains free for other tasks when using the interrupt is also shown by the appearance of the command prompt >>> in the shell. Hence, you can continue to work here simultaneously:

Figure 8.3: Running timer and active shell. Other functions can also run in the program while the timer is active. The following code causes led1 at pin 25 to flash at a period of 125 ms, while at the same time led2 at port 26 flashes every second: # LED_timer_and_mainprogram.py from machine import Pin, Timer from time import sleep led1 = Pin(25, Pin.OUT) led2 = Pin(26,Pin.OUT) timer = Timer(0)

● 85

MicroPython for Microcontrollers

def handleInterrupt(timer): led1.value(not led1.value()) timer.init(period=125, mode=Timer.PERIODIC, callback=handleInterrupt) while True: led2.value(1) sleep(.1) led2.value(0) sleep(1)) The second LED must be connected to port 26 with a series resistor.

Finally, the following program shows that two LEDS with completely different frequencies can be switched using two timers: # LED_double_timer.py import machine led1 = machine.Pin(25, machine.Pin.OUT) led2 = machine.Pin(26, machine.Pin.OUT) timer1 = machine.Timer(0) timer2 = machine.Timer(1) def handleInterrupt1(timer1): led1.value(not led1.value()) def handleInterrupt2(timer2): led2.value(not led2.value()) timer1.init(period=125, mode=machine.Timer.PERIODIC, callback=handleInterrupt1) timer2.init(period=517, mode=machine.Timer.PERIODIC, callback=handleInterrupt2)

Without interrupts and timers, this relatively simple task would no longer be feasible.

8.4 A multifunctional flashing light Red bicycle spotlights are nowadays equipped with several powerful LEDs. In addition, it is often possible to set different signal patterns in addition to continuous light operation. In this way, increased attention can be generated. Blinking taillights permanently mounted on the bicycle are not legal, but the carrying of secondary lights on the helmet or rucksack is permitted under certain circumstances. However, before using a "flashing light" in traffic, you should always inform yourself about the current legal situation.

● 86

Chapter 8 • Interrupts and Timers

Figure 8.4: LED bicycle taillight. With the ESP controller, a multifunctional flashing light can be easily reproduced. The projected taillight should have the following performance characteristics: • 5 LEDs • Permanent light • Blinking • Flashing • Chase effect Switching between the individual operating states is a classic interrupt application. Without the use of interrupt technology, an efficient switchover control would not be possible. The following program does the job: # bike light.py from machine import Pin from time import sleep LED = [25,26,32,27,14] del_time = 0.1 mode=1 def handle_interrupt(button1): global mode mode+=1 if(mode>4): mode=1 print(mode) button1 = Pin(4, Pin.IN) button1.irq(trigger=Pin.IRQ_RISING, handler=handle_interrupt)

● 87

MicroPython for Microcontrollers

for n in range(len(LED)): LED[n] = Pin(LED[n],Pin.OUT) while True: if (mode==1):

# LEDs all on

for n in range(len(LED)): LED[n].value(1) if (mode==2):

# LEDs blink

for n in range(len(LED)): LED[n].value(1) sleep(del_time) for n in range(len(LED)): LED[n].value(0) sleep(del_time) if (mode==3):

# LEDs flash

for n in range(len(LED)): LED[n].value(1) sleep(del_time) for n in range(len(LED)): LED[n].value(0) sleep(del_time*5) if (mode==4):

# LEDs chaser

for n in range(len(LED)): LED[n].value(1) sleep(del_time) LED[n].value(0) sleep(del_time)

Since, in contrast to the simple chaser from Section 6.2, several LEDs are now active at the same time, the hardware design must be modified somewhat:

Figure 8.5: Circuit diagram for LED taillight.

● 88

Chapter 9 • Using Sensors

Figure 8.6: Breadboard construction of the LED taillight. To switch between operating modes, a button at pin 4 including pull-up resistor and debouncing capacitor has been added. In addition, each LED now has its own series resistor. With a common resistor, the individual LEDs would shine less and less brightly with each additional LED switched on.

● 89

MicroPython for Microcontrollers

Chapter 9 • Using Sensors The evaluation of sensors and electronic measuring transformers is a central task of microcontroller technology. This chapter therefore deals with the use of MicroPython in measurement and sensor technology in more detail. The ESP32 has eighteen analogue inputs and is therefore ideally equipped for measurement applications. In addition to the evaluation of sensor signals, the sensor technology also includes the output and processing of measured values and the processing of signals of all kinds. In particular, what is called "signal conditioning" plays an outstanding role. Methods like • signal conversion • linearization • signal amplification • filtering are classic tasks of microcontroller-based data acquisition. Without these methods, many tasks and procedures in technology, applied physics or medicine would not be realizable. With MicroPython, measured values can be displayed directly on the console. Thonny even has a special plotter that enables the graphical display of values. Alternatively, it is also possible to display the values on a display, so that the ESP32 can also work in stand-alone mode. The second method is described in more detail in the following chapter.

9.1 Acquisition of measurement and sensor values Even with digital I/O pins, it is already possible to read in measured values. Thus, binary voltage levels can be read 0 V or 3.3 V "measured values" from each GPIO input of the ESP controller. This is often sufficient for simple measurement or monitoring tasks. Real analogue —i.e. continuous — values, on the other hand, cannot be measured with digital ports. As already mentioned in the section on digital-to-analogue conversion, nature is predominantly analogue. Therefore, special methods and procedures have been developed for the acquisition of signals in the analogue domain. In the ESP32, so-called analogue/digital converters (ADC) are available for this purpose. These are, so to speak, the counterpart to the DACs and allow the simultaneous acquisition of several analogue channels. ADCs have become an integral part of modern signal acquisition. In all areas of technology, they monitor the proper function of components and systems. In audio and communication devices such as smartphones or tablets, they convert microphone signals into high-quality digital data streams. Temperature, light intensity or pressure are just a few examples of the many parameters that are recorded and evaluated by ADCs in vehicles or buildings. The converters can be characterized by two essential parameters: • resolution in bits • conversion speed

● 90

Chapter 9 • Using Sensors

The precision with which an analogue signal can be digitised is determined by the first value. The conversion time is decisive for the working speed. It determines the maximum frequency with which a signal can be quantized. This conversion time depends mainly on the conversion method used. Figure 9.1 shows the digitisation of an analogue voltage curve with an ADC. The converter scans the analogue voltage curve at certain points in time and converts the determined value into a digital quantity. The ADC in an ESP32 chip has a resolution of 12 bits. When normalised to 3.3 V, a voltage of 2.45 V, for example, produces: Q = 2.45 V / 3.3 V * 4095 = 3040 bits

Figure 9.1: Digitization of analogue values. The wide field of application of digital measurement technology led to the development of various ADC processes. Some areas of application require the highest possible measuring precision. Other processes rely on the fastest possible conversion. As both features cannot be converted at the same time, several ADC conversion principles were developed which clearly differ in terms of precision and speed. The following table summarizes these: Measurement procedure

Application

Properties

Parallel converter

fast digital oscilloscopes, control

very fast, complex, high

engineering, research

power consumption

Successive approximation

Procedure for most internal AD

fast, high precision,

(SAR)

converters of microcontrollers,

complex

standard method Single-slope or dual-slope

Multimeter

low cost, good linearity, slow

Delta-Sigma

Precision measurements, audio

inexpensive, slow

technology

● 91

MicroPython for Microcontrollers

As a good compromise, successive approximation is mainly used in microcontroller technology. The two transducers in the ESP32 are also based on this method. Analog multiplexers ensure that the ESP chip is capable of recording 18 analogue channels at a measuring rate of several thousand measurements per second. The achievable conversion speed depends, among other things, on the selected actual resolution of the ADC. Further information can be found in the following sections.

9.2 Precise recording of voltages: a DIY voltmeter In a first example application, the evaluation of analogue-digital converters under MicroPython shall be demonstrated. For this purpose, the analogue voltage generated by a potentiometer is recorded and displayed in the console. The pins 25 - 34 should be used as universal ADC inputs. Other ADC inputs are assigned with important double functions, so they should only be used if the other channels are already occupied. In the following example, the analogue input pin 34 is used. The following program shows the easiest way to read out the ESP32's ADC: # ADC_atten_11db.py from machine import ADC, Pin from time import sleep adc = ADC(Pin(34))

# create ADC object on ADC pin

adc.atten(ADC.ATTN_11DB) while True: print(adc.read())

# read value, 0-1024

sleep(1)

On the hardware side, only a 10-kohm potentiometer has to be connected to pin 34:

Figure 9.2: Voltage measurement with a potentiometer.

● 92

Chapter 9 • Using Sensors

The additional 1-kohm resistor is only used to protect the ESP chip. In the event of a fault, the maximum current is limited if the voltage applied to the potentiometer is slightly too high. In this way, damage to the chip can be avoided.

Figure 9.3: Breadboard layout for recording analogue measured values. Values between 0 and 4095 are output for various voltage settings on the potentiometer. This corresponds to the resolution of the ADC of 12 bits: 212 – 1 = 4095, but if you measure the voltages with an external multimeter, you will find that the value 4095 is already reached at a voltage of 1 volt. When using the standard configuration, the input voltages at the ADC pin must therefore be between 0.0 V and 1.0 V. For all voltages above 1.0 V the value 4095 is displayed. To increase this usable voltage range, an internal voltage divider can be activated. Using the commands Damping (dB)

Damping (linear)

Ui max

dc.atten(ATTN_0DB)

0 dB

1

1.00 V

adc.atten(ATTN_2_5DB)

2.5 dB

0.75

1.34 V

adc.atten(ATTN_6DB)

6 dB

0.5

2V

adc.atten(ATTN_11DB)

11 dB

0.282

3.6 V

the internal damping can be activated. The attenuation of 0 dB is the standard setting. The resolution can also be configured. Possible options are:

● 93

MicroPython for Microcontrollers

ADC.WIDTH_9BIT: ADC.WIDTH_10BIT: ADC.WIDTH_11BIT: ADC.WIDTH_12BIT:

9-bit data 10-bit data 11-bit data 12-bit data (standard configuration)

Important note: The absolute maximum rated voltage for the input pins is 3.6 V. Higher voltages can damage ESP32! After loading the program, the measured values are displayed in the console:

Figure 9.4: Display of the measured values in the Thonny console. At high measuring rates, the individual values become hard to read. In this case, the plotter function of the Thonny-IDE is the means of choice. Using View → Plotter the measured values can be displayed graphically.

● 94

Chapter 9 • Using Sensors

Figure 9.5: Graphic representation in the plotter. This function is ideally suited for the quick and clear presentation of extensive measurement data, results, or sensor values etc.

9.3 Linearity correction The ADC conversion of the ESP32 controller has the disadvantage that the resulting characteristic curve is non-linear. At ADC values above 3000, the deviation from the ideal characteristic curve is clearly visible. Considerable deviations also occur near the zero point (see Figure 9.7). As a result, larger measurement errors occur, especially at the edges. However, these can be significantly reduced by suitable measures such as linearisation with a compensation polynomial or a restriction of the measuring range. The non-linearity of the ADC can be easily displayed graphically using the (linear) DAC. The following program provides the corresponding measurement data: # ADC_DAC_tst.py from machine import DAC, ADC, Pin import time dac0=DAC(Pin(25)) adc0=ADC(Pin(34)) adc0.atten(ADC.ATTN_11DB)

● 95

MicroPython for Microcontrollers

for n in range(0, 256): print(n, end =' ‚) dac0.write(n) time.sleep(0.1) print(adc0.read()) time.sleep(0.1)

The values thus obtained can be displayed in a slide chart using Excel or Libre-Office:

Figure 9.6: The non-linear characteristic of the ADC.

9.4 Linearization by limitation of the value range A compensation polynomial allows the values to be linearised over the entire measuring range. However, it is not possible to achieve very high precision with this. It is better to use only the largely linear parts of the characteristic curve. It can be seen from Figure 9.6 that the ADC operates largely linearly in the range up to approx. 3000 counts. If one restricts oneself to this range, the calibration line shown in Figure 9.7 results. With the regression formula derived from it: voltage = 0.000816 * ADC_count + 0.037822 voltage values between 200 mV and 2.5 volts can now be measured very precisely. This is usually completely sufficient for sensor applications, as many sensors do not reach values of less than 0.2 volts anyway. The measuring program for this looks like this: # ADC_lin.py from machine import Pin, ADC from time import sleep pot = ADC(Pin(34)) pot.atten(ADC.ATTN_11DB) #Full range: 3.3v while True: pot_value = pot.read() voltage = 0.000816*pot_value + 0.037822

● 96

Chapter 9 • Using Sensors

print(voltage) sleep(0.1)

With a high-quality and exactly calibrated voltmeter the values can be measured again. The deviations should remain well below 3%. This means that nothing stands in the way of using analogue measuring transducers such as photodiodes, analogue temperature sensors or strain gauges. For even higher requirements, digital transducers can also be used. The ESP32 is also ideally equipped for this. These sensors can communicate directly with the processor via suitable bus systems. Further details can be found starting from Section 9.10.

Figure 9.7: Linearized ADC characteristic. This means that the full voltage range cannot be used for high accuracy requirements. The voltage values must be limited accordingly. Another possibility is to correct the measured values by software via a polynomial. Several methods are available for this purpose. In the next section, the standard method for linearising transfer functions is explained in more detail.

9.5 Linearization of the ADC input by means of compensation polynomial If the entire value range of the ESP32 internal analogue-to-digital converter is to be used, a software correction is required. This is done by using different interpolation points from the actual measurement curve. These are used to create a so-called "compensation curve polynomial". The ADC values can then be corrected with the parameters of the polynomial. The compensation polynomial thus determined is y =

-0.000000000009824x^3 +



0.000000016557283x^2 +



0.000854596860691x



+

0.065440348345433

● 97

MicroPython for Microcontrollers

For this purpose, a function is implemented in MicroPython: # ADC_lin_poly.py from machine import ADC, Pin from time import sleep adc = ADC(Pin(34))

# create ADC object on ADC pin

adc.atten(ADC.ATTN_11DB) def ReadVoltage(): ADC=adc.read() return -0.000000000009824*pow(ADC,3)+0.000000016557283*pow(ADC,2)+0.000854596860691*ADC+0.065440348345433; while True: print(adc.read(), " ", end="") print(ReadVoltage()) sleep(0.1) }

With this method a good linearity and precision is achieved. The deviations now remain below 60 mV over the entire measuring range. This is completely sufficient for most practical applications. For an even better accuracy a 4th degree polynomial could also be used. However, other influences such as digitization noise will then already be noticeable, so that the effort is hardly worthwhile. Additional improvements could now be made by further limiting the voltage range. However, this is not necessary for the following applications.

9.6 Voltage measurement Only voltages of 3.3 V or less may be applied to an ADC input of the ESP32 chip. Higher voltages can lead to the destruction of the entire controller. However, the measuring range can be extended almost indefinitely with a voltage divider. The following figure shows a circuit for measuring input voltages of up to approx. 30 V. With a voltage divider consisting of a 100 kohm and a 10 kohm resistor, the input voltage is reduced to 1/11th of its value: Uo = R1 / (R1 + R2) = 10 kohm / 110 kohm = 1/11

● 98

Chapter 9 • Using Sensors

Figure 9.8: Voltage divider for extending the ADC measuring range.

IMPORTANT: The structure must be carefully checked before applying external voltages. If the resistors are mixed up, for example, this can lead to the destruction of the ESP board! In electronic circuits and systems, the supply voltages are usually below 30 V. The measuring range of the circuit shown in Figure 9.8 is therefore sufficient for many applications. Voltages above 50 V may only be measured with safety-tested measuring devices anyway. In this context the following note must always be observed: Voltages higher than 50 V can be life-threatening under special circumstances! When using the prescaler, the actual input voltage of 30 V is thus reduced to 2.73 V at the ADC input. This means that the internal ADC of the ESP32 can now also measure voltages in the extended range up to 30 V. The Schottky diodes (SD1 and SD2) shown in the circuit diagram are not required for the actual measurement. They only protect the inputs of the ESP chip against overload in case of an error. As soon as the voltage at the controller input falls below 0 V or exceeds 3.3 V, the diodes become conductive and thus prevent possible overvoltages at the ADC. he influence of the voltage divider must of course be taken into account in the software. The calibration factor cal is responsible for this. It is used to calculate the scaling factor out of the voltage divider. # Voltmeter_30V.py from machine import ADC, Pin from time import sleep adc = ADC(Pin(34))

# create ADC object on ADC pin

adc.atten(ADC.ATTN_11DB)

● 99

MicroPython for Microcontrollers

Vref=3.30

# internal reference voltage

R1=100

# for voltage divider

R2=10

# for voltage divide

cal=1*(R1+R2)/R2

# calibration factor

while True: output="V = {:5.1f} V" print(output.format(adc.read()*Vref/4095*cal)) sleep(1)

A comparison of the measured values with a high-quality calibrated multimeter reveals the non-linearity of the ESP32-ADC already mentioned. The error can be more than one Volt. The following program provides much more precise values: # Voltmeter_30V_lin.py from machine import ADC, Pin from time import sleep adc = ADC(Pin(34))

# create ADC object on ADC pin

adc.atten(ADC.ATTN_11DB) Vref=3.30

# internal reference voltage

R1=100

# for voltage divider

R2=10

# for voltage divide

cal=1*(R1+R2)/R2

# calibration factor

def ReadVoltage(): ADC=adc.read() return -0.000000000009824*pow(ADC,3)+0.000000016557283*pow(ADC,2)+0.000854596860691*ADC+0.065440348345433; while True: output="V = {:5.1f} V" print(output.format(ReadVoltage()*cal)) sleep(1)

A step-by-step comparison with a calibrated benchtop voltmeter yields the following table: U_Reference/V

● 100

U_ESP32/V

0.201

0.22

0.496

0.49

1.007

1.01

2.005

1.99

Chapter 9 • Using Sensors

3.007

3.02

5.022

5.05

10.055

10.09

15.013

15.12

20.039

20.04

25.019

25.06

30.018

30.16

The constants used here in the program in the form of the cal factor and the reference voltage are called software calibration parameters. Alternatively, a hardware calibration could be carried out with a precision potentiometer or a spindle trimmer. Trimmers specially developed for the application can be adjusted very precisely and have good long-term stability due to their closed design. When comparing with a calibrated measuring instrument, the trimmer is adjusted until the ESP32 voltmeter shows the correct value. It is then no longer necessary to change the parameters in the program. Thus, in special environmental conditions (e.g. at extreme temperatures), recalibration can be carried out without changing the program. A disadvantage of hardware calibration is that additional components are required. Potentiometers and especially spindle trimmers are comparatively expensive and always show some drift. Environmental influences lead to changes in the electrical parameters, so that the long-term stability of the measuring device deteriorates. If a total resistance of 1 kiloohm is selected for the potentiometer, the measured value can be tweaked by about 5%. Higher resistance values provide a wider adjustment range, but also reduce the precision of adjustment.

9.7 Cross-interferences: side effects in sensor technology Measuring analogue voltage values with the ESP-32 ADCs should no longer be a problem. This clears the way for the evaluation of sensors with analogue output voltages. With these probes or sensors, components are available which can convert physical quantities into electrical values. Almost all physical values can be recorded electronically. In addition to the parameters already mentioned, such as temperature, humidity, or light intensity, this also goes for other important variables such as • Volume or sound intensity • Mechanical printing • Radio, heat or infrared radiation • Radioactive radiation levels • Accelerations or mechanical forces • All types of magnetic and electric fields • Chemical parameters such as pH value or conductivity of solutions • etc.

● 101

MicroPython for Microcontrollers

Hundreds of different instrument transformers are installed in chemical production plants, aircraft, satellites or modern motor vehicles. Without high-quality sensors all these technical installations would be unthinkable. Ideally, sensors measure a precisely defined, specific value. This value is reproducibly and as accurately as possible converted into an electrical quantity such as a voltage or a resistance value. A linear relationship between the measured variable and the electrical value is desirable. For microcontrollers such as the ESP32, however, even a non-linear transfer function does not pose a problem, as linearisation can be carried out with suitable software methods without any great effort. So-called "cross-interferences" are not so easy to eliminate. Many sensors not only react to the desired measured variable, but also to other physical values. Some examples are: • Temperature dependence of photosensors • Influence of vibrations on sound transducers • Influence of air humidity on sensors for electric fields • Reaction of gas sensors to several chemical compounds • Thermal interference with humidity or pressure sensors The elimination of such influences can be associated with considerable effort. One method is the additional and independent measurement of the disturbance variable and a mathematical correction of the measured value based on this. In any case, when using sensors, it should always be checked whether cross-sensitivities can influence or falsify the measuring precision in an inadmissible way.

9.8 Touching permitted: capacitive touch sensors Touch sensors are the classics of sensor technology. In the 1970s and 80s, they were a must for every television set and stereo system. They replaced the familiar control buttons and made it possible to change programmes or adjust the volume simply by touch. But also the screens of modern smartphones are, in principle, touch sensors, which can be operated without keyboards or mechanical operating elements. A conventional touch sensor consists of metallic electrodes. Occasionally these are covered with a thin protective surface. If the sensor is touched with a finger, this can be determined by a change in the capacitance of the electrode. To use the touch sensors of the ESP32, the TouchPad class must be loaded in the machine module. Afterwards, the method TouchPad.read() is at disposal: from machine import TouchPad, Pin t=TouchPad(Pin(14)) t.read() # Returns a smaller number when touched

TouchPad.read() returns a relative capacitance change. Without touching sensor surfaces connected to ESP, large numbers, i.e. typically values greater than 800, are returned. If an

● 102

Chapter 9 • Using Sensors

active electrode is touched, the values fall below 200. However, the results are relative and may vary depending on the shape and size of the electrode. The following table gives some indication of the expected values: Unconnected pin: > 1000 With electrode connected - without touching: 800 to 1000 With touching: < 200 Calibration may thus be required before the touchpads can be used in a particular application environment. The ESP32 provides ten touchpad inputs. These are located at pins 0, 2, 4, 12, 13, 14, 15, 27, 32 and 33 The following program can be used to check the function of the touch-sensitive inputs: # touch_test.py from machine import TouchPad, Pin from time import sleep from machine import TouchPad, Pin t1 = TouchPad(Pin(2)) t2 = TouchPad(Pin(4)) while True: cap1 = t1.read() print(cap1, end=" ")

cap2 = t2.read() print(cap2) sleep(1)

As electrodes, items such as drawing pins or small copper coins can be used. The following figure shows a suggested layout for controlling inputs 2 and 4:

● 103

MicroPython for Microcontrollers

Figure 9.9: Touch sensors connected to the ESP32. After loading the program, the sensor values are output. If none of the sensors is touched, the numerical values will be above 800. If one of the electrodes is touched lightly with a finger, the values of the relevant channel fall below 200. In the plotter, the signal course can be traced:

Figure 9.10: Signal change upon touching the touch sensors. With the following script, the two LEDs on ports 25 and 26 can be switched via the touch pads. When a pad is touched, the corresponding LED lights up: # touch_LED.py from machine import TouchPad, Pin from time import sleep t1 = TouchPad(Pin(2)) t2 = TouchPad(Pin(4)) led1 = Pin(25, Pin.OUT) led2 = Pin(26, Pin.OUT) while True:

● 104

Chapter 9 • Using Sensors

if t1.read() < 500: led1.value(1) else: led1.value(0) if t2.read() < 500: led2.value(1) else: led2.value(0)

Note: the ESP32 can also be woken from sleep mode via touch pads. For further details on using sleep methods, refer to Chapter 17.

9.9 Well chilled or overheated: temperature sensors provide clarity The precise measurement of temperatures is one of the most important sensor applications in electronic measurement technology. Thermosensors and temperature probes are used to monitor the processors of modern PCs or chemical reactions in industrial plants as well as in oil temperatures in motorboats or server rooms of large computer systems. Precise and continuous temperature monitoring is also often extremely important in the medical field. With classic alcohol or mercury thermometers, only the current temperature can be measured. An electronic thermometer, on the other hand, also allows time resolved measurements. This is of utmost importance for the temperature monitoring of power transistors, microprocessors, incubators, or server farms, as only the observation over longer periods of time allows a safe operation. In case of an emergency an additional cooling unit can be activated or even the performance of a complete server farm can be shut down. Simple NTC sensors (Negative Temperature Coefficient) are inexpensive and provide useful temperature readings, but the required calibration is a major disadvantage. For single sensors and in non-professional applications this is usually acceptable. In a professional environment and when using many sensors, however, the calibration effort can quickly become uneconomical. Here, factory calibrated sensors like the LM35 or the TMP36 are preferred. These achieve their high measuring accuracy through individual adjustment by the manufacturer. These sensors can therefore be used directly without any additional preparatory work. The pinning of the widely used sensor element type TMP36 can be seen in the following figure:

Figure 9.11: TMP36 sensor connections.

● 105

MicroPython for Microcontrollers

The following data apply to the TMP36: Supply voltage: Calibration: Scaling factor: Accuracy: Linearity: Temperature range: Closed-circuit current:

2.7 V to 5.5 V factory setting in °C 10 mV/°C ±2 °C (typical) ±0.5 °C (typical) –40 °C to +125 °C threshold):

● 130

Chapter 10 • Display Technology and Small-Size Screens

ledRed.value(0) ledGreen.value(1) else: ledRed.value(1) ledGreen.value(0) sleep(.1)

For monitoring tasks, a permanent magnet must be attached to the door or window in question. The ESP module is mounted so that the magnet is near the module when windows or doors are closed. When opening, the magnet is then removed from the ESP module and the magnetic field strength near the chip drops to almost zero. Threshold detection generates a digital signal. In the example program, this switches off the green LED and activates the red LED. The signal can also be used for other purposes. For example, it can be forwarded via WLAN to a PC or a smartphone, where it can trigger a corresponding alarm.

● 131

MicroPython for Microcontrollers

Chapter 10 • Display Technology and Small-Size Screens Displaying texts and values in the console is perfectly adequate for many test purposes and simple applications. However, this variant has the big disadvantage that a PC or at least a laptop is always required. If the system is in permanent operation for days or weeks, the operation of these devices will consume an unnecessary amount of power. Furthermore, it is not always desirable or practical to use a separate computer for each microcontroller application. If it is only a matter of displaying a time or the measured data from climate sensors, it is much better to connect your own small display to the controller. A widely used type is the SSD1306. This display unit has a resolution of 128 x 64 pixels with a size of only 0.96 inch (just under 2.5 cm). As a standard, MicroPython comes with a driver for this display version. This driver already loaded when uploading the file system to the ESP32. The driver makes it possible to display text and numeric data as well as simple graphics. The SSD1306 display is equipped with internal RAM and its own oscillator. Therefore it can be operated without any external components. In addition, it has a brightness control with 256 adjustable levels. The main features of the SSD1306 display are: • Resolution: 128 x 64 dot matrix • Power supply: 1.65 V to 3.3 V • Operating temperature range: –40 °C to +85 °C • Integrated 128 x 64-bit SRAM display buffer • Continuous scroll function in horizontal and vertical direction • On-chip oscillator OLED displays do not require background lighting because each individual pixel is capable of emitting light. For this reason, this variant is still easy to read even under unfavourable lighting conditions. In addition, the contrast is significantly higher compared to liquid crystal displays (LCDs). Since a pixel only consumes energy when it actually lights up, OLED displays are very energy efficient. The simplest versions of SSD1306 boards have only four pins. This is sufficient to control the display via the I2C bus. Other versions have reset pins or an additional SPI interface. For most applications, though, the simple design is sufficient. The following table shows all necessary connections.

● 132

Chapter 10 • Display Technology and Small-Size Screens

OLED-Pin

ESP32

VDD

3V3

GND

GND

SCK

GPIO 22

SDA

GPIO 21

The "circuit diagram" looks like this:

Figure 10.1: SSD1306 display on an ESP32. The following script outputs a text message and a simple graphic element in the form of a frame on the display: # SSD1306_DEMO.py from machine import Pin, I2C from ssd1306 import SSD1306_I2C i2c=I2C(-1,scl=Pin(22),sda=Pin(21)) # I2C Pin assignment oled_width=128 oled_height=64 oled = SSD1306_I2C(oled_width, oled_height, i2c) lin_hight = 9 col_width = 8

● 133

MicroPython for Microcontrollers

def text_write(text,lin, col): oled.text(text,col*col_width,lin*lin_hight) oled.fill(0) text_write("MicroPython", 1, 2) text_write("for", 3, 6) text_write("ESP32", 5, 5) oled.rect(5, 5, 116, 52, 1) oled.show()

and gives this result:

Figure 10.2: SSD1306 display with text and graphic output. To control the display, the required modules must be imported. As already mentioned, the libraries "machine" and "SSD1306" are normally already available as standard libraries. If necessary, however, an ssd1306.py file can be uploaded separately to the board. The pin declaration for the I2C bus is done using: i2c = I2C (-1, scl = pin (22), sda = pin (21))

The number of pixels of the connected module is recorded with the following variables: oled_width = 128 oled_height = 64

● 134

Chapter 10 • Display Technology and Small-Size Screens

The parameter "–1" indicates that the module used has neither reset nor interrupt pins. With this information an SSD1306_I2C object with the name oled can be created. Here the previously defined data is taken over: oled = ssd1306.SSD1306_I2C (oled_width, oled_height, i2c)

The display is now ready for operation. The function "text()" outputs information on the display. The method show() is used to update the display. The text() function accepts the following arguments: • Message (String) • X-position and Y-position of the text field in pixel units • Optional text colour: 0 = black (dark) and 1 = white (light) The following instruction outputs a message in white or blue colour on a dark background. The text starts at the position x = 0 and y = 0: oled.text ('MicroPython!', 0, 0)

The show() method makes the changes visible on the display. The library also contains other useful methods. The function fill(1) creates a full permanent white screen, i.e. all pixels are lit. With oled.fill (0) all pixels are set to black or dark. The pixel() method allows graphical representations. It accepts the following arguments: • X-coordinate: horizontal pixel position • Y-coordinate: vertical pixel position • Pixel colour: 0 = black, 1 = white A single white pixel in the upper left corner can be created like this: oled.pixel (0, 0, 1)

and using oled.invert (True).

the OLED colours are inverted. White becomes black and vice versa. To return to the original colours, oled.invert (False) can be used.

10.1 Graphical representations In addition to the pixel instructions, other graphic commands are also available. Horizontal and vertical lines can be drawn with .hline () or .vline (). The XY-start position as well as the line length and colour are specified.

● 135

MicroPython for Microcontrollers

For example, the following program draws concentric rectangular frames on the display: # SSD1306_frames.py from machine import Pin, I2C import ssd1306 i2c = I2C(-1,scl=Pin(22),sda=Pin(21)) oled_width = 128 oled_height = 64 oled = ssd1306.SSD1306_I2C(oled_width, oled_height, i2c) for n in [0,5,10,15,20,25]: oled.hline(n, n, oled_width-1-2*n, 1-2*n) oled.hline(n, oled_height-1-n, oled_width-1-2*n, 1-2*n) oled.vline(n, n, oled_height-1-2*n, 1-2*n) oled.vline(oled_width-1-n, n, oled_height-2*n, 1-2*n) oled.show()

Figure 10.3: Frame in the OLED display. Diagonals are drawn using: .line (x1, y1, x2, y2, c) between two defined points (x1, y1) and (x2, y2). The parameter c controls the colour of the drawn line. For simple graphics bitmaps can be written pixel by pixel into the display buffer. The following program shows a corresponding example: # SSD1306_bitmap_DEMO.py from machine import Pin, I2C import ssd1306 import urandom i2c = I2C(-1, scl=Pin(22), sda=Pin(21)) oled_width = 128 oled_height = 64

● 136

Chapter 10 • Display Technology and Small-Size Screens

oled = ssd1306.SSD1306_I2C(oled_width, oled_height, i2c) # frame oled.hline(0, 0, oled_width-1, 1) oled.hline(0, oled_height-1, oled_width-1, 1) oled.vline(0, 0, oled_height-1, 1) oled.vline(oled_width-1, 0, oled_height, 1) oled.show() ICON = [ [0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0], [0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0], [0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0], [0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0], ] for n in range(12): xofs = urandom.randint(1, oled_width-12) yofs = urandom.randint(1, oled_height-12) for y, row in enumerate(ICON): for x, c in enumerate(row): oled.pixel(x+xofs, y+yofs, c) oled.show()

with the following result on the display:

● 137

MicroPython for Microcontrollers

Figure 10.4: Graphic elements on the OLED display.

10.2 OLED display as data plotter In addition to bitmaps, measurement data can also be graphically displayed on the OLED display. This means you are no longer dependent on the plotter function in Thonny but can also set up stand-alone devices with graphic output. The following program provides a rolling display as known from professional ECG devices in hospitals. # Rolling_ECG_display.py from machine import Pin, ADC, I2C from time import sleep import ssd1306 i2c = I2C(-1, scl=Pin(22), sda=Pin(21)) oled_width = 128 oled_height = 64 oled = ssd1306.SSD1306_I2C(oled_width, oled_height, i2c) pot = ADC(Pin(34)) pot.atten(ADC.ATTN_11DB)

#Full range: 3.3v

vMax = 3.4 dotPos_old = int(oled_height/2) while True: pot_value = pot.read() voltage = 0.000816*pot_value + 0.037822 # print(voltage) dotPos_new = int(voltage/vMax*oled_height)

● 138

Chapter 10 • Display Technology and Small-Size Screens

oled.line(0, dotPos_new, 0, dotPos_old, 1) oled.scroll(1, 0) oled.line(0, dotPos_new, 0, dotPos_old, 0) dotPos_old = dotPos_new oled.pixel(0, int(oled_height/2), 1) oled.show()

To record the measured values a potentiometer can be connected to the ADC input 34 (see section 9.2). After starting the program the voltage values are shown continuously on the display. This is made possible by the integrated scroll function. Via the instruction oled.scroll(1, 0)

the entire screen content is moved by one pixel. If you do not want to record single pixels but a continuous curve, you have to connect the points with lines. Two variables are necessary for this: dotPos_old

and dotPos_new

This draws a line between the current and the last measured value. Then the display is shifted by one pixel. Finally the new position is transferred to the temporary memory: dotPos_old = dotPos_new

and the game starts all over again. The following figure shows an example of continuously changing potentiometer values:

● 139

MicroPython for Microcontrollers

Figure 10.5: Data output on the OLED display. If you have an ECG amplifier, you can also record the electrical signals of the human heart in this way. The result is the typical electrocardiogram, as known from intensive care units in hospitals:

Figure 10.6: ECG signal on the OLED display.

10.3 The exact time please: digital clock with OLED display Another useful application for the display is the output of the time. This turns the ESP32 together with the SSD1307 into a practical digital clock. The function time() from the time module returns the number of seconds since the board was switched on or reset. Via a variable time_offset=20*3600+00*60+0 # hh+mm+ss

● 140

Chapter 10 • Display Technology and Small-Size Screens

a start time can be specified. In this case the clock starts with the time 20:00:00. The routine "time_text()": .

def time_text(time): secs=time%60 mins=(time//60)%60 hours=(time//3600)%24 return "{:02d}:{:02d}:{:02d}".format(hours,mins,secs)

converts the consecutive seconds into hours, minutes and seconds, i.e. into the usual hh:mm:ss representation.

Figure 10.7: Digital clock with OLED display The clock can be set using two pushbuttons (Ta1 and Ta2) on ports 02 and 04.

● 141

MicroPython for Microcontrollers

Figure 10.8: Circuit diagram of the digital clock. The buttons are again equipped with 100-nF capacitors for debouncing. The 1-kohm resistors serve as pull-ups. The associated interrupt routines def handle_interrupt_min(pin): global time_offset time_offset+=60 time.sleep(.2)

and def handle_interrupt_hr(pin): global time_offset time_offset+=3600 time.sleep(.2)

ensure that the minutes (60 seconds) or hours (3600 seconds) increase by one each time the key is pressed. The complete digital clock program looks like this: # setable_clock.py from machine import Pin,I2C import time from ssd1306 import SSD1306_I2C

● 142

Chapter 10 • Display Technology and Small-Size Screens

i2c = I2C(-1,scl=Pin(22),sda=Pin(21)) oled_width=128 oled_height=64 oled = SSD1306_I2C(oled_width,oled_height,i2c) time_offset=20*3600+00*60+0

# hh+mm+ss

lin_hight=5 col_width=8 def handle_interrupt_min(pin): global time_offset time_offset+=60 time.sleep(.2) def handle_interrupt_hr(pin): global time_offset time_offset+=3600 time.sleep(.2) button_min = Pin(4, Pin.IN) button_min.irq(trigger=Pin.IRQ_RISING, handler=handle_interrupt_min) button_hr = Pin(2, Pin.IN) button_hr.irq(trigger=Pin.IRQ_RISING, handler=handle_interrupt_hr) def text_write(text, lin, col=0): oled.text(text, col*col_width, lin*lin_hight) def time_text(time): secs=time%60 mins=(time//60)%60 hours=(time//3600)%24 return "{:02d}:{:02d}:{:02d}".format(hours,mins,secs) def show(): oled.fill(0) text_write("Current time:",1,2) current_text = time_text(current_time) text_write(current_text,6,4) oled.rect(10,25,108,16,1) oled.show() while True: current_time=time_offset+time.time() show()

● 143

MicroPython for Microcontrollers

10.4 Not just for athletes: a stopwatch A stopwatch can also be easily realized. A resolution as high as 1/1000 second is even possible with little effort. The hardware structure shown in Figure 10.8 can be used unmodified. The keys, however, have new functions: Ta1: Start / Reset Ta2: Stop If you wish to forfeit the 1-kohm pullups, you can also activate the internal pull-up resistors: start_button = Pin(2,Pin.IN,Pin.PULL_UP) stop_button = Pin(4,Pin.IN,Pin.PULL_UP)

This results in the following program: # stopwatch.py from machine import Pin, I2C import time from ssd1306 import SSD1306_I2C i2c = I2C(-1, scl=Pin(22), sda=Pin(21)) oled_width = 128 oled_height = 64 oled = SSD1306_I2C(oled_width,oled_height,i2c) start_button = Pin(2,Pin.IN,Pin.PULL_UP) stop_button = Pin(4,Pin.IN,Pin.PULL_UP) start_time = 0 total_time = 0 active = False lin_hight = 5 col_width = 8 led = Pin(25, Pin.OUT) def text_write(text, lin, col=0): oled.text(text, col*col_width, lin*lin_hight) def time_text(time): mills = time%1000 secs = (time//1000)%60 mins = (time//60000)%60 hours = (time//3600000)%24 return "{:02d}:{:02d}:{:02d}.{:03d}".format(hours,mins,secs,mills)

● 144

Chapter 10 • Display Technology and Small-Size Screens

def show(): oled.fill(0) total_text=time_text(total_time) text_write(total_text,6,2) oled.show() while True: if not active: led.value(0) if not start_button.value(): start_time = time.ticks_ms() active = True if active: led.value(1) total_time = time.ticks_ms() - start_time if not stop_button.value(): active = False time.sleep(3) total_time=0 show()

In the main loop, two states are assumed via the variable "active". When the stopwatch is stopped, the system waits until the start button is pressed: if not start_button.value():

The clock then starts. With the second push-button the clock is stopped, and the stopped time can be read. Pressing Ta1 again resets the time, and the clock is available for new time readings. The pushbuttons are set to "low-active". This means that in the normal state a HIGH signal (3.3 V) is present at pins 02 and 04. When a key is pressed, it is pulled to LOW (GND). Therefore the construction if not ... is to be used in the program.

10.5 Just touch: stop watch with sensor keys The stopwatch can also be controlled by capacitive sensors. Then the push buttons can be saved and replaced by simple metallic pads. Furthermore, the problem of key bouncing is eliminated. The following illustration shows a layout suggestion for this. The 1-kohm protective resistors were omitted here. However, if the clock is to be used for a longer period of time in practice, they should be installed as shown in Figure 9.9. This reduces the risk of damage to the ESP controller by electrostatic voltages.

● 145

MicroPython for Microcontrollers

Figure 10.9: Stopwatch with sensor buttons. In the program, the button interrogation is replaced by two routines for capacitive sensors: def start_touch(): if t1.read() < 500: return True else: return False def stop_touch(): if t2.read() < 500: return True else: return False

If necessary, the threshold value 500 can be adapted to the real conditions. In the main loop, only the button queries then have to be replaced by the new routines: # stopwatch_touch_sensor.py from machine import Pin, I2C, TouchPad import time from ssd1306 import SSD1306_I2C

● 146

Chapter 10 • Display Technology and Small-Size Screens

i2c = I2C(-1, scl=Pin(22), sda=Pin(21)) oled_width = 128 oled_height = 64 oled = SSD1306_I2C(oled_width,oled_height,i2c) t1 = TouchPad(Pin(2)) # start sensor pad t2 = TouchPad(Pin(4)) # stop sensor pad start_time = 0 total_time = 0 active = False lin_hight = 5 col_width = 8 led = Pin(25, Pin.OUT) def text_write(text, lin, col=0): oled.text(text, col*col_width, lin*lin_hight) def time_text(time): mills = time%1000 secs = (time//1000)%60 mins = (time//60000)%60 hours = (time//3600000)%24 return "{:02d}:{:02d}:{:02d}.{:03d}".format(hours,mins,secs,mills) def show(): oled.fill(0) total_text=time_text(total_time) text_write(total_text,6,2) oled.show() def start_touch(): if t1.read() < 500: return True else: return False def stop_touch(): if t2.read() < 500: return True else: return False

● 147

MicroPython for Microcontrollers

while True: if not active: led.value(0) if start_touch(): start_time = time.ticks_ms() active = True if active: led.value(1) total_time = time.ticks_ms() - start_time if stop_touch(): active = False time.sleep(3) total_time=0 show()

This application demonstrates how the integrated touch sensor function of the ESP32 can be used easily and beneficially.

10.6 Great climate with the BME280 sensor! OLED displays are also ideally suited for the output of sensor values, as the following illustration shows:

Figure 10.10: Sensor values on the OLED display. The following program demonstrates how the values of the BME280 sensor (see Section 9.19) can be shown on the display. This makes you independent of a PC or laptop as data terminal: # BME280 Temp_Humit_Press-sensor_to_SSD1306.py from machine import Pin, I2C from time import sleep import ssd1306 import BME280 # ESP32 - Pin assignment i2c = I2C(scl=Pin(22), sda=Pin(21), freq=10000)

● 148

Chapter 10 • Display Technology and Small-Size Screens

# OLED setup oled_width = 128 oled_height = 64 oled = ssd1306.SSD1306_I2C(oled_width, oled_height, i2c) while True: oled.fill(0) oled.text(‚BME280 climate', 0, 0) bme = BME280.BME280(i2c=i2c) temp = bme.read_temperature()/100 hum = bme.read_humidity()/1024 pres = bme.read_pressure()/25600 print(‚Temp: %7.2f' %temp) print(‚Humi: %7.2f' %hum) print(‚Pres: %7.2f' %pres) print() temp_string=str(‚Temp:%7.1f' %temp) hum_string =str(‚Humi:%7.1f' %hum) pres_string=str(‚Pres:%7.1f' %pres) oled.text(temp_string, 0, 10) oled.text(‚ C', 90 ,10) oled.text(hum_string, 0, 20) oled.text(‚ %', 90 ,20) oled.text(pres_string, 0, 30) oled.text(‚ hPa', 90 ,30) oled.show() sleep(1)

If the ESP32 is expected to start automatically after a power interruption, the program must be reloaded as main.py, together with a dummy-boot.py file. In this way, you can now build small and compact devices which can take over useful tasks in everyday life. Refer to Section 14.6 for methods of transferring climate data to the internet by way of WLAN.

● 149

MicroPython for Microcontrollers

Chapter 11 • LED Matrices and Large Displays After describing the use of OLED displays in detail in the last chapter, the following sections will focus on the control of another very popular display, using MicroPython. With so-called dot-matrix displays, you can also display numbers, letters, symbols and graphics. The main difference to the OLED display is the achievable brightness and the size of the display. LED matrices can be up to several meters in size. Very high brightness levels can also be achieved with modern LEDs. This display variant is therefore often used for large-surface displays or advertising boards in busy squares, railway stations or airports and in public buses and trains. In the stock exchange halls of the world, the current financial data appear on so-called "live tickers". Dot-matrices are particularly popular in Asia, as they can also be used to represent Far Eastern characters, as the following illustration shows:

Figure 11.1: LED dot matrices are very popular in Asia. LED matrices with 5 x 7 = 35 LEDs are widely used. But various other designs are available, too. Designs with 8 x 8 LEDs are also frequently encountered.

Figure 11.2: Principle of dot matrix control. The direct control of 8 x 8 dot matrices would require 65 lines, since 64 pin connections and a common cathode would have to be connected. With a matrix, considerably fewer connections are required. Here, 8 LEDs are connected in one column and one row. So only 8 + 8 = 16 connections are necessary. The figure above shows the principle for a 3 x 4 matrix. Instead of 13 connections only 7 connections are required for individual control of the LEDs.

● 150

Chapter 11 • LED Matrices and Large Displays

To control the second LED in the second line, for example, all line connections except the second must be set to HIGH. The second connection, however, must be at GND-potential. In the case of the columns, HIGH potential may only be present in the second column. The direct control of dot matrices demands a large part of the controller's resources. If sensor values are also to be recorded or actuators are to be controlled, even a powerful ESP32 controller quickly reaches its limits. The control of larger displays with one hundred or more LEDs also quickly becomes a problem, on the one hand because of the required computing power, and on the other because of the limited number of available pins on a controller. Cost-effective display drivers such as the MAX7219 can help here. These devices have an SPI-compatible interface and can thus control displays with up to 8 x 8 = 64 matrix elements with only three digital pins. The drivers are available as complete modules. The following figure shows an example:

Figure 11.3: LED Matrix Module. Connecting the driver modules to the ESP32 is very easy. Only the three SPI- pins have to be connected to the controller board: • MAX7219_data (DIN) Port D02 • MAX7219_load (CS) Port D05 • MAX7219_clock (CLK)→ Port D04 • MAX7219_GND ESP31 GND Due to the relatively high power consumption, it is advisable to provide the power supply externally. This method allows almost any size of display to be set up. The controller is hardly loaded anymore, since only individual commands have to be sent via the SPI bus. In addition, sufficient pins remain free for operating external sensors or other peripherals. Now nothing stands in the way of the realization of large-format displays, for example, for advertising purposes or at sports events.

● 151

MicroPython for Microcontrollers

A link for a suitable Python library to control the Maxim ICs can be found in the download package. After the driver file "Max7219.py" has been downloaded to the controller, the following instructions are available: spi = SPI(1, baudrate=10000000, polarity=1, phase=0, sck=Pin(CLK), mosi=Pin(DIN)) ss = Pin(CS, Pin.OUT)

for the above pin assignment, set • CLK = 4 • DIN = 2 • CS = 5 Next, a display "object" can be created: display = max7219.Matrix8x8(spi, ss, MN)

whereby for MN, the number of matrix elements used must be entered. Afterwards, texts and graphics can be designed with the following commands: display.pixel(x,y,1) set a pixel at the coordinate x,y display.pixel(x,y,0) delete a pixel at the coordinate x,y display.hline(x,y,l,1) horizontal line from x,y - length l display.vline(x,y,l,1) vertical line from x,y - length l display.line(a,b,c,d,1) line from a,b to c,d display.rect(a,b,c,d,1) rectangle with corners a, b, c, d display.text('text',x,y,1) text at position x,y display.scroll(x,0) scroll by x pixels display.show() update display This allows you to create advertisements that are effective and easy to read even from several metres away,

11.1 LED matrix in action The following code shows an example of a display with six 8 x 8 matrix elements: # LED_matrix_test.py import max7219 from machine import Pin, SPI spi = SPI(1, baudrate=10000000, polarity=1, phase=0, sck=Pin(4), mosi=Pin(2)) ss = Pin(5, Pin.OUT)

● 152

Chapter 11 • LED Matrices and Large Displays

display = max7219.Matrix8x8(spi, ss, 6) display.text(‚Python',0,0,1) display.show()

After loading the program onto the ESP controller, the text is shown on the display:

Figure 11.4: Dot matrix display with six 8 x 8 matrix elements. Displays and texts do not have to be static. Even moving graphics can be implemented without any problems. The next section shows a corresponding example.

11.2 Running scripts and animated graphics The scroll function can also be used to create running scripts and the like. This allows longer texts to be output on small or short displays. The following program lets the lettering "Python" run from right to left over a dot-matrix display: # LED_matrix_ticker.py import max7219 from machine import Pin, SPI from time import sleep spi = SPI(1,baudrate=10000000, polarity=1, phase=0, sck=Pin(4), mosi=Pin(2)) ss = Pin(5,Pin.OUT) speedFactor=0.05 pixelDistance=7 display = max7219.Matrix8x8(spi, ss, 6) def moveLeft(Pixel): for i in range(Pixel): display.scroll(-1,0) sleep(speedFactor) display.show() while True: display.text(‚P',40,0,1) moveLeft(pixelDistance) display.text(‚y',40,0,1) moveLeft(pixelDistance) display.text(‚t',40,0,1) moveLeft(pixelDistance) display.text(‚h',40,0,1)

● 153

MicroPython for Microcontrollers

moveLeft(pixelDistance) display.text(‚o',40,0,1) moveLeft(pixelDistance) display.text(‚n',40,0,1) moveLeft(pixelDistance) display.text(‚ ‚,40,0,1) moveLeft(pixelDistance)

The individual letters are generated using display.text('....',40,0,1)

at the right-hand edge of the display. Next, these are moved to the left by the value "pixelDistance" using the function "moveLeft": for i in range(8): display.scroll(-1,0) sleep(speedFactor)

The apparent running speed can be changed with the value "speedFactor".

● 154

Chapter 12 • Physical Computing: Servos Bring Movement into Play

Chapter 12 • P  hysical Computing: Servos Bring Movement into Play "Give me a place to stand and with a lever I will move the whole world." Archimedes is said to have used this sentence to illustrate the law of levers. Today he could say, "give me a servo and I will move the whole world!" Physical computing is concerned with the collection of environmental data and the control and regulation of mechanical variables. Using sensors, important data can be easily collected and quantified. The control of mechanical variables, on the other hand, is usually associated with greater effort. Increasingly, physical computing finds its way into art and design. It is also used in robotics and in the development of autonomous machines. Astonishing PhysCom-based projects have already been realized with microcontrollers, including self-balancing robots, laser light harvests, automated high-speed photography or a wide variety of home automation projects. The actuators available are, for example, electromagnets, direct-current, stepper, or servo motors. If these are to be operated by a controller, special measures are required to suppress induction voltages, such as blocking capacitors and flyback (anti-surge) diodes. The simplest way is to control model making servo motors. These contain complete drive systems including motor control and positioning system. The latter consists of a gearbox and a potentiometer. The potentiometer is firmly connected to the motor axis via the gear unit. The potentiometer voltage thus provides a direct measure of the current motor position. A control loop ensures that the servo can be precisely positioned via a control signal. Such systems are therefore ideally suited for control by microcontrollers.

12.1 A servo tester The method of pulse width modulation has already been used to generate quasi-analogue signals. This allowed the brightness of LEDs to be continuously changed. A special type of PWM is also used to control a servo. The following illustration shows a corresponding signal curve and the corresponding servo positions.

● 155

MicroPython for Microcontrollers

Figure 12.1: Servo control signal. The pulse interval of approx. 20 ms, or the repetition frequency of 50 Hz is of minor importance. Larger tolerances are also acceptable here. The position information lies in the duration of the control pulse. The following quasi-standard has been established for this: Pulse Duration

Arm Position

1 ms

Left stop

1.5 ms

Middle position

2 ms

Right stop

Figure 12.2: Servo for use in model building. Due to the integrated control electronics, only one control line is required in addition to the power supply. This can be connected to any I/O pin. The cables are marked by the following colours as standard:

● 156

Chapter 12 • Physical Computing: Servos Bring Movement into Play

Red: +5 V Black: GND Orange or brown: Control signal For larger servos a separate 5 V source is recommended. Here rechargeable batteries or a suitably sized mains adapter can be used. The control of servos with MicroPython requires the machine module: from machine import Pin

This can be used to specify the pin on which the servo is to operate, e.g. pin 18: p4 = machine.pin(18)

The PWM frequency is set to 50 Hz, corresponding to a period of 20 ms: servo = machine.PWM(p4,freq=50)

This completes the servo object. Now the duty cycle must be defined. The PWM has a resolution of 10 bits, i.e. 2^10 = 1024 values. To reach the middle position of the servo arm, a pulse duration of 1.5 ms / (20 ms / 1023) = 76.7 ms, i.e. the value 77, is the best approximation. Correspondingly, the values 52 and 102 result to the right and left extreme positions respectively, so that these parameters can be defined in the program: # duty for servo is between 52...102 duty_min=52 # 52*20/1023 ms=1.02 ms duty_mid=77 # 77*20/1023 ms=1.51 ms duty_max=102 # 102*20/1023 ms=1.99 ms

For these values, the servo arm moves to the following positions: 52:

Left stop

(–45° position)

77:

Middle position

(0° position)

102:

Right stop

(+45° position)

Since larger deflections lead to damage in some servo versions, values exceeding about 45° should be avoided.

● 157

MicroPython for Microcontrollers

A servo test can now be carried out with the following Python program: # Servo_tst.py import machine from machine import Pin from time import sleep p4 = machine.Pin(18) servo = machine.PWM(p4,freq=50) # duty for servo is between 52...102 duty_min=52 # 52*20/1023 ms=1.02 ms duty_mid=77 # 77*20/1023 ms=1.51 ms duty_max=102 # 102*20/1023 ms=1.99 ms while True: for pos in (duty_min,duty_mid,duty_max): print(pos) servo.duty(pos) sleep(1)

After connecting the servo (see figure) and loading the program, the servo arm should move from the minimum position via the centre to the maximum excursion and back again.

Figure 12.3: Servo on the ESP32

12.2 Mega-display servo thermometer In addition to model building applications, servos can also be used in many other areas. One interesting application is large-format displays which are easy to read even from long distances. With an OLED display it is already difficult to read the numbers from a distance of more than one metre. The display value of the servo display presented here, on the other hand, can easily be seen from several meters. When a pointer is attached to the servo, a

● 158

Chapter 12 • Physical Computing: Servos Bring Movement into Play

very flexible quasi-analogue display instrument is created. By means of a scale, values can then be displayed as on a classic measuring instrument. The program for a temperature display consists of a combination of the evaluation code for the DS18B20 from Chapter 9.11 and the servo control: # servoDisplay_thermometer.py import machine from machine import Pin import onewire import ds18x20 from time import sleep p4 = machine.Pin(18) servo = machine.PWM(p4,freq=50) # duty for servo is between 40 - 115 duty_min=52

# 52*20/1023

ms=1.02 ms

duty_mid=77

# 77*20/1023

ms=1.51 ms

duty_max=102 # 102*20/1023 ms=1.99 ms ow=onewire.OneWire(Pin(25))

#Init wire

ow.scan() ds=ds18x20.DS18X20(ow)

#create ds18x20 object

while True: roms=ds.scan()

#scan ds18x20

ds.convert_temp()

#convert temperature

for rom in roms: T=ds.read_temp(rom) print(T)

# test output temperature

pos = int(duty_max-(duty_max-duty_min)*T/50) print(pos)

# test output servo position

servo.duty(pos) sleep(1)

Only a single DS18(x)20 sensor is required to operate the thermometer. If several measuring transducers are connected to the One-Wire bus, the one with the most significant identifier is evaluated. Pin 18 has been selected for connecting the servo signal. In addition only the power supply lines must be connected to GND and VIN (5 V) on the ESP board. However, it is better to use a separate supply for the servo. The following figures show the circuit diagram using an external power supply and a suggested layout for the display.

● 159

MicroPython for Microcontrollers

Figure 12.4: Circuit diagram for thermometer with servo display.

Figure 12.5: Setup of the thermometer with servo-driven pointer readout.

● 160

Chapter 13 • RFID and Wireless Data Transmission

Chapter 13 • RFID and Wireless Data Transmission RFID stands for Radio-Frequency Identification. Reader devices with this functionality are able to read data wirelessly from passive transponders called RFID tags, over the air, i.e. by radio. A transponder (transmitter / responder) can be labelled with a special code that makes it clearly identifiable. MicroPython provides a special library that allows these codes to be read out wirelessly (see download package). This allows the ESP32 to be used to implement locking systems or similar projects in which a person has to identify themselves with a transmitter. The transponders are available in a wide variety of shapes and variants. The following illustrations show first a receiver module and then two different RFID TAGs. One of the two tags has the form of a key fob, the other one consists of a plastic card in credit card format.

Figure 13.1: RFID module.

Figure 13.2: RFID card and keychain. Transponders can absorb energy from an electromagnetic field generated by the transmitter. This means that the transmitter integrated in the transponder can be operated without its own energy source. A classic RFID TAG therefore does not need built-in batteries or accumulators and is permanently ready for use. The transponder sends back its integrated code on a fixed frequency. This code is then received and processed further.

● 161

MicroPython for Microcontrollers

RFID TAGs can also be written with new codes. However, this is very time-consuming, which is why the procedure is not pursued further here. Most applications can also be carried out with the codes already present in the tags.

13.1 Reading cards and chips With the mfrc522.py library, the "Unique Identifier" (UID) number, which contains the individual identification data of an RFID TAG, can be read. A Python program for this goes along these lines: # RFID_test.py import mfrc522 # RFID RX pinning sck = 0 mosi= 2 miso= 4 rst = 5 cs

=14

# SDA on RFID-RC522 boards

def do_read(): rdr = mfrc522.MFRC522(sck, mosi, miso, rst, cs) print("Place card before reader") try: while True: (stat, tag_type) = rdr.request(rdr.REQIDL) if stat == rdr.OK: (stat, raw_uid) = rdr.anticoll() if stat == rdr.OK: print("Card detected") print("type: 0x%02x" % tag_type) print(raw_uid[0], raw_uid[1], raw_uid[2], raw_uid[3]) print("") except KeyboardInterrupt: print("Bye") while True: do_read()

Here, the pins for connecting the RFID module to the ESP32 are first defined. The following figure shows the wiring diagram:

● 162

Chapter 13 • RFID and Wireless Data Transmission

Figure 13.3: RFID module on an ESP32 The following table lists the required connections: RFID module

ESP32

SCK

I/O 00

MOSI

I/O 02

MISO

I/O 04

RST

I/O 05

CS (SDA)

I/O 14

RST

not connected

The routine called do_read() then takes care of reading the TAGs. After starting the program, a card or another TAG must be brought within the range of the RFID module. An output in the following form should then appear in the console:

Figure 13.4: ID numbers of different RFID TAGs

● 163

MicroPython for Microcontrollers

13.2 Contactless and secure: RFID lock RFID technology works touch-free and thus is highly hygienic and anti-contaminant. Switchon or switch-off processes can be triggered over several centimetres. Possible applications are the opening of locks, doors and gates with coded key cards. As this procedure does not require direct physical contact, it is also often used in hospitals and nursing homes for hygiene reasons.

A person who is authorized to enter a particular room is given his or her own TAG in the form of a card or key ring. An RFID module attached to the door opens a locking mechanism only if a valid RFID TAG comes into its range. There are several advantages compared to locks with matching keys: 1. TAGs are significantly cheaper than security keys 2. If an ID-TAG is lost, the relevant code is deleted from the list of valid IDs. The replacement of locks or locking systems is not required. 3. Certain people, such as hotel guests who have accidentally taken their TAG home, can be blocked. In this case, blocking the relevant code can restore security. In practical applications, a certain UID can be compared with the access-authorised card number. The following program shows an example: # RFID_access_control.py import mfrc522 from machine import Pin, PWM from time import sleep # RFID RX pinning sck = 0 mosi= 2 miso= 4 rst = 5 cs

=14

# or SDA on RFID-RC522 boards

ledRed = Pin(18, Pin.OUT) ledGreen = Pin(19, Pin.OUT) p4 = Pin(21) servo = PWM(p4,freq=50) duty_min=52 # 52*20/1023 ms=1.02 ms duty_max=102 # 102*20/1023 ms=1.99 ms

● 164

Chapter 13 • RFID and Wireless Data Transmission

servo.duty(duty_max) def open_lock(): servo.duty(duty_min) sleep(1) servo.duty(duty_max) def do_read(): rdr = mfrc522.MFRC522(sck, mosi, miso, rst, cs) print("") print("Place card before reader to read from address 0x08") print("") try: while True: (stat, tag_type) = rdr.request(rdr.REQIDL) if stat == rdr.OK: (stat, raw_uid) = rdr.anticoll() if stat == rdr.OK: print("New card detected") print("

- tag type: 0x%02x" % tag_type)

print(raw_uid[0], raw_uid[1], raw_uid[2], raw_uid[3]) print("") if raw_uid[0]==124 and raw_uid[1]==24 and raw_uid[2]==62 and raw_uid[3]==17: print("OK!") ledGreen.value(1) open_lock() sleep(1) ledGreen.value(0) else: print("NOT OK!") ledRed.value(1) sleep(1) ledRed.value(0)

except KeyboardInterrupt: print("Bye") while True: do_read()

● 165

MicroPython for Microcontrollers

Once the PINs for the RFID transponder have been defined, two LEDs are activated. The red one indicates an invalid card, the green one lights up when an approved UID is detected. To trigger a switching operation, the knowledge from the last chapter can be used. A closing mechanism can be moved via a model-making servo, here at pin 21. In the procedure "do_read", the card data are read out via rdr = mfrc522.MFRC522(sck, mosi, miso, rst, cs)

A note that reads print("Place card before reader to read from address 0x08")

prompts you to hold the card up to the transponder. In practice, this request can of course also be done via a small display. The decisive program line if raw_uid[0]==136 and raw_uid[1]==4 and raw_uid[2]==97 and raw_uid[3]==65:

compares the read UID with the given data in the example: 124 24 62 17 If there is a match, the closing mechanism is actuated. Otherwise, only the red LED lights up briefly. To read out card codes, you can use the program from the last chapter. The following figure shows a possible application in the form of a lock box. All electronics are integrated into the lock box. To open the box, a valid RFID TAG is brought into its vicinity. As a precaution, you should always include access for an external power supply. If the batteries are empty, the box would otherwise have to be opened by force.

Figure 13.5: RFID-controlled Vault.

● 166

Chapter 14 • MicroPython and the Internet of Things (IoT)

Chapter 14 • M  icroPython and the Internet of Things (IoT) In this chapter, the ESP board gets integrated into a network. In addition to wired connections, most networks now also have WLAN (wireless LAN). This means that the advantages of a computer network can be used without the need to lay cables. In principle, each connection of two computers already represents a simple network. If more and more computers, laptops, PCs or tablets are included, more and more complex structures are created. These can be set up via various network components such as hubs, routers and switches. This requires a suitable transmission protocol. On the global internet, the TCP-IP protocol is used for this purpose. The standard protocol in Ethernet and thus also in WLAN is called TCP (Transfer Control Protocol). This protocol allows the transmission of data via local or even global networks and ensures almost error-free data communication. IP stands for Internet Protocol. This is where the addressing of data packets takes place. Since there are always several senders and receivers in a network, a procedure is necessary that always transmits the data packets to be transmitted to the correct receiver. The IP protocol ensures the correct addressing of the data packets. The IP addresses of the IPv4 notation consist of 4 bytes of 8 bits each, i.e., a total of 32 bits. So, theoretically, 232 = 4,294,967,296 addresses are available. Even this large number is now no longer sufficient for the global internet. IoT applications and machine-to-machine communication in particular require that the system be expanded to IPv6. However, home networks continue to work with 4-byte addresses. In the private router, each device is assigned an address of the form xxx.xxx.xxx.xxx For example, the IP address 192.168.178.32. The assignment of an IP address can also be done fully automatically. If the ESP32 is to be integrated into a WLAN, only the network name and access code must be known. Further details are explained in the next chapters. Note: in the following, various information such as IP addresses are "greyed out" for reasons of data protection, even if this is not necessarily highly sensitive information. This procedure should also be understood as an indication of the cautious handling of data in general.

● 167

MicroPython for Microcontrollers

The so-called MAC address (for Media Access Control) also plays an important role. This is a globally unique identifier that is assigned to every network-compatible device. It consists of six bytes. The first three bytes indicate a manufacturer-specific identification code, followed by an individual code given by the manufacturer. A typical MAC address looks like this: 22-2C-DA-3A-A4-1B The MAC address is required if network components are to be explicitly addressed for the benefit of services offered on higher communication layers. Since this also applies to an ESP32 chip, it is also assigned its own MAC address. If the router of a home network is connected to the internet via a DSL line or even an optical fibre, it is called a "gateway". The gateway function is also assigned a special IP address. When data packets are sent to this address, the gateway forwards the data via the provider to the internet. In this way, data can be exchanged with the controller over the full internet. In the following chapters, for example, global communication is established via the ThingSpeak server.

14.1 For modern detectives: a network scanner When police radio was still 100% analogue, crooks often used so-called "radio scanners" to listen in on police communications. The introduction of digital radio transmission and sophisticated encryption methods put a stop to this activity. As far as WLAN goes, however, scanners are completely legal and can be used by anyone. In a first application, the ESP board is used as a scanner. It can be used to detect all active networks in the vicinity. The function station.scan()

returns a list with information on all locally available WLAN access points: • ssid: "Service Set Identifier", i.e., the name of the WLAN-Network • bssid: "Basic Service Set Identification" — corresponds to the MAC address of the wireless access point • channel: network channel • RSSI:  "Received Signal Strength Indicator": signal strength in dB • authmode: authentication mode: – open – WEP – WPA-PSK – WPA2-PSK – WPA/WPA2-PSK • hidden: hidden network? False – station visible True – station hidden

● 168

Chapter 14 • MicroPython and the Internet of Things (IoT)

Accordingly, a MicroPython WLAN scanner can look like this: # boot.py : executed @ every boot # WLAN scanner import network station = network.WLAN(network.STA_IF) station.active(True) n=station.scan() print("Wifi networks found:") print("---------------------") for i in n: print("Network: ", i[0]) print("BSSID: ", i[1]) print("channel: ", i[2]) print("RSSI: ", i[3], "dB") print("authmode: ", i[4]) print("hidden: ", i[5]) print("---------------------")

The data is output to the console:

Figure 14.1: WLAN scan in the shell. The program detects all WLAN networks within range. This function is very useful, for example, if you want to check quickly and easily whether a WLAN is available at a certain location.

14.2 Connected but no cables: WLAN The ESP32's WLAN interface can also be used to exchange information with a network. This makes it possible to control devices, systems or installations. All kinds of electrical devices can then be switched wirelessly via WLAN using a web server.

● 169

MicroPython for Microcontrollers

In order for the ESP-based server to restart automatically after a possible reboot, the two files • boot.py • main.py are required. The boot.py file contains the program parts that are needed to start the network connection. These include importing libraries, information for logging into the network and establishing the connection with the local WLAN: # boot.py für WLAN connection try: import usocket as socket except: import socket import network from machine import Pin import dht import esp esp.osdebug(None) import gc gc.collect() ssid = ‚xxxxxxxxxxxxx' password = ‚12345678901234567890' station = network.WLAN(network.STA_IF) station.active(True) station.connect(ssid, password) while station.isconnected() == False: pass print(‚Connection successful') print(station.ifconfig())

The information for the network access

● 170

Chapter 14 • MicroPython and the Internet of Things (IoT)

• ssid = ‚xxxxxxxxxxxxx' • password = ‚12345678901234567890' is to be replaced by the corresponding data of the domestic WLAN. This can be found, for example, on the back of the router, or in its instruction manual. Web servers work with so-called "sockets" of the Python API. Sockets are program units that serve as communication end points. They provide the basis for data exchange with other programmes or computers. The communication partners can be installed on the same computer, on a network element, or on computers accessible via the network. Communication via sockets can be bidirectional. Data can therefore be simultaneously received and sent. Sockets thus form a platform-independent, standardised interface between a network protocol and the underlying application software. The socket library for the ESP controller is imported as follows (see boot.py): try: import usocket as socket except: import socket

So, if the more universal usocket module is not available, the standard version is used. Then the network library is imported. This enables the ESP32 to exchange data with WLAN networks. For the wireless control of the GPIO pins, only the pin class from the machine module is required: from machine import Pin

The lines import esp esp.osdebug(None)

disable the debugging messages. If the output of corresponding information is desired, the lines can be omitted or commented out. A so-called "garbage collector" (gc) is then activated. This represents a possible form of automatic memory management. This releases memory space that may be occupied by objects that are no longer used by the program. With the information for logging into the WLAN (network SSID and password of the router used), the ESP32 can establish a connection to the local router. The ESP32 is then set up and activated as a WLAN station: station = network.WLAN(network.STA_IF) station.active(True)

● 171

MicroPython for Microcontrollers

After that, the controller establishes a connection to the router. The while loop ensures that the program is not continued as long as the ESP module is not connected to the local WLAN network. After a successful connection, the network parameters, including the IP address of the ESP32, are output:

Figure 14.2: Output of the network parameters

14.3 Switch and control with the web server After the board has made contact with the WLAN, an independent web server can be set up. This can be used, for example, to control various outputs. The server should offer the following possibilities: • Control of separate channels for the GPIOs of the ESP board. • Access via an IP address. • Control via any browser in the local home network. • Clicking on the buttons of the web server should immediately change the status of the active channels. • Feedback by displaying the current port status on the web page. To test the server, two LEDs are first connected to the ports used (22 and 23). If necessary, the LEDs can of course also be replaced by relays or other electronic components such as power transistors or triacs, etc., in order to switch higher output levels. After the contact to the network has already been established in the boot.py file, the construction of the server webpage can be carried out in the main.py file. Here, pin objects are first defined for the GPIOs to be controlled. In the following example, a "led1" is to be connected to pin 22 and a "led2" to pin 23: from machine import Pin led1 = Pin(22,Pin.OUT) led2 = Pin(23,Pin.OUT)

The web page has the task of displaying the current GPIO states. Before the HTML text is generated, the LED states must be inspected. These are recorded in the variable gpio_state: if led1.value()==1: gpio_state1="ON" else: gpio_state1="OFF" if led2.value()==1:

● 172

Chapter 14 • MicroPython and the Internet of Things (IoT)

gpio_state2="ON" else: gpio_state2="OFF"

The design of the web page is then determined. The main points of this design will be briefly explained below. In the first HTML block, the basic parameters such as the • title • size • font of the page are defined: html = """ WLAN server

WLAN server V 1.2

Channel 1: """ + gpio_state1 + """

ON OFF

Channel 2: """ + gpio_state2 + """

ON OFF

"""

● 173

MicroPython for Microcontrollers

After the HTML code for the website has been created, a listening socket is required in order to wait for incoming requests and to send the HTML text as a response. For this purpose, a new socket object "s" is created with the appropriate socket type (STREAM TCP). This socket object can then be bound to an address (network interface and port number) via the bind() method. s=socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind((‚', 80)) s.listen(5)

The empty string "" provides the IP address of the local host and thus the current IP address of the ESP32. The port number 80 serves as the standard port. Now the server can connect to the network. The corresponding line enables the server to establish a "read" connection. The argument of the corresponding listen() method specifies the maximum number of connections in the queue, a maximum of five. The while loop waits for requests. When a client connects, the server calls the accept() method to accept the connection. Then it stores a new socket object to accept and send data for the variable conn. The client address is stored to connect to the server for the variable "addr". Through the line print(‚Got a connection from %s' % str(addr))

the client's address is output to the console for control. The data exchange between client and server takes place with the methods send() and recv(). The recv() method receives the data from the client socket. The argument of the method specifies the maximum amount of data that can be received at once. The variable "response" contains the HTML text returned by the web_page() function. In it, a search is held for the key "ledx=on/off" and the LED is switched on or off accordingly. Finally, the response is sent to the socket client with the methods send() and sendall() and the socket is closed with conn.close (). The entire main.py file for building the server webpage then looks like this: # main.py: WebServer_WLAN_switch from machine import Pin led1 = Pin(22,Pin.OUT) led2 = Pin(23,Pin.OUT) def web_page():

● 174

Chapter 14 • MicroPython and the Internet of Things (IoT)

if led1.value()==1: gpio_state1="ON" else: gpio_state1="OFF" if led2.value()==1: gpio_state2="ON" else: gpio_state2="OFF" html = """ WLAN server

WLAN server V 1.2

Channel 1: """ + gpio_state1 + """

ON OFF

Channel 2: """ + gpio_state2 + """

ON OFF

""" return html s=socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind((‚', 80)) s.listen(5) while True: conn, addr = s.accept() print(‚Got a connection from %s' % str(addr)) request = conn.recv(1024) request = str(request) print(‚Content = %s' % request)

● 175

MicroPython for Microcontrollers

led1_on = request.find(‚/led1=on') led1_off = request.find(‚/led1=off') led2_on = request.find(‚/led2=on') led2_off = request.find(‚/led2=off') if led1_on==6: print(‚LED ON') led1.value(1) if led1_off==6: print(‚LED OFF') led1.value(0) if led2_on==6: print(‚LED ON') led2.value(1) if led2_off==6: print(‚LED OFF') led2.value(0) response = web_page() conn.send(response) conn.close()

14.4 The WLAN web server in action The hardware of the web server only includes the ESP board with one LED each at GPIO port 22 and 23 and the associated series resistors (2 x 150 ohms).

Figure 14.3: ESP32 WebServer. Once the files main.py and boot.py have been loaded into the ESP32 "device" folder, the ESP EN/RST button can be pressed. After a few seconds, the connection to the local WLAN router is established. The associated IP address is displayed in the shell.

● 176

Chapter 14 • MicroPython and the Internet of Things (IoT)

Figure 14.4: Connection setup and IP address of the ESP32 board. A computer logged on to the same LAN is required to call up the web page. On this computer, any browser can be opened with the above-mentioned ESP IP address in the input field (see image).

Figure 14.5: The website for the WLAN switch. After pressing the virtual "ON" button, the associated LED lights up. In addition, the GPIO status on the page is updated immediately. By clicking an "OFF button", the associated LED can be switched off.

14.5 Reading out sensor data via WLAN In addition to switching devices, reading out and transmitting sensor data is one of the most important tasks of a web server. In the following, for example, three analogue channels are to be sent to a web client via WLAN. To ensure that defined values are applied to the channels, they are wired with potentiometers. Alternatively, any sensors with analogue outputs such as photodiodes or analogue temperature sensors can be used (see Chapter 9).

● 177

MicroPython for Microcontrollers

Figure 14.6: A web server for the transmission of analogue channels. The connection to the WLAN is established as usual via the boot.py file. It can therefore be taken over unchanged. After importing the pin and ADC, the ADC channels are defined in the main.py file: adcs = [ADC(Pin(i)) for i in (32,34,35)] Danach erfolgt der Aufbau der Web-Page: html = """

ADC MAP ADC MAP %s
PinValue


"""

complete with title, heading and a pre-formatted table. Then the sockets are activated again. In the main loop, the channels defined in "adcs" are output via rows = [‚%s%d' % (str(p), p.read()) for p in adcs]

using the table created. The following figure shows an example for three analogue values:

● 178

Chapter 14 • MicroPython and the Internet of Things (IoT)

Figure 14.7: Analogue measured values in the browser However, the procedure described here only allows the distribution of data in the house's own intranet via LAN or WLAN. Access from outside is not possible without further ado. The default settings of the home router generally prevent external access to internal network resources. This also makes sense, as it is usually not desirable for unknown persons to control one's own home automation. Special ports could be released for external access. It would then be possible to access the controller in the home network from anywhere in the world. This procedure, however, requires in-depth knowledge of how to handle the corresponding security precautions in order to rule out misuse. Due to these associated risks, this method will not be described further here. A much simpler and better method is presented in Chapter 16, "Sending data to the internet via ThingSpeak". There, a freely available internet platform is used to retrieve measurement data from one's own home automation worldwide. In addition, the platform offers extensive possibilities for graphically displaying measured values and data. Statistical methods for data collection and processing are also provided. Access to the platform can be regulated and restricted via various settings. This provides a reasonable level of security, although of course no system can offer absolute protection against unwanted intrusion.

14.6 Recording environmental parameters: WLAN Thermo/Hygrometer If measured values must be recorded from remote, changing or difficult-to-access locations, it is preferable not to have to lay measuring cables. In this case, radio transmission can be the method of choice. A WLAN-capable recording system can be used for this purpose. If real measured values are to be transmitted, only the potentiometers from the last chapter need to be replaced by suitable sensors. For wireless remote temperature measurement, for example, the setup from Figure 9.12 can be used again. In the corresponding program, the WLAN data transmission is combined with the thermometer program.

● 179

MicroPython for Microcontrollers

Alternatively, a DHT22 sensor and a 10 kiloohm resistor can be used as a pull-up. The connection and evaluation of this and other sensors has already been explained in Chapter 9. Now, however, the recorded values are not only to be shown locally on a display, but also transmitted wirelessly via WLAN. Again, a boot.py file and a main.py file are needed for this project. The boot.py is identical to the version for the LED server. In the line of main.py, the sensor pin is now specified instead of the LED pins: sensor = dht.DHT22(Pin(14))

Temperature and humidity are read via def read_sensor ():

The two variables "temp" (temperature) and "hum" (humidity) store the temperature and humidity data read from the sensor. With the following try/except construction, the execution of the program continues even if an exception occurs. This prevents the web server from crashing if no data can be read from the sensor. If the readings are valid, a message is prepared that contains the temperature and humidity readings: msg = (b ‚{0: 3.1f}, {1: 3.1f}'. format (temp, hum))

Finally, the data is returned with return (msg). If the sensor cannot be read because, for example, the connection to the measuring unit is interrupted, an error message ("Failed to read sensor") is generated. The web_page() function again returns an HTML page. Just as with the LED server, the general design of the page is defined here first. Then two routines are created to display the temperature and the humidity:



Temperature """+str(temp)+""" °C



Humidity """+str(hum)+""" %



● 180

Chapter 14 • MicroPython and the Internet of Things (IoT)

Subsequently, the program steps already discussed in Section 14.9 are executed to transfer the web page. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind((‚', 80)) s.listen(5)

In the "while" loop, the function read_sensor() is called to output the sensor values and update the global variables temp and hum. The complete main.py looks like this: # main.py: ENVIRO Server DHT11 import dht sensor = dht.DHT11(Pin(14)) def read_sensor(): global temp, hum temp = hum = 0 try: sensor.measure() temp = sensor.temperature() hum = sensor.humidity() if (isinstance(temp, int) and isinstance(hum, int)): msg = (b'{0:3.1f},{1:3.1f}'.format(temp, hum)) print(msg) return(msg) else: return(‚Invalid sensor readings.') except OSError as e: return(‚Failed to read sensor.') def web_page(): html = """



ESP32 ENVIRO Server

● 181

MicroPython for Microcontrollers

Temperature: """+str(temp)+""" °C

Humidity: """+str(hum)+""" %



""" return html s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind((‚', 80)) s.listen(5) while True: conn, addr = s.accept() print(‚Got a connection from %s' % str(addr)) request = conn.recv(1024) print(‚Content = %s' % str(request)) sensor_readings = read_sensor() print(sensor_readings) response = web_page() conn.sendall(response) conn.close()

After loading the files onto the ESP32, a web browser can be started again, and you can enter the current IP of the ESP32. The measurement data will now appear as a web page:

Figure 14.8: The Thermo/Hygro Server running and displayed in a browser.

● 182

Chapter 15 • Simple and Good: The MQTT Protocol

Chapter 15 • Simple and Good: The MQTT Protocol This chapter covers the basics of the MQTT protocol. MQTT stands for Message Queuing Telemetry Transport. It is a simple publish-and-subscribe system with which messages can be published and received. The protocol was developed for, among other things, data transmission at low bandwidth. This makes it the preferred solution for IoT applications. With MQTT, commands can be sent to control outputs. Furthermore, it is also possible to read data from a sensor node and publish it. During the development of the protocol, the need to be able to establish communication between multiple devices without much effort was centralised. MQTT includes the following basic concepts: • Publish/Subscribe • Messages • Topics • Broker The first approach is the publish-and-subscribe system. This allows a device to publish a message on a specific topic. In addition, a specific topic can also be subscribed to in order to receive messages.

Figure 15.1: MQTT: Basic procedure. Messages are information to be exchanged between different devices. These can be commands or data. Another important concept is topics. Topics contain information about what news a participant is interested in or where news should be published. Topics are represented with strings separated by a slash ("/"). Each slash indicates a topic level. For example, the topic "coffee machine" in an office could be represented like this: work/office/coffeemachine

● 183

MicroPython for Microcontrollers

Subjects are case-sensitive: work/office/coffeemachine

and work/office/CoffeeMachine

are therefore two different topics. So if you want to switch on a coffee machine in the office via MQTT, the following scenario must take place:

Figure 15.2: MQTT runtime scenario. A terminal device such as a laptop or smartphone publishes the "on" or "off" command on the topic of work/office/coffeemachine. Another device, for example the ESP32, has subscribed to this topic. So when a new message is published on this topic, the ESP32 receives the message "On" or "Off" and switches the coffee machine on or off. Finally, the broker is also required. It is primarily responsible for receiving all messages, filtering them and deciding who is interested in them. It also has the task of publishing the information for all subscribed clients. Various brokers are available for this purpose. A well-known version is the Mosquito broker, which can be installed in the Raspberry Pi. Alternatively, a cloud MQTT broker such as ThingSpeak can be used.

● 184

Chapter 15 • Simple and Good: The MQTT Protocol

15.1 MQTT via ThingSpeak In ThingSpeak, data can be presented in a wide variety of forms. The website offers comprehensive support for various microcontroller systems. Logging into the ThingSpeak platform is done via a login page. After successful login, unique assignment codes, so-called API keys (for Application Programming Interface), can be queried under Channels → MyChannels The following ThingSpeak channel information is required for communication via MQTT: • Channel ID (at the top of each "channel" page) • User ID (Account -> My Profile) • Read API Key (API Keys TAB) • Write API Key (API Keys TAB) • MQTT API Key (Account -> My Profile) The following figure shows an example of the API Keys page.

Figure 15.3: API keys in ThingSpeak.

● 185

MicroPython for Microcontrollers

For the data transfer to Thingspeak.com, the two files boot.py and main.py are required again (in the download package under MQTT_thingspeak). boot.py remains unchanged as usual and establishes the connection to the WLAN. First, a client with a freely selectable number is created in main.py: myMqttClient = bytes("client_"+str(2151139), 'utf-8')

Then this client is connected to the Thingspeak MQTT broker. The connection is made via a TCP port. THINGSPEAK_URL=b"mqtt.thingspeak.com" THINGSPEAK_USER_ID=b'USER_ID' THINGSPEAK_MQTT_API_KEY=b'MQTT_API_KEY" client=MQTTClient(client_id=myMqttClient, server=THINGSPEAK_URL, user=THINGSPEAK_USER_ID, password=THINGSPEAK_MQTT_API_KEY, ssl=False)

For the placeholders • USER_ID • MQTT_API_KEY the data taken from the ThingSpeak webpage must be used here. Then an attempt is made to establish the connection: try: client.connect() except Exception as e: print(‚could not connect to MQTT server {}{}'.format(type(e).__name__, e)) sys.exit()

In the event of an error, a corresponding message is output. After specifying the 1. THINGSPEAK_CHANNEL_ID = b'XXXXXX' 2. THINGSPEAK_CHANNEL_WRITE_API_KEY = b'1234567890ABCDFG' and defining the time period between two data transmissions (minimum 15 seconds), PUB_TIME_SEC = 15

you can start sending the values:

● 186

Chapter 15 • Simple and Good: The MQTT Protocol

dummyData = adc.read() credentials = bytes("channels/{:s}/publish/{:s}".format(THINGSPEAK_CHANNEL_ ID, THINGSPEAK_CHANNEL_WRITE_API_KEY), ‚utf-8') payload = bytes("field1={:.1f}\n".format(dummyData), ‚utf-8') client.publish(credentials, payload) time.sleep(PUB_TIME_SEC)

To prevent a possible program termination, the transmission sequence was embedded in a try/except construction. This included, the entire program looks like this: # main: MQTT_ThingSpeak from umqtt.robust import MQTTClient import time import os #import gc import sys from machine import ADC, Pin adc = ADC(Pin(34))

# create ADC object on ADC pin

adc.atten(ADC.ATTN_11DB) # create a random MQTT clientID randomNum = int.from_bytes(os.urandom(3), ‚little') myMqttClient = bytes("client_"+str(randomNum), ‚utf-8') # connect to Thingspeak MQTT broker via unsecure TCP (port 1883) THINGSPEAK_URL=b"mqtt.thingspeak.com" THINGSPEAK_USER_ID=b'tonismarthome' THINGSPEAK_MQTT_API_KEY=b'65A4YORGS7N6HPFB' client=MQTTClient(client_id=myMqttClient, server=THINGSPEAK_URL, user=THINGSPEAK_USER_ID, password=THINGSPEAK_MQTT_API_KEY, ssl=False) try: client.connect() except Exception as e: print(‚could not connect to MQTT server {}{}'.format(type(e).__name__, e)) sys.exit() # publish to Thingspeak using MQTT THINGSPEAK_CHANNEL_ID = b'123456' THINGSPEAK_CHANNEL_WRITE_API_KEY = b'1234567890123456'

● 187

MicroPython for Microcontrollers

PUB_TIME_SEC = 15 while True: try: dummyData = adc.read() print(dummyData) credentials = bytes("channels/{:s}/publish/{:s}".format(THINGSPEAK_ CHANNEL_ID, THINGSPEAK_CHANNEL_WRITE_API_KEY), ‚utf-8') payload = bytes("field1={:.1f}\n".format(dummyData), ‚utf-8') client.publish(credentials, payload) time.sleep(PUB_TIME_SEC) except KeyboardInterrupt: print(‚exit...') client.disconnect() sys.exit()

Finally, the file robust.py (see download package) must be loaded onto the ESP. This contains the basic routines for the MQTT protocol. Then the program sequence can be started via a reboot. The ESP automatically logs into the specified WLAN and connects to the ThingSpeak server. Now data can already be uploaded to the web page and then queried worldwide. For this purpose, you can set up your individual ThingSpeak web page. The data channels can be configured individually under: MyChannels → New Channel

Figure 15.4: MyChannels on ThingSpeak.com. At this point, several channels can be defined. In the program above, a so-called field has already been defined.

● 188

Chapter 15 • Simple and Good: The MQTT Protocol

On the channel page, graphical representations can be created under "Add Visualizations". For dummy ADC data, the result looks like this:

Figure 15.5: Dummy data on the ThingSpeak page. On the hardware side, the setup used in Fig. 9.2, i.e. a potentiometer on port 34, can be used again here.

● 189

MicroPython for Microcontrollers

Chapter 16 • S  ending Data to the Internet via ThingSpeak Within a WLAN, the data is initially only available in a limited environment. This has the advantage that the measured values or similar are also relatively secure. However, there are also situations in which you want to retrieve measurement data or sensor values from a greater distance or even worldwide. In many cases, it is desirable to be able to check the home data on the road, from the workplace or on holiday. In principle, it would be possible to make all values from the home WLAN available globally, if we enable external access to the home WLAN. However, this is associated with various security risks. This is where an online platform like ThingSpeak can put its strengths to use. Via the IoT service, measurement or sensor values can be logged and are then available worldwide. In addition to access via the internet, an app for mobile devices is also available (see below). Password-protected access to the ThingSpeak platform also ensures sufficient data protection. The ESP32 controller is virtually predestined for use on ThingSpeak thanks to its integrated wireless communication capabilities. This integrated WLAN connection is a decisive advantage over other systems such as the classic Arduino boards. These required their own "WLAN shield" in order to communicate via a wireless network. With the ESP32 chip, on the other hand, this functionality is already integrated.

16.1 Rain or storm? Virtual weather station available worldwide In general, one will not only want to send dummy data of potentiometer values, but real, measured values. Weather or climate data are of particular importance in this context. For reliable weather forecasts, it is important to know climate or weather data even from distant locations. For example, if you are on holiday or on a business trip, it can be interesting to check the weather station at home. If there is a threat of frost, for example, you can ask your neighbour to turn on the heating. Or you can check the weather data at your holiday residence from home. If necessary, you can activate the air-conditioning there far in advance and then find rooms at a pleasant temperature upon arrival. The BME280 sensor can be used for this purpose. Its basic function and the procedure for reading out the data has already been explained in section 9.19. Now this data is to be transferred to the thingspeak.com page. With the integrated sensors for • Temperature • Humidity • Air pressure you can make the most important data available via ThingSpeak. To do this, in the test program from the last section, instead of the dummy data, only the real values are transferred:

def collectData():

● 190

Chapter 16 • Sending Data to the Internet via ThingSpeak

bme =BME280.BME280(i2c=i2c) temp=0.01*int(bme.read_temperature()) humi=0.01*int(bme.read_humidity()/10.24) pres=0.01*int(bme.read_pressure()/256) return temp,humi,pres

Reading out the data via the I2C bus has already been explained in Chapter 9 and further details can be found in Section 18.1. In addition to the transmission to the ThingSpeak side, the climate values should also be visible locally in a display. Therefore, the corresponding program parts from Section 10.6 are included. A boot and a main file are again required so that the WLAN climate station starts up correctly after a possible power interruption. The WLAN is accessed as usual via the boot.py file, which can be adopted unchanged from the last section. The complete main.py file, on the other hand, now looks like this: #

ClimateStation.py

import network from umqtt.simple import MQTTClient from time import sleep from machine import Pin, I2C import ssd1306 import BME280 PUB_TIME_SEC=15 # final->300 # ThingSpeak com data SERVER="mqtt.thingspeak.com" CHANNEL_ID="123456" WRITE_API_KEY="ABCDEFGH1234567890" # MQTT client object & MQTT topic string client=MQTTClient("umqtt_client", SERVER) topic="channels/"+CHANNEL_ID+"/publish/"+WRITE_API_KEY # ESP32 - Pin assignment i2c = I2C(scl=Pin(22), sda=Pin(21), freq=10000) # OLED setup oled_width = 128 oled_height = 64 oled = ssd1306.SSD1306_I2C(oled_width, oled_height, i2c) # Function to read all data: def collectData(): bme =BME280.BME280(i2c=i2c) temp=0.01*int(bme.read_temperature()) humi=0.01*int(bme.read_humidity()/10.24)

● 191

MicroPython for Microcontrollers

pres=0.01*int(bme.read_pressure()/256) return temp,humi,pres # send data continuously while True: oled.fill(0) oled.text(‚BME280 climate', 0, 0) temp,humi,pres=collectData() print(‚Temp: %7.1f' %temp) print(‚Humi: %7.1f' %humi) print(‚Pres: %7.1f' %pres) print() temp_string=str(‚Temp:%7.2f' %temp) humi_string =str(‚Humi:%7.2f' %humi) pres_string=str(‚Pres:%7.2f' %pres) oled.text(temp_string, 0, 10) oled.text(‚ C', 90 ,10) oled.text(humi_string, 0, 20) oled.text(‚ %', 90 ,20) oled.text(pres_string, 0, 30) oled.text(‚ hPa', 90 ,30) oled.show() #check data on terminal print("Data for ThingSpeak:") print(temp,humi,pres) print("--------------------") #send date to ThingSpeak payload="field1="+str(temp)+"&field2="+str(humi)+"&field3="+str(pres) client.connect() client.publish(topic, payload) client.disconnect() sleep(PUB_TIME_SEC)

After entering the Thingspeak fields, the setup of the database is complete and all collected values can be displayed graphically in different representations. Fig. 16.1 shows an example of the visualisation of the sensor data. The next section shows how the graphics can be customized.

● 192

Chapter 16 • Sending Data to the Internet via ThingSpeak

Figure 16.1: Display of climate data in ThingSpeak.

Figure 16.2: Local display of climate data on the OLED display.

● 193

MicroPython for Microcontrollers

Figure 16.3: Compact WLAN weather station with display.

16.2 Graphical representation of data in ThingSpeak All data and measured values can be displayed graphically in different representations. The following illustrations show some suggestions for displaying the sensor data:

Figure 16.4: Data display in ThingSpeak. The graphics can be individually designed. Different colours and colour combinations make for a wide range of possibilities. The axes, the number of measuring points, the measuring time spans, etc. can be customised, as can the line types and the number of averages, etc. In addition, various virtual instruments can be displayed. With these, certain setpoint or danger areas can be marked in colour. The settings can be called up via the pencil symbol at the upper right edge of the field:

● 194

Chapter 16 • Sending Data to the Internet via ThingSpeak

Figure 16.5: Options for data analysis. In this way, very clear and informative data displays can be created. In particular, • graph titles, • axis labels, • line & background colours, • graph types like - line graphs, - bar graphs, - spline graphs, • the number of measuring points, • time scales, • agencies, and others can be set. In addition, virtual analogue instruments or striking warning displays are available. So there are practically no limits to the individual design of your own data display.

16.3 Data for the smartphone with the ThingView app With "ThingView", an app is available for the evaluation of data on mobile devices such as smartphones or tablet computers. With it, all measured values can be checked and monitored quickly and easily worldwide. The app can be downloaded free of charge from well-known app stores (e.g. Play Store). Regardless of whether you want to read the values at home from abroad or check the current weather at work, the app offers all possibilities. After entering the channel ID and the corresponding API key, the data is available on any mobile device. The app takes over the window settings such as colour, time scales or chart type and number of results. The following figure shows the app in action:

● 195

MicroPython for Microcontrollers

Figure 16.6: Data in the ThingView app.

16.4 Against unwanted visitors: Optical room surveillance Optosensors can be used to measure more than just room brightness. They can also be used to set up a ThingSpeak Iot system for monitoring tasks. In this way, rooms can be monitored for unwanted activities and uninvited "guests". Acoustic alarms are often not very useful, as they only warn unwanted visitors. If, on the other hand, movements in a room are recorded, it is easy to check whether rooms have been entered without permission in the case of suspicious activities. It is also possible to do this without a special light source. It is often sufficient to detect the passive lighting conditions in a room. An unexpected increase in brightness at 01:30 in a basement room, for example, indicates an uninvited visitor who unintentionally illuminates the light sensor module with a torch.

● 196

Chapter 16 • Sending Data to the Internet via ThingSpeak

During the day, natural light can be used for room monitoring. Daylight changes comparatively slowly. Sunrises or sunsets always take longer periods of time. If a so-called spike is observed, a person or an animal has probably cast its shadow on the light sensor. The structure shown in Figure 9.17 can be used as the hardware basis. The corresponding main.py program looks like this: #

BPW40_intrusion_detection.py

from time import sleep from umqtt.simple import MQTTClient from machine import Pin, ADC # ThingSpeak data SERVER="mqtt.thingspeak.com" THINGSPEAK_CHANNEL_ID = b'123456' THINGSPEAK_CHANNEL_WRITE_API_KEY = b'1234567890123456' PUB_TIME_SEC=15 # final->300 # MQTT client object & MQTT topic string client=MQTTClient("umqtt_client", SERVER) topic="channels/"+CHANNEL_ID+"/publish/"+WRITE_API_KEY fotoPin = ADC(Pin(34)) fotoPin.atten(ADC.ATTN_11DB)

# input range 0 ... 3,3 V

# Function to read all data: def collectData(): data0=fotoPin.read()/40.96 return data0 # send data continuously while True: data0=collectData() #check data on terminal print(data0) payload="field1="+str(data0) client.connect() client.publish(topic, payload) client.disconnect() sleep(PUB_TIME_SEC)

In the function def collectData():

the current brightness values are recorded and normalised to 100% again. In the main loop, these are then sent to the ThingSpeak page. There they can be displayed in a graph

● 197

MicroPython for Microcontrollers

as in Figure 16.7. The example shows several "spikes" that clearly indicate that a person was in the monitored area during the period in question.

Figure 16.7: Spikes produced by the optical room monitor reveal a person was present in the surveyed area.

● 198

Chapter 17 • Micropower Techniques and Sleep Modes

Chapter 17 • Micropower Techniques and Sleep Modes If electronic devices are not operated at a fixed location but are mobile, they cannot be supplied with a power supply unit or connected to a USB port. Operation with rechargeable or dry batteries is then an alternative. Climate, environmental or other measuring stations in remote locations are also often dependent on battery operation. In these cases, the power consumption of the system is of crucial importance. Especially when the devices run continuously, low power consumption is of utmost interest. Often, such a measuring system only needs to record a certain sensor value once a minute, for example. In between, no actions are necessary. If the controller is left running in normal operation, this is accompanied by a substantial amount of energy consumption. It is much cheaper to put the chip into "sleep mode", in which it only consumes a very small amount of power. In the following sections, corresponding operating modes are introduced and some examples are described.

17.1 Saving power protects the environment: low-power technologies The capacity of modern accumulator cells or batteries is in the range of a few ampère-hours (Ah). For operating times of weeks or months, a measuring system may therefore only consume a few microampères (mAh) on average. With the ESP32 controller, this goal is certainly achievable. The controller can be set to "deep sleep" mode for this purpose. In normal operation with an empty main loop containing only the classic sleep(1) command, the power consumption of a typical ESP board is about 50 mA. With the help of the sleep mode, the power consumption can be significantly reduced. The following program first causes an LED on port 02 to flash three times briefly, then the controller goes into sleep mode: # deepSleep_demo.py import machine from machine import Pin from time import sleep led = Pin (22, Pin.OUT) #blink LED for n in range(3): led.value(1) sleep(.1) led.value(0) sleep(.1) sleep(5) # awake time

● 199

MicroPython for Microcontrollers

print(‚going to sleep...') machine.deepsleep(10000)

# in milliseconds!

Right after starting the program, the current consumption of the board can still be measured at almost 50 mA. After about one second, however, the current consumption is reduced to less than 5 mA. The controller itself consumes much less current, but a USB-to-serial converter and a power-on LED are also active on the ESP boards. These components cannot be switched off without hardware intervention. Nevertheless, a power reduction by a factor of 10 is quite considerable and quite useful. By using the sleep mode, the life of a battery or the operating time of a battery charge can be extended by this factor. This is perfectly sufficient for many applications. With a power supply capacity of, for example, 3,000 mAh, runtimes of approx. 500 hours or over 20 days would now be achievable. With permanently active operation, on the other hand, the power supply would be exhausted after only 48 hours. Operation with a battery-buffered solar cell is now also much easier. In the solar cell operated Climate station (see Section 17.3), the sleep mode extends the runtime of the buffer battery to acceptable values.

17.2 Disabling unnecessary consumers Using the sleep mode already reduces the current consumption of the controller quite considerably. When using complete controller boards, though, this is only noticeable to a limited extent. Besides the ESP32 chip itself, these also contain other consumers, such as power-on LEDs or USB-to-serial converters. In order to further reduce the consumption of an exclusively battery-powered ESP32-based device, further measures are therefore necessary. Power LEDs or other operating status indicators must be disabled. Interface converters and other components must be able to be switched off. With appropriate effort, the current consumption could be reduced to less than 1 mA. To do this, however, all unnecessary consumers would have to be disconnected from the power supply by means of appropriate line interruptions. However, this is hardly feasible with simple means on the classic development boards. The required hardware interventions presuppose a high level of experience, so that this procedure is reserved for users with the relevant specialised knowledge. Therefore, this topic will not be discussed further here. In these cases, it is usually better to switch to special boards anyway. In addition, direct operation at 3.3 V should be aimed for. Voltage reduction from, say, 5 V to 3.3 V is always associated with losses and should therefore be avoided. The power losses of electronic components usually increase with the square of the operating voltage. For this reason, all external components should also be operated at 3.3 V. The brown-out detector (BOD) of the ESP32, which detects undervoltage and then triggers a reset of the CPU, must be adjusted accordingly.

● 200

Chapter 17 • Micropower Techniques and Sleep Modes

Digital sensors should be avoided, as they also have quite high quiescent current consumption. Preference should be given to classic analogue transducers (phototransistors, thermal sensors, etc.). If the use of digital sensors nevertheless cannot be avoided, they should be able to be switched on and off via I/O ports so that they are only in operation when they are actually carrying out their measuring tasks.

17.3 Weather station with battery or solar operation As an application of the deep sleep mode, the weather station from Chapter 16 can be converted to low-power operation. To do this, only the line sleep(PUB_TIME_SEC)

should be replaced by machine.deepsleep(PUB_TIME_SEC)

In addition, a sleep(1) instruction is recommended before the "deepsleep" command. This will make the program a little more stable. To further reduce power consumption, you can also disconnect the display and remove the corresponding code lines. This allows the station to run permanently in 24-hour operation with a small battery-buffered solar cell. The following illustration shows the setup with a solar power bank.

Figure 17.1: Weather station with solar-powered operation.

● 201

MicroPython for Microcontrollers

Chapter 18 • Bus Systems for Efficient Communication Bus systems have already been used in various chapters. They were used again and again for the control of actuators and sensors. They allow a large number of components to be connected to a controller with a few processor pins and a minimum of circuitry. In these last chapters of the book, these systems will be discussed in more detail. On the software side, MicroPython provides convenient drivers for controlling the connected components. Two bus systems have found widespread use for microcontroller applications: • I²C (Inter IC or IIC) • SPI (Serial Peripheral Interface) These two systems have interesting possibilities when it comes to realizing larger projects. With increasingly complex tasks and substantial extensions, at some point even the ESP32 will run out of pins. Bus systems are an excellent solution here, as many components can be controlled via just a few GPIO pins. Since many sensors have the corresponding interfaces, buses have already been used on several occasions. The following table summarizes some examples: Module

Bus System

SSD1306 OLED display

I2C

RC522 RFID

SPI

BMP280 Barometer

I2C

BME280 Multi climate sensor

I2C

In addition, a variety of other components can be connected to the ESP32 via bus systems, for example, • displays and display units, • EEPROMs, flash memory or SD cards, • real-time clocks. Most of these components can also be used under MicroPython without any problems, especially if helpful libraries are available.

18.1 Basics and applications of the I²C bus The ESP32 has 36 digital IO pins, but not all of them are available on most boards. For smaller projects, this is perfectly acceptable, but for larger applications, you may come up against limits. Bus systems offer a cost-effective expansion option here. They allow a wide range of functions to be controlled with just a few pins. A classic example is the use of an I²C display. This requires only two port pins in contrast to the six or more ports occupied by a classic HD44780 LCD. In this chapter, the I²C bus will be considered first. The SPI bus will then be dealt with in the following sections.

● 202

Chapter 18 • Bus Systems for Efficient Communication

I²C, usually pronounced "I-squared-C-", stands for Inter-Integrated-Circuit. The serial twowire bus was developed by Philips now over 30 years ago. The system quickly advanced to become the quasi-industry standard for control tasks in the microcontroller environment. Low costs and simple implementation quickly ensured widespread use. A transmission rate of up to 3.4 MBit/s is sufficient for many applications and has not allowed the bus to lose any of its popularity to this day. The I²C system enables efficient data exchange between several ICs on one board. A serial bus structure was implemented in order to get by with only a few tracks. This resulted in a bidirectional bus system in a master/slave architecture. Thanks to an integrated transmission protocol and software addressing, only two connection lines are required: • the clock line SCL (Serial Clock) • the data line SDA (Serial Data) With these two signals, a microcontroller can control a complete network of components with only two port pins. Applications of the bus are mainly found in consumer electronics. The reading of real-time clocks, the control of displays or the electronic volume adjustment are typical I²C applications. The following figure shows the basic structure of an I²C bus.

Figure 18.1: Basic structure of the I2C bus. Increasing performance requirements have led to a steady rise in clock rates over the course of time. Nevertheless, slower components can also be operated on the bus by means of clock stretching (see below). Since no fixed clock times have to be adhered to, both slower and very fast bus participants can be operated simultaneously. The I²C bus has been constantly developed further and is now no longer only used for connecting individual ICs. The simple control software can be adapted very flexibly so that the bus can also be used in larger systems. The structure of the I²C software also allows the use of slower programming languages such as Python. This is another reason why the system is ideally suited for a wide range of applications in the IoT sector. The I²C bus is based on a master-slave system. Data transmission is always started by a "master". Then the "slave", which is addressed via its address, responds to the request. In multimaster mode, several masters can work on one bus. Two masters then communicate with each other by briefly reconfiguring one as a slave. This special access control on the bus is precisely regulated by a corresponding specification. However, this is a relatively rarely used application that will not be considered further here.

● 203

MicroPython for Microcontrollers

Components and devices connected to the bus have open-collector inputs. Together with pull-up resistors, this creates a wired-AND circuit. This allows the bus to be operated with different voltages. The pull-ups only have to be connected to the correct voltage (e.g. Vdd = 3.3 V or Vdd = 5 V). A valid high level for bus signals is at least 0.7 Vdd volts. The low level must not exceed 0.3 Vdd volts. If there are frequent transmission errors, the voltages should be checked with an oscilloscope. If the voltage values deviate from the target range, the pull-up resistors must be adjusted. In some controllers, internal pull-ups are even integrated; external resistors can be omitted in this case. The datasheets of I2C components typically contain corresponding information. The I²C bus system is based on positive logic. Consequently, a high level on the data line corresponds to a logic one, the low level to a logic zero. The bus clock is always specified by the master. The various bus modes always work with a maximum permitted bus clock frequency. Slower clock rates are only possible if they are supported by the master. However, some I2C components, such as analogue-to-digital converters, require a certain minimum clock frequency in order to work without errors. Here it must be checked whether this is supported by the master. The most common clock rates are: • 100 kHz • 400 kHz • 1.0 MHz • 3.4 MHz

clock: clock: clock: clock:

Standard mode Fast mode Fast Mode Plus High Speed Mode

If the slave needs more time than the clock of the master, it can keep the clock line low between the transmission of individual bytes. The clock stretching already mentioned can be used to adjust the master clock if necessary. In an I²C system, data is only valid if its logical level does not change during a clock high phase. Start and stop signals are the exception to this rule. Start signals are characterised by falling edges on the data signal while the clock line remains at high level. Stop signals, on the other hand, are signalled by a rising edge on the data line, while the clock signal remains at high level. As is usual in data technology, individual data units on the I²C bus also consist of eight data bits each, a so-called octet. This can be interpreted either as a value or as an address. In addition, there is an ACK-bit (acknowledge) as confirmation. This is signalled by the slave by a low level on the data line. The first byte sent by the master is a standard I²C address. The first seven bits represent the actual address. The eighth and last bit (R/W bit) tells the slave whether it is to receive data from the master (LOW) or transmit data to the master (HIGH). Thus, an address space of 7 bits is available in an I²C system. With 16 addresses reserved for special purposes, 112 of the 27 = 128 possible addresses remain, which can be addressed simultaneously on one bus.

● 204

Chapter 18 • Bus Systems for Efficient Communication

Each I²C-capable component has an address defined by the manufacturer, of which three bits, the so-called sub-address, can often be individually defined via three control pins. This means that up to eight ICs of the same type can be operated on one I²C bus. This is described in more detail below using an air humidity and temperature sensor of the type BME280. For many applications, more than 100 participants on a bus system are sufficient. The available addresses can still become scarce in extensive professional systems. For this reason, addressing was extended to 10 bits a few years ago. By using 4 of the 16 reserved addresses, the new address space is downward compatible with the older 7-bit standard. Both types of addressing can be used simultaneously, so that currently up to 1136 components can be addressed on one bus. The I²C data transmission always begins with a start signal from the master. Then follows the desired address. This is confirmed by the ACK-bit of the addressed slave. Depending on the R/W bit, data can then be written or read byte by byte. When writing, the ACK is sent by the slave; when reading, it is sent by the master. The transmission is terminated with the stop signal. In the I²C protocol, data transmission starts with the most significant bit ("MSB-first"). For high-speed mode, a corresponding master code is sent first in fast or standard mode. This causes the entire system to switch to the new, higher frequency.

Figure 18.2: I²C bus timing. The I²C bus makes it possible to control a network of electronic components with only two GPIO pins. In professional applications, this has significant cost advantages. Since the risk of failure increases with the number of connections required, the testing and inspection effort also increases. Fewer traces on a board therefore minimize production, development and testing costs. The I²C interface is best suited for peripherals with lower data rates. Control and configuration data usually do not require high clock frequencies. The I²C bus is therefore often used for electronic volume controls, AD or DA converters with low sampling rates, small, non-volatile memories, real-time clocks or bidirectional switches. As the BME280 example shows, electronic sensors for climate data such as temperature, air pressure or humidity with integrated analogue-to-digital converters are particularly suitable for the I²C bus.

● 205

MicroPython for Microcontrollers

The following table shows some other frequently used I²C-capable chips. Helpful MicroPython libraries are available for these and other sensors, so their use should not pose any problems. IC / Component

Function

DSS1306

OLED Graphic Display 0.96"

AT24C256

EEPROM

BMP180/280

Barometric air pressure sensor

BME280

Climate sensor

DS1307

Real-time clock with battery buffer

I2C16x4

4 x 16 segment LCD display

LM75

Temperature sensor

MAX127

A/D converter

PCF8574

Port expander

PCF8583

Real-time clock

The table shows only a small number of the available I²C components. In particular, components were selected which are preferably used in the smart home sector. Another advantage of the I²C system is the so-called hot-plug ability. This entails that components can be added to or removed from the bus during operation. In MicroPython, this feature can be supported by the try/except construction. This means that unwanted program aborts can be effectively avoided, even if elements are removed or added. The table clearly shows that the acquisition of sensor values is one of the most important applications of the I²C bus. Almost all physical variables can be recorded with I²C sensors. Some components have become particularly established in Internet of Things (IoT) applications. The most important of these will be presented below as examples of applications for the bus system. Remote temperature management, for example, is very unreliable with simple analogue sensors. Thermal voltages, line resistances or electromagnetic interference all lead to significant measurement errors. Additionally, there are often considerable distances between the sensor and the digital control system, especially in smart home systems. This, too, can lead to measuring errors. Digital sensors are much less susceptible to these types of errors. With these, the measured value is converted into a digital signal directly at the point of measurement, making the system less sensitive to the above-mentioned influences. For these reasons, it is also possible to bridge larger distances between the sensor and a smart home control centre. If an increasing number of components are connected to a bus, it is advantageous to check the entire setup before commissioning. The following table shows some known sensors and their associated I²C addresses:

● 206

Chapter 18 • Bus Systems for Efficient Communication Component

Binary Address

Hex Address

BME280

0b1110110

0x76

BMP185

0b1110111

0x77

I²C display

0b0011100

0x3C

Due to their individually different addresses, all sensors present on the bus can be addressed simultaneously without any problems. The function of the bus can be checked with a so-called I²C scanner. In MicroPython, an I²C scanner may look like this: # I2C_scanner.py from machine import Pin, I2C #i2c = I2C(scl=Pin(5), sda=Pin(4)) i2c = I2C(-1, scl=Pin(22), sda=Pin(21)) print(‚Scan i2c bus...') devices = i2c.scan() if len(devices) == 0: print("No i2c device !") else: print(‚i2c devices found:',len(devices)) for device in devices: print("Decimal address: ",device," - Hex address: ",hex(device))

If all components are connected correctly, the respective bus addresses appear in the console:

Figure 18.3: The I²C scanner finds two components on the bus. This ensures that the bus works correctly and that all sensors can supply data. Now nothing stands in the way of using the I²C system for IoT or smart home applications.

18.2 The SPI bus Besides the I²C system, the SPI bus (Serial Peripheral Interface) is the second important bus system to establish itself in the microcontroller sector. The clock frequencies of SPI components can be up to several megahertz. This makes the SPI bus potentially much faster than I²C systems. In addition to the term SPI, which was originally introduced by

● 207

MicroPython for Microcontrollers

Motorola, the term "Microwire", coined by National Semiconductor, is also frequently used. Both terms use the same functional principles. Many important applications can be covered with SPI devices, including: • • • • • • •

RFID transponder EEPROM LC display controller DACs and ADCs All types of sensors LED matrix controls etc.

Furthermore, audio components or tuning elements or control systems based on SPI are available for hi-fi and TV sets or household machines. The SPI bus uses the principle of synchronous data transmission. Separate lines are therefore required for data and transmission clock. This does not require synchronous clock generation on both sides. The transmitted clock signals to the receiver with high precision at which time the bits on the data line are to be scanned. The rising or falling edge of the clock signal can be used for this purpose. If the receiver detects an edge on the clock line, it immediately scans the data signal to read the next bit (see figure). Since the clock is sent together with the data, there is no need to specify a clock frequency, a so-called "baud rate".

Figure 18.4: Data communication via the SPI bus. The receiver side of the SPI bus can consist of a simple shift register. This is a much simpler and cheaper solution than the highly integrated UART (Universal Asynchronous Receiver/ Transmitter) components for asynchronous serial interfaces. The SPI system is therefore often used for simple and cost-effective solutions in the non-professional sector. However, synchronous data transmission has the disadvantage that several signal lines are required. In total, up to four lines are necessary:

● 208

Chapter 18 • Bus Systems for Efficient Communication

• • • •

Clock line, SCLK or SCK (Serial Clock) MOSI (Master Out Slave In) or Serial Data In (SDI) MISO (Master In Slave Out) or Serial Data OUT (SDO) Chip Select Signal (CS) or SS for Slave Select

Figure 18.5: SPI bus signal. The currently addressed peripheral device is activated via the CS line. Signals in the SPI system are low-active, i.e. the CS line remains high-potential until the chip is to be addressed. The data lines are at high-impedance in the idle state and thus electrically decoupled from the data bus. Figure 18.5 shows how an SPI telegram and the associated clock signal look in practice. If the individual components on an SPI bus are to communicate bidirectionally, all four signal lines are required. If only limited data exchange is required, one line can be omitted. If, for example, a peripheral element does not need to be configured, the data input line can be omitted. As soon as the corresponding chip is selected via the CS line, it starts sending data. In ADCs, for example, the MISO line is superfluous and can be omitted. Likewise, LCD controllers only need to receive data. In this case, the MOSI connection can be economized. Under MicroPython, suitable libraries are usually available for the commonest of SPI components. If the correct library is installed, it is possible to communicate with the relevant device without any problems. In the following, some peripheral components will be introduced. The various components can be divided into the following main categories: • • • • •

Memory (EEPROM and FLASH) Signal converter (ADC and DAC) Real Time Clocks (RTC) Sensors (temperature, pressure, humidity, light intensity etc.) Other (LCD controller, digital potentiometer, USB controller, signal mixer, etc.)

Most components can be assigned to the first three categories: memory, converters and RTCs. Components from the last two groups, on the other hand, are reserved for special applications. In the field of ADCs, various clock frequencies, channel numbers and resolutions are available. The bit resolutions range from 8, 10 and 12 to 24 bits. The available clock frequencies start at 30 kilosamples (KS) per second and reach up to 600+ kilosamples per second for high-performance ICs.

● 209

MicroPython for Microcontrollers

If the speed or resolution of the ESP32's internal ADCs is not sufficient for a particular application, an SPI converter can be a suitable solution. EEPROMs are predominantly available as memory chips. The storage capacities of EEPROMs range from a few bits to several kilobits. Clock frequencies of up to 3 MHz are available for the storage speeds. The special case of SD and micro-SD cards is dealt with in section 18.4. There are comparatively few SPI devices in the sensor sector. Since only low data transfer rates are often required here, the I²C bus is often preferred. Measurements such as the detection of temperatures, humidity, gas concentrations, wind speeds, light intensity, etc., do not need extremely high data rates and can also be detected with slow interfaces, so that the high data rates of the SPI bus can be dispensed with.

18.3 The members of the SPI family The following table shows some of the most important SPI components: Module

Function

74HC595

Shift register

AD8403

Digital potentiometer

MAX7219

LED display driver

MCP4912

10 bit DAC

NRF24L01

Radio module

RC522

RFID transponder

The table contains only a small excerpt from the extensive SPI family. Mainly devices for which a MicroPython driver is available were selected. The display driver for LED matrices was already used in Section 11. The RFID transponder RC522 was introduced in Chapter 13. Furthermore, the SPI connection of displays is an interesting alternative. The use of OLED displays with I²C bus in Chapter 10 contains corresponding examples.

18.4 Controlling SD and µSD cards via SPI Secure Digital (SD) or Micro Secure Digital (µSD) cards can also be addressed via an SPI interface. The memory cards are used in digital cameras or smartphones etc. as mass storage devices. These cards can also be used with the ESP32. Some boards, such as the NodeESP board, have an internal slot for an SD card. Although it is somewhat awkwardly placed on the underside of the board, it can still be used to expand the memory of the ESP32 easily and inexpensively up to a size of several gigabytes. SD cards communicate with the controller via an SPI protocol. Therefore, all modules or with an SD library are addressable. Again, the connection of the card reader with the controller is made via the already known pins. This means that the I/O pins concerned can no longer be used for other purposes.

● 210

Chapter 18 • Bus Systems for Efficient Communication

The illustration shows the corresponding connections on the SD card. The use of SD cards is particularly easy if you use ready-made SD modules. That way, you do not have to worry about the pin assignment. After plugging in the module or connecting it to an SD plug-in card, all the necessary signals are correctly connected.

Figure 18.6: SPI interface on an SD card. If you want to expand the memory capacity of the ESP32, SD cards are a good and inexpensive option. With them, the available memory can be expanded into the gigabyte range. Due to mass production, SD cards are cheaper and available with larger capacities than external EEPROMs.

● 211

MicroPython for Microcontrollers

Chapter 19 • B  uilding Circuits with Components and Breadboards If you want to work with MicroPython on an ESP32, you practically always need other electronic components. In the simplest case, this may only be an external LED with a series resistor. However, as the complexity of the projects increases, so does the number of components required. This section therefore briefly describes the most important basic components, such as: • Jumper cables • Resistors • Light emitting diodes (LEDs) • Capacitors With more experience comes the ability to realize more extensive set-ups. To crank up your skills, various methods are available for electronic circuit design, testing, and faultfinding. One variant is the creation of a circuit board onto which you solder the components. This allows reliable and durable circuits and devices to be created. In addition, special breadboards are widely used for hobby applications. These have a regular conductor track structure, which makes it possible to realize more complex circuit variants with components and connecting wires. However, this method is not very suitable for experimental purposes, as it is always necessary to re-solder for modifications or variants. Socalled "breadboards" have therefore become established in this area. These are solderless plug-in boards that make it possible to create even complex circuits without soldering. These boards are ideally suited for teaching and experimenting purposes. The following illustration shows a "playground system" composed of two boards, on which larger circuits with various sensors, control elements, displays, and so on, can be built.

Figure 19.1: Playground consisting of two larger breadboards.

● 212

Chapter 19 • Building Circuits with Components and Breadboards

19.1 Breadboards Various breadboards of various sizes can be used to connect ESP32 boards to other electronic components without soldering. Most of them are divided into three parts:

1. main working area 2. two bus tracks

Figure 19.2: Typical breadboard. The work or "patch" area consists of several rows of metal springs. The springs each have five holes for receiving component wires. Component terminals that are inserted into one of these five receiving holes are conductively connected to each other. The black lines drawn in Figure 19.2 indicate some of these (invisible) connections.

Figure 19.3: Breadboard variants Bus rails are connected to each other over half or the entire length of the breadboard. If you want to use divided rails over the entire breadboard, you have to make do with bridging wire pieces (wire bridges). The bus rails often serve as power supply rails. Plug-in boards are available in a wide variety of shapes, colours, designs and sizes. Many variants have connectors at the edges so that several boards can be plugged together.

● 213

MicroPython for Microcontrollers

Such "plug-in boards", "experimenter's plug-in boards", or simply "breadboards" are widely used today in the electronics industry as well as in home labs for circuit development. If used properly, they have a long service life. Thin connecting wires can easily bend when plugged in, therefore the insertion of the component wires into the holes of the plug-in board should always be done exactly vertically. Particularly if the breadboard is still new, inserting the wires may require some force. Stronger tweezers or flat-nose pliers can then help when inserting the connections. It is ideal for the tip of the tool to be covered with rubber tubing or adhesive tape, as this protects the components and gives the tool a better grip. If necessary, you can widen the individual springs inside the board somewhat by inserting a pin. However, you should not overdo it, as this can lead to contact problems later.

19.2 Wire jumpers and jumper cables Pieces of wire can be used to make connections on the breadboard. However, these often do not provide good electrical contact. In addition, the bare wire ends are easily bent and eventually break off. So-called "jumpers" are much better here. These are flexible stranded wires with contact pins at both ends. This allows electrical connections to be made quickly and safely.

Figure 19.4: Jumper cable. An alternative to the jumper cables are so-called Dupont cables. These can be used to connect components such as the DHT22 sensor or an OLED module to a breadboard.

● 214

Chapter 19 • Building Circuits with Components and Breadboards

Figure 19.5: Dupont cable. Pinheaders as depicted in Fig. 19.6 also make suitable connecting devices.

Figure 19.6: A 3-pin and a 12-pin pinheader. Dupont sockets can also be connected to a breadboard:

Figure 19.7: Dupont cable with 3-pin pinheader plugged on.

19.3 Resistors Resistors are among the basic components in electronics. They are non-polarized, so the direction of installation is irrelevant. The value of a resistor is coded by printed coloured rings. Four coloured rings are required for resistors with a tolerance of 5%. Three of them indicate

● 215

MicroPython for Microcontrollers

the resistance value, the fourth is gold-coloured for a tolerance and indicates the tolerance value. For metal film resistors with 1% tolerance, five coloured rings are required, here the brown fifth ring indicates the tolerance. The ring for the tolerance value can be recognized by the fact that it is slightly wider than the others.

Figure 19.8: Through-hole (TH) resistors.

Resistors with a value of 150 or 220 ohms are often used as series resistors for LEDs or LEDbased displays. The values 1-kohm, 10-kohm, and 100-kohm are also frequently required (where kohm = kilo-ohm; kΩ; 1000 ohms). If necessary, you can create further values yourself by connecting them in parallel or series (e.g. 500 ohms by connecting two 1 kohm in parallel, or 20 kohm by connecting two 10 kohm resistors in series, etc.). The following values are recommended for a start: Quantity

Value

Colour rings for 5% tolerance

Colour rings for 1% tolerance

10

220 ohms

Red - Red - Brown

Red - Red - Black - Black

10

1 kohms

Brown - Black - Red

Brown - Black - Black - Brown

5

10 kohms

Brown - Black - Orange

Brown - Black - Black - Red

5

100 kohms

Brown - Black - Yellow

Brown - Black - Black - Orange

In specialized trade and online shops, assortment boxes with the most important resistance values are often offered. In general, it is much cheaper to purchase such a range than to order the resistors individually.

19.4 Light-emitting diodes (LEDs) LEDs are used, for example, to indicate port states (HIGH/LOW). They only light up if they are correctly polarized. If, contrary to expectations, an LED does not light up, first check the polarity. The cathode of an LED has a flattening on the plastic housing. This connection must

● 216

Chapter 19 • Building Circuits with Components and Breadboards

be connected to the more negative voltage potential. Often the cathode can also be recognized by the shorter connecting wire. When connecting standard LEDs to a voltage source, a series resistor is always required. Since the ESP32 works with signal levels of 3.3 V, 220- or 150-ohm resistors are well suited for this purpose. Because between 1.6 V and 2.5 V drops across an LED — depending on the colour — a voltage of around 0.8 V to 1.6 V remains for the series resistor to drop. The LED currents are therefore around 4 mA to 7 mA. Thus, modern LEDs shine with sufficient brightness and both the LED and the controller operate in the safe range.

Figure 19.9: Light-emitting diodes.

19.5 Capacitors and electrolytic capacitors In addition to resistors, capacitors are also among the basic components of electronics. Simple capacitors are not polarized. However, care must be taken with electrolytic capacitors. Always ensure that the polarity is correct, as they will be destroyed if the polarity is reversed. This is why electrolytic capacitors always bear a corresponding marking. In microcontroller technology, the exact values of electrolytic capacitors are less important. They are often needed as so-called blocking capacitors to suppress interference, for which the exact value is not critical. Instead of a 10-µF type, for example, a 33-µF value can practically always be used, if it is available. For the beginning, a few values are sufficient, which are summarized in the following table. Number

Value

Labelling

Around 10

10 microfarads, 16V

10µ

Around 5

100 microfarads, 16V

100µ

● 217

MicroPython for Microcontrollers

The following illustration shows some electrolytic capacitors in radial housings:

Figure 19.10: Electrolytic capacitors. If errors occur sporadically in digital circuits, especially in more extensive setups, it is advisable to add some electrolytic capacitors on the power supply rails — with the correct polarity, naturally. If an oscilloscope is available, the supply voltage can be analyzed more precisely. If downward spikes, i.e. brief voltage dips, become visible here, a small electrolytic capacitor should be used locally on the board to maintain a clean supply voltage.

● 218

Chapter 20 • Troubleshooting

Chapter 20 • Troubleshooting The following is a list of the most common causes of errors in breadboard assemblies. If the list is conscientiously checked in the event of an error, there is a high probability that the circuit will work properly afterwards.

1. Hardware structure • Are all polarized components correctly mounted? Especially check LEDs and displays! • Make sure that bare connecting wires of components do not touch each other unintentionally. • Are all resistors correctly selected? In poor lighting conditions, the colour rings (especially red and orange) can easily be confused. • Reverse-engineering: if a circuit does not want to work at all, it can be very useful to try to draw its circuit diagram after the actual wiring and component layout. This often makes the assignment of the individual components clearer. • Is the USB or programming cable connected correctly? 2. Software-related issues Errors can also occur when programming the ESP chip. The following actions can be helpful here: • Reloading the MicroPython system • Pressing the Boot or Enable buttons • Restarting Thonny • Restarting µPyCraft

● 219

MicroPython for Microcontrollers

Chapter 21 • Hardware Resources Components, parts and modules can be ordered from the major electronics mail order companies: • Reichelt Electronics: • Conrad Electronic: • ELV-Elektronik AG: • Elektor Store:

www.reichelt.de www.conrad.de www.elv.de www.elektor.com

In addition, globally operating online retailers and distributors such as • Mouser • Farnell • RS Components • Amazon • eBay • AliExpress offer a wide range of electronic components. In particular, assortment boxes with various interesting components and modules can be found here.

● 220

Chapter 22 • List of Figures

Chapter 22 • List of Figures Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure

2.1: ESP32 boards (PICO-KIT, Node-ESP and NodeMCU)................................. 14 2.2: ESP32 PICO-KIT board......................................................................... 16 2.3: ESP board plugged into a breadboard..................................................... 17 2.4: NodeESP board in battery mode............................................................ 18 3.1: uPyCraft-IDE....................................................................................... 20 3.2: Selecting the port................................................................................ 21 3.3: Selecting the board type....................................................................... 21 3.4: The parameters for flashing the firmware................................................ 22 3.5: Creating a new file "main.py"................................................................ 24 3.6: Standard libraries in the uPy_lib folder.................................................... 24 3.7: Successful download of the first program................................................ 26 3.8: Internal LED at port 02 in action............................................................ 27 3.9: The COM port of the ESP32 in the Device Manager................................... 28 3.10: Information about ESP32.................................................................... 28 3.11: Successful erasing of the flash memory................................................. 29 3.12: Upload of the firmware is completed..................................................... 30 3.13: MicroPython reports to the TeraTerminal............................................... 30 3.14: Programming via TeraTerminal............................................................. 31 3.15: Help function in the terminal................................................................ 31 3.16: The Thonny-IDE after start-up............................................................. 32 3.17: The options window in Thonny............................................................. 33 3.18: Query when saving............................................................................. 36 4.1: Comment function in Thonny................................................................. 42 4.2: Print command in the console................................................................ 42 4.3: Print command as program instruction................................................... 43 4.4: Print command as program instruction in Thonny..................................... 43 4.5: Print command in the Thonny console.................................................... 44 4.6: Circuit diagram for LED at port 25.......................................................... 45 4.7: LED hooked up on port 25..................................................................... 45 4.8: Pin numbers here (here 25 and 26) on the ESP board............................... 46 4.9: Capturing voltage levels........................................................................ 47 4.10: Hardware structure for reading voltage levels........................................ 48 4.11: Deleting variables.............................................................................. 51 4.12: Small 1-times-1 multiplication table..................................................... 57 6.1: Circuit diagram for the running lights..................................................... 65 6.2: Construction method for the running lights or LED Chaser......................... 65 6.3: Circuit diagram for multicolour LED control.............................................. 67 6.4: Program abort with error message......................................................... 68 6.5: Error is intercepted.............................................................................. 69 7.1: PWM signal......................................................................................... 71 7.2: PWM signal on the oscilloscope screen.................................................... 71 7.3: Analogue voltage output on a DMM........................................................ 77 7.4: Sawtooth voltage on the oscilloscope...................................................... 78 7.5: ESP32 as a sine/rectangle generator...................................................... 79

● 221

MicroPython for Microcontrollers

Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure Figure

● 222

7.6: Impure sinewave signal........................................................................ 80 8.1: Interrupts........................................................................................... 81 8.2: Schematic of an automatic night light..................................................... 82 8.3: Running timer and active shell............................................................... 85 8.4: LED bicycle taillight.............................................................................. 87 8.5: Circuit diagram for LED taillight............................................................. 88 8.6: Breadboard construction of the LED taillight............................................ 89 9.1: Digitization of analogue values.............................................................. 91 9.2: Voltage measurement with a potentiometer............................................. 92 9.3: Breadboard layout for recording analogue measured values...................... 93 9.4: Display of the measured values in the Thonny console.............................. 94 9.5: Graphic representation in the plotter...................................................... 95 9.6: The non-linear characteristic of the ADC................................................. 96 9.7: Linearized ADC characteristic................................................................. 97 9.8: Voltage divider for extending the ADC measuring range............................ 99 9.9: Touch sensors connected to the ESP32................................................. 104 9.10: Signal change upon touching the touch sensors................................... 104 9.11: TMP36 sensor connections................................................................. 105 9.12: TMP36 on the ESP board................................................................... 106 9.13: Pinout of the DS18x20 thermosensor.................................................. 109 9.14: One-wire sensor hooked up to the ESP32............................................ 110 9.15: Multiple one-wire sensors connected to the ESP32................................ 111 9.16: Phototransistor................................................................................ 113 9.17: Connection diagram of the electronic luxmeter..................................... 114 9.18: A dual-transducer ultrasonic module................................................... 116 9.19: Ultrasonic module on the ESP32......................................................... 117 9.20: Setup for ultrasonic distance measurement......................................... 117 9.21: Ultrasonic-sound transmission pulse (top trace) and reception pulse (bottom trace)................................................................................. 119 9.22: Piezo buzzer.................................................................................... 120 9.23: Temperature/Humidity Sensors types DHT11 and DHT22...................... 121 9.24: DHT11/22 pin assignment................................................................. 122 9.25: Circuit diagram of the DHT module connected to the ESP board............. 123 9.26: DHT22 module and ESP module on the breadboard.............................. 123 9.27: Warning message for sensor failure.................................................... 124 9.28: DHT11 / DHT22 comparison measurement.......................................... 126 9.29: BME280 and ESP32 on the breadboard............................................... 127 9.30: Height measurement with the BME280............................................... 129 9.31: Measured values of the Hall sensor..................................................... 130 10.1: SSD1306 display on an ESP32........................................................... 133 10.2: SSD1306 display with text and graphic output..................................... 134 10.3: Frame in the OLED display................................................................. 136 10.4: Graphic elements on the OLED display................................................ 138 10.5: Data output on the OLED display........................................................ 140 10.6: ECG signal on the OLED display......................................................... 140 10.7: Digital clock with OLED display.......................................................... 141

Chapter 22 • List of Figures

Figure 10.8: Circuit diagram of the digital clock...................................................... 142 Figure 10.9: Stopwatch with sensor buttons.......................................................... 146 Figure 10.10: Sensor values on the OLED display................................................... 148 Figure 11.1: LED dot matrices are very popular in Asia........................................... 150 Figure 11.2: Principle of dot matrix control............................................................ 150 Figure 11.3: LED Matrix Module........................................................................... 151 Figure 11.4: Dot matrix display with six 8 x 8 matrix elements................................ 153 Figure 12.1: Servo control signal.......................................................................... 156 Figure 12.2: Servo for use in model building.......................................................... 156 Figure 12.3: Servo on the ESP32.......................................................................... 158 Figure 12.4: Circuit diagram for thermometer with servo display.............................. 160 Figure 12.5: Setup of the thermometer with servo-driven pointer readout................. 160 Figure 13.1: RFID module................................................................................... 161 Figure 13.2: RFID card and keychain.................................................................... 161 Figure 13.3: RFID module on an ESP32................................................................. 163 Figure 13.4: ID numbers of different RFID TAGs..................................................... 163 Figure 13.5: RFID-controlled Vault....................................................................... 166 Figure 14.3: ESP32 WebServer............................................................................. 176 Figure 14.4: Connection setup and IP address of the ESP32 board............................ 177 Figure 14.5: The website for the WLAN switch....................................................... 177 Figure 14.6: A web server for the transmission of analogue channels........................ 178 Figure 14.7: Analogue measured values in the browser........................................... 179 Figure 14.8: The Thermo/Hygro Server running and displayed in a browser............... 182 Figure 15.1: MQTT: Basic procedure..................................................................... 183 Figure 15.2: MQTT runtime scenario..................................................................... 184 Figure 15.3: API keys in ThingSpeak..................................................................... 185 Figure 15.4: MyChannels on ThingSpeak.com........................................................ 188 Figure 15.5: Dummy data on the ThingSpeak page................................................ 189 Figure 16.1: Display of climate data in ThingSpeak................................................. 193 Figure 16.2: Local display of climate data on the OLED display................................. 193 Figure 16.3: Compact WLAN weather station with display........................................ 194 Figure 16.4: Data display in ThingSpeak............................................................... 194 Figure 16.5: Options for data analysis.................................................................. 195 Figure 16.6: Data in the ThingView app................................................................. 196 Figure 16.7: Spikes produced by the optical room monitor reveal a person was present in the surveyed area............................................................. 198 Figure 17.1: Weather station with solar-powered operation..................................... 201 Figure 18.1: Basic structure of the I2C bus............................................................ 203 Figure 18.2: I²C bus timing................................................................................. 205 Figure 18.3: The I²C scanner finds two components on the bus............................... 207 Figure 18.4: Data communication via the SPI bus................................................... 208 Figure 18.5: SPI bus signal.................................................................................. 209 Figure 18.6: SPI interface on an SD card............................................................... 211 Figure 19.1: Playground consisting of two larger breadboards.................................. 212 Figure 19.2: Typical breadboard............................................................................. 213 Figure 19.3: Breadboard variants......................................................................... 213

● 223

MicroPython for Microcontrollers

Figure Figure Figure Figure Figure Figure Figure

● 224

19.4: Jumper cable................................................................................... 19.5: Dupont cable................................................................................... 19.6: A 3-pin and a 12-pin pinheader.......................................................... 19.7: Dupont cable with 3-pin pinheader plugged on..................................... 19.8: Through-hole (TH) resistors............................................................... 19.9: Light-emitting diodes........................................................................ 19.10: Electrolytic capacitors.....................................................................

214 215 215 215 216 217 218

Chapter 23 • Bill of Materials

Chapter 23 • Bill of Materials The following electronic components are recommended for carrying out the experiments described in this book. The components are included with the book in the MicroPython for Microcontrollers Product Bundle supplied by Elektor. 1. Resistors:

10x 220 Ω, 0.25 W 10x 1 kΩ, 0.25 W 5x 10 kΩ, 0.25 W 5x 100 kΩ, 0.25 W

2. LEDs:

5x red, 3mm diam. 1x multicolour (RGB)

3. Capacitors:

10x 10 µF 16 V, radial electrolytic 5x 100 µF 16 V, radial electrolytic

4. Potentiometer: 1x 10 kΩ linear 5. Sensors:

Temperature, analogue: TMP36 Temperature, digital: DS18x20 Light: BPW40 Ultrasound: HC-SR04 Temperature/humidity: DHT22 / DHT11 Climate: BME280 Sound transducer: Piezo buzzer (passive)

6. Display: OLED: SSD1306 LED, dot-matrix: MAX7219 7. Pushbutton:

2x

8. Servo:

Miniservo:

9. RFID module:

mfrc522

Type 9g

● 225

MicroPython for Microcontrollers

Index 8-bit resolution......................................76 8 x 8 dot matrices................................150 µPyCraft................................................19 µSD....................................................210

A ACK-bit...............................................205 active USB.............................................13 actuators.............................................155 ADC......................................................90 ADC conversion principles........................91 air pressure.........................................126 alarm system simulator...........................60 analogue...............................................90 analogue channels..................................92 analogue/digital converters......................90 API keys..............................................185 Arrays...................................................52 artificial intelligence................................39 automatic bathroom or stairwell lighting....82 automatic bedside lamp..........................82 automatic lighting systems....................112 automatic SOS beacon............................61 autonomous machines..........................155 autonomous vehicles............................115

B battery operation.................................199 beating heart.........................................73 bicycle spotlights....................................86 bidirectional bus system........................203 binary voltage........................................90 biologically optimized awakening..............74 blocking capacitors...............................155 blocks...................................................44 BME280..................................... 126, 190 BME280 sensor....................................148 BOD...................................................200 Boolean.................................................50 boot.py...............................................170 BPW40................................................114 Broker................................................183 brown-out detector...............................200 Bus systems........................................202

● 226

buzzer................................................117

C cal factor.............................................101 calibrated voltmeter................................97 capacitance change..............................102 capacitive sensors................................145 C/C++..................................................39 class "Pin".............................................45 comment...............................................41 commenting-out.....................................42 comparative measurements...................125 compensation curve polynomial................97 compensation polynomial........................96 Complex................................................50 continuous.............................................90 control structures...................................63 conversion speed....................................90 cross-interferences...............................102 cross-sensitivities.................................102 capacitors............................................217

D DAC......................................................70 data type..............................................50 deep sleep...........................................199 Delta-Sigma..........................................91 determination of room heights...............115 DHT11................................................121 DHT22................................................121 digital clock.........................................140 Digital to Analogue Converter...................70 digital voltage values..............................70 digitization noise....................................98 distance warning device........................119 distress at sea.......................................62 dot-matrix displays...............................150 DS18×20............................................108 dual-slope.............................................91 duty cycle..............................................70

E ECG amplifier.......................................140 electrolytic capacitors............................218



electromagnets....................................155 engine speeds......................................129 EEPROM..............................................202 else......................................................63 ESP32...................................................11 ESP32 DEV KIT DOIT..............................14 ESP32-PICO-KIT.....................................14 excess temperature signal.......................81

F False.....................................................51 filtering.................................................90 flashing LED..........................................60 Floating point.........................................50 for loops...............................................64 format..................................................55

G garbage collector..................................171 gateway..............................................168 global...................................................83 GPIO....................................................83 graphical display....................................90

H Hall-effect...........................................129 Hall effect sensor..................................129 Hall sensor..........................................129 hardware calibration.............................101 HC-SR04.............................................116 hectopascals........................................128 HIGH....................................................70 high-speed photography........................155 home networks....................................167 hPa.....................................................128 HTML text...........................................172 humidity.............................................121 humidity levels.....................................121

I I²C.....................................................202 if..........................................................63 Integer.................................................50 Inter-Integrated-Circuit.........................203 Internet Protocol..................................167 interrupt_handler...................................83

interrupt pins.......................................135 interrupts..............................................81 interrupt technology...............................87 IP.......................................................167 IRQ_FALLING.........................................83 IRQ_RISNING........................................83

J JOY-iT NodeMCU.....................................14

L large-format displays............................158 laser monitoring...................................112 LDRs...................................................112 LED flashing..........................................26 LEDs...................................................216 light barriers........................................112 light dependent resistors.......................112 light-reflecting materials........................115 light-sensitive components....................112 Li-ion batteries.......................................18 Li-ion battery charger.............................14 linearisation...........................................95 linearity................................................98 linearization...........................................90 live tickers...........................................150 LM35..................................................105 lock box..............................................166 Loops...................................................63 LOW.....................................................70 low-active...........................................145 luxmeter.............................................114

M MAC address........................................168 machine learning....................................39 magnetic field......................................130 magnetic field strength.........................129 Magnetic proximity...............................129 master/slave architecture......................203 MAX7219............................................151 measurement of temperatures...............105 Media Access Control............................168 Message Queuing Telemetry Transport....183 Micro Secure Digital..............................210 Micro-USB.............................................17

● 227

MicroPython for Microcontrollers

Microwire............................................208 MISO..................................................209 monitoring doors..................................130 mood lights...........................................75 MOSI..................................................209 moving graphics...................................153 MQTT broker............................... 184, 186 MQTT protocol......................................183 MSB-first.............................................205 multicolour LEDs....................................66

N Negative Temperature Coefficient...........105 network..............................................167 Noise signal.........................................107 non-linear.............................................95 non-linearity........................................100 north pole...........................................130 NTC sensors........................................105

O One-Wire bus.......................................108 open-collector inputs............................204 operators..............................................53 Optosensors........................................196

P Parallel converter...................................91 photodiodes.........................................112 Photo sensors......................................112 phototransistors...................................112 Phototransistors...................................112 Physical computing...............................155 piezo buzzer........................................120 plotter function......................................94 power consumption..............................199 power interruption................................149 precision...............................................98 precision potentiometer.........................101 program structure..................................44 publish-and-subscribe system................183 pull-up................................................123 pulsewidth modulation............................70 PWM.....................................................70 PWM-capable port..................................72 PWM control..........................................75

● 228

Q quasi-analogue display..........................159 quasi-analogue signals..........................155

R Radio-Frequency Identification...............161 Raspberry Pi..........................................11 reference voltage.................................101 resolution....................................... 90, 93 RFID...................................................161 RFID tags............................................161 RFID technology...................................164 robotics...............................................120 robot technology..................................115 rolling display......................................138 room brightness...................................196 running lights........................................64 ry/except..............................................68

S safety shutdown.....................................81 SAR......................................................91 sawtooth voltage....................................78 scanners.............................................168 Schottky diodes......................................99 Scientific notation...................................51 SCK....................................................209 SCL....................................................203 SCLK..................................................209 SD......................................................210 SDA....................................................203 Secure Digital......................................210 self-balancing robots.............................155 Serial Clock.........................................203 Serial Data..........................................203 Serial Peripheral Interface............ 202, 207 servo..................................................155 show() method....................................135 signal amplification.................................90 signal conditioning..................................90 signal conversion....................................90 single-chip systems................................11 Single-slope...........................................91 sleep command......................................48 sleep_us().............................................74 smartphones........................................195



SoC......................................................11 sockets...............................................171 software calibration..............................101 software correction.................................97 south pole...........................................130 SPI.....................................................202 SPI bus...............................................207 SPI-compatible interface........................151 spikes.................................................218 spindle trimmer....................................101 SSD1306.............................................132 stepper...............................................155 stopwatch...........................................145 Successive approximation........................91 surface properties................................115 synchronous data transmission...............208 Systems on Chip....................................11

T tablet computers..................................195 TCP....................................................167 temperature........................................121 temperature display..............................159 temperature probes..............................105 text() function.....................................135 Thermosensors....................................105 ThingSpeak........................ 168, 184, 190 ThingSpeak platform.............................185 ThingView...........................................195 Thonny.......................................... 19, 32

ultrasonic measuring.............................115 ultrasonic module.................................116 ultrasound...........................................115 Unique Identifier..................................162 USB power supply..................................17 USB-to-serial converters........................200

V variable name........................................50 variables...............................................50 voltage dips.........................................218

W warning tone.......................................120 web server..........................................177 while loops............................................64 wired-AND...........................................204 wireless communication capabilities........190 wireless LAN........................................167 WLAN.................................................167 WLAN access points..............................168

time().................................................140 time-critical process................................81 "time" module........................................48 time resolved measurements.................105 TMP36................................................105 Touch sensors......................................102 Transfer Control Protocol.......................167 transmitter/receiver modules.................116 transponder.........................................161 True.....................................................51 true analogue voltage.............................74 try/except-construction.........................124

U UART..................................................208 UID....................................................162

● 229

books books

MicroPython for Microcontrollers Projects with Thonny-IDE, uPyCraft-IDE, and ESP32

The “Python” programming language has enjoyed an enormous upswing in recent years. Not least, various single-board systems such as the Raspberry Pi have contributed to its popularity. But Python has also found widespread use in other fields, such as artificial intelligence (AI) or machine learning (ML). It is obvious, therefore, to use Python or the “MicroPython” variant for use in SoCs (Systems on Chip) as well. Powerful controllers such as the ESP32 from Espressif Systems offer excellent performance as well as Wi-Fi and Bluetooth functionality at an affordable price. With these features, the Maker scene has been taken by storm. Compared to other controllers, the ESP32 has a significantly larger flash and SRAM memory, as well as a much higher CPU speed. Due to these characteristics, the chip is not only suitable for classic C applications, but also for programming with MicroPython. This book introduces the application of modern one-chip systems. In addition to the technical background, the focus is on MicroPython itself. After the introduction to the language, the programming skills learned are immediately put into practice. The individual projects are suitable for use in the laboratory as well as for everyday applications. So, in addition to the actual learning effect, the focus is also on the joy of building complete and useful devices. By using laboratory breadboards, circuits of all kinds can be realized with little effort, turning the testing and debugging of the 100% homebrew projects into an instructive pleasure.

Günter Spanner The author has been active in the field of electronics development and technology management for various large corporations for over 25 years. In addition to his work as a lecturer, he has successfully published technical articles and books on the topics of electronics, microcontrollers, and sensor technology, as well as courses and learning packages. Furthermore, he is known to a wide audience through acclaimed specialist lectures and webinars.

The various applications, such as weather stations, digital voltmeters, ultrasound range finders, RFID card readers or function generators, make the projects presented ideally suited for practical courses or subject and study work in the natural sciences, or in science and technology classes. Elektor International Media BV www.elektor.com ISBN 978-3-89576-436-3