主板

主板实物图

https://pico.org.cn/
在这里插入图片描述

主板引脚图

在这里插入图片描述

在这里插入图片描述

Thonny开发IDE工具

https://thonny.org

配置解释器:Raspberry Pi Pico
工具=》选项=》解释器(选择Raspberry Pi Pico)
在这里插入图片描述

查看帮助信息

help(‘modules’) :查看可以通过import导入的模名
在这里插入图片描述
help(模块名):查看指定模块下的类、函数、常量:
在这里插入图片描述
help(模块名.类):查看指定模块类包含的函数和常量
在这里插入图片描述

Micropython官网文档

micropython参考文档

CPU主频

  • RP2040主频最高支持133MHz
import machine

print(machine.freq()) # 打印当前CPU频率
machine.freq(24000000) # 设置CPU频率

GPIO 输出

GPIO输出模式:machine.Pin.OUT
GPIO输入模式:machine.Pin.IN

import machine
import utime

led = machine.Pin(25, machine.Pin.OUT)
print('gpio output demo...')
while True:
    led.value(0)
    utime.sleep(1)
    led.value(1)
    utime.sleep(0.5)
    
	# 其它GPIO相关操作接口
	#led.low()
    #led.high()
    #led.toggle()
    #led.on()
    #led.off()
    #led.value(0)
    #led.value(1)
    #state=led.value()
    #print(state)

GPIO 输入

上拉:machine.Pin.PULL_UP
下拉:machine.Pin.PULL_DOWN

import machine
import utime

key = machine.Pin(23, machine.Pin.IN, machine.Pin.PULL_UP)
led = machine.Pin(25, machine.Pin.OUT)

print('gpio input demo...')
while True:
    if key.value() == 1:
        led.value(1)
    else:
        led.value(0)
    utime.sleep_ms(100)
        

GPIO 中断

irq(trigger, handler), trigger中断触发方式,handler中断处理函数
下降沿:trigger=machine.Pin.IRQ_FALLING
上升沿:trigger=machine.Pin.IRQ_RISING

import machine
import utime

key = machine.Pin(23, machine.Pin.IN, machine.Pin.PULL_DOWN)
led = machine.Pin(25, machine.Pin.OUT)

print('gpio irq demo...')
def irq_handler(pin):
    print(pin)
    led.toggle()

key.irq(trigger=machine.Pin.IRQ_FALLING, handler=irq_handler)

while True:
    utime.sleep(1)
    print("main loop...")

ADC(模数转换)

外部ADC模拟电压表

import machine
import utime
import math

adc0 = machine.ADC(26)
adc1 = machine.ADC(27)
adc2 = machine.ADC(28)

adcvalue0 = 0
adcvalue1 = 0
adcvalue2 = 0
factor = 3.3/(65536)

while True:
    adcvalue0 = adc0.read_u16()*factor
    adcvalue1 = adc1.read_u16()*factor
    adcvalue2 = adc2.read_u16()*factor
    print(adcvalue0, adcvalue1, adcvalue2)
    utime.sleep_ms(500)    

内部ADC测量温度

import machine
import utime

sensor_temp = machine.ADC(4)
#sensor_temp = machine.ADC(machine.ADC.CORE_TEMP)
conversion_factor = 3.3/(65535)
while True:
    reading = sensor_temp.read_u16()*conversion_factor
    temperature = 27 - (reading - 0.706)/0.001721
    print(temperature,"C")
    utime.sleep(1)

PWM(脉宽调制)

PWM相关接口:
pwm0 = machine.PWM(machine.Pin(0))
pwm0.freq() # 返回当前PWM设置频率
pwm0.freq(2000) # 设置PWM频率
pwm0.duty_u16(15000) # 设置占空比(0~65535)
pwm0.duty_ns(10) # 设置占空比时间ns

import machine
import utime
import urandom

led_r = machine.PWM(machine.Pin(4))
led_g = machine.PWM(machine.Pin(3))
led_b = machine.PWM(machine.Pin(2))

led_r.freq(1000)
led_g.freq(1000)
led_b.freq(1000)

print(led_r.freq())
print(led_g.freq())
print(led_b.freq())

while True:
    led_r.duty_u16(urandom.randrange(1, 65535, 10))
    led_g.duty_u16(urandom.randrange(1, 65535, 20))
    led_b.duty_u16(urandom.randrange(1, 65535, 30))    
    utime.sleep_ms(100)

WDT看门狗

import machine
import utime

# enable the WDT with a timeout of 5s (1s is the minimum)
wdt = machine.WDT(timeout=5000)

print("WDT Demo...")
while True:
    wdt.feed()
    utime.sleep(3)

RTC实时时钟

rtc = machine.RTC()
rtc.datetime()返回一个元组数据:
(年,月,日,星期,时,分,秒,0)
(2022, 10, 14, 4, 14, 41, 57, 0)

import machine
import utime

rtc = machine.RTC()

# 设置RTC日期时间等参数
# rtc.datetime((2020, 1, 21, 2, 10, 32, 36, 0))

while True:
    print(rtc.datetime())
    utime.sleep(1)

I2C总线接口

I2C总线的通讯频率:

  • 标准模式(Standard):100kbps
  • 快速模式(Fast):400kbps
  • 快速模式+(Fast-Plus):1Mbps
  • 高速模式(High-speed):3.4Mbps
  • 超快模式(Ultra-Fast):5Mbps(单向传输)

构造函数

  • machine.I2C(id, *, scl, sda, freq=400000)
    使用以下参数构造并返回一个新的 I2C 对象:
    id:标识特定的 I2C 外设。允许的值取决于特定的端口/板
    scl:应该是一个 pin 对象,指定用于 SCL 的 pin。
    sda:应该是一个 pin 对象,指定用于 SDA 的 pin。
    freq:应该是一个整数,用于设置 SCL 的最大频率。

一般方法

  • i2c.scan(): 扫描所有 0x08 和 0x77 之间的 I2C 地址,然后返回一个有响应地址的列表

标准总线操作

  • i2c.readfrom(addr, nbytes, stop=True):

    • 功能:从addr指定的从站读取nbytes
    • addr:从设备地址
    • nbytes:指定读取的字节数
    • stop:True传输结束时发送停止信号
    • 返回读取数据的对象
    • buf = i2c.readfrom(0x44, 5)
  • i2c.readfrom_into(addr, buf, stop=True):

    • 功能:从addr指定的从设备读入buf长度的数据到buf内
    • addr:从设备地址
    • stop:True传输结束时发送停止信号
    • 返回: None
    • buf = bytearray(3)
      i2c.readfrom_into(0x44, buf)
  • i2c.writeto(addr, buf, stop=True):

    • 功能:将buf 中的字节写入addr指定的从设备。
    • addr:从设备I2C地址
    • buf:要写入的字节数组,存放写入的数据,写入的长度为buf的长度。
    • stop:True传输结束时发送停止信号
    • 返回接收到的ACK数
    • 示例:
      buf=bytearray([0x01,0x02,0x03])
      i2c.writeto(0x74, buf) # 向从设备地址为0x74设备写入3个字节数据
  • i2c.writevto(addr, vector,stop:True):新增更高效的大量数据写入操作。(设备地址 + 命令 + 数据)

    • 功能:将vector 中包含的字节写入addr指定的从站
    • addr:设备地址
    • vector:vector应该是具有缓冲协议的元组或对象列表
    • stop:True传输结束时发送停止信号
    • 返回接收到的 ACK 数
    • 示例:
      write_list = [b"\x40", None] # b"\x40" : 命名
      write_list[1] = bytearray([0x01,0x05,0x06,0x08]) # 数据
      ret = i2c.writevto(0x44, write_list)
      print(ret) # 写入字节数 5 个

内存操作

  • i2c.readfrom_mem(addr, memaddr, nbytes, *, addrsize=8):

    • 功能:从addr指定的从设备的memaddr指定的内存地址开始,读取nbytes。
    • addr:从设备地址
    • memaddr:寄存器地址
    • nbytes:读取字节数
    • addrsize:寄存器地址长度
    • 返回读取数据的对象
    • buf = i2c.readfrom_mem(0x44, 0x3244, 5, addrsize=16)
  • i2c.readfrom_mem_into(addr, memaddr, buf, *, addrsize=8):

    • 功能:从addr指定的从设备的memaddr内存地址开始读入buf长度的数据到buf。
    • addr:从设备地址
    • memaddr:寄存器地址
    • buf:存放读取数据的字节数组
    • addrsize:寄存器长度
    • 返回None
    • buf = bytearray(10)
      i2c.readfrom_mem_into(0x44, 0x33, buf, addrsize=8)
  • i2c.writeto_mem(addr, memaddr, buf, *, addrsize=8):

    • 功能:将buf中的数据写入到addr从设备的 memaddr开始的寄存器地址中。
    • addr:从设备地址
    • memaddr:寄存器地址
    • buf:写入的数据字节数组
    • addrsize:寄存器地址长度,8:单字节,16:双字节
    • 示例:
      buf = bytearray([0x01,0x02,0x03])
      i2c.writeto_mem(0x44, 0xCC66, buf, addrsize=16)

最原始的通信方式:

 def write_data(self, buf):
     self.temp[0] = self.addr << 1
     self.temp[1] = 0x40
     self.i2c.start()       
     self.i2c.write(self.temp)       
     self.i2c.write(buf)       
     self.i2c.stop()

搜索I2C总线设备:

from machine import Pin, I2C
import utime

i2c = I2C(0, sda=Pin(0), scl=Pin(1), freq=400000)
devlist = i2c.scan()
print(devlist)
for dev in devlist:
    print(hex(dev))

读写I2C设备示例:

import machine
import utime

sda = machine.Pin(16)
scl = machine.Pin(17)
i2c = machine.I2C(0, sda=sda, scl=scl, freq=200000)
  
print(i2c.scan())

i2c.writeto(35, '0x01') # power on
i2c.writeto(35, '0x10') # H-resolution mode
i2c.writeto(35, '0x20')
utime.sleep(0.2)



while True:
    i2c.writeto(35, '\x01')
    val = i2c.readfrom(35, 2, True)
    print(val)
    utime.sleep(1)

UART串口通信

串口通信相关接口:
rxbuf=bytes()
rxData=bytes()
txData=bytes()
tx = machine.Pin(16)
rx = machine.Pin(17)
uart = machine.UART(0, baudrate=9600, bits=8, parity=None, stop=1, tx=tx, rx=rx)
uart.any() # True:有可以读取的数据,False:没有可读取的数据
rxData += uart.read(1) # 读取一个字节数据
rxData = uart.readline() # 读取一行数据
uart.readinto(rxbuf, 10) # 读取10个字节数据到rxbuf
uart.sendbreak() # 中断串口数据发送

txData = b’hello world!’
uart.write(txData) # 串口写入数据
uart.txdone() # 串口数据 True:发送完成, False:还有数据未发送成功
uart.flush() # 串口刷新数据
uart.deinit() # 串口反初始化

uart.CTS
uart.RTS
uart.INV_RX
uart.INV_TX

from machine import Pin,UART
import utime

uart0 = UART(0, baudrate=9600, bits=8, parity=None, stop=1, tx=Pin(16), rx=Pin(17), )
#uart0.deinit()

txData = b'hello world\n\r'
rxData = bytes()
uart0.write(txData)
#buf=bytes()
#uart0.readinto(buf, 10)
#uart0.sendbreak()

print(type(txData))
print(type(rxData))
while True:
    while uart0.any() > 0:
        #rxData += uart0.read(1)
        rxData = uart0.readline()
        print(rxData.decode('utf-8'))
        if not uart0.txdone():
            uart0.flush()
        uart0.write(rxData)
    utime.sleep(0.2)

Timer定时器

初始化并启动定时器:

  • Timer.init(*, mode=Timer.PERIODIC, period=- 1, callback=None)
    mode: 定时器模式(Timer.ONE_SHOT , Timer.PERIODIC)
    period:定时器周期
    callback:定时器回调函数
  • Timer.deinit()

启动一个定时器:

from machine import Pin, Timer

led = Pin(25, Pin.OUT)
tim = Timer()

def tick(timer):
   global led
   led.toggle()

tim.init(freq=2.5, mode=Timer.PERIODIC, callback=tick)

启动多个定时器:

import utime
from machine import Timer

def tim_callback1(timer):
    """
    Timer Callback Function.
    """
    print("Timer 1...")
    pass

def tim_callback2(timer):
    print("Timer 2...")
    pass

tim1 = Timer()
tim1.init(mode=Timer.PERIODIC, period=1000, callback=tim_callback1)
#tim.init(mode=Timer.ONE_SHOT, period=100, callback=tim_callback)

tim2 = Timer()
tim2.init(mode=Timer.PERIODIC, period=2000, callback=tim_callback2)

print("timer demo ...")

#tim1.deinit()
#tim2.deinit()
while True:
    utime.sleep(1)

双核多线程

RP2040 CPU是双核默认代码运行在core0通过
_thread.start_new_thread启动的线程代码运行在core1上,注:start_new_thread只能调用一次,多次调用会提示core 1已使用;

import time, _thread

def th1_task(n, delay):
    while True:
        print("thread 1 running...",n)
        time.sleep(delay)
    pass

_thread.start_new_thread(th1_task,(10, 1))

print("thread demo...")
while True:
    print("main loop...")
    time.sleep(10)

使用线程互斥锁:

import utime
import _thread

# 线程互斥锁
lock = _thread.allocate_lock()

# 内核1 运行任务
def core1_task():
    """
    Core1 task
    """
    while True:
        #lock.acquire()
        print("core1 task")
        utime.sleep(0.5)
        #lock.release()
    pass

_thread.start_new_thread(core1_task, ())

while True:
    #lock.acquire()
    print("core0 task")
    utime.sleep(0.5)
    #lock.release()
        

文件操作

file = open("test.txt", "w")
file.write("Hello, File!")
file.write(str('13245')+"\n")
file.flush()
file.close()

file = open("test.txt")
print(file.read())
file.close()

模块

超声波测距模块

import machine
import utime

trig = machine.Pin(16, machine.Pin.OUT)
echo = machine.Pin(17, machine.Pin.IN)

def get_distance(trig, echo):
    # 10us high
    trig.low()
    utime.sleep_us(2)
    trig.high()
    utime.sleep_us(10)
    trig.low()
    
    while (echo.value() == 0):
        start = utime.ticks_us()
    while echo.value() == 1:
        end = utime.ticks_us()
        d = (end - start) * 0.034 / 2
    return d

trig.low()

while True:
    distance = get_distance(trig, echo)
    print("距离:{:.2f} cm".format(distance))
    utime.sleep(0.1)
    

舵机控制

棕色:GND(电源负极)
红色:VCC(电源正极)
橙色:PWM(控制信号)

在这里插入图片描述
控制时序0~180角度
在这里插入图片描述
控制时序-90 ~ 0 ~ 90角度
在这里插入图片描述

from machine import Pin, PWM
import utime

pwm0 = PWM(Pin(0))
pwm0.freq(50)
updown = True

# 舵机控制信号周期T=20ms, f=1/T = 1/20ms = 50Hz
# 脉冲宽度:0.5ms ---> 0度    PWM_DUTY=65535*(0.5ms/20ms)=1638
# 脉冲宽度:1.5ms ---> 90度   PWM_DUTY=65535*(1.5ms/20ms)=4915
# 脉冲宽度:2.5ms ---> 180度  PWM_DUTY=65535*(2.5ms/20ms)=8192

vmin, vmax = (65535*(0.5/20)), (65535*(2.5/20))
def get_angle(angle):   
    duty = int(vmin + (((vmax-vmin)/180) *angle) )
    return duty

angle = 0
pwm0.duty_u16(get_angle(angle))
utime.sleep(2)

while True:
    angle = 0
    pwm0.duty_u16(get_angle(angle))
    utime.sleep(1)
    angle = 45
    pwm0.duty_u16(get_angle(angle))
    utime.sleep(1)
    angle = 90
    pwm0.duty_u16(get_angle(angle))
    utime.sleep(1)
    angle = 135
    pwm0.duty_u16(get_angle(angle))
    utime.sleep(1)
    angle = 180
    pwm0.duty_u16(get_angle(angle))
    utime.sleep(1)

WS2812 RGB灯

将该文件通过Thonny保存到Raspberry PI Pico 的:“/lib/ws2812b.py”目录下
在这里插入图片描述
在这里插入图片描述
文件已保存到Raspberry Pi Pico内,然后就可以在代码使用import ws2812b
在这里插入图片描述

  • ws2812b(num, sm, pin)
    num代表ws2812的数量
    sm是内核,目前需要设置为0
    pin是使用的引脚
  • set_pixel(n, r, g, b)
    n是第几个ws2812
    r, b, b是红绿蓝颜色
  • show(),刷新显示
  • fill((r, g, b)),填充所有ws2812
  • set_pixel_line(n1,n2,r,g,b),设置从n1到n2颜色
  • set_pixel_line_gradient(n1,n2,r1,g1,b1,r2,g2,b2),设置从n1到n2渐变色
    ws2812b.py
import array, time
from machine import Pin
import rp2

@rp2.asm_pio(sideset_init=rp2.PIO.OUT_LOW, out_shiftdir=rp2.PIO.SHIFT_LEFT, autopull=True, pull_thresh=24)
def ws2812():
    T1 = 2
    T2 = 5
    T3 = 3
    wrap_target()
    label("bitloop")
    out(x, 1)               .side(0)    [T3 - 1]
    jmp(not_x, "do_zero")   .side(1)    [T1 - 1]
    jmp("bitloop")          .side(1)    [T2 - 1]
    label("do_zero")
    nop()                   .side(0)    [T2 - 1]
    wrap()
    
