EDIT: solution found - see Arduino Uno intermittently stops writing to serial buffer - #9 by system - Interfacing w/ Software on the Computer - Arduino Forum
I'm using my Uno to control a stepper motor (with an EasyDriver) and a relay to control a valve.
The code below waits for me to send a single byte over serial then sends back a message to confirm that it's executed the command.
Here's the code:
// parameters
const int stepsPerRev = 200; // depends on stepper
const int microstepsPerStep = 8; // depends on EasyDriver
const float degreesPerRev = 360; // 360 deg per revolution
float microstepsPerDeg = (stepsPerRev * microstepsPerStep) /degreesPerRev; // 4.44 microsteps/degree
int numberVials = 8; // number of vials on sampler
// setup pins
#define DIR_PIN 2
#define STEP_PIN 3
#define RELAY_PIN 7
byte cmd;
void setup()
{
Serial.begin(9600);
pinMode(DIR_PIN, OUTPUT);
pinMode(STEP_PIN, OUTPUT);
pinMode(RELAY_PIN, OUTPUT);
}
void loop()
{
if (Serial.available()) {
cmd = Serial.read();
parsecommand(cmd);
}
}
void parsecommand(int cmd) {
switch (cmd)
{
case 48: // 0: switch valve off
{
digitalWrite(RELAY_PIN, LOW);
Serial.println("off");
break;
}
case 49: // 1: switch valve on
{
digitalWrite(RELAY_PIN, HIGH);
Serial.println("on");
// Serial.flush();
break;
}
case 50: // 2: advance one position
{
float degreesToMove = (360/numberVials);
rotateDeg(degreesToMove);
Serial.println("moved");
break;
}
case 63: // ?: check arduino status
{
Serial.println("ready");
break;
}
default:
{
Serial.println("error");
}
}
}
void rotateSteps(int microsteps){
//rotate a specific number of microsteps (8 microsteps per step)
// (negitive for reverse movement)
int dir = (microsteps > 0)? HIGH:LOW;
digitalWrite(DIR_PIN,dir);
microsteps = abs(microsteps);
float usDelay = 1400;
for (int i=0; i < microsteps; i++)
{
digitalWrite(STEP_PIN, HIGH);
delayMicroseconds(usDelay);
digitalWrite(STEP_PIN, LOW);
delayMicroseconds(usDelay);
}
}
void rotateDeg(float deg) {
float microstepsToMove = microstepsPerDeg * deg;
int microstepsToMoveInt; // need to round to the nearaest integer
if (microstepsToMove > 0.0) {
microstepsToMoveInt = floor(microstepsToMove + 0.5);
}
else {
microstepsToMoveInt = ceil(microstepsToMove - 0.5);
}
rotateSteps(microstepsToMoveInt);
}
I'm talking to the Arduino with MATLAB r2013a on Windows 7. I send the command, wait a second, then see how many bytes are available. I then check again, and if the number of bytes hasn't changed and is non-zero, the buffer is read.
But the problem I'm having is that the Arduino seems to randomly stop writing to the serial buffer. 0 bytes are available. However, I can carry on sending commands from MATLAB and the Arduino moves the stepper/opens/closes the valve. It just doesn't write back and I need to know that the command has happened.
I only get this problem on Windows 7. I've tried it on Windows XP and Mac 10.8.3 with various versions of MATLAB and I can't reproduce the bug. I've also rewritten the serial code with Python and, again, only have this trouble on Windows 7.
Does anyone have any advice? I'm at my wit's end trying to fix this.
(Please note that I've cut the jumper on the board to prevent the Arduino reseting on serial connections, otherwise the valve turns to its default off state whenever I connect).
MATLAB code is:
function autosampler(cmd)
if ispc == true
port = 'COM3';
elseif ismac == true
port = '/dev/tty.usbmodemfa131';
end
s = serial(port);
s.baudrate = 9600;
s.terminator = '';
fopen(s);
fprintf(s,cmd);
cont = false;
while cont == false
% short pause, then check the number of bytes available
pause(0.5)
q1 = s.bytesavailable();
if q1 == 0 % no bytes available
cont = false; % restart loop
elseif q1 > 0 % bytes available
pause(0.1) % wait
q2 = s.bytesavailable(); % check again
if q1 == q2 % same number of bytes as last time?
cont = true; % exit loop
else
cont = false; % continue loop
end
end
end
response = fread(s,q2);
% convert from ASCII codes. Don't include the [13 10] at end.
response = char(response(1:(end-2))');
% print with timestamp
fprintf('%s: %s\n',datestr(now),response)
fclose(s)
end