Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <LiquidCrystal.h> // Библиотека LCD
- #include <OneWire.h>
- #include <SPI.h>
- #include <SD.h>
- /* условные обозначения на LCD:
- "A=xx.xx" - показания сенсоров температуры. Идентифицируются по возрастанию значения адреса. Соостветствие букв может изменяться при добавлении нового сенсора.
- "-" в конце первой строки - означает, размер файла не изменился после операции записи в файл.
- "+" в конце первой строки - означает, размер файла изменился после операции записи в файл. Всё нормально записалось.
- "!" в конце второй строки - означает, размер файла не изменился после операции записи в файл, после этого происходит перезагрузка контроллера.
- */
- #define Relay A2 // вывод для управления насосом
- #define sunrise 40 // уровень освещённости для включения насоса
- #define interval 20 // интервал замеров в секундах
- boolean Flag_nasosa = 0; // статус состояния циркуляционного насоса
- boolean Flag_SD = 0; // переменная для работы без SD карты
- float sun = 0; // глобальная переменная значения освещённости
- unsigned long oldmillis = 0; // время предыдущего цикла измерений
- const int chipSelect = 2; // CS SD-карты (13 SCK, 12-MISO, 11-MOSI, 2-CS )
- OneWire ds(A3); // on pin A3 (a 4.7K resistor is necessary) // Вход с датчиков температуры.
- LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // Подключение LCD
- byte n = 0; // позиция на индикаторе
- //unsigned int bri = 126; // Переменная для хранения значения яркости (в будущем будет регулировка яркоски LCD)
- volatile unsigned long quantity = 0; // считаем количество прерываний от расходомера
- unsigned long oldquantity = 0; // предыдущее количество прерываний от расходомера
- unsigned long rasxod = 0; // количество прерываний от расходомера за интервал между измерениями
- //--------------------------------------------------------------------------------------------------------------------------------------------------------
- void flowmeter() { // обработка прерываний от расходомера
- quantity++; // увеличиваем на единицу
- }
- //--------------------------------------------------------------------------------------------------------------------------------------------------------
- void(* resetFunc) (void) = 0; //объявляем функцию reset с адресом 0
- //--------------------------------------------------------------------------------------------------------------------------------------------------------
- void NewLogger(String ADDR, String data) { // процедура записи каждого отдельного сенсора в отдельный файл "АДРЕС_ДАТЧИКА.ТХТ"
- // структура записи: время фиксации измерений от запуска; показания именно этого сенсора температуры; показания сенсора освещённости; расход теплоносителя между замерами; состояние реле насоса (0/1)
- unsigned long Filesize = 0; // размер файла до процедуры записи
- unsigned long Filesize_1 = 0; // размер файла после процедуры записи
- String filename = "LOG/" + ADDR + ".txt"; // будем всё писать в каталог LOG на карте, если много "насрать" к корень диска, то карта долго инициализируется.
- File dataFile = SD.open(filename, FILE_WRITE); // открываем файл на SD-карте для записи
- Filesize = dataFile.size(); // получаем размер файла до записи информации
- dataFile.println(data); // пишем в файл заранее подготовленную строку данных
- Filesize_1 = dataFile.size(); // получаем размер файла после вероятной записи информации
- dataFile.close(); // закрываем файл
- if (Filesize_1 != Filesize) { // если размер файла после операции записи изменился, то значит всё хорошо
- lcd.setCursor(15, 0); // Установка курсора место вывода служебной информации в первой строке
- lcd.print("+"); // выводим на экран условный знак "+"
- Serial.println(" saved successfully"); // диагностическая информация в терминал
- Filesize = Filesize_1; // присваиваем глобальной переменной Filesize новое значение
- Flag_SD = 1;
- return ;
- }
- // если размер после операции записи не изменился, то значит у Хьюстона проблемы
- lcd.setCursor(15, 0); // Установка курсора место вывода служебной информации в первой строке
- lcd.print("-"); // выводим на экран условный знак "-"
- lcd.setCursor(15, 1); // Установка курсора место вывода служебной информации во второй строке
- lcd.print("!"); // выводим на экран условный знак "!"
- Flag_SD = 0;
- return;
- }
- //----------------------------измеряем температуру-------------------
- byte Read_Temp() {
- byte i;
- byte present = 0; // флаг наличия сенсора на шине OneWire
- byte type_s; // тип сенсора
- byte data[12]; // массив для данных сенсора
- byte addr[8]; // массив для адреса сенсора
- float celsius; // переменная для значения температуры
- String string_ADDR = ""; // переменная для значения адреса сенсора
- String string_SD_data = ""; // переменная для аккумулирования данных для записи на SD-карту
- unsigned long time_sensor = 0; // переменная для фиксации времени измерения
- ds.reset(); // сброс на шине, начало обмены информации
- ds.write(0xCC, 1); // всем всем всем
- ds.write(0x44, 1); // команда сенсорам "начать преобразование температуры"
- time_sensor = millis() / 1000; // начинаем формировать строку для записи на карту, пишем время в секундах от начала работы системы и разделитель ";"
- delay(1000); // ждём 1 секунду, чтобы все датчики успели завершить преобразование
- lcd.clear(); // Подготавливаем дисплей для отображения информации о температуре датчиков. Переход на первую строку
- while ( ds.search(addr) != 0) { // читаем данные с шины, пока не закончатся все имеющиеся датчики
- for ( i = 4; i < 8; i++) { // будем читать только последние 4 байт адреса очередного сенсора DS18x20, чтобы не превысить имя файла 8.3
- string_ADDR = string_ADDR + String(addr[i], HEX); // собираем полученные данные в строку для записи имени файла(часть адреса сенсора)
- }
- if (OneWire::crc8(addr, 7) != addr[7]) { // проверяем контрольную сумму считанного адреса сенсора
- string_SD_data = String(time_sensor) + "CRC is not valid! ; "; // если контрольная сумма не совпадает, то сообщаем об этом в логфайл
- return (0); // дальнейшее чтение данных на шине прекращаем, следующий сеанс связи по расписанию
- }
- // если получение адреса сенсора прошло без ошибок, то продолжаем работать дальше
- switch (addr[0]) { // первый байт ROM показывает тип датчика
- case 0x10:
- //Serial.println(" Chip = DS18S20"); // or old DS1820
- type_s = 1;
- break;
- case 0x28:
- //Serial.println(" Chip = DS18B20");
- type_s = 0;
- break;
- case 0x22:
- //Serial.println(" Chip = DS1822");
- type_s = 0;
- break;
- default:
- //Serial.println("Device is not a DS18x20 family device.");
- return (0);
- }
- ds.reset(); // инициализируем шину OneWire
- ds.select(addr); // выбираем текущий сенсор
- ds.write(0xBE); // Читаем Scratchpad
- for ( i = 0; i < 9; i++) { // нам необходимо получить 9 байт
- data[i] = ds.read(); // заполняем массив данными
- }
- int16_t raw = (data[1] << 8) | data[0]; // проводим небольшие вычисления
- if (type_s) {
- raw = raw << 3; // 9 bit resolution default
- if (data[7] == 0x10) {
- // "count remain" gives full 12 bit resolution
- raw = (raw & 0xFFF0) + 12 - data[6];
- }
- } else {
- byte cfg = (data[4] & 0x60);
- // at lower res, the low bits are undefined, so let's zero them
- if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms
- else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
- else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
- // default is 12 bit resolution, 750 ms conversion time
- }
- celsius = (float)raw / 16.0; // и получаем температуру в градусах Цельсия
- string_SD_data = String(time_sensor) + " ; " + String(celsius) + " ; " + String(sun) + " ; " + String(rasxod) + " ; " + String(Flag_nasosa); // добавляем все данные в строку сразу после значений этого сенсора
- NewLogger(string_ADDR, string_SD_data); // отправляем данные записываться на SD-карту
- Serial.print(string_ADDR);
- Serial.print(" ");
- Serial.println(string_SD_data);
- Serial.println();
- string_ADDR = ""; // очищаем строку данных для следующего измерения
- string_SD_data = ""; // очищаем строку данных для следующего измерения
- // вывод информации о значениях температуры всех на LCD дисплей для наглядного отображения
- n++; // следующую позиция на индикаторе
- if (n > 0 && n < 5) {
- switch (n) { // в зависимости от порядкового номера сенсора выводим информацию на LCD дисплей
- case 1:
- lcd.setCursor(0, 0);
- lcd.print("A="); // датчики идентифицируем по буквам алфавита
- lcd.print(celsius);
- break;
- case 2:
- lcd.setCursor(8, 0); // в позицию 8 первой строки
- lcd.print("B=");
- lcd.print(celsius);
- break;
- case 3:
- lcd.setCursor(0, 1); // в позицию начала первой строки
- lcd.print("C=");
- lcd.print(celsius);
- break;
- case 4:
- lcd.setCursor(8, 1); // в позицию 8 второй строки
- lcd.print("D=");
- lcd.print(celsius);
- break;
- }
- if (n == 4) {
- delay(5000);
- lcd.clear();
- }
- }
- if (n > 4 && n < 9) {
- switch (n) { // в зависимости от порядкового номера сенсора выводим информацию на LCD дисплей
- case 5:
- lcd.setCursor(0, 0);
- lcd.print("E="); // датчики идентифицируем по буквам алфавита
- lcd.print(celsius);
- break;
- case 6:
- lcd.setCursor(8, 0); // в позицию 8 первой строки
- lcd.print("F=");
- lcd.print(celsius);
- break;
- case 7:
- lcd.setCursor(0, 1); // в позицию начала первой строки
- lcd.print("G=");
- lcd.print(celsius);
- break;
- case 8:
- lcd.setCursor(8, 1); // в позицию 8 второй строки
- lcd.print("H=");
- lcd.print(celsius);
- break;
- }
- if (n == 8) {
- delay(5000);
- lcd.clear();
- }
- }
- if (n > 8 && n < 13) {
- switch (n) { // в зависимости от порядкового номера сенсора выводим информацию на LCD дисплей
- case 9:
- lcd.setCursor(0, 0);
- lcd.print("I="); // датчики идентифицируем по буквам алфавита
- lcd.print(celsius);
- break;
- case 10:
- lcd.setCursor(8, 0); // в позицию 8 первой строки
- lcd.print("J=");
- lcd.print(celsius);
- break;
- case 11:
- lcd.setCursor(0, 1); // в позицию начала первой строки
- lcd.print("K=");
- lcd.print(celsius);
- break;
- case 12:
- lcd.setCursor(8, 1); // в позицию 8 второй строки
- lcd.print("L=");
- lcd.print(celsius);
- break;
- }
- if (n == 12) {
- delay(5000);
- lcd.clear();
- }
- }
- if (n > 12 && n < 17) {
- switch (n) { // в зависимости от порядкового номера сенсора выводим информацию на LCD дисплей
- case 12:
- lcd.setCursor(0, 0);
- lcd.print("M="); // датчики идентифицируем по буквам алфавита
- lcd.print(celsius);
- break;
- case 14:
- lcd.setCursor(8, 0); // в позицию 8 первой строки
- lcd.print("N=");
- lcd.print(celsius);
- break;
- case 15:
- lcd.setCursor(0, 1); // в позицию начала первой строки
- lcd.print("O=");
- lcd.print(celsius);
- break;
- case 16:
- lcd.setCursor(8, 1); // в позицию 8 второй строки
- lcd.print("P=");
- lcd.print(celsius);
- break;
- }
- if (n == 16) {
- delay(5000);
- lcd.clear();
- }
- }
- if (n > 16 && n < 21) {
- switch (n) { // в зависимости от порядкового номера сенсора выводим информацию на LCD дисплей
- case 17:
- lcd.setCursor(0, 0);
- lcd.print("Q="); // датчики идентифицируем по буквам алфавита
- lcd.print(celsius);
- break;
- case 18:
- lcd.setCursor(8, 0); // в позицию 8 первой строки
- lcd.print("R=");
- lcd.print(celsius);
- break;
- case 19:
- lcd.setCursor(0, 1); // в позицию начала первой строки
- lcd.print("S=");
- lcd.print(celsius);
- break;
- case 20:
- lcd.setCursor(8, 1); // в позицию 8 второй строки
- lcd.print("T=");
- lcd.print(celsius);
- break;
- }
- if (n == 20) {
- delay(5000);
- lcd.clear();
- }
- }
- if (n > 20 && n < 25) {
- switch (n) { // в зависимости от порядкового номера сенсора выводим информацию на LCD дисплей
- case 21:
- lcd.setCursor(0, 0);
- lcd.print("U="); // датчики идентифицируем по буквам алфавита
- lcd.print(celsius);
- break;
- case 22:
- lcd.setCursor(8, 0); // в позицию 8 первой строки
- lcd.print("V=");
- lcd.print(celsius);
- break;
- case 23:
- lcd.setCursor(0, 1); // в позицию начала первой строки
- lcd.print("W=");
- lcd.print(celsius);
- break;
- case 24:
- lcd.setCursor(8, 1); // в позицию 8 второй строки
- lcd.print("X=");
- lcd.print(celsius);
- break;
- }
- if (n == 24) {
- delay(5000);
- lcd.clear();
- }
- }
- if (n > 24 && n < 27) {
- switch (n) { // в зависимости от порядкового номера сенсора выводим информацию на LCD дисплей
- case 25:
- lcd.setCursor(0, 0);
- lcd.print("Y="); // датчики идентифицируем по буквам алфавита
- lcd.print(celsius);
- break;
- case 26:
- lcd.setCursor(8, 0); // в позицию 8 первой строки
- lcd.print("Z=");
- lcd.print(celsius);
- break;
- }
- if (n == 26) {
- delay(5000);
- lcd.clear();
- }
- }
- if (n > 26) {
- lcd.setCursor(0, 0);
- lcd.print("reached the max.");
- lcd.setCursor(0, 1);
- lcd.print("number of sensors");
- delay(5000);
- return (0);
- }
- }
- delay(4000);
- lcd.clear(); // Очистка LCD
- lcd.print("No more sensors");
- delay(2000);
- return (1);
- }
- //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- void setup() {
- pinMode(Relay, OUTPUT); // вывод для управления насосом
- pinMode(3,INPUT); // вход для прерываний от расходомера
- digitalWrite(3,HIGH); // подтягиваем на +5V встроенным резистором 10к
- digitalWrite(Relay, LOW); // инициализируем вывод управления реле насоса
- Serial.begin(9600); // Инициализация терминала для диагностической информации
- lcd.begin(16, 2); // Настройка LCD 2 строки 16 символов
- lcd.clear(); // Очистка LCD
- lcd.print(" DataLogger "); // Вывод строчки на LCD (Название программы)
- Serial.println("Initializing SD card..."); // диагностическая информация в терминал
- lcd.setCursor(0, 1); // Установка курсора в начало второй строки LCD
- lcd.print(" Init SD card..."); // диагностическая информация на LCD
- delay(1000);
- if (!SD.begin(chipSelect)) { // Если SD-карта отсутствует или на может быть инициализирована, то
- Serial.println("Card failed, or not present"); // диагностическая информация в терминал
- lcd.setCursor(0, 1); // Установка курсора в начало второй строки LCD
- lcd.print(" SD card Error "); // диагностическая информация на LCD
- delay(1000);
- return; // программа продолжит работу без SD-карты один цикл измерений и затем перезапустится
- }
- Serial.println("card initialized."); // диагностическая информация в терминал, если инициализация прошла успешно
- lcd.setCursor(0, 1); // Установка курсора в начало второй строки LCD
- lcd.print(" SD card Ok "); // диагностическая информация на LCD
- delay(1000);
- attachInterrupt(1, flowmeter, FALLING); // назначим прерывание INT1 для расходомера
- }
- //-------------------------------------------------------------------------------------------------------------------------------------------
- //------------------------------------ сенсор освещённости ---------------------------------------------------------------------------------
- void Sun_sensor() { // вычисляем количество солнечного света для включения насоса и оценки работы солнечного коллектора
- sun = (1023 - analogRead(A1)) / 10.00; // читаем аналоговый порт А1 данные о текущей освещённости
- return;
- }
- //------------------------------------------------------------------------------------------------------------------------------------------
- void loop() {
- Sun_sensor(); // регулярно проверяем освещённость для оперативного управления насосом
- if (sun > sunrise) {
- digitalWrite(Relay, HIGH); // если Солнце встало, то включаем насос
- Flag_nasosa = 1;
- }
- else {
- digitalWrite(Relay, LOW); // если Солнца нет, то насос выключаем
- // возвращаемся обратно
- Flag_nasosa = 0;
- }
- //-------------------------------------------------------------------------------------------------------------------------------------------
- if (((millis() - oldmillis) / 1000 > interval) || (Flag_SD == 0)) { // попадаем сюда только после таймера задержки или в первый раз после перезагрузки
- rasxod = quantity - oldquantity; // проверяем, сколько там воды утекло с момента прошлого измерения
- oldquantity = quantity; // нарекаем момент старого измерения новым измерением
- n = 0; // страница для вывода на индикаторе в начало
- Read_Temp(); // читаем температуру с сенсоров DS18x20 и записываем в лог файл
- if (Flag_SD == 0) { // если один цикл измерений и записи прошёл с ошибкой, то ребутим систему
- lcd.setCursor(0, 1); // позиция во второй строке
- lcd.print(" system reset "); // информационное сообщение на LCD дисплее
- delay(5000); // задержка, чтобы пользователь заметил
- resetFunc(); // вызываем reset
- }
- oldmillis = millis(); // если всё нормально, то сбрасываем таймер
- }
- else {
- lcd.setCursor(0, 0); // Установка курсора в начало первой строки LCD
- lcd.print("Waiting.... "); // информационное сообщение на LCD дисплее
- lcd.setCursor(0, 1); // Установка курсора в начало второй строки LCD
- lcd.print(" voda="); // информационное сообщение на LCD дисплее
- lcd.print(quantity); // Индикация работы расходомера
- lcd.setCursor(0, 1); // Установка курсора в начало второй строки LCD
- lcd.print( interval - (millis() - oldmillis) / 1000); // информационное сообщение на LCD дисплее
- delay(500); // замедляем частоту обновления информации об оставшемся времени
- lcd.print(" "); // аккуратненько подчищаем, для исключения наложения цифр
- }
- //----------------------------------------------------------------------------------------------------------------------------------------
- // key = read_buttons(); // Считывание значения кнопки
- // unsigned int bri = Do_Key(key);
- // analogWrite(10, bri / 256); //изменить значение яркости подсветки
- // analogWrite(10, bri); //изменить значение яркости подсветки
- // lcd.setCursor(8, 1);
- // lcd.print(bri / 256); //отобразить текущую яркость на LCD
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement