1,710 137 10MB
English Pages 229 Year 2021
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
"""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)Pin | Value |
---|
Temperature """+str(temp)+""" °C
Humidity """+str(hum)+""" %
Temperature: """+str(temp)+""" °C
Humidity: """+str(hum)+""" %