Damien George
9 years ago
13 changed files with 960 additions and 1 deletions
@ -0,0 +1,19 @@ |
|||
Analog to Digital Conversion |
|||
============================ |
|||
|
|||
The ESP8266 has a single pin (separate to the GPIO pins) which can be used to |
|||
read analog voltages and convert them to a digital value. You can construct |
|||
such an ADC pin object using:: |
|||
|
|||
>>> import machine |
|||
>>> adc = machine.ADC(0) |
|||
|
|||
Then read its value with:: |
|||
|
|||
>>> adc.read() |
|||
58 |
|||
|
|||
The values returned from the ``read()`` function are between 0 (for 0.0 volts) |
|||
and 1024 (for 1.0 volts). Please note that this input can only tolerate a |
|||
maximum of 1.0 volts and you must use a voltage divider circuit to measure |
|||
larger voltages. |
@ -0,0 +1,70 @@ |
|||
The internal filesystem |
|||
======================= |
|||
|
|||
If your devices has 1Mbyte or more of storage then it will be set up (upon first |
|||
boot) to contain a filesystem. This filesystem uses the FAT format and is |
|||
stored in the flash after the MicroPython firmware. |
|||
|
|||
Creating and reading files |
|||
-------------------------- |
|||
|
|||
MicroPython on the ESP8266 supports the standard way of accessing files in |
|||
Python, using the built-in ``open()`` function. |
|||
|
|||
To create a file try:: |
|||
|
|||
>>> f = open('data.txt', 'w') |
|||
>>> f.write('some data') |
|||
9 |
|||
>>> f.close() |
|||
|
|||
The "9" is the number of bytes that were written with the ``write()`` method. |
|||
Then you can read back the contents of this new file using:: |
|||
|
|||
>>> f = open('data.txt') |
|||
>>> f.read() |
|||
'some data' |
|||
>>> f.close() |
|||
|
|||
Note that the default mode when opening a file is to open it in read-only mode, |
|||
and as a text file. Specify ``'wb'`` as the second argument to ``open()`` to |
|||
open for writing in binary mode, and ``'rb'`` to open for reading in binary |
|||
mode. |
|||
|
|||
Listing file and more |
|||
--------------------- |
|||
|
|||
The os module can be used for further control over the filesystem. First |
|||
import the module:: |
|||
|
|||
>>> import os |
|||
|
|||
Then try listing the contents of the filesystem:: |
|||
|
|||
>>> os.listdir() |
|||
['boot.py', 'port_config.py', 'data.txt'] |
|||
|
|||
You can make directories:: |
|||
|
|||
>>> os.mkdir('dir') |
|||
|
|||
And remove entries:: |
|||
|
|||
>>> os.remove('data.txt') |
|||
|
|||
Start up scripts |
|||
---------------- |
|||
|
|||
There are two files that are treated specially by the ESP8266 when it starts up: |
|||
boot.py and main.py. The boot.py script is executed first (if it exists) and |
|||
then once it completes the main.py script is executed. You can create these |
|||
files yourself and populate them with the code that you want to run when the |
|||
device starts up. |
|||
|
|||
Accessing the filesystem via WebREPL |
|||
------------------------------------ |
|||
|
|||
You can access the filesystem over WebREPL using the provided command-line |
|||
tool. This tool is found at `<https://github.com/micropython/webrepl>`__ |
|||
and is called webrepl_cli.py. Please refer to that program for information |
|||
on how to use it. |
@ -0,0 +1,95 @@ |
|||
Introduction to MicroPython on the ESP8266 |
|||
========================================== |
|||
|
|||
Using MicroPython is a great way to get the most of your ESP8266 board. And |
|||
vice versa, the ESP8266 chip is a great platform for using MicroPython. This |
|||
tutorial will guide you through setting up MicroPython, getting a prompt, using |
|||
WebREPL, connecting to the network and communicating with the Internet, using |
|||
the hardware peripherals, and controlling some external components. |
|||
|
|||
Let's get started! |
|||
|
|||
Requirements |
|||
------------ |
|||
|
|||
The first thing you need is a board with an ESP8266 chip. The MicroPython |
|||
software supports the ESP8266 chip itself and any board should work. The main |
|||
characteristic of a board is how much flash it has, how the GPIO pins are |
|||
connected to the outside world, and whether it includes a built-in USB-serial |
|||
convertor to make the UART available to your PC. |
|||
|
|||
The minimum requirement for flash size is 512k. A board with this amount of |
|||
flash will not have room for a filesystem, but otherwise is fully functional. |
|||
If your board has 1Mbyte or more of flash then it will support a filesystem. |
|||
|
|||
Names of pins will be given in this tutorial using the chip names (eg GPIO0) |
|||
and it should be straightforward to find which pin this corresponds to on your |
|||
particular board. |
|||
|
|||
Powering the board |
|||
------------------ |
|||
|
|||
If your board has a USB connector on it then most likely it is powered through |
|||
this when connected to your PC. Otherwise you will need to power it directly. |
|||
Please refer to the documentation for your board for further details. |
|||
|
|||
Deploying the firmware |
|||
---------------------- |
|||
|
|||
The very first thing you need to do is put the MicroPython firmware (compiled |
|||
code) on your ESP8266 device. There are two main steps to do this: first you |
|||
need to put your device in boot-loader mode, and second you need to copy across |
|||
the firmware. The exact procedure for these steps is highly dependent on the |
|||
particular board and you will need to refer to its documentation for details. |
|||
|
|||
If you have a board that has a USB connector, a USB-serial convertor, and has |
|||
the DTR and RTS pins wired in a special way then deploying the firmware should |
|||
be easy as all steps can be done automatically. Boards that have such features |
|||
include the Adafruit Feather HUZZAH and NodeMCU boards. |
|||
|
|||
For best results it is recommended to first erase the entire flash of your |
|||
device before putting on new MicroPython firmware. |
|||
|
|||
Currently we only support esptool.py to copy across the firmware. You can find |
|||
this tool here: `<https://github.com/themadinventor/esptool/>`__ . Any other |
|||
flashing program should work, so feel free to try them out, or refer to the |
|||
documentation for your board to see its recommendations. |
|||
|
|||
Using esptool.py you can erase the flash with the command:: |
|||
|
|||
esptool.py --port /dev/ttyUSB0 erase_flash |
|||
|
|||
And then deploy the new firmware using:: |
|||
|
|||
esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=8m 0 mp-esp8266-firmware.bin |
|||
|
|||
You might need to change the "port" setting to something else relevant for your |
|||
PC. You may also need to reduce the baudrate if you get errors when flashing |
|||
(eg down to 115200). |
|||
|
|||
If you have a NodeMCU board, you may need to use the following command to deploy |
|||
the firmware (note the "-fm dio" option):: |
|||
|
|||
esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=8m -fm dio 0 mp-esp8266-firmware.bin |
|||
|
|||
If the above commands run without error then MicroPython should be installed on |
|||
your board! |
|||
|
|||
Serial prompt |
|||
------------- |
|||
|
|||
Once you have the firmware on the device you can access the REPL (Python prompt) |
|||
over UART0 (GPIO1=TX, GPIO3=RX), which might be connected to a USB-serial |
|||
convertor, depending on your board. The baudrate is 115200. The next part of |
|||
the tutorial will discuss the prompt in more detail. |
|||
|
|||
WiFi |
|||
---- |
|||
|
|||
After a fresh install and boot the device configures itself as a WiFi access |
|||
point (AP) that you can connect to. The ESSID is of the form MicroPython-xxxxxx |
|||
where the x's are replaced with part of the MAC address of your device (so will |
|||
be the same everytime, and most likely different for all ESP8266 chips). The |
|||
password for the WiFi is micropythoN (note the upper-case N). Its IP address |
|||
will be 192.168.4.1 once you connect to its network. WiFi configuration will |
|||
be discussed in more detail later in the tutorial. |
@ -0,0 +1,70 @@ |
|||
Controlling NeoPixels |
|||
===================== |
|||
|
|||
NeoPixels, also known as WS2812 LEDs, are full-colour LEDs that are connected in |
|||
serial, are individually addressable, and can have their red, green and blue |
|||
components set between 0 and 255. They require precise timing to control them |
|||
and there is a special neopixel module to do just this. |
|||
|
|||
To create a NeoPixel object do the following:: |
|||
|
|||
>>> import machine, neopixel |
|||
>>> np = neopixel.NeoPixel(machine.Pin(4), 8) |
|||
|
|||
This configures a NeoPixel strip on GPIO4 with 8 pixels. You can adjust the |
|||
"4" (pin number) and the "8" (number of pixel) to suit your set up. |
|||
|
|||
To set the colour of pixels use:: |
|||
|
|||
>>> np[0] = (255, 0, 0) # set to red, full brightness |
|||
>>> np[1] = (0, 128, 0) # set to green, half brightness |
|||
>>> np[2] = (0, 0, 64) # set to blue, quarter brightness |
|||
|
|||
Then use the ``write()`` method to output the colours to the LEDs:: |
|||
|
|||
>>> np.write() |
|||
|
|||
The following demo function makes a fancy show on the LEDs:: |
|||
|
|||
import time |
|||
|
|||
def demo(np): |
|||
n = np.n |
|||
|
|||
# cycle |
|||
for i in range(4 * n): |
|||
for j in range(n): |
|||
np[j] = (0, 0, 0) |
|||
np[i % n] = (255, 255, 255) |
|||
np.write() |
|||
time.sleep_ms(25) |
|||
|
|||
# bounce |
|||
for i in range(4 * n): |
|||
for j in range(n): |
|||
np[j] = (0, 0, 128) |
|||
if (i // n) % 2 == 0: |
|||
np[i % n] = (0, 0, 0) |
|||
else: |
|||
np[n - 1 - (i % n)] = (0, 0, 0) |
|||
np.write() |
|||
time.sleep_ms(60) |
|||
|
|||
# fade in/out |
|||
for i in range(0, 4 * 256, 8): |
|||
for j in range(n): |
|||
if (i // 256) % 2 == 0: |
|||
val = i & 0xff |
|||
else: |
|||
val = 255 - (i & 0xff) |
|||
np[j] = (val, 0, 0) |
|||
np.write() |
|||
|
|||
# clear |
|||
for i in range(n): |
|||
np[i] = (0, 0, 0) |
|||
np.write() |
|||
|
|||
Execute it using:: |
|||
|
|||
>>> demo(np) |
@ -0,0 +1,81 @@ |
|||
Network basics |
|||
============== |
|||
|
|||
The network module is used to configure the WiFi connection. There are two WiFi |
|||
interfaces, one for the station (when the ESP8266 connects to a router) and one |
|||
for the access point (for other devices to connect to the ESP8266). Create |
|||
instances of these objects using:: |
|||
|
|||
>>> import network |
|||
>>> sta_if = network.WLAN(network.STA_IF) |
|||
>>> ap_if = network.WLAN(network.AP_IF) |
|||
|
|||
You can check if the interfaces are active by:: |
|||
|
|||
>>> sta_if.active() |
|||
False |
|||
>>> ap_if.active() |
|||
True |
|||
|
|||
You can also check the network settings of the interface by:: |
|||
|
|||
>>> ap.ifconfig() |
|||
('192.168.4.1', '255.255.255.0', '192.168.4.1', '8.8.8.8') |
|||
|
|||
The returned values are: IP address, netmask, gateway, DNS. |
|||
|
|||
Configuration of the WiFi |
|||
------------------------- |
|||
|
|||
Upon a fresh install the ESP8266 is configured in access point mode, so the |
|||
AP_IF interface is active and the STA_IF interface is inactive. You can |
|||
configure the module to connect to your own network using the STA_IF interface. |
|||
|
|||
First activate the station interface:: |
|||
|
|||
>>> sta_if.active(True) |
|||
|
|||
Then connect to your WiFi network:: |
|||
|
|||
>>> sta_if.connect('<your ESSID>', '<your password>') |
|||
|
|||
To check if the connection is established use:: |
|||
|
|||
>>> sta_if.isconnected() |
|||
|
|||
Once established you can check the IP address:: |
|||
|
|||
>>> sta_if.ifconfig() |
|||
('192.168.0.2', '255.255.255.0', '192.168.0.1', '8.8.8.8') |
|||
|
|||
You can then disable the access-point interface if you no longer need it:: |
|||
|
|||
>>> ap_if.active(False) |
|||
|
|||
Here is a function you can run (or put in your boot.py file) to automatically |
|||
connect to your WiFi network:: |
|||
|
|||
def do_connect(): |
|||
import network |
|||
sta_if = network.WLAN(network.STA_IF) |
|||
if not sta_if.isconnected(): |
|||
print('connecting to network...') |
|||
sta_if.active(True) |
|||
sta_if.connect('<essid>', '<password>') |
|||
while not network.isconnected(): |
|||
pass |
|||
print('network config:', sta_if.ifconfig()) |
|||
|
|||
Sockets |
|||
------- |
|||
|
|||
Once the WiFi is set up the way to access the network is by using sockets. |
|||
A socket represents an endpoint on a network device, and when two sockets are |
|||
connected together communication can proceed. |
|||
Internet protocols are built on top of sockets, such as email (SMTP), the web |
|||
(HTTP), telnet, ssh, among many others. Each of these protocols is assigned |
|||
a specific port, which is just an integer. Given an IP address and a port |
|||
number you can connect to a remote device and start talking with it. |
|||
|
|||
The next part of the tutorial discusses how to use sockets to do some common |
|||
and useful network tasks. |
@ -0,0 +1,121 @@ |
|||
Network - TCP sockets |
|||
===================== |
|||
|
|||
The building block of most of the internet is the TCP socket. These sockets |
|||
provide a reliable stream of bytes between the connected network devices. |
|||
This part of the tutorial will show how to use TCP sockets in a few different |
|||
cases. |
|||
|
|||
Star Wars Asciimation |
|||
--------------------- |
|||
|
|||
The simplest thing to do is to download data from the internet. In this case |
|||
we will use the Star Wars Asciimation service provided by the blinkenlights.nl |
|||
website. It uses the telnet protocol on port 23 to stream data to anyone that |
|||
connects. It's very simple to use because it doesn't require you to |
|||
authenticate (give a username or password), you can just start downloading data |
|||
straight away. |
|||
|
|||
The first thing to do is make sure we have the socket module available:: |
|||
|
|||
>>> import socket |
|||
|
|||
Then get the IP address of the server:: |
|||
|
|||
>>> addr_info = socket.getaddrinfo("towel.blinkenlights.nl", 23) |
|||
|
|||
The ``getaddrinfo`` function actually returns a list of addresses, and each |
|||
address has more information than we need. We want to get just the first valid |
|||
address, and then just the IP address and port of the server. To do this use:: |
|||
|
|||
>>> addr = addr_info[0][-1] |
|||
|
|||
If you type ``addr_info`` and ``addr`` at the prompt you will see exactly what |
|||
information they hold. |
|||
|
|||
Using the IP address we can make a socket and connect to the server:: |
|||
|
|||
>>> s = socket.socket() |
|||
>>> s.connect(addr[0][-1]) |
|||
|
|||
Now that we are connected we can download and display the data:: |
|||
|
|||
>>> while True: |
|||
... data = s.recv(500) |
|||
... print(str(data, 'utf8'), end='') |
|||
... |
|||
|
|||
When this loop executes it should start showing the animation (use ctrl-C to |
|||
interrupt it). |
|||
|
|||
You should also be able to run this same code on your PC using normal Python if |
|||
you want to try it out there. |
|||
|
|||
HTTP GET request |
|||
---------------- |
|||
|
|||
The next example shows how to download a webpage. HTTP uses port 80 and you |
|||
first need to send a "GET" request before you can download anything. As part |
|||
of the request you need to specify the page to retrieve. |
|||
|
|||
Let's define a function that can download and print a URL:: |
|||
|
|||
def http_get(url): |
|||
_, _, host, path = url.split('/', 3) |
|||
addr = socket.getaddrinfo(host, 80)[0][-1] |
|||
s = socket.socket() |
|||
s.connect(addr) |
|||
s.send(bytes('GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n' % (path, host), 'utf8')) |
|||
while True: |
|||
data = s.recv(100) |
|||
if data: |
|||
print(str(data, 'utf8'), end='') |
|||
else: |
|||
break |
|||
|
|||
Make sure that you import the socket module before running this function. Then |
|||
you can try:: |
|||
|
|||
>>> http_get('http://micropython.org/ks/test.html') |
|||
|
|||
This should retrieve the webpage and print the HTML to the console. |
|||
|
|||
Simple HTTP server |
|||
------------------ |
|||
|
|||
The following code creates an simple HTTP server which serves a single webpage |
|||
that contains a table with the state of all the GPIO pins:: |
|||
|
|||
import machine |
|||
pins = [machine.Pin(i, machine.Pin.IN) for i in (0, 2, 4, 5, 12, 13, 14, 15)] |
|||
|
|||
html = """<!DOCTYPE html> |
|||
<html> |
|||
<head> <title>ESP8266 Pins</title> </head> |
|||
<body> <h1>ESP8266 Pins</h1> |
|||
<table border="1"> <tr><th>Pin</th><th>Value</th></tr> %s </table> |
|||
</body> |
|||
</html> |
|||
""" |
|||
|
|||
import socket |
|||
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1] |
|||
|
|||
s = socket.socket() |
|||
s.bind(addr) |
|||
s.listen(1) |
|||
|
|||
print('listening on', addr) |
|||
|
|||
while True: |
|||
cl, addr = s.accept() |
|||
print('client connected from', addr) |
|||
cl_file = cl.makefile('rwb', 0) |
|||
while True: |
|||
line = cl_file.readline() |
|||
if not line or line == b'\r\n': |
|||
break |
|||
rows = ['<tr><td>%s</td><td>%d</td></tr>' % (str(p), p.value()) for p in pins] |
|||
response = html % '\n'.join(rows) |
|||
cl.send(response) |
|||
cl.close() |
@ -0,0 +1,12 @@ |
|||
Next steps |
|||
========== |
|||
|
|||
That brings us to the end of the tutorial! Hopefully by now you have a good |
|||
feel for the capabilities of MicroPython on the ESP8266 and understand how to |
|||
control both the WiFi and IO aspects of the chip. |
|||
|
|||
There are many features that were not covered in this tutorial. The best way |
|||
to learn about them is to read the full documentation of the modules, and to |
|||
experiment! |
|||
|
|||
Good luck creating your Internet of Things devices! |
@ -0,0 +1,37 @@ |
|||
Controlling 1-wire devices |
|||
========================== |
|||
|
|||
The 1-wire bus is a serial bus that uses just a single wire for communication |
|||
(in addition to wires for ground and power). The DS18B20 temperature sensor |
|||
is a very popular 1-wire device, and here we show how to use the onewire module |
|||
to read from such a device. |
|||
|
|||
For the following code to work you need to have at least one DS18B20 temperature |
|||
sensor with its data line connected to GPIO12. You must also power the sensors |
|||
and connect a 4.7k Ohm resistor between the data pin and the power pin. :: |
|||
|
|||
import time |
|||
import machine |
|||
import onewire |
|||
|
|||
# the device is on GPIO12 |
|||
dat = machine.Pin(12) |
|||
|
|||
# create the onewire object |
|||
ds = onewire.DS18B20(onewire.OneWire(dat)) |
|||
|
|||
# scan for devices on the bus |
|||
roms = ds.scan() |
|||
print('found devices:', roms) |
|||
|
|||
# loop 10 times and print all temperatures |
|||
for i in range(10): |
|||
print('temperatures:', end=' ') |
|||
ds.convert_temp() |
|||
time.sleep_ms(750) |
|||
for rom in roms: |
|||
print(ds.read_temp(rom), end=' ') |
|||
print() |
|||
|
|||
Note that you must execute the ``convert_temp()`` function to initiate a |
|||
temperature reading, then wait at least 750ms before reading the value. |
@ -0,0 +1,75 @@ |
|||
GPIO Pins |
|||
========= |
|||
|
|||
The way to connect your board to the external world, and control other |
|||
components, is through the GPIO pins. Not all pins are available to use, |
|||
in most cases only pins 0, 2, 4, 5, 12, 13, 14, 15, and 16 can be used. |
|||
|
|||
The pins are available in the machine module, so make sure you import that |
|||
first. Then you can create a pin using:: |
|||
|
|||
>>> pin = machine.Pin(0) |
|||
|
|||
Here, the "0" is the pin that you want to access. Usually you want to |
|||
configure the pin to be input or output, and you do this when constructing |
|||
it. To make an input pin use:: |
|||
|
|||
>>> pin = machine.Pin(0, machine.Pin.OUT, machine.Pin.PULL_UP) |
|||
|
|||
You can either use PULL_UP or PULL_NONE for the input pull-mode. If it's |
|||
not specified then it defaults to PULL_NONE. You can read the value on |
|||
the pin using:: |
|||
|
|||
>>> pin.value() |
|||
0 |
|||
|
|||
The pin on your board may return 0 or 1 here, depending on what it's connected |
|||
to. To make an output pin use:: |
|||
|
|||
>>> pin = machine.Pin(0, machine.Pin.OUT) |
|||
|
|||
Then set its value using:: |
|||
|
|||
>>> pin.value(0) |
|||
>>> pin.value(1) |
|||
|
|||
Or:: |
|||
|
|||
>>> pin.low() |
|||
>>> pin.high() |
|||
|
|||
External interrupts |
|||
------------------- |
|||
|
|||
All pins except number 16 can be configured to trigger a hard interrupt if their |
|||
input changes. You can set code (a callback function) to be executed on the |
|||
trigger. |
|||
|
|||
Let's first define a callback function, which must take a single argument, |
|||
being the pin that triggered the function. We will make the function just print |
|||
the pin:: |
|||
|
|||
>>> def callback(p): |
|||
... print('pin change', p) |
|||
|
|||
Next we will create two pins and configure them as inputs:: |
|||
|
|||
>>> from machine import Pin |
|||
>>> p0 = Pin(0, Pin.IN) |
|||
>>> p2 = Pin(2, Pin.IN) |
|||
|
|||
An finally we need to tell the pins when to trigger, and the function to call |
|||
when they detect an event:: |
|||
|
|||
>>> p0.irq(Pin.IRQ_FALLING, callback) |
|||
>>> p2.irq(Pin.IRQ_RISING | Pin.IRQ_FALLING, callback) |
|||
|
|||
We set pin 0 to trigger only on a falling edge of the input (when it goes from |
|||
high to low), and set pin 2 to trigger on both a rising and falling edge. After |
|||
entering this code you can apply high and low voltages to pins 0 and 2 to see |
|||
the interrupt being executed. |
|||
|
|||
A hard interrupt will trigger as soon as the event occurs and will interrupt any |
|||
running code, including Python code. As such your callback functions are |
|||
limited in what they can do (they cannot allocate memory, for example) and |
|||
should be as short and simple as possible. |
@ -0,0 +1,61 @@ |
|||
Power control |
|||
============= |
|||
|
|||
The ESP8266 provides the ability to change the CPU frequency on the fly, and |
|||
enter a deep-sleep state. Both can be used to manage power consumption. |
|||
|
|||
Changing the CPU frequency |
|||
-------------------------- |
|||
|
|||
The machine module has a function to get and set the CPU frequency. To get the |
|||
current frequency use:: |
|||
|
|||
>>> import machine |
|||
>>> machine.freq() |
|||
80000000 |
|||
|
|||
By default the CPU runs at 80MHz. It can be change to 160MHz if you need more |
|||
processing power, at the expense of current consumption:: |
|||
|
|||
>>> machine.freq(160000000) |
|||
>>> machine.freq() |
|||
160000000 |
|||
|
|||
You can change to the higher frequency just while your code does the heavy |
|||
processing and then change back when its finished. |
|||
|
|||
Deep-sleep mode |
|||
--------------- |
|||
|
|||
The deep-sleep mode will shut down the ESP8266 and all its peripherals, |
|||
including the WiFi (but not including the real-time-clock, which is used to wake |
|||
the chip). This drastically reduces current consumption and is a good way to |
|||
make devices that can run for a while on a battery. |
|||
|
|||
To be able to use the deep-sleep feature you must connect GPIO16 to the reset |
|||
pin (RST on the Adafruit Feather HUZZAH board). Then the following code can be |
|||
used to sleep and wake the device:: |
|||
|
|||
import machine |
|||
|
|||
# configure RTC.ALARM0 to be able to wake the device |
|||
rtc = machine.RTC() |
|||
rtc.irq(trigger=rtc.ALARM0, wake=machine.DEEPSLEEP) |
|||
|
|||
# set RTC.ALARM0 to fire after 10 seconds (waking the device) |
|||
rtc.alarm(rtc.ALARM0, 10000) |
|||
|
|||
# put the device to sleep |
|||
machine.deepsleep() |
|||
|
|||
Note that when the chip wakes from a deep-sleep it is completely reset, |
|||
including all of the memory. The boot scripts will run as usual and you can |
|||
put code in them to check the reset cause to perhaps do something different if |
|||
the device just woke from a deep-sleep. For example, to print the reset cause |
|||
you can use:: |
|||
|
|||
if machine.reset_cause() == machine.DEEPSLEEP_RESET: |
|||
print('woke from a deep sleep') |
|||
else: |
|||
print('power on or hard reset') |
|||
|
@ -0,0 +1,87 @@ |
|||
Pulse Width Modulation |
|||
====================== |
|||
|
|||
Pulse width modulation (PWM) is a way to get an artificial analog output on a |
|||
digital pin. It achieves this by rapidly toggling the pin from low to high. |
|||
There are two parameters associated with this: the frequency of the toggling, |
|||
and the duty cycle. The duty cycle is defined to be how long the pin is high |
|||
compared with the length of a single period (low plus high time). Maximum |
|||
duty cycle is when the pin is high all of the time, and minimum is when it is |
|||
low all of the time. |
|||
|
|||
On the ESP8266 the pins 0, 2, 4, 5, 12, 13, 14 and 15 all support PWM. The |
|||
limitation is that they must all be at the same frequency, and the frequency |
|||
must be between 1Hz and 1kHz. |
|||
|
|||
To use PWM on a pin you must first create the pin object, for example:: |
|||
|
|||
>>> import machine |
|||
>>> p12 = machine.Pin(12) |
|||
|
|||
Then create the PWM object using:: |
|||
|
|||
>>> pwm12 = machine.PWM(p12) |
|||
|
|||
You can set the frequency and duty cycle using:: |
|||
|
|||
>>> pwm12.freq(500) |
|||
>>> pwm12.duty(512) |
|||
|
|||
Note that the duty cycle is between 0 (all off) and 1023 (all on), with 512 |
|||
being a 50% duty. If you print the PWM object then it will tell you its current |
|||
configuration:: |
|||
|
|||
>>> pwm12 |
|||
PWM(12, freq=500, duty=512) |
|||
|
|||
You can also call the ``freq()`` and ``duty()`` methods with no arguments to |
|||
get their current values. |
|||
|
|||
The pin will continue to be in PWM mode until you deinitialise it using:: |
|||
|
|||
>>> pwm12.deinit() |
|||
|
|||
Fading an LED |
|||
------------- |
|||
|
|||
Let's use the PWM feature to fade an LED. Assuming your board has an LED |
|||
connected to pin 2 (ESP-12 modules do) we can create an LED-PWM object using:: |
|||
|
|||
>>> led = machine.PWM(machine.Pin(2), freq=1000) |
|||
|
|||
Notice that we can set the frequency in the PWM constructor. |
|||
|
|||
For the next part we will use timing and some math, so import these modules:: |
|||
|
|||
>>> import time, math |
|||
|
|||
Then create a function to pulse the LED:: |
|||
|
|||
>>> def pulse(l, t): |
|||
... for i in range(20): |
|||
... l.duty(int(math.sin(i / 10 * math.pi) * 500 + 500)) |
|||
... time.sleep_ms(t) |
|||
|
|||
You can try this function out using:: |
|||
|
|||
>>> pulse(led, 50) |
|||
|
|||
For a nice effect you can pulse many times in a row:: |
|||
|
|||
>>> for i in range(10): |
|||
... pulse(led, 20) |
|||
|
|||
Remember you can use ctrl-C to interrupt the code. |
|||
|
|||
Control a hobby servo |
|||
--------------------- |
|||
|
|||
Hobby servo motors can be controlled using PWM. They require a frequency of |
|||
50Hz and then a duty between about 40 and 115, with 77 being the centre value. |
|||
If you connect a servo to the power and ground pins, and then the signal line |
|||
to pin 12 (other pins will work just as well), you can control the motor using:: |
|||
|
|||
>>> servo = machine.PWM(machine.Pin(12), freq=50) |
|||
>>> servo.duty(40) |
|||
>>> servo.duty(115) |
|||
>>> servo.duty(77) |
@ -0,0 +1,205 @@ |
|||
Getting a MicroPython REPL prompt |
|||
================================= |
|||
|
|||
REPL stands for Read Evaluate Print Loop, and is the name given to the |
|||
interactive MicroPython prompt that you can access on the ESP8266. Using the |
|||
REPL is by far the easiest way to test out your code and run commands. |
|||
|
|||
There are two ways to access the REPL: either via a wired connection through the |
|||
UART serial port, or via WiFi. |
|||
|
|||
REPL over the serial port |
|||
------------------------- |
|||
|
|||
The REPL is always available on the UART0 serial peripheral, which is connected |
|||
to the pins GPIO1 for TX and GPIO3 for RX. The baudrate of the REPL is 115200. |
|||
If your board has a USB-serial convertor on it then you should be able to access |
|||
the REPL directly from your PC. Otherwise you will need to have a way of |
|||
communicating with the UART. |
|||
|
|||
To access the prompt over USB-serial you need to use a terminal emulator program. |
|||
On Windows TeraTerm is a good choice, on Mac you can use the built-in screen |
|||
program, and Linux has picocom and minicom. Of course, there are many other |
|||
terminal programs that will work, so pick your favourite! |
|||
|
|||
For example, on Linux you can try running:: |
|||
|
|||
picocom /dev/ttyUSB0 |
|||
|
|||
Once you have made the connection over the serial port you can test if it is |
|||
working by hitting enter a few times. You should see the Python REPL prompt, |
|||
indicated by ``>>>``. |
|||
|
|||
WebREPL - a prompt over WiFi |
|||
---------------------------- |
|||
|
|||
WebREPL allows you to use the Python prompt over WiFi, connecting through a |
|||
browser. |
|||
|
|||
The first thing you need to do is get the WebREPL client loaded in your |
|||
favourite browser. The client can be found in the GitHub repository |
|||
`<https://github.com/micropython/webrepl>`__ . It is called webrepl.html. |
|||
The latest versions of Firefox and Chrome are supported. |
|||
|
|||
To use WebREPL connect your computer to the ESP8266's access point |
|||
(MicroPython-xxxxxx, see the previous section about this). If you have |
|||
already reconfigured your ESP8266 to connect to a router then you can |
|||
skip this part. |
|||
|
|||
Once you are on the same network as the ESP8266 you should then open |
|||
open webrepl.html in your browser and click the "Connect" button (if |
|||
you are connecting via a router then you may need to change the IP address, |
|||
by default the IP address is correct when connected to the ESP8266's access |
|||
point). If the connection succeeds then you should see a welcome message. |
|||
|
|||
On the first connection you need to set a password. Make sure that the |
|||
terminal widget is selected by clicking on it, and then type it your password |
|||
twice (they should match each other). Then ESP8266 will then reboot with |
|||
the password applied (the WiFi will go down but come back up again). |
|||
|
|||
You should then click the "Connect" button again, and enter your password |
|||
to connect. If you type in the correct password you should get a prompt |
|||
looking like ``>>>``. You can now start typing Python commands! |
|||
|
|||
Using the REPL |
|||
-------------- |
|||
|
|||
Once you have a prompt you can start experimenting! Anything you type at the |
|||
prompt will be executed after you press the Enter key. MicroPython will run |
|||
the code that you enter and print the result (if there is one). If there is an |
|||
error with the text that you enter then an error message is printed. |
|||
|
|||
Try typing the following at the prompt:: |
|||
|
|||
>>> print('hello esp8266!') |
|||
hello esp8266! |
|||
|
|||
Note that you shouldn't type the ``>>>`` arrows, they are there to indicate that |
|||
you should type the text after it at the prompt. And then the line following is |
|||
what the device should respond with. In the end, once you have entered the text |
|||
``print("hello esp8266!")`` and pressed the Enter key, the output on your screen |
|||
should look exactly like it does above. |
|||
|
|||
If you already know some python you can now try some basic commands here. For |
|||
example:: |
|||
|
|||
>>> 1 + 2 |
|||
3 |
|||
>>> 1 / 2 |
|||
0.5 |
|||
>>> 12**34 |
|||
4922235242952026704037113243122008064 |
|||
|
|||
If your board has an LED attached to GPIO2 (the ESP-12 modules do) then you can |
|||
turn it on and off using the following code:: |
|||
|
|||
>>> import machine |
|||
>>> pin = machine.Pin(2, machine.Pin.OUT) |
|||
>>> pin.high() |
|||
>>> pin.low() |
|||
|
|||
Note that ``high`` might turn the LED off and ``low`` might turn it on (or vice |
|||
versa), depending on how the LED is wired on your board. |
|||
|
|||
Line editing |
|||
~~~~~~~~~~~~ |
|||
|
|||
You can edit the current line that you are entering using the left and right |
|||
arrow keys to move the cursor, as well as the delete and backspace keys. Also, |
|||
pressing Home or ctrl-A moves the cursor to the start of the line, and pressing |
|||
End or ctrl-E moves to the end of the line. |
|||
|
|||
Input history |
|||
~~~~~~~~~~~~~ |
|||
|
|||
The REPL remembers a certain number of previous lines of text that you entered |
|||
(up to 8 on the ESP8266). To recall previous lines use the up and down arrow |
|||
keys. |
|||
|
|||
Tab completion |
|||
~~~~~~~~~~~~~~ |
|||
|
|||
Pressing the Tab key will do an auto-completion of the current word that you are |
|||
entering. This can be very useful to find out functions and methods that a |
|||
module or object has. Try it out by typing "ma" and then pressing Tab. It |
|||
should complete to "machine" (assuming you imported machine in the above |
|||
example). Then type "." and press Tab again to see a list of all the functions |
|||
that the machine module has. |
|||
|
|||
Line continuation and auto-indent |
|||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|||
|
|||
Certain things that you type will need "continuing", that is, will need more |
|||
lines of text to make a proper Python statement. In this case the prompt will |
|||
change to ``...`` and the cursor will auto-indent the correct amount so you can |
|||
start typing the next line straight away. Try this by defining the following |
|||
function:: |
|||
|
|||
>>> def toggle(p): |
|||
... p.value(not p.value()) |
|||
... |
|||
... |
|||
... |
|||
>>> |
|||
|
|||
In the above, you needed to press the Enter key three times in a row to finish |
|||
the compound statement (that's the three lines with just dots on them). The |
|||
other way to finish a compound statement is to press backspace to get to the |
|||
start of the line, then press the Enter key. (If you did something wrong and |
|||
want to escape the continuation mode then press ctrl-C; all lines will be |
|||
ignored.) |
|||
|
|||
The function you just defined allows you to toggle a pin. The pin object you |
|||
created earlier should still exist (recreate it if it doesn't) and you can |
|||
toggle the LED using:: |
|||
|
|||
>>> toggle(pin) |
|||
|
|||
Let's now toggle the LED in a loop (if you don't have an LED then you can just |
|||
print some text instead of calling toggle, to see the effect):: |
|||
|
|||
>>> import time |
|||
>>> while True: |
|||
... toggle(pin) |
|||
... time.sleep_ms(500) |
|||
... |
|||
... |
|||
... |
|||
>>> |
|||
|
|||
This will toggle the LED at 1Hz (half a second on, half a second off). To stop |
|||
the toggling press ctrl-C, which will raise a KeyboardInterrupt exception and |
|||
break out of the loop. |
|||
|
|||
The time module provides some useful functions for making delays and doing |
|||
timing. Use tab completion to find out what they are and play around with them! |
|||
|
|||
Paste mode |
|||
~~~~~~~~~~ |
|||
|
|||
Pressing ctrl-E will enter a special paste mode. This allows you to copy and |
|||
paste a chunk of text into the REPL. If you press ctrl-E you will see the |
|||
paste-mode prompt:: |
|||
|
|||
paste mode; Ctrl-C to cancel, Ctrl-D to finish |
|||
=== |
|||
|
|||
You can then paste (or type) your text in. Note that none of the special keys |
|||
or commands work in paste mode (eg Tab or backspace), they are just accepted |
|||
as-is. Press ctrl-D to finish entering the text and execute it. |
|||
|
|||
Other control commands |
|||
~~~~~~~~~~~~~~~~~~~~~~ |
|||
|
|||
There are four other control commands: |
|||
|
|||
* Ctrl-A on a blank line will enter raw REPL mode. This is like a permanent |
|||
paste mode, except that characters are not echoed back. |
|||
|
|||
* Ctrl-B on a blank like goes to normal REPL mode. |
|||
|
|||
* Ctrl-C cancels any input, or interrupts the currently running code. |
|||
|
|||
* Ctrl-D on a blank line will do a soft reset. |
|||
|
|||
Note that ctrl-A and ctrl-D do not work with WebREPL. |
Loading…
Reference in new issue