例程讲解-02-arduino_spi_slave 从设备
# Arduino 作为SPI主设备, OpenMV作为SPI从设备。
#
# 请把OpenMV和Arduino按照下面连线:
#
# 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
import pyb, ustruct, time
text = "Hello World!\n"
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!\n" (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_ms(1000)
###################################################################################################
# Arduino Code
###################################################################################################
#
#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); // 给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); // 延时一点时间,不要马上循环
}