quarta-feira, 20 de maio de 2015

Implementando sensor de temperatura e umidade com C#

Como todos sabem, o serial monitor do arduino, possui um limite bem pequeno para possibilidades de comunicação, além de não ser possível elaborar interfaces gráficas com botões e tudo mais. Uma solução para isso é criar programas executáveis em C# (csharp), que é uma linguagem de programação voltada para objetos desenvolvida pela microsoft e baseada no C++ e integrar ao seu projeto. Nesse post vou apresentar para vocês uma pequena interação entre o C# e o arduino, onde o microcontrolador lê um sensor de temperatura e umidade DHT11 e a aplicação em C# mostra esses valores no display e plota um gráfico com os número de temperatura umidade relativa recebidos. 

Para chegar nisso, temos duas partes principais: a primeira é a programação do arduino para ler os valores do sensor e fazer um Serial.print quando ele receber o caractere 'a' na porta serial que foi enviada pelo programa. A segunda parte é fazer toda a interface e programação em C# utilizando o Visual Studio, para que a cada 1s ele envie o caractere 'a' na porta serial, para o arduino lhe fornecer os valores de leituras. Esse delay entre as leituras pode ser alterado para o tempo que você quiser, apenas achei 1s conveniente para mim. Vamos à programação no arduino.

#include "DHT.h"

#define DHTPIN 2
#define DHTTYPE DHT11

DHT dht(DHTPIN, DHTTYPE);

void setup() {
  Serial.begin(9600); 

  dht.begin();
}

void loop() {
  delay(500);

  int h = dht.readHumidity();
  int t = dht.readTemperature();

  char x = Serial.read();
  
  if(x == 'a'){
    Serial.print(h);
    Serial.print(","); 
    Serial.println(t);
  }
}

Essa parte não tem nenhum segredo. Ele captura os valores de temperatura e umidade e joga na porta serial quando recebe o caractere 'a'. Já a parte em C# é um pouco mais complexa, mas nada fora do normal.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
using System.Threading;

namespace arduino
{
    public partial class Form1 : Form
    {

        Thread X;
        public Form1()
        {
            InitializeComponent();
            ComboPorta.DataSource = SerialPort.GetPortNames();
            X = new Thread(new ThreadStart(Serial));
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (SP.IsOpen)
            {
                SP.Close();
                X.Abort();
                timerx.Enabled = false;
            }
            else
            {
                SP.PortName = ComboPorta.Text;
                SP.BaudRate = Convert.ToInt32(ComboBaud.Text);
                SP.Open();
                //X.Start();
                timerx.Enabled = true;
               
            }
        }

        void Serial()
        {
            while (true)
            {
                SP.Write("a");
                textBox1.Text += SP.ReadLine();
                textBox1.Text += "\r\n";
            }
        }


        private void timerx_Tick(object sender, EventArgs e)
        {
            SP.Write("a");
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            SP.Close();
            X.Abort();
            timerx.Enabled = false;
        }

        private void SP_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            this.Invoke(new EventHandler(transfere));
        }

        void transfere(object sender, EventArgs e)
        {
            string dado = SP.ReadLine();
            string [] dados = dado.Split(',');
            textBox1.Text += dados[0];
            textBox1.Text += "%\r\n";
            textBox1.Select(textBox1.Text.Length, 0);
            textBox1.ScrollToCaret();
            
            textBox2.Text += dados[1];
            textBox2.Text += "°C\r\n";
            textBox2.Select(textBox2.Text.Length, 0);
            textBox2.ScrollToCaret();

            chart1.Series[0].Points.Add(Convert.ToDouble(dados[0]));
            chart1.Series[1].Points.Add(Convert.ToDouble(dados[1]));
            int x = chart1.Series[0].Points.Count;
            if (x > 100)
                chart1.ChartAreas[0].AxisX.ScaleView.Zoom(x - 100, x);
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            
        }

        private void label4_Click(object sender, EventArgs e)
        {

        }

            
    }
}

Sintetizando todo esse código, temos o programa enviando a cada 1000ms o char 'a' na porta serial e capturando os dados fornecidos que logo depois são quebrados pela função split e atribuídos como dados[1] e dados [2], para umidade e temperatura respectivamente. O resto é lógica incorporada ao C# e a interface visual do programa. O resultado final é esse:


Logo abaixo deixo o link para download tanto da programação em arduino como o projeto no Visual Studio para quem quiser testar, implementar, modificar, etc. Ah, o arquivo executável do programa encontra-se na pasta SerialPort\visual\arduino\bin\Debug.

Download do programa: https://goo.gl/Xk8jgm

3 comentários:

  1. bom dia. criei outro grafico no visual studio2015 , só que ele não cria esta barra de rolagem que possui neste seu exemplo. poderia me dizer como posso fazer isto?

    ResponderExcluir
  2. bom dia. criei outro grafico no visual studio2015 , só que ele não cria esta barra de rolagem que possui neste seu exemplo. poderia me dizer como posso fazer isto?

    ResponderExcluir
  3. Vou tentar adaptar esses recursos naquele esquema da irrigação, lá do forum... futuramente

    ResponderExcluir