Reputation: 51
Using Microsoft Visual Expres, Win Form Application In my application I am sending data from PC to microcontroller via serial communication. It works like that: App from PC send data - microcontroller do his program - in the end of microcontrollers program send character to application - application receive character and send another data.
My problem is, when I wait for the character from microcontroller, whole App(in PC) becomes inactive(cant press any button or close the program).
Friend told me to try Threads. I tried to do it with thread(I am pretty new in threads). When I run my app it throw an exception: Acces to the port "COM6" is denied. It looks like that serial port is opened in one thread, before other thread close the port.
Is there any way to set the port as open for all threads? Or any better ideas how to make my App active while waiting for response frommicrocontroller?
There are some lines of code with threads:
.
.
.
poslat(data_all); //sending data function
Thread t = new Thread(cakaj);
t.Start(); // start of thread cakaj
.
.
.
there is function for sending data
static void poslat(string data)
{
SerialPort COMport = new SerialPort();
COMport.PortName = "COM6";
COMport.BaudRate = 1200;
COMport.DataBits = 8;
COMport.Parity = Parity.None;
COMport.StopBits = StopBits.One;
COMport.Open();
COMport.Write(data);
COMport.WriteTimeout = 500;
COMport.Close();
}
function for waiting for a character from microcotroller
void cakaj()
{
SerialPort COMport = new SerialPort();
int byteRead;
COMport.PortName = "COM6"; //
COMport.BaudRate = 1200;
COMport.DataBits = 8;
COMport.Parity = Parity.None;
COMport.StopBits = StopBits.One;
COMport.Open(); //**Program points there with error message:Acces to the port "COM6" is denied.**
do
{
byteRead = COMport.ReadByte();
} while (byteRead != 75); // ASCII K = 75
t.Abort();
COMport.Close();
return;
}
Upvotes: 0
Views: 373
Reputation: 6522
You're creating two different instances of SerialPort COMport
using the same port COM6
. What you can do is make the COMport
variable as a field for your class and access that in poslat
and cakaj
.
Also, you can instead use the DataReceived event instead of making another thread.
Your code will look something like this.
class YourClass
{
static SerialPort _COMport;
int byteRead; //make byteRead a field so you can also share it outside cakaj
SerialPort COMport //share COMport for poslat and cakaj
{
get
{
if(_COMport == null)
{
CreateCOMport();
}
return _COMport;
}
}
void CreateCOMport()
{
_COMport = new SerialPort();
_COMport.PortName = "COM6";
_COMport.BaudRate = 1200;
_COMport.DataBits = 8;
_COMport.Parity = Parity.None;
_COMport.StopBits = StopBits.One;
_COMport.DataReceived += cakaj;
//COMport will listen for any incoming data
//when there is data available, method cakaj will run
}
void poslat(string data)
{
if (!COMport.IsOpen)
{
COMport.Open();
}
COMport.Write(data);
COMport.WriteTimeout = 500;
}
void cakaj(object sender, SerialDataReceivedEventArgs e)
{
do
{
byteRead = COMport.ReadByte();
} while (byteRead != 75);
COMport.Close();
}
}
EDIT: remember to call COMport.Close()
somewhere within this class.
I changed the approach and there are many ways to improve it but I think it will do the work...
Upvotes: 1
Reputation: 3629
If you want your Forms application's main thread to wait in a loop you have to make sure to give it the opportunity to handle events.
You can do that by modifying your waiting loop like this:
do
{
Application.DoEvents(); // handle Windows Forms events
byteRead = COMport.ReadByte();
} while (byteRead != 75); // ASCII K = 75
This will make sure your app can still respond to events while waiting.
Of course this is only necessary when it is your application's main thread that's waiting. Background threads don't have to do this and in fact they must not do it.
Upvotes: -1