• OpenMV与I2C二线串行协议


    在OpenMV的底层逻辑中,I2C被定义为一个类


    I2C类—二线串行协议

    I2C是一个设备间传输的二线串行协议。其物理层包括两条线:SCL和SDA,分别为时钟线数据线OpenMV不再为SDA和SCL提供上拉,因此SDA和SCL需要外部上拉才能使I2C工作

    I2C对象创建在特定总线上。可在创建时或创建后初始化。

    例子:

    bus:总线	master:主机		slaves:从机
    
    • 1
    from pyb import I2C
    
    i2c = I2C(2)                         # 在总线2上创建
    
    i2c = I2C(2, I2C.MASTER)             # 初始化为主机
    	或
    i2c.init(I2C.MASTER, baudrate=20000) # 初始化为master,设置时钟频率为20000hz
    
    i2c.init(I2C.SLAVE, addr=0x42)       # 初始化为具有给定地址的从机
    
    i2c.deinit()                         # 关闭外设
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    其中的两个常量

    • I2C.MASTER将总线初始化为**"主机"模式**
    • I2C.SLAVE将总线初始化为**"从机"模式**

    打印i2c对象可以提供关于其配置的信息

    发送与接受

    发送:

    i2c.send(‘abc’) # 发送3个字节
     i2c.send(0x42) #发送由括号内给定的单个字节
    
    • 1
    • 2

    接收:

    i2c.recv(3) # 接收3个字节
    
    • 1

    接收数据,先创建一个缓冲区bytearray:

    data = bytearray(3)  # create a buffer 创建一个缓冲区
    i2c.recv(data)       # receive 3 bytes, writing them into data 接收3个字节,并将其写入数据
    
    • 1
    • 2

    你可以指定一个超时时长(单位:毫秒):

    i2c.send(b'123', timeout=2000)   # timeout after 2 seconds 2秒后超时
    
    • 1

    主机必须指定接收方地址

    i2c.init(I2C.MASTER)
    i2c.send('123', 0x42)        # send 3 bytes to slave with address 0x42 使用0x42地址向从机发送3个字节
    i2c.send(b'456', addr=0x42)  # keyword for address 地址关键字
    
    • 1
    • 2
    • 3

    主机也有其他方法

    i2c.is_ready(0x42)           # check if slave 0x42 is ready 检查从机0x42是否准备充分
    i2c.scan()                   # scan for slaves on the bus, returning
                                 #   a list of valid addresses 在总线上浏览从机,返回一个有效地址列表
                                 
    i2c.mem_read(3, 0x42, 2)     # read 3 bytes from memory of slave 0x42, 从从机0x42的内存中读取3个字节
                                 #   starting at address 2 in the slave  从从机的地址2开始
                                 
    i2c.mem_write('abc', 0x42, 2, timeout=1000) # write 'abc' (3 bytes) to memory of slave 0x42 将“abc”写入从机内存
                                                # starting at address 2 in the slave, timeout after 1 second 从从机的地址2开始,1秒后超时
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    构造函数

    class pyb.I2C(bus, ...)
    
    • 1

    在给定总线上构建一个I2C对象。 bus 可为24在没有其他参数的情况下,可创建I2C对象,但未进行初始化( 该对象的设置来自总线的最后一次初始化,若存在的话)。
    若给定额外参数则总线进行初始化。初始化参数详见 init 。

    OpenMV CamI2C总线的物理引脚为:

    • I2C(2) is on the Y position: (SCL, SDA) = (P4, P5) = (PB10, PB11)

    OpenMV Cam M7中:

    • I2C(2) is on the Y position: (SCL, SDA) = (P4, P5) = (PB10, PB11)
    • I2C(4) is on the Y position: (SCL, SDA) = (P7, P8) = (PD12, PD13)

    方法

    关闭I2C总线

    I2C.deinit()
    
    • 1

    初始化I2C总线

    使用给定参数初始化I2C总线:

    I2C.init(mode, \*, addr=0x12, baudrate=400000, gencall=False, dma=False)
    
    • 1
    • mode 须为 主机I2C.MASTER 或 从机I2C.SLAVE
    • addr 是一个7位地址 (只对从机有效)
    • baudrateSCL时钟线的时钟频率 (只对主机有效)
    • gencall 是指是否支持一般调用模式。
    • dma 是否允许将DMA用于I2C传输(请注意,DMA传输具有更精确的时序,但目前不能正确处理总线错误)

    检测从机是否准备好

    I2C.is_ready(addr)
    
    • 1

    检查I2C设备是否响应给定地址。只在主模式有效(只能由主机调用)


    主机读从机的数据

    I2C.mem_read(data, addr, memaddr, \*, timeout=5000, addr_size=8
    
    • 1

    从I2C设备(从机)内存中读取

    • data 可为一个要读入的整数(要读取的字节数量)或缓冲区
    • addrI2C设备地址
    • memaddrI2C设备中内存的位置
    • timeout 是以毫秒计的等待读取的超时时长
    • addr_size 选择memaddr宽度:8或16位
      返回读取数据。只在主模式下有效(只能由主机调用)。

    主机向从机中写入数据

    I2C.mem_write(data, addr, memaddr, \*, timeout=5000, addr_size=8)
    
    • 1

    写入I2C设备的内存:

    • data 可为一个用来写入的整数或缓冲区。
    • addrI2C设备的地址。
    • memaddrI2C设备中存储写入数据的内存的位置
    • timeout 是以毫秒计的等待写入的超时时长
    • addr_size 选择memaddr宽度:8或16位
      返回值为 None. 只在主模式下有(该方法只能由主机调用)

    在总线上接受数据

    I2C.recv(recv, addr=0x00, \*, timeout=5000)
    
    • 1

    总线上接受数据

    • recv 可为一个整数,即接收的字节的数量;或为一个使用收到的字节来填充的可变缓冲区。
    • addr 是用以接收的地址(只在主模式下需要)
    • timeout 是以毫秒计的等待接收的超时时长
      返回值:若 recv 为一个整数,则有一个新的字节缓冲区来接收,否则这一缓冲区将传递给recv

    在总线上发送数据

    I2C.send(send, addr=0x00, \*, timeout=5000)
    
    • 1

    总线上发送数据:

    • send 是要发送的数据(一个整数或一个缓冲区对象)
    • addr 是要发送到的地址(只在主模式下需要
    • timeout 是以毫秒计的等待发送的超时时长
      返回值: None.

    主机浏览从机

    I2C.scan()
    
    • 1

    浏览从0x010x7f的所有I2C地址,并返回一个响应的地址的列表只在主模式下有效。


    例子

    # Arduino 作为I2C主设备, OpenMV作为I2C从设备。
    #
    # 请把OpenMV和Arduino按照下面连线:
    #
    # OpenMV Cam Master I2C Data  (P5) - Arduino Uno Data  (A4)     SDA数据线
    # OpenMV Cam Master I2C Clock (P4) - Arduino Uno Clock (A5)     SCL时钟线
    # OpenMV Cam Ground                - Arduino Ground             GND地线
    
    import pyb, ustruct # ustruct 用于打包和解压原始数据类型 的 "类"
    
    text = "Hello World!\n"
    data = ustruct.pack("<%ds" % len(text), text)
    # 使用 "ustruct" 来生成需要发送的数据包 
            #ustruct.pack(fmt, v1, v2, ...):根据格式字符串fmt,打包 v1, v2, … 值。返回值为一个解码该值的字节对象
            # "<" 把数据以小端序放进struct中
            # "%ds" 把字符串放进数据流,比如:"13s" 对应的 "Hello World!\n" (13 chars).
    # 详见 https://docs.python.org/3/library/struct.html
    
    
    # READ ME!!!
    #
    # 请理解,当您的OpenMV摄像头不是I2C主设备,所以不管是使用中断回调,
    # 还是下方的轮循,都可能会错过响应发送数据给主机。当这种情况发生时,
    # Arduino会获得NAK,并且不得不从OpenMV再次读数据。请注意,
    # OpenMV和Arduino都不擅长解决I2C的错误。在OpenMV和Arduino中,
    # 你可以通过释放I2C外设,再重新初始化外设,来恢复功能。
    
    
    # 构造I2C对象
    # OpenMV上的硬件I2C总线都是2
    bus = pyb.I2C(2, pyb.I2C.SLAVE, addr=0x12)
    bus.deinit() # 完全关闭设备
    bus = pyb.I2C(2, pyb.I2C.SLAVE, addr=0x12)
    print("Waiting for Arduino...")
    
    
    
    # 请注意,为了正常同步工作,OpenMV Cam必须 在Arduino轮询数据之前运行此脚本。
    # 否则,I2C字节帧会变得乱七八糟。所以,保持Arduino在reset状态,
    # 直到OpenMV显示“Waiting for Arduino...”。
    
    
    while(True):
        try:
            bus.send(ustruct.pack("<h", len(data)), timeout=10000) # 首先发送长度 (16-bits).
            try:
                bus.send(data, timeout=10000) # 然后发送数据
                print("Sent Data!") # 没有遇到错误时,会显示
            except OSError as err: # 如果遇到错误 触发异常
                pass # 不用担心遇到错误,会跳过
                # 请注意,有3个可能的错误。 超时错误(timeout error),
                # 通用错误(general purpose error)或繁忙错误
                #(busy error)。 “err.arg[0]”的错误代码分别
                # 为116,5,16。
        except OSError as err:
            pass # 不用担心遇到错误,会跳过
            # 请注意,有3个可能的错误。 超时错误(timeout error),
            # 通用错误(general purpose error)或繁忙错误
            #(busy error)。 “err.arg[0]”的错误代码分别
            # 为116,5,16。
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
  • 相关阅读:
    BUUCTF-做题记录
    Springboot知识点梳理(一)
    Java-Web手写MVC框架
    mysql主从复制和读写分离
    v-if与v-show造成部分元素丢失的问题——v-if复用元素问题
    vue3插槽、具名插槽、作用域插槽-足够入门了!
    Health Kit申请验证有问题?解决方案全解析
    Windows实现到WSL的免密登录
    计算机毕业设计ssm社区疫情防控系统3j56g系统+程序+源码+lw+远程部署
    服务器卡顿了该如何处理
  • 原文地址:https://blog.csdn.net/m0_59466249/article/details/125404643