Crie seu próprio programa de comunicação serial em C# - Tutorial 3(Seleção de porta, Reset via serial)

Até agora sempre definíamos as propriedades como o nome da porta e BaudRate no projeto, para fins de testes funciona muito bem. Porém isso deixa o programa pouco flexível, já que a porta que o arduino usa pode mudar dependendo do PC onde ele tem os drives instalados.

Neste tutorial estarei mostrando como dar o poder de escolha ao usuário de qual porta e baud rate usar, e para aqueles que usam o arduino, a escolha de habilitar ou não o reset via serial.

Vou aproveitar e mostrar também o como salvar essas configurações para que da próxima vez que o programa for executado ele “lembre” delas e as tome como default.

Primeiro passo: adicionar novos itens.

Depois de criar um novo projeto, no menu projeto escolham a opção adicionar novo item.

Adicionem um novo formulário e coloquem o nome de “Config_Serial.cs”.

Depois adicionem um novo arquivo de configurações e coloquem o nome de “Minhas_Config.settings”.

Antes trabalhar com esses novos itens adicionem os seguintes controles no formulario1(Form1).

  • MenuStrip
  • SerialPort

Alterei o nome de serialPort1 para Porta fiz algumas modificações no menuStrip1 para que ficasse assim:

Apenas troquei a cor atribuindo a propriedade BackColor a cor GradientActiveCaption e criei um menu conexão adicionei as opções configurar e conectar.

Dando um duplo click na opção configurar teremos acesso ao evento dele (Click).

Qual é a ideia? Configurar qual porta e velocidade que vamos usar. Só que eu preferi fazer esse procedimento em outro formulário pra ganhar mais espaço no principal, pra isso adicionamos o formulário Config_Serial anteriormente.

Bom, precisamos chamar esse novo formulário através do menu então façam o seguinte:

private void configurarToolStripMenuItem_Click(object sender, EventArgs e)

        {

            Config_Serial janela2 = new Config_Serial(this);

            janela2.ShowDialog();

        }

Primeiro declaramos uma nova variável do tipo Config_serial, que corresponde ao nome que demos ao segundo formulário, com o nome janela2 e inicializamos ela passando este formulário (Form1) como parâmetro usando a palavra this. Na segunda linha o segundo formulário é exibido.

É importante entender porque passar o Form1 como parâmetro neste caso. O que acontece é que as variáveis de um formulário não podem ser acessadas por outro. Como vamos mudar duas propriedade do objeto Porta através do segundo formulário, e aquele esta no primeiro, com esse procedimento poderemos mudar campos desse objeto. Também é importante que mudem a propriedade Modifiers  do objeto Porta para public.

No evento da opção Conectar do menu deixem parecido com isso:

private void conectarToolStripMenuItem_Click(object sender, EventArgs e)

        {

            try

            {

                if (Porta.IsOpen)

                {

                    Porta.Close();

                    conectarToolStripMenuItem.Text = "Conectar";

                }

                else

                {

                    Porta.Open();

                    if (reset)

                    {

                        Porta.DtrEnable = true;

                        Porta.DtrEnable = false;

                    }

                    conectarToolStripMenuItem.Text = "Desconectar";

                }

            }

            catch(SystemException erro)

            {

                MessageBox.Show(erro.Message, "Erro", MessageBoxButtons.OK, MessageBoxIcon.Error);

            }

        }

Traduzindo: se estiver conectado, desconecta e muda o texto do menu para “Conectar”.

Senão, conecta e muda o texto para “Desconectar”.

Se ocorrer algum erro mostra a descrição dele, que esta na variável erro.Message num formulário com titulo “Erro”, que tem um botão de ok e um ícone de Error.

Assim podemos iniciar e encerrar a comunicação quando quisermos.

Abro um parêntese para falar do seguinte trecho:

                 if (reset)

                    {

                        Porta.DtrEnable = true;

                        Porta.DtrEnable = false;

                    }

Aqueles que usam o arduino, devem ter notado que o Serial Monitor é capaz de resetar o arduino assim que é aberto.

Esse trecho de código faz o mesmo, se a variável reset for verdadeira, reseta o arduino ao conectar.

Declarem essa variável com antecedência:

public bool reset = false;

public porque vamos acessa-la também no segundo formulário.

2º passo: segundo formulário.

Agora que terminamos o formulário principal, vamos trabalhar o segundo que é onde faremos as configurações da porta.

Adicionem os seguintes controles:

  • 1 x GroupBox
  • 2 x Label:
  • 2 x ComboBox
  • 1 x Checkbox
  • 1 x Timer

Redimensionem e mudem os text para que fique dessa forma:

  • Mudem a propriedade FormBorderStyle para FixedToolWindow para impedir redimensionamento em tempo de execução, e retirar os botões de maximizar e minimizar.
  • Mudem também para DropDownList da propriedade DropDownStyle dos dois comboBox’s
  • No timer1 deixem um intervalo de 1000 ms e deixem a propriedade enabled em true.

Esse timer vai servir para atualizar a lista de portas que o PC tem disponível.

No comboBox correspondente ao baud rate, no meu caso o comboBox2, coloquei as velocidades padrão do Serial Monitor na propriedade items.

Vejam o resultado:

Como nós não sabemos de inicio quantas e qual porta o arduino esta conectado devemos usar uma função que pelo menos nos retorne os nomes das portas existentes. Essa função é usada nesse trecho:

void busca_de_portas(bool x)

        {

            int num = portas.Length;

            portas = SerialPort.GetPortNames();

            if (num != portas.Length || x)

            {

                comboBox1.Items.Clear();

                for (int i = 0; i < portas.Length; i++)

                {

                    comboBox1.Items.Add(portas[i]);

                }

            }

        }

O segredo esta nesta função: SerialPort.GetPortNames(). Ela retorna um array do tipo string contendo os nomes das portas existentes. Tendo posse dos nomes, basta preencher o comboBox1 com eles, e é isso que a rotina busca_de_portas fará. Mas fará somente se o número de portas variar. O campo Length quer dizer o tamanho de um determinado array.

Não esquecer de declarar portas antes de usar:

string[] portas = {""};

Para poder usar SerialPort.GetPortNames() é necessário incluir uma classe fazendo .

using System.IO.Ports;

Ok, agora no evento de Load do formulário e no Tick do timer1 é só chamar a rotina acima:

private void Config_Serial_Load(object sender, EventArgs e)

        {

            busca_de_portas(true);

        }

 

private void timer1_Tick(object sender, EventArgs e)

        {

            busca_de_portas(false);

        }

Assim será feita uma pesquisa pelos nomes ao carregar e também num intervalo de 1000 ms.

Ao carregar é importante passar o true porque mesmo no caso de o número de portas ser 1(numero inicial de elementos do array portas)ele possa atualizar o comboBox1.

No meu caso só existe a porta que o arduino está, mas quem tiver mais de uma, pode acontecer de os nomes ficarem fora de ordem. Pra corrigir isso basta mudar a propriedade Sorted do comboBox1 para true.

No evento checkBox1_CheckedChanged façam o mesmo que o exemplo abaixo:

private void checkBox1_CheckedChanged(object sender, EventArgs e)

        {

            if(checkBox1.Checked)

            {

                reset2 = true;

            }

            else

            {

                reset2 = false;

            }

        }

Declarem antes a variável bool reset2 = false; que será responsável por habilitar o reset do arduino ao conectar.

Ok, o usuário escolheu, qual porta, qual velocidade, e até se deseja resetar o arduino. Agora resta passar essa informações pro Form1 já que é nele que está o objeto Porta. Arbitrei que iria passar esses dados quando fechasse as configurações.

Lembrem se que passamos o Form1 como parâmetro quando fizemos:

Config_Serial janela2 = new Config_Serial(this);  

Para usar esse parâmetro faremos o seguinte:

Form1 janela1;

public Config_Serial(Form1 x)

        {

            InitializeComponent();

            janela1 = x;

        }

Logo que clicamos em algum controle para ter acesso a algum evento esse método já é automaticamente gerada para nós logo no começo do código. Ele originalmente vem sem parâmetros. O que fizemos aqui foi declarar um objeto do tipo Form1 com nome janela1 e recebeu o valor x passado pelo formulário anterior.

Agora podemos passar as informações para o formulário anterior fazendo:

private void Config_Serial_FormClosing(object sender, FormClosingEventArgs e)

        {

            try

            {            

                janela1.Porta.BaudRate = Convert.ToInt32(comboBox2.Text);

                janela1.Porta.PortName = comboBox1.Text;

                janela1.Text = comboBox1.Text + "/" + comboBox2.Text;

                janela1.reset = reset2;         

            }

            catch

            {

                DialogResult escolha;

                escolha = MessageBox.Show("Prencha todos os campos ", "Aviso", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation);

                if (escolha == System.Windows.Forms.DialogResult.OK)

                {

                    e.Cancel = true;

                }

            }

        }

O código acima tenta passar os dados para o formulário anterior, caso não consiga ele mostra uma mensagem que diz: "Prencha todos os campos corretamente", e dá duas opções ao usuário:

  • Ok: significa que o evento será cancelado(e.cancel) para correção das informações
  • Cancel: segue com o evento, fechando o formulário.

Passo 3: Configurar definições.

Ufa! Conseguimos, por aqui termina para quem se deu por satisfeito com o resultado.

Porém é um pouco chato sempre ter que ir no menu e escolher de novo os parâmetros para configurar a conexão serial, seria interessante que o programa guardasse essas informações mesmo depois de fechado.

Pra isso mesmo que adicionamos no começo do projeto um arquivo de configurações com o nome de minhas_config.settings. Ele vai guardar dados que serão usados na próxima vez que o programa for executado.

Ele deve ter essa cara:

Aqui já defini alguns valores que eu desejo guardar.

A ideia é atualizar e salvar esses valores quando fecharmos o programa, logo devemos usar o evento FormClosing do Form1

private void Form1_FormClosing(object sender, FormClosingEventArgs e)

        {

            try

            {

                Minhas_Config.Default.Nome_Porta = Porta.PortName;

                Minhas_Config.Default.Baud_Rate = Porta.BaudRate;

                Minhas_Config.Default.restart_arduino = reset;

                Minhas_Config.Default.Save();

            }

            catch

            {

                MessageBox.Show("Erro ao salvar!Reconfigure quando executar novamente","Erro");

            }

        }

E quando abrirmos novamente o programa, carregar os valores guardados:

private void Form1_Load(object sender, EventArgs e)

        {

            try

            {

                Porta.PortName = Minhas_Config.Default.Nome_Porta;

                Porta.BaudRate = Minhas_Config.Default.Baud_Rate;

                reset = Minhas_Config.Default.restart_arduino;

                Text = Porta.PortName + "/" + Convert.ToString(Porta.BaudRate);

            }

            catch

            {

                MessageBox.Show("Erro ao carregar! Reconfigure", "Erro");

            }

        }

Pronto, com isso termino mais um tutorial, adaptem a suas necessidades. Até a próxima.

Código Form1:

http://pastebin.com/vbdaNXy6

Código Config_Serial:

http://pastebin.com/EwJnfck3

Exibições: 1010

Responder esta

Respostas a este tópico

Parábens!!!

Ficou muito claro e didático.

Abraço

Yure, tá muito legal!

Vc tá deixando todos os passos num único tutorial pra gente acessar depois? É q como eu tenho emprego, laboratorio, curso de linux, curso de infoseg, familia, bichos de estimacao, casa em reforma e 400 alunos, tá dificil acompanhar na mesma velocidade...

Eu estou colocando no blog tambem, vc pode encontra-los na lista de tutoriais (artigos e outros) na pagina inicial do Lab. 

Opa, daí é legal! Ultimamente meu tempo ta uma bagunca, muita coisa pra fazer e nenhum tempo de sobra, to me reorganizando geral aqui. Daí vou pegando as coisas pra estudar passo a passo, etapa por etapa, pra aprender bem cada uma antes de prosseguir.

Show vou implementar e te falo

abs.

RSS

© 2024   Criado por Marcelo Rodrigues.   Ativado por

Badges  |  Relatar um incidente  |  Termos de serviço