arduino_i2c_slave.py
# Este trabalho está licenciado sob a licença MIT.
# Copyright (c) 2013-2023 OpenMV LLC. Todos os direitos reservados.
# https://github.com/openmv/openmv/blob/master/LICENSE
#
# I2C com o Arduino como dispositivo mestre e a OpenMV Cam como escravo.
#
# Conecte sua OpenMV Cam ao seu Arduino da seguinte forma:
#
# OpenMV Cam Master I2C Data (P5) - Arduino Uno Data (A4)
# OpenMV Cam Master I2C Clock (P4) - Arduino Uno Clock (A5)
# OpenMV Cam Ground - Arduino Ground
import pyb
import struct
text = "Hello World!\n"
data = struct.pack("<%ds" % len(text), text)
# Use "struct" para montar os pacotes de dados a serem enviados.
# "<" coloca os dados na struct em ordem little endian.
# "%ds" coloca uma string no fluxo de dados. Ex.: "13s" para "Hello World!\n" (13 caracteres).
# Veja https://docs.python.org/3/library/struct.html
# LEIA-ME!!!
#
# Entenda que, quando sua OpenMV Cam não é o mestre I2C, ela pode deixar de responder ao
# envio de dados como escravo I2C, mesmo que você chame "i2c.send()" em um callback de interrupção ou no
# laço principal abaixo. Quando isso acontece, o Arduino recebe um NAK e precisa tentar ler novamente da
# OpenMV Cam. Note que tanto os drivers I2C do Arduino quanto os da OpenMV Cam não são bons para se
# recuperarem após encontrar qualquer erro I2C. Na OpenMV Cam e no Arduino, você pode se recuperar
# desinicializando e reinicializando os periféricos I2C.
# O barramento I2C de hardware da sua OpenMV Cam é sempre o barramento I2C 2.
bus = pyb.I2C(2, pyb.I2C.SLAVE, addr=0x12)
bus.deinit() # Redefine totalmente o dispositivo I2C...
bus = pyb.I2C(2, pyb.I2C.SLAVE, addr=0x12)
print("Waiting for Arduino...")
# Note que, para que a sincronização funcione corretamente, a OpenMV Cam deve estar executando este script antes que o
# Arduino comece a consultar a OpenMV Cam em busca de dados. Caso contrário, o enquadramento de bytes I2C fica bagunçado,
# e assim por diante. Portanto, mantenha o Arduino em reset até que a OpenMV Cam esteja em "Waiting for Arduino...".
while True:
try:
bus.send(
struct.pack("<h", len(data)), timeout=10000
) # Envia primeiro o len (16 bits).
try:
bus.send(data, timeout=10000) # Envia os dados em seguida.
print("Sent Data!") # Só é alcançado quando não há erro.
except OSError as err:
pass # Não se importa com erros - portanto, pass.
# Note que há 3 possíveis erros. Um erro de timeout, um erro de propósito geral, ou
# um erro de ocupado. Os códigos de erro são 116, 5, 16, respectivamente, para "err.arg[0]".
except OSError as err:
pass # Não se importa com erros - portanto, pass.
# Note que há 3 possíveis erros. Um erro de timeout, um erro de propósito geral, ou
# um erro de ocupado. Os códigos de erro são 116, 5, 16, respectivamente, para "err.arg[0]".
###################################################################################################
# Código do Arduino
###################################################################################################
#
# #include <Wire.h>
# #define BAUD_RATE 19200
# #define CHAR_BUF 128
#
# void setup() {
# Serial.begin(BAUD_RATE);
# Wire.begin();
# delay(1000); // Dá tempo para a OpenMV Cam inicializar.
# }
#
# void loop() {
# int32_t temp = 0;
# char buff[CHAR_BUF] = {0};
#
# Wire.requestFrom(0x12, 2);
# if(Wire.available() == 2) { // obteve o comprimento?
#
# temp = Wire.read() | (Wire.read() << 8);
# delay(1); // Dá algum tempo de preparação...
#
# Wire.requestFrom(0x12, temp);
# if(Wire.available() == temp) { // obteve a mensagem completa?
#
# temp = 0;
# while(Wire.available()) buff[temp++] = Wire.read();
#
# } else {
# while(Wire.available()) Wire.read(); // Descarta bytes inválidos.
# }
# } else {
# while(Wire.available()) Wire.read(); // Descarta bytes inválidos.
# }
#
# Serial.print(buff);
# delay(1); // Não repete o laço rápido demais.
# }