Faz um tempão que não posto aqui, mas hoje também não poderei me deter muito aqui. O fato de eu não ter postado nada aqui ultimamente não quer dizer que eu esteja parado. O problema é que algumas vezes começo a trabalhar em mais de um software ao mesmo e começa a ficar difícil filtrar e decidir o que pode ser interessante postar aqui e o que só é relevante lá dentro do software mesmo.
Mas essa semana me deparei com algo muito incômodo. Eu já fiz um outro post falando um pouco sobre comunicação serial com C#, então não vou entrar em detalhes agora, embora eu não tenha explorado todos os recursos da classe SerialPort naquele post. Mas o fato aqui é outro: usar uma thread para receber os dados de uma porta serial.
Mas o que é uma thread?
Thread é um trecho de código-fonte que deve ser executado determinado número de vezes (ou o tempo inteiro) em paralelo ao código do programa. Na prática esses processos não são paralelos, o que acontece na verdade é uma alternância entre o código principal e o código da thread.
Eu, particularmente, prefiro não usar threads se houver uma forma de não usá-las, mas às vezes não há escapatória.
Meu caso:
Estive refazendo um código de programa desenvolvido em VB 6.0 que o Visual Studio converteu parcialmente para VB.NET. O software usava um componente de comunicação serial obsoleto (conhecido como MSComm) o qual substitui por um objeto da classe SerialPort do namespace System.IO.Ports, com as devidas alterações no código-fonte, claro. Mas não foi sobre isso que vim escrever.
Feito isso decidi reescrever o código em C# (para fins de conhecimento geral, pois isso me ajudou a conhecer um pouco do VB.NET, que até então não tinha tido contato) e depois implementar um terminal de comunicação serial no software. Basicamente um terminal para enviar comandos via porta serial e escrever as linhas recebidas como resposta na tela.
O problema de fazer isso é que é necessário ficar "monitorando" a porta serial, ficar constantemente lendo a entrada de dados. Para fazer isso pode-se criar uma thread que fique executando um código que leia a porta serial e escreva o que foi lido num TextBox, por exemplo. Mas não vou entrar no detalhe da criação de uma thread.
A outra forma de fazer isso é usar o evento DataReceived existente na classe SerialPort e é a forma que demonstrarei. Esse evento já funciona como uma thread então os mesmos problemas que eu tive com thread eu encontrei ao lidar com esse evento.
IMPORTANTE!
Como estou com pressa, para agilizar a explicação vou subentender algumas coisas.
Estou trabalhando dentro da classe Form1.cs, que é a janela de interface de um software qualquer, a qual já tem um objeto SerialPort nomeado portaSerial devidamente instanciado e a conexão com a porta serial já foi aberta (tudo isso subentende que o namespace System.IO.Ports tenha sido importado). Tenho também um TextBox chamado terminalSerial devidamente instanciado e com a propriedade Multiline com o valor true.
Então o que fiz a princípio foi o seguinte:
{
.
.
.
private void portaSerial_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
string mensagem;
try
{
mensagem = portaSerial.ReadExisting().ToString();
}
catch (TimeoutException)
{
mensagem = "TimeOutException";
}
try
{
terminalSerial.AppendText(mensagem + Environment.NewLine);
}
catch (InvalidOperationException e)
{
MessageBox.Show("Erro: " + e.Message);
}
}
.
.
.
}
Compilando e testando eu obtive o seguinte problema:
Como disse, esse evento funciona como uma thread e quando ele é executado aconetece um erro na linha:
terminalSerial.AppendText(mensagem + Environment.NewLine);
Sempre que tento executar uma MessageBox aparece com o texto:
Erro: Operação entre threads inválida: controle 'terminalSerial' acessado de um thread que não é aquele no qual foi criado.
Bom. Não descobri um jeito de acessar um controle de uma Form diretamente de dentro de uma thread, mas pesquisando pela internet descobri uma forma bem rápida de contornar esse problema. Inclusive retirei aquele try/catch para InvalidOperationException já que a exceção não estava mais sendo gerada.
{
.
.
.
private void portaSerial_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
string mensagem;
try
{
mensagem = portaSerial.ReadExisting().ToString();
}
catch (TimeoutException)
{
mensagem = "TimeOutException";
}
terminalSerial.Invoke(new EventHandler(delegate{ terminalSerial.AppendText(mensagem + Environment.NewLine); }));
}
.
.
.
}
Hoje era isso.
Talvez eu faça um edit nesse post outro dia, para acrecentar algumas coisas e torná-lo mais completo, mas agora estou com um pouco de pressa então vou deixá-lo assim, sem grandes explicações.
Um site que me ajudou muito:
http://www.dreamincode.net/forums/topic/35775-serial-port-communication-in-c%23/
Estou começando a aprender a usar threads melhor e consegui alguns materiais interessantes, então pretendo fazer um novo post bem completo só sobre threads no futuro, mas ainda não tenho idéia de quanto tempo isso pode demorar.
5 comentários:
I found this site using [url=http://google.com]google.com[/url]. And i want to thank you for your work. You have done really excellent site. Great work, great site! Cheers!
Sorry for offtopic
Olá,
Depois de muito pesquisar achei um vídeo no youtube com um código bem simples para acessar a porta paralela.
No meu caso eu tenho q comunicar um microcontrolador a porta e fazer uma interface com o visual C# express 2010.
A aplicação é simples preciso ligar e desligar um led!
mas quando executo o Visual C # retorna uma menssagem dizendo: "Access to port 'COM3' is denied"
não consigo descobrir qual é o problema.
Abaixo o código:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
namespace interface_Motor_Csharp_e_Proteus
{
public partial class Form1 : Form
{
SerialPort porta = new SerialPort("COM3", 9600, Parity.None,8,StopBits.One );
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
porta.Open();
porta.Write("l");
porta.Close();
}
private void button2_Click(object sender, EventArgs e)
{
porta.Open();
porta.Write("d");
porta.Close();
}
}
}
Gostaria de saber se alguém pode me ajudar!
Acho que tô respondendo meio tarde, mas caso tu chegue a passar por aqui.
Pedro, se o acesso a porta está sendo negado é bem possível que ela já esteja sendo acessada de alguma outra forma.
Uma forma de saber se a porta está sendo ou não usada é a propriedade IsOpen da classe SerialPort.
Se te interessar, há um post especificamente sobre porta serial aqui no blog.
http://underlineivan.blogspot.com/2010/06/acessando-porta-serial-com-c.html
A princípio não há nada errado no código, então há algum outro fator negando teu acesso. É difícil analisar o que está acontecendo já que o problema, pelo menos a princípio, não é no código.
hello there ..
it is my first post here and i hope that you will help me with it ..
any one could tell me about good please to sell and buy traffic ?
many thanks .
hello there ..
it is my first post here and i hope that you will help me with it ..
any one could tell me about good please to sell and buy traffic ?
many thanks .
Postar um comentário