micropython开发与实战阅读笔记

对本文的一些说明
本文来源于阅读《MicroPython开发与实战》时所做的笔记,这本书不是很厚,所以内容也不是很全面,但作为一个入门工具书还是够的,再由于本人不是这方面的大佬,也不是这个专业的,所做的笔记也必然不是很全面,这仅是我本人阅读笔记,放出来希望能帮助到一些刚入门的ESP32学者。在这里插入图片描述

本人使用的开发板是合宙esp32c3,书籍使用的是NodeMCU-32S,大部分只是引脚不同和资源个数不同,资源的使用方法是相通的,我对部分代码参数进行调整以适配合宙esp32c3,如果有使用其他型号开发板的学者,也可以很容易复现代码。
书中部分代码我在开发板上无法运行成功,对此类代码已做标注

书籍情况介绍,本书共262页
1~12MPy介绍及Python安装,占比4.6%,累计4.6%
13~125讲解Python语法,占比43.1%,累计47.7%
126~172讲通过MPy使用WIFI,PWM,ADC,定时器,UART,SPI(ADC和SPI仅作必要介绍),占比17.94%,累计65.65%
后面讲的MQTT连接阿里云,MPy for STM32F4,暂未看到,先不写。

  • 初始环境配置
  1. 下载对应的micropython固件
  2. pip install esptool
  3. 清空flash: esptool.py --chip esp32c3 --port COM? erase_flash
  4. 烧写固件:esptool.py --chip esp32c3 --port COM? --baud 460800 write_flash -z 0x0 esp32c3-xxx.bin
  5. 写代码,注意utf-8编码,main.py
  6. cp ./main.py /pyboard/
  7. pip install rshell,安装完成后rshell --buffer-size 512 --editor D:\programfiles\notepad++\notepad++.exe -p COM?
  8. repl并重启开发板,可以看到输出信息
    由于每次都要重新输入rshell的一长串命令,十分不便,所以想写成一个bat脚本,但是由于从未接触过bat命令,从网上找了不少,又结合AI,勉强拼凑出一份能用的脚本
    conn.bat文件内容,该文件会调用下面的getCOM.bat文件
@echo off  
chcp 65001
call getCOM.bat
setlocal EnableDelayedExpansion  
  
:: 获取用户输入的COM端口号  
set /p "port=请输入COM端口号: "  
  
:: 移除用户输入中可能的前导"COM"字符串  
set "COM_PORT=!port:COM=!"  
  
:: 如果用户没有输入"COM",则添加前缀  
if not "!COM_PORT:~0,3!"=="COM" set "COM_PORT=COM!COM_PORT!"  
  
:: 调用rshell命令,使用用户输入的COM端口  
rshell --buffer-size 512 --editor "D:\programfiles\notepad++\notepad++.exe" -p !COM_PORT!  

goto :EOF

getCOM.bat内容

@echo off
setlocal

:: wmic /format:list strips trailing spaces (at least for path win32_pnpentity)
for /f "tokens=1* delims==" %%I in ('wmic path win32_pnpentity get caption /format:list ^| find "COM"') do (
    call :setCOM "%%~J"
)

:: display all _COM* variables
set _COM

:: end main batch
goto :EOF

:setCOM <WMIC_output_line>
:: sets _COM#=line
setlocal
set "str=%~1"
set "num=%str:*(COM=%"
set "num=%num:)=%"
set str=%str:(COM=&rem.%
endlocal & set "_COM%num%=%str%"
goto :EOF

现象截图
在这里插入图片描述
在这里插入图片描述
如果我有任何错误及改进意见,欢迎指出!

esp32网络基础使用

import network

sta_if = network.WLAN(network.STA_IF)    #STA模式
ap_if = network.WLAN(network.AP_IF)     #AP模式

使用以下命令检查接口是否有效

sta_if.active()
ap_if.active()

连接WIFI

#首先激活station接口
sta_if.active(True)
#然后连接到网络
sta_if.connect("WIFI名","WIFI密码")

使用以下命令检查连接是否建立sta_if.isconnected()

查看IPsta_if.ifconfig()

开机自动连接WIFI

下面的函数可以自动运行并连接到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("WIFI名","WIFI密码")
        while not sta_if.isconnected():
            pass
    print('network config:', sta_ifconfig())

获取系统时间

import time
time.localtime()

此方法获取的并不是当前真正的时间,若需获取准确时间,可以用MPY的ntptime时间同步模块,从服务器校准时间

ntptime.settime(timezone = 8,server = 'ntp.ntsc.ac.cn')为默认参数,可以自己修改,目前感觉似乎没有参数

import time
import ntptime
print(f'同步前本地时间{str(time.localtime())}')
ntptime.settime()
print(f'同步后本地时间{str(time.localtime())}')

网上找的

import ntptime
def sync_ntp():
     ntptime.NTP_DELTA = 3155644800   # 可选 UTC+8偏移时间(秒),不设置就是UTC0
     ntptime.host = 'ntp1.aliyun.com'  # 可选,ntp服务器,默认是"pool.ntp.org"
     ntptime.settime()   # 修改设备时间,到这就已经设置好了

sync_ntp()

get请求

import urequests
a = urequests.get("http://www.baidu.com")
a.text

socket模块

socket模块的宏

名称含义
socket.AF_INET地址簇TCP/IP-IPV4
socket.AF_INET6地址簇TCP/IP-IPV6
socket.SOCK_STREAM套接字类型TCP流
socket.SOCK_DGRAM套接字类型UDP数据报
socket.SOCK_RAW套接字类型原始套接字
socket.SO_REUSEADDR套接字选项允许重用地址
socket.IPPROTO_TCPIP协议号TCP协议
socket.IPPROTO_UDPIP协议号UDP协议
socket.SOL_SOCKET套接字选项等级套接字选项

socket模块的API

1.socket.getaddrinfo(host, port)
将主机域名和端口转换为用于创建套接字的5元组序列
(family, type, proto, canonname, sockaddr)

>>> info = socket.getaddrinfo("172.0.0.1",80)
>>> info
[(2, 1, 0, '172.0.0.1', ('172.0.0.1', 80))]

2.socket.socket([af, type, proto])
创建套接字
af:地址,type:类型,proto:协议号
一般不指定proto

>>> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> print(s)
>>> print(s)
<socket>

3.socket.bind(address)
以列表或元组方式绑定地址和端口号
address:一个包含地址和端口号的元组或列表

addr = ("127.0.0.1", 10000)
s.bind(addr)

4.socket.listen([backlog])
监听套接字,使服务器能够接收连续
backlog:接收套接字的最大个数,有默认值

s.listen(100)

5.socket.accept()
阻塞接收连接请求,只能在绑定地址端口号和监听后调用,返回conn和address
返回值:conn:新的套接字对象,可以用来收发消息
address:连接到服务器的客户端地址

conn, address = s.accept()

6.socket.connect(address)
连接服务器
address:服务器地址和端口号的元组或列表

host = "192.168.3.147"
port = 100
s.connect((host, port))

7.socket.send(bytes)
发送数据,并返回发送的字节数。
bytes:bytes类型数据

s.send("hello, I am TCP Client")

8.socket.recv(bufsize)
接收数据,并返回接收到的数据对象
bufsize: 接收数据的最大字节数

data = conn.recv(1024)

9.socket.close()
关闭套接字

s.close()

利用socket下载网页数据

使用socket定义一个可以下载和打印URL的函数

# 目前似乎无法成功
import socket
def httpGet(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
    s.close()

    # 函数使用
    httpGet('http://www.baidu.com/')

利用socket实现ESP32的网络通信

esp32与PC须在同一局域网内

电脑端代码

import socket
import _thread

def tcplink(conn, addr):
    print('addr:',addr)
    print('conn',conn)
    while 1:
        data = conn.recv(1024)
        #防止对面断线连接没关掉
        if not data:
            break
        print('msg:', str(data,"utf-8"))
    conn.close()

sock_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock_tcp.bind(('0.0.0.0', 6000))
sock_tcp.listen(100)
print('listening')
while 1:
    conn, addr = sock_tcp.accept()
    _thread.start_new_thread(tcplink, (conn, addr))

ESP32端代码

import socket
import _thread

sock_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock_tcp.connect(("电脑IP地址172.26.96.101", 6000))
sock_tcp.sendall(bytes("i am zzp!", "utf-8"))

硬件控制

Pin例程

from machine import Pin
D4 = Pin(12, Pin.OUT)
led.value([x])# 可读可写
led.on()
led.off()

延时

utime模块
utime.sleep(s)
utime.sleep_ms(ms)
utime.sleep_us(us)

import utime
utime.sleep_ms(500) #延时500ms

控制LED闪烁

import utime
from machine import Pin

D4 = Pin(12, Pin.OUT)
# 循环10次亮灭
for i in range(10):
    D4.value(1)
    utime.sleep_ms(500)
    D4.value(0)
    utime.sleep_ms(500)

PWM脉宽调制技术-呼吸灯

ESP32的占空比(duty)不是百分比而是一个分辨率,范围0~1023

from machine import Pin, PWM
D4 = Pin(2, Pin.OUT)
# 把Pin对象传入PWM构造器
D4 = PWM(D4) #也可以直接初始化,D4 = PWM(D4, freq=1000, duty=500)

方法

  1. PWM.init(freq, duty)
  2. PWM.freq([freq_val]) 可读可写
  3. PWM.duty([duty_val]) 可读可写
  4. PWM.deinit() 释放PWM对象

PWM控制LED亮度

把下列代码保存为pwm_led.py

from machine import Pin, PWM
class PWM_LED:
    def __init__(self,pinNum,freq=1000):
        pin = Pin(pinNum,Pin.OUT)
        self.pwm = PWM(pin,freq=freq)
    def change_duty(self,duty):
        self.pwm.duty(duty)
    def deinit(self):
        self.pwm.deinit()

呼吸灯

import machine, utime, math
from pwm_led import *
from machine import Pin

pwm_led = PWM_LED(12)
def pulse(switch, period, gears):
    # 呼吸灯核心代码
    # 借用sin正弦函数,将PWM范围控制在23~1023
    # switch开关对象
    # period呼吸一次的周期,单位ms
    #gears呼吸过程经历的亮度档位数
    for i in range(2*gears):
        switch.change_duty(int(math.sin(i/gears*math.pi)*500)+523)
        # 延时
        utime.sleep_ms(int(period/(2*gears)))

# 呼吸10次
for i in range(10):
    pulse(pwm_led, 2000, 100)
# 释放资源
pwm_led.deinit()

ADC例程

构造对象

classmachine.ADC(pin)
创建与设定引脚关联的ADC对象。用户可以读取该引脚上的模拟值
Pin:ADC在专用因脚伤可以用

from machine import ADC, Pin
adc = ADC(Pin(0))

方法

  • ADC.atten(db)设置ADC衰减量,即设置输入范围,未设置默认为1V
宏定义衰减量/db数值满量程电压
ADC.ATTN_0DB001
ADC.ATTN_2_5DB2.511.5
ADC.ATTN_6DB622
ADC.ATTN_11DB1133.3
  • ADC.width(bit)设置分辨率
宏定义数值满量程
ADC.WIDTH_9BIT0511
ADC.WIDTH_10BIT11023
ADC.WIDTH_11BIT22047
ADC.WIDTH_12BIT34095
  • ADC.read()读取ADC值并返回读取结果

RTC例程

RTC是独立的时钟,可以跟踪日期和时间

构造对象

classmachine.RTC()创建RTC对象

初始化RTC时间

RTC.init([datetimetuple])
元组(年,月,日,周(0~6),时,分,秒,毫秒)
rtc.init((2024, 4, 17, 2, 15, 50, 40, 0))

查看RTC时间

RTC.init([datetimetuple])
未给参数则读取时间

缺陷:每过7h45min就会有秒级别的误差,所以建议每隔7小时校准一次时间

Timer例程

构造对象

  • class machine.Timer(id,...)构造给定id的新计时器对象,id为任意正数

初始化定时器

  • Timer.init(*, mode=Timer.PERIODIC, period=-1,callback=None)
    mode是定时器模式之一
    • Timer.ONE_SHOT:计时器运行一次
    • Timer.PERIODIC:计时器运行多次

period:定时时间,0~3 435 973 836ms
callback:回调函数
示例代码:tim.init(mode=Timer.ONE_SHOT, period=1000, callback=lambda t:print('haha))

释放定时器资源

Timer.deinit()取消定时器初始化,停止计时器,并禁用计时器外围设备

定时器控制LED闪烁

示例代码

from machine import Timer, Pin
import utime
def toggle_led(led_pin):
    # LED翻转
    led_pin.value(not led_pin.value())
def led_blink_timed(timer, led_pin, freq):
    """
    led按照特定的频率闪烁
    LED闪烁周期 = 1000ms/2
    状态变换时间间隔(period) = LED闪烁周期/2
    """
    # 计算状态变换时间间隔
    period = int(1000/freq/2)
    #初始化定时器
    # 这里回调是使用了lambda表达式,因为回调函数需要传入led_pin
    timer.init(period=period, mode=Timer.PERIODIC, callback=lambda t:toggle_led(led_pin))
# 声明D4作为LED引脚
led_pin = Pin(12, Pin.OUT)
timer = Timer(0) # 创建定时器对象,实测1不好使
led_blink_timed(timer, led_pin, freq=20)

串口UART例程

合宙esp32c3
UART0_RX:08 UART0_TX:09
UART1_RX:01 UAER1_TX:00

构造对象

class machine.UART(id, baudrate, bits, parity, rx, tx, stop, timeout)
id:串口编号
bandrate:波特率
bits:数据位,默认8,可选7,9
parity:校验方式,默认None不校验,0偶校验,1奇校验
rx:接收口的GPIO编号
tx:发送口的GPIO编号
stop:停止位,默认1,可选2
timeout:超时时间,0~2 147 483 647

>>> from machine import UART
>>> u = UART(1)
>>> print(u)
UART(1, baudrate=115211, bits=8, parity=None, stop=1, tx=10, rx=9, rts=-1, cts=-1, txbuf=256, rxbuf=256, timeout=0, timeout_char=0)

方法

  • UART.read([nbytes]):读字符,参数可选,为最多读取字节数,否则尽可能读取多的数据
    返回值:包含读入的字节的字节对象,超时返回None
  • UART.readinto(buf[, nbytes]):将字节读入buf.
    返回读取并写入到buf的字节数,超时返回None
  • UART.readline():读一行,读到换行符结束,超时返回None
  • UART.write(buf):串口发送数据,返回发送的字节数,超时返回None
  • UART.any():检查是否有可读的数据,返回可读数据长度

ESP32串口通信——字符串自收发实验

将UART1的TX和RX连接起来,在合宙esp32c3中就是IO00和IO01连接

from machine import UART, Timer
import select, time

# 创建一个UART对象,将引脚0和引脚1相连
uart = UART(1, baudrate=9600, tx=01, rx=00)
# 创建一个Timer,使用中断来轮询串口是否有数据可读
timer = Timer(0)
timer.init(period=50,mode=Timer.PERIODIC, callback=lambda t:read_uart(uart))

def read_uart(uart):
    if uart.any():
        print('received:'+uart.read().decode()+'\n')

if __name__ == '__main__':
    try:
        for i in range(10):
            uart.write(input('send:'))
            time.sleep_ms(50)
    except:
        timer.deinit()

SPI例程

构造对象

硬件SPI

HSPI后遭,代码如下

>>> from machine import SPI
>>> hspi = SPI(1)
>>> print(hspi)
SPI(id=1, baudrate=500000, polarity=0, phase=0, bits=8, firstbit=0, sck=6, mosi=7, miso=2)
软件SPI

方法1:类构造

  • SPI(baudrate, polarity, phase, bits, firstbit, sck, mosi, miso)
    baudrate:SCK时钟频率,范围0~0x0FFFFFFF(2 147 483 647)
    polarity:极性,分为以下两种情况:
    • 0:空闲电平:底
    • 1:空闲电平:高
      phase:相位,分为以下两种情况:
    • 0:在第一时钟沿采集数据
    • 1:在第二时钟沿采集数据
      bits:数据位
      firstbit:从地位向高位发还是从高位往低位发
      sck:时钟引脚
      mosi:主设备出,从设备入引脚
      miso:主设备入,从设备出引脚
from machine import SPI, Pin
spi = SPI(baudrate=115200, polarity=1, phase=0, sck=Pin(17), mosi=Pin(27), miso=Pin(18))

方法2:使用init构造

  • SPI.init(baudrate, polarity, phase, sck, mosi, miso)
    初始化SPI总线
from machine import SPI, Pin
spi = SPI.init(baudrate=115200, polarity=1, phase=0, sck=Pin(17), mosi=Pin(27), miso=Pin(18))

方法

  • SPI.deinit():关闭SPI总线
  • SPI.read(nbytes, write=0x00):读取由nbytes指定的字节数,同时连续写入由write给定的单字节
    (Read a number of bytes specified by nbytes while continuously writing the single byte given by write. Returns a bytes object with the data that was read.)
  • SPI.readinto(buf, write=0x00):读入由buf指定的缓冲区,同时不断写入由write给定的单字节。返回读取的字节数
  • SPI.write(buf):写入buf中的字节,返回写入的字节数
  • SPI.write_readinto(write_buf, read_buf)
    从write_buf中写入字节,同时读入read_buf中。缓冲区可以是相同的,也可以不同,但是两个缓冲区都必须有相同长度,
    返回写入的字节数

MQTT与阿里云平台实战-未写

  • 30
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值