# Arduino 作为SPI主设备, OpenMV作为SPI从设备。
# 请把OpenMV和Arduino Uno按照下面连线:
# OpenMV Cam Master Out Slave In (P0) - Arduino Uno MOSI (11)
# OpenMV Cam Master In Slave Out (P1) - Arduino Uno MISO (12)
# OpenMV Cam Serial Clock (P2) - Arduino Uno SCK (13)
# OpenMV Cam Slave Select (P3) - Arduino Uno SS (10)
# OpenMV Cam Ground - Arduino Ground
# 请把OpenMV和Arduino 2560按照下面连线:
# OpenMV Cam Master Out Slave In (P0) - Arduino Uno MOSI (51)
# OpenMV Cam Master In Slave Out (P1) - Arduino Uno MISO (50)
# OpenMV Cam Serial Clock (P2) - Arduino Uno SCK (52)
# OpenMV Cam Slave Select (P3) - Arduino Uno SS (53)
# OpenMV Cam Ground - Arduino Ground
openmv4IDE代码:
import pyb, ustruct, time text = "Hello World! " data = ustruct.pack("<bi%ds" % len(text), 85, len(text), text) # 85 is a sync char. # 使用 "ustruct" 来生成需要发送的数据包 # "<" 把数据以小端序放进struct中 # "b" 把一个 signed char 放进数据流 # "i" 把一个 signed integer 放进数据流 # "%ds" 把字符串放进数据流,比如:"13s" 对应的 "Hello World! " (13 chars). # 详见 https://docs.python.org/3/library/struct.html # 零填充数据为4字节加4字节的倍数。 data += "x00" * (4 + (len(data) % 4)) # READ ME!!! # # 请理解,当您的OpenMV摄像头不是SPI主设备,所以不管是使用中断回调, # 还是下方的轮循,都可能会错过响应发送数据给主机。处于这点, # 你必须设计你的通信协议,比如从设备(OpenMV)没有及时调用"spi.send()"回应, # 那么SPI读取到的垃圾数据应该被丢弃。为了达到这个目的,我们使用一个85 # (二进制01010101)的同步字符,Arduino将把它看作是第一个读取的字节。 # 如果它没有看到这个,那么它会中止SPI事务,然后再试一次。 其次, # 为了清除SPI外设状态,我们总是发送四个字节的倍数和一个额外的四个零字节, # 以确保SPI外设不会保存可能为85的任何陈旧数据。注意,OpenMV可能会随机 # 错过调用 "spi.send()",因为中断服务程序。当你连接到电脑的时候,中断 # 可能会发生很多次。 # OpenMV上的硬件SPI总线都是2 # polarity = 0 -> clock 闲时为低 # phase = 0 -> 取样数据在clock上升沿,输出数据在下降沿。 spi = pyb.SPI(2, pyb.SPI.SLAVE, polarity=0, phase=0) # NSS callback. def nss_callback(line): global spi, data try: spi.send(data, timeout=1000) # 如果同步第一帧失败,我们再一次同步 print("Sent Data!") # 没有遇到错误时,会显示 except OSError as err: pass # 不用担心遇到错误,会跳过 # 请注意,有3个可能的错误。 超时错误(timeout error), # 通用错误(general purpose error)或繁忙错误 #(busy error)。 “err.arg[0]”的错误代码分别 # 为116,5,16。 # 在IRQ模式中配置NSS/CS,以便在主机请求时发送数据 pyb.ExtInt(pyb.Pin("P3"), pyb.ExtInt.IRQ_FALLING, pyb.Pin.PULL_UP, nss_callback) while(True): time.sleep(1)
arduino代码:
#include <SPI.h> #define SS_PIN 53 //10引脚得改为53管脚 #define BAUD_RATE 19200 #define CHAR_BUF 128 int temp; void setup() { pinMode(SS_PIN, OUTPUT); Serial.begin(BAUD_RATE); SPI.begin(); SPI.setBitOrder(MSBFIRST); SPI.setClockDivider(SPI_CLOCK_DIV16); SPI.setDataMode(SPI_MODE0); delay(1000); // 给OpenMV摄像头启动的时间 } void loop(){ int32_t len = 0; char buff[CHAR_BUF] = {0}; digitalWrite(SS_PIN, LOW); delay(1); // 给OpenMV摄像头一些时间来设置发送数据 if (SPI.transfer(1) == 85) { // saw sync char? SPI.transfer(&len, 4); // get length if (len) { SPI.transfer(&buff, min(len, CHAR_BUF)); temp -= min(len, CHAR_BUF); } while (len--) SPI.transfer(0); // eat any remaining bytes } digitalWrite(SS_PIN, HIGH); Serial.print(buff); delay(1); // 延时一点时间,不要马上循环 }
openmv4运行效果:
arduuno运行效果:
本文章实现了主从设备的发送与接受数据!
正是步行者,一步步登峰!