Найти в Дзене
Рагозин Николай

Код на C++ для логгера Cyber Hen DA&S

Приветствую тебя дорогой мой друг. Если ты здесь, то скорее всего ты уже прочитал предыдущие статьи связанные с нашим логгером, иначе ты просто не поймешь, что здесь происходит. Ну, а если ты случайно сюда забрёл, советую прочитать тебе изначально статьи: - Логгер для Cyber Hen DA&S, для чего я его создаю, компоненты для прототипа - Схема подключения компонентов логгера для Cyber Hen DA&S 1. Тебе самому нужно будет запрограммировать модуль RTC. В данном коде отсутствует данная функция. Это сделать не так уж и сложно. Благодаря великому и могучему интернету это сделать будет не сложно. Либо я напишу статью, со своими кодами, для программирования RTC (на данный момент коды не оттестированы, так, что вы это делаете на свой страх и риск, хотя это громко сказано. Можете чуть подождать, я обязательно оттестирую на микроконтроллерах, только мне нужно будет прикупить ещё модулей) 2. В данном коде только программно, (в самом коде) можно установить временной интервал для снятия показаний. По умо
Оглавление

Приветствую тебя дорогой мой друг. Если ты здесь, то скорее всего ты уже прочитал предыдущие статьи связанные с нашим логгером, иначе ты просто не поймешь, что здесь происходит. Ну, а если ты случайно сюда забрёл, советую прочитать тебе изначально статьи:

- Логгер для Cyber Hen DA&S, для чего я его создаю, компоненты для прототипа

- Схема подключения компонентов логгера для Cyber Hen DA&S

Итак, поехали. В открытом доступе я выложу рабочий код для нашего логгера. Но будут нюансы.

1. Тебе самому нужно будет запрограммировать модуль RTC. В данном коде отсутствует данная функция. Это сделать не так уж и сложно. Благодаря великому и могучему интернету это сделать будет не сложно. Либо я напишу статью, со своими кодами, для программирования RTC (на данный момент коды не оттестированы, так, что вы это делаете на свой страх и риск, хотя это громко сказано. Можете чуть подождать, я обязательно оттестирую на микроконтроллерах, только мне нужно будет прикупить ещё модулей)

2. В данном коде только программно, (в самом коде) можно установить временной интервал для снятия показаний. По умолчанию он стоит 1 минута.

const unsigned long logInterval = 60000;    // 1 минута (60000 мс)

3. Отсутствует всякая калибровка датчика. Т.е. показания датчика записываются как есть, что показывает датчик, то и пишется на карту памяти.

Код логгера Cyber Hen DA&S V.1:

#include <OneWire.h>
#include <DallasTemperature.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <RTClib.h>
#include <SD.h>
// Пины
#define ONE_WIRE_BUS 7       // Датчик DS18B20 на D7
#define SD_CS 10             // SD-модуль (CS на D10)
#define BUTTON_UP 2          // Кнопка 1 (D2)
#define BUTTON_DOWN 3        // Кнопка 2 (D3)
#define BUTTON_SELECT 4      // Кнопка 3 (D4)
#define BUTTON_BACK 5        // Кнопка 4 (D5)
// Инициализация компонентов
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
LiquidCrystal_I2C lcd(0x27, 20, 4); // Адрес I2C: 0x27 или 0x3F
RTC_DS3231 rtc;
File dataFile;
// Переменные
float currentTemp = 0.0;
float prevTemp = 0.0;
bool isLogging = true;
unsigned long lastLogTime = 0;
unsigned long lastTempUpdate = 0;
const unsigned long logInterval = 60000;    // 1 минута (60000 мс)
const unsigned long tempUpdateInterval = 5000; // 5 секунд (5000 мс)
void setup() {
Serial.begin(9600);
// Инициализация LCD
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Initializing...");
// Инициализация датчика температуры
sensors.begin();
// Инициализация RTC
if (!rtc.begin()) {
lcd.setCursor(0, 1);
lcd.print("RTC Error!");
while (1);
}
// Инициализация SD-карты
if (!SD.begin(SD_CS)) {
lcd.setCursor(0, 1);
lcd.print("SD Card Error!");
while (1);
}
// Настройка кнопок
pinMode(BUTTON_UP, INPUT_PULLUP);
pinMode(BUTTON_DOWN, INPUT_PULLUP);
pinMode(BUTTON_SELECT, INPUT_PULLUP);
pinMode(BUTTON_BACK, INPUT_PULLUP);
lcd.clear();
}
void loop() {
DateTime now = rtc.now();
unsigned long currentMillis = millis();
// Обновление температуры каждые 5 секунд
if (currentMillis - lastTempUpdate >= tempUpdateInterval) {
sensors.requestTemperatures();
currentTemp = sensors.getTempCByIndex(0);
lastTempUpdate = currentMillis;
}
// Обновление времени на LCD каждую секунду
updateTimeDisplay(now);
// Логирование на SD-карту (если разрешено и прошла минута)
if (isLogging && currentMillis - lastLogTime >= logInterval) {
logData(now);
prevTemp = currentTemp;
lastLogTime = currentMillis;
}
// Проверка кнопок
checkButtons();
delay(100); // Небольшая задержка для стабильности
}
// Обновление времени на LCD (вызывается в каждом цикле)
void updateTimeDisplay(DateTime now) {
// Первая строка - дата
lcd.setCursor(0, 0);
lcd.print("Date: ");
print2Digits(now.day());
lcd.print("/");
print2Digits(now.month());
lcd.print("/");
lcd.print(now.year());
// Вторая строка - время (обновляется постоянно)
lcd.setCursor(0, 1);
lcd.print("Time: ");
print2Digits(now.hour());
lcd.print(":");
print2Digits(now.minute());
lcd.print(":");
print2Digits(now.second());
lcd.print("   "); // Очистка оставшихся символов
// Третья строка - текущая температура (обновляется каждые 5 сек)
lcd.setCursor(0, 2);
lcd.print("Temp: ");
lcd.print(currentTemp, 1);
lcd.print(" C    ");
// Четвертая строка - предыдущая температура
lcd.setCursor(0, 3);
lcd.print("Prev: ");
lcd.print(prevTemp, 1);
lcd.print(" C    ");
}
// Вспомогательная функция для вывода двузначных чисел
void print2Digits(int number) {
if (number < 10) {
lcd.print("0");
}
lcd.print(number);
}
// Запись данных на SD-карту
void logData(DateTime now) {
dataFile = SD.open("temp1.txt", FILE_WRITE);
if (dataFile) {
print2DigitsToFile(now.hour());
dataFile.print(":");
print2DigitsToFile(now.minute());
dataFile.print(":");
print2DigitsToFile(now.second());
dataFile.print(" - ");
print2DigitsToFile(now.day());
dataFile.print("/");
print2DigitsToFile(now.month());
dataFile.print("/");
dataFile.print(now.year());
dataFile.print(" - Temp: ");
dataFile.print(currentTemp, 1);
dataFile.println(" C");
dataFile.close();
} else {
lcd.setCursor(0, 3);
lcd.print("SD Write Error!");
delay(1000);
}
}
// Вспомогательная функция для записи двузначных чисел в файл
void print2DigitsToFile(int number) {
if (number < 10) {
dataFile.print("0");
}
dataFile.print(number);
}
// Проверка кнопок
void checkButtons() {
if (digitalRead(BUTTON_SELECT) == LOW) { // Кнопка 3 (SELECT)
delay(200); // Дебаунс
showStopLoggingMenu();
}
}
// Меню остановки записи
void showStopLoggingMenu() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Stop logging?");
lcd.setCursor(0, 1);
lcd.print("1:Yes  2:No");
lcd.setCursor(0, 2);
lcd.print("3:Confirm");
lcd.setCursor(0, 3);
lcd.print("4:Cancel");
bool choiceMade = false;
bool choice = false;
while (!choiceMade) {
if (digitalRead(BUTTON_UP) == LOW) { // Кнопка 1 (YES)
delay(200);
choice = true;
lcd.setCursor(0, 1);
lcd.print("1:>Yes< 2:No ");
}
else if (digitalRead(BUTTON_DOWN) == LOW) { // Кнопка 2 (NO)
delay(200);
choice = false;
lcd.setCursor(0, 1);
lcd.print("1:Yes  2:>No< ");
}
else if (digitalRead(BUTTON_SELECT) == LOW) { // Кнопка 3 (CONFIRM)
delay(200);
if (choice) {
isLogging = false;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Logging STOPPED");
} else {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Logging continues");
}
delay(1000);
choiceMade = true;
}
else if (digitalRead(BUTTON_BACK) == LOW) { // Кнопка 4 (CANCEL)
delay(200);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Cancelled");
delay(1000);
choiceMade = true;
}
}
lcd.clear();
}

Вот такой код я предлагаю вашему вниманию. Это вполне рабочий код, но не забывает про прошивку RTC, форматирование карты памяти в FAT32.

В закрытом доступе будет более продвинутый код:

1. Функция калибровки температурного датчика.

2. Функция установки реального времени при загрузке скетча.

На данный момент, это те функции, которые оттестированы, и проходят уже полевые испытания.

Если вам нужен полный код, либо есть желания, чтобы в данный код были внесены изменения/дополнения, можете мне писать на почту (nickredflag@yandex.ru), если у нас будет взаимное понимание, то можно будет реализовать пожелания!