【Banana PI Leaf S3开发板试用体验】MicroPython环境搭建

IIC接口介绍

i2c类实例化

I2C是设备之间的两线通信协议。在物理层它只需要两个信号线:SCL 和 SDA,分别是时钟和数据线。I2C 对象关联到总线,它可以在创建时初始化,也可以稍后初始化。
与I2C有关的类定义在machine中,我们可以通过

class machine.I2C(scl, sda, freq)

实例化一个I2C的类
其中
scl为i2c设备时钟引脚对象;sda为i2c设备数据线引脚对象;freq为SCL时钟频率(0 < freq ≤ 500000(Hz))。

i2c类中的函数介绍

I2C.init(scl, sda, freq)

函数说明:初始化i2c总线。

scl:SCL信号线的I/O口
sda:SDA信号线的I/O口
freq:SCL时钟频率
示例:

i2c.init(scl=Pin(22),sda=Pin(21))

I2C.scan()

函数说明:扫描0x08到0x77之间的I2C地址,并返回设备列表。
示例:

i2c.scan()

I2C.start()

函数说明:在总线上触发START状态(SCL为高电平时,SDA转为低电平)。
示例:

i2c.start()

I2C.stop()

函数说明:在总线上触发STOP状态 (SCL为高电平时,SDA转为高电平)。
示例:

i2c.stop()

I2C.write(buf)

函数说明:buf中的数据写入到总线,并返回写入的字节数。

buf:存储数据的缓冲区
注意:
使用write()函数时要与start函数一起使用,否则无法返回写入的字节数。
示例:

buf = b'123'
i2c.start()
i2c.write(buf)

I2C.readinto(buf, nack=True)
函数说明:从总线上读取数据并存放到buf,无返回值。

buf:存储数据的缓冲区
注意:
读取的字节数是buf的长度。在接收到最后一个字节之前,总线将发送ACK信号。在接收到最后一个字节后,如果nack为True,那么将发送一个NACK信号,否则将发送一个ACK信号。 示例:

buf=bytearray(3)
i2c.readinto(buf)

I2C.readfrom(addr, nbytes)

函数说明:从指定地址设备读取数据,返回读取对象,这个对象与I2C设备有关。

addr:i2c设备地址(可由scan函数读取出来)
nbytes:要读取数据的大小
示例:

data = i2c.readfrom(24, 8)
print(data)

运行结果:
b’\x00\x02\x00\x00\xe8\x03\xe8\x03’

I2C.readfrom_into(addr, buf)

函数说明:从指定地址设备读取buf.len()个数据到buf。

addr:i2c设备地址(可由scan函数读取出来)
buf:存储数据的缓冲区
示例:

buf = bytearray(8)
i2c.readfrom_into(24, buf)
print(buf)

运行结果:
bytearray(b’\x00\x02\x00\x00\xe8\x03\xe8\x03’)

I2C.writeto(addr, buf)

函数说明:将buf中的数据写入设备,并返回写入数据的大小。

addr:i2c设备地址(可由scan函数读取出来)
buf:存储数据的缓冲区
示例:

b = bytearray(3)
b[0] = 24
b[1] = 111
b[2] = 107
i = i2c.writeto(24,b)

I2C.readfrom_mem(addr, memaddr, nbytes, addrsize=8)
函数说明:从I2C设备的寄存器中读取并返回数据。

addr:i2c设备地址(可由scan函数读取出来)
memaddr:寄存器地址
nbytes:要读取的字节大小
addrsize:指定地址大小,默认为8位(在ESP8266上这个参数无效,地址大小总是8位)
示例:

b = i2c. readfrom_mem(24,  0x58, 3)
print(b)

运行结果:
b’\x00\x02\x01’

I2C.readfrom_mem_into(addr, memaddr, buf, addrsize=8)
函数说明:从I2C设备的寄存器中读取buf.len()个数据到buf,无返回值。

addr:i2c设备地址(可由scan函数读取出来)
memaddr:寄存器地址
buf:存储数据的缓冲区
addrsize:指定地址大小,默认为8位(在ESP8266上这个参数无效,地址大小总是8位),读取数据数量是buf的长度。
示例:

buf=bytearray(8)
i2c.readfrom_mem_into(24, 0x58, buf)

I2C.writeto_mem(addr, memaddr, buf, addrsize=8)
函数说明: 将buf 中的数据全部写入到从设备 addr 的内存 memaddr。

addr:i2c设备地址(可由scan函数读取出来)
memaddr:寄存器地址
buf:存储数据的缓冲区
addrsize:指定地址大小,默认为8位(在ESP8266上这个参数无效,地址大小总是8位),读取数据数量是buf的长度。
示例:

buf = b'123'
i2c.writeto_mem(24, 0x58, buf)

最佳实践

PCA9685 是最常见的多路PWM控制器,最高可以输出16路12位分辨率的PWM,可以用来控制LED或者舵机。这里我们着重讲解下如何控制舵机。
在这里插入图片描述
在这里插入图片描述

舵机控制

假设舵机为50HZ的控制频率,脉宽为0.5ms~2.5ms,12位分辨率(4096级),相关精度计算如下:

  • PWM周期:
    在这里插入图片描述
  • 时间分辨率:
    在这里插入图片描述
  • 最大脉宽时间:
    在这里插入图片描述
  • 0-180度的舵机,角度分辨率:
    在这里插入图片描述

寄存器介绍

MODE1

首先介绍MODE1寄存器,如下图:
在这里插入图片描述
在使用该寄存器的时候要注意:

  • 如果未停止所有PWM输出就将其进入到睡眠模式,那么,所有输出通道在下一轮都将输出高电平。
  • 睡眠后重新启动PWM的操作为:
  • 注意,在设置PWM频率(写PRESCALE寄存器)的时候,要先设置为Sleep模式,请参考后面源码部分。

MODE2

该寄存器的各位功能如下图所示:
在这里插入图片描述

PWM ctrl

PWM通道寄存器如下图:
在这里插入图片描述

代码

PCA9685

import ustruct
import time


class PCA9685:
    def __init__(self, i2c, address=0x40):
        self.i2c = i2c
        self.address = address
        self.reset()

    def _write(self, address, value):
        self.i2c.writeto_mem(self.address, address, bytearray([value]))

    def _read(self, address):
        return self.i2c.readfrom_mem(self.address, address, 1)[0]

    def reset(self):
        self._write(0x00, 0x00) # Mode1

    def freq(self, freq=None):
        if freq is None:
            return int(25000000.0 / 4096 / (self._read(0xfe) - 0.5))
        prescale = int(25000000.0 / 4096.0 / freq + 0.5)
        old_mode = self._read(0x00) # Mode 1
        self._write(0x00, (old_mode & 0x7F) | 0x10) # Mode 1, sleep
        self._write(0xfe, prescale) # Prescale
        self._write(0x00, old_mode) # Mode 1
        time.sleep_us(5)
        self._write(0x00, old_mode | 0xa1) # Mode 1, autoincrement on

    def pwm(self, index, on=None, off=None):
        if on is None or off is None:
            data = self.i2c.readfrom_mem(self.address, 0x06 + 4 * index, 4)
            return ustruct.unpack('<HH', data)
        data = ustruct.pack('<HH', on, off)
        self.i2c.writeto_mem(self.address, 0x06 + 4 * index,  data)

    def duty(self, index, value=None, invert=False):
        if value is None:
            pwm = self.pwm(index)
            if pwm == (0, 4096):
                value = 0
            elif pwm == (4096, 0):
                value = 4095
            value = pwm[1]
            if invert:
                value = 4095 - value
            return value
        if not 0 <= value <= 4095:
            raise ValueError("Out of range")
        if invert:
            value = 4095 - value
        if value == 0:
            self.pwm(index, 0, 4096)
        elif value == 4095:
            self.pwm(index, 4096, 0)
        else:
            self.pwm(index, 0, value)

servo

import pca9685
import math

class Servos:
    def __init__(self, i2c, address=0x40, freq=50, min_us=600, max_us=2400,
                 degrees=180):
        self.period = 1000000 / freq
        self.min_duty = self._us2duty(min_us)
        self.max_duty = self._us2duty(max_us)
        self.degrees = degrees
        self.freq = freq
        self.pca9685 = pca9685.PCA9685(i2c, address)
        self.pca9685.freq(freq)

    def _us2duty(self, value):
        return int(4095 * value / self.period)

    def position(self, index, degrees=None, radians=None, us=None, duty=None):
        span = self.max_duty - self.min_duty
        if degrees is not None:
            duty = self.min_duty + span * degrees / self.degrees
        elif radians is not None:
            duty = self.min_duty + span * radians / math.radians(self.degrees)
        elif us is not None:
            duty = self._us2duty(us)
        elif duty is not None:
            pass
        else:
            return self.pca9685.duty(index)
        duty = min(self.max_duty, max(self.min_duty, int(duty)))
        self.pca9685.duty(index, duty)

    def release(self, index):
        self.pca9685.duty(index, 0)

main

from machine import Pin, SoftI2C
import servo

i2c = SoftI2C(scl=Pin(18), sda=Pin(19), freq=100000)
servo = Servos(i2c, address=0x40, freq=50, min_us=650, max_us=2800, degrees=180)

for i in range(0, 180):
    servo.position(0, i) #0接口,度数
    print(i)
    time.sleep(0.2) #间隔时间

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值