Приветствую тебя дорогой мой друг. Если ты здесь, то скорее всего ты уже прочитал предыдущие статьи связанные с нашим логгером, иначе ты просто не поймешь, что здесь происходит. Ну, а если ты случайно сюда забрёл, советую прочитать тебе изначально статьи:
- Логгер для 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), если у нас будет взаимное понимание, то можно будет реализовать пожелания!