Azzera filtri
Azzera filtri

MATLAB Arduino Uno Serial Communication Issue (writeline)

8 visualizzazioni (ultimi 30 giorni)
pb
pb il 11 Nov 2023
Commentato: pb il 20 Nov 2023
Hi folks,
I have a strange issue using serial communication between MATLAB - Arduino (an Arduino Uno), where it works.... until it doesn't. I posted a question about this on the Arduino forums too, but posting here as well to comment more on the MATLAB side of things, and of course if anyone is also familiar with Arduinos, then both!
Below, I am posting the MATLAB code (shortened sample - where the issue is reproduced), and followed by that I am posting an Arduino code that demonstrates what the issue is. In this instance, MATLAB sends four instructions, first one, later another one, and lastly two together (for two separate ports). What is happening is that I can run the MATLAB code once, and everything works as expected. Then the next time I run it, the Arduino will only respond to the first instruction, and nothing else. I could run it again, and it may still not work. Then I could run it again, and it works. It continues to follow this pattern erratically. Just a note, the writeline function is configured to have a endline character at the end of any string sent. Here are some of the debugging steps (MATLAB side) I have tried / issues I have tried to think about:
  1. Writeline sends ASCII data, and generally one character is one byte. The Arduino serial buffer can hold 64 bytes. My instruction sets are one character for a relay pin, max four characters for activation time, and four characters for the duration. There are two spaces in between. Each instruction is definitely processed, especially because I tried debugging with a pause(0.5) after each writeline, before the next one is received, so we never get to 64 bytes. It is indeed the case that with a longer pause, it atleast seemed that the issue happened after more runs of the code
  2. On the Arduino side of things, I put in a Serial.println statement right at the beginning of the serial.available loop, just to see that whenever the issue occurs, is it even entering the loop? ---- therein lies the issue somewhere, it is not entering when the issue starts. So something about the serial data not being stored in the Serial buffer. That could be a MATLAB - Arduino serial connection issue, but then the error pattern, as erratic as it is, is still too specific for that. The issue never happens the first time, and in many cases - the first several times --- I try to run the program.
  3. I had MATLAB display for me every instruction set it sends, and it was as expected
Thanks in advance for looking at this!:
MATLAB Code:
% Define the COM port and communication settings
comPort = 'COM4'; % Replace 'COMX' with your Arduino's COM port
baudRate = 9600;
% Create a serial port object
s = serialport(comPort, baudRate);
pause(5);
% % Define the instruction set (relay, activation time, and duration)
relayPin = 2; % Control relay on pin 2
relayPin = num2str(relayPin);
activationTime = 500; % Activation time in milliseconds
activationTime = num2str(activationTime);
duration = 250; % Duration in milliseconds
duration = num2str(duration);
% Create the instruction string with the relay, activation time, and duration
instruction = horzcat(relayPin,' ',activationTime,' ',duration);
% Send the instruction to the Arduino
writeline(s,instruction);
% % Define the instruction set (relay, activation time, and duration)
relayPin = 5; % Control relay on pin 2
relayPin = num2str(relayPin);
activationTime = 4000; % Activation time in milliseconds
activationTime = num2str(activationTime);
duration = 250; % Duration in milliseconds
duration = num2str(duration);
% Create the instruction string with the relay, activation time, and duration
instruction = horzcat(relayPin,' ',activationTime,' ',duration);
% Send the instruction to the Arduino
writeline(s,instruction);
% % Define the instruction set (relay, activation time, and duration)
relayPin = 6; % Example: Control relay on pin 2
relayPin = num2str(relayPin);
activationTime = 7000; % Activation time in milliseconds
activationTime = num2str(activationTime);
duration = 250; % Duration in milliseconds
duration = num2str(duration);
% Create the instruction string with the relay, activation time, and duration
instruction = horzcat(relayPin,' ',activationTime,' ',duration);
% Send the instruction to the Arduino
writeline(s,instruction);
% % Define the instruction set (relay, activation time, and duration)
relayPin = 5; % Example: Control relay on pin 2
relayPin = num2str(relayPin);
activationTime = 7000; % Activation time in milliseconds
activationTime = num2str(activationTime);
duration = 250; % Duration in milliseconds
duration = num2str(duration);
% Create the instruction string with the relay, activation time, and duration
instruction = horzcat(relayPin,' ',activationTime,' ',duration);
% Send the instruction to the Arduino
writeline(s,instruction);
% Close the serial port when done
clear s;
clear all;
Arduino Code (Was able to create it thanks to a very helpful poster on Arduino Forums)
const byte pins [] = {2, 5, 6, 7};
const byte conveyorpin = 3;
char conveyorstring[8];
char speedchar[2];
const int Npin = sizeof(pins);
int speed;
float dutycycle;
int roundeddutycycle;
struct Instr {
int state;
int pin;
unsigned long msecStart;
unsigned long msecStop;
};
const int Ninstr = 30;
Instr instr [Ninstr] = {}; // initialize all fields to zero
enum { Available = 0, InUse, Set }; // Available (0) will be default value
enum { Off = HIGH, On = LOW };
char s [80]; // for use with sprintf()
// -----------------------------------------------------------------------------
void
addInstr (
int pin,
unsigned long msecStart,
unsigned long msecStop )
{
sprintf (s, "addIntr: pin %d, %lu start, %lu stop",
pin, msecStart, msecStop);
Serial.println (s);
for (int i = 0; i < Ninstr; i++) {
if (Available == instr [i].state) {
instr [i].state = InUse;
instr [i].pin = pin;
instr [i].msecStart = msecStart;
instr [i].msecStop = msecStop;
return;
}
}
Serial.println ("addIntr: none available");
}
// -----------------------------------------------------------------------------
void loop ()
{
unsigned long msec = millis ();
if (Serial.available () > 0) {
char buf [80];
int n = Serial.readBytesUntil ('\n', buf, sizeof(buf)-1);
buf [n] = '\0';
int pin;
unsigned long msecStart;
unsigned long msecDuration;
for (int j = 0;j<8;j++){
conveyorstring[j]=buf[j];
}
conveyorstring[8] = '\0';
if (strcmp(conveyorstring,"Conveyor") == 0){
sscanf(buf, "Conveyor %d", & speed);
analogWrite(conveyorpin,speed);
}else{
sscanf (buf, "%d %ld %ld", & pin, & msecStart, & msecDuration);
addInstr (pin, msec + msecStart, msec + msecStart + msecDuration);
}
//memset(conveyorstring,0,sizeof(conveyorstring));
}
// Check and execute relay instructions
for (int i = 0; i < Ninstr; i++) {
switch (instr [i].state) {
case InUse:
if (msec >= instr [i].msecStart) {
instr [i].state = Set;
digitalWrite (instr [i].pin, On);
sprintf (s, "loop: set pin %d", instr [i].pin);
Serial.println (s);
}
break;
case Set:
if (msec >= instr [i].msecStop) {
instr [i].state = Available;
digitalWrite (instr [i].pin, Off);
sprintf (s, "loop: clear pin %d", instr [i].pin);
Serial.println (s);
}
break;
}
}
}
// -----------------------------------------------------------------------------
void setup () {
Serial.begin (9600);
for (int i = 0; i < Npin; i++) {
pinMode (pins[i], OUTPUT);
digitalWrite (pins[i], Off);
}
pinMode(conveyorpin,OUTPUT);
}

Risposte (1)

Yamilet
Yamilet il 11 Nov 2023
% Define the COM port and communication settings
comPort = 'COM4'; % Replace 'COMX' with your Arduino's COM port
baudRate = 9600;
% Create a serial port object
s = serialport(comPort, baudRate);
pause(5);
% % Define the instruction set (relay, activation time, and duration)
relayPin = 2; % Control relay on pin 2
relayPin = num2str(relayPin);
activationTime = 500; % Activation time in milliseconds
activationTime = num2str(activationTime);
duration = 250; % Duration in milliseconds
duration = num2str(duration);
% Create the instruction string with the relay, activation time, and duration
instruction = horzcat(relayPin,' ',activationTime,' ',duration);
% Send the instruction to the Arduino
writeline(s,instruction);
% % Define the instruction set (relay, activation time, and duration)
relayPin = 5; % Control relay on pin 2
relayPin = num2str(relayPin);
activationTime = 4000; % Activation time in milliseconds
activationTime = num2str(activationTime);
duration = 250; % Duration in milliseconds
duration = num2str(duration);
% Create the instruction string with the relay, activation time, and duration
instruction = horzcat(relayPin,' ',activationTime,' ',duration);
% Send the instruction to the Arduino
writeline(s,instruction);
% % Define the instruction set (relay, activation time, and duration)
relayPin = 6; % Example: Control relay on pin 2
relayPin = num2str(relayPin);
activationTime = 7000; % Activation time in milliseconds
activationTime = num2str(activationTime);
duration = 250; % Duration in milliseconds
duration = num2str(duration);
% Create the instruction string with the relay, activation time, and duration
instruction = horzcat(relayPin,' ',activationTime,' ',duration);
% Send the instruction to the Arduino
writeline(s,instruction);
% % Define the instruction set (relay, activation time, and duration)
relayPin = 5; % Example: Control relay on pin 2
relayPin = num2str(relayPin);
activationTime = 7000; % Activation time in milliseconds
activationTime = num2str(activationTime);
duration = 250; % Duration in milliseconds
duration = num2str(duration);
% Create the instruction string with the relay, activation time, and duration
instruction = horzcat(relayPin,' ',activationTime,' ',duration);
% Send the instruction to the Arduino
writeline(s,instruction);
% Close the serial port when done
clear s;
clear all;
  4 Commenti
Walter Roberson
Walter Roberson il 13 Nov 2023
The only difference is that @Yamilet removed some empty lines -- which should not affect execution at all.
pb
pb il 20 Nov 2023
Noted, thanks @Walter Roberson
Quick question for you, the documentation for the writeline function: here, states that it writes ASCII data to the serial port. I did not use it initially and instead used this. This did not work for me, but I opted for the write function instead of the writeline function first because I wasn't sure if MATLAB would be writing the binary representations of ASCII characters to the serial port, and in the Arduino side of the equation, do I have to compare the strings received using the binary representations or can I use readable characters. However, I saw this video, and saw he it wasn't the ASCII representations so figured it's ok.
Further, I would think it's still ok because on the first execution the MATLAB code works fine, but not on subsequent executions. However, just to check if this is the source of the problem, could you clarify if MATLAB is writing data to the serial port in a different way than I am thinking?

Accedi per commentare.

Categorie

Scopri di più su MATLAB Support Package for Arduino Hardware in Help Center e File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by