#delay here is the reset time. You need a pause to reset the LED strip back to the initial LED
#however, if you have quite a bit of processing to do before the next time you update the strip
#you could put in delay=0 (or a lower delay)
class ws2812b:
    def __init__(self, num_leds, state_machine, pin, delay=0.001):
        self.pixels = array.array("I", [0 for _ in range(num_leds)])
        self.sm = rp2.StateMachine(state_machine, ws2812, freq=8000000, sideset_base=Pin(pin))
        self.sm.active(1)
        self.num_leds = num_leds
        self.delay = delay
        self.brightnessvalue = 255

    # Set the overal value to adjust brightness when updating leds
    def brightness(self, brightness = None):
        if brightness == None:
            return self.brightnessvalue
        else:
            if (brightness < 1):
                brightness = 1
        if (brightness > 255):
            brightness = 255
        self.brightnessvalue = brightness

      # Create a gradient with two RGB colors between "pixel1" and "pixel2" (inclusive)
    def set_pixel_line_gradient(self, pixel1, pixel2, left_red, left_green, left_blue, right_red, right_green, right_blue):
        if pixel2 - pixel1 == 0: return
    
        right_pixel = max(pixel1, pixel2)
        left_pixel = min(pixel1, pixel2)
        
        for i in range(right_pixel - left_pixel + 1):
            fraction = i / (right_pixel - left_pixel)
            red = round((right_red - left_red) * fraction + left_red)
            green = round((right_green - left_green) * fraction + left_green)
            blue = round((right_blue - left_blue) * fraction + left_blue)
            
            self.set_pixel(left_pixel + i, red, green, blue)
    
      # Set an array of pixels starting from "pixel1" to "pixel2" to the desired color.
    def set_pixel_line(self, pixel1, pixel2, red, green, blue):
        for i in range(pixel1, pixel2+1):
            self.set_pixel(i, red, green, blue)

    def set_pixel(self, pixel_num, red, green, blue):
        # Adjust color values with brightnesslevel
        blue = round(blue * (self.brightness() / 255))
        red = round(red * (self.brightness() / 255))
        green = round(green * (self.brightness() / 255))

        self.pixels[pixel_num] = blue | red << 8 | green << 16
    
    # rotate x pixels to the left
    def rotate_left(self, num_of_pixels):
        if num_of_pixels == None:
            num_of_pixels = 1
        self.pixels = self.pixels[num_of_pixels:] + self.pixels[:num_of_pixels]

    # rotate x pixels to the right
    def rotate_right(self, num_of_pixels):
        if num_of_pixels == None:
            num_of_pixels = 1
        num_of_pixels = -1 * num_of_pixels
        self.pixels = self.pixels[num_of_pixels:] + self.pixels[:num_of_pixels]

    def show(self):
        for i in range(self.num_leds):
            self.sm.put(self.pixels[i],8)
        time.sleep(self.delay)
            
    def fill(self, red, green, blue):
        for i in range(self.num_leds):
            self.set_pixel(i, red, green, blue)
        time.sleep(self.delay)

Demo演示代码

from machine  import Pin
import utime
import ws2812b

print(str(ws2812b))

led = ws2812b.ws2812b(9, 0, 6)	# 参数1:LED灯个数, 参数2:固定填0,参数3:Pin端口号

led.fill(255, 0, 0)
led.set_pixel(0, 255, 0, 0) # 设置第一个像素,为红色
#led.set_pixel_line(1, 3, 255, 255, 0)
led.set_pixel_line_gradient(0, 8, 255, 0, 0, 0, 255, 0)# 设置渐变
led.show()

while True:
    #led.rotate_left(1)
    led.rotate_right(1)
    led.show()
    utime.sleep(1)

SSD1306 OLED屏

ssd1306.py保存到pico的/lib目录

# MicroPython SSD1306 OLED driver, I2C and SPI interfaces

from micropython import const
import framebuf


# register definitions
SET_CONTRAST = const(0x81)
SET_ENTIRE_ON = const(0xA4)
SET_NORM_INV = const(0xA6)
SET_DISP = const(0xAE)
SET_MEM_ADDR = const(0x20)
SET_COL_ADDR = const(0x21)
SET_PAGE_ADDR = const(0x22)
SET_DISP_START_LINE = const(0x40)
SET_SEG_REMAP = const(0xA0)
SET_MUX_RATIO = const(0xA8)
SET_COM_OUT_DIR = const(0xC0)
SET_DISP_OFFSET = const(0xD3)
SET_COM_PIN_CFG = const(0xDA)
SET_DISP_CLK_DIV = const(0xD5)
SET_PRECHARGE = const(0xD9)
SET_VCOM_DESEL = const(0xDB)
SET_CHARGE_PUMP = const(0x8D)

# Subclassing FrameBuffer provides support for graphics primitives
# http://docs.micropython.org/en/latest/pyboard/library/framebuf.html
class SSD1306(framebuf.FrameBuffer):
    def __init__(self, width, height, external_vcc):
        self.width = width
        self.height = height
        self.external_vcc = external_vcc
        self.pages = self.height // 8
        self.buffer = bytearray(self.pages * self.width)
        super().__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB)
        self.init_display()

    def init_display(self):
        for cmd in (
            SET_DISP | 0x00,  # off
            # address setting
            SET_MEM_ADDR,
            0x00,  # horizontal
            # resolution and layout
            SET_DISP_START_LINE | 0x00,
            SET_SEG_REMAP | 0x01,  # column addr 127 mapped to SEG0
            SET_MUX_RATIO,
            self.height - 1,
            SET_COM_OUT_DIR | 0x08,  # scan from COM[N] to COM0
            SET_DISP_OFFSET,
            0x00,
            SET_COM_PIN_CFG,
            0x02 if self.width > 2 * self.height else 0x12,
            # timing and driving scheme
            SET_DISP_CLK_DIV,
            0x80,
            SET_PRECHARGE,
            0x22 if self.external_vcc else 0xF1,
            SET_VCOM_DESEL,
            0x30,  # 0.83*Vcc
            # display
            SET_CONTRAST,
            0xFF,  # maximum
            SET_ENTIRE_ON,  # output follows RAM contents
            SET_NORM_INV,  # not inverted
            # charge pump
            SET_CHARGE_PUMP,
            0x10 if self.external_vcc else 0x14,
            SET_DISP | 0x01,
        ):  # on
            self.write_cmd(cmd)
        self.fill(0)
        self.show()

    def poweroff(self):
        self.write_cmd(SET_DISP | 0x00)

    def poweron(self):
        self.write_cmd(SET_DISP | 0x01)

    def contrast(self, contrast):
        self.write_cmd(SET_CONTRAST)
        self.write_cmd(contrast)

    def invert(self, invert):
        self.write_cmd(SET_NORM_INV | (invert & 1))

    def show(self):
        x0 = 0
        x1 = self.width - 1
        if self.width == 64:
            # displays with width of 64 pixels are shifted by 32
            x0 += 32
            x1 += 32
        self.write_cmd(SET_COL_ADDR)
        self.write_cmd(x0)
        self.write_cmd(x1)
        self.write_cmd(SET_PAGE_ADDR)
        self.write_cmd(0)
        self.write_cmd(self.pages - 1)
        self.write_data(self.buffer)


class SSD1306_I2C(SSD1306):
    def __init__(self, width, height, i2c, addr=0x3C, external_vcc=False):
        self.i2c = i2c
        self.addr = addr
        self.temp = bytearray(2)
        self.write_list = [b"\x40", None]  # Co=0, D/C#=1
        super().__init__(width, height, external_vcc)

    def write_cmd(self, cmd):
        self.temp[0] = 0x80  # Co=1, D/C#=0
        self.temp[1] = cmd
        self.i2c.writeto(self.addr, self.temp)

    def write_data(self, buf):
        self.write_list[1] = buf
        self.i2c.writevto(self.addr, self.write_list)


class SSD1306_SPI(SSD1306):
    def __init__(self, width, height, spi, dc, res, cs, external_vcc=False):
        self.rate = 10 * 1024 * 1024
        dc.init(dc.OUT, value=0)
        res.init(res.OUT, value=0)
        cs.init(cs.OUT, value=1)
        self.spi = spi
        self.dc = dc
        self.res = res
        self.cs = cs
        import time

        self.res(1)
        time.sleep_ms(1)
        self.res(0)
        time.sleep_ms(10)
        self.res(1)
        super().__init__(width, height, external_vcc)

    def write_cmd(self, cmd):
        self.spi.init(baudrate=self.rate, polarity=0, phase=0)
        self.cs(1)
        self.dc(0)
        self.cs(0)
        self.spi.write(bytearray([cmd]))
        self.cs(1)

    def write_data(self, buf):
        self.spi.init(baudrate=self.rate, polarity=0, phase=0)
        self.cs(1)
        self.dc(1)
        self.cs(0)
        self.spi.write(buf)
        self.cs(1)
from machine import Pin,I2C
from ssd1306 import SSD1306_I2C
import framebuf
import utime
import array

i2c = I2C(0, scl=Pin(9), sda=Pin(8))
print("I2C Address:", hex(i2c.scan()[0]).upper())

WIDTH  = 128
HEIGHT = 64
oled = SSD1306_I2C(WIDTH, HEIGHT, i2c)

# Raspberry Pi logo as 32x32 bytearray
buffer = bytearray(b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00|?\x00\x01\x86@\x80\x01\x01\x80\x80\x01\x11\x88\x80\x01\x05\xa0\x80\x00\x83\xc1\x00\x00C\xe3\x00\x00~\xfc\x00\x00L'\x00\x00\x9c\x11\x00\x00\xbf\xfd\x00\x00\xe1\x87\x00\x01\xc1\x83\x80\x02A\x82@\x02A\x82@\x02\xc1\xc2@\x02\xf6>\xc0\x01\xfc=\x80\x01\x18\x18\x80\x01\x88\x10\x80\x00\x8c!\x00\x00\x87\xf1\x00\x00\x7f\xf6\x00\x008\x1c\x00\x00\x0c \x00\x00\x03\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")

# Load the raspberry pi logo into the framebuffer (the image is 32x32)
fb = framebuf.FrameBuffer(buffer, 32, 32, framebuf.MONO_HLSB)


oled.fill(0)
oled.blit(fb, (128-32)//2, (64-32)//2)
oled.text('RaspberryPi Pico', 0, 48)
oled.show()
utime.sleep(1)

#oled.invert(True)	# 反色
#oled.invert(False) # 正常
#oled.poweroff()
#oled.poweron()
oled.contrast(250) # 0x0~0xFF

oled.fill(0)
oled.text("Hello", 15, 30)
oled.text("RP2040", 15, 40)
oled.hline(0,0,60, 1)
oled.hline(0,20,60, 1)  # 水平线, X,Y, W, 颜色
oled.vline(0,0,20, 1)
oled.vline(60,0,20, 1)  # 垂直线, X,Y, W, 颜色
oled.rect(80, 0, 40, 10, 1, True) # X,Y, 宽度,高度,颜色,True:实心矩形,False:空心矩形
oled.ellipse(40, 20, 30, 10, 1, True, 0b0010) # 中心X,中心Y,宽度,高度,颜色,实心/空心  象限Q4|Q3|Q2|Q1
oled.pixel(64, 32, 1)   # 画一个像素,X,Y, 颜色

coords = array.array('h', [0,0,  15,12, 2,8,  16,26]) # 路径坐标, [x0,y0, x1,y1,...xn,yn]
oled.poly(60, 20, coords, 1, False) #多边形  x, y, 路径,颜色,实心/空心
oled.show()


while True:
#     oled.scroll(0,1)
    oled.show()
    utime.sleep_ms(200)

AHT10温湿度传感器

aht10.py另存到pico的/lib/aht10.py

import time
from math import log

# AHT10 Library for MicroPython on ESP32
# Author: Sean Yong
# Date: 23rd December, 2019
# Version 1.0

#CONSTANTS
AHT10_ADDRESS = 0x38 # 0111000 (7bit address)
AHT10_READ_DELAY_MS = 75 # Time it takes for AHT to collect data
AHT_TEMPERATURE_CONST = 200
AHT_TEMPERATURE_OFFSET = 50
KILOBYTE_CONST = 1048576
CMD_INITIALIZE = bytearray([0xE1, 0x08, 0x00])
CMD_MEASURE = bytearray([0xAC, 0x33, 0x00])
FARENHEIT_MULTIPLIER = 9/5
FARENHEIT_OFFSET = 32

class AHT10:
    def __init__(self, i2c, mode=0, address=AHT10_ADDRESS):
        if i2c is None:
            raise ValueError('I2C object required.')
        if mode is not (0 and 1):
            raise ValueError('Mode must be either 0 for Celsius or 1 Farenheit')
        self.i2c = i2c
        self.address = address
        self.i2c.writeto(address, CMD_INITIALIZE)
        self.readings_raw = bytearray(8)
        self.results_parsed = [0, 0]
        self.mode = mode # 0 for Celsius, 1 for Farenheit

    def read_raw(self):
        self.i2c.writeto(self.address, CMD_MEASURE)
        time.sleep_ms(AHT10_READ_DELAY_MS)
        self.readings_raw = self.i2c.readfrom(AHT10_ADDRESS, 6)
        self.results_parsed[0] = self.readings_raw[1] << 12 | self.readings_raw[2] << 4 | self.readings_raw[3] >> 4
        self.results_parsed[1] = (self.readings_raw[3] & 0x0F) << 16 | self.readings_raw[4] << 8 | self.readings_raw[5]

    def humidity(self):
        self.read_raw()
        return (self.results_parsed[0] / KILOBYTE_CONST) * 100 

    def temperature(self):
        self.read_raw()
        if self.mode is 0:
            return (self.results_parsed[1] / KILOBYTE_CONST) * AHT_TEMPERATURE_CONST - AHT_TEMPERATURE_OFFSET
        else:
            return ((self.results_parsed[1] / KILOBYTE_CONST) * AHT_TEMPERATURE_CONST - AHT_TEMPERATURE_OFFSET) * FARENHEIT_MULTIPLIER + FARENHEIT_OFFSET

    def set_mode(self, mode):
        if mode is not (0 or 1):
            raise ValueError('Mode must be either 0 for Celsius or 1 Farenheit')
        self.mode = mode

    def print(self):
        print("Temperature: " + str(self.temperature()) + ("C","F")[self.mode] + ", Humidity: " + str(self.humidity()))

    def dew_point(self):
        h = self.humidity()
        t = self.temperature()
        prev_mode = self.mode
        self.mode = 0
        h = (log(h, 10) - 2) / 0.4343 + (17.62 * t) / (243.12 + t)
        return 243.12 * h / (17.62 - h)

from machine import Pin,I2C
import utime
import aht10

i2c = I2C(0, sda=Pin(8), scl=Pin(9),freq=400000)
devlist = i2c.scan()
print("Address List:",devlist)
for dev in devlist:
    print(hex(dev))

aht10 = aht10.AHT10(i2c, mode=0, address=0x38)

while True:
    humi = aht10.humidity()     # 湿度
    temp = aht10.temperature()  # 温度
    dewp = aht10.dew_point()    # 露点
    aht10.print()
    utime.sleep(1)    

OLED显示AHT10读取值

from machine import Pin,I2C
from ssd1306 import SSD1306_I2C,SSD1306_SPI
import framebuf
import array
import utime
import aht10


i2c = I2C(0, sda=Pin(8), scl=Pin(9),freq=400000)
devlist = i2c.scan()
print("Address List:",devlist)
for dev in devlist:
    print(hex(dev))



# Raspberry Pi logo as 32x32 bytearray
buffer = bytearray(b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00|?\x00\x01\x86@\x80\x01\x01\x80\x80\x01\x11\x88\x80\x01\x05\xa0\x80\x00\x83\xc1\x00\x00C\xe3\x00\x00~\xfc\x00\x00L'\x00\x00\x9c\x11\x00\x00\xbf\xfd\x00\x00\xe1\x87\x00\x01\xc1\x83\x80\x02A\x82@\x02A\x82@\x02\xc1\xc2@\x02\xf6>\xc0\x01\xfc=\x80\x01\x18\x18\x80\x01\x88\x10\x80\x00\x8c!\x00\x00\x87\xf1\x00\x00\x7f\xf6\x00\x008\x1c\x00\x00\x0c \x00\x00\x03\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")

# Load the raspberry pi logo into the framebuffer (the image is 32x32)
fb = framebuf.FrameBuffer(buffer, 32, 32, framebuf.MONO_HLSB)

WIDTH = 128
HEIGHT = 64
oled = SSD1306_I2C(WIDTH,HEIGHT,i2c)
oled.fill(0)
# oled.blit(fb, (128-32)//2, (64-32)//2)
oled.text('RaspberryPi Pico', 0, 0)
oled.hline(0,12, 128, 1)
oled.blit(fb, (128-32), 15)
oled.show()

aht10 = aht10.AHT10(i2c, mode=0, address=0x38)
utime.sleep(1)

while True:
    humi = aht10.humidity()
    temp = aht10.temperature()
    dewp = aht10.dew_point()
    #aht10.print()
    utime.sleep(0.2)
    #oled.fill(0)
    oled.rect(0,15,128-32,45, 0, True)
    oled.text("Temp:{:.2f}C".format(temp), 0, 15)
    oled.text("Humi:{:.2f}%".format(humi), 0, 25)
    oled.text("Dewp:{:.2f}C".format(dewp), 0, 35)
    oled.show()
    
    utime.sleep(1)    
  

在这里插入图片描述

BH1750光照度传感器

bh1750.py

import utime

# BH1750 Library for MicroPython on RP2040
# Author: Song YuLong
# Date: 2022-10-25
# Version 1.0

#CONSTANTS
BH1750_ADDRESS = const (0x23) # 00100011 I2C Slave Address
BH1750_READ_DELAY_MS = 180    # measurement time ms.

BH1750_POWERDOWN =  bytearray([0x00])		# Power Down
BH1750_POWERON   =  bytearray([0x01])		# Power On
BH1750_RESET     =  bytearray([0x07])		# Reset Data Register Value.

# Countinue :
# One Time  : it is automatically set to power down mode after measurement.
BH1750_CONTINUE_H_MODE  = bytearray([0x10]) # Countinue H-Resolution Mode 1lx 120ms
BH1750_CONTINUE_H_MODE2 = bytearray([0x11]) # Countinue H-Resolution Mode 0.5lx 120ms
BH1750_CONTINUE_L_MODE  = bytearray([0x13])	# Countinue L-Resolution Mode 4lx 16ms
BH1750_ONE_TIME_H_MODE  = bytearray([0x20]) # One Time H-Resolution Mode 1lx 120ms
BH1750_ONE_TIME_H_MODE2 = bytearray([0x21]) # One Time H-Resolution Mode 0.5lx 120ms
BH1750_ONE_TIME_L_MODE  = bytearray([0x23]) # One Time L-Resolution Mode 4lx 16ms

class BH1750:
    def __init__(self, i2c, mode=0, address=BH1750_ADDRESS):
        if i2c is None:
            raise ValueError('I2C object required.')
        
        if mode == 0:
            self.mode = BH1750_CONTINUE_H_MODE
        elif mode == 1:
            self.mode = BH1750_CONTINUE_H_MODE2
        elif mode == 2:
            self.mode = BH1750_CONTINUE_L_MODE
        elif mode == 3:
            self.mode = BH1750_ONE_TIME_H_MODE
        elif mode == 4:
            self.mode = BH1750_ONE_TIME_H_MODE2
        elif mode == 5:
            self.mode = BH1750_ONE_TIME_L_MODE
        
        if self.mode == BH1750_CONTINUE_H_MODE2 or self.mode == BH1750_ONE_TIME_H_MODE2:
            self.resolurtion = 0.5
        elif self.mode == BH1750_CONTINUE_H_MODE or self.mode == BH1750_ONE_TIME_H_MODE:
            self.resolurtion = 1
        elif self.mode == BH1750_CONTINUE_L_MODE or self.mode == BH1750_ONE_TIME_L_MODE:
            self.resolurtion = 4
        else:
            raise ValueError('Mode must be 0 ~ 5')
        
        self.i2c = i2c
        self.address = address
        self.i2c.writeto(address, BH1750_POWERDOWN)
        self.i2c.writeto(address, BH1750_POWERON)
        self.i2c.writeto(address, self.mode)
        self.rawdata = bytearray(8)
        self.value = 0.0
        
    def read_raw(self):
        self.i2c.writeto(self.address, self.mode)
        utime.sleep_ms(BH1750_READ_DELAY_MS) # max 160ms
        self.rawdata = self.i2c.readfrom(self.address, 2) 
    
    def illuminance(self):
        # illumination =(reg[15:0] * resolurtion) / 1.2 (unit:lx)
        self.read_raw()
        self.value = ((self.rawdata[0]<<8 | self.rawdata[1]) * self.resolurtion)/1.2
        return self.value
    
    def output(self):
        print("illuminance -->{:.2f}".format(self.value), "LX")
    
    def set_mode(self, mode):
        if mode == 0:
            self.mode = BH1750_CONTINUE_H_MODE
        elif mode == 1:
            self.mode = BH1750_CONTINUE_H_MODE2
        elif mode == 2:
            self.mode = BH1750_CONTINUE_L_MODE
        elif mode == 3:
            self.mode = BH1750_ONE_TIME_H_MODE
        elif mode == 4:
            self.mode = BH1750_ONE_TIME_H_MODE2
        elif mode == 5:
            self.mode = BH1750_ONE_TIME_L_MODE
            
        if self.mode == BH1750_CONTINUE_H_MODE2 or self.mode == BH1750_ONE_TIME_H_MODE2:
            self.resolurtion = 0.5
        elif self.mode == BH1750_CONTINUE_H_MODE or self.mode == BH1750_ONE_TIME_H_MODE:
            self.resolurtion = 1
        elif self.mode == BH1750_CONTINUE_L_MODE or self.mode == BH1750_ONE_TIME_L_MODE:
            self.resolurtion = 4
        else:
            raise ValueError('Mode must be 0 ~ 5')

bh1750_demo.py

from machine import Pin,I2C
import utime
import bh1750

i2c = I2C(0, sda=Pin(8), scl=Pin(9), freq=200000)
devlist = i2c.scan()
print(devlist)
for dev in devlist:
    print(hex(dev))

bh1750 = bh1750.BH1750(i2c, mode=1, address=0x23)

print("BH1750 Demo...")
value = 0.0

while True:
    value = bh1750.illuminance()
    print("illuminance:{:.2f} lx".format(value))
    #bh1750.output()
    utime.sleep(0.1)

BMP280 气压强传感器

bmp280.py

from micropython import const
from ustruct import unpack as unp

# Author David Stenwall Wahlund (david at dafnet.se)

# Power Modes
BMP280_POWER_SLEEP = const(0)
BMP280_POWER_FORCED = const(1)
BMP280_POWER_NORMAL = const(3)

BMP280_SPI3W_ON = const(1)
BMP280_SPI3W_OFF = const(0)

BMP280_TEMP_OS_SKIP = const(0)
BMP280_TEMP_OS_1 = const(1)
BMP280_TEMP_OS_2 = const(2)
BMP280_TEMP_OS_4 = const(3)
BMP280_TEMP_OS_8 = const(4)
BMP280_TEMP_OS_16 = const(5)

BMP280_PRES_OS_SKIP = const(0)
BMP280_PRES_OS_1 = const(1)
BMP280_PRES_OS_2 = const(2)
BMP280_PRES_OS_4 = const(3)
BMP280_PRES_OS_8 = const(4)
BMP280_PRES_OS_16 = const(5)

# Standby settings in ms
BMP280_STANDBY_0_5 = const(0)
BMP280_STANDBY_62_5 = const(1)
BMP280_STANDBY_125 = const(2)
BMP280_STANDBY_250 = const(3)
BMP280_STANDBY_500 = const(4)
BMP280_STANDBY_1000 = const(5)
BMP280_STANDBY_2000 = const(6)
BMP280_STANDBY_4000 = const(7)

# IIR Filter setting
BMP280_IIR_FILTER_OFF = const(0)
BMP280_IIR_FILTER_2 = const(1)
BMP280_IIR_FILTER_4 = const(2)
BMP280_IIR_FILTER_8 = const(3)
BMP280_IIR_FILTER_16 = const(4)

# Oversampling setting
BMP280_OS_ULTRALOW = const(0)
BMP280_OS_LOW = const(1)
BMP280_OS_STANDARD = const(2)
BMP280_OS_HIGH = const(3)
BMP280_OS_ULTRAHIGH = const(4)

# Oversampling matrix
# (PRESS_OS, TEMP_OS, sample time in ms)
_BMP280_OS_MATRIX = [
    [BMP280_PRES_OS_1, BMP280_TEMP_OS_1, 7],
    [BMP280_PRES_OS_2, BMP280_TEMP_OS_1, 9],
    [BMP280_PRES_OS_4, BMP280_TEMP_OS_1, 14],
    [BMP280_PRES_OS_8, BMP280_TEMP_OS_1, 23],
    [BMP280_PRES_OS_16, BMP280_TEMP_OS_2, 44]
]

# Use cases
BMP280_CASE_HANDHELD_LOW = const(0)
BMP280_CASE_HANDHELD_DYN = const(1)
BMP280_CASE_WEATHER = const(2)
BMP280_CASE_FLOOR = const(3)
BMP280_CASE_DROP = const(4)
BMP280_CASE_INDOOR = const(5)

_BMP280_CASE_MATRIX = [
    [BMP280_POWER_NORMAL, BMP280_OS_ULTRAHIGH, BMP280_IIR_FILTER_4, BMP280_STANDBY_62_5],
    [BMP280_POWER_NORMAL, BMP280_OS_STANDARD, BMP280_IIR_FILTER_16, BMP280_STANDBY_0_5],
    [BMP280_POWER_FORCED, BMP280_OS_ULTRALOW, BMP280_IIR_FILTER_OFF, BMP280_STANDBY_0_5],
    [BMP280_POWER_NORMAL, BMP280_OS_STANDARD, BMP280_IIR_FILTER_4, BMP280_STANDBY_125],
    [BMP280_POWER_NORMAL, BMP280_OS_LOW, BMP280_IIR_FILTER_OFF, BMP280_STANDBY_0_5],
    [BMP280_POWER_NORMAL, BMP280_OS_ULTRAHIGH, BMP280_IIR_FILTER_16, BMP280_STANDBY_0_5]
]

_BMP280_REGISTER_ID = const(0xD0)
_BMP280_REGISTER_RESET = const(0xE0)
_BMP280_REGISTER_STATUS = const(0xF3)
_BMP280_REGISTER_CONTROL = const(0xF4)
_BMP280_REGISTER_CONFIG = const(0xF5)  # IIR filter config

_BMP280_REGISTER_DATA = const(0xF7)


class BMP280:
    def __init__(self, i2c_bus, addr=0x76, use_case=BMP280_CASE_HANDHELD_DYN):
        self._bmp_i2c = i2c_bus
        self._i2c_addr = addr

        # read calibration data
        # < little-endian
        # H unsigned short
        # h signed short
        self._T1 = unp('<H', self._read(0x88, 2))[0]
        self._T2 = unp('<h', self._read(0x8A, 2))[0]
        self._T3 = unp('<h', self._read(0x8C, 2))[0]
        self._P1 = unp('<H', self._read(0x8E, 2))[0]
        self._P2 = unp('<h', self._read(0x90, 2))[0]
        self._P3 = unp('<h', self._read(0x92, 2))[0]
        self._P4 = unp('<h', self._read(0x94, 2))[0]
        self._P5 = unp('<h', self._read(0x96, 2))[0]
        self._P6 = unp('<h', self._read(0x98, 2))[0]
        self._P7 = unp('<h', self._read(0x9A, 2))[0]
        self._P8 = unp('<h', self._read(0x9C, 2))[0]
        self._P9 = unp('<h', self._read(0x9E, 2))[0]

        # output raw
        self._t_raw = 0
        self._t_fine = 0
        self._t = 0

        self._p_raw = 0
        self._p = 0
        
        self._h = 0

        self.read_wait_ms = 0  # interval between forced measure and readout
        self._new_read_ms = 200  # interval between
        self._last_read_ts = 0

        if use_case is not None:
            self.use_case(use_case)

    def _read(self, addr, size=1):
        return self._bmp_i2c.readfrom_mem(self._i2c_addr, addr, size)

    def _write(self, addr, b_arr):
        if not type(b_arr) is bytearray:
            b_arr = bytearray([b_arr])
        return self._bmp_i2c.writeto_mem(self._i2c_addr, addr, b_arr)

    def _gauge(self):
        # TODO limit new reads
        # read all data at once (as by spec)
        d = self._read(_BMP280_REGISTER_DATA, 6)

        self._p_raw = (d[0] << 12) + (d[1] << 4) + (d[2] >> 4)
        self._t_raw = (d[3] << 12) + (d[4] << 4) + (d[5] >> 4)

        self._t_fine = 0
        self._t = 0
        self._p = 0
        self._h = 0

    def reset(self):
        self._write(_BMP280_REGISTER_RESET, 0xB6)

    def load_test_calibration(self):
        self._T1 = 27504
        self._T2 = 26435
        self._T3 = -1000
        self._P1 = 36477
        self._P2 = -10685
        self._P3 = 3024
        self._P4 = 2855
        self._P5 = 140
        self._P6 = -7
        self._P7 = 15500
        self._P8 = -14600
        self._P9 = 6000

    def load_test_data(self):
        self._t_raw = 519888
        self._p_raw = 415148

    def print_calibration(self):
        print("T1: {} {}".format(self._T1, type(self._T1)))
        print("T2: {} {}".format(self._T2, type(self._T2)))
        print("T3: {} {}".format(self._T3, type(self._T3)))
        print("P1: {} {}".format(self._P1, type(self._P1)))
        print("P2: {} {}".format(self._P2, type(self._P2)))
        print("P3: {} {}".format(self._P3, type(self._P3)))
        print("P4: {} {}".format(self._P4, type(self._P4)))
        print("P5: {} {}".format(self._P5, type(self._P5)))
        print("P6: {} {}".format(self._P6, type(self._P6)))
        print("P7: {} {}".format(self._P7, type(self._P7)))
        print("P8: {} {}".format(self._P8, type(self._P8)))
        print("P9: {} {}".format(self._P9, type(self._P9)))

    def _calc_t_fine(self):
        # From datasheet page 22
        self._gauge()
        if self._t_fine == 0:
            var1 = (((self._t_raw >> 3) - (self._T1 << 1)) * self._T2) >> 11
            var2 = (((((self._t_raw >> 4) - self._T1)
                      * ((self._t_raw >> 4)
                         - self._T1)) >> 12)
                    * self._T3) >> 14
            self._t_fine = var1 + var2

    @property
    def temperature(self):
        self._calc_t_fine()
        if self._t == 0:
            self._t = ((self._t_fine * 5 + 128) >> 8) / 100.
        return self._t

    @property
    def pressure(self):
        # From datasheet page 22
        self._calc_t_fine()
        if self._p == 0:
            var1 = self._t_fine - 128000
            var2 = var1 * var1 * self._P6
            var2 = var2 + ((var1 * self._P5) << 17)
            var2 = var2 + (self._P4 << 35)
            var1 = ((var1 * var1 * self._P3) >> 8) + ((var1 * self._P2) << 12)
            var1 = (((1 << 47) + var1) * self._P1) >> 33

            if var1 == 0:
                return 0

            p = 1048576 - self._p_raw
            p = int((((p << 31) - var2) * 3125) / var1)
            var1 = (self._P9 * (p >> 13) * (p >> 13)) >> 25
            var2 = (self._P8 * p) >> 19

            p = ((p + var1 + var2) >> 8) + (self._P7 << 4)
            self._p = p / 256.0
        return self._p
    
    @property
    def altitude_p_t(self):
        '''
        Calculate altitude from current temperature and pressure.
        h = ( (((P0/P)^(1/5.257))-1) * (T + 237.15) ) / 0.0065
        h:altitude (m)
        P0:101.325(kPa)
        P:current pressure in kPa
        T:current temperature in Celsius
        '''
        self._h = ( (((101.325/(self._p/1000))**(1/5.257))-1) * (self._t + 273.15) ) / 0.0065
        return self._h
    
    @property
    def altitude_p(self):
        self._h = 44330 * (1 - (((self._p/1000)/101.325)**(1/5.255)))
        return self._h
    
    def _write_bits(self, address, value, length, shift=0):
        d = self._read(address)[0]
        m = int('1' * length, 2) << shift
        d &= ~m
        d |= m & value << shift
        self._write(address, d)

    def _read_bits(self, address, length, shift=0):
        d = self._read(address)[0]
        return d >> shift & int('1' * length, 2)

    @property
    def standby(self):
        return self._read_bits(_BMP280_REGISTER_CONFIG, 3, 5)

    @standby.setter
    def standby(self, v):
        assert 0 <= v <= 7
        self._write_bits(_BMP280_REGISTER_CONFIG, v, 3, 5)

    @property
    def iir(self):
        return self._read_bits(_BMP280_REGISTER_CONFIG, 3, 2)

    @iir.setter
    def iir(self, v):
        assert 0 <= v <= 4
        self._write_bits(_BMP280_REGISTER_CONFIG, v, 3, 2)

    @property
    def spi3w(self):
        return self._read_bits(_BMP280_REGISTER_CONFIG, 1)

    @spi3w.setter
    def spi3w(self, v):
        assert v in (0, 1)
        self._write_bits(_BMP280_REGISTER_CONFIG, v, 1)

    @property
    def temp_os(self):
        return self._read_bits(_BMP280_REGISTER_CONTROL, 3, 5)

    @temp_os.setter
    def temp_os(self, v):
        assert 0 <= v <= 5
        self._write_bits(_BMP280_REGISTER_CONTROL, v, 3, 5)

    @property
    def press_os(self):
        return self._read_bits(_BMP280_REGISTER_CONTROL, 3, 2)

    @press_os.setter
    def press_os(self, v):
        assert 0 <= v <= 5
        self._write_bits(_BMP280_REGISTER_CONTROL, v, 3, 2)

    @property
    def power_mode(self):
        return self._read_bits(_BMP280_REGISTER_CONTROL, 2)

    @power_mode.setter
    def power_mode(self, v):
        assert 0 <= v <= 3
        self._write_bits(_BMP280_REGISTER_CONTROL, v, 2)

    @property
    def is_measuring(self):
        return bool(self._read_bits(_BMP280_REGISTER_STATUS, 1, 3))

    @property
    def is_updating(self):
        return bool(self._read_bits(_BMP280_REGISTER_STATUS, 1))

    @property
    def chip_id(self):
        return self._read(_BMP280_REGISTER_ID, 2)

    @property
    def in_normal_mode(self):
        return self.power_mode == BMP280_POWER_NORMAL

    def force_measure(self):
        self.power_mode = BMP280_POWER_FORCED

    def normal_measure(self):
        self.power_mode = BMP280_POWER_NORMAL

    def sleep(self):
        self.power_mode = BMP280_POWER_SLEEP

    def use_case(self, uc):
        assert 0 <= uc <= 5
        pm, oss, iir, sb = _BMP280_CASE_MATRIX[uc]
        p_os, t_os, self.read_wait_ms = _BMP280_OS_MATRIX[oss]
        self._write(_BMP280_REGISTER_CONFIG, (iir << 2) + (sb << 5))
        self._write(_BMP280_REGISTER_CONTROL, pm + (p_os << 2) + (t_os << 5))

    def oversample(self, oss):
        assert 0 <= oss <= 4
        p_os, t_os, self.read_wait_ms = _BMP280_OS_MATRIX[oss]
        self._write_bits(_BMP280_REGISTER_CONTROL, p_os + (t_os << 3), 2)

bmp280_demo.py

from machine import Pin, I2C
import utime
import bmp280
import math
from ustruct import unpack as unp

i2c = I2C(0, sda=Pin(8), scl=Pin(9), freq=200000)
devlist = i2c.scan()
print(devlist)
for dev in devlist:
    print(hex(dev))

print("BMP280 Demo...")
bmp280 = bmp280.BMP280(i2c_bus=i2c, addr=0x76)
bmp280.use_case(1)
bmp280.oversample(1)
bmp280.iir = 2
bmp280.temp_os=2
bmp280.press_os=2

bmp280.print_calibration()
print(bmp280.chip_id)

    
while True:
    t = bmp280.temperature
    p = bmp280.pressure
    h = bmp280.altitude_p_t	# calculate altitude from pressure and temperature
    h1 = bmp280.altitude_p  # calculate altitude from pressure
    print("P:{:.2f}(kPa)".format(p/1000),"T:{:.2f}(C)".format(t), "H:{:.2f}(m)".format(h), "H1:{:.2f}(m)".format(h1))
    #print(p, t, h, h1)
    utime.sleep(0.5)

运行效果:
在这里插入图片描述

HMC5883L地磁传感器

IC丝印L883为HMC8553L
IC丝印5883为QMC5883L
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

库模块/lib/hmc5883l.py

import math
import machine

from ustruct import pack
from array import array


class HMC5883L:
    __gain__ = {
        '0.88': (0 << 5, 0.73),
        '1.3':  (1 << 5, 0.92),
        '1.9':  (2 << 5, 1.22),
        '2.5':  (3 << 5, 1.52),
        '4.0':  (4 << 5, 2.27),
        '4.7':  (5 << 5, 2.56),
        '5.6':  (6 << 5, 3.03),
        '8.1':  (7 << 5, 4.35)
    }

    def __init__(self, i2c, address=30, gauss='1.3', declination=(0, 0)):
        self.i2c = i2c
        self.address = address

        # Initialize sensor.
        #i2c.start()

        # Configuration register A:
        #   0bx11xxxxx  -> 8 samples averaged per measurement
        #   0bxxx100xx  -> 15 Hz, rate at which data is written to output registers
        #   0bxxxxxx00  -> Normal measurement mode
        i2c.writeto_mem(self.address, 0x00, pack('B', 0b111000))

        # Configuration register B:
        reg_value, self.gain = self.__gain__[gauss]
        i2c.writeto_mem(self.address, 0x01, pack('B', reg_value))

        # Set mode register to continuous mode.
        i2c.writeto_mem(self.address, 0x02, pack('B', 0x00))
        #i2c.stop()

        # Convert declination (tuple of degrees and minutes) to radians.
        self.declination = (declination[0] + declination[1] / 60) * math.pi / 180

        # Reserve some memory for the raw xyz measurements.
        self.data = array('B', [0] * 6)

    def read(self):
        data = self.data
        gain = self.gain

        self.i2c.readfrom_mem_into(self.address, 0x03, data)

        x = (data[0] << 8) | data[1]
        z = (data[2] << 8) | data[3]
        y = (data[4] << 8) | data[5]

        x = x - (1 << 16) if x & (1 << 15) else x
        y = y - (1 << 16) if y & (1 << 15) else y
        z = z - (1 << 16) if z & (1 << 15) else z

        x = round(x * gain, 4)
        y = round(y * gain, 4)
        z = round(z * gain, 4)

        return x, y, z

    def heading(self, x, y):
        heading_rad = math.atan2(y, x)
        heading_rad += self.declination

        # Correct reverse heading.
        if heading_rad < 0:
            heading_rad += 2 * math.pi

        # Compensate for wrapping.
        elif heading_rad > 2 * math.pi:
            heading_rad -= 2 * math.pi

        # Convert from radians to degrees.
        heading = heading_rad * 180 / math.pi
        degrees = math.floor(heading)
        minutes = round((heading - degrees) * 60)
        return degrees, minutes

    def format_result(self, x, y, z):
        degrees, minutes = self.heading(x, y)
        return 'X: {:.4f}, Y: {:.4f}, Z: {:.4f}, Heading: {}° {}′ '.format(x, y, z, degrees, minutes)

hmc5883l_demo.py

from machine import Pin,I2C
import utime
from hmc5883l import HMC5883L
from ssd1306 import SSD1306_I2C,SSD1306_SPI

i2c0 = I2C(0, sda=Pin(8), scl=Pin(9),freq=400000)
devlist = i2c0.scan()
print("I2C0 Address List:",devlist)
for dev in devlist:
    print(hex(dev))
      
mSensor = HMC5883L(i2c0, address=0x1e, gauss='1.3')


while True:
    x, y, z = mSensor.read()
    print(mSensor.format_result(x, y, z))
    utime.sleep(0.1)

MCP4725数模转换

在这里插入图片描述
/lib/mcp4725.py

#Library for the MCP4725 I2C bus DAC 
from machine import I2C

#The MCP4725 has support from 2 addresses
BUS_ADDRESS = [0x60,0x62,0x63]

#The device supports a few power down modes on startup and during operation 
POWER_DOWN_MODE = {'Off':0, '1k':1, '100k':2, '500k':3}
        
class MCP4725:
    def __init__(self,i2c, address=BUS_ADDRESS[0]) :
        self.i2c=i2c
        self.address=address
        self._writeBuffer=bytearray(2)
        
    def write(self,value):
        if value < 0:
            value=0
        value=value & 0xFFF
        self._writeBuffer[0]=(value>>8) & 0xFF
        self._writeBuffer[1]=value & 0xFF
        return self.i2c.writeto(self.address,self._writeBuffer)==2

    def read(self):
        buf=bytearray(5)
        if self.i2c.readfrom_into(self.address,buf) ==5:
            eeprom_write_busy=(buf[0] & 0x80)==0
            power_down=self._powerDownKey((buf[0] >> 1) & 0x03)
            value=((buf[1]<<8) | (buf[2])) >> 4
            eeprom_power_down=self._powerDownKey((buf[3]>>5) & 0x03)
            eeprom_value=((buf[3] & 0x0f)<<8) | buf[4] 
            return (eeprom_write_busy,power_down,value,eeprom_power_down,eeprom_value)
        return None

    def config(self,power_down='Off',value=0,eeprom=False):
        buf=bytearray()
        conf=0x40 | (POWER_DOWN_MODE[power_down] << 1)
        if eeprom:
            #store the powerdown and output value in eeprom
            conf=conf | 0x60
        buf.append(conf)
        #check value range
        if value<0:
            value=0
        value=value & 0xFFF
        buf.append(value >> 4)
        buf.append((value & 0x0F)<<4)
        return self.i2c.writeto(self.address,buf)==3

    def _powerDownKey(self,value):
        for key,item in POWER_DOWN_MODE.items():
            if item == value:
                return key

mcp4725_demo.py

from machine import Pin,I2C
import mcp4725
import utime
import math
import machine


i2c0 = I2C(0, sda=Pin(8), scl=Pin(9), freq=400000)

devlist = i2c0.scan()
print(devlist)
for dev in devlist:
    print(hex(dev))

#create the MCP4725 driver
dac=mcp4725.MCP4725(i2c0,mcp4725.BUS_ADDRESS[0])

#configure the DAC to output ``Vdd/2`` on power-up or after a reset
#dac.config('Off',2048, eeprom=True)

#configure the DAC to go into power-down mode and set the output value to maximum output.
dac.config('100k',4096)
print(dac.read())

x = 0
value = 0
updown = True

while True:
#     print(value)
    dac.write(value)
    # 正弦波
    value = 2048+int(math.sin(x)*2048)
    x += 0.01
    if x >= 360:
        x = 0.0
    
    
    # 方波
    '''
    if value == 0:
        value = 4095
    else:
        value = 0
    '''
    
    # 锯齿波 正
    '''
    if value < 4096:
        value += 1
    elif value == 4096:
        value=0
    '''
    # 锯齿波 反
    '''
    if value > 0:
        value -= 1
    elif value <= 0:
        value = 4095  
    '''
    # 三角波
    '''
    if updown :
        value+=1
    else:
        value-=1
        
    if value == 4096:
        updown = False
    elif value == 0:
        updown = True
    '''        

正弦波
在这里插入图片描述
方波
在这里插入图片描述
锯齿波
在这里插入图片描述
在这里插入图片描述
三角波

在这里插入图片描述

GNSS导航模块

在这里插入图片描述
在这里插入图片描述

navigation.py

#
#  songyulong
#  2022-11-03
#  GNSS 模块库
#  GNSS(Global Navigation Satellite System) 的全称是全球导航卫星系统


# 保存配置参数命令 CAS00
CMD_SAVE_CONFIG = const(b'$PCAS00*01\r\n')  # save configuration information to flash

# 串口通信波特率设置命令 CAS01
CMD_SET_BAUDRATE_4800bps  = const(b'$PCAS01,0*1C\r\n')
CMD_SET_BAUDRATE_9600bps  = const(b'$PCAS01,1*1D\r\n')
CMD_SET_BAUDRATE_19200bps = const(b'$PCAS01,2*1E\r\n')
CMD_SET_BAUDRATE_38400bps = const(b'$PCAS01,3*1F\r\n')
CMD_SET_BAUDRATE_57600bps = const(b'$PCAS01,4*18\r\n')
CMD_SET_BAUDRATE_115200bps= const(b'$PCAS01,5*19\r\n')

# 设定定位更新率 CAS02
CMD_SET_UPDATE_FREQ_1HZ = const(b'$PCAS02,1000*2E\r\n')
CMD_SET_UPDATE_FREQ_2HZ = const(b'$PCAS02,500*1A\r\n')
CMD_SET_UPDATE_FREQ_4HZ = const(b'$PCAS02,250*18\r\n')
CMD_SET_UPDATE_FREQ_5HZ = const(b'$PCAS02,200*1D\r\n')
CMD_SET_UPDATE_FREQ_10HZ= const(b'$PCAS02,100*1E\r\n')

# 设置要求输出或停止输出的 NMEA 语句。CAS03

# 配置工作系统 CAS04  GPS:美国,BDS:中国, GLONASS:俄罗斯
CMD_SET_SYS_GPS              = const(b'$PCAS04,1*18\r\n') 
CMD_SET_SYS_BDS              = const(b'$PCAS04,2*1B\r\n')  
CMD_SET_SYS_GPS_BDS          = const(b'$PCAS04,3*1A\r\n')  
CMD_SET_SYS_GLONASS          = const(b'$PCAS04,4*1D\r\n')
CMD_SET_SYS_GPS_GLONASS      = const(b'$PCAS04,5*1C\r\n')
CMD_SET_SYS_BDS_GLONASS      = const(b'$PCAS04,6*1F\r\n')
CMD_SET_SYS_GPS_BDS_GLONASS  = const(b'$PCAS04,7*1E\r\n')

# 接收机重启 CAS10
CMD_RESTART_Hot     = const(b'$PCAS10,0*1C\r\n') # 热启动 :不使用初始化信息,备份存储中的所有数据有效
CMD_RESTART_Warm    = const(b'$PCAS10,1*1D\r\n') # 温启动 :不使用初始化信息,清除星历
CMD_RESTART_Cold    = const(b'$PCAS10,2*1E\r\n') # 冷启动 :不使用初始化信息,清除备份存储中除配置外的所有数据。
CMD_RESTART_Factory = const(b'$PCAS10,3*1F\r\n') # 出厂启动 :清除内存所有数据,并将接收机复位至出厂默认配置



class NAVIGATION:
    def __init__(self, uart, mode=CMD_SET_SYS_GPS_BDS, update_freq=CMD_SET_UPDATE_FREQ_1HZ):
        self.uart = uart
        self.mode = mode
        self.update_freq = update_freq
        self.longitude = 0
        self.latitude = 0
        self.speed = 0
        self.course = 0
        self.year = 0
        self.month = 0
        self.day = 0
        self.hour = 0
        self.minute = 0
        self.second = 0
        self.rxbuf = bytes()
        self.send_command(self.mode)
        self.send_command(self.update_freq)
        
    def deinit(self):
        self.uart.deinit()
        
    def send_command(self, cmd):
        self.uart.write(cmd)
        
    def recv_loop(self):
        while self.uart.any() > 0:
            #self.rxbuf=self.uart.readline()
            #self.parse_message(self.rxbuf)            
            c = self.uart.read(1)
            self.rxbuf += c
            if c == b'\n': # 一行报文结收结束
                self.parse_message(self.rxbuf)
                self.rxbuf = b''
    
    def parse_message(self,msg):
        try:
            root = msg.decode('utf-8')
            #print(root)
            if (root.startswith('$GNRMC') or root.startswith('$BDRMC') or root.startswith('$GPRMC')): #                 
                GNRMC = root.split(',')
                if GNRMC[2] == 'A':  # 'A':有效, 'V':无效
                    #print(GNRMC)
                    self.hour = int(GNRMC[1][0:2])
                    self.minute = int(GNRMC[1][2:4])
                    self.second = int(GNRMC[1][4:6])
                    #ms = int(GNRMC[1][7:10])
                    
                    self.day = int(GNRMC[9][0:2])
                    self.month = int(GNRMC[9][2:4])
                    self.year = int(GNRMC[9][4:6])

                    if GNRMC[4] == 'N': # 北纬
                        self.latitude = float(GNRMC[3])                        
                    elif GNRMC[4] == 'S': # 南纬
                        self.latitude = -(float(GNRMC[3]))
                        
                    if GNRMC[6] == 'E': # 东经
                        self.longitude = float(GNRMC[5])
                    elif GNRMC[6] == 'W': # 西经
                        self.longitude = -(float(GNRMC[5]))
                        
                    self.speed = float(GNRMC[7])
                    self.course = float(GNRMC[8])
                    #print(self.longitude, self.latitude, self.speed, self.course)
                else:
                    self.latitude = 0
                    self.longitude = 0
                
            elif (root.startswitch('$BDGSV')):
                print('BDGSV')
        except:
            pass
    pass

from machine import Pin,I2C,UART
from ssd1306 import SSD1306_I2C,SSD1306_SPI
import framebuf

import utime
import navigation
from navigation import *
import _thread

i2c0 = I2C(0, sda=Pin(8), scl=Pin(9),freq=400000)
WIDTH = 128
HEIGHT = 64
oled = SSD1306_I2C(WIDTH,HEIGHT,i2c0)
oled.fill(0)

uart0 = UART(1, baudrate=9600, bits=8, parity=None, stop=1, tx=Pin(4), rx=Pin(5), )
nav = navigation.NAVIGATION(uart0)
nav.send_command(CMD_SET_SYS_BDS)
nav.send_command(CMD_SET_UPDATE_FREQ_1HZ)

# 导航模块结束数据任务
def navigation_task(delay):
    while True:
        nav.recv_loop()
        utime.sleep_ms(delay)
        
_thread.start_new_thread(navigation_task, (1,) )
utime.sleep(1.5)

while True:
    #nav.recv_loop()
    oled.fill(0)
    oled.text("Lat:{:.4f}".format(nav.latitude), 0, 0)
    oled.text("Lon:{:.4f}".format(nav.longitude), 0, 10)
    oled.text("Speed:{:.2f}".format(nav.speed), 0, 20)
    oled.text("Course:{:.2f}".format(nav.course), 0, 30)
    oled.text("{:02d}/{:02d}/{:02d}".format(nav.year, nav.month, nav.day), 0, 40)
    oled.text("{:02d}:{:02d}:{:02d}".format(nav.hour+8, nav.minute, nav.second), 0, 50)
    oled.show()
    #print("main loop....", nav.longitude, nav.latitude, nav.speed, nav.course)
    utime.sleep(1)

在这里插入图片描述

无线串口模块(LoRa 433M)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
简单数据透传Demo

from machine import Pin,UART
import utime

class WIRELESS_UART:
    def __init__(self, uart, m0, m1, aux=-1, mode=0):
        self.uart = uart
        self.mode = mode
        self.m0 = Pin(m0, Pin.OUT)
        self.m1 = Pin(m1, Pin.OUT)
        if aux >= 0:
            self.aux = Pin(aux, Pin.IN)
        self.set_mode(mode)
        self.rxbuf = bytes()
        
    def set_mode(self, mode):
        self.mode = mode
        if self.mode == 0:
            self.m0.value(0)
            self.m1.value(0)
        elif self.mode == 1:
            self.m0.value(1)
            self.m1.value(0)
        elif self.mode == 2:
            self.m0.value(0)
            self.m1.value(1)
        elif self.mode == 3:
            self.m0.value(1)
            self.m1.value(1)
        else:
            print('Error mode must be in 0 ~ 3')
            
    def write(self, data):
        self.uart.write(data)
        
    def recv_loop(self):
        while self.uart.any() > 0:
            #self.rxbuf=self.uart.readline()
            #self.parse_message(self.rxbuf)            
            c = self.uart.read(1)
            self.rxbuf += c
            if c == b'\n': # 一行报文结收结束
                print(self.rxbuf)
                self.uart.write(b'\n'+self.rxbuf)
                self.rxbuf = b''    
        
uart0 = UART(0, baudrate=9600, bits=8, parity=None, stop=1, tx=Pin(16), rx=Pin(17) )    
wuart = WIRELESS_UART(uart=uart0, m0=19, m1=18, aux=-1, mode=0)        
wuart.set_mode(0) # mode:0,1,2,3

while True:
    #wuart.write(b'good')
    wuart.recv_loop()
    utime.sleep_ms(10)

支持参数配置Demo

from machine import Pin,UART
import utime
import struct


CMD_READ_CONFIG = bytes([0xC1,0xC1,0xC1]) # 读取模块配置参数,比如:C0 00 00 18 50 44。
CMD_READ_INFO = bytes([0xC3,0xC3,0xC3]) # 读取模块版本信息,比如:C3 30 xx yy;30表示E30系列,
CMD_RESET = bytes([0xC4,0xC4,0xC4]) # 复位模块

# 串口校验模式
UART_8N1 = 0x00<<6
UART_8O1 = 0x01<<6
UART_8E1 = 0x02<<6

# 串口波特率
BAUDRATE_1200   = 0x00<<3
BAUDRATE_2400   = 0x01<<3
BAUDRATE_4800   = 0x02<<3
BAUDRATE_9600   = 0x03<<3
BAUDRATE_19200  = 0x04<<3
BAUDRATE_38400  = 0x05<<3
BAUDRATE_57600  = 0x06<<3
BAUDRATE_115200 = 0x07<<3

# 无线空中速率
AIRRATE_1KBPS = 0x00
AIRRATE_2KBPS = 0x01
AIRRATE_5KBPS = 0x02
AIRRATE_8KBPS = 0x03
AIRRATE_10KBPS = 0x04
AIRRATE_15KBPS = 0x05
AIRRATE_20KBPS = 0x06
AIRRATE_25KBPS = 0x07


# 定点发生使能
TRS_MODE = 0x00<<7
FIX_MODE = 0x01<<7

# IO驱动
IO_PPO = 0x01<<6 # Push-Pull Output 推挽输出
IO_ODO = 0x00<<6 # Open Drain Output 开漏输出

WAKEUP_250MS  = 0x00<<3
WAKEUP_500MS  = 0x01<<3
WAKEUP_750MS  = 0x02<<3
WAKEUP_1000MS = 0x03<<3
WAKEUP_1250MS = 0x04<<3
WAKEUP_1500MS = 0x05<<3
WAKEUP_1750MS = 0x06<<3
WAKEUP_2000MS = 0x07<<3

# FEC开关
FEC_ON = 0x01<<2
FEC_OFF = 0x00<<2

# 发射功率
POWER_10dBm = 0x00
POWER_9dBm  = 0x01
POWER_8dBm  = 0x02
POWER_7dBm  = 0x03



class WIRELESS_UART:
    def __init__(self, uart, m0, m1, aux=-1, mode=0):
        self.uart = uart
        self.mode = mode
        self.m0 = Pin(m0, Pin.OUT)
        self.m1 = Pin(m1, Pin.OUT)
        if aux >= 0:
            self.aux = Pin(aux, Pin.IN)
        self.HEAD = 0xC2 # 0xC0:设置参数到ROM, 0xC2:设置参数到RAM
        self.ADDH = 0x00 # 地址高字节 00H-FFH
        self.ADDL = 0x00 # 地址低字节 00H-FFH
        self.SPED = UART_8N1|BAUDRATE_9600|AIRRATE_1KBPS # 速率参数
        self.CHAN = 0xFF # 通信频率 信道
        self.OPTION = TRS_MODE|IO_PPO|WAKEUP_250MS|FEC_ON|POWER_10dBm  #选项
        print(self.SPED, self.OPTION)
        self.set_mode(mode)
        self.rxbuf = bytes()
        self.recv = bytes()
        
    def send_configurate(self, save=False):
        mode = self.mode
        self.set_mode(3)
        utime.sleep_ms(100)
        if save==True:
            self.HEAD = 0xC0
        else:
            self.HEAD = 0xC2
        cmd = bytearray([self.HEAD, self.ADDH, self.ADDL, self.SPED, self.CHAN, self.OPTION])
        print(cmd)
        self.uart.write(cmd)
        utime.sleep_ms(200)
        self.set_mode(mode)
        
    def set_mode(self, mode):
        self.mode = mode
        # mode_0: 一般模式
        # mode_1: 唤醒模式
        # mode_2: 省电模式
        # mode_3: 休眠模式
        if self.mode == 0:
            self.m0.value(0)
            self.m1.value(0)
        elif self.mode == 1:
            self.m0.value(1)
            self.m1.value(0)
        elif self.mode == 2:
            self.m0.value(0)
            self.m1.value(1)
        elif self.mode == 3:
            self.m0.value(1)
            self.m1.value(1)
        else:
            print('Error mode must be in 0 ~ 3')
    
    def read_configurate(self):
        mode = self.mode
        self.set_mode(3)
        self.uart.write(CMD_READ_CONFIG)
        utime.sleep_ms(200)
        recv = bytes()
        while self.uart.any():
            recv +=  self.uart.read(1)
        self.set_mode(mode)
        print(len(recv))
        if len(recv)>=6:
            umode = (recv[3]&0xC0)>>6 # [7,6] 串口校验位模式
            ubsp = (recv[3]&0x38)>>3 # [5,4,3] TTL串口速率(bps)
            wbps = (recv[3]&0x07)    # [2,1,0] 无线空中速率(bps)
            freq = 425+(int(recv[4]) * 0.1) # 通信频率 425M+CHAN*0.1M  00H-FFH,对应425~455MHz
            fcc = (recv[5]&0x04)>>2 #[2] FCC开关 0:关闭FCC, 1:打开FCC
            dBm = (recv[5]&0x03) #[1,0] 发射功率
            print('----------Configurate-------------')
            print('-- head {:#X}'.format(recv[0]))
            print('-- ADDH {:#X}'.format(recv[1]))
            print('-- ADDL {:#X}'.format(recv[2]))
            print('-- SPEED:{:x}'.format(umode))
            print('-- ubsp:{:x}'.format(ubsp))
            print('-- wbps:{:x}'.format(wbps))
            print('-- ch:{:x}'.format(recv[4]))
            print('-- freq:{:d}MHz'.format(freq))
            print('-- option:{:x}'.format(recv[5]))
            print('-- FCC:{:d}'.format(fcc))
            print('-- dBm:{:d}dBm'.format(dBm))
            
        else:
            print('error configuarte head')
        
        return recv
    
    def write(self, data):
        self.uart.write(data)
        
    def recv_loop(self):
        while self.uart.any() > 0:
            #self.rxbuf=self.uart.readline()
            #self.parse_message(self.rxbuf)            
            c = self.uart.read(1)
            self.rxbuf += c
            #print(c)
            if c == b'\n': # 一行报文结收结束
                print(self.rxbuf)
                self.uart.write(b'\n'+self.rxbuf)
                self.rxbuf = b''    
        
uart0 = UART(0, baudrate=9600, bits=8, parity=None, stop=1, tx=Pin(16), rx=Pin(17) )    
wuart = WIRELESS_UART(uart=uart0, m0=19, m1=18, aux=-1, mode=0)        

wuart.set_mode(0)

wuart.send_configurate(False)
utime.sleep(1)
ret = wuart.read_configurate()
for r in ret:
    print(r)

utime.sleep(1)
while True:
    #wuart.write(b'good')
    wuart.recv_loop()
    utime.sleep_ms(100)

旋转编码器

在这里插入图片描述

from machine import Pin
import utime

key = Pin(18, Pin.IN)
rotary_clk = Pin(19, Pin.IN)
rotary_dt  = Pin(20, Pin.IN)

def rotary_encoder_task(pin):
    # 当CLK下降沿时,DT是低电平:顺时针旋转,DT是高电平:逆时针旋转
    if rotary_dt.value() == 0:
        print('----right---')
    else:
        print('----left---')
    
rotary_clk.irq(trigger=Pin.IRQ_FALLING, handler=rotary_encoder_task)

# 当按键按下或抬起时会有抖动,这里增加个变量以便过滤掉干扰脉冲
key_pressed = False
def key_task(pin):
    global key_pressed
    if key_pressed == False:
        if key.value()==0:
            key_pressed = True
            print('key down')
    elif key_pressed == True:
        if key.value()==1:
            key_pressed = False
            print('key up')
        
key.irq(trigger=Pin.IRQ_FALLING|Pin.IRQ_RISING, handler=key_task)

while True:
    utime.sleep(0.5)

在这里插入图片描述

步进电机

在这里插入图片描述

2相4线步进电机

from machine import Pin,PWM
import machine
import utime

delay_ms = 2

# 四个引脚各一根控制线:A~H表示各线时序
#         A     B     C     D     E     F     G     H
# A+      1     1     0     0     0     0     0     1
# A-      0     0     0     1     1     1     0     0
# B+      0     1     1     1     0     0     0     0
# B-      0     0     0     0     0     1     1     1


AP = Pin(32, Pin.OUT)
BP = Pin(33, Pin.OUT)
AN = Pin(25, Pin.OUT)
BN = Pin(26, Pin.OUT)

AP.value(0)
BP.value(0)
AN.value(0)
BN.value(0)

def motor_step(step=0, delay_ms=1):
    if step == 0:
        # A S1: 1 0 0 0
        AP.value(1)
        AN.value(0)
        BP.value(0)
        BN.value(0)    
    elif step == 1:
        # B S2: 1 0 1 0
        AP.value(1)
        AN.value(0)
        BP.value(1)
        BN.value(0)
    elif step == 2:
        # C S3: 0 0 1 0
        AP.value(0)
        AN.value(0)
        BP.value(1)
        BN.value(0)
    elif step == 3:
        # D S4: 0 1 1 0
        AP.value(0)
        AN.value(1)
        BP.value(1)
        BN.value(0)
    elif step == 4:
        # E S5: 0 1 0 0
        AP.value(0)
        AN.value(1)
        BP.value(0)
        BN.value(0)
    elif step == 5:
        # F S6: 0 1 0 1
        AP.value(0)
        AN.value(1)
        BP.value(0)
        BN.value(1)
    elif step == 6:
        # G S7: 0 0 0 1
        AP.value(0)
        AN.value(0)
        BP.value(0)
        BN.value(1)
    elif step == 7:
        # H S8: 1 0 0 1
        AP.value(1)
        AN.value(0)
        BP.value(0)
        BN.value(1)
    utime.sleep_ms(delay_ms)

def motor_control(dir=0, speed=1):
    if dir == 0:
        # 逆时针 旋转 step 7 ~ 0
        for i in range(0, 7):
            motor_step(7-i, speed)
    else:
        # 逆时针 旋转 step 0 ~ 7
        for i in range(0, 7):
            motor_step(i, speed)
    
    
while True:
    #motor_control(0, 2) # 逆时针
    motor_control(1, 2) # 顺时针

4相5线步进电机

from machine import Pin,PWM
import machine
import utime

class step_motor():
    '''
    引脚线序:A~H时序,45线共阳接法,8拍控制时序
    +-------------------------------------------------------+    
    |      |  A  |  B  |  C  |  D  |  E  |  F  |  G  |  H   |
    +-------------------------------------------------------|
    |COM      +     +     +     +     +     +     +     +   |
    |  A      0     0     1     1     1     1     1     0   |
    |  B      1     0     0     0     1     1     1     1   |
    |  C      1     1     1     0     0     0     1     1   |
    |  D      1     1     1     1     1     0     0     0   |
    +-------------------------------------------------------+
    '''
    def __init__(self, a, b, c, d):
        self._a = Pin(a, Pin.OUT)
        self._b = Pin(b, Pin.OUT)
        self._c = Pin(c, Pin.OUT)
        self._d = Pin(d, Pin.OUT)
        
    def one_step(self, step=0, delay_ms=1):
        if step == 0:
            # A S1: 0 1 1 1
            self._a.value(0)
            self._b.value(1)
            self._c.value(1)
            self._d.value(1)    
        elif step == 1:
            # B S2: 0 0 1 1
            self._a.value(0)
            self._b.value(0)
            self._c.value(1)
            self._d.value(1)  
        elif step == 2:
            # C S3: 1 0 1 1
            self._a.value(1)
            self._b.value(0)
            self._c.value(1)
            self._d.value(1)  
        elif step == 3:
            # D S4: 1 0 0 1
            self._a.value(1)
            self._b.value(0)
            self._c.value(0)
            self._d.value(1)  
        elif step == 4:
            # E S5: 1 1 0 1
            self._a.value(1)
            self._b.value(1)
            self._c.value(0)
            self._d.value(1)  
        elif step == 5:
            # F S6: 1 1 0 0
            self._a.value(1)
            self._b.value(1)
            self._c.value(0)
            self._d.value(0)
        elif step == 6:
            # G S7: 1 1 1 0
            self._a.value(1)
            self._b.value(1)
            self._c.value(1)
            self._d.value(0)  
        elif step == 7:
            # H S8: 0 1 1 0
            self._a.value(0)
            self._b.value(1)
            self._c.value(1)
            self._d.value(0)  
        utime.sleep_ms(delay_ms)
        
    def motor_control(self, dir=0, speed=1):
        if dir == 0:
            # 逆时针 旋转 step 0 ~ 7
            for i in range(0, 7):
                self.one_step(i, speed)            
        else:
            # 逆时针 旋转 step 7 ~ 0
            for i in range(0, 7):
                self.one_step(7-i, speed)
                                
    def go_steps(self, dir=0, steps=0, speed=1):
        for i in range(steps):
            if dir == 0:
                self.one_step(7-(i%8), speed)
            else:
                self.one_step((i%8), speed)
        
        
        
motor = step_motor(0, 2, 15, 13)

# 此电机转速比 1:64
# 步距角度:5.625/64=0.087890625度
# 360/0.087890625=4096个脉冲
# motor_control执行一次产生8个脉冲,4096/8=512

# motor_control执行512次,电机输出刚好旋转一圈360角度
for i in range(512*5): #
    motor.motor_control(1, 2)


# 走4096步,电机输出转一圈
motor.go_steps(1, 4096, 2)

while True:
    utime.sleep(1)
#    motor.motor_control(0, 2)
#    motor.motor_control(1, 1)

INA219电流/电源监测模块

INA219 是一款具备 I2C 或 SMBUS 兼容接口的分流器和功率监测计。该器件监测分流器电压降和总线电源电压,转换次数和滤波选项可通过编程设定。可编程校准值与内部乘法器相结合,支持直接读取电流值(单位:安培)。通过附加乘法寄存器可计算功率(单位:瓦)。I2C 或 SMBUS 兼容接口 具有 16 个可编程地址。INA219 可在 0V 至 26V 范围内感测总线中的分压。该器件由 3V 至 5.5V 单电源供电,电源的最大流耗为1mA。INA219 的工作温度范围为 -40°C 至 125°C。

特性:

  • 监测电压范围:0V 至 26V
  • 可监测电流、电压、和功率
  • 16 个可编程地址
  • 高精度:整个温度范围内的精度为 0.5%(最大
    值)(INA219B)
  • 滤波选项
  • 校准寄存器
    在这里插入图片描述

Demo

from machine import Pin,UART,ADC,I2C
import machine
import utime
import _thread
import struct
import math
import ws2812b

from ssd1306 import SSD1306_I2C,SSD1306_SPI
import framebuf
import array
import utime

from ina219 import INA219,DeviceRangeError


i2c0 = I2C(0, sda=Pin(0), scl=Pin(1),freq=400000)
devlist = i2c0.scan()
print("I2C0 Address List:",devlist)
for dev in devlist:
    print(hex(dev))

i2c1 = I2C(1, sda=Pin(6), scl=Pin(7),freq=400000)
devlist = i2c1.scan()
print("I2C1 Address List:",devlist)
for dev in devlist:
    print(hex(dev))
    
# Raspberry Pi logo as 32x32 bytearray
buffer = bytearray(b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00|?\x00\x01\x86@\x80\x01\x01\x80\x80\x01\x11\x88\x80\x01\x05\xa0\x80\x00\x83\xc1\x00\x00C\xe3\x00\x00~\xfc\x00\x00L'\x00\x00\x9c\x11\x00\x00\xbf\xfd\x00\x00\xe1\x87\x00\x01\xc1\x83\x80\x02A\x82@\x02A\x82@\x02\xc1\xc2@\x02\xf6>\xc0\x01\xfc=\x80\x01\x18\x18\x80\x01\x88\x10\x80\x00\x8c!\x00\x00\x87\xf1\x00\x00\x7f\xf6\x00\x008\x1c\x00\x00\x0c \x00\x00\x03\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")

# Load the raspberry pi logo into the framebuffer (the image is 32x32)
fb = framebuf.FrameBuffer(buffer, 32, 32, framebuf.MONO_HLSB)

WIDTH = 128
HEIGHT = 64

try:
    oled = SSD1306_I2C(WIDTH,HEIGHT,i2c0)    
except:
    pass

oled.fill(0)
# oled.blit(fb, (128-32)//2, (64-32)//2)
#oled.text('RaspberryPi Pico', 0, 0)
#oled.hline(0,12, 128, 1)
#oled.blit(fb, (128-32), 15)
#oled.show()


# 分路电阻值,单位为欧姆(强制)
SHUNT_OHMS = 0.1

# 以安培为单位的最大预期电流(可选)
MAX_EXPECTED_AMPS = 3 #1
 
# 电阻值,通讯协议,电流值
ina = INA219(SHUNT_OHMS, i2c0, MAX_EXPECTED_AMPS)
 
# 配置和校准INA219的测量方式OUT输出12位
#ina.configure(ina.RANGE_32V)
ina.configure(voltage_range=ina.RANGE_32V, gain=ina.GAIN_AUTO,
                  bus_adc=ina.ADC_16SAMP, shunt_adc=ina.ADC_16SAMP)

while True:
    voltage = ina.voltage()
    current = ina.current()
    power = ina.power()
    shunt = ina.shunt_voltage()
    
    print("电压:", voltage, "V")
    print("电流:", current, "mA")
    print("功率:", power, "mW")
    print("分压:", shunt, "mV")
    
    oled.fill(0)
    oled.text("Voltage:{:.2f}V".format(voltage), 0, 0)
    oled.text("Current:{:.2f}mA".format(current), 0, 12)
    oled.text("Power:{:.2f}mW".format(power), 0, 12*2)
    oled.text("shunt:{:.2f}mV".format(shunt), 0, 12*3)
    oled.show()
    utime.sleep(0.2)

驱动库文件:ina219.py

"""MicroPython library for the INA219 sensor.
This library supports the INA219 sensor from Texas Instruments with
MicroPython using the I2C bus.
"""

import utime
from math import trunc
from micropython import const
 
 
class INA219:
    """Provides all the functionality to interact with the INA219 sensor."""
 
    RANGE_16V = const(0)  # Range 0-16 volts
    RANGE_32V = const(1)  # Range 0-32 volts
 
    GAIN_1_40MV = const(0)  # Maximum shunt voltage 40mV
    GAIN_2_80MV = const(1)  # Maximum shunt voltage 80mV
    GAIN_4_160MV = const(2)  # Maximum shunt voltage 160mV
    GAIN_8_320MV = const(3)  # Maximum shunt voltage 320mV
    GAIN_AUTO = const(-1)  # Determine gain automatically
 
    ADC_9BIT = const(0)  # 9-bit conversion time  84us.
    ADC_10BIT = const(1)  # 10-bit conversion time 148us.
    ADC_11BIT = const(2)  # 11-bit conversion time 2766us.
    ADC_12BIT = const(3)  # 12-bit conversion time 532us.
    ADC_2SAMP = const(9)  # 2 samples at 12-bit, conversion time 1.06ms.
    ADC_4SAMP = const(10)  # 4 samples at 12-bit, conversion time 2.13ms.
    ADC_8SAMP = const(11)  # 8 samples at 12-bit, conversion time 4.26ms.
    ADC_16SAMP = const(12)  # 16 samples at 12-bit,conversion time 8.51ms
    ADC_32SAMP = const(13)  # 32 samples at 12-bit, conversion time 17.02ms.
    ADC_64SAMP = const(14)  # 64 samples at 12-bit, conversion time 34.05ms.
    ADC_128SAMP = const(15)  # 128 samples at 12-bit, conversion time 68.10ms.
 
    __ADC_CONVERSION = {
        ADC_9BIT: "9-bit",
        ADC_10BIT: "10-bit",
        ADC_11BIT: "11-bit",
        ADC_12BIT: "12-bit",
        ADC_2SAMP: "12-bit, 2 samples",
        ADC_4SAMP: "12-bit, 4 samples",
        ADC_8SAMP: "12-bit, 8 samples",
        ADC_16SAMP: "12-bit, 16 samples",
        ADC_32SAMP: "12-bit, 32 samples",
        ADC_64SAMP: "12-bit, 64 samples",
        ADC_128SAMP: "12-bit, 128 samples"
    }
 
    __ADDRESS = 0x40
 
    __REG_CONFIG = 0x00
    __REG_SHUNTVOLTAGE = 0x01
    __REG_BUSVOLTAGE = 0x02
    __REG_POWER = 0x03
    __REG_CURRENT = 0x04
    __REG_CALIBRATION = 0x05
 
    __RST = 15
    __BRNG = 13
    __PG1 = 12
    __PG0 = 11
    __BADC4 = 10
    __BADC3 = 9
    __BADC2 = 8
    __BADC1 = 7
    __SADC4 = 6
    __SADC3 = 5
    __SADC2 = 4
    __SADC1 = 3
    __MODE3 = 2
    __MODE2 = 1
    __MODE1 = 0
 
    __OVF = 1
    __CNVR = 2
 
    __BUS_RANGE = [16, 32]
    __GAIN_VOLTS = [0.04, 0.08, 0.16, 0.32]
 
    __CONT_SH_BUS = 7
 
    __AMP_ERR_MSG = ('Expected current %.3fA is greater '
                     'than max possible current %.3fA')
    __RNG_ERR_MSG = ('Expected amps %.2fA, out of range, use a lower '
                     'value shunt resistor')
    __VOLT_ERR_MSG = ('Invalid voltage range, must be one of: '
                      'RANGE_16V, RANGE_32V')
 
    __LOG_FORMAT = '%(asctime)s - %(levelname)s - INA219 %(message)s'
    __LOG_MSG_1 = ('shunt ohms: %.3f, bus max volts: %d, '
                   'shunt volts max: %.2f%s, '
                   'bus ADC: %s, shunt ADC: %s')
    __LOG_MSG_2 = ('calibrate called with: bus max volts: %dV, '
                   'max shunt volts: %.2fV%s')
    __LOG_MSG_3 = ('Current overflow detected - '
                   'attempting to increase gain')
 
    __SHUNT_MILLIVOLTS_LSB = 0.01  # 10uV
    __BUS_MILLIVOLTS_LSB = 4  # 4mV
    __CALIBRATION_FACTOR = 0.04096
    # Max value supported value (65534 decimal) of the calibration register
    # (D0 bit is always zero, p31 of spec)
    __MAX_CALIBRATION_VALUE = 0xFFFE
    # In the spec (p17) the current LSB factor for the minimum LSB is
    # documented as 32767, but a larger value (100.1% of 32767) is used
    # to guarantee that current overflow can always be detected.
    __CURRENT_LSB_FACTOR = 32800
 
    def __init__(self, shunt_ohms, i2c, max_expected_amps=None,
                 address=__ADDRESS):
        """Construct the class.
        At a minimum pass in the resistance of the shunt resistor and I2C
        interface to which the sensor is connected.
        Arguments:
        shunt_ohms -- value of shunt resistor in Ohms (mandatory).
        i2c -- an instance of the I2C class from the *machine* module, either
            I2C(1) or I2C(2) (mandatory).
        max_expected_amps -- the maximum expected current in Amps (optional).
        address -- the I2C address of the INA219, defaults to
            *0x40* (optional).
        log_level -- set to logging.DEBUG to see detailed calibration
            calculations (optional).
        """
       
        
        self._i2c = i2c
        self._address = address
        self._shunt_ohms = shunt_ohms
        self._max_expected_amps = max_expected_amps
        self._min_device_current_lsb = self._calculate_min_current_lsb()
        self._gain = None
        self._auto_gain_enabled = False
 
    def configure(self, voltage_range=RANGE_32V, gain=GAIN_AUTO,
                  bus_adc=ADC_12BIT, shunt_adc=ADC_12BIT):
        """Configure and calibrate how the INA219 will take measurements.
        Arguments:
        voltage_range -- The full scale voltage range, this is either 16V
            or 32V represented by one of the following constants;
            RANGE_16V, RANGE_32V (default).
        gain -- The gain which controls the maximum range of the shunt
            voltage represented by one of the following constants;
            GAIN_1_40MV, GAIN_2_80MV, GAIN_4_160MV,
            GAIN_8_320MV, GAIN_AUTO (default).
        bus_adc -- The bus ADC resolution (9, 10, 11, or 12-bit) or
            set the number of samples used when averaging results
            represent by one of the following constants; ADC_9BIT,
            ADC_10BIT, ADC_11BIT, ADC_12BIT (default),
            ADC_2SAMP, ADC_4SAMP, ADC_8SAMP, ADC_16SAMP,
            ADC_32SAMP, ADC_64SAMP, ADC_128SAMP
        shunt_adc -- The shunt ADC resolution (9, 10, 11, or 12-bit) or
            set the number of samples used when averaging results
            represent by one of the following constants; ADC_9BIT,
            ADC_10BIT, ADC_11BIT, ADC_12BIT (default),
            ADC_2SAMP, ADC_4SAMP, ADC_8SAMP, ADC_16SAMP,
            ADC_32SAMP, ADC_64SAMP, ADC_128SAMP
        """
        self.__validate_voltage_range(voltage_range)
        self._voltage_range = voltage_range
 
        if self._max_expected_amps is not None:
            if gain == self.GAIN_AUTO:
                self._auto_gain_enabled = True
                self._gain = self._determine_gain(self._max_expected_amps)
            else:
                self._gain = gain
        else:
            if gain != self.GAIN_AUTO:
                self._gain = gain
            else:
                self._auto_gain_enabled = True
                self._gain = self.GAIN_1_40MV
 
        
 
        self._calibrate(
            self.__BUS_RANGE[voltage_range], self.__GAIN_VOLTS[self._gain],
            self._max_expected_amps)
        self._configure(voltage_range, self._gain, bus_adc, shunt_adc)
 
    def voltage(self):
        """Return the bus voltage in volts."""
        value = self._voltage_register()
        return float(value) * self.__BUS_MILLIVOLTS_LSB / 1000
 
    def supply_voltage(self):
        """Return the bus supply voltage in volts.
        This is the sum of the bus voltage and shunt voltage. A
        DeviceRangeError exception is thrown if current overflow occurs.
        """
        return self.voltage() + (float(self.shunt_voltage()) / 1000)
 
    def current(self):
        """Return the bus current in milliamps.
        A DeviceRangeError exception is thrown if current overflow occurs.
        """
        self._handle_current_overflow()
        return self._current_register() * self._current_lsb * 1000
 
    def power(self):
        """Return the bus power consumption in milliwatts.
        A DeviceRangeError exception is thrown if current overflow occurs.
        """
        self._handle_current_overflow()
        return self._power_register() * self._power_lsb * 1000
 
    def shunt_voltage(self):
        """Return the shunt voltage in millivolts.
        A DeviceRangeError exception is thrown if current overflow occurs.
        """
        self._handle_current_overflow()
        return self._shunt_voltage_register() * self.__SHUNT_MILLIVOLTS_LSB
 
    def sleep(self):
        """Put the INA219 into power down mode."""
        configuration = self._read_configuration()
        self._configuration_register(configuration & 0xFFF8)
 
    def wake(self):
        """Wake the INA219 from power down mode."""
        configuration = self._read_configuration()
        self._configuration_register(configuration | 0x0007)
        # 40us delay to recover from powerdown (p14 of spec)
        utime.sleep_us(40)
 
    def current_overflow(self):
        """Return true if the sensor has detect current overflow.
        In this case the current and power values are invalid.
        """
        return self._has_current_overflow()
 
    def reset(self):
        """Reset the INA219 to its default configuration."""
        self._configuration_register(1 << self.__RST)
 
    def _handle_current_overflow(self):
        if self._auto_gain_enabled:
            while self._has_current_overflow():
                self._increase_gain()
        else:
            if self._has_current_overflow():
                raise DeviceRangeError(self.__GAIN_VOLTS[self._gain])
 
    def _determine_gain(self, max_expected_amps):
        shunt_v = max_expected_amps * self._shunt_ohms
        if shunt_v > self.__GAIN_VOLTS[3]:
            raise ValueError(self.__RNG_ERR_MSG % max_expected_amps)
        gain = min(v for v in self.__GAIN_VOLTS if v > shunt_v)
        return self.__GAIN_VOLTS.index(gain)
 
    def _increase_gain(self):        
        gain = self._read_gain()
        if gain < len(self.__GAIN_VOLTS) - 1:
            gain = gain + 1
            self._calibrate(self.__BUS_RANGE[self._voltage_range],
                            self.__GAIN_VOLTS[gain])
            self._configure_gain(gain)
            # 1ms delay required for new configuration to take effect,
            # otherwise invalid current/power readings can occur.
            utime.sleep_ms(1)
        else:           
            raise DeviceRangeError(self.__GAIN_VOLTS[gain], True)
 
    def _configure(self, voltage_range, gain, bus_adc, shunt_adc):
        configuration = (
            voltage_range << self.__BRNG | gain << self.__PG0 |
            bus_adc << self.__BADC1 | shunt_adc << self.__SADC1 |
            self.__CONT_SH_BUS)
        self._configuration_register(configuration)
 
    def _calibrate(self, bus_volts_max, shunt_volts_max,
                   max_expected_amps=None):        
 
        max_possible_amps = shunt_volts_max / self._shunt_ohms
        
 
        self._current_lsb = \
            self._determine_current_lsb(max_expected_amps, max_possible_amps)
        self._power_lsb = self._current_lsb * 20        
    
        max_current = self._current_lsb * 32767
    
        max_shunt_voltage = max_current * self._shunt_ohms
        
 
        calibration = trunc(self.__CALIBRATION_FACTOR /
                            (self._current_lsb * self._shunt_ohms))        
        self._calibration_register(calibration)
 
    def _determine_current_lsb(self, max_expected_amps, max_possible_amps):
        if max_expected_amps is not None:
            if max_expected_amps > round(max_possible_amps, 3):
                raise ValueError(self.__AMP_ERR_MSG %
                                 (max_expected_amps, max_possible_amps))
            
            if max_expected_amps < max_possible_amps:
                current_lsb = max_expected_amps / self.__CURRENT_LSB_FACTOR
            else:
                current_lsb = max_possible_amps / self.__CURRENT_LSB_FACTOR
        else:
            current_lsb = max_possible_amps / self.__CURRENT_LSB_FACTOR
 
        if current_lsb < self._min_device_current_lsb:
            current_lsb = self._min_device_current_lsb
        return current_lsb
 
    def _configuration_register(self, register_value):
        
        self.__write_register(self.__REG_CONFIG, register_value)
 
    def _read_configuration(self):
        return self.__read_register(self.__REG_CONFIG)
 
    def _calculate_min_current_lsb(self):
        return self.__CALIBRATION_FACTOR / \
            (self._shunt_ohms * self.__MAX_CALIBRATION_VALUE)
 
    def _read_gain(self):
        configuration = self._read_configuration()
        gain = (configuration & 0x1800) >> self.__PG0
        
        return gain
 
    def _configure_gain(self, gain):
        configuration = self._read_configuration()
        configuration = configuration & 0xE7FF
        self._configuration_register(configuration | (gain << self.__PG0))
        self._gain = gain
        
 
    def _calibration_register(self, register_value):
        self.__write_register(self.__REG_CALIBRATION, register_value)
 
    def _has_current_overflow(self):
        ovf = self._read_voltage_register() & self.__OVF
        return (ovf == 1)
 
    def _voltage_register(self):
        register_value = self._read_voltage_register()
        return register_value >> 3
 
    def _read_voltage_register(self):
        return self.__read_register(self.__REG_BUSVOLTAGE)
 
    def _current_register(self):
        return self.__read_register(self.__REG_CURRENT, True)
 
    def _shunt_voltage_register(self):
        return self.__read_register(self.__REG_SHUNTVOLTAGE, True)
 
    def _power_register(self):
        return self.__read_register(self.__REG_POWER)
 
    def __validate_voltage_range(self, voltage_range):
        if voltage_range > len(self.__BUS_RANGE) - 1:
            raise ValueError(self.__VOLT_ERR_MSG)
 
    def __write_register(self, register, register_value):
        self.__log_register_operation("write", register, register_value)
 
        register_bytes = self.__to_bytes(register_value)
        self._i2c.writeto_mem(self._address, register, register_bytes)
 
    def __to_bytes(self, register_value):
        return bytearray([(register_value >> 8) & 0xFF, register_value & 0xFF])
 
    def __read_register(self, register, negative_value_supported=False):
        register_bytes = self._i2c.readfrom_mem(self._address, register, 2)
        register_value = int.from_bytes(register_bytes, 'big')
        if negative_value_supported:
            # Two's compliment
            if register_value > 32767:
                register_value -= 65536
 
        self.__log_register_operation("read", register, register_value)
        return register_value
 
    def __log_register_operation(self, msg, register, value):
        # performance optimisation
        #if logging._level == logging.DEBUG:
        #    binary = '{0:#018b}'.format(value)
        #    self._log.debug("%s register 0x%02x: 0x%04x %s",
        #                    msg, register, value, binary)
         pass
 
    def __max_expected_amps_to_string(self, max_expected_amps):
        if max_expected_amps is None:
            return ''
        else:
            return ', max expected amps: %.3fA' % max_expected_amps
 
 
class DeviceRangeError(Exception):
    """This exception is throw to prevent invalid readings.
    Invalid readings occur When the current is greater than allowed given
    calibration of the device.
    """
 
    __DEV_RNG_ERR = ('Current out of range (overflow), '
                     'for gain %.2fV')
 
    def __init__(self, gain_volts, device_max=False):
        """Construct the class."""
        msg = self.__DEV_RNG_ERR % gain_volts
        if device_max:
            msg = msg + ', device limit reached'
        super(DeviceRangeError, self).__init__(msg)
        self.gain_volts = gain_volts
        self.device_limit_reached = device_max

模块接线示意图:
在这里插入图片描述
在这里插入图片描述

PJ7620手势识别传感器

PAJ7620是一款通过红外线感应手势的传感器模块,可以实现识别9种不同的手势动作,包括向上、向下、向左、向右、向前、向后、左旋转、有旋转、波动等。

演示Demo:

from machine import Pin,UART,ADC,I2C
import machine
import utime
import _thread
import struct
import math

from ssd1306 import SSD1306_I2C,SSD1306_SPI
import framebuf
import array

from paj7620 import PAJ7620


led = Pin(25, Pin.OUT)

i2c0 = I2C(0, sda=Pin(0), scl=Pin(1),freq=400000)
devlist = i2c0.scan()
print("I2C0 Address List:",devlist)
for dev in devlist:
    print(hex(dev))
    

 
# Raspberry Pi logo as 32x32 bytearray
buffer = bytearray(b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00|?\x00\x01\x86@\x80\x01\x01\x80\x80\x01\x11\x88\x80\x01\x05\xa0\x80\x00\x83\xc1\x00\x00C\xe3\x00\x00~\xfc\x00\x00L'\x00\x00\x9c\x11\x00\x00\xbf\xfd\x00\x00\xe1\x87\x00\x01\xc1\x83\x80\x02A\x82@\x02A\x82@\x02\xc1\xc2@\x02\xf6>\xc0\x01\xfc=\x80\x01\x18\x18\x80\x01\x88\x10\x80\x00\x8c!\x00\x00\x87\xf1\x00\x00\x7f\xf6\x00\x008\x1c\x00\x00\x0c \x00\x00\x03\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
# Load the raspberry pi logo into the framebuffer (the image is 32x32)
fb = framebuf.FrameBuffer(buffer, 32, 32, framebuf.MONO_HLSB)

WIDTH = 128
HEIGHT = 64

try:
    oled = SSD1306_I2C(WIDTH,HEIGHT,i2c0)    
except:
    print("oled initialize error!")
    pass
oled.fill(0)


# 手势传感器
paj = PAJ7620(i2c=i2c0)


def PAJ7260():
    Gesture = [" ","Forward-前","Backward-后","Right-右","Left-左","Up-上","Down-下","Clockwise-顺","anti-clockwise-逆","Wave-波浪"]
        
    print(get)
    if get != 0:
        if Gesture[get] == Gesture[9]:
            led.value(not led.value())
        else:
            led.value(0)
            
def main():
    while True:
        geste = paj.gesture()
        # geste peut contenir les valeurs suivantes
        # 	0 : nothing
        # 	1 : Forward
        # 	2 : Backward
        # 	3 : Right
        # 	4 : Left
        # 	5 : Up
        # 	6 : Down
        # 	7 : Clockwise
        # 	8 : anti-clockwise
        # 	9 : wave
        
        oled.fill(0)  # efface l'ecran
        if geste == 1: 
            oled.text("Forward", 0, 0)
        elif geste == 2:
            oled.text("Backward", 0, 0)
        elif geste == 3:
            oled.text("Right", 0, 0)
        elif geste == 4:
            oled.text("Left", 0, 0)
        elif geste == 5:
            oled.text("Up", 0, 0)
        elif geste == 6:
            oled.text("Down", 0, 0)
        elif geste == 7:
            oled.text("Clockwise", 0, 0)
        elif geste == 8:
            oled.text("anti-clockwise", 0, 0)
        elif geste == 9:
            oled.text("wave", 0, 0)
        else:
            oled.text("Get Gesture", 0, 0)
        oled.show()
        utime.sleep(0.5)

if __name__ == "__main__":
    main()

驱动库:paj7620.py

#
# Librairie pour l'utilisation du capteur de geste PAJ7620
#
# adaptation pour l'ESP32 du programme Python pour le Raspberry a partir 
# https://github.com/SeeedDocument/wiki_english/blob/master/docs/Grove-Gesture_v1.0.md
#
import machine, time

# Registres et variables pour le capteur de geste
GES_REACTION_TIME = 0.2  # Ajustement du temps de reaction en secondes
GES_ENTRY_TIME = 0.5  # si reconnaissance des gestes Avance/Recule, GES_REACTION_TIME doit etre inferieur a GES_ENTRY_TIME(0.5s).

BANK0 = 0
BANK1 = 1

PAJ7620_ADDR_BASE = 0x00
# registre de selection de la banque
PAJ7620_REGISTER_BANK_SEL = (PAJ7620_ADDR_BASE + 0xEF)	        # W

# adresse i2c
PAJ7620_ID = 0x73

# registres BANK 0
PAJ7620_ADDR_SUSPEND_CMD	    = (PAJ7620_ADDR_BASE + 0x3)	     # W
PAJ7620_ADDR_GES_PS_DET_MASK_0	= (PAJ7620_ADDR_BASE + 0x41)	 # RW
PAJ7620_ADDR_GES_PS_DET_MASK_1	= (PAJ7620_ADDR_BASE + 0x42)	 # RW
PAJ7620_ADDR_GES_PS_DET_FLAG_0	= (PAJ7620_ADDR_BASE + 0x43)	 # R
PAJ7620_ADDR_GES_PS_DET_FLAG_1	= (PAJ7620_ADDR_BASE + 0x44)	 # R
PAJ7620_ADDR_STATE_INDICATOR	= (PAJ7620_ADDR_BASE + 0x45)	 # R
PAJ7620_ADDR_PS_HIGH_THRESHOLD	= (PAJ7620_ADDR_BASE + 0x69)	 # RW
PAJ7620_ADDR_PS_LOW_THRESHOLD	= (PAJ7620_ADDR_BASE + 0x6A)	 # RW
PAJ7620_ADDR_PS_APPROACH_STATE	= (PAJ7620_ADDR_BASE + 0x6B)	 # R
PAJ7620_ADDR_PS_RAW_DATA	    = (PAJ7620_ADDR_BASE + 0x6C)	 # R

# registres BANK 1
PAJ7620_ADDR_PS_GAIN		    = (PAJ7620_ADDR_BASE + 0x44)	# RW
PAJ7620_ADDR_IDLE_S1_STEP_0    = (PAJ7620_ADDR_BASE + 0x67)	    # RW
PAJ7620_ADDR_IDLE_S1_STEP_1    = (PAJ7620_ADDR_BASE + 0x68)	    # RW
PAJ7620_ADDR_IDLE_S2_STEP_0    = (PAJ7620_ADDR_BASE + 0x69)	    # RW
PAJ7620_ADDR_IDLE_S2_STEP_1    = (PAJ7620_ADDR_BASE + 0x6A)	    # RW
PAJ7620_ADDR_OP_TO_S1_STEP_0	= (PAJ7620_ADDR_BASE + 0x6B)	# RW
PAJ7620_ADDR_OP_TO_S1_STEP_1	= (PAJ7620_ADDR_BASE + 0x6C)	# RW
PAJ7620_ADDR_OP_TO_S2_STEP_0	= (PAJ7620_ADDR_BASE + 0x6D)	# RW
PAJ7620_ADDR_OP_TO_S2_STEP_1	= (PAJ7620_ADDR_BASE + 0x6E)	# RW
PAJ7620_ADDR_OPERATION_ENABLE	= (PAJ7620_ADDR_BASE + 0x72)	# RW

# PAJ7620 selection de la banque
PAJ7620_BANK0 = 0
PAJ7620_BANK1 = 1

# gestes detectes
GES_RIGHT_FLAG           = 1<<0
GES_LEFT_FLAG            = 1<<1
GES_UP_FLAG              = 1<<2
GES_DOWN_FLAG            = 1<<3
GES_FORWARD_FLAG         = 1<<4
GES_BACKWARD_FLAG        = 1<<5
GES_CLOCKWISE_FLAG       = 1<<6
GES_COUNT_CLOCKWISE_FLAG = 1<<7
GES_WAVE_FLAG            = 1<<0

# retour des gestes
NOTHING         = 0
FORWARD 		= 1
BACKWARD 		= 2
RIGHT			= 3
LEFT			= 4
UP			    = 5
DOWN			= 6
CLOCKWISE		= 7
ANTI_CLOCKWISE	= 8
WAVE			= 9

# etat initial des differents registres 
initRegisterArray = ([0xEF,0x00],[0x32,0x29],[0x33,0x01],[0x34,0x00],[0x35,0x01],[0x36,0x00],
[0x37,0x07],[0x38,0x17],[0x39,0x06],[0x3A,0x12],[0x3F,0x00],[0x40,0x02],[0x41,0xFF],[0x42,0x01],
[0x46,0x2D],[0x47,0x0F],[0x48,0x3C],[0x49,0x00],[0x4A,0x1E],[0x4B,0x00],[0x4C,0x20],[0x4D,0x00],
[0x4E,0x1A],[0x4F,0x14],[0x50,0x00],[0x51,0x10],[0x52,0x00],[0x5C,0x02],[0x5D,0x00],[0x5E,0x10],
[0x5F,0x3F],[0x60,0x27],[0x61,0x28],[0x62,0x00],[0x63,0x03],[0x64,0xF7],[0x65,0x03],[0x66,0xD9],
[0x67,0x03],[0x68,0x01],[0x69,0xC8],[0x6A,0x40],[0x6D,0x04],[0x6E,0x00],[0x6F,0x00],[0x70,0x80],
[0x71,0x00],[0x72,0x00],[0x73,0x00],[0x74,0xF0],[0x75,0x00],[0x80,0x42],[0x81,0x44],[0x82,0x04],
[0x83,0x20],[0x84,0x20],[0x85,0x00],[0x86,0x10],[0x87,0x00],[0x88,0x05],[0x89,0x18],[0x8A,0x10],
[0x8B,0x01],[0x8C,0x37],[0x8D,0x00],[0x8E,0xF0],[0x8F,0x81],[0x90,0x06],[0x91,0x06],[0x92,0x1E],
[0x93,0x0D],[0x94,0x0A],[0x95,0x0A],[0x96,0x0C],[0x97,0x05],[0x98,0x0A],[0x99,0x41],[0x9A,0x14],
[0x9B,0x0A],[0x9C,0x3F],[0x9D,0x33],[0x9E,0xAE],[0x9F,0xF9],[0xA0,0x48],[0xA1,0x13],[0xA2,0x10],
[0xA3,0x08],[0xA4,0x30],[0xA5,0x19],[0xA6,0x10],[0xA7,0x08],[0xA8,0x24],[0xA9,0x04],[0xAA,0x1E],
[0xAB,0x1E],[0xCC,0x19],[0xCD,0x0B],[0xCE,0x13],[0xCF,0x64],[0xD0,0x21],[0xD1,0x0F],[0xD2,0x88],
[0xE0,0x01],[0xE1,0x04],[0xE2,0x41],[0xE3,0xD6],[0xE4,0x00],[0xE5,0x0C],[0xE6,0x0A],[0xE7,0x00],
[0xE8,0x00],[0xE9,0x00],[0xEE,0x07],[0xEF,0x01],[0x00,0x1E],[0x01,0x1E],[0x02,0x0F],[0x03,0x10],
[0x04,0x02],[0x05,0x00],[0x06,0xB0],[0x07,0x04],[0x08,0x0D],[0x09,0x0E],[0x0A,0x9C],[0x0B,0x04],
[0x0C,0x05],[0x0D,0x0F],[0x0E,0x02],[0x0F,0x12],[0x10,0x02],[0x11,0x02],[0x12,0x00],[0x13,0x01],
[0x14,0x05],[0x15,0x07],[0x16,0x05],[0x17,0x07],[0x18,0x01],[0x19,0x04],[0x1A,0x05],[0x1B,0x0C],
[0x1C,0x2A],[0x1D,0x01],[0x1E,0x00],[0x21,0x00],[0x22,0x00],[0x23,0x00],[0x25,0x01],[0x26,0x00],
[0x27,0x39],[0x28,0x7F],[0x29,0x08],[0x30,0x03],[0x31,0x00],[0x32,0x1A],[0x33,0x1A],[0x34,0x07],
[0x35,0x07],[0x36,0x01],[0x37,0xFF],[0x38,0x36],[0x39,0x07],[0x3A,0x00],[0x3E,0xFF],[0x3F,0x00],
[0x40,0x77],[0x41,0x40],[0x42,0x00],[0x43,0x30],[0x44,0xA0],[0x45,0x5C],[0x46,0x00],[0x47,0x00],
[0x48,0x58],[0x4A,0x1E],[0x4B,0x1E],[0x4C,0x00],[0x4D,0x00],[0x4E,0xA0],[0x4F,0x80],[0x50,0x00],
[0x51,0x00],[0x52,0x00],[0x53,0x00],[0x54,0x00],[0x57,0x80],[0x59,0x10],[0x5A,0x08],[0x5B,0x94],
[0x5C,0xE8],[0x5D,0x08],[0x5E,0x3D],[0x5F,0x99],[0x60,0x45],[0x61,0x40],[0x63,0x2D],[0x64,0x02],
[0x65,0x96],[0x66,0x00],[0x67,0x97],[0x68,0x01],[0x69,0xCD],[0x6A,0x01],[0x6B,0xB0],[0x6C,0x04],
[0x6D,0x2C],[0x6E,0x01],[0x6F,0x32],[0x71,0x00],[0x72,0x01],[0x73,0x35],[0x74,0x00],[0x75,0x33],
[0x76,0x31],[0x77,0x01],[0x7C,0x84],[0x7D,0x03],[0x7E,0x01])

class PAJ7620():
    def __init__(self, i2c, address=PAJ7620_ID):
        self.i2c = i2c
        self.address = address
        time.sleep(0.001)
        self.paj7620SelectBank(BANK0)
        data0 = self.paj7620ReadReg(0, 1)[0]
        data1 = self.paj7620ReadReg(1, 1)[0]
        if data0 != 0x20 or data1 != 0x76:
            print("Capteur en erreur")
        for i in range(len(initRegisterArray)):
            self.paj7620WriteReg(initRegisterArray[i][0], initRegisterArray[i][1])
        self.paj7620SelectBank(BANK0)
        
    def paj7620WriteReg(self, addr, cmd):
        # Ecriture d'un octet dans un registre du capteur
        buf = bytearray(1)
        buf[0] = cmd
        self.i2c.writeto_mem(self.address, addr, buf)
	
    def paj7620SelectBank(self, bank):
        # Selection de la banque de registre
        if bank == BANK0:
            self.paj7620WriteReg(PAJ7620_REGISTER_BANK_SEL, PAJ7620_BANK0)
    
    def paj7620ReadReg(self, addr, qty):
        # Lecture d'un bloc a l'adresse 'addr' avec un nombre d'octets 'qty'
        return self.i2c.readfrom_mem(self.address, addr, qty)
    
    def gesture(self):
        # Retourne une valeur à partir du capteur
        # 	0 : nothing
        # 	1 : Forward
        # 	2 : Backward
        # 	3 : Right
        # 	4 : Left
        # 	5 : Up
        # 	6 : Down
        # 	7 : Clockwise
        # 	8 : anti-clockwise
        # 	9 : wave
        data = self.paj7620ReadReg(0x43, 1)[0]
        if data == GES_RIGHT_FLAG:
            time.sleep(GES_ENTRY_TIME)
            data = self.paj7620ReadReg(0x43, 1)[0]
            if data == GES_FORWARD_FLAG:
                return FORWARD
            elif data == GES_BACKWARD_FLAG:
                return BACKWARD
            else:
                return RIGHT
        elif data == GES_LEFT_FLAG:
            time.sleep(GES_ENTRY_TIME)
            data = self.paj7620ReadReg(0x43, 1)[0]
            if data == GES_FORWARD_FLAG:
                return FORWARD
            elif data == GES_BACKWARD_FLAG:
                return BACKWARD
            else:
                return LEFT
        elif data == GES_UP_FLAG:
            time.sleep(GES_ENTRY_TIME)
            data = self.paj7620ReadReg(0x43, 1)[0]
            if data == GES_FORWARD_FLAG:
                return FORWARD
            elif data == GES_BACKWARD_FLAG:
                return BACKWARD
            else:
                return UP
        elif data == GES_DOWN_FLAG:
            time.sleep(GES_ENTRY_TIME)
            data = self.paj7620ReadReg(0x43, 1)[0]
            if data == GES_FORWARD_FLAG:
                return FORWARD
            elif data == GES_BACKWARD_FLAG:
                return BACKWARD
            else:
                return DOWN
        elif data == GES_FORWARD_FLAG:
            return FORWARD
        elif data == GES_BACKWARD_FLAG:
            return BACKWARD
        elif data == GES_CLOCKWISE_FLAG:
            return CLOCKWISE
        elif data == GES_COUNT_CLOCKWISE_FLAG:
            return ANTI_CLOCKWISE
        else:
            data1 = self.paj7620ReadReg(0x44, 1)[0]
            if (data1 == GES_WAVE_FLAG):
                return WAVE
        return NOTHING

在这里插入图片描述

HX711称重模块

演示Demo

from machine import Pin, I2C
import utime
from hx711 import HX711

from ssd1306 import SSD1306_I2C,SSD1306_SPI
import framebuf
import array


i2c0 = I2C(0, sda=Pin(0), scl=Pin(1),freq=400000)
devlist = i2c0.scan()
print("I2C0 Address List:",devlist)
for dev in devlist:
    print(hex(dev))
    
    # Raspberry Pi logo as 32x32 bytearray
buffer = bytearray(b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00|?\x00\x01\x86@\x80\x01\x01\x80\x80\x01\x11\x88\x80\x01\x05\xa0\x80\x00\x83\xc1\x00\x00C\xe3\x00\x00~\xfc\x00\x00L'\x00\x00\x9c\x11\x00\x00\xbf\xfd\x00\x00\xe1\x87\x00\x01\xc1\x83\x80\x02A\x82@\x02A\x82@\x02\xc1\xc2@\x02\xf6>\xc0\x01\xfc=\x80\x01\x18\x18\x80\x01\x88\x10\x80\x00\x8c!\x00\x00\x87\xf1\x00\x00\x7f\xf6\x00\x008\x1c\x00\x00\x0c \x00\x00\x03\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")

# Load the raspberry pi logo into the framebuffer (the image is 32x32)
fb = framebuf.FrameBuffer(buffer, 32, 32, framebuf.MONO_HLSB)

WIDTH = 128
HEIGHT = 64

try:
    oled = SSD1306_I2C(WIDTH,HEIGHT,i2c0)    
except:
    pass

oled.fill(0)
    
    
# ===============================================================    
# channel=HX711.CHANNEL_A_128, capvalue=1010
# channel=HX711.CHANNEL_A_64, capvalue=505
hx711 = HX711(d_out=16, pd_sck=17, channel=HX711.CHANNEL_A_128, capvalue=1010)
hx711.PowerOn()
utime.sleep_ms(500)

# 自动设置清零值
hx711.AutoCalibrationValue()

# 手动设置清零值

#calval = hx711.ReadCount(HX711.CHANNEL_A_128)
#print('calval',calval)
#hx711.SetCalibrationValue(calval)

hx711.Info()
utime.sleep(1)


while True:
    weights = hx711.GetWeights()
    print('W:',weights)
    #val = hx711.GetChannelBValue()
    #print(val)
    oled.fill(0)
    oled.text("Weights:{:.2f}V".format(weights), 0, 0)
    oled.show() 
    utime.sleep_ms(100)

驱动库hx711.py

import machine
from machine import Pin
import utime
from micropython import const


class HX711:
    CHANNEL_A_128 = const(1)
    CHANNEL_B_32 = const(2)
    CHANNEL_A_64 = const(3)
    
    def __init__(self, d_out, pd_sck, channel=CHANNEL_A_128, capvalue=429.50, interval=20, timeout=100):
        self.dk = Pin(d_out, Pin.OUT)
        self.do = Pin(pd_sck, Pin.IN)
        self.channel = channel
        self.timeout = timeout*1000
        self.interval = interval
        self.lastread = 0
        self.capvalue = capvalue
        self.calibration = 0
        self.cur_count = 0
        
    def AutoCalibrationValue(self):
        sums = 0
        trys = 0
        for i in range(50):
            count =self.ReadCount(self.channel)
            if (count != 0):
                sums += count
                trys += 1
                if trys == 10:
                    break
            else:
                utime.sleep_ms(10)
        print(sums, trys)
        count =int(sums/trys)
        self.SetCalibrationValue(count)
                        
    def SetCalibrationValue(self, cal):
        self.calibration = cal
        print('calibration:', self.calibration)
        
    def PowerOff(self):
        self.dk.value(1)
        utime.sleep_ms(100)
        
    def PowerOn(self):
        self.dk.value(1)
        utime.sleep_ms(10)
        self.dk.value(0)
        utime.sleep_ms(100)
        
    def ReadCount(self, channel=CHANNEL_A_128):
        if (utime.ticks_us()/1000) < self.lastread:
            return self.cur_count
        else:
            self.lastread = int((utime.ticks_us()/1000)+self.interval)
            
        self.dk.value(0)
        #utime.sleep_us(1)
        count = 0
        errtime = utime.ticks_us()
        while (self.do.value() == 1):
            start = utime.ticks_us() -  errtime
            if start > self.timeout:
                return 0
            pass
        
        for i in range(24):
            self.dk.value(1)
            utime.sleep_us(1)
            self.dk.value(0)
            count = count << 1;
            if self.do.value():
                count += 1
                
        # 第25个脉冲,下次转换通道A,增益128
        if channel >= CHANNEL_A_128:
            self.dk.value(1)
            utime.sleep_us(1)
            self.dk.value(0)
        if channel >= CHANNEL_B_32:
            self.dk.value(1)
            utime.sleep_us(1)
            self.dk.value(0)
        if channel >= CHANNEL_A_64:
            self.dk.value(1)
            utime.sleep_us(1)
            self.dk.value(0)
        #utime.sleep_us(1)
        count = count^0x800000
        self.cur_count = count
        return self.cur_count
    
    def GetWeights(self):
        count = self.ReadCount(self.channel)
        if count == 0:
            print('HX711 ReadCount Error.')
            return 0
        #print('count:', count, 'calibration:', self.calibration)
        return float((count-self.calibration)/self.capvalue)
    
    def GetChannelBValue(self):
        count = self.ReadCount(CHANNEL_B_32)
        if count == 0:
            print('HX711 ReadCount Error.')
            return 0
        return  count
    
    def Info(self):
        print('CapValue:', self.capvalue)
        print('Calibration:', self.calibration)
        if self.channel == CHANNEL_A_128:
            print('Channel:A 128')
        elif self.channel == CHANNEL_A_64:
            print('Channel:A 64')        

在这里插入图片描述

PCF8563(RTC模块)

在这里插入图片描述

/lib/pcf8563.py

'''
MIT License

Copyright (c) 2019 lewis he

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

pcf8563.py - MicroPython library for NXP PCF8563 Real-time clock/calendar
Created by Lewis he on September 17, 2019.
github:https://github.com/lewisxhe/PCF8563_PythonLibrary
'''
import utime
from machine import I2C

PCF8563_SLAVE_ADDRESS = const(0x51)
PCF8563_STAT1_REG = const(0x00)
PCF8563_STAT2_REG = const(0x01)
PCF8563_SEC_REG = const(0x02)
PCF8563_MIN_REG = const(0x03)
PCF8563_HR_REG = const(0x04)
PCF8563_DAY_REG = const(0x05)
PCF8563_WEEKDAY_REG = const(0x06)
PCF8563_MONTH_REG = const(0x07)
PCF8563_YEAR_REG = const(0x08)
PCF8563_SQW_REG = const(0x0D)
PCF8563_TIMER1_REG = const(0x0E)
PCF8563_TIMER2_REG = const(0x0F)
PCF8563_VOL_LOW_MASK = const(0x80)
PCF8563_minuteS_MASK = const(0x7F)
PCF8563_HOUR_MASK = const(0x3F)
PCF8563_WEEKDAY_MASK = const(0x07)
PCF8563_CENTURY_MASK = const(0x80)
PCF8563_DAY_MASK = const(0x3F)
PCF8563_MONTH_MASK = const(0x1F)
PCF8563_TIMER_CTL_MASK = const(0x03)
PCF8563_ALARM_AF = const(0x08)
PCF8563_TIMER_TF = const(0x04)
PCF8563_ALARM_AIE = const(0x02)
PCF8563_TIMER_TIE = const(0x01)
PCF8563_TIMER_TE = const(0x80)
PCF8563_TIMER_TD10 = const(0x03)
PCF8563_NO_ALARM = const(0xFF)
PCF8563_ALARM_ENABLE = const(0x80)
PCF8563_CLK_ENABLE = const(0x80)
PCF8563_ALARM_MINUTES = const(0x09)
PCF8563_ALARM_HOURS = const(0x0A)
PCF8563_ALARM_DAY = const(0x0B)
PCF8563_ALARM_WEEKDAY = const(0x0C)

CLOCK_CLK_OUT_FREQ_32_DOT_768KHZ = const(0x80)
CLOCK_CLK_OUT_FREQ_1_DOT_024KHZ = const(0x81)
CLOCK_CLK_OUT_FREQ_32_KHZ = const(0x82)
CLOCK_CLK_OUT_FREQ_1_HZ = const(0x83)
CLOCK_CLK_HIGH_IMPEDANCE = const(0x0)


class PCF8563:
    def __init__(self, i2c, address=None):
        """Initialization needs to be given an initialized I2C port
        """
        self.i2c = i2c
        self.address = address if address else PCF8563_SLAVE_ADDRESS
        self.buffer = bytearray(16)
        self.bytebuf = memoryview(self.buffer[0:1])

    def __write_byte(self, reg, val):
        self.bytebuf[0] = val
        self.i2c.writeto_mem(self.address, reg, self.bytebuf)

    def __read_byte(self, reg):
        self.i2c.readfrom_mem_into(self.address, reg, self.bytebuf)
        return self.bytebuf[0]

    def __bcd2dec(self, bcd):
        return (((bcd & 0xf0) >> 4) * 10 + (bcd & 0x0f))

    def __dec2bcd(self, dec):
        tens, units = divmod(dec, 10)
        return (tens << 4) + units

    def seconds(self):
        """Get the current allowed seconds of PCF8563
        """
        return self.__bcd2dec(self.__read_byte(PCF8563_SEC_REG) & 0x7F)

    def minutes(self):
        """Get the current allowed minutes of PCF8563
        """
        return self.__bcd2dec(self.__read_byte(PCF8563_MIN_REG) & 0x7F)

    def hours(self):
        """Get the current allowed hours of PCF8563
        """
        d = self.__read_byte(PCF8563_HR_REG) & 0x3F
        return self.__bcd2dec(d & 0x3F)

    def day(self):
        """Get the current allowed day of PCF8563
        """
        return self.__bcd2dec(self.__read_byte(PCF8563_WEEKDAY_REG) & 0x07)

    def date(self):
        """Get the current allowed date of PCF8563
        """
        return self.__bcd2dec(self.__read_byte(PCF8563_DAY_REG) & 0x3F)

    def month(self):
        """Get the current allowed month of PCF8563
        """
        return self.__bcd2dec(self.__read_byte(PCF8563_MONTH_REG) & 0x1F)

    def year(self):
        """Get the current allowed year of PCF8563
        """
        return self.__bcd2dec(self.__read_byte(PCF8563_YEAR_REG))

    def datetime(self):
        """Return a tuple such as (year, month, date, day, hours, minutes,
        seconds).
        """
        return (self.year(), self.month(), self.date(),
                self.day(), self.hours(), self.minutes(),
                self.seconds())

    def write_all(self, seconds=None, minutes=None, hours=None, day=None,
                  date=None, month=None, year=None):
        """Direct write un-none value.
        Range: seconds [0,59], minutes [0,59], hours [0,23],
               day [0,7], date [1-31], month [1-12], year [0-99].
        """
        if seconds is not None:
            if seconds < 0 or seconds > 59:
                raise ValueError('Seconds is out of range [0,59].')
            seconds_reg = self.__dec2bcd(seconds)
            self.__write_byte(PCF8563_SEC_REG, seconds_reg)

        if minutes is not None:
            if minutes < 0 or minutes > 59:
                raise ValueError('Minutes is out of range [0,59].')
            self.__write_byte(PCF8563_MIN_REG, self.__dec2bcd(minutes))

        if hours is not None:
            if hours < 0 or hours > 23:
                raise ValueError('Hours is out of range [0,23].')
            # no 12 hour mode
            self.__write_byte(PCF8563_HR_REG, self.__dec2bcd(hours))

        if year is not None:
            if year < 0 or year > 99:
                raise ValueError('Years is out of range [0,99].')
            self.__write_byte(PCF8563_YEAR_REG, self.__dec2bcd(year))

        if month is not None:
            if month < 1 or month > 12:
                raise ValueError('Month is out of range [1,12].')
            self.__write_byte(PCF8563_MONTH_REG, self.__dec2bcd(month))

        if date is not None:
            if date < 1 or date > 31:
                raise ValueError('Date is out of range [1,31].')
            self.__write_byte(PCF8563_DAY_REG, self.__dec2bcd(date))

        if day is not None:
            if day < 1 or day > 7:
                raise ValueError('Day is out of range [1,7].')
            self.__write_byte(PCF8563_WEEKDAY_REG, self.__dec2bcd(day))

    def set_datetime(self, dt):
        """Input a tuple such as (year, month, date, day, hours, minutes,
        seconds).
        """
        self.write_all(dt[5], dt[4], dt[3],
                       dt[6], dt[2], dt[1], dt[0] % 100)

    def write_now(self):
        """Write the current system time to PCF8563
        """
        self.set_datetime(utime.localtime())

    def set_clk_out_frequency(self, frequency=CLOCK_CLK_OUT_FREQ_1_HZ):
        """Set the clock output pin frequency
        """
        self.__write_byte(PCF8563_SQW_REG, frequency)

    def check_if_alarm_on(self):
        """Read the register to get the alarm enabled
        """
        return bool(self.__read_byte(PCF8563_STAT2_REG) & PCF8563_ALARM_AF)

    def turn_alarm_off(self):
        """Should not affect the alarm interrupt state.
        """
        alarm_state = self.__read_byte(PCF8563_STAT2_REG)
        self.__write_byte(PCF8563_STAT2_REG, alarm_state & 0xf7)

    def clear_alarm(self):
        """Clear status register.
        """
        alarm_state = self.__read_byte(PCF8563_STAT2_REG)
        alarm_state &= ~(PCF8563_ALARM_AF)
        alarm_state |= PCF8563_TIMER_TF
        self.__write_byte(PCF8563_STAT2_REG, alarm_state)

        self.__write_byte(PCF8563_ALARM_MINUTES, 0x80)
        self.__write_byte(PCF8563_ALARM_HOURS, 0x80)
        self.__write_byte(PCF8563_ALARM_DAY, 0x80)
        self.__write_byte(PCF8563_ALARM_WEEKDAY, 0x80)

    def check_for_alarm_interrupt(self):
        """check for alarm interrupt,is alram int return True
        """
        return bool(self.__read_byte(PCF8563_STAT2_REG) & 0x02)

    def enable_alarm_interrupt(self):
        """Turn on the alarm interrupt output to the interrupt pin
        """
        alarm_state = self.__read_byte(PCF8563_STAT2_REG)
        alarm_state &= ~PCF8563_ALARM_AF
        alarm_state |= (PCF8563_TIMER_TF | PCF8563_ALARM_AIE)
        self.__write_byte(PCF8563_STAT2_REG, alarm_state)

    def disable_alarm_interrupt(self):
        """Turn off the alarm interrupt output to the interrupt pin
        """
        alarm_state = self.__read_byte(PCF8563_STAT2_REG)
        alarm_state &= ~(PCF8563_ALARM_AF | PCF8563_ALARM_AIE)
        alarm_state |= PCF8563_TIMER_TF
        self.__write_byte(PCF8563_STAT2_REG, alarm_state)

    def set_daily_alarm(self, hours=None, minutes=None, date=None, weekday=None):
        """Set alarm match, allow sometimes, minute, day, week
        """
        if minutes is None:
            minutes = PCF8563_ALARM_ENABLE
            self.__write_byte(PCF8563_ALARM_MINUTES, minutes)
        else:
            if minutes < 0 or minutes > 59:
                raise ValueError('Minutes is out of range [0,59].')
            self.__write_byte(PCF8563_ALARM_MINUTES,
                            self.__dec2bcd(minutes) & 0x7f)

        if hours is None:
            hours = PCF8563_ALARM_ENABLE
            self.__write_byte(PCF8563_ALARM_HOURS, hours)
        else:
            if hours < 0 or hours > 23:
                raise ValueError('Hours is out of range [0,23].')
            self.__write_byte(PCF8563_ALARM_HOURS, self.__dec2bcd(
                hours) & 0x7f)

        if date is None:
            date = PCF8563_ALARM_ENABLE
            self.__write_byte(PCF8563_ALARM_DAY, date)
        else:
            if date < 1 or date > 31:
                raise ValueError('date is out of range [1,31].')
            self.__write_byte(PCF8563_ALARM_DAY, self.__dec2bcd(
                date) & 0x7f)

        if weekday is None:
            weekday = PCF8563_ALARM_ENABLE
            self.__write_byte(PCF8563_ALARM_WEEKDAY, weekday)
        else:
            if weekday < 0 or weekday > 6:
                raise ValueError('weekday is out of range [0,6].')
            self.__write_byte(PCF8563_ALARM_WEEKDAY, self.__dec2bcd(
                weekday) & 0x7f)

闹钟应用Demo:
设定时间到INT脚产生一个中断脉冲输出

import utime
import time
import pcf8563
from machine import I2C
from machine import Pin

def handle_interrupt(pin):
    if r.check_for_alarm_interrupt():
        print('is alarm clock interrupt')
    else:
        print('is not for alarm interrupt')
    r.clear_alarm()

irq = Pin(37, mode=Pin.IN,handler=handle_interrupt,trigger=Pin.IRQ_FALLING)
i2c = I2C(scl=22, sda=21)
r = pcf8563.PCF8563(i2c)

print('rtc time')
r.datetime()
time.sleep(1)

print('Clear alarm config register')
r.clear_alarm()

print('Setting current clock datetime')
r.write_all(50,30,15,3,17,9,49)

print('Set the alarm to match for minutes')
r.set_daily_alarm(minutes=31)

print('Enable rtc chip interrupt')
r.enable_alarm_interrupt()

while True:
    r.datetime()
    time.sleep(1)

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