micropython esp wifi 配置

wifimgr.py

import network
import socket
import ure
import time

ap_ssid = "WifiManager"
ap_password = "tayfunulu"
ap_authmode = 3  # WPA2

NETWORK_PROFILES = 'wifi.dat'

wlan_ap = network.WLAN(network.AP_IF)
wlan_sta = network.WLAN(network.STA_IF)

server_socket = None


def get_connection():
    """return a working WLAN(STA_IF) instance or None"""

    # First check if there already is any connection:
    if wlan_sta.isconnected():
        return wlan_sta

    connected = False
    try:
        # ESP connecting to WiFi takes time, wait a bit and try again:
        time.sleep(3)
        if wlan_sta.isconnected():
            return wlan_sta

        # Read known network profiles from file
        profiles = read_profiles()

        # Search WiFis in range
        wlan_sta.active(True)
        networks = wlan_sta.scan()

        AUTHMODE = {0: "open", 1: "WEP", 2: "WPA-PSK", 3: "WPA2-PSK", 4: "WPA/WPA2-PSK"}
        for ssid, bssid, channel, rssi, authmode, hidden in sorted(networks, key=lambda x: x[3], reverse=True):
            ssid = ssid.decode('utf-8')
            encrypted = authmode > 0
            print("ssid: %s chan: %d rssi: %d authmode: %s" % (ssid, channel, rssi, AUTHMODE.get(authmode, '?')))
            if encrypted:
                if ssid in profiles:
                    password = profiles[ssid]
                    connected = do_connect(ssid, password)
                else:
                    print("skipping unknown encrypted network")
            else:  # open
                connected = do_connect(ssid, None)
            if connected:
                break

    except OSError as e:
        print("exception", str(e))

    # start web server for connection manager:
    if not connected:
        connected = start()

    return wlan_sta if connected else None


def read_profiles():
    with open(NETWORK_PROFILES) as f:
        lines = f.readlines()
    profiles = {}
    for line in lines:
        ssid, password = line.strip("\n").split(";")
        profiles[ssid] = password
    return profiles


def write_profiles(profiles):
    lines = []
    for ssid, password in profiles.items():
        lines.append("%s;%s\n" % (ssid, password))
    with open(NETWORK_PROFILES, "w") as f:
        f.write(''.join(lines))


def do_connect(ssid, password):
    wlan_sta.active(True)
    if wlan_sta.isconnected():
        return None
    print('Trying to connect to %s...' % ssid)
    wlan_sta.connect(ssid, password)
    for retry in range(100):
        connected = wlan_sta.isconnected()
        if connected:
            break
        time.sleep(0.1)
        print('.', end='')
    if connected:
        print('\nConnected. Network config: ', wlan_sta.ifconfig())
    else:
        print('\nFailed. Not Connected to: ' + ssid)
    return connected


def send_header(client, status_code=200, content_length=None ):
    client.sendall("HTTP/1.0 {} OK\r\n".format(status_code))
    client.sendall("Content-Type: text/html\r\n")
    if content_length is not None:
      client.sendall("Content-Length: {}\r\n".format(content_length))
    client.sendall("\r\n")


def send_response(client, payload, status_code=200):
    content_length = len(payload)
    send_header(client, status_code, content_length)
    if content_length > 0:
        client.sendall(payload)
    client.close()


def handle_root(client):
    wlan_sta.active(True)
    ssids = sorted(ssid.decode('utf-8') for ssid, *_ in wlan_sta.scan())
    send_header(client)
    client.sendall("""\
        <html>
            <h1 style="color: #5e9ca0; text-align: center;">
                <span style="color: #ff0000;">
                    Wi-Fi Client Setup
                </span>
            </h1>
            <form action="configure" method="post">
                <table style="margin-left: auto; margin-right: auto;">
                    <tbody>
    """)
    while len(ssids):
        ssid = ssids.pop(0)
        client.sendall("""\
                        <tr>
                            <td colspan="2">
                                <input type="radio" name="ssid" value="{0}" />{0}
                            </td>
                        </tr>
        """.format(ssid))
    client.sendall("""\
                        <tr>
                            <td>Password:</td>
                            <td><input name="password" type="password" /></td>
                        </tr>
                    </tbody>
                </table>
                <p style="text-align: center;">
                    <input type="submit" value="Submit" />
                </p>
            </form>
            <p>&nbsp;</p>
            <hr />
            <h5>
                <span style="color: #ff0000;">
                    Your ssid and password information will be saved into the
                    "%(filename)s" file in your ESP module for future usage.
                    Be careful about security!
                </span>
            </h5>
            <hr />
            <h2 style="color: #2e6c80;">
                Some useful infos:
            </h2>
            <ul>
                <li>
                    Original code from <a href="https://github.com/cpopp/MicroPythonSamples"
                        target="_blank" rel="noopener">cpopp/MicroPythonSamples</a>.
                </li>
                <li>
                    This code available at <a href="https://github.com/tayfunulu/WiFiManager"
                        target="_blank" rel="noopener">tayfunulu/WiFiManager</a>.
                </li>
            </ul>
        </html>
    """ % dict(filename=NETWORK_PROFILES))
    client.close()


def handle_configure(client, request):
    match = ure.search("ssid=([^&]*)&password=(.*)", request)

    if match is None:
        send_response(client, "Parameters not found", status_code=400)
        return False
    # version 1.9 compatibility
    try:
        ssid = match.group(1).decode("utf-8").replace("%3F", "?").replace("%21", "!")
        password = match.group(2).decode("utf-8").replace("%3F", "?").replace("%21", "!")
    except Exception:
        ssid = match.group(1).replace("%3F", "?").replace("%21", "!")
        password = match.group(2).replace("%3F", "?").replace("%21", "!")

    if len(ssid) == 0:
        send_response(client, "SSID must be provided", status_code=400)
        return False

    if do_connect(ssid, password):
        response = """\
            <html>
                <center>
                    <br><br>
                    <h1 style="color: #5e9ca0; text-align: center;">
                        <span style="color: #ff0000;">
                            ESP successfully connected to WiFi network %(ssid)s.
                        </span>
                    </h1>
                    <br><br>
                </center>
            </html>
        """ % dict(ssid=ssid)
        send_response(client, response)
        try:
            profiles = read_profiles()
        except OSError:
            profiles = {}
        profiles[ssid] = password
        write_profiles(profiles)

        time.sleep(5)

        return True
    else:
        response = """\
            <html>
                <center>
                    <h1 style="color: #5e9ca0; text-align: center;">
                        <span style="color: #ff0000;">
                            ESP could not connect to WiFi network %(ssid)s.
                        </span>
                    </h1>
                    <br><br>
                    <form>
                        <input type="button" value="Go back!" onclick="history.back()"></input>
                    </form>
                </center>
            </html>
        """ % dict(ssid=ssid)
        send_response(client, response)
        return False


def handle_not_found(client, url):
    send_response(client, "Path not found: {}".format(url), status_code=404)


def stop():
    global server_socket

    if server_socket:
        server_socket.close()
        server_socket = None


def start(port=80):
    global server_socket

    addr = socket.getaddrinfo('0.0.0.0', port)[0][-1]

    stop()

    wlan_sta.active(True)
    wlan_ap.active(True)

    wlan_ap.config(essid=ap_ssid, password=ap_password, authmode=ap_authmode)

    server_socket = socket.socket()
    server_socket.bind(addr)
    server_socket.listen(1)

    print('Connect to WiFi ssid ' + ap_ssid + ', default password: ' + ap_password)
    print('and access the ESP via your favorite web browser at 192.168.4.1.')
    print('Listening on:', addr)

    while True:
        if wlan_sta.isconnected():
            return True

        client, addr = server_socket.accept()
        print('client connected from', addr)
        try:
            client.settimeout(5.0)

            request = b""
            try:
                while "\r\n\r\n" not in request:
                    request += client.recv(512)
            except OSError:
                pass

            print("Request is: {}".format(request))
            if "HTTP" not in request:  # skip invalid requests
                continue

            # version 1.9 compatibility
            try:
                url = ure.search("(?:GET|POST) /(.*?)(?:\\?.*?)? HTTP", request).group(1).decode("utf-8").rstrip("/")
            except Exception:
                url = ure.search("(?:GET|POST) /(.*?)(?:\\?.*?)? HTTP", request).group(1).rstrip("/")
            print("URL is {}".format(url))

            if url == "":
                handle_root(client)
            elif url == "configure":
                handle_configure(client, request)
            else:
                handle_not_found(client, url)

        finally:
            client.close()

main.py

import wifimgr


wlan = wifimgr.get_connection()
if wlan is None:
    print("Could not initialize the network connection.")
    while True:
        pass  # you shall not pass :D


# Main Code goes here, wlan is a working network.WLAN(STA_IF) instance.
print("ESP OK")

更新

import network
import socket
import ure
import time

ap_ssid = "upday"
ap_password = "12345678"
ap_authmode = 3  # WPA2

NETWORK_PROFILES = 'wifi.dat'

wlan_ap = network.WLAN(network.AP_IF)
wlan_sta = network.WLAN(network.STA_IF)

server_socket = None


def get_connection():
    """return a working WLAN(STA_IF) instance or None"""

    # First check if there already is any connection:
    if wlan_sta.isconnected():
        return wlan_sta

    connected = False
    try:
        # ESP connecting to WiFi takes time, wait a bit and try again:
        time.sleep(3)
        if wlan_sta.isconnected():
            return wlan_sta

        # Read known network profiles from file
        profiles = read_profiles()

        # Search WiFis in range
        wlan_sta.active(True)
        networks = wlan_sta.scan()

        AUTHMODE = {0: "open", 1: "WEP", 2: "WPA-PSK", 3: "WPA2-PSK", 4: "WPA/WPA2-PSK"}
        for ssid, bssid, channel, rssi, authmode, hidden in sorted(networks, key=lambda x: x[3], reverse=True):
            ssid = ssid.decode('utf-8')
            encrypted = authmode > 0
            print("ssid: %s chan: %d rssi: %d authmode: %s" % (ssid, channel, rssi, AUTHMODE.get(authmode, '?')))
            if encrypted:
                if ssid in profiles:
                    password = profiles[ssid]
                    connected = do_connect(ssid, password)
                else:
                    print("skipping unknown encrypted network")
            else:  # open
                connected = do_connect(ssid, None)
            if connected:
                break

    except OSError as e:
        print("exception", str(e))

    # start web server for connection manager:
    if not connected:
        connected = start()

    return wlan_sta if connected else None


def read_profiles():
    with open(NETWORK_PROFILES) as f:
        lines = f.readlines()
    profiles = {}
    for line in lines:
        ssid, password = line.strip("\n").split(";")
        profiles[ssid] = password
    return profiles


def write_profiles(profiles):
    lines = []
    for ssid, password in profiles.items():
        lines.append("%s;%s\n" % (ssid, password))
    with open(NETWORK_PROFILES, "w") as f:
        f.write(''.join(lines))


def do_connect(ssid, password):
    wlan_sta.active(True)
    if wlan_sta.isconnected():
        return None
    print('Trying to connect to %s...' % ssid)
    wlan_sta.connect(ssid, password)
    for retry in range(100):
        connected = wlan_sta.isconnected()
        if connected:
            break
        time.sleep(0.1)
        print('.', end='')
    if connected:
        print('\nConnected. Network config: ', wlan_sta.ifconfig())
    else:
        print('\nFailed. Not Connected to: ' + ssid)
    return connected


def send_header(client, status_code=200, content_length=None ):
    client.sendall("HTTP/1.0 {} OK\r\n".format(status_code))
    client.sendall("Content-Type: text/html\r\n")
    if content_length is not None:
      client.sendall("Content-Length: {}\r\n".format(content_length))
    client.sendall("\r\n")


def send_response(client, payload, status_code=200):
    content_length = len(payload)
    send_header(client, status_code, content_length)
    if content_length > 0:
        client.sendall(payload)
    client.close()


def handle_root(client):
    wlan_sta.active(True)
    ssids = sorted(ssid.decode('utf-8') for ssid, *_ in wlan_sta.scan())
    send_header(client)
    client.sendall("""\
        <html>
            <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
            <head>
            <h2 style="color: #5e9ca0; text-align: center;">
                <span style="color: #ff0000;">
                    请选择浇灌系统连接的wifi热点
                </span>
            </h2>
            <form action="configure" method="post">
                <table style="margin-left: auto; margin-right: auto;">
                    <tbody>
    """)
    while len(ssids):
        ssid = ssids.pop(0)
        client.sendall("""\
                        <tr>
                            <td colspan="2">
                                <input type="radio" name="ssid" value="{0}" />{0}
                            </td>
                        </tr>
        """.format(ssid))
    client.sendall("""\
                        <tr>
                            <td>密码:</td>
                            <td><input name="password" type="password" /></td>
                        </tr>
                    </tbody>
                </table>
                <p style="text-align: center;">
                    <input type="submit" value="提交" />
                </p>
            </form>
            <p>&nbsp;</p>
            <hr />
            <h4>
                <span style="color: #ff0000;">
                    设置成功后,请断开电源重新通电。
                </span>
            </h4>
            <hr />
            <h3 style="color: #2e6c80;">
                使用参考:
            </h3>
            <ul>
                <li>
                    请访问 <a href="https://up.day"
                        target="_blank" rel="noopener">up.day</a>.
                </li>
            </ul>
        </html>
    """ )
    client.close()


def handle_configure(client, request):
    match = ure.search("ssid=([^&]*)&password=(.*)", request)

    if match is None:
        send_response(client, "Parameters not found", status_code=400)
        return False
    # version 1.9 compatibility
    try:
        ssid = match.group(1).decode("utf-8").replace("%3F", "?").replace("%21", "!")
        password = match.group(2).decode("utf-8").replace("%3F", "?").replace("%21", "!")
    except Exception:
        ssid = match.group(1).replace("%3F", "?").replace("%21", "!")
        password = match.group(2).replace("%3F", "?").replace("%21", "!")

    if len(ssid) == 0:
        send_response(client, "SSID must be provided", status_code=400)
        return False

    if do_connect(ssid, password):
        response = """\
            <html>
            <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
            <head>
                <center>
                    <br><br>
                    <h1 style="color: #5e9ca0; text-align: center;">
                        <span style="color: #ff0000;">
                            成功连接到 WiFi 网络 %(ssid)s,请断电重启.
                        </span>
                    </h1>
                    <br><br>
                </center>
            </html>
        """ % dict(ssid=ssid)
        send_response(client, response)
        try:
            profiles = read_profiles()
        except OSError:
            profiles = {}
        profiles[ssid] = password
        write_profiles(profiles)

        time.sleep(5)

        return True
    else:
        response = """\
            <html>
                <center>
                    <h1 style="color: #5e9ca0; text-align: center;">
                        <span style="color: #ff0000;">
                            ESP could not connect to WiFi network %(ssid)s.
                        </span>
                    </h1>
                    <br><br>
                    <form>
                        <input type="button" value="Go back!" onclick="history.back()"></input>
                    </form>
                </center>
            </html>
        """ % dict(ssid=ssid)
        send_response(client, response)
        return False


def handle_not_found(client, url):
    send_response(client, "Path not found: {}".format(url), status_code=404)


def stop():
    global server_socket

    if server_socket:
        server_socket.close()
        server_socket = None


def start(port=80):
    global server_socket

    addr = socket.getaddrinfo('0.0.0.0', port)[0][-1]

    stop()

    wlan_sta.active(True)
    wlan_ap.active(True)

    wlan_ap.config(essid=ap_ssid, password=ap_password, authmode=ap_authmode)

    server_socket = socket.socket()
    server_socket.bind(addr)
    server_socket.listen(1)

    print('Connect to WiFi ssid ' + ap_ssid + ', default password: ' + ap_password)
    print('and access the ESP via your favorite web browser at 192.168.4.1.')
    print('Listening on:', addr)

    while True:
        if wlan_sta.isconnected():
            return True

        client, addr = server_socket.accept()
        print('client connected from', addr)
        try:
            client.settimeout(5.0)

            request = b""
            try:
                while "\r\n\r\n" not in request:
                    request += client.recv(512)
            except OSError:
                pass

            print("Request is: {}".format(request))
            if "HTTP" not in request:  # skip invalid requests
                continue

            # version 1.9 compatibility
            try:
                url = ure.search("(?:GET|POST) /(.*?)(?:\\?.*?)? HTTP", request).group(1).decode("utf-8").rstrip("/")
            except Exception:
                url = ure.search("(?:GET|POST) /(.*?)(?:\\?.*?)? HTTP", request).group(1).rstrip("/")
            print("URL is {}".format(url))

            if url == "":
                handle_root(client)
            elif url == "configure":
                handle_configure(client, request)
            else:
                handle_not_found(client, url)

        finally:
            client.close()


另一个详细参考

https://blog.csdn.net/weixin_37272286/article/details/116297086

编译esp32-c3的micropython固件

1.1.2. ESP-IDF开发环境

在linux子系统命令行模式下依次执行如下指令:

cd ~
git clone https://gitee.com/EspressifSystems/esp-gitee-tools.git
git clone https://gitee.com/EspressifSystems/esp-idf.git
ls

cd esp-idf
git checkout v4.4.1
cd ~/esp-gitee-tools
./submodule-update.sh ~/esp-idf/
./install.sh ~/esp-idf/

 . /home/peter/esp-idf/export.sh

idf.py build

cd ~/esp-idf/
source export.sh

cd ~
git clone https://gitee.com/CHN_ZC/micropython.git
sudo chmod a+rwx micropython
cd ~/micropython
make -C mpy-cross
cd ports/esp32
make submodules
make

1.1.4. 测试模块

Python文件模块放在esp32下的modules文件夹,进入该文件夹:

cd modules

新建一个测试用的python文件,如下:

nano test.py

文件内容如下:

from time import sleep
def hello():
    print("hello world")
def hw(str):
    print(str)
def cycle(str):
    while True:
        print(str)
        sleep(1)

保存后回到esp32目录,执行编译操作:

cd ~/micropython   #micropython根目录

make -C mpy-cross

cd ports/esp32/

  . /home/peter/esp-idf/export.sh

编译esp32c3固件

make clean

更改ports/esp32/Makefile文件

找到 BOARD ?= GENERIC
改为 BOARD ?= GENERIC_C3

或
BOARD ?= GENERIC_C3_USB

make

留意上面的三个文件及地址,分别是烧录文件及偏移地址。

注意:

严格按照执行后的提示执行一下,否则会导致环境变量等等没有设置,为后续编译带来很多麻烦

esptool安装方法

1. 下载 esptool.py 源码

git clone https://github.com/espressif/esptool.git

2. 目录导入到全局环境变量

以 ubuntu 为例:

将 export PATH=/home/chenwu/esp/esptool:$PATH 添加到 /etc/profile 文件结尾

执行 source /etc/profile

3.安装成功后通过 esptool.py version 查看版本:

注意: esptool.py v3.0 版本后,才对 ESP32-S 系列支持。

如果使用新款芯片,可以通过 git pull 来更新 esptool.py 版本。

关于luatos的esp32-c3的烧录注意事项(USB-JTAG)

1、按住rst键不放,再按住boot键不放,此时松开rst键

2、esptool.py –chip esp32c3 –port /dev/ttyACM1 erase_flash

3、正常烧录固件

4、按下rst键盘重启

5、正常使用

树莓派系列配置屏幕常亮、去掉启动滚动代码及彩虹画,增加开机动画

1 设置不黑屏不休眠
1.1 打开lightdm.conf
sudo nano /etc/lightdm/lightdm.conf
1.
1.2 修改lightdm.conf

找到 [SeatDefaults] 段下的 ’xserver-command=X’, 取消注释 , 修改为

xserver-command=X -s 0 -dpms

-s 设置屏幕保护不启用

dpms 关闭电源节能管理


1.3 重启使设置生效
sudo reboot
1.
2 屏蔽开机彩虹屏和文本,修改开机启动图片、设置开机动画
2.1 硬件环境

树莓派4B

系统:Linux raspberrypi 5.10.63-v7l+ #1496 SMP Wed Dec 1 15:58:56 GMT 2021 armv7l GNU/Linux

2.2 禁用彩虹屏
2.2.1 打开config.txt文件
sudo nano /boot/config.txt
1.
在末尾另起一行输入

disable_splash=1
1.
2.3 取消光标跳动和代码滚动
2.3.1 打开cmdline
sudo nano /boot/cmdline.txt
1.
2.3.2 添加如下命令
consoleblank=1 logo.nologo quiet loglevel=0 plymouth.enable=0 vt.global_cursor_default=0 plymouth.ignore-serial-consoles splash fastboot noatime nodiratime noram
1.
2.4 修改开机启动图片
默认的启动图片是树莓派标识,且树莓派的默认主题是pix(起码我的是这样,不清楚的可以自己查下设备的主题)。所以我的开机图片路径在/usr/share/plymouth/themes/pix/splash.png,把这张图片强覆盖即可。

2.5 添加开机动画
​ 使用开机动画,需要用的一个播放器​​omxplayer​​,自行安装

sudo apt-get update
sudo apt-get install omxplayer
1.
2.
2.5.1 打开rc.local文件
sudo nano /etc/rc.local
1.
2.5.2 在适当位置加入命令
omxplayer [动画文件.mov] &
1.
例如我的开机动画视频是logo.mov,放在/home/pi下,那么语句就是

登录后复制
omxplayer /home/pi/logo.mov &
1.


编译micropython-lvgl

屏和esp32引脚接线重新定义:

https://github.com/lvgl/lv_binding_micropython

去除Envo Storefront主题的底部版权信息

今天发现一个wordpress的主题不错,风格超赞,但底部的“自豪地采用wordprss及Envo Storefront”极其刺眼,到网上找了一圈,没有看到去除的方法,于是自己动手,发现这个主题厂家很鬼,将版权信息放在了一个特殊的地方,修改如下:

编译esp32-c3 lv-micropython固件

git clone -b v4.3.1 --recursive https://github.com/espressif/esp-idf.git

$ cd esp-idf
$ git checkout v4.3.1
$ git submodule update --init --recursive

$ cd esp-idf
$ ./install.sh       # (or install.bat on Windows)
$ source export.sh   # (or export.bat on Windows)

$ git clone https://github.com/lvgl/lv_micropython.git
$ cd ~/lv_micropython
$ git submodule update --init
$ cd lib/lv_bindings/
$ git submodule update --init
$ cd ~/lv_micropython/
$ make -C mpy-cross

对于编译过程中缺少的文件,find / -name xxxx,然后拷贝即可,估计是路径设置问题导致

编译esp32-c3 micropython lvgl

https://blog.csdn.net/qq_34440409/article/details/118365689

https://blog.csdn.net/wangyx1234/article/details/108554228

git clone https://github.com/lvgl/lv_micropython.git
cd lv_micropython
git submodule update --init
cd lib/lv_bindings/
git submodule update --init

编译mpy-cross工具:

cd ~/lv_micropython
make -C mpy-cross

编译unix端口的mpy:

make -C ports/unix/

编译好后测试下

./ports/unix/micropython

重新编译mpy:

cd lv_micropython/ports/unix
make clean
make -j

Demo测试

lvgl官方提供的测试例子在这个路径下:lib\lv_bindings\examples

可以用编译出来的micropython解释器去执行该目录下的测试脚本。

举个栗子:

打开/lib/lv_bindings/examples/advanced_demo.py文件,在末尾加入以下代码:

if __name__ == '__main__':
   import time
   while True:
      time.sleep(1)

执行

 ./ports/unix/micropython lib/lv_bindings/examples/advanced_demo.py

编译esp32-c3

make -C mpy-cross
make -C ports/esp32 LV_CFLAGS="-DLV_COLOR_DEPTH=16 -DLV_COLOR_16_SWAP=1" BOARD=GENERIC_SPIRAM deploy

https://github.com/lvgl/lv_micropython/blob/master/ports/esp32/README.md#setting-up-the-toolchain-and-esp-idf

MicroPython端口到ESP32

这是 MicroPython 到乐鑫 ESP32 系列微控制器的端口。它使用ESP-IDF框架,MicroPython在FreeRTOS下作为任务运行。

支持的功能包括:

  • REPL(Python prompt)over UART0。
  • MicroPython任务的16k堆栈和大约100k的Python堆。
  • 启用了MicroPython的许多功能:unicode,任意精度整数,单精度浮点数,复数,冻结字节码以及许多内部模块。
  • 使用闪存的内部文件系统(目前大小为2M)。
  • 机器模块带有GPIO,UART,SPI,软件I2C,ADC,DAC,PWM,触摸板,WDT和定时器。
  • 支持无线局域网 (WiFi) 的网络模块。
  • 通过蓝牙模块支持低功耗蓝牙 (BLE)。

该 ESP32 端口的初始开发部分由 Microbric Pty Ltd 赞助。

设置 ESP-IDF 和构建环境

ESP32 上的 MicroPython 需要乐鑫 IDF 版本 4(物联网开发框架,又名 SDK)。ESP-IDF 包括管理 ESP32 微控制器所需的库和 RTOS,以及管理构建固件所需的构建环境和工具链的方法。

ESP-IDF 变化很快,MicroPython 仅支持某些版本。目前,MicroPython 支持 v4.0.2、v4.1.1 和 v4.2,但其他 IDF v4 版本也可能有效。

要安装 ESP-IDF,可在乐鑫入门指南中找到完整说明。

如果您使用的是 Windows 机器,那么适用于 Linux 的 Windows 子系统是安装 ESP32 工具链和构建项目的最有效方法。如果您使用 WSL,请按照 Linux 说明而不是 Windows 说明进行操作。

乐鑫说明将指导您使用(或)脚本下载工具链并设置环境。要采取的步骤总结如下。install.shinstall.bat

要签出 IDF 的副本,请使用 git 克隆:

$ git clone -b v4.0.2 --recursive https://github.com/espressif/esp-idf.git

您可以替换为 或或任何其他受支持的版本。(您不需要完整的递归克隆;有关更详细的设置命令,请参阅此存储库中的函数。v4.0.2v4.1.1v4.2ci_esp32_setuptools/ci.sh

如果您已经拥有 IDF 的副本,请签出与 MicroPython 兼容的版本,并使用以下命令更新子模块:

$ cd esp-idf
$ git checkout v4.2
$ git submodule update --init --recursive

克隆 IDF 并将其签出为正确版本后,运行以下脚本:install.sh

$ cd esp-idf
$ ./install.sh       # (or install.bat on Windows)
$ source export.sh   # (or export.bat on Windows)

该步骤只需执行一次。您将需要为每个新会话提供源。install.shexport.sh

注意:如果您正在为 ESP32-S2、ESP32-C3 或 ESP32-S3 构建 MicroPython,请确保您使用的是以下必需的 IDF 版本:

  • ESP32-S3 目前需要最新的 ,但最终或更晚可用时需要。masterv4.4
  • ESP32-S2 和 ESP32-C3 需要或更高版本。v4.3.1

构建固件

必须构建MicroPython交叉编译器以将某些内置脚本预编译为字节码。这可以通过以下方式完成(从此存储库的根目录):

$ git clone https://github.com/lvgl/lv_micropython.git
$ cd lv_micropython
$ git submodule update --init
$ cd lib/lv_bindings/
$ git submodule update --init
$ cd ~/lv_micropython
$ make -C mpy-cross

然后为 ESP32 运行构建 MicroPython:

$ cd ports/esp32
$ make submodules
$ make

这将在子目录中生成一个组合映像(此固件映像由以下部分组成:引导加载程序.bin、分区.bin和 micropython.bin)。firmware.binbuild-GENERIC/

要刷新固件,您必须将 ESP32 模块置于引导加载程序模式并连接到 PC 上的串行端口。有关如何执行此操作,请参阅特定 ESP32 模块的文档。您还需要具有用户权限才能访问设备。在 Linux 上,您可以通过将用户添加到组,然后重新启动或注销并再次登录来启用此功能。(注意:在某些发行版上,这可能是组,请运行以检查。/dev/ttyUSB0dialoutuucpls -la /dev/ttyUSB0

$ sudo adduser <username> dialout

如果您是首次将MicroPython安装到您的模块中,或者在安装任何其他固件之后,您应该首先完全擦除闪存:

$ make erase

要将 MicroPython 固件刷新到 ESP32,请使用:

$ make deploy

由上述命令构建的默认 ESP32 开发板是该版本,它应该适用于大多数 ESP32 模块。您可以通过传递给 make 命令来指定不同的电路板,例如:GENERICBOARD=<board>

$ make BOARD=GENERIC_SPIRAM

注意:上述“make”命令是作为 ESP-IDF 一部分的基础构建工具的精简包装器。您可以改为直接使用,例如:idf.pyidf.py

$ idf.py build
$ idf.py -D MICROPY_BOARD=GENERIC_SPIRAM build
$ idf.py flash

在设备上获取 Python 提示

您可以通过串行端口UART0获得提示,UART0与用于对固件进行编程的UART相同。REPL 的波特率为 115200,您可以使用如下命令:

$ picocom -b 115200 /dev/ttyUSB0

$ miniterm.py /dev/ttyUSB0 115200

您还可以使用 .idf.py monitor

配置无线网络和使用开发板

ESP32 端口在模块和面向用户的 API 方面(几乎)等同于 ESP8266。有一些小的区别,特别是 ESP32 在启动时不会自动连接到最后一个接入点。但在大多数情况下,ESP8266 的文档和教程应该适用于 ESP32(至少对于已实现的组件)。

有关快速参考,请参阅 http://docs.micropython.org/en/latest/esp8266/esp8266/quickref.html;有关教程,请参阅 http://docs.micropython.org/en/latest/esp8266/esp8266/tutorial/intro.html

以下功能可用于连接到WiFi接入点(您可以传入自己的SSID和密码,或更改默认值,以便您可以快速呼叫并正常工作):wlan_connect()

def wlan_connect(ssid='MYSSID', password='MYPASS'):
    import network
    wlan = network.WLAN(network.STA_IF)
    if not wlan.active() or not wlan.isconnected():
        wlan.active(True)
        print('connecting to:', ssid)
        wlan.connect(ssid, password)
        while not wlan.isconnected():
            pass
    print('network config:', wlan.ifconfig())

请注意,某些主板要求您在使用 WiFi 之前配置 WiFi 天线。在像LoPy和WiPy 2.0这样的Pycom板上,你需要执行以下代码来选择内部天线(最好将此行放在 boot.py 文件中):

import machine
antenna = machine.Pin(16, machine.Pin.OUT, value=0)

定义自定义 ESP32 开发板

默认的 ESP-IDF 配置设置由目录中的主板定义提供。对于自定义配置,您可以定义自己的主板目录。通过复制现有配置(如)并对其进行修改以适合您的主板来开始新的主板配置。GENERICboards/GENERICGENERIC

特定于 MicroPython 的配置值在特定于主板的文件中定义,该文件包含在 中。其他设置被放入 ,包括配置 ESP-IDF 设置的文件列表。目录中提供了一些标准文件,如 。您还可以在主板目录中定义自定义。mpconfigboard.hmpconfigport.hmpconfigboard.cmakesdkconfigsdkconfigboards/boards/sdkconfig.ble

有关配置的更多示例,请参阅现有主板定义。

配置故障排除

  • 编程后连续重启:确保主板正确(例如 ESP-WROOM-32 应为 DIO)。然后执行 、重新生成、重新部署。CONFIG_ESPTOOLPY_FLASHMODEmake clean

https://github.com/lvgl/lv_micropython

构建说明
Unix (Linux) 端口
sudo apt-get install build-essential libreadline-dev libffi-dev git pkg-config libsdl2-2.0-0 libsdl2-dev python3.8 parallelPython 3 是必需的,但如果需要,您可以安装其他版本的 python3 而不是 3.8。
git clone https://github.com/lvgl/lv_micropython.git
cd lv_micropython
git submodule update --init --recursive lib/lv_bindings
make -C mpy-cross
make -C ports/unix submodules
make -C ports/unix
./ports/unix/micropython
ESP32 端口
请为 esp-idf 安装目录设置参数。它需要与Micropython预期的esp-idf匹配,否则将显示警告(并且构建可能会失败)有关更多详细信息,请参阅设置工具链和ESP-IDFESPIDF

使用 IL9341 驱动程序时,需要将颜色深度和交换模式设置为与 ILI9341 匹配。这可以从命令行完成。以下是构建 ESP32 + LVGL 的命令,该命令与 ILI9341 驱动程序兼容:

make -C mpy-cross
make -C ports/esp32 LV_CFLAGS="-DLV_COLOR_DEPTH=16 -DLV_COLOR_16_SWAP=1" BOARD=GENERIC_SPIRAM deploy
关于参数的说明:

LV_CFLAGS用于覆盖颜色深度和交换模式,以实现 ILI9341 兼容性。
LV_COLOR_DEPTH=16如果您计划使用 ILI9341 驱动程序,则需要。
LV_COLOR_16_SWAP=1如果您计划使用纯微孔显示驱动程序,则需要。
BOARD- 我使用带有SPIRAM的WROVER板。您可以从目录中选择其他板。ports/esp32/boards/
deploy- make命令将创建Micropython的ESP32端口,并将尝试通过USB-UART桥部署它。
有关更多详细信息,请参阅 Micropython ESP32 自述文件。

JavaScript 端口
请参阅分支的自述文件:https://github.com/lvgl/lv_micropython/tree/lvgl_javascript_v8#javascript-portlvgl_javascript

树莓派皮库端口
此端口使用 C 模块的 Micropython 基础结构,并且必须提供:USER_C_MODULES

cd ports/rp2
make USER_C_MODULES=../../lv_bindings/bindings.cmake

参考

https://blog.csdn.net/qq_36953463/article/details/120378152

更换头文件:

cp /home/peter/micropython-esp32-homekit_ok/components/esp-idf/components/hal/esp32c3/include/hal/gpio_ll.h /home/peter/esp-idf/components/hal/esp32c3/include/hal/gpio_ll.h

gpio_ll下载

https://github.com/espressif/esp-idf/blob/master/components/soc/esp32/include/soc/i2s_reg.h

重要参考:

https://github.com/bupthl/lv_micropython

分类目录电子爱好者

固件

https://forum.lvgl.io/t/building-lv-micropython-for-raspberry-pi-pico-failed/7840/4

在fritzing中插入自己的丝印图像

一直以来,fritzing很受欢迎,但因其用户绝大多数为非行业用户,深入应用案例较少,如何在fritzing的PCB中使用自己的logo或文字网上资料很少,这里给出一个比较简单的方法。

1、安装LibreOffice软件,该软件是流行的免费开源办公软件,对标微软办公三件套

2、打开LibreOffice Draw程序,新建文件并插入艺术字,字体和形状根据自己需要修改

3、修改页面属性中的页面大小,适配艺术字长宽大小

4、导出文件格式为svg

5、在fritzing的PCB视图中插入silkscreen image

树莓派中nohup 、&、重定向的使用

一、nohup 和 & 使用方法

1.1、 nohup (不挂断)

nohup 是 no hung up 的缩写,意思是不挂断 。
使用 Xshell 等Linux 客户端工具,远程执行 Linux 脚本时,有时候会由于网络问题,导致客户端失去连接,终端断开,脚本运行一半就意外结束了。这种时候,就可以用nohup 指令来运行指令,使脚本可以忽略挂起,仍可继续运行。
nohup 语法格式:

nohup command [arg…]
1
说明:

除了无法进行输入操作(比如输入命令、换行、打空格等) 外 ,
标准输出 保存到 nohup.out文件中。
关闭客户端后,命令仍然会运行,不会挂断。
例如:

执行 nohup sh test.sh 脚本命令后,终端不能接收任何输入,标准输出 会输出到当前目录的nohup.out 文件。即使关闭xshell 退出后,当前session依然继续运行。

1.2、 & (可交互)

& 语法格式:

command [arg…] &
1
说明:

能进行输入操作(比如输入命令、换行、打空格等),即 可进行交互 输入和输出的操作。
标准输出 保存到 nohup.out文件中。
但是 关闭客户端后,程序会就马上停止。
例如:

执行 sh test.sh & 脚本命令后 ,关闭 xshell,脚本程序也立刻停止。

1.3、nohup 和 & 一块使用(不挂断,可交互)

语法格式:

nohup command [arg…] &
1
说明:

能进行输入操作(比如输入命令、换行、打空格等),即 可进行交互 输入和输出的操作,
标准输出 保存到 nohup.out 中,
关闭客户端后命令仍然会运行。
例子:
执行 nohup sh test.sh & 命令后,能进行输入操作,标准输出 的日志写入到 nohup.out 文件,即使关闭xshell,退出当前session后,脚本命令依然继续运行。

输入输出问题已经解决了, 是不是就完美了? 其实还有一个问题没有解决, 请往下看!
二、 日志 的 重定向 >

上面提到的日志文件默认名称是 nohup.out ,如果修改日志文件的名称,则用到 重定向 ,符号是 > ,语法格式是

fileLog
1
说明:

是重定向的符号。
fileLog 是日志文件名称,最好是英文、数字。
此时, nohup、 & 、 > 三者一块使用的 语法格式 :

nohup command >fileLog &
1
示例:

nohup start.sh >aa.log &
1
说明:执行上面的命令后,可以进行输入,也能在后台运行,运行的日志输出到 aa.log 日志中。

三、错误信息的处理

nohup command >fileLog &
1
虽然解决输入输出,后台也能运行问题,但是还有一项是 错误信息 无法输出到 日志文件中,要解决这个问题,需要增加命令 2 > file 。

标准输出 和 错误信息 同时使用,语法格式如下:

fileLog1 2 >fileLog2
1
有人会疑问,2 是什么意思? 请往下看。

3.1、Linux 标准输入、输出、错误信息的符号

Linux 标准输入、输出、错误信息的符号:

0 表示 stdin (standard input) 标准信息输入 ;
1 表示 stdout (standard output) 标准信息输出 ;
2 表示 stderr (standard error) 错误信息 ;
/dev/null 表示空设备文件。 如果不想输出任何的日志时,使用此参数 。
再来回顾上面的示例:

fileLog1 2 >fileLog2
1
fileLog1 :即 1 >fileLog1,1是标准信息输出,是默认的,可以省略,fileLog1是 日志文件名字。

2 >fileLog2 :2 是错误信息,即将 错误信息 输出 到 fileLog2 文件中 。

到这时,明白 2 含义了吧!

3.2、错误信息 和 标准输出 输出在同一个文件中

如果想把 错误信息 和 标准输出 在同一个文件中 ,使用 2>&1 。 语法如下:

fileLog 2>&1
1
说明:

fileLog 表示 标准信息 输出到 fileLog 文件中;
2>&1 表示 把 2(错误信息) 重定向, 输出到 1(标准输出) 中 。
两者的共同使用,表示 把 2(错误信息) 、1(标准输出) 都输出到同一个文件(fileLog)中。

3.3、思考:不想输出日志信息怎么办 ?

提示:/dev/null 表示空设备文件。 如果不想输出任何的日志时,使用此参数 。

四、综合使用(推荐)

综上所述, 功能最全、推荐语法如下:

nohup command >fileLog 2>&1 &
1
示例:

nohup start.sh > mySysLog.log 2>&1 &
1
说明: 执行命令后,并且将 标准输出(1)、错误信息(2) 写入到 mySysLog.log 文件中。

五、知识扩展

5.1、不停止服务,直接清空nohup.out

如果脚本一直运行下去,nohup.out 日志会一直增长,日志但是硬盘容量有限,怎么把日志文件的大小减少 ?
注意,千万别直接删除日志文件,会造成服务无法输出日志,服务异常直接停止运行,这是最严重生产事故。

不停止服务,直接清空nohup.out文件有两种方法:

第1种:

cat /dev/null > nohup.out

第2种:

cp /dev/null nohup.out

5.2、只记录警告级别比较高的日志

输出的日志太多,nohup.out 增长特别快,对于不重要的日记,可以不记录,选择只记录警告级别比较高的日志。

只输出错误信息到日志文件,其它日志不输出

nohup ./program > /dev/null 2>log &

5.2、不想输出日志

不想输出日志,什么日志都不要,只要服务能正常运行就行了。

什么日志也不输出

nohup ./program > /dev/null 2>&1 &