You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python向带外部EEPROM的Arduino串口传输数据中断求助

Troubleshooting and Fixing Serial Transfer Interruption Between Python and Arduino

Let's break down the issues causing your serial transfer to interrupt early, and fix them step by step:

Python Code Issues & Fixes

  1. Redundant & Misplaced Serial Reads
    Your current code calls ser.readline() multiple times in nested loops, which causes you to discard incoming serial data accidentally. For example, in the loop checking for "OK\n", you call ser.readline() again to check for "write\n"—this skips the actual response you're waiting for.
  2. Unnecessary Duplicate Writes
    You're writing "SOK\n" twice in the data send loop, which confuses the Arduino's state machine.
  3. Missing Serial Timeout Handling
    Without setting a timeout on the serial port, your Python code can hang indefinitely if the Arduino doesn't send the expected response.

Fixed Python Code

import binascii
import serial
import time

# Set up serial with a timeout to prevent hanging
ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=1)
totalcount = 0

# Wait for Arduino to request address
while True:
    response = ser.readline().decode('utf-8').strip()
    if response == "address":
        ser.write(b"0\n")  # Send address with newline to match Arduino's reading
        print("Sent address 0")
        break

# Read and process the file
with open('TestCard.txt', 'rb') as f:
    hexdata = binascii.hexlify(f.read())
    # Split into 2-character hex chunks (1 byte each)
    hexlist = [hexdata[i:i+2].decode('utf-8') for i in range(0, len(hexdata), 2)]

for idx, hex_byte in enumerate(hexlist):
    # Send transfer request
    ser.write(b"srq\n")
    print("Sent srq")
    
    # Wait for Arduino's OK response
    while True:
        response = ser.readline().decode('utf-8').strip()
        if response == "OK":
            print("Received OK")
            break
        elif response == "write":
            # Resend srq if Arduino asks for it
            ser.write(b"srq\n")
            print("Resent srq after write request")
    
    # Wait for Arduino's read request
    while True:
        response = ser.readline().decode('utf-8').strip()
        if response == "read":
            ser.write(b"SOK\n")
            print("Sent SOK")
            break
    
    # Send the hex byte (convert to bytes)
    ser.write(hex_byte.encode('utf-8') + b"\n")  # Add newline to signal end of byte
    print(f"Written {hex_byte}")
    totalcount += 1
    
    # Log every 16 bytes
    if (idx + 1) % 16 == 0:
        print("\n=== 16 Bytes Sent ===\n")

# Send EOF signal
ser.write(b"EOF\n")
print("\nSent EOF")
ser.close()

Arduino Code Issues & Fixes

  1. Broken String Comparison Functions
    Your checksrq(), checkEOF(), and checkSOK() functions are flawed—they overwrite the same flag on every character, so only the last character determines the result. You need to check all characters and return false immediately if any mismatch occurs.
  2. Incorrect Function Call in Loop
    while(checkSOK == false) is missing parentheses (checkSOK()), so it's comparing the function pointer to false instead of calling the function. This causes an infinite loop, which halts the transfer.
  3. Unchecked Serial Reads
    You call Serial.read() without checking if data is available, which returns -1 (a byte value of 0xFF) when no data is present, corrupting your comparison checks.
  4. Buggy Address Calculation
    addr += i inside the 16-byte loop causes the address to accumulate incorrectly (e.g., 0+0+1+2+...+15 = 120 instead of 0-15 for the first block). You need a separate variable to track the current EEPROM address.
  5. EOF Handling Logic
    The EOF check is only done once at the start of the loop, so the Arduino doesn't respond to EOF during data transfer.

Fixed Arduino Code

#include <Wire.h>

#define EEPROM_ADDR 0x50
byte buff[16];
int current_addr = -1;
int byte_count = 0;
char read_buffer[5]; // Hold up to 4 characters + null terminator
const char srq[] = "srq";
const char eof[] = "EOF";
const char sok[] = "SOK";
bool transfer_ended = false;

// EEPROM Write/Read Functions (unchanged, but kept for completeness)
void i2c_eeprom_write_byte(int deviceaddress, unsigned int eeaddress, byte data) {
    Wire.beginTransmission(deviceaddress);
    Wire.write((int)(eeaddress >> 8)); // MSB
    Wire.write((int)(eeaddress & 0xFF)); // LSB
    Wire.write(data);
    Wire.endTransmission();
    delay(5); // EEPROM needs time to write
}

byte i2c_eeprom_read_byte(int deviceaddress, unsigned int eeaddress) {
    byte rdata = 0xFF;
    Wire.beginTransmission(deviceaddress);
    Wire.write((int)(eeaddress >> 8)); // MSB
    Wire.write((int)(eeaddress & 0xFF)); // LSB
    Wire.endTransmission();
    Wire.requestFrom(deviceaddress, 1);
    if (Wire.available()) rdata = Wire.read();
    return rdata;
}

// Helper: Read a line from serial (returns true if line was read)
bool read_serial_line(char* buffer, size_t buffer_size) {
    static int idx = 0;
    while (Serial.available() > 0) {
        char c = Serial.read();
        if (c == '\n' || c == '\r') {
            buffer[idx] = '\0';
            idx = 0;
            return true;
        } else if (idx < buffer_size - 1) {
            buffer[idx++] = c;
        }
    }
    return false;
}

// Fixed string comparison functions
bool is_srq() {
    return strcmp(read_buffer, srq) == 0;
}

bool is_eof() {
    return strcmp(read_buffer, eof) == 0;
}

bool is_sok() {
    return strcmp(read_buffer, sok) == 0;
}

void setup() {
    Wire.begin();
    Serial.begin(9600);
    while (!Serial); // Wait for serial to connect (for USB boards)
}

void loop() {
    if (transfer_ended) {
        delay(1000);
        return;
    }

    // Step 1: Wait for address from Python
    while (current_addr == -1 && !transfer_ended) {
        Serial.println("address");
        if (read_serial_line(read_buffer, sizeof(read_buffer))) {
            // Convert received string to integer address
            current_addr = atoi(read_buffer);
            Serial.print("Received address: ");
            Serial.println(current_addr);
        }
        delay(200);
    }

    // Step 2: Wait for SRQ or EOF
    bool srq_received = false;
    while (!srq_received && !transfer_ended) {
        if (read_serial_line(read_buffer, sizeof(read_buffer))) {
            if (is_srq()) {
                Serial.println("OK");
                srq_received = true;
            } else if (is_eof()) {
                transfer_ended = true;
                Serial.println("Transfer ended (EOF received)");
            }
        }
        delay(10);
    }

    if (transfer_ended) return;

    // Step 3: Request data from Python
    Serial.println("read");
    bool sok_received = false;
    while (!sok_received && !transfer_ended) {
        if (read_serial_line(read_buffer, sizeof(read_buffer))) {
            if (is_sok()) {
                sok_received = true;
            } else {
                Serial.println("read"); // Re-request if not SOK
            }
        }
        delay(10);
    }

    if (transfer_ended) return;

    // Step 4: Read 1 byte of hex data, convert to byte value
    if (read_serial_line(read_buffer, sizeof(read_buffer))) {
        byte data_byte = strtol(read_buffer, NULL, 16);
        buff[byte_count++] = data_byte;

        // When we have 16 bytes, write to EEPROM
        if (byte_count == 16) {
            for (int i = 0; i < 16; i++) {
                i2c_eeprom_write_byte(EEPROM_ADDR, current_addr + i, buff[i]);
                Serial.println("write");
            }
            current_addr += 16; // Move to next EEPROM page
            byte_count = 0;
            Serial.println("Next Block");
        }
    }
}

Key Improvements Summary

  • Python: Added serial timeout, simplified response handling to avoid data loss, fixed duplicate writes, and ensured consistent newline framing.
  • Arduino: Fixed string comparison logic, added proper serial line reading (with null termination), corrected address calculation, fixed the infinite loop bug, and improved EOF handling.

These changes should resolve the early transfer interruptions and ensure reliable 1024-byte data transfer to the EEPROM.

内容的提问来源于stack exchange,提问作者Jimmy.D

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:35:47