Example: 07-Interface-Library/00-Arduino/arduino_spi_slave.py
# 本作品采用MIT许可证授权。
# 版权所有 (c) 2013-2023 OpenMV LLC。保留所有权利。
# https://github.com/openmv/openmv/blob/master/LICENSE
#
# SPI 以 Arduino 为主设备,OpenMV Cam 为从设备。
#
# 请按如下方式将您的OpenMV Cam连接到Arduino:
#
# OpenMV Cam 主出从入 (P0) - Arduino Uno MOSI (11)
# OpenMV Cam 主入从出 (P1) - Arduino Uno MISO (12)
# OpenMV Cam 串行时钟 (P2) - Arduino Uno SCK (13)
# OpenMV Cam 从选择 (P3) - Arduino Uno SS (10)
# OpenMV Cam 地线 - Arduino 地线
import pyb
import struct
import time
text = "Hello World!\n"
data = struct.pack("<bi%ds" % len(text), 85, len(text), text) # 85 是同步字符。
# 使用“struct”构建要发送的数据包。
# “<”将结构中的数据按小端序排列。
# "b" 在数据流中放入一个有符号字符。
# "i" 在数据流中放入一个有符号整数。
# “%ds”在数据流中放入一个字符串。例如,“13s”对应“Hello World!\n”(13个字符)。
# 参见 https://docs.python.org/3/library/struct.html
# 请阅读!!!
#
# 请理解,当您的 OpenMV Cam 不是 SPI 主设备时,它可能会错过响应
# 作为 SPI 从设备发送数据,无论您是在中断回调中还是在
# 下面的主循环中调用 "spi.send()"。因此,您必须绝对设计您的通信协议,使得
# 如果从设备(OpenMV Cam)没有及时调用 "spi.send()",则垃圾数据
# 从SPI外设读取的数据由主设备(Arduino)丢弃。为了实现这一点,我们使用
# 同步字符85(二进制01010101),Arduino会将其作为读取的第一个字节。
# 如果没有看到这个字符,它将中止SPI事务并重试。其次,为了
# 清除SPI外设状态,我们总是发送四字节的倍数,并额外发送四个零
# 字节,以确保SPI外设不会保留任何可能是85的陈旧数据。注意
# OpenMV Cam会随机错过“spi.send()”窗口,因为它需要处理
# 中断。连接到PC时,中断会频繁发生。
# 您的OpenMV Cam的硬件SPI总线始终是SPI总线2。
# 极性=0 -> 时钟空闲时为低电平。
# 相位=0 -> 在时钟上升沿采样数据,在时钟下降沿输出数据。
spi = pyb.SPI(2, pyb.SPI.SLAVE, polarity=0, phase=0)
# NSS回调。
def nss_callback(line):
global spi, data
try:
spi.send(data, timeout=1000)
except OSError as err:
pass # 不要在意错误 - 所以跳过。
# 请注意,有3种可能的错误。超时错误、通用错误或
# 忙碌错误。错误代码分别为116、5、16,对应"err.arg[0]"。
# 配置NSS/CS为IRQ模式,以便在主设备请求时发送数据。
pyb.ExtInt(pyb.Pin("P3"), pyb.ExtInt.IRQ_FALLING, pyb.Pin.PULL_UP, nss_callback)
while True:
time.sleep_ms(1000)
###################################################################################################
# Arduino代码
###################################################################################################
#
# #include <SPI.h>
# #define SS_PIN 10
# #define BAUD_RATE 19200
# #define CHAR_BUF 128
#
# 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); // Give the OpenMV Cam time to bootup.
# }
#
# void loop() {
# int32_t len = 0;
# char buff[CHAR_BUF] = {0};
# digitalWrite(SS_PIN, LOW);
# delay(1); // Give the OpenMV Cam some time to setup to send data.
#
# if(SPI.transfer(1) == 85) { // saw sync char?
# SPI.transfer(&len, 4); // get length
# if (len) {
# SPI.transfer(&buff, min(len, CHAR_BUF));
# len -= min(len, CHAR_BUF);
# }
# while (len--) SPI.transfer(0); // eat any remaining bytes
# }
#
# digitalWrite(SS_PIN, HIGH);
# Serial.print(buff);
# delay(1); // Don't loop to quickly.
# }