Back in 2014 I posted this Python - Arduino demo. When I looked at it recently it seemed out of line with my more recent Serial Input Basics - updated which was written 2 years later.
In the following pair of programs the Arduino code is almost identical to the code in the 3rd example in Serial Input Basics and the Python code simply sends a short message to the Arduino and prints the reply it receives.
The Python code works with Python3 and Python2.
Arduino Code
// This is very similar to Example 3 - Receive with start- and end-markers
// in Serial Input Basics http://forum.arduino.cc/index.php?topic=396450.0
const byte numChars = 64;
char receivedChars[numChars];
boolean newData = false;
byte ledPin = 13; // the onboard LED
//===============
void setup() {
Serial.begin(115200);
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, HIGH);
delay(200);
digitalWrite(ledPin, LOW);
delay(200);
digitalWrite(ledPin, HIGH);
Serial.println("<Arduino is ready>");
}
//===============
void loop() {
recvWithStartEndMarkers();
replyToPython();
}
//===============
void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;
while (Serial.available() > 0 && newData == false) {
rc = Serial.read();
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
}
else if (rc == startMarker) {
recvInProgress = true;
}
}
}
//===============
void replyToPython() {
if (newData == true) {
Serial.print("<This just in ... ");
Serial.print(receivedChars);
Serial.print(" ");
Serial.print(millis());
Serial.print('>');
// change the state of the LED everytime a reply is sent
digitalWrite(ledPin, ! digitalRead(ledPin));
newData = false;
}
}
//===============
Python code
import serial
import time
startMarker = '<'
endMarker = '>'
dataStarted = False
dataBuf = ""
messageComplete = False
#========================
#========================
# the functions
def setupSerial(baudRate, serialPortName):
global serialPort
serialPort = serial.Serial(port= serialPortName, baudrate = baudRate, timeout=0, rtscts=True)
print("Serial port " + serialPortName + " opened Baudrate " + str(baudRate))
waitForArduino()
#========================
def sendToArduino(stringToSend):
# this adds the start- and end-markers before sending
global startMarker, endMarker, serialPort
stringWithMarkers = (startMarker)
stringWithMarkers += stringToSend
stringWithMarkers += (endMarker)
serialPort.write(stringWithMarkers.encode('utf-8')) # encode needed for Python3
#==================
def recvLikeArduino():
global startMarker, endMarker, serialPort, dataStarted, dataBuf, messageComplete
if serialPort.inWaiting() > 0 and messageComplete == False:
x = serialPort.read().decode("utf-8") # decode needed for Python3
if dataStarted == True:
if x != endMarker:
dataBuf = dataBuf + x
else:
dataStarted = False
messageComplete = True
elif x == startMarker:
dataBuf = ''
dataStarted = True
if (messageComplete == True):
messageComplete = False
return dataBuf
else:
return "XXX"
#==================
def waitForArduino():
# wait until the Arduino sends 'Arduino is ready' - allows time for Arduino reset
# it also ensures that any bytes left over from a previous message are discarded
print("Waiting for Arduino to reset")
msg = ""
while msg.find("Arduino is ready") == -1:
msg = recvLikeArduino()
if not (msg == 'XXX'):
print(msg)
#====================
#====================
# the program
setupSerial(115200, "/dev/ttyACM0")
count = 0
prevTime = time.time()
while True:
# check for a reply
arduinoReply = recvLikeArduino()
if not (arduinoReply == 'XXX'):
print ("Time %s Reply %s" %(time.time(), arduinoReply))
# send a message at intervals
if time.time() - prevTime > 1.0:
sendToArduino("this is a test " + str(count))
prevTime = time.time()
count += 1
...R