Advertisement
Guest User

Datalogger

a guest
Feb 21st, 2017
124
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 30.36 KB | None | 0 0
  1. #include <LiquidCrystal.h> // Библиотека LCD
  2. #include <OneWire.h>
  3. #include <SPI.h>
  4. #include <SD.h>
  5.  
  6. /* условные обозначения на LCD:
  7.     "A=xx.xx" - показания сенсоров температуры. Идентифицируются по возрастанию значения адреса. Соостветствие букв может изменяться при добавлении нового сенсора.
  8.     "-" в конце первой строки - означает, размер файла не изменился после операции записи в файл.
  9.     "+" в конце первой строки - означает, размер файла изменился после операции записи в файл. Всё нормально записалось.
  10.     "!" в конце второй строки - означает, размер файла не изменился после операции записи в файл, после этого происходит перезагрузка контроллера.
  11. */
  12.  
  13. #define Relay A2                                      // вывод для управления насосом
  14. #define sunrise 40                                    // уровень освещённости для включения насоса
  15. #define interval 20                                   // интервал замеров в секундах
  16.  
  17. boolean Flag_nasosa = 0;                              // статус состояния циркуляционного насоса
  18. boolean Flag_SD = 0;                                  // переменная для работы без SD карты
  19. float sun = 0;                                        // глобальная переменная значения освещённости
  20.  
  21. unsigned long oldmillis = 0;                          // время предыдущего цикла измерений
  22.  
  23. const int chipSelect = 2;                             // CS SD-карты  (13 SCK, 12-MISO, 11-MOSI, 2-CS )
  24. OneWire  ds(A3);                                      // on pin A3 (a 4.7K resistor is necessary)  // Вход с датчиков температуры.
  25. LiquidCrystal lcd(8, 9, 4, 5, 6, 7);                  // Подключение LCD
  26.  
  27. byte n = 0;                                           // позиция на индикаторе
  28.  
  29. //unsigned int bri = 126;                             // Переменная для хранения значения яркости (в будущем будет регулировка яркоски LCD)
  30.  
  31. volatile unsigned long quantity = 0;                  // считаем количество прерываний от расходомера
  32. unsigned long oldquantity = 0;                        // предыдущее количество прерываний от расходомера
  33.  
  34. unsigned long rasxod = 0;                             // количество прерываний от расходомера за интервал между измерениями
  35.  
  36.  
  37. //--------------------------------------------------------------------------------------------------------------------------------------------------------
  38. void flowmeter() {                                    // обработка прерываний от расходомера
  39.  
  40.   quantity++;                                         // увеличиваем на единицу
  41. }
  42. //--------------------------------------------------------------------------------------------------------------------------------------------------------
  43.  
  44. void(* resetFunc) (void) = 0;                         //объявляем функцию reset с адресом 0
  45.  
  46. //--------------------------------------------------------------------------------------------------------------------------------------------------------
  47.  
  48.  
  49. void NewLogger(String ADDR, String data) {                // процедура записи каждого отдельного сенсора в отдельный файл "АДРЕС_ДАТЧИКА.ТХТ"
  50.   // структура записи: время фиксации измерений от запуска; показания именно этого сенсора температуры; показания сенсора освещённости; расход теплоносителя между замерами; состояние реле насоса (0/1)
  51.  
  52.   unsigned long  Filesize = 0;                            // размер файла до процедуры записи
  53.   unsigned long  Filesize_1 = 0;                          // размер файла после процедуры записи
  54.  
  55.   String  filename = "LOG/" + ADDR + ".txt";              // будем всё писать в каталог LOG на карте, если много "насрать" к корень диска, то карта долго инициализируется.
  56.  
  57.   File dataFile = SD.open(filename, FILE_WRITE);          // открываем файл на SD-карте для записи
  58.   Filesize = dataFile.size();                             // получаем размер файла до записи информации
  59.  
  60.   dataFile.println(data);                                 // пишем в файл заранее подготовленную строку данных
  61.  
  62.   Filesize_1 = dataFile.size();                           // получаем размер файла после вероятной записи информации
  63.   dataFile.close();                                       // закрываем файл
  64.  
  65.   if (Filesize_1 != Filesize) {                           // если размер файла после операции записи изменился, то значит всё хорошо
  66.  
  67.     lcd.setCursor(15, 0);                                 // Установка курсора место вывода служебной информации в первой строке
  68.     lcd.print("+");                                       // выводим на экран условный знак "+"
  69.  
  70.     Serial.println(" saved successfully");                // диагностическая информация в терминал
  71.     Filesize = Filesize_1;                                // присваиваем глобальной переменной Filesize новое значение
  72.  
  73.     Flag_SD = 1;
  74.  
  75.     return ;
  76.   }
  77.  
  78.   // если размер после операции записи не изменился, то значит у Хьюстона проблемы
  79.  
  80.   lcd.setCursor(15, 0);                                 // Установка курсора место вывода служебной информации в первой строке
  81.   lcd.print("-");                                       // выводим на экран условный знак "-"
  82.   lcd.setCursor(15, 1);                                 // Установка курсора место вывода служебной информации во второй строке
  83.   lcd.print("!");                                       // выводим на экран условный знак "!"
  84.   Flag_SD = 0;
  85.  
  86.   return;
  87. }
  88.  
  89. //----------------------------измеряем температуру-------------------
  90. byte Read_Temp() {
  91.  
  92.   byte i;
  93.   byte present = 0;                                             // флаг наличия сенсора на шине OneWire
  94.   byte type_s;                                                  // тип сенсора
  95.   byte data[12];                                                // массив для данных сенсора
  96.   byte addr[8];                                                 // массив для адреса сенсора
  97.   float celsius;                                                // переменная для значения температуры
  98.   String string_ADDR = "";                                      // переменная для значения адреса сенсора
  99.   String string_SD_data = "";                                   // переменная для аккумулирования данных для записи на SD-карту
  100.   unsigned long time_sensor = 0;                                // переменная для фиксации времени измерения
  101.  
  102.   ds.reset();                                                   // сброс на шине, начало обмены информации
  103.   ds.write(0xCC, 1);                                            // всем всем всем
  104.   ds.write(0x44, 1);                                            // команда сенсорам "начать преобразование температуры"
  105.  
  106.   time_sensor = millis() / 1000;             // начинаем формировать строку для записи на карту, пишем время в секундах от начала работы системы и разделитель ";"
  107.  
  108.   delay(1000);                                                  // ждём 1 секунду, чтобы все датчики успели завершить преобразование
  109.  
  110.   lcd.clear();                                                  // Подготавливаем дисплей для отображения информации о температуре датчиков. Переход на первую строку
  111.  
  112.   while ( ds.search(addr) != 0) {                               // читаем данные с шины, пока не закончатся все имеющиеся датчики
  113.  
  114.     for ( i = 4; i < 8; i++) {                                  // будем читать только последние 4 байт адреса очередного сенсора DS18x20, чтобы не превысить имя файла 8.3
  115.       string_ADDR = string_ADDR + String(addr[i], HEX);         // собираем полученные данные в строку для записи имени файла(часть адреса сенсора)
  116.     }
  117.     if (OneWire::crc8(addr, 7) != addr[7]) {                    // проверяем контрольную сумму считанного адреса сенсора
  118.       string_SD_data = String(time_sensor) + "CRC is not valid! ; ";           // если контрольная сумма не совпадает, то сообщаем об этом в логфайл
  119.       return (0);                                               // дальнейшее чтение данных на шине прекращаем, следующий сеанс связи по расписанию
  120.     }
  121.  
  122.     // если получение адреса сенсора прошло без ошибок, то продолжаем работать дальше
  123.  
  124.     switch (addr[0]) {                                          // первый байт ROM показывает тип датчика
  125.       case 0x10:
  126.         //Serial.println("  Chip = DS18S20");  // or old DS1820
  127.         type_s = 1;
  128.         break;
  129.       case 0x28:
  130.         //Serial.println("  Chip = DS18B20");
  131.         type_s = 0;
  132.         break;
  133.       case 0x22:
  134.         //Serial.println("  Chip = DS1822");
  135.         type_s = 0;
  136.         break;
  137.       default:
  138.         //Serial.println("Device is not a DS18x20 family device.");
  139.         return (0);
  140.     }
  141.  
  142.     ds.reset();                                                  // инициализируем шину OneWire
  143.     ds.select(addr);                                             // выбираем текущий сенсор
  144.     ds.write(0xBE);                                              // Читаем Scratchpad
  145.  
  146.     for ( i = 0; i < 9; i++) {                                   // нам необходимо получить 9 байт
  147.       data[i] = ds.read();                                       // заполняем массив данными
  148.     }
  149.  
  150.     int16_t raw = (data[1] << 8) | data[0];                      // проводим небольшие вычисления
  151.     if (type_s) {
  152.       raw = raw << 3; // 9 bit resolution default
  153.       if (data[7] == 0x10) {
  154.         // "count remain" gives full 12 bit resolution
  155.         raw = (raw & 0xFFF0) + 12 - data[6];
  156.       }
  157.     } else {
  158.       byte cfg = (data[4] & 0x60);
  159.       // at lower res, the low bits are undefined, so let's zero them
  160.       if (cfg == 0x00) raw = raw & ~7;  // 9 bit resolution, 93.75 ms
  161.       else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
  162.       else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
  163.       // default is 12 bit resolution, 750 ms conversion time
  164.     }
  165.     celsius = (float)raw / 16.0;                                 // и получаем температуру в градусах Цельсия
  166.  
  167.     string_SD_data = String(time_sensor) + " ; " + String(celsius) + " ; " + String(sun) + " ; " + String(rasxod) + " ; " + String(Flag_nasosa);           // добавляем все данные в строку сразу после значений этого сенсора
  168.     NewLogger(string_ADDR, string_SD_data);                      // отправляем данные записываться на SD-карту
  169.  
  170.     Serial.print(string_ADDR);
  171.     Serial.print("   ");
  172.     Serial.println(string_SD_data);
  173.     Serial.println();
  174.  
  175.     string_ADDR = "";                                            // очищаем строку данных для следующего измерения
  176.     string_SD_data = "";                                         // очищаем строку данных для следующего измерения
  177.  
  178.     //  вывод информации о значениях температуры всех на LCD дисплей для наглядного отображения
  179.  
  180.     n++;                                                         // следующую позиция на индикаторе
  181.     if (n > 0 && n < 5) {
  182.       switch (n) {                                               // в зависимости от порядкового номера сенсора выводим информацию на LCD дисплей
  183.         case 1:
  184.           lcd.setCursor(0, 0);
  185.           lcd.print("A=");                                       // датчики идентифицируем по буквам алфавита
  186.           lcd.print(celsius);
  187.           break;
  188.  
  189.         case 2:
  190.           lcd.setCursor(8, 0);                                   // в позицию 8 первой строки
  191.           lcd.print("B=");
  192.           lcd.print(celsius);
  193.           break;
  194.  
  195.         case 3:
  196.           lcd.setCursor(0, 1);                                   // в позицию начала первой строки
  197.           lcd.print("C=");
  198.           lcd.print(celsius);
  199.           break;
  200.  
  201.         case 4:
  202.           lcd.setCursor(8, 1);                                   // в позицию 8 второй строки
  203.           lcd.print("D=");
  204.           lcd.print(celsius);
  205.           break;
  206.       }
  207.       if (n == 4) {
  208.         delay(5000);
  209.         lcd.clear();
  210.       }
  211.     }
  212.     if (n > 4 && n < 9) {
  213.       switch (n) {                                               // в зависимости от порядкового номера сенсора выводим информацию на LCD дисплей
  214.         case 5:
  215.           lcd.setCursor(0, 0);
  216.           lcd.print("E=");                                       // датчики идентифицируем по буквам алфавита
  217.           lcd.print(celsius);
  218.           break;
  219.  
  220.         case 6:
  221.           lcd.setCursor(8, 0);                                   // в позицию 8 первой строки
  222.           lcd.print("F=");
  223.           lcd.print(celsius);
  224.           break;
  225.  
  226.         case 7:
  227.           lcd.setCursor(0, 1);                                   // в позицию начала первой строки
  228.           lcd.print("G=");
  229.           lcd.print(celsius);
  230.           break;
  231.  
  232.         case 8:
  233.           lcd.setCursor(8, 1);                                   // в позицию 8 второй строки
  234.           lcd.print("H=");
  235.           lcd.print(celsius);
  236.           break;
  237.       }
  238.       if (n == 8) {
  239.         delay(5000);
  240.         lcd.clear();
  241.       }
  242.     }
  243.     if (n > 8 && n < 13) {
  244.       switch (n) {                                               // в зависимости от порядкового номера сенсора выводим информацию на LCD дисплей
  245.         case 9:
  246.           lcd.setCursor(0, 0);
  247.           lcd.print("I=");                                       // датчики идентифицируем по буквам алфавита
  248.           lcd.print(celsius);
  249.           break;
  250.  
  251.         case 10:
  252.           lcd.setCursor(8, 0);                                   // в позицию 8 первой строки
  253.           lcd.print("J=");
  254.           lcd.print(celsius);
  255.           break;
  256.  
  257.         case 11:
  258.           lcd.setCursor(0, 1);                                   // в позицию начала первой строки
  259.           lcd.print("K=");
  260.           lcd.print(celsius);
  261.           break;
  262.  
  263.         case 12:
  264.           lcd.setCursor(8, 1);                                   // в позицию 8 второй строки
  265.           lcd.print("L=");
  266.           lcd.print(celsius);
  267.           break;
  268.       }
  269.       if (n == 12) {
  270.         delay(5000);
  271.         lcd.clear();
  272.       }
  273.     }
  274.     if (n > 12 && n < 17) {
  275.       switch (n) {                                               // в зависимости от порядкового номера сенсора выводим информацию на LCD дисплей
  276.         case 12:
  277.           lcd.setCursor(0, 0);
  278.           lcd.print("M=");                                       // датчики идентифицируем по буквам алфавита
  279.           lcd.print(celsius);
  280.           break;
  281.  
  282.         case 14:
  283.           lcd.setCursor(8, 0);                                   // в позицию 8 первой строки
  284.           lcd.print("N=");
  285.           lcd.print(celsius);
  286.           break;
  287.  
  288.         case 15:
  289.           lcd.setCursor(0, 1);                                   // в позицию начала первой строки
  290.           lcd.print("O=");
  291.           lcd.print(celsius);
  292.           break;
  293.  
  294.         case 16:
  295.           lcd.setCursor(8, 1);                                   // в позицию 8 второй строки
  296.           lcd.print("P=");
  297.           lcd.print(celsius);
  298.           break;
  299.       }
  300.       if (n == 16) {
  301.         delay(5000);
  302.         lcd.clear();
  303.       }
  304.     }
  305.     if (n > 16 && n < 21) {
  306.       switch (n) {                                               // в зависимости от порядкового номера сенсора выводим информацию на LCD дисплей
  307.         case 17:
  308.           lcd.setCursor(0, 0);
  309.           lcd.print("Q=");                                       // датчики идентифицируем по буквам алфавита
  310.           lcd.print(celsius);
  311.           break;
  312.  
  313.         case 18:
  314.           lcd.setCursor(8, 0);                                   // в позицию 8 первой строки
  315.           lcd.print("R=");
  316.           lcd.print(celsius);
  317.           break;
  318.  
  319.         case 19:
  320.           lcd.setCursor(0, 1);                                   // в позицию начала первой строки
  321.           lcd.print("S=");
  322.           lcd.print(celsius);
  323.           break;
  324.  
  325.         case 20:
  326.           lcd.setCursor(8, 1);                                   // в позицию 8 второй строки
  327.           lcd.print("T=");
  328.           lcd.print(celsius);
  329.           break;
  330.       }
  331.       if (n == 20) {
  332.         delay(5000);
  333.         lcd.clear();
  334.       }
  335.     }
  336.     if (n > 20 && n < 25) {
  337.       switch (n) {                                               // в зависимости от порядкового номера сенсора выводим информацию на LCD дисплей
  338.         case 21:
  339.           lcd.setCursor(0, 0);
  340.           lcd.print("U=");                                       // датчики идентифицируем по буквам алфавита
  341.           lcd.print(celsius);
  342.           break;
  343.  
  344.         case 22:
  345.           lcd.setCursor(8, 0);                                   // в позицию 8 первой строки
  346.           lcd.print("V=");
  347.           lcd.print(celsius);
  348.           break;
  349.  
  350.         case 23:
  351.           lcd.setCursor(0, 1);                                   // в позицию начала первой строки
  352.           lcd.print("W=");
  353.           lcd.print(celsius);
  354.           break;
  355.  
  356.         case 24:
  357.           lcd.setCursor(8, 1);                                   // в позицию 8 второй строки
  358.           lcd.print("X=");
  359.           lcd.print(celsius);
  360.           break;
  361.       }
  362.       if (n == 24) {
  363.         delay(5000);
  364.         lcd.clear();
  365.       }
  366.     }
  367.     if (n > 24 && n < 27) {
  368.       switch (n) {                                               // в зависимости от порядкового номера сенсора выводим информацию на LCD дисплей
  369.         case 25:
  370.           lcd.setCursor(0, 0);
  371.           lcd.print("Y=");                                       // датчики идентифицируем по буквам алфавита
  372.           lcd.print(celsius);
  373.           break;
  374.  
  375.         case 26:
  376.           lcd.setCursor(8, 0);                                   // в позицию 8 первой строки
  377.           lcd.print("Z=");
  378.           lcd.print(celsius);
  379.           break;
  380.       }
  381.       if (n == 26) {
  382.         delay(5000);
  383.         lcd.clear();
  384.       }
  385.     }
  386.     if (n > 26) {
  387.       lcd.setCursor(0, 0);
  388.       lcd.print("reached the max.");
  389.       lcd.setCursor(0, 1);
  390.       lcd.print("number of sensors");
  391.       delay(5000);
  392.       return (0);
  393.     }
  394.  
  395.  
  396.   }
  397.   delay(4000);
  398.   lcd.clear(); // Очистка LCD
  399.   lcd.print("No more sensors");
  400.   delay(2000);
  401.  
  402.   return (1);
  403. }
  404.  
  405.  
  406. //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  407. void setup() {
  408.  
  409.   pinMode(Relay, OUTPUT);                                 // вывод для управления насосом
  410.   pinMode(3,INPUT);                                       // вход для прерываний от расходомера
  411.   digitalWrite(3,HIGH);                                   // подтягиваем на +5V встроенным резистором 10к
  412.   digitalWrite(Relay, LOW);                               // инициализируем вывод управления реле насоса
  413.  
  414.   Serial.begin(9600);                                     // Инициализация терминала для диагностической информации
  415.  
  416.   lcd.begin(16, 2);                                       // Настройка LCD 2 строки 16 символов
  417.   lcd.clear();                                            // Очистка LCD
  418.  
  419.   lcd.print("   DataLogger   ");                          // Вывод строчки на LCD (Название программы)
  420.  
  421.   Serial.println("Initializing SD card...");              // диагностическая информация в терминал
  422.  
  423.   lcd.setCursor(0, 1);                                    // Установка курсора в начало второй строки LCD
  424.   lcd.print(" Init SD card...");                          // диагностическая информация на LCD
  425.   delay(1000);
  426.  
  427.   if (!SD.begin(chipSelect)) {                            // Если SD-карта отсутствует или на может быть инициализирована, то
  428.  
  429.     Serial.println("Card failed, or not present");        // диагностическая информация в терминал
  430.     lcd.setCursor(0, 1);                                  // Установка курсора в начало второй строки LCD
  431.     lcd.print("  SD card Error ");                        // диагностическая информация на LCD
  432.     delay(1000);
  433.     return;                                               // программа продолжит работу без SD-карты один цикл измерений и затем перезапустится
  434.   }
  435.   Serial.println("card initialized.");                    // диагностическая информация в терминал, если инициализация прошла успешно
  436.  
  437.   lcd.setCursor(0, 1);                                    // Установка курсора в начало второй строки LCD
  438.   lcd.print("   SD card Ok   ");                          // диагностическая информация на LCD
  439.   delay(1000);
  440.  
  441.   attachInterrupt(1, flowmeter, FALLING);                 // назначим прерывание INT1 для расходомера
  442. }
  443.  
  444. //-------------------------------------------------------------------------------------------------------------------------------------------
  445.  
  446.  
  447.  
  448. //------------------------------------ сенсор освещённости ---------------------------------------------------------------------------------
  449. void Sun_sensor() {                                       // вычисляем количество солнечного света для включения насоса и оценки работы солнечного коллектора
  450.  
  451.   sun = (1023 - analogRead(A1)) / 10.00;                  // читаем аналоговый порт А1 данные о текущей освещённости
  452.  
  453.   return;
  454. }
  455. //------------------------------------------------------------------------------------------------------------------------------------------
  456. void loop() {
  457.  
  458.  
  459.   Sun_sensor();                                           // регулярно проверяем освещённость для оперативного управления насосом
  460.  
  461.   if (sun > sunrise) {
  462.     digitalWrite(Relay, HIGH);                            // если Солнце встало, то включаем насос
  463.     Flag_nasosa = 1;
  464.   }
  465.   else {
  466.     digitalWrite(Relay, LOW);                             // если Солнца нет, то насос выключаем
  467.     // возвращаемся обратно
  468.     Flag_nasosa = 0;
  469.   }
  470.  
  471.   //-------------------------------------------------------------------------------------------------------------------------------------------
  472.  
  473.   if (((millis() - oldmillis) / 1000 > interval) || (Flag_SD == 0)) {  // попадаем сюда только после таймера задержки или в первый раз после перезагрузки
  474.  
  475.     rasxod = quantity - oldquantity;                      // проверяем, сколько там воды утекло с момента прошлого измерения
  476.     oldquantity = quantity;                               // нарекаем момент старого измерения новым измерением
  477.  
  478.     n = 0;                                                // страница для вывода на индикаторе в начало
  479.     Read_Temp();                                          // читаем температуру с сенсоров DS18x20 и записываем в лог файл
  480.  
  481.  
  482.     if (Flag_SD == 0) {                                   // если один цикл измерений и записи прошёл с ошибкой, то ребутим систему
  483.       lcd.setCursor(0, 1);                                // позиция во второй строке
  484.       lcd.print(" system reset ");                        // информационное сообщение на LCD дисплее
  485.       delay(5000);                                        // задержка, чтобы пользователь заметил
  486.       resetFunc();                                        // вызываем reset
  487.     }
  488.    
  489. oldmillis = millis();                                     // если всё нормально, то сбрасываем таймер
  490. }
  491.   else {
  492.     lcd.setCursor(0, 0);                                  // Установка курсора в начало первой строки LCD
  493.     lcd.print("Waiting....      ");                       // информационное сообщение на LCD дисплее
  494.     lcd.setCursor(0, 1);                                  // Установка курсора в начало второй строки LCD
  495.     lcd.print("      voda=");                                   // информационное сообщение на LCD дисплее
  496.     lcd.print(quantity);                                  // Индикация работы расходомера
  497.     lcd.setCursor(0, 1);                                  // Установка курсора в начало второй строки LCD
  498.     lcd.print( interval - (millis() - oldmillis) / 1000); // информационное сообщение на LCD дисплее
  499.    
  500.     delay(500);                                           // замедляем частоту обновления информации об оставшемся времени
  501.     lcd.print("                ");                        // аккуратненько подчищаем, для исключения наложения цифр
  502.   }
  503.  
  504. //----------------------------------------------------------------------------------------------------------------------------------------
  505.  
  506.   // key = read_buttons(); // Считывание значения кнопки
  507.  
  508.   // unsigned int bri = Do_Key(key);
  509.  
  510.   //  analogWrite(10, bri / 256); //изменить значение яркости подсветки
  511.   //  analogWrite(10, bri); //изменить значение яркости подсветки
  512.   // lcd.setCursor(8, 1);
  513.   // lcd.print(bri / 256); //отобразить текущую яркость на LCD
  514.  
  515. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement