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

Redimencionem 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 Form1com 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); //Mostra no titulo do formulário o nome da porta seguido de "/" e o baudrate.

            }

            catch

            {

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

            }

        }

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

Código Form1:

http://adf.ly/1UB5KF

Código Config_Serial:

http://adf.ly/1UB5O8

Exibições: 7377

Comentar

Você precisa ser um membro de Laboratorio de Garagem (arduino, eletrônica, robotica, hacking) para adicionar comentários!

Entrar em Laboratorio de Garagem (arduino, eletrônica, robotica, hacking)

Comentário de Gil Carneiro em 1 outubro 2019 às 10:18

Bom dia !

Utilizei este exemplo numa impressão de cheque que preciso fazer em serial.  Mas minha classe imprimir.cs esta fora dor Form1,  como passo por parametro o objeto Porta para a classe imprimir.cs ?

grato

Comentário de vincenteludugeriodossantosneto em 28 setembro 2016 às 2:01

cara ola, qual software vc usou para desenvolver o aplicativo ?

© 2024   Criado por Marcelo Rodrigues.   Ativado por

Badges  |  Relatar um incidente  |  Termos de serviço