411 lines
13 KiB
C++
411 lines
13 KiB
C++
#include <Adafruit_GFX.h>
|
||
#include <Adafruit_SSD1306.h>
|
||
#include <Wire.h>
|
||
#include <OneWire.h>
|
||
#include <DallasTemperature.h>
|
||
#include "button.h"
|
||
#include "variables.h"
|
||
#include <EEPROM.h>
|
||
#include "i18n.h"
|
||
|
||
// Для руссификации, нужно glcdfont.c поместить в C:\Users\USER\Documents\Arduino\libraries\Adafruit_GFX_Library. У вас путь до библиотеки может отличаться.
|
||
// Конвертор из UTF-8 в бинарную строку здесь: https://грибовы.рф/rusifikaciya-displeya-ssd1306/
|
||
|
||
i18n __lang(1); // 0 - английский язык, 1 - русский язык
|
||
|
||
Adafruit_SSD1306 display = Adafruit_SSD1306(128, 64, &Wire);
|
||
#define ONE_WIRE_BUS 2
|
||
OneWire oneWire(ONE_WIRE_BUS);
|
||
DallasTemperature sensors(&oneWire);
|
||
button btn1(4); // указываем пин кнопки 1
|
||
button btn2(5); // указываем пин кнопки 2
|
||
int piezoPin = 3; // пин бипера
|
||
int LightPin = A2; // пин подсветки кнопок
|
||
|
||
// Вольтметр
|
||
const int analogInput PROGMEM = A0; // Аналоговый порт куда подключается выход с делителя напряжения
|
||
const double inaccuracy PROGMEM = 0.5;
|
||
const float R1 PROGMEM= 10000.0; // Сопротивление R1 (10K) в ОМАХ
|
||
const float R2 PROGMEM = 2000.0; // Сопротивление R2 (2K)в ОМАХ
|
||
float vout = 0.0;
|
||
float vin = 0.0;
|
||
int value = 0;
|
||
|
||
// моточасы по умолчанию
|
||
struct SavedData {
|
||
byte beeper=0; // 1 - звук кнопок есть, 0 - нет
|
||
byte light=0; // 1 - подсветка кнопок есть, 0 - нет
|
||
int motoclock_motor=13200; // замена масла двигателя
|
||
int motoclock_kpp=26000; // замена масла МКПП
|
||
long motoclock_most=79200; // замена масла мосты
|
||
long motoclock_grm=79200; // замена ремня грм
|
||
};
|
||
SavedData ee_data; // данные с нестираемой памяти
|
||
SavedData etalon; // данные по умолчанию
|
||
|
||
long old_milis,old_milis_2;
|
||
byte layout=0; // текущий экран 0 - температура, 1 - моточасы
|
||
float celsius1,celsius2,celsius3;
|
||
|
||
extern int __bss_end;
|
||
extern void *__brkval;
|
||
|
||
void setup() {
|
||
Serial.begin(9600);
|
||
|
||
// инициализирую дисплей
|
||
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
|
||
display.cp437(true);
|
||
display.clearDisplay();
|
||
display.drawBitmap(0, 0, fxf, 128, 64, WHITE);
|
||
display.display();
|
||
|
||
// инициализация ног
|
||
pinMode(piezoPin, OUTPUT);
|
||
pinMode(analogInput, INPUT);
|
||
pinMode(LightPin, OUTPUT);
|
||
|
||
ee_data.beeper=1;
|
||
beep(ee_data.beeper,piezoPin);delay(1000);beep(ee_data.beeper,piezoPin); // два бипа - успешно включились
|
||
|
||
// читаем данные из энергонезависимой памяти
|
||
EEPROM.get(2,ee_data);
|
||
if (ee_data.beeper>0){ee_data.beeper=1;};
|
||
|
||
// если данных нет, то ставим их "по умолчанию"
|
||
if ((ee_data.motoclock_motor<0) or (ee_data.motoclock_kpp<0) or (ee_data.motoclock_most<0) or (ee_data.motoclock_grm<0)){
|
||
ee_data=etalon;
|
||
};
|
||
|
||
// включаем подсветку кнопок если нужно
|
||
if (ee_data.light==1){digitalWrite(LightPin, HIGH);} else {digitalWrite(LightPin, LOW);};
|
||
|
||
old_milis=millis(); // засекаем время начало работы адулины
|
||
old_milis_2=millis(); // засекаем время начало работы адулины
|
||
|
||
display.clearDisplay();
|
||
LayoutScreen(true,0); // Показываем основной экран
|
||
|
||
//ee_data.motoclock_motor=9;
|
||
}
|
||
|
||
int memoryFree(){
|
||
int freeValue;
|
||
if((int)__brkval == 0)
|
||
freeValue = ((int)&freeValue) - ((int)&__bss_end);
|
||
else
|
||
freeValue = ((int)&freeValue) - ((int)__brkval);
|
||
return freeValue;
|
||
}
|
||
|
||
// звуковой сигнал по нажатию кнопки
|
||
void beep(bool beeper,int piezoPin){
|
||
if (beeper==1) {
|
||
for (int i=0; i <= 100; i++){
|
||
digitalWrite(piezoPin, HIGH);
|
||
delay(1);
|
||
digitalWrite(piezoPin, LOW);
|
||
delay(1);
|
||
}
|
||
} else {
|
||
delay(500);
|
||
}
|
||
}
|
||
|
||
// отобразить текущий экран
|
||
// refresh true/false - стереть всё предварительно
|
||
// lay - экран. 0 - температура, 1 - моточасы
|
||
void LayoutScreen(boolean refresh,byte lay){
|
||
if (refresh==true){
|
||
display.clearDisplay();
|
||
display.drawBitmap(65, 32, fxf3, 59, 32, WHITE);
|
||
};
|
||
if (lay==0){
|
||
display.setTextColor(WHITE, BLACK);
|
||
// улица
|
||
display.setTextSize(2);
|
||
display.setCursor(50, 1);
|
||
//display.print(F("Street:"));
|
||
display.print(celsius1);display.print("c");
|
||
// салон
|
||
display.setTextSize(1);
|
||
display.setCursor(4, 1);
|
||
//display.print(F("Int:"));
|
||
display.print(celsius2);display.print("c");
|
||
// двигатель
|
||
display.drawBitmap(1, 22, ico_dvig, 16, 16, WHITE);
|
||
display.setCursor(20, 26);
|
||
display.print(celsius3);display.print("c");
|
||
// батарея
|
||
display.drawBitmap(1, 42, ico_bat, 16, 16, WHITE);
|
||
display.setCursor(20, 46);
|
||
display.print(vin);display.print("v");
|
||
|
||
display.display();
|
||
|
||
} else {
|
||
display.setTextColor(WHITE, BLACK);
|
||
display.setCursor(1, 1);
|
||
display.print(__lang.translate(F("Motoclock:")));display.print(ee_data.motoclock_motor/60);display.print(__lang.translate(F("h")));
|
||
display.setCursor(1, 10);
|
||
display.print(__lang.translate(F("Transmission:")));display.print(ee_data.motoclock_kpp/60);display.print(__lang.translate(F("h")));
|
||
display.setCursor(1, 20);
|
||
display.print(__lang.translate(F("Bridge:")));display.print(ee_data.motoclock_most/60);display.print(__lang.translate(F("h")));
|
||
display.setCursor(1, 30);
|
||
display.print(__lang.translate(F("GRM ribbon:")));display.print(ee_data.motoclock_grm/60);display.print(__lang.translate(F("h")));
|
||
|
||
display.display();
|
||
};
|
||
}
|
||
void PutStringMenu(int curpoz,int cursor,String myPointer){
|
||
if (curpoz==cursor){
|
||
display.print("> ");
|
||
};
|
||
display.println(myPointer);
|
||
};
|
||
|
||
void PutCharMenu(int curpoz,int cursor,char *myPointer, int length){
|
||
if (curpoz==cursor){
|
||
display.print("> ");
|
||
};
|
||
for (byte i = 0; i < length; i++) {
|
||
display.print(*(myPointer + i));
|
||
};
|
||
display.println();
|
||
|
||
};
|
||
void PutYouSure(int poz){
|
||
display.clearDisplay();
|
||
display.setCursor(1, 1);
|
||
display.println("You sure?");
|
||
display.setCursor(1, 15);
|
||
|
||
PutCharMenu(1,poz,"No",2); // Нет
|
||
PutCharMenu(2,poz,"Yes",3); // Да
|
||
|
||
display.display();
|
||
}
|
||
int AreYouSure(){
|
||
int poz=1;
|
||
PutYouSure(poz);
|
||
while(true){
|
||
if (btn1.click()) {
|
||
beep(ee_data.beeper,piezoPin);
|
||
poz=poz+1;
|
||
if (poz>=3){
|
||
poz=1;
|
||
};
|
||
PutYouSure(poz);
|
||
};
|
||
if (btn2.click()) {
|
||
return poz;
|
||
};
|
||
|
||
};
|
||
}
|
||
void ClearedTxt(){
|
||
display.clearDisplay();
|
||
display.setCursor(1, 20);
|
||
display.println(F("Cleared"));
|
||
display.display();
|
||
delay(1000);
|
||
};
|
||
void VerifyAllMoto(){
|
||
if ((ee_data.motoclock_motor<10) or (ee_data.motoclock_kpp<10) or (ee_data.motoclock_most<10) or (ee_data.motoclock_grm<10)){
|
||
display.clearDisplay();
|
||
display.setCursor(1, 0);
|
||
display.println(F("Its time to:"));
|
||
if (ee_data.motoclock_motor<10){
|
||
display.println(F("-Replace engine oil"));
|
||
};
|
||
if (ee_data.motoclock_kpp<10){
|
||
display.println(F("-Replace kpp oil"));
|
||
};
|
||
if (ee_data.motoclock_most<10){
|
||
display.println(F("-Replace brige oil"));
|
||
};
|
||
if (ee_data.motoclock_grm<10){
|
||
display.println(F("-Replace grm"));
|
||
};
|
||
display.display();
|
||
beep(ee_data.beeper,piezoPin);delay(1000);beep(ee_data.beeper,piezoPin);
|
||
beep(ee_data.beeper,piezoPin);delay(1000);beep(ee_data.beeper,piezoPin);
|
||
LayoutScreen(true,layout);
|
||
};
|
||
};
|
||
void PutMotoMenu(int poz){
|
||
display.clearDisplay();
|
||
display.setCursor(1, 1);
|
||
PutStringMenu(1,poz,F("Engine oil")); // Масло двигателя
|
||
PutStringMenu(2,poz,F("Gear oil")); // Масло в КПП
|
||
PutStringMenu(3,poz,F("Bridge oil")); // Масло в мостах
|
||
PutStringMenu(4,poz,F("Ribbon")); // ремень ГРМ
|
||
PutStringMenu(5,poz,F("Exit"));
|
||
display.display();
|
||
}
|
||
void SaveData(){
|
||
EEPROM.put(2,ee_data);
|
||
}
|
||
void MenuMoto(){
|
||
int poz=1;
|
||
PutMotoMenu(poz);
|
||
while(true){
|
||
if (btn1.click()) {
|
||
poz=poz+1;
|
||
if (poz>=6){
|
||
poz=1;
|
||
};
|
||
PutMotoMenu(poz);
|
||
beep(ee_data.beeper,piezoPin);
|
||
};
|
||
if (btn2.click()) {
|
||
// сброс моточасы масло двигателя
|
||
if (poz==1){
|
||
int sure=AreYouSure();
|
||
if (sure==2){
|
||
ee_data.motoclock_motor=etalon.motoclock_motor;
|
||
SaveData();
|
||
ClearedTxt();
|
||
};
|
||
};
|
||
// сброс моточасы масло кпп
|
||
if (poz==2){
|
||
int sure=AreYouSure();
|
||
if (sure==2){
|
||
ee_data.motoclock_kpp=etalon.motoclock_kpp;
|
||
SaveData();
|
||
ClearedTxt();
|
||
};
|
||
};
|
||
// сброс моточасы масло мосты
|
||
if (poz==3){
|
||
int sure=AreYouSure();
|
||
if (sure==2){
|
||
ee_data.motoclock_most=etalon.motoclock_most;
|
||
SaveData();
|
||
ClearedTxt();
|
||
};
|
||
};
|
||
// сброс моточасы ремень ГРМ
|
||
if (poz==4){
|
||
int sure=AreYouSure();
|
||
if (sure==2){
|
||
ee_data.motoclock_grm=etalon.motoclock_grm;
|
||
SaveData();
|
||
ClearedTxt();
|
||
};
|
||
};
|
||
if (poz==5){
|
||
return 0;
|
||
}
|
||
PutMotoMenu(poz);
|
||
beep(ee_data.beeper,piezoPin);
|
||
};
|
||
};
|
||
};
|
||
void PutMainMenu(int poz){
|
||
display.clearDisplay();
|
||
display.setCursor(1, 1);
|
||
PutStringMenu(1,poz,F("Motoclock"));
|
||
if (ee_data.beeper==1){
|
||
PutStringMenu(2,poz,F("Sound: Yes"));
|
||
} else {
|
||
PutStringMenu(2,poz,F("Sound: No"));
|
||
};
|
||
if (ee_data.light==1){
|
||
PutStringMenu(3,poz,F("Light: Yes"));
|
||
ee_data.light=1;
|
||
} else {
|
||
PutStringMenu(3,poz,F("Light: No"));
|
||
ee_data.light=0;
|
||
};
|
||
PutStringMenu(4,poz,F("Exit"));
|
||
display.display();
|
||
}
|
||
void MainMenu(){
|
||
int poz=1;
|
||
PutMainMenu(poz);
|
||
while(true){
|
||
if (btn1.click()) {
|
||
poz=poz+1;
|
||
if (poz>=5){
|
||
poz=1;
|
||
};
|
||
PutMainMenu(poz);
|
||
beep(ee_data.beeper,piezoPin);
|
||
};
|
||
if (btn2.click()) {
|
||
// сброс моточасов
|
||
if (poz==1){
|
||
MenuMoto();
|
||
PutMainMenu(poz);
|
||
};
|
||
// Звук кнопок
|
||
if (poz==2){
|
||
if (ee_data.beeper==1){
|
||
ee_data.beeper=0;
|
||
} else {
|
||
ee_data.beeper=1;
|
||
};
|
||
SaveData();
|
||
PutMainMenu(poz);
|
||
};
|
||
// подсветка кнопок
|
||
if (poz==3){
|
||
if (ee_data.light==1){
|
||
ee_data.light=0;
|
||
digitalWrite(LightPin, LOW);
|
||
} else {
|
||
ee_data.light=1;
|
||
digitalWrite(LightPin, HIGH);
|
||
};
|
||
SaveData();
|
||
PutMainMenu(poz);
|
||
};
|
||
if (poz==4){ // Exit
|
||
return 0;
|
||
};
|
||
beep(ee_data.beeper,piezoPin);
|
||
};
|
||
};
|
||
}
|
||
void GetDataSensors(){
|
||
// читаем показания датчиков температуры
|
||
sensors.requestTemperatures();
|
||
celsius1=sensors.getTempCByIndex(0); if (celsius1<-120){celsius1=0;};
|
||
celsius2=sensors.getTempCByIndex(1); if (celsius2<-120){celsius2=0;};
|
||
celsius3=sensors.getTempCByIndex(2); if (celsius3<-120){celsius3=0;};
|
||
// читаем показания вольтметра
|
||
value = analogRead(analogInput);
|
||
vout = (value * 5.0) / 1024.0;
|
||
vin = vout / (R2/(R1+R2))-inaccuracy;
|
||
old_milis_2=millis();
|
||
};
|
||
void loop() {
|
||
if (millis()-old_milis_2>1000){ // раз в секунду читаем показания
|
||
GetDataSensors();
|
||
LayoutScreen(false,layout);
|
||
Serial.println(memoryFree());
|
||
};
|
||
if (millis()-old_milis>60000){
|
||
old_milis=millis();
|
||
Serial.println(F("Timer! save to eerom"));
|
||
if (ee_data.motoclock_motor>0){ee_data.motoclock_motor=ee_data.motoclock_motor-1;};
|
||
if (ee_data.motoclock_kpp>0){ee_data.motoclock_kpp=ee_data.motoclock_kpp-1;};
|
||
if (ee_data.motoclock_most>0){ee_data.motoclock_most=ee_data.motoclock_most-1;};
|
||
if (ee_data.motoclock_grm>0){ee_data.motoclock_grm=ee_data.motoclock_grm-1;};
|
||
SaveData();
|
||
VerifyAllMoto();
|
||
}
|
||
if (btn1.click()) {
|
||
MainMenu();
|
||
LayoutScreen(true,layout);
|
||
};
|
||
if (btn2.click()) {
|
||
layout=layout+1;
|
||
if (layout>1){layout=0;};
|
||
LayoutScreen(true,layout);
|
||
beep(ee_data.beeper,piezoPin);
|
||
};
|
||
};
|