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
- Redundant & Misplaced Serial Reads
Your current code callsser.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 callser.readline()again to check for "write\n"—this skips the actual response you're waiting for. - Unnecessary Duplicate Writes
You're writing "SOK\n" twice in the data send loop, which confuses the Arduino's state machine. - 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
- Broken String Comparison Functions
Yourchecksrq(),checkEOF(), andcheckSOK()functions are flawed—they overwrite thesameflag 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. - 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. - Unchecked Serial Reads
You callSerial.read()without checking if data is available, which returns-1(a byte value of 0xFF) when no data is present, corrupting your comparison checks. - Buggy Address Calculation
addr += iinside 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. - 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
相关产品推荐
相关产品推荐

