网站首页 > 编程文章 正文
ESP8266的资源非常有限(比如RAM内存)。因此请避免分配太大的容器对象(列表,字典)和缓冲区。
ESP8266也没完整的操作系统来跟踪资源并自动清理它们,所以请务必在使用后尽快关闭打开的文件、套接字等。
boot过程
启动时,MicroPython EPS8266在FlashROM中安装文件系统,执行_boot.py脚本,如果FlashROM不可用,则执行模块的首次安装并创建文件系统。该引导过程不能供普通用户定制。
一旦安装了文件系统,就执行boot.py。boot.py是在第一次设置模块时创建的,并具有启动WebREPL等守护进程的命令(默认禁用,可通过webrepl_setup模块进行配置),对boot.py文件的修改应该谨慎。
引导过程的最后一步,如果存在main.py,则从文件系统执行。这个文件是一个钩子,用于在每次引导时启动用户应用程序(而不是转到REPL)。对于小型测试应用程序,可以直接将它们命名为main.py,反之,建议将应用程序保存在单独的文件中,并在main.py中引入(import)使用。
已知问题
实时时钟(RTC):
- ESP8266中的RTC精度很差,误差可能是秒/分钟。为了测量足够短的时间间隔,可以使用time.time()等函数,还可以使用附带的ntptime.py模块从网络同步时间。
- 由于ESP8266芯片的限制,内部实时时钟(RTC)将每7:45小时溢出一次。如果需要长期工作的RTC时间,则必须在7小时内至少调用time()或localtime()一次,MicroPython将处理溢出。
同时操作STA_IF和AP_IF
- 支持STA_IF和AP_IF接口同时操作。但是,由于硬件的限制,如果STA_IF没有连接和搜索到AP,AP_IF中可能存在性能问题。可以在只使用AP_IF的环境中禁用STA_IF。
socket和WiFi缓冲区溢出
- 套接字实例在显式关闭之前一直保持活动状态,这有两个问题。首先,它们会占用RAM,因此打开套接字而不关闭它们的应用程序最终可能会耗尽内存。其次,没有正确关闭socket会导致供应商WiFi堆栈的底层部分发出Lmac错误。如果数据进入套接字,但没有及时处理,就会发生这种情况。这可能会溢出WiFi堆栈输入队列并导致死锁,解锁的唯一方法是硬复位。
- 上述情况也可能发生在应用程序因任何原因(包括异常)终止并退出REPL之后。随后的数据到达会触发失败,并重复发出上述错误消息。因此,套接字在任何情况下都应该关闭,无论应用程序是否成功终止或通过异常终止,例如使用try/finally:
sock = socket(...)
try:
# Use sock
finally:
sock.close()
SSL / TLS的局限性
ESP8266使用axTLS库,这是具有兼容许可的最小TLS库之一。然而,它也有一些已知的问题/限制:
- 不支持DH (Diffie-Hellman)密钥交换和ECC (Elliptic-curve cryptography)。这意味着它不能与需要使用这些功能的站点一起工作(它可以与使用RSA证书的典型站点一起工作)。
- 半双工通信性质。axTLS在发送和接收时都使用一个缓冲区,这样可以节省大量内存,并且可以很好地与HTTP等协议一起工作。但是,不遵循经典请求-响应模型的协议可能存在问题。
除了axTLS自身的限制外,MicroPython使用的配置还针对代码大小进行了高度优化,这导致了额外的限制(这些限制在未来可能会被取消):
- 未启用优化的RSA算法,可能导致SSL握手速度变慢。
- 没有启用会话重用,这意味着每个连接都必须经历完整的、昂贵的SSL握手。
除了上面描述的axTLS特定限制外,在低内存设备上使用TLS还有另一个一般限制:
- TLS标准指定TLS记录(TLS通信的单位,整个记录必须在处理之前被缓冲)的最大长度为16KB。这几乎是可用ESP8266内存的一半,在一个或多或少高级的应用程序中,由于内存碎片问题,很难分配内存。折衷的办法是使用更小的缓冲区,因为SSL最有意思的用法是访问各种REST api,这通常需要更小的消息。缓冲区大小约为5KB,并不时进行调整,以作为参考
在MicroPython基于axTLS的ssl模块中,还有一些没有具体实现的特性:
- 证书没有经过验证(这使得连接容易受到中间人攻击)。
- 不支持客户端证书(计划在1.9.4发行版中修复)。
在ESP8266上使用mircoPython
烧录mircopython
- 固件下载:http://micropython.org/download#esp8266
- 使用esptool工具,需要使用pip或者下载:http://micropython.org/download#esp8266\
pip install esptool
esptool.py --port /dev/ttyUSB0 erase_flash
esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=detect 0 esp8266-20170108-v1.8.7.bin
- 验证固件
import esp
esp.check_fw()
串口提示
- 一旦设备有了固件,就可以通过UART0 (GPIO1=TX, GPIO3=RX)访问REPL (Python提示符)。
- 波特率为115200。
Wifi
- 在安装好固件并启动后,设备将自己配置为可以连接的WiFi接入点(AP)。
- ESSID的形式是MicroPython-xxxxxx,其中x被替换为设备MAC地址的一部分
- WiFi的密码是micropythoN(注意大写N)。
- ESP8266的IP地址是192.168.4.1。
REPL
- REPL:Read Evaluate Print Loop
- 有两种方式访问REPL:
通过UART串口的有线连接
- REPL在UART0串行外设上始终可用,GPIO1用于TX的引脚和GPIO3用于RX引脚。
- REPL的波特率为115200
- 终端程序:thonny,picocom/mincom(linux)
picocom /dev/ttyUSB0 -b115200
通过WiFi使用WebREPL
import webrepl_setup
- 在连接到WebREPL之前,需要先通过正常的串行连接启用并设置一个密码。
REPL使用
- 行编辑Ctrl+A,HomeCtrl+E, End
- 输入历史:ESP8266为8条历史记录
- Tab自动补齐自动补齐模块查看模块功能,模块名称+".",tab键。
- 黏贴模式:ctrl + E
其他控制命令
- 在空行上按Ctrl-A将进入原始REPL模式。这类似于永久粘贴模式,只是字符不会回显。
- 在空白的地方按Ctrl-B进入正常的REPL模式。
- Ctrl-C取消任何输入,或中断当前运行的代码。
- 在空行上按Ctrl-D将进行软重置。
文件系统
如果设备有1Mbyte或更多的存储空间,那么将被设置(在第一次引导时)包含一个文件系统。该文件系统使用FAT格式,存储在MicroPython固件之后的闪存中。
创建和读取文件:支持使用内置open()函数。
- 默认文件打开为只读模式
f = open('data.txt')
f.read()
'some data'
f.close()
- w:指定打开为可写模式
f = open('data.txt', 'w')
f.write('some data')
9
f.close()
- wb:二进制写入模式
- rb:二进制读取模式
列出文件:使用os模块
import os
os.listdir()
['boot.py', 'port_config.py', 'data.txt']
os.mkdir('dir')
os.remove('data.txt')
启动脚本
- Boot.py:最先执行,执行一次
- Main.py
网络基础
网络模块用于配置WiFi连接。有两个WiFi接口,一个用于工作站(当ESP8266连接到路由器时),另一个用于接入点(用于其他设备连接到ESP8266)。
import network
sta_if = network.WLAN(network.STA_IF)
ap_if = network.WLAN(network.AP_IF)
# 检查网络是否连接
sta_if.active()
False
ap_if.active()
True
# 查看网络信息
ap_if.ifconfig()
('192.168.4.1', '255.255.255.0', '192.168.4.1', '8.8.8.8')
对于新的ESP8266,默认配置为接入点模式,因此AP_IF接口是活动的,STA_IF接口是不活动的。可以将模块配置为使用STA_IF接口连接到现有网络。
# 激活sta模式
sta_if.active(True)
# 配置ssid和密码连接网络
sta_if.connect('<your SSID>', '<your key>')
# 验证网络是否正常连接
sta_if.isconnected()
# 查看网络信息
sta_if.ifconfig()
('192.168.0.2', '255.255.255.0', '192.168.0.1', '8.8.8.8')
# 可根据需要选择是否关闭AP模式
ap_if.active(False)
- 自动连接wifi网络配置脚本,可存放与boot.py文件,启动即执行。
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('<ssid>', '<key>')
while not sta_if.isconnected():
pass
print('network config:', sta_if.ifconfig())
TCP套接字
大多数互联网的构建块是TCP套接字。这些套接字在连接的网络设备之间提供可靠的字节流。
- 从网上下载数据
# 导入模块
import socket
# 获取服务器的IP地址:
addr_info = socket.getaddrinfo("towel.blinkenlights.nl", 23)
# getaddrinfo函数实际上返回一个地址列表,可选择第一个可用地址和端口
addr = addr_info[0][-1]
# 使用IP地址创建一个套接字并连接到服务器
s = socket.socket()
s.connect(addr)
# 下载并显示数据
while True:
data = s.recv(500)
print(str(data, 'utf8'), end='')
- 如何下载网页。HTTP使用端口80,首先需要发送一个“GET”请求,指定要检索的页面。
# 定义函数
def http_get(url):
import socket
_, _, 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
s.close()
# 执行函数
http_get('http://micropython.org/ks/test.html')
- 简易HTTP服务器
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('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n')
cl.send(response)
cl.close()
GPIO引脚
不是所有引脚都是可用的,只有0, 2, 4, 5, 12, 13, 14, 15和16能够使用,GPIO16没有上拉模式。
# 导入machine模块
import machine
# 配置引脚输入或输出,以及是否开启内部上拉电阻(默认None)
pin = machine.Pin(0)
pin = machine.Pin(0, machine.Pin.IN, machine.Pin.PULL_UP)
# 读取引脚状态
pin.value()
0
# 设置引脚
pin = machine.Pin(0, machine.Pin.OUT)
pin.value(0)
pin.value(1)
pin.off()
pin.on()
外部中断:
除16引脚之外的所有引脚都可以配置为在输入改变时触发硬件中断,并可以设置要在触发器上执行的代码(回调函数)。
# 定义回调函数,用于处理中断事件
def callback(p):
... print('pin change', p)
# 配置引脚
from machine import Pin
p0 = Pin(0, Pin.IN)
p2 = Pin(2, Pin.IN)
# 引脚0设置为仅在输入的下降沿上触发(当它从高到低时)
p0.irq(trigger=Pin.IRQ_FALLING, handler=callback)
# 引脚2设置为在上升沿和下降沿上触发
p2.irq(trigger=Pin.IRQ_RISING | Pin.IRQ_FALLING, handler=callback)
# 可以将高电压和低电压应用到引脚0和2,以查看正在执行的中断。
- 触发中断事件并调用回调函数进行处理
- 硬件中断在事件发生时立即触发,并将中断任何正在运行的代码,包括Python代码。因此,回调函数所能做的事情是有限的(例如,它们不能分配内存),并且应该尽可能的简短。
PWM:Pulse Width Modulation,脉冲宽度调制脉宽调制
(PWM)是一种在数字引脚上获得人工模拟输出的方法。它通过快速切换引脚电压从低到高来实现这一点。
有两个参数与此相关:切换频率和占空比。占空比定义为高电压与单个周期(低时间加高时间)的长度比。最大占空比是指引脚一直为高电压,最小占空比是指引脚一直低电压。
在ESP8266上,引脚0、2、4、5、12、13、14和15都支持PWM。限制是这些引脚必须处于相同的频率,并且频率必须在1Hz和1kHz之间。创建引脚对象
# 创建PWM对象
import machine
p12 = machine.Pin(12)
pwm12 = machine.PWM(p12)
# 设置频率和占空比
pwm12.freq(500)
pwm12.duty(512)
# 注意,占空比在0(全关)和1023(全开)之间,512是50%的占空比。
# 超过这个最小/最大值的值将被剪切。打印PWM对象,
# 可查看当前配置
pwm12
PWM(12, freq=500, duty=512)
# 还可以调用不带参数的freq()和duty()方法来获取当前配置值。
# 引脚将保持在PWM模式,直到去初始化:
pwm12.deinit()
渐变(fade)LED
# 创建pwm引脚对象,并设置频率
led = machine.PWM(machine.Pin(2), freq=1000)
# 创建调制函数
import time, math
def pulse(l, t):
for i in range(20):
l.duty(int(math.sin(i / 10 * math.pi) * 500 + 500))
time.sleep_ms(t)
# 调用
for i in range(10):
pulse(led, 20)
控制舵机
- 伺服电机可以使用PWM控制。要求频率为50Hz,占空比在40到115之间,以77为中心值。
servo = machine.PWM(machine.Pin(12), freq=50)
servo.duty(40)
servo.duty(115)
servo.duty(77)
ADC
ESP8266有一个单独引脚(与GPIO引脚分开),可用于读取模拟电压并将其转换为数字值。
# 创建ADC对象
import machine
adc = machine.ADC(0)
# 读取值
adc.read()
58
- read()函数返回的值介于0(0.0伏)和1024(1.0伏)之间。请注意,此输入只能容忍最大1.0伏,必须使用分压器电路来测量更大的电压。
电源(功耗)控制
- 动态改变CPU频率获取当前CPU频率
import machine
machine.freq()
80000000
- 修改CPU频率为160MHz,可以在执行繁重的任务时更改为较高的频率,在完成处理时再更改回来用以控制功耗。
machine.freq(160000000)
machine.freq()
160000000
- 深度睡眠状态深度睡眠模式将关闭ESP8266及其所有外设,包括WiFi(但不包括用于唤醒芯片的实时时钟),能够有效降低电流消耗。为了使用深度睡眠功能,必须将GPIO16连接到复位引脚(RST)。
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()
- 注意,当芯片从深度睡眠中醒来时,它将被完全重置,包括所有的内存,boot脚本将照常运行。可以boot脚本其中放入代码以检查重置原因
if machine.reset_cause() == machine.DEEPSLEEP_RESET:
print('woke from a deep sleep')
else:
print('power on or hard reset')
控制DS18B20(1-wire)
1-wire总线是一种串行总线,它只使用一根线进行通信(除了地线和电源线)。DS18B20温度传感器是一种非常流行的单总线元件。将数据线连接到GPIO12,并在数据引脚和电源引脚之间连接一个4.7k欧姆电阻。
import time
import machine
import onewire, ds18x20
# the device is on GPIO12
dat = machine.Pin(12)
# create the onewire object
ds = ds18x20.DS18X20(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()
- 注意,必须执行convert_temp()函数来初始化温度读数,然后至少等待750ms才能读取该值。
控制NeoPixels(WS2812LEDs)
NeoPixels,也称为WS2812 led,是串行全彩led,可单独寻址,其红色、绿色和蓝色设置在0到255之间。创建NeoPixels对象(在GPIO4上配置一个8像素的NeoPixel灯条)
import machine, neopixel
# 定义在GPIO4上配置一个8像素的NeoPixel条带
np = neopixel.NeoPixel(machine.Pin(4), 8)
# 设置各像素的颜色
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
# 对于超过3种颜色的led,例如RGBW像素或RGBY像素,NeoPixel类采用bpp参数。
import machine, neopixel
np = neopixel.NeoPixel(machine.Pin(4), 8, bpp=4)
# 在4-bpp模式下,记得使用4元组而不是3元组来设置颜色。
np[0] = (255, 0, 0, 128) # Orange in an RGBY Setup
np[1] = (0, 255, 0, 128) # Yellow-green in an RGBY Setup
np[2] = (0, 0, 255, 128) # Green-blue in an RGBY Setup
# 使用write()方法将颜色输出到led
np.write()
# 示例
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()
# 执行示例
demo(np)
控制APA102 LEDs
- APA102 led,也称为DotStar led,是可单独寻址的全彩RGB led,通常以串形形式。与NeoPixels的不同之处在于,需要两个引脚来控制——一个时钟引脚和一个数据引脚。可以在比NeoPixels更高的数据和PWM频率下工作,并且更适合于视觉持久效果。创建APA102对象:配置一个60像素的APA102条带,时钟引脚GPIO5,数据引脚GPIO4。
import machine, apa102
strip = apa102.APA102(machine.Pin(5), machine.Pin(4), 60)
- RGB颜色数据,以及亮度等级,以一定的顺序被发送到APA102。通常是(红,绿,蓝,亮度)。如果使用的是较新的ap102c led,绿色和蓝色顺序交换(红,蓝,绿,亮度)。如果希望以RGB顺序提供颜色,而不是RBG,可以自定义元组颜色顺序:
# 自定义元组颜色顺序
strip.ORDER = (0, 2, 1, 3)
# 设置像素颜色
strip[0] = (255, 255, 255, 31) # set to white, full brightness
strip[1] = (255, 0, 0, 31) # set to red, full brightness
strip[2] = (0, 255, 0, 15) # set to green, half brightness
strip[3] = (0, 0, 255, 7) # set to blue, quarter brightness
# 使用write()方法将颜色输出到led
strip.write()
- 示例
import time
import machine, apa102
# 1M strip with 60 LEDs
strip = apa102.APA102(machine.Pin(5), machine.Pin(4), 60)
brightness = 1 # 0 is off, 1 is dim, 31 is max
# Helper for converting 0-255 offset to a colour tuple
def wheel(offset, brightness):
# The colours are a transition r - g - b - back to r
offset = 255 - offset
if offset < 85:
return (255 - offset * 3, 0, offset * 3, brightness)
if offset < 170:
offset -= 85
return (0, offset * 3, 255 - offset * 3, brightness)
offset -= 170
return (offset * 3, 255 - offset * 3, 0, brightness)
# Demo 1: RGB RGB RGB
red = 0xff0000
green = red >> 8
blue = red >> 16
for i in range(strip.n):
colour = red >> (i % 3) * 8
strip[i] = ((colour & red) >> 16, (colour & green) >> 8, (colour & blue), brightness)
strip.write()
# Demo 2: Show all colours of the rainbow
for i in range(strip.n):
strip[i] = wheel((i * 256 // strip.n) % 255, brightness)
strip.write()
# Demo 3: Fade all pixels together through rainbow colours, offset each pixel
for r in range(5):
for n in range(256):
for i in range(strip.n):
strip[i] = wheel(((i * 256 // strip.n) + n) & 255, brightness)
strip.write()
time.sleep_ms(25)
# Demo 4: Same colour, different brightness levels
for b in range(31,-1,-1):
strip[0] = (255, 153, 0, b)
strip.write()
time.sleep_ms(250)
# End: Turn off all the LEDs
strip.fill((0, 0, 0, 0))
strip.write()
使用温湿度传感器DHT11
DHT(Digital Humidity & Temperature)数字温湿度传感器是低成本的数字传感器,带有电容式湿度传感器和热敏电阻,其芯片能够将模拟信号转换为数字,并提供单总线接口(或I2C接口)。
DHT11(蓝色)和DHT22(白色)传感器提供相同的1-wire接口,DHT22需要一个单独的对象,具有更复杂的计算。DHT22对湿度和温度读数都有1个小数位分辨率。DHT11则是整数。
自定义的1-wire协议(与Dallas 1-wire协议不同)用于从传感器获取测量数据。有效测量载荷由湿度值、温度值和校验和组成。使用1-wire接口,构造引用数据引脚对象
# DHT11
import dht
import machine
d = dht.DHT11(machine.Pin(4))
# DHT22
import dht
import machine
d = dht.DHT22(machine.Pin(4))
# 测量和读取
d.measure()
d.temperature()
d.humidity()
- temperature()返回的值是摄氏度,humidity()返回的值是相对湿度的百分比。
- DHT11每秒调用一次,DHT22每两秒调用一次。
在1-wire模式下,4个引脚中只有3个被使用,而在I2C模式下,所有4个引脚都被使用。旧的传感器可能仍然有4个引脚,即使它们不支持I2C,第三个引脚根本没有连接。
- 引脚配置传感器没有I2C工作在1-wire模式(例如;Dht11, dht22, am2301, am2302):1=VDD, 2=Data, 3=NC, 4=GND
- 传感器有I2C工作在1-wire模式(例如;Dht12, am2320, am2321, am2322):1=VDD, 2=Data, 3=GND, 4=GND
- 传感器有I2C工作在I2C模式(例如。Dht12, am2320, am2321, am2322):1=VDD, 2=SDA, 3=GND, 4=SCL
数据、SDA和SCL引脚应该使用上拉电阻。
要使较新的I2C传感器工作在向后兼容的1-wire模式,必须将3和4引脚连接到GND,用以禁用I2C接口。
DHT22传感器现在以AM2302的名称出售,在其他方面是相同的。
使用SSD1306 OLED
SSD1306 OLED显示器使用SPI或I2C接口,有多种尺寸(128x64, 128x32, 72x40, 64x48)和颜色(白色,黄色,蓝色,黄色+蓝色)。
- 硬件SPI接口:
from machine import Pin, SPI
import ssd1306
hspi = SPI(1) # sck=14 (scl), mosi=13 (sda), miso=12 (unused)
dc = Pin(4) # data/command
rst = Pin(5) # reset
cs = Pin(15) # chip select, some modules do not have a pin for this
display = ssd1306.SSD1306_SPI(128, 64, hspi, dc, rst, cs)
- 软件SPI接口:
from machine import Pin, SoftSPI
import ssd1306
spi = SoftSPI(baudrate=500000, polarity=1, phase=0, sck=Pin(14), mosi=Pin(13), miso=Pin(12))
dc = Pin(4) # data/command
rst = Pin(5) # reset
cs = Pin(15) # chip select, some modules do not have a pin for this
display = ssd1306.SSD1306_SPI(128, 64, spi, dc, rst, cs)
- I2C接口
from machine import Pin, I2C
import ssd1306
# using default address 0x3C
i2c = I2C(sda=Pin(4), scl=Pin(5))
display = ssd1306.SSD1306_I2C(128, 64, i2c)
- 在第一行打印Hello World:
display.text('Hello, World!', 0, 0, 1)
display.show()
- 基本功能
display.poweroff() # power off the display, pixels persist in memory
display.poweron() # power on the display, pixels redrawn
display.contrast(0) # dim
display.contrast(255) # bright
display.invert(1) # display inverted
display.invert(0) # display normal
display.rotate(True) # rotate 180 degrees
display.rotate(False) # rotate 0 degrees
display.show() # write the contents of the FrameBuffer to display memory
- 子类FrameBuffer提供了对基本图形的支持:
display.fill(0) # fill entire screen with colour=0
display.pixel(0, 10) # get pixel at x=0, y=10
display.pixel(0, 10, 1) # set pixel at x=0, y=10 to colour=1
display.hline(0, 8, 4, 1) # draw horizontal line x=0, y=8, width=4, colour=1
display.vline(0, 8, 4, 1) # draw vertical line x=0, y=8, height=4, colour=1
display.line(0, 0, 127, 63, 1) # draw a line from 0,0 to 127,63
display.rect(10, 10, 107, 43, 1) # draw a rectangle outline 10,10 to 117,53, colour=1
display.fill_rect(10, 10, 107, 43, 1) # draw a solid rectangle 10,10 to 117,53, colour=1
display.text('Hello World', 0, 0, 1) # draw some text at x=0, y=0, colour=1
display.scroll(20, 0) # scroll 20 pixels to the right
# draw another FrameBuffer on top of the current one at the given coordinates
import framebuf
fbuf = framebuf.FrameBuffer(bytearray(8 * 8 * 1), 8, 8, framebuf.MONO_VLSB)
fbuf.line(0, 0, 7, 7, 1)
display.blit(fbuf, 10, 10, 0) # draw on top at x=10, y=10, key=0
display.show()
- 示例:绘制MicroPython标志并显示一些文本信息:
display.fill(0)
display.fill_rect(0, 0, 32, 32, 1)
display.fill_rect(2, 2, 28, 28, 0)
display.vline(9, 8, 22, 1)
display.vline(16, 2, 22, 1)
display.vline(23, 8, 22, 1)
display.fill_rect(26, 24, 2, 4, 1)
display.text('MicroPython', 40, 0, 1)
display.text('SSD1306', 40, 12, 1)
display.text('OLED 128x64', 40, 24, 1)
display.show()
常用模块和功能参考
machine模块
import machine
machine.freq() # 获取CPU的当前频率
machine.freq(160000000) # 设置CPU频率为160 MHz
esp模块
import esp
esp.osdebug(None) # 关闭 O/S 调试信息
esp.osdebug(0) # 重定向 O/S 调试信息到 UART(0)
network模块
import network
# STA模式
wlan = network.WLAN(network.STA_IF) # 创建STA接口
wlan.active(True) # 激活接口
wlan.scan() # 扫描AP
wlan.isconnected() # 检查STA是否连接到AP
wlan.connect('ssid', 'key') # 指定SSID和密码连接AP
wlan.config('mac') # 获取接口MAC地址
wlan.ifconfig() # 获取接口网络信息,包括IP/netmask/gw/DNS
# AP模式
ap = network.WLAN(network.AP_IF) # 创建AP接口
ap.active(True) # 激活接口
ap.config(ssid='ESP-AP') # 设置AP的SSID
# STA模式网络连接函数
def do_connect():
import network
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if not wlan.isconnected():
print('connecting to network...')
wlan.connect('ssid', 'key')
while not wlan.isconnected():
pass
print('network config:', wlan.ifconfig())
time模块
import time
time.sleep(1) # 睡眠1秒
time.sleep_ms(500) # 睡眠500毫秒
time.sleep_us(10) # 睡眠10微秒
start = time.ticks_ms() # 获取毫秒计数器
delta = time.ticks_diff(time.ticks_ms(), start) # 计算时间差
timers:支持基于rtos的虚拟定时器。使用ID为-1的machine.Timer定时器类,周期单位为毫秒。
from machine import Timer
tim = Timer(-1)
tim.init(period=5000, mode=Timer.ONE_SHOT, callback=lambda t:print(1))
tim.init(period=2000, mode=Timer.PERIODIC, callback=lambda t:print(2))
Pins和GPIO:使用machin.Pin类
- 可用引脚为:0、1、2、3、4、5、12、13、14、15、16
- 注意,引脚(1)和引脚(3)分别是REPL UART的TX和RX
- Pin(16)是一个特殊的Pin(用于从深度睡眠模式唤醒),可能无法用于更高级别的类,如Neopixel。
- 高级抽象类machine.Signal用于翻转引脚电平,可用于低电平激活的LED。
from machine import Pin
p0 = Pin(0, Pin.OUT) # 定义GPIO0为输出引脚
p0.on() # 设置引脚为高电平
p0.off() # 设置引脚为低电平
p0.value(1) # 设置引脚为高电平
p2 = Pin(2, Pin.IN) # 定义GPIO2为输入引脚
print(p2.value()) # 获取引脚的电平,1为高电平,0为低电平
p4 = Pin(4, Pin.IN, Pin.PULL_UP) # 定义GPIO5为输入,并启用内部上拉电阻
p5 = Pin(5, Pin.OUT, value=1) # 定义GPIO5输出高电平
UART(串口总线):两个uart可用。
- UART0在引脚1 (TX)和3 (RX)上。UART0是双向的,默认情况下用于REPL
- UART1位于引脚2 (TX)和8 (RX)上,但引脚8用于连接闪存芯片,因此UART1仅为TX。
- 当UART0附加到REPL时,UART(0)上的所有传入字符都会直接进入stdin,因此uart.read()将总是返回None。
- 如果需要从UART(0)中读取字符,则使用sys.stdin.read(),同时它也用于REPL(或分离,读取,然后重新连接)。分离后,UART(0)可以用于其他目的。
from machine import UART
uart = UART(0, baudrate=9600)
uart.write('hello')
uart.read(5) # 读取最多5个字节
# 从REPL分离UART0
import os
os.dupterm(None, 1)
# 重新连接REPL
import os, machine
uart = machine.UART(0, 115200)
os.dupterm(uart, 1)
PWM(pulse width modulation):脉冲宽度调制
- PWM可以在除引脚(16)以外的所有引脚上启用。
- 所有通道都有一个单一频率,范围在1到1000之间(以Hz为单位)。
- 占空比介于0和1023之间。
from machine import Pin, PWM
pwm0 = PWM(Pin(0)) # 对指定引脚创建PWM对象
pwm0.freq() # 获取当前频率
pwm0.freq(1000) # 设置频率
pwm0.duty() # 获取当前占空比
pwm0.duty(200) # 设置占空比
pwm0.deinit() # 关闭引脚PWM功能
pwm2 = PWM(Pin(2), freq=500, duty=512) # 创建PWM对象并指定频率和占空比
ADC (analog to digital conversion):模数转换
- ADC在专用引脚上可用。
- 注意:ADC引脚上的输入电压必须在0v到1.0v之间。
from machine import ADC
adc = ADC(0) # 在ADC引脚创建ADC对象
adc.read() # 读取ADC的值,范围0-1024
软件SPI总线:
- 是通过软件实现的(bit-banging),可以在所有引脚上工作,并通过machine.SoftSPI类访问。
from machine import Pin, SoftSPI
# 在特定引脚构造SPI总线
# polarity参数标识SCK idle状态的电平
# phase=0 标识从SCK的第一个边沿开始采样 , phase=1标识从SCK的第二个边沿开始采样
spi = SoftSPI(baudrate=100000, polarity=1, phase=0, sck=Pin(0), mosi=Pin(2), miso=Pin(4))
spi.init(baudrate=200000) # 设置波特率
spi.read(10) # 从 MISO读取10字节
spi.read(10, 0xff) # 在MOSI上输出0xff同时读取10个字节
buf = bytearray(50) # 创建缓冲区
spi.readinto(buf) # 读入给定的缓冲区(buf前面只当为50个字节)
spi.readinto(buf, 0xff) # 读入给定的缓冲区,并在MOSI上输出0xff
spi.write(b'12345') # 在MOSI上写5个字节
buf = bytearray(4) # 创建缓冲区
spi.write_readinto(b'1234', buf) # 写入到MOSI,并从MISO读入缓冲区
spi.write_readinto(buf, buf) # 将buf写入MOSI,并将MISO读回buf
硬件SPI总线
- 硬件SPI速度更快(高达80Mhz),但只能在特定引脚上工作:MISO是GPIO12, MOSI是GPIO13, SCK是GPIO14。和软件SPI具有相同的方法,除了构造函数和init的引脚参数(因为它们是固定的):
from machine import Pin, SPI
hspi = SPI(1, baudrate=80000000, polarity=0, phase=0)
I2C总线
- I2C总线是软件实现的,可以在所有引脚上工作,并通过machine.I2C类(machine.SoftI2C的别名)访问
from machine import Pin, I2C
# 构造 I2C 总线
i2c = I2C(scl=Pin(5), sda=Pin(4), freq=100000)
i2c.readfrom(0x3a, 4) # 从地址为0x3a的外设读取4个字节
i2c.writeto(0x3a, '12') # 向地址为0x3a的外设写入“12”
buf = bytearray(10) # 创建10字节缓冲区
i2c.writeto(0x3a, buf) # 对指定的外设写入缓冲区的数据
RTC(Real time clock)实时时钟
- machine.RTC类方法中RTC.now(), RTC.irq(handler=*)(使用自定义处理程序),RTC.init()和RTC.deinit()目前不支持。
from machine import RTC
rtc = RTC()
rtc.datetime((2017, 8, 23, 1, 12, 48, 0, 0)) # 设置日期时间
rtc.datetime() # 获取日期时间
# 连接wifi,使用ntp同步时间
ntptime.settime() # 设置从远程服务器同步时间
rtc.datetime() # 获取 UTC日期时间
WDT(watchdog timer)看门狗
- machine.WDT
from machine import WDT
# 启用 WDT
wdt = WDT()
wdt.feed()
深度睡眠模式
- 将GPIO16连接到复位引脚(RST)。
import machine
# 配置使用RTC.ALARM0唤醒设备
rtc = machine.RTC()
rtc.irq(trigger=rtc.ALARM0, wake=machine.DEEPSLEEP)
# 检查设备是否是从深度睡眠模式唤醒
if machine.reset_cause() == machine.DEEPSLEEP_RESET:
print('woke from a deep sleep')
# 设置RTC.ALARM0 在10秒后唤醒设备
rtc.alarm(rtc.ALARM0, 10000)
# 使设备进入深度睡眠模式
machine.deepsleep()
单总线(OneWire)
- OneWire是软件实现的,可以在所有引脚上工作
from machine import Pin
import onewire
ow = onewire.OneWire(Pin(12)) # 在 GPIO12引脚创建单总线
ow.scan() # 返回单总线上连接的设备
ow.reset() # 重置总线
ow.readbyte() # 读取一个字节
ow.writebyte(0x12) # 向总线特定地址设备写入一个字节
ow.write('123') # 向总线写入字节
ow.select_rom(b'12345678') # 根据ROM代码选择特定的设备
- DS18S20和DS18B20设备驱动程序:确保数据线连接4.7k的上拉电阻注意,每次要对温度进行采样时都必须调用convert_temp()方法。
import time, ds18x20
ds = ds18x20.DS18X20(ow)
roms = ds.scan()
ds.convert_temp()
time.sleep_ms(750)
for rom in roms:
print(ds.read_temp(rom))
NeoPixel
- 默认情况下,NeoPixel被配置为控制更流行的800kHz设备。可以在构造NeoPixel对象时,通过传递timing=0,使用替代计时来控制其他(通常是400kHz)设备。
- NeoPixel的底层驱动,参见machine.bitstream。
from machine import Pin
from neopixel import NeoPixel
pin = Pin(0, Pin.OUT) # 设置GPIO0 输出到 NeoPixels
np = NeoPixel(pin, 8) # 在GPIO0上创建8灯珠的NeoPixel
np[0] = (255, 255, 255) # 设置第一个灯珠为白色
np.write() # 写入数据到所有灯珠
r, g, b = np[0] # 获取第一个灯珠的颜色
APA102
from machine import Pin
from apa102 import APA102
clock = Pin(14, Pin.OUT) # 设置 GPIO14 为时钟输出
data = Pin(13, Pin.OUT) # 设置 GPIO13 为数据输出
apa = APA102(clock, data, 8) # 创建8灯珠APA102
apa[0] = (255, 255, 255, 31) #设置第一个灯珠为白色,最大亮度为31
apa.write() # 写入数据到所有灯珠
r, g, b, brightness = apa[0] # 获取第一个灯珠的颜色
- APA102底层控制
import esp
esp.apa102_write(clock_pin, data_pin, rgbi_buf)
DHT
- DHT驱动是软件实现的,可以在所有引脚上工作:
import dht
import machine
d = dht.DHT11(machine.Pin(4))
d.measure()
d.temperature() # 摄氏度
d.humidity() # 湿度百分比
d = dht.DHT22(machine.Pin(4))
d.measure()
d.temperature() # 摄氏度
d.humidity() # 湿度百分比
SSD1306 OLED
from machine import Pin, I2C
import ssd1306
i2c = I2C(scl=Pin(5), sda=Pin(4), freq=100000)
display = ssd1306.SSD1306_I2C(128, 64, i2c)
display.text('Hello World', 0, 0, 1)
display.show()
WebREPL(web browser interactive prompt)
- 初始化webrepl配置
import webrepl_setup
- 如果未设置启动时自动启动,可手动启动
import webrepl
webrepl.start()
其他
猜你喜欢
- 2024-10-21 NodeMCU使用AiThinkerIDE_V0.5开发小记
- 2024-10-21 基于ESP8266的WIFI模块(含源代码)
- 2024-10-21 你家的智能咖啡机可被轻松黑掉,阻止办法只有拔插头
- 2024-10-21 ESP8266自动下载电路分析(esp8266下载接线)
- 2024-10-21 ESP8266 ADC – 使用 Arduino IDE 读取模拟值
- 2024-10-21 esphome安装过程图文记录(esp homekit)
- 2024-10-21 FireBeetle ESP8266,专为物联网设计的低功耗开发套件,开发必备
- 2024-10-21 可用作Zigbee路由器的Sonoff ZBBridge网关
- 2024-10-21 ESP8266 天气小工具 V2.0(esp8266 oled天气)
- 2024-10-21 在ESP8266和树莓派4开发板上使用Qoitech Otii开发工具入门
你 发表评论:
欢迎- 05-142014年最流行前端开发框架对比评测
- 05-14七爪源码:如何使用 Next.js 构建 Shopify 店面
- 05-14Web 前端怎样入门?
- 05-14我为什么不建议你使用框架
- 05-14推荐几个好用的React UI 框架
- 05-14PDFsharp:强大的 .NET 跨平台 PDF 处理库
- 05-14一组开源免费的Web动画图标,荐给需要的设计师和程序员
- 05-14salesforce 零基础学习(二十九)Record Types简单介绍
- 最近发表
- 标签列表
-
- spire.doc (59)
- system.data.oracleclient (61)
- 按键小精灵源码提取 (66)
- pyqt5designer教程 (65)
- 联想刷bios工具 (66)
- c#源码 (64)
- graphics.h头文件 (62)
- mysqldump下载 (66)
- sqljdbc4.jar下载 (56)
- libmp3lame (60)
- maven3.3.9 (63)
- 二调符号库 (57)
- 苹果ios字体下载 (56)
- git.exe下载 (68)
- diskgenius_winpe (72)
- pythoncrc16 (57)
- solidworks宏文件下载 (59)
- qt帮助文档中文版 (73)
- satacontroller (66)
- hgcad (64)
- bootimg.exe (69)
- android-gif-drawable (62)
- axure9元件库免费下载 (57)
- libmysqlclient.so.18 (58)
- springbootdemo (64)
本文暂时没有评论,来添加一个吧(●'◡'●)