How to transmit and receive raw data from a microcontroller to a remote computer?

 Here’s a practical, no-fluff roadmap for sending raw bytes between a microcontroller and a remote computer (over the internet).



1) Pick your transport

  • Direct IP from the MCU: MCU with Ethernet/Wi-Fi (e.g., ESP32, W5500, NINA) → TCP or UDP sockets to a public server.

  • Via a gateway: MCU talks UART/USB to a Raspberry Pi (or similar), and the Pi forwards data over TCP/UDP/SSH/VPN.

  • Cellular/LPWAN: Use LTE-M/NB-IoT modem (PPP/AT or built-in sockets). Same socket idea, just different link.

Tip: Inbound connections to a device behind NAT are painful. Easiest: host a public server (cloud VM) and have the MCU dial out to it.

2) Frame your “raw” bytes

Raw ≠ structureless. Use a tiny frame so both sides can parse:

[0xAA 0x55] [LEN(2B)] [PAYLOAD (LEN bytes)] [CRC16(2B)]

Or simpler: [LEN][PAYLOAD]. If you stream without length, at least add a delimiter (e.g., '\n') and escape it when it appears in data.

3) Reliability & security

  • TCP gives ordered, reliable bytes (most common).

  • UDP is lighter/low-latency, but add sequence numbers, ACK/timeout if you need reliability.

  • Security: Use TLS (client → server). If TLS on MCU is heavy, terminate TLS on the server (e.g., stunnel/Nginx “stream”) and keep the MCU→server hop inside a VPN (e.g., WireGuard).

4) Minimal working example (TCP)

A) Remote computer (server) — Python 3

# server.py (listens on 0.0.0.0:5000) import socket, struct def recv_all(sock, n): data = b"" while len(data) < n: chunk = sock.recv(n - len(data)) if not chunk: return None data += chunk return data with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind(("", 5000)) s.listen(1) print("Listening on :5000") conn, addr = s.accept() print("Client:", addr) with conn: while True: hdr = recv_all(conn, 2) # 2-byte length if not hdr: break (length,) = struct.unpack("!H", hdr) # network byte order payload = recv_all(conn, length) if payload is None: break # Do something with raw bytes: print("Got", length, "bytes:", payload.hex()) # Echo back (optional): conn.sendall(struct.pack("!H", len(payload)) + payload)

B) Microcontroller (client) — ESP32 (Arduino)

#include <WiFi.h> const char* ssid = "YOUR_SSID"; const char* pass = "YOUR_PASS"; const char* host = "YOUR_SERVER_IP_OR_DNS"; const uint16_t port = 5000; WiFiClient client; void sendFrame(const uint8_t* data, uint16_t len) { uint8_t hdr[2] = { (uint8_t)(len >> 8), (uint8_t)(len & 0xFF) }; client.write(hdr, 2); client.write(data, len); } void setup() { Serial.begin(115200); WiFi.begin(ssid, pass); while (WiFi.status() != WL_CONNECTED) delay(200); if (!client.connect(host, port)) { while (1) { delay(1000); } } // Example payload: 2 bytes sensor, 4 bytes counter (big-endian) static uint32_t counter = 0; uint8_t payload[6]; uint16_t sensor = 1234; // demo payload[0] = sensor >> 8; payload[1] = sensor & 0xFF; payload[2] = (counter >> 24) & 0xFF; payload[3] = (counter >> 16) & 0xFF; payload[4] = (counter >> 8) & 0xFF; payload[5] = (counter) & 0xFF; sendFrame(payload, sizeof(payload)); counter++; } void loop() { // Read echo (optional) while (client.available() >= 2) { uint16_t len = (client.read() << 8) | client.read(); while (client.available() < len) ; // simple demo; add timeout in real code for (uint16_t i=0;i<len;i++) (void)client.read(); // consume } delay(1000); }

No Wi-Fi/Ethernet on your MCU? Connect its UART to a Raspberry Pi and run a serial-to-socket bridge (e.g., ser2net), or write a tiny Python script on the Pi that reads /dev/ttyAMA0 and forwards to your TCP server.

5) UDP variant (when you control both ends)

  • MCU: sendto(serverIP, port, payload).

  • PC: Python socket.socket(AF_INET, SOCK_DGRAM)recvfrom.
    Add [SEQ][PAYLOAD][CRC]; the PC can ACK sequence SEQ back so the MCU retries on timeout.

6) NAT traversal options

  • Put the Python server on a public VM (recommended).

  • Or set up WireGuard between MCU’s gateway (Pi) and your PC.

  • Or use reverse SSH tunnel from a Pi:
    ssh -N -R 5000:localhost:5000 user@public-host (then the MCU connects to public-host:5000 locally on the Pi).

7) Practical checklist

  • Fixed endianness (use big-endian/network order), and document it.

  • Length-prefix frames; add CRC16 if you want quick integrity checks.

  • Keep-alive (TCP): send a short heartbeat every few seconds; detect disconnects.

  • Backpressure: use ring buffers; don’t block ISR/context.

  • Time sync if needed (NTP from MCU or gateway).

  • Throughput targets: choose TCP for reliability, UDP for low jitter.

评论

此博客中的热门博文

How To Connect Stm32 To PC?

Detailed Explanation of STM32 HAL Library Clock System

How to add a GPS sensor to ESP32 for Wokwi?