Learn how to MicroPython Programming with ESP32 and ESP8266, a re-implementation of Python programming language for microcontrollers.
Apart from a few minor differences, programming in MicroPython is very similar to programming in Python since it shares all of Python's language capabilities. MicroPython does not by default include the whole standard library since embedded systems and microcontrollers have far more limited capabilities than our PCs.
MicroPython programming is identical to Python programming if you already know how to do it. You only need to keep in mind that MicroPython is only used for restricted devices. As a result, you may expect to see a lot of traffic on your website.
This article explains the Python programming language syntax basics that also apply to MicroPython, like:
- Mathematical operators
- Relational operators
- Data types
- print() function
- Conditional statements
- While and for loops
- User defined functions
- Classes and objects
- Modules
Prerequisites
We're going to use the uPyCraft IDE in this tutorial, but you may use any other program. Follow these next tutorials to install and get started with the uPyCraft IDE:
- Getting Started with MicroPython on ESP32 and ESP8266
- Install uPyCraft IDE:
- Flash/Upload MicroPython Firmware to ESP32 and ESP8266
Mathematical Operators
Micropython is capable of doing mathematical operations. The following table shows the mathematical operators that are supported:
Operator | Mathematical Operation |
+ | Addition |
– | Subtraction |
* | Multiplication |
/ | Division |
// | Division, discarding the decimal point |
% | Remainder after division |
In the Shell, try several operations to see how they work. For example:
>>> 2+2*9-3 17 >>> 28594/2312 12.36765 >>> 214522236/7.5 2.860297e+07 >>> 23//2 11 >>> 25%3 1
If you import the math module, you may perform more mathematical operations like square root, trigonometric functions, logarithms, exponentiation, etc.
Relational Operators
By using relational operators, comparisons may be performed. These show the relation between the two values and compare the values on each side.
Operator | Description |
== | Equal to |
!= | Not equal to |
> | Greater than |
< | Less than |
>= | Greater than or equal to |
<= | Less than or equal to |
Try several comparisons and test the result:
>>> 2 == 3 False >>> 4 == 4 True >>> 3 > 2 True >>> 489808234 != 2223 True >>> 4.5 >= 4.5 True
Assigning Values to Variables
You don't need to declare the type of each variable in Python. You know that you need to declare the type of a variable when adding a new variable if you're used to programming your boards using the Arduino IDE. In Python, there is a thing.
For values like text or numbers, variables are simply storage placeholders. The equal sign (=), with the variable name on the left and the value on the right, is used to assign a value to a variable.
For example, you might simply type the following to create a variable to hold the GPIO number where an LED is connected:
led_pin = 23
In the Arduino IDE, you would have something like:
const int led_pin = 23;
As you can see, Python is much simpler than programming in C (in Arduino IDE).
Note: The variable names you give must be case-sensitive and cannot include spaces; thus, led_pin differs from LED_PIN or Led_Pin.
Data Types
Variables don't simply store whole numbers; they may also store other types of values. This is where data types come into play. A data type classification tells what operations may be done with a value and how it should be stored.
The following table shows the data types we’ll use most often in our projects.
Data type | Description |
int (Int) | Integer (whole number) |
float (Float) | Number with a decimal point |
str (String) | Set of characters between quotation marks |
bool (Boolean) | True or False |
Let’s create variables with different data types:
>>> a = 6 >>> b = 95.32 >>> c = 'Hello World!' >>> d = True
- The first value assigned to a is an integer, which is a whole number.
- The b variable contains a float value, which is a number with a decimal.
- The third value, ‘Hello World!’, is a string, which is a series of characters. A string must be put inside single (‘Hello World!’) or double quotation (“Hello World!”) marks.
- Finally, d is a Boolean, which is a type that can only take either True or False.
The type()
function may be used to check the data type of a variable. This function accepts as an argument the variable whose data type you wish to check.
type(variable)
For example, after declaring the variables in the previous example (a, b, c, and d), you can check their data type. For example, if you type:
>>> type(a)
It returns:
<class 'int'>
This tells us that a is an int (integer). Experiment with the other variables, and you should get:
>>> type(b) <class 'float'> >>> type(c) <class 'str'> >>> type(d) <class 'bool'>
print() Function
Between the brackets, the print() function prints the message into the Shell. Debugging the code and keeping track of what's going on is very useful in our projects. For example:
>>> print('LED is on') LED is on
Comments
Python comments start with the hash character (#) and go all the way to the end of the line. A comment is useful to add “notes” to your program or to tell everyone who reads the script what the program does. Your program doesn't get any more functionality as a result of this. For example:
# This is just a comment
There are occasions when you should avoid adding comments to save space on the ESP memory since we are working under constrained conditions in MicroPython.
Conditional Statements
You'll probably need to perform various actions based on whether a given condition is True or False to write useful programs. Conditional statements are what we're talking about. The following describes their structure:
if <expr1>: <statement1> elif <expr2>: <statement2> elif <expr3>: <statement3> (...) else: <statementn>
<expr> is a Boolean expression, and it can be either True or False. If it is True, the <statement> right after it is executed. The <statement> should be indented so that Python knows what statement belongs to each expression.
The elif statement stands for else if and runs only if the first if condition is not True.
The else statement only runs if none of the other expressions are True.
A program may have an unlimited number of elif statements. It's not required to include another clause, but if there is one, it must come at the end.
Curly brackets are used in the Arduino IDE to define code blocks. We use indentation with MicroPython. After each expression, you also need to include a colon (:). The expression does not need to be enclosed inside parentheses, unlike the Arduino IDE.
Important: Four spaces are the standard indentation in Python. To fit more code into the memory of the microcontroller, the indentation in MicroPython should only be 2 spaces.
While and For loops
As long as a condition is satisfied, loops let you execute a piece of code multiple times. While and for loops are two different types of loops. For instance, using a while loop, you can print all the numbers between 1 and 10:
number = 1 while number <= 10: print(number) number = number + 1
As long as the number variable's value is less than or equal to (<=) 10, the while loop's code, which is shown by the indentation, is executed. Every loop prints the current number, followed by an addition of 1.
You can also print numbers from 1 to 10 using a for loop, like this:
number = 1 for number in range(1, 11): print(number)
As long as the value of the long variable falls between the range of 1 and 11, the for loop will execute. The range() function automatically assigns the next value to the next variable until it is one lower than the final value you specify.
When you wish to repeat a block of code a certain number of times, you should use a for loop. When you want to repeatedly run code until a certain condition is no longer true, use a while loop. Then, if you're lucky enough to have a job, you may be able to get away with it.
The for and while Boolean expressions should have a colon right after them, much like the conditional statements, and the expressions that will be executed should be indented.
User-defined Functions
You use the word def, followed by the side you wish to give the function, and a set of brackets to define a new function. Add a colon after the parentheses, then tell the function what to do. In MicroPython, the statements must be indented by two spaces. For example:
def my_function(<arg1>, <arg2>, ...): <statement> (...) return
For example, a function that converts the temperature in Celsius to Fahrenheit could be the following:
def celsius_to_fahrenheit(temp_celsius): temp_fahrenheit = temp_celsius * (9/5) + 32 return temp_fahrenheit
The celsius_to_fahrenheit() function accepts as an argument a temperature in Celsius (temp_celsius). Then, it does the calculation to convert the temperature. Finally, it returns the temperature in Fahrenheit (temp_fahrenheit).
Note: Functions don’t necessarily need to return something. They could just perform some work without needing to return anything.
Classes and Objects
Python is a language for object-oriented programming (OOP). Classes and objects are two crucial OOP ideas that you should comprehend.
A class is an object's blueprint. It specifies a set of characteristics (data and function) for an object. Methods are the names given to the functions found inside a class. The class keyword is used to define classes, followed by the class name. For example:
class MyClass: (...)
Note: By convention, classes’ names in Python should be CapWords. However, you can give it whatever name you want.
A class's instances are objects. Simply put, it is a single entity made up of data and methods. All the functions of the object's class are accessible through it. Confused? Take a look at a simple example.
We may think of the term “person” as a class if we'd like to define several persons in a Python program using the same attributes. Using attributes like name, age, nationality, etc., we may wish to define a person.
Therefore, a class named “Person” may be created. The attributes of our class will be as follows: name, age, and country. As many attributes as you want may be added. We'll also create a method (function) that prints a summary of the person depending on its attributes:
class Person: name = "" age = 0 country = "" def description(self): print("%s is %d years old and he is from %s." %(self.name, self.age, self.country))
You can see that we define a new class by using the keyword class, followed by the name we wish to give the class.
We define a number of variables that may store values within the Person class. By default, the age is 0, and the name and country are empty strings. The function (method) that prints all the values of the variables into the Shell is then also defined.
The self-parameter should be an argument for all functions inside a class, along with any other arguments that may be required.
The self parameter refers to the actual object. It is used to get access to variables belonging to the class. To access the name variable inside the class, for example, we should use self.name.
We can produce as many Person objects as we desire by using the class we just built. A name, an age, and a nation will be included in the Person object. Using the description()
method, we can also print its description.
For example, to create a new Person object called person1:
>>> person1 = Person()
Set the object’s properties
To set the name, age, and country of the person1 object. You can do it as follows:
>>> person1.name = "Rui" >>> person1.age = 25 >>> person1.country = "Portugal"
Calling methods
Later in your code, you can use the created description()
method on any Person object. To call the description()
method on the person1 object:
>>> person1.description()
This should print the following:
Rui is 25 years old and he is from Portugal.
You should now understand that you are able to create as many objects as you want using the same class and that you can use the available methods with all of that class's methods.
The constructor method
You may use the constructor method inside your class instead of having to define a class and then set the object's properties, which can be time-consuming.
As soon as a class object is created, data is started using the constructor method. Also known as the __init__ method, the constructor method is a method. The Person()
class looks as follows when using the __init__ method:
class Person(): def __init__(self, name, age, country): self.name = name self.age = age self.country = country def description(self): print("%s is %d years old and he is from %s." %(self.name, self.age, self.country))
Then, to instantiate a Person object with the same attributes we’ve defined earlier, we just need to do the following:
>>> person1 = Person("Rui", 25, "Portugal")
If you call the description()
on the person1 object, you’ll get the same result:
>>> person1.description() Rui is 25 years old and he is from Portugal.
Modules
You may use a set of classes and functions from a module in your code. A module is a file. It's possible to call it a library if you want to, but it's not a must. You just need to import that class into your code to have access to the classes and functions inside that code.
Use pre-made modules from the standard Python library or create your own. When it comes to MicroPython, it only comes with a small portion of the standard Python library, but it does come with a set of modules to control GPIOs, make network connections, and much more.
Importing modules/libraries is as simple as using:
import module_name
For example, to import the machine library that contains classes to control GPIOs, type the following:
import machine
You won't need all the classes in one module for the majority of programs. Just a single class may be what you wish to import. To import only the Pin class from the machine module, for example.
from machine import Pin
Conclusion
The basics of Python that also apply to MicroPython have just been touched on in this tutorial. You'll find that MicroPython has a far more straightforward and user-friendly syntax if you're accustomed to programming electronics using the Arduino IDE. Let's just summarise a few of the key differences between your Arduino sketches and MicroPython programs:
- You don’t use a semicolon at the end of a statement.
- After Boolean expressions in conditional statements and loops, you use a colon:.
- To define code blocks, use indentation instead of curly brackets {}.
- When creating a variable, you don’t need to define which data type it is; you don’t need to declare a variable.
- Indentation in MicroPython is 2 spaces.
If you like MicroPython, you may also like:
- How to Flash MicroPython Firmware to ESP32 and ESP8266
- Getting Started with MicroPython on ESP32 and ESP8266
- How to Install uPyCraft IDE on a Windows PC
We hope you find this tutorial useful. Thanks for reading.