Метеостанція + побудова графіку + C#
Автор: Alex-human, переклад.
Джерело:http://cxem.net
Хоча я новачок в роботі з arduino, і все ще не знаю добре про можливості даного апарату, я вирішив поділитися своїм успішним досвідом, тому що знаю, як це – шукати те, що не можливо знайти, особливо коли його просто неіснує. В цій статті я докладно опишу мій проект, який є моєю практичною роботою в університеті. Мені його ніхто не нав’язував, просто друг захопився і показав мені. Мене ця штукенція звичайно ж зацікавила і я вирішив спробувати. До того ж програма не надто складна.
Отже, робота полягає в наступному: з відомого багатьом давача DHT11 (давач вологості і температури) приймаємо дані через COM порт, далі записуємо дані в текстовий файл і за цими даними будуємо графік змін.
Arduino Uno побудований на ATmega328. Платформа має 14 цифрових входів/виходів, 6 аналогових входів, кварцовий генератор 16 МГц, роз’єм USB, силовий роз’єм, роз’їм ICSP і кнопку перезавантаження. Для роботи необхідно підключити платформу до комп’ютера з допомогою кабеля USB, або подати живлення з допомогою адаптера AC/DC або батареї.
Характеристики:
Мікроконтролер ATmega328
Рабоча напруга 5 В
Вхідна напруга (рекомендована) 7-12 В
Вхідна напруга (гранична) 6-20 В
Цифрові Входи/Виходи 14
Аналогові входи 6
Постійний струм через вхід/вихід 40 мА
Постійний струм для виводу 3.3 В 50 мА
Флеш – пам’ять 32 Кб (ATmega328) з яких 0.5 Кб використовується для завантажувача
ОЗП 2 Кб (ATmega328)
EEPROM 1 Кб (ATmega328)
Тактова частота 16 МГц
Датчик DHT11
Відносна вологість:
Роздільна здатність = 16 Bit
повторюваність = ±1%
точність = якщо 25℃, то ±5%
взаємозамінність = повністю взаємозамінний
час відгуку = 1-2 сек
гістерезис = <±0,3% RH
стабільність = <±0,5% RH/год
Температура:
Роздільна здатність = 16 Bit
повторюваність = ±0,2℃
діапазон = якщо 25℃ ± 2℃
час відгуку = 1-2 сек
Електричні характеристики:
живлення = 3,5 – 5,5 V
Фотографія давача в розрізі:
DHT11 цифровий давач температури і вологості є складеним давачем, який містить калібрований цифровий вихідний сигнал з показами температури і вологості. Він має високу надійність та чудову довготривалу стабільність роботи. Давач включає в себе резистивний сенсор вологості і компоненти NTC (negative temperature coefficient) структури для вимірювання температури.
Підключення
1 – VCC – живлення 3,5 – 5,5 V
2 – DATA – передача даних
3 – NC – не використовується
4 – GND – від’ємне живлення
Для підключення до arduino необхідно під’ єднати між 1 і 2 ніжкою резистор = 10кОм.
Схема під’єднання
Схема:
Програмний код (скетч для давача DHT11)
#include "DHT.h" #define DHTPIN 2 // у меня подключен ко 2 пину, поэтому 2 #define DHTTYPE DHT11 // указываем какой датчик DHT dht(DHTPIN, DHTTYPE); void setup() { Serial.begin(9600); //указываем скорость передачи в бодах dht.begin(); } void loop() { int h = dht.readHumidity();//переменная для влажности int t = dht.readTemperature();//переменная для температуры if (isnan(t) || isnan(h)) {//проверка (что мы получаем на запрос из датчика - цифры?) Serial.println("Failed to read from DHT");//сообщение об ошибке } else { //Serial.print("Humidity: "); <strong> </strong>Serial.print(h);//вывожу построчно - влажность Serial.print("\t\n");//сдвиг каретки и начало строки // Serial.print("Temperature: "); Serial.print(t);//температура Serial.print("\n"); //Serial.println(" *C"); } delay(60000);//задержка времени в милсек. = 1 мин. //delay(3600000);//на каждый час }
Завантажую даний скетч, і кожну хвилину отримую дані в моніторі COM порту
34 – в % відносна вологість
25 – в ℃ температура
Далі я так би мовити прикрашав свою програму, надавав їй товарного вигляду. Все це я робив в середовищі програмування Microsoft Visual Studio 2012 .NET. Я зробив за стосунок, який через COM порт отримує дані і обробляє їх. Отримую і записую у файл. Також порядково. В першому рядку значення, а другому – дата і час моменту отримання даних. Це згодиться для побудови графіків. Хто не знайомий з C#, дуже рекомендую – зручна річ. Створюю форму з 2-ма текст боксами, перший буде виводити значення вологості, другий – значення температури. Із них створюється файл, якщо не був створений, а якщо вже існує то дописуємо в нього. 2 файли – 1- Графік температури, 2-Графік вологості. Назви можете придумувати свої. Елементи, що використовуються в програмі : : textbox і textbox1, openFileDialog – для роботи з вибором файлу для графіка, notifyIcon – для роботи з іконкою, для звертання в трей.
Ось запуск застосунку
Для перегляду графіка, натискаємо на кнопку Демонстрація графіку і вибираємо файл, тобто те що ми хочемо побачити (вологість чи температуру)
Далі натискаємо – Відкрити і побачимо графік
Це графік відносної вологості. Графік має властивість – він масштабується по осі Х. Якщо інтервал великий – ми мишкою виділяємо зону, яка цікава для нас і вона наближується. Якщо загальний графік то на осі Х біля 0 натискаємо “-” і графік буде загальним.
Також я трохи вдосконалив програму – зробив так щоб вона зверталася в трей. Бо для того щоб працювати вона має бути запущена і хоча вікно можна звертати, але ймовірно воно буде заважати. А так дуже зручно.
1-ий значок в треї – програма. Після натискання лівою кнопкою мишки – звертається або розвертається.
Наводжу сирець своєї програми:
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.IO; namespace arduino { public partial class Form1 : Form { public Form1() { InitializeComponent(); notifyIcon1.Visible = false; this.notifyIcon1.MouseClick += new MouseEventHandler(notifyIcon1_MouseClick); this.Resize += new System.EventHandler(this.Form1_Resize); // Открываем порт, и задаем скорость в 9600 бод serialPort1.PortName = "COM6"; serialPort1.BaudRate = 9600; serialPort1.DtrEnable = true; serialPort1.Open(); serialPort1.DataReceived += serialPort1_DataReceived; serialPort1.DataReceived += serialPort1_DataReceived1; } //****** поток ком порта private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) { string vlag = serialPort1.ReadLine(); this.BeginInvoke(new LineReceivedEvent(LineReceived), vlag); } private void serialPort1_DataReceived1(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) { string temp = serialPort1.ReadLine(); this.BeginInvoke(new LineReceivedEvent1(LineReceived1), temp); } //запись влажности private delegate void LineReceivedEvent(string vlag); private void LineReceived(string vlag) { textBox1.Text = vlag; string path = "График_влажности.txt"; string date = DateTime.Now.ToString(); // Создание файла и запись в него using (StreamWriter sw = File.AppendText(path)) { sw.WriteLine(vlag); sw.WriteLine(date); } } //запись температуры private delegate void LineReceivedEvent1(string temp); private void LineReceived1(string temp) { textBox2.Text = temp.ToString(); string path = "График_температуры.txt"; string date = DateTime.Now.ToString(); // Создание файла и запись в него using (StreamWriter sw = File.AppendText(path)) { sw.WriteLine(temp); sw.WriteLine(date); } } private void button1_Click(object sender, EventArgs e) { if (openFileDialog1.ShowDialog() == DialogResult.OK) { chart1.ChartAreas[0].AxisX.ScaleView.Zoom(0,30); chart1.ChartAreas[0].CursorX.IsUserEnabled = true; chart1.ChartAreas[0].CursorX.IsUserSelectionEnabled = true; chart1.ChartAreas[0].AxisX.ScaleView.Zoomable = true; chart1.ChartAreas[0].AxisX.ScrollBar.IsPositionedInside = true; //chart1.ChartAreas[0].AxisY.ScaleView.Zoom(0, 30); //chart1.ChartAreas[0].CursorY.IsUserEnabled = true; //chart1.ChartAreas[0].CursorY.IsUserSelectionEnabled = true; //chart1.ChartAreas[0].AxisY.ScaleView.Zoomable = true; //chart1.ChartAreas[0].AxisY.ScrollBar.IsPositionedInside = true; StreamReader streamReader = new StreamReader(openFileDialog1.FileName); chart1.Series[0].Points.Clear(); while (!streamReader.EndOfStream) { string Y = streamReader.ReadLine(); string X = streamReader.ReadLine(); chart1.Series[0].Color = Color.Red; chart1.Series[0].BorderWidth = 1; chart1.Series[0].Points.AddXY(X, Y); } streamReader.Close(); } } private void Form1_Resize(object sender, EventArgs e) { if (this.WindowState == FormWindowState.Minimized) { this.Hide(); notifyIcon1.Visible = true; } } private void notifyIcon1_MouseClick(object sender, MouseEventArgs e) { this.Show(); this.WindowState = FormWindowState.Normal; notifyIcon1.Visible = false; } } }
Прикріплені файли: