Jak wyświetlić na tablecie z systemem android przewodowo USB obraz z arduino GIGA, podaj przykładowy program?
SerialUSB
w postaci ustalonego protokołu (nagłówek + dane + stopka/CRC). usb‑serial‑for‑android
, odbiera bajty, rekonstruuje bitmapę i wyświetla ją. • Arduino GIGA R1 WiFi (USB‑C; wsparcie USB Device i USB Host)
• Moduł kamery – np. ArduCAM OV5642 lub prosty moduł SPI (OV2640/OV7670)
• Tablet Android z obsługą USB OTG + przejściówka OTG (USB‑C↔USB‑A)
Poniższy szkic przechwytuje pojedynczą klatkę JPEG z ArduCAM OV5642 (QVGA 320×240), pakuje w nagłówek i wysyła do hosta.
#include <ArduCAM.h>
#include <SPI.h>
#define CS_PIN 7 // Chip Select kamery
#define BAUD 2000000 // 2 Mb/s – realnie ok. 180 kB/s
ArduCAM cam(OV5642, CS_PIN);
void setup() {
Serial.begin(BAUD);
while (!Serial) {} // czekaj na enumerację USB
SPI.begin();
pinMode(CS_PIN, OUTPUT);
digitalWrite(CS_PIN, HIGH);
// Szybki test połączenia
cam.write_reg(ARDUCHIP_TEST1, 0x55);
if (cam.read_reg(ARDUCHIP_TEST1) != 0x55) {
Serial.println(F("Kamera nieodpowiada"));
while (1);
}
cam.set_format(JPEG);
cam.InitCAM();
cam.OV5642_set_JPEG_size(OV5642_320x240);
delay(1000);
Serial.println(F("READY"));
}
void loop() {
if (Serial.available() && Serial.read() == 'C') { // command 'C' = capture
sendFrame();
}
}
void sendFrame() {
cam.flush_fifo();
cam.clear_fifo_flag();
cam.start_capture();
while (!cam.get_bit(ARDUCHIP_TRIG, CAP_DONE_MASK));
uint32_t len = cam.read_fifo_length();
if (len == 0 || len > 250*1024) return; // sanity check
// Nagłówek: 0xAB 0xCD + 3‑bajtowa długość
uint8_t hdr[5] = {0xAB, 0xCD, (uint8_t)(len>>16), (uint8_t)(len>>8), (uint8_t)len};
Serial.write(hdr, 5);
cam.CS_LOW();
cam.set_fifo_burst();
for (uint32_t i = 0; i < len; i++) {
Serial.write(SPI.transfer(0x00));
if (i % 1024 == 0) Serial.flush(); // opróżnij bufor co 1 kB
}
cam.CS_HIGH();
uint16_t crc = 0xFFFF; // proste CRC‑16
Serial.write((uint8_t*)&crc, 2); // stopka
}
• Komenda 'C'
z tabletu uruchamia wykonanie zdjęcia.
• Nagłówek i stopka pozwalają aplikacji Android sprawdzić kompletność klatki.
Biblioteka: implementation("com.github.mik3y:usb-serial-for-android:3.5.2")
class MainActivity : AppCompatActivity() {
private lateinit var usbManager: UsbManager
private var serialPort: UsbSerialPort? = null
private val ioExecutor = Executors.newSingleThreadExecutor()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
usbManager = getSystemService(USB_SERVICE) as UsbManager
openSerial()
findViewById<Button>(R.id.btnCapture).setOnClickListener { sendCommand('C'.code) }
}
private fun openSerial() {
val driver = UsbSerialProber.getDefaultProber().findAllDrivers(usbManager).firstOrNull() ?: return
val conn = usbManager.openDevice(driver.device) ?: return
serialPort = driver.ports[0].apply {
open(conn)
setParameters(2_000_000, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE)
}
val manager = SerialInputOutputManager(serialPort, listener)
ioExecutor.submit(manager)
}
private val listener = object : SerialInputOutputManager.Listener {
private val buffer = ByteArrayOutputStream()
private var expectedLen = -1
override fun onNewData(data: ByteArray) {
for (b in data) processByte(b.toInt() and 0xFF)
}
private fun processByte(b: Int) {
buffer.write(b)
val arr = buffer.toByteArray()
if (expectedLen == -1 && arr.size >= 5 && arr[0]==0xAB.toByte() && arr[1]==0xCD.toByte()) {
expectedLen = (arr[2].toUByte().toInt() shl 16) or
(arr[3].toUByte().toInt() shl 8) or arr[4].toUByte().toInt()
buffer.reset() // usuń nagłówek
} else if (expectedLen > -1 && buffer.size() >= expectedLen + 2) { // +CRC
val jpeg = buffer.toByteArray().copyOfRange(0, expectedLen)
runOnUiThread {
val bmp = BitmapFactory.decodeByteArray(jpeg, 0, jpeg.size)
findViewById<ImageView>(R.id.imageView).setImageBitmap(bmp)
}
buffer.reset(); expectedLen = -1
}
}
override fun onRunError(e: Exception) { e.printStackTrace() }
}
private fun sendCommand(c: Int) = serialPort?.write(byteArrayOf(c.toByte()), 10)
}
• Przycisk „Capture” wysyła 'C'
, aplikacja czeka na nagłówek, odczytuje długość, kolekcjonuje JPEG i wyświetla.
• Do manifestu dodaj <uses-feature android:name="android.hardware.usb.host" android:required="true"/>
oraz filtr device_filter.xml
z VID/PID Arduino.
usb-serial-for-android
jest de‑facto standardem (ostatnia stabilna: 3.5.2 – luty 2024). Serial.flush()
po 1–2 kB ogranicza przepełnienie bufora USB. UsbSerialPort
(metoda .purgeHwBuffers()
) co kilka sekund. Arduino GIGA nie wyśle wideo do Androida jak klasyczna kamera, ale przy wykorzystaniu USB CDC można sprawnie przesłać skompresowany JPEG lub ramkę RGB. W praktyce:
SerialUSB
(przykład powyżej). usb‑serial‑for‑android
), zweryfikuj długość/CRC i wyświetl jako Bitmap
.