I am working on making an interface between MATLAB and Arduino. In other words, I want to send some data from MATLAB to Arduino. I have written programs both in MATLAB and the Arduino IDE.
MATLAB program:
c = 1;
if (c ~= 0 )
f = 1;
else
disp('vhxhjf');
end
disp(f)
arduino=serial('COM5','BaudRate',9600); % create serial communication object on port COM4
fopen(arduino); % initiate arduino communication
while f
fprintf(arduino,'%s',char(f)); % send answer variable content to arduino
end
fclose(arduino); % end communication with arduino
Code for Arduino:
int ledPin = 13;
int matlabData ;
void setup() {
pinMode(13,OUTPUT);
Serial.begin(9600);
// turn the LED on when we're done
// digitalWrite(13, HIGH);
}
void loop() {
if(Serial.available() > 0 ) {
matlabData = Serial.read();
if ( matlabData != 0) {
digitalWrite(13, HIGH);
delay(1000);
digitalWrite(13,LOW);
delay(1000);
}
else
digitalWrite(13,LOW);
}
}
The problem is whenever I am uploading the sketch , this error is being thrown regularly in arduino ide:
avrdude: ser_open(): can't open device "\\.\COM5": The system cannot find the file specified
It was works on the first try, but after that the above error is thrown continuosly .
Also in matlab, after the first try , the following error is thrown:
enter code here
Error using serial/fopen (line 72)
Open failed: Port: COM5 is not available. No ports are available.
Use INSTRFIND to determine if other instrument objects are connected to requested device.
Error in SP (line 65)
fopen(arduino); % initiate arduino communication
>> instrfind
Instrument Object Array
Index: Type: Status: Name:
1 serial open Serial-COM5
2 serial closed Serial-COM5
and also the command instrfind is showing that the com5 port is closed after the first try.
I have tried the solution given in this link but it is didn't work:
http://forum.arduino.cc/index.php?topic=48421.0
This usually happens when you don't close the port.
In your code, when do you close it? When is f changed so the loop exits?
According to these people, you can try to do
delete(instrfindall)
before trying to open the port or
fopen(arduino);
closeFID = onCleanup(#() fclose(arduino));
...
IMHO the second solution looks better (less destructive)
BTW: put a delay or a sleep (I don't know how this is done in ML) in the fprintf loop, otherwise you will send too many data to the poor Arduino...
Related
I recently connected a reactor control tower through a serial 'COMMS' port to my computer (serial to USB). It seems to create a connection on the COM4 port (as indicated on the control panel 'devices and printers' section). However, it always gives me the following message when i try to 'fwrite(s)' or 'fscanf(s)'.
Warning: Unsuccessful read: The specified amount of data was not returned within the Timeout period..
%My COM4
s = serial('COM4');
s.BaudRate = 9600;
s.DataBits = 8;
s.Parity ='none';
s.StopBits = 1;
s.FlowControl='none';
s.Terminator = ';';
s.ByteOrder = 'LittleEndian';
s.ReadAsyncMode = 'manual';
% Building write message.
devID = '02'; % device ID
cmd = 'S'; % command read or write; S for write
readM = cell(961,3);% Read at most 961-by-3 values filling a 961–by–3 matrix in column order
strF = num2str(i);
strF = '11'; %pH parameter
strP = '15'; %pH set point
val = '006.8'; %pH set value
msg_ = strcat('!', devID, cmd, strF, strP, val);%output the string
chksum = dec2hex(mod(sum(msg_),256)); %conversion to hexdec
msg = strcat(msg_,':', char(chksum), ';');
fopen(s); %connects s to the device using fopen , writes and reads text data
fwrite(s, uint8(msg)); %writes the binary data/ Convert to 8-bit unsigned integer (unit8) to the instrument connected to s.
reply=fscanf(s); %reads ASCII data from the device connected to the serial port object and returns it to reply, for binary data use fread
fclose(s); %Disconnect s from the scope, and remove s from memory and the workspace.
This leads me to believe that the device is connected but is not sending or receiving information and I am unsure as to how I can configure this or even really check if there is communication occurring between the tower and my computer.
Recently wrote code that establishes a connection between two instances of matlab. I can send messages through the TCP-IP connection which will execute code. Now I'm trying to setup the code to be interruptible as I would like to start/stop a function through TCP-IP. Problem though is that sending a second command does nothing until the function is completed. Is there a way to interrupt a TCP-IP callback function?
code:
classdef connectcompstogether<handle
properties
serverIP
clientIP
tcpipServer
tcpipClient
Port = 4000;
bsize = 8;
earlystop
end
methods
function gh = connectcompstogether(~)
% gh.serverIP = '127.0.0.1';
gh.serverIP = 'localhost';
gh.clientIP = '0.0.0.0';
end
function SetupServer(gh)
gh.tcpipServer = tcpip(gh.clientIP,gh.Port,'NetworkRole','Server');
set(gh.tcpipServer,'OutputBufferSize',gh.bsize);
fopen(gh.tcpipServer);
display('Established Connection')
end
function SetupClient(gh)
gh.tcpipClient = tcpip(gh.serverIP,gh.Port,'NetworkRole','Client');
set(gh.tcpipClient, 'InputBufferSize',gh.bsize);
set(gh.tcpipClient, 'BytesAvailableFcnCount',8);
set(gh.tcpipClient, 'BytesAvailableFcnMode','byte');
set(gh.tcpipClient, 'BytesAvailableFcn', #(h,e)gh.recmessage(h,e));
fopen(gh.tcpipClient);
display('Established Connection')
end
function CloseClient(gh)
fclose(gh.tcpipClient);
gh.tcpipClient = [];
end
end
methods
function sendmessage(gh,message)
fwrite(gh.tcpipServer,message,'double');
end
function recmessage(gh,h,e)
Message = fread(gh.tcpipClient,gh.bsize/8,'double');
if Message == 444
gh.Funwithnumbers();
elseif Message == 777
gh.earlystop = 1;
end
end
function Funwithnumbers(gh)
x=1;
while true
if x > 5000, break;end
if gh.earlystop == 1,break;end
x = x+1;
display(x)
end
end
end
end
for ease to understand code.
server
Ser = connectcompstogether;
ser.SetupServer();
ser.sendmessage(333);
Client
cli = connectcompstogether;
cli.SetupClient();
Update:
So after going through the web, I have found out based on this post that the tcpip callback cannot be interrupt. The post was in 2017 which means my 2016a version definitely cannot interrupt a callback.
So An update to my question, Is it possible to start a subprocess in matlab to run the function. I just want to use the callback to start code. If I can start a subprocess from the callback. Than I should be able to free up the main process and use tcpip to start/stop a function on a different computer.
Update 2:
So I tried to utilize parallel processing using the 'spmd' command but the problem still persisted.
function recmessage(gh,h,e)
Message = fread(gh.tcpipClient,gh.bsize/8,'double');
spmd
switch labindex
case 1
if Message == 444
gh.Funwithnumbers();
elseif Message == 777
gh.earlystop = 1;
end
end
end
end
You may use a timer object, which is convenient to delay the execution of some function.
t=timer('ExecutionMode','singleShot', 'StartDelay',0, 'TimerFcn',#myCallback);
start(t);
In this case, the StartDelay is 0, so myCallback will be almost immediately added to the queue of tasks to be processed by Matlab. The execution however will start only after the callback to the tcpip object has been completed. It will block the queue once started, however.
You may try something like:
properties
t=timer('ExecutionMode','singleShot', 'StartDelay',0, 'TimerFcn',#myCallback);
end
function tcpipCallback(gh,tcpObj,~)
message=fread(tcpObj,1,'double');
if message==444
if strcmp(get(t,'Running'),'on')
error('The function is running already');
else
set(gh.t,'UserData',false);
start(gh.t);
end
elseif message==777
set(gh.t,'UserData',true);
end
function myCallback(tObj,~)
ii=0;
while ii<5000
if get(tObj,'UserData'),break,end
ii=ii+1;
pause(.0001); %Pause to interrupt the callback; drawnnow might work too; or perhaps this is not needed at all.
end
end
I'm trying to make a serial communication between two ESP8266 Wifi chips.
To start, I tried sending a sample data 10 times in a for loop. Here is the code:
Transmiter:
for Packets = 1 : 10
SendData(client,Data(Packets));
end
Receiver:
Packets = 1
while(1)
Data(Packets) = ReceiveData(Server);
Packets = Packets + 1;
if (packets == 10)
break
end
end
it works good. The problem is when I want to send data with some delays, the transmitter should connect to receiver again and the server (receiver) receives some data indicating that connection is made again.
The received Buffer should be:
+IPD,0,1024:ùüþþþýýþþÿÿûûýþýûúþÿúóýÿþþþþþýúøûýþ...
but after reconnecting the received Buffer is:
0,CLOSED %Receiver Prompt, disconnected from Transmiter
0,CONNECT %Receiver Prompt,connected to Transmiter
+IPD,0,1024:ùüþþþýýþþÿÿûûýþýûúþÿúóýÿþþþþþýúøûýþ...
The remaining part of data will be read in next packet and same for next packets.
what should I do to receive just the data?
The send and receive functions:
function ReceivedBuffer = ReceiveData(SerialPort)
ReceivedBuffer = fread(server,1038); %Size data = 1038 Bytes
end
function SendData(SerialPort,Data)
fwrite(SerialPort,Data);
end
I have connected my RPI and atmega328 together in order to control the start of an event on my arduino. In order to do so, GPIO 25 (RPI) is connected directly to pin7 (Arduino PD7). I've got a python script on the RPI witch set the GPIO 25 to high then back to LOW:
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(25, GPIO.OUT)
GPIO.output(25, 1)
#Do some stuff
GPIO.output(25, 0)
The arduino is waiting in a loop for either a physical button to be pressed or the pin7 to be set to HIGH by the RPI:
const int interrupt = 7;
const int button = 13;
const int led = 9;
void setup() {
Serial.begin(9600);
pinMode(interrupt, INPUT);
pinMode(button,INPUT);
pinMode(led, OUTPUT);
digitalWrite(led, LOW);
}
void loop() {
bool on = false;
bool buttonOn = false;
while (!on || !buttonOn) {
on = digitalRead(interrupt);
buttonOn = digitalRead(button);
digitalWrite(led, LOW);
}
digitalWrite(led, HIGH);
delay(1000);
}
Now unfortunately this doesn't work. I have checked the logic level of the atmega328 (https://learn.sparkfun.com/tutorials/logic-levels) and it seems that 3.3V is good enough for HIGH signal.
Am I missing something with the pull up /pull down resistance? I know the PD7 on the atmega is specified as follow:
Port D is an 8-bit bi-directional I/O port with internal pull-up
resistors (selected for each bit). The Port D output buffers have
symmetrical drive characteristics with both high sink and source
capability. As inputs, Port D pins that are externally pulled low will
source current if the pull-up resistors are activated. The Port D pins
are tristated when a reset condition becomes active, even if the clock
is not running.
EDIT:
I have done more testing and I am getting the HIGH or LOW value correctly. It seems that the issue comes from the:
while ((!on) || (!buttonOn)) {
Is there an issue with Arduino and the OR operator in a while loop? Even when one condition is true and the other one is false, it never goes out of the loop.
while ((!on) || (!buttonOn)) {
}
That loop will run as long as one of the variables is false.
Yesterday I was for some reason thinking that you were reading the interrupt pin twice when reading your code.
3.3 v output should be ok to turn the Arduino input high.
You can have a wiring problem or your raspberry pi can be so fast that the arduino misses the pulse.
Change your program on the raspberry pi to leave the output high for so long (e.g. 10) seconds that you can measure it with a multimeter to see that you are setting the right pin.
Does the Arduino now see the input?
I'm trying to read the data from the COM3 port.
I'm using this code:
in = fscanf(s);
if(in == 'A')
fclose(s);
break;
end
The problem is that when no data is sent to the com3 port, the fscanf() will wait for a certain time interval and then give a timeout.
Is there a way to read data only when it is present?
Read only when data present
You can read out the BytesAvailable-property of the serial object s to know how many bytes are in the buffer ready to be read:
bytes = get(s,'BytesAvailable'); % using getter-function
bytes = s.BytesAvailable; % using object-oriented-addressing
Then you can check the value of bytes to match your criteria. Assuming a char is 1 byte, then you can check for this easily before reading the buffer.
if (bytes >= 1)
in = fscanf(s);
% do the handling of 'in' here
end
Minimize the time to wait
You can manually set the Timeout-property of the serial object s to a lower value to continue execution earlier as the default timeout.
set(s,'Timeout',1); % sets timeout to 1 second (default is 10 seconds)
Most likely you will get the following warning:
Unsuccessful read: A timeout occurred before the Terminator was
reached..
It can be suppressed by executing the following command before fscanf.
warning('off','MATLAB:serial:fscanf:unsuccessfulRead');
Here is an example:
s = serial('COM3');
set(s,'Timeout',1); % sets timeout to 1 second (default is 10 seconds)
fopen(s);
warning('off','MATLAB:serial:fscanf:unsuccessfulRead');
in = fscanf(s);
warning('on','MATLAB:serial:fscanf:unsuccessfulRead');
if(in == 'A')
fclose(s);
break;
end