Потихоньку переписываю древний проект по поливу огурцов в определенные дни и время. С отображение информации на графическом экране вопросов нет, с логикой тоже все норм. Задался вопросом отображением информации необходимого параметра (например текущего времени или выбора дня полива) в режиме настройки.
Т е будет две кнопки, одна выбирает что меняется, этот элемент начинает мигать, второй кнопкой меняется значение, получается подобие многоуровнего меню.
Думал просто функциями, получется нагромождение case/if . Думал запихнуть все это в классы, но совсем не соображу иерархию всего этого.
Это делается интерфейсами.
Т.е. делается базовый класс “редактируемое значение”. В базовом классе есть базовые функции типа: “показать текущее значение”, “обработать нажатие кнопки “вверх””, “обработать нажатие кнопки “вниз””, "обработать нажатие “средней кнопки” и т.п.
Затем все редактируемые параметры оформляются классами, производными от базового.
Основная программа знает какой из параметров сейчас “активен” и когда начинается редактирование, просто вызывает методы базового класса в контексте данного параметра, т.е. она по большому счёту и не знает, что на самом деле редактирует.
Если надо, я могу придумать небольшой пример подобной организации. Только, чтобы от этого была польза, скажите, что у Вас есть, чтобы я сделал пример на таком же железе, чтобы Вы могли легко запустить у себя и посмотреть. Ну или можно сделать на мониторе порта, в принципе - не так красиво будет, но разобраться можно. А так, у меня есть 16х2, 20х4, дисплейчик от Nokia, может ещё чего, смотреть надо).
Точно будет интересно
когда допишу (ближе к осени) выложу.
to ЕвгенийП, спасибо! Пошел изучать…
нет пока ничего, программа на STM32CubeIDE, которая тупо что то отображает, но буду конечно все переписывать, вопросы будут - задам, спасибо!
Прооосим, прооосим, прооосим, прооосим…
Делаешь полностью независимый обработчик клавиатуры, который пережевывает все отскоки, двойные нажатия, и подобные вещи и выдает четкие коды значимых для тебя событий и ничего лишнего.
Делаешь виртуальный класс с методом, принимающим код события.
От него наследуешь все свои элементы и в каждом пишешь свою логику обработки клавиш через switch.
Делать кучу разных обработчиков на каждый чих это лишние буквы и в таких простых меню не нужно.
Что то получается в первом приближении:
Спойлер
class ifaceItem { // интерфейс элемента внутри группы, например текущий день недели, или часы полива
private:
protected:
ifaceItem * parentItem;
unsigned short countChildren = 0;
ifaceItem * childItems[32];
unsigned char fontSize;
unsigned long blinkTimer;
unsigned char modeShow = 0; // режим отображения 0-показывается 1-нет 2-моргает
public:
unsigned short posX, posY, sizeX, sizeY, backgroundColor = 0x0000;
unsigned short iX, iY, itemColor = 0x0000;
void addChild(ifaceItem * newChild) {this->childItems[this->countChildren] = newChild; ++this->countChildren;}
ifaceItem * getChild(unsigned char posChild) {return this->childItems[posChild];}
unsigned char getCountChildren(void) {return this->countChildren;}
virtual void showItem(void){}; // отобразить элемент
virtual void changeValue() {}; // изменить значение элемента
virtual void blinkItem() {}; // мигает позиция
virtual ~ifaceItem(void) {} // деструктор
};
class baseUnit:public ifaceItem { // группа
private:
protected:
public:
baseUnit(ifaceItem * itemParent = nullptr, unsigned short pX = 0, unsigned short pY = 0, unsigned short sX = 32, unsigned short sY = 64, unsigned short bColor = 0x00);
virtual void showItem(void) override;
virtual ~baseUnit(void) {}; // деструктор
};
class baseDayOfWeekCurrentDateTime:public ifaceItem { // элемент день денели текстом выводится
private:
unsigned char * textWDay[8] = {(unsigned char *)"Sunday", (unsigned char *)"Monday", (unsigned char *)"Tuesday", (unsigned char *)"Wednesday", (unsigned char *)"Thursday", (unsigned char *)"Friday", (unsigned char *)"Saturday", (unsigned char *)"Sunday"};
unsigned char currentDayOfWeek = 0;
protected:
public:
baseDayOfWeekCurrentDateTime(ifaceItem * itemParent = nullptr, unsigned short pX = 0, unsigned short pY = 0, unsigned iSize = 0, unsigned short iColor = 0x00);
virtual void showItem(void) override;
virtual ~baseDayOfWeekCurrentDateTime(void) {}; // деструктор
};
baseUnit::baseUnit(ifaceItem * itemParent, unsigned short pX, unsigned short pY, unsigned short sX, unsigned short sY, unsigned short bColor) {
this->countChildren = 0;
this->parentItem = itemParent;
if (itemParent != nullptr) {
this->posX = pX;
this->posY = pY;
this->sizeX = sX;
this->sizeY = sY;
this->backgroundColor = bColor;
this->modeShow = 0;
}
}
void baseUnit::showItem(void) {
f103st7735fillRect(this->backgroundColor, this->posX, this->posY, this->sizeX-1, this->sizeY-1);
}
baseDayOfWeekCurrentDateTime::baseDayOfWeekCurrentDateTime(ifaceItem * itemParent, unsigned short pX, unsigned short pY, unsigned iSize, unsigned short iColor) {
this->countChildren = 0;
this->parentItem = itemParent;
this->iX = pX;
this->iY = pY;
this->itemColor = iColor;
this->modeShow = 0;
}
void baseDayOfWeekCurrentDateTime::showItem(void) {
f103st7735printString((unsigned char *)this->textWDay[this->currentDayOfWeek], this->itemColor, this->parentItem->backgroundColor, this->fontSize, this->iX+this->parentItem->posX, this->iY+this->parentItem->posY);
}
baseUnit iMainDisplay;
baseUnit iCurrentDateTime((ifaceItem *)&iMainDisplay, 0, 0,
st7735sizeX, fontSizeY[currentWDaySize]+fontSizeY[currentDateSize]+fontSizeY[currentTimeSize], currentWDayBack);
baseUnit iPumperDaysTime((ifaceItem *)&iMainDisplay, 0, fontSizeY[currentWDaySize]+fontSizeY[currentDateSize]+fontSizeY[currentTimeSize],
st7735sizeX, fontSizeY[currentWDaySize]+fontSizeY[currentDateSize]+fontSizeY[currentTimeSize]+fontSizeY[pumpDaysSize]*2+fontSizeY[pumpTimeSize]+fontSizeY[0]*2,
pumpBackground);
baseUnit iPeriodTime((ifaceItem *)&iMainDisplay, 0, fontSizeY[currentWDaySize]+fontSizeY[currentDateSize]+fontSizeY[currentTimeSize]+fontSizeY[pumpDaysSize]*2+fontSizeY[pumpTimeSize]+fontSizeY[0]*2,
st7735sizeX, fontSizeY[currentWDaySize]+fontSizeY[currentDateSize]+fontSizeY[currentTimeSize]+fontSizeY[pumpDaysSize]*2+fontSizeY[pumpTimeSize]+fontSizeY[0]*2+fontSizeY[pumpPeriodSize]+fontSizeY[0]*2,
pumpPeriodBack);
baseDayOfWeekCurrentDateTime iDayOfWeekCurrentDateTime((ifaceItem *)&iCurrentDateTime, 0, 0, currentWDaySize, currentWDayColor);
void initPumper(void) {
iMainDisplay.addChild((ifaceItem *)&iCurrentDateTime);
iCurrentDateTime.showItem();
iMainDisplay.addChild((ifaceItem *)&iPumperDaysTime);
iPumperDaysTime.showItem();
iMainDisplay.addChild((ifaceItem *)&iPeriodTime);
iPeriodTime.showItem();
//--current date time
iCurrentDateTime.addChild((ifaceItem *)&iDayOfWeekCurrentDateTime);
iDayOfWeekCurrentDateTime.showItem();
}
Спасибо! за пинок в правильном направлении, все прекрасно выбирается/мигает/настройки меняются, все красиво!
Спойлер
/*
* pumper.h
*
* Created on: 13 июн. 2023 г.
* Author: seleznev_a
*/
#ifndef PUMPER_H_
#define PUMPER_H_
class ifaceItem { // интерфейс элемента внутри группы, например текущий день недели, или часы полива
private:
protected:
ifaceItem * parentItem;
ifaceItem * childItems[32];
unsigned char noEditItem = 0;
unsigned short currentValue = 0;
unsigned short minValue = 0;
unsigned short maxValue = 1;
unsigned short countChildren = 0;
public:
unsigned short posX, posY, sizeX, sizeY, backgroundColor = 0x0000;
void addChild(ifaceItem * newChild) {this->childItems[this->countChildren] = newChild; ++this->countChildren;}
ifaceItem * getChild(unsigned char posChild) {return this->childItems[posChild];}
unsigned char getCountChildren(void) {return this->countChildren;}
void setNoEditedItem(void) {this->noEditItem = 1;}
unsigned char getNoEditedItem(void) {return this->noEditItem;}
unsigned char getValue(void) {return this->currentValue;}
virtual void showItem(void){}; // отобразить элемент
virtual void changeValue() {++this->currentValue; if (this->currentValue > this->maxValue) this->currentValue = this->minValue;} // изменить значение элемента
virtual void blinkItem() {}; // мигает позиция
virtual void setValue(unsigned short inValue) {this->currentValue = inValue;}
//virtual void minValueSet(unsigned short inValue) {this->minValue = inValue;}
//virtual void maxValueSet(unsigned short inValue) {this->maxValue = inValue;}
};
class baseUnit:public ifaceItem { // группа
private:
protected:
unsigned short iX, iY, itemColor = 0x0000;
unsigned char fontSize;
unsigned char modeShow = 0; // режим отображения 0-показывается 1+2-моргает
unsigned long blinkTimer;
public:
baseUnit(ifaceItem * itemParent = nullptr, unsigned short pX = 0, unsigned short pY = 0, unsigned short sX = 32, unsigned short sY = 64, unsigned short bColor = 0x00);
virtual void showItem(void) override;
virtual void blinkItem(void) override;
};
class baseOneCharValue:public baseUnit { // элемент - один символ
private:
protected:
public:
baseOneCharValue(ifaceItem * itemParent = nullptr, unsigned short pX = 0, unsigned short pY = 0, unsigned char iSize = 0, unsigned short iColor = 0x00, unsigned short mV = 0, unsigned short xV = 1);
virtual void showItem(void) override;
//virtual void blinkItem(void) override;
};
class baseNum2digValue:public baseOneCharValue { // элемент - число из двух цифр
private:
protected:
public:
baseNum2digValue(ifaceItem * itemParent = nullptr, unsigned short pX = 0, unsigned short pY = 0, unsigned char iSize = 0, unsigned short iColor = 0x00, unsigned short mV = 0, unsigned short xV = 1):
baseOneCharValue(itemParent, pX, pY, iSize, iColor, mV, xV) {};
virtual void showItem(void) override;
virtual void blinkItem(void) override;
};
class baseDictWDayValue:public baseOneCharValue { // элемент - техт из справочника день недели
private:
protected:
unsigned char * textWDay[9] = {(unsigned char *)"Sunday", (unsigned char *)"Monday", (unsigned char *)"Tuesday", (unsigned char *)"Wednesday", (unsigned char *)"Thursday", (unsigned char *)"Friday", (unsigned char *)"Saturday", (unsigned char *)" ", (unsigned char *)"-no set- "};
public:
baseDictWDayValue(ifaceItem * itemParent = nullptr, unsigned short pX = 0, unsigned short pY = 0, unsigned char iSize = 0, unsigned short iColor = 0x00, unsigned short mV = 0, unsigned short xV = 1):
baseOneCharValue(itemParent, pX, pY, iSize, iColor, mV, xV) {};
virtual void showItem(void) override;
virtual void blinkItem(void) override;
};
class baseDictMonthValue:public baseOneCharValue { // элемент - техт из справочника месяцы
private:
unsigned char * textMonths[14] = {(unsigned char *)"January ", (unsigned char *)"February ", (unsigned char *)"March ", (unsigned char *)"April ", (unsigned char *)"May ", (unsigned char *)"June ", (unsigned char *)"July ", (unsigned char *)"August ", (unsigned char *)"September", (unsigned char *)"October ", (unsigned char *)"November ", (unsigned char *)"December ", (unsigned char *)" ", (unsigned char *)"-no set- "};
protected:
public:
baseDictMonthValue(ifaceItem * itemParent = nullptr, unsigned short pX = 0, unsigned short pY = 0, unsigned char iSize = 0, unsigned short iColor = 0x00, unsigned short mV = 0, unsigned short xV = 1):
baseOneCharValue(itemParent, pX, pY, iSize, iColor, mV, xV) {};
virtual void showItem(void) override;
virtual void blinkItem(void) override;
};
class baseDictPumpDaysValue:public baseDictWDayValue { // элемент - по два символа из дней недели - дни полива, value подсвеченный выбранный день
private:
unsigned char weekDay = 0; // день недели 0...6
unsigned short colorDay = 0x5555; // цвет выбранного дня
unsigned short colorLabel = 0xAAAA; // цвет фона выбранного дня
protected:
public:
baseDictPumpDaysValue(ifaceItem * itemParent = nullptr, unsigned short pX = 0, unsigned short pY = 0, unsigned char iSize = 0, unsigned short iColor = 0x00, unsigned char inDay = 0, unsigned short daColor = 0xAAAA, unsigned short lbColor = 0x5555);
virtual void showItem(void) override;
virtual void blinkItem(void) override;
};
class baseNum2digText:public baseNum2digValue { // элемент - число из двух цифр + текст
private:
unsigned char * endText;
protected:
public:
baseNum2digText(ifaceItem * itemParent = nullptr, unsigned short pX = 0, unsigned short pY = 0, unsigned char iSize = 0, unsigned short iColor = 0x00, unsigned char * inText = nullptr, unsigned short mV = 0, unsigned short xV = 1);
virtual void showItem(void) override;
virtual void blinkItem(void) override;
};
void loopPumper(void);
void f1InitPumpGpio(void);
void initPumper(void);
#define blinkPeriod 500UL
#define keys_short_press 50UL
#define keys_long_press 2000UL
#define currentWDayColor ST7735_MAGENTA
#define currentWDayBack ST7735_BLACK
#define currentWDaySize 0
#define currentDateColor ST7735_GREEN
#define currentDateSize 0
#define currentTimeColor ST7735_YELLOW
#define currentTimeSize 2
#define currentTimeStartX 18
#define pumpBackground ST7735_WHITE
#define pumpDaysColor ST7735_BLACK
#define pumpSelectedDay ST7735_YELLOW
#define pumpSelectedBack ST7735_BLUE
#define pumpDaysSize 0
#define pumpTimeColor ST7735_GREEN
#define pumpTimeSize 2
#define pumpPeriodColor ST7735_ORANGE
#define pumpPeriodBack ST7735_BLUE
#define pumpPeriodSize 2
#endif /* PUMPER_H_ */
/*
* pumper.c
*
* Created on: 13 июн. 2023 г.
* Author: seleznev_a
*/
#include "pumper.h"
#include "f103ds3231.h"
#include "stm32f10x.h"
#include <time.h>
#include "f103c8t6.h"
#include "f103st7735.h"
#include "stdlib.h"
unsigned char timeIsGood = 0;
unsigned char pumpDays[7] = {0, 0, 1, 0, 1, 0, 0};
unsigned char pumpTime[2] = {20, 18};
unsigned char pumpPeriod = 5;
unsigned char devModes = 0; // 1-settings mode
unsigned long unusedDevice; // таймер бездействия пользователя
baseUnit iMainDisplay;
//--current date time
baseUnit iCurrentDateTime((ifaceItem *)&iMainDisplay, 0, 0,
st7735sizeX, fontSizeY[currentWDaySize]+fontSizeY[currentDateSize]+fontSizeY[currentTimeSize], currentWDayBack);
baseDictWDayValue iDayOfWeekCurrentDateTime((ifaceItem *)&iCurrentDateTime, 0, 0,
currentWDaySize, currentWDayColor, 0, 6);
baseNum2digValue iHourTimeCurrentDateTime((ifaceItem *)&iCurrentDateTime, currentTimeStartX,
fontSizeY[currentWDaySize], currentTimeSize, currentTimeColor, 0, 23);
baseOneCharValue iPointTimeCurrentDateTime((ifaceItem *)&iCurrentDateTime, currentTimeStartX + fontSizeX[currentTimeSize] * 2, fontSizeY[currentWDaySize],
currentTimeSize, currentTimeColor);
baseNum2digValue iMinTimeCurrentDateTime((ifaceItem *)&iCurrentDateTime, currentTimeStartX + fontSizeX[currentTimeSize] * 3, fontSizeY[currentWDaySize],
currentTimeSize, currentTimeColor, 0, 59);
baseNum2digValue iMDayCurrentDateTime((ifaceItem *)&iCurrentDateTime, 0, fontSizeY[currentWDaySize]+fontSizeY[currentTimeSize],
currentDateSize, currentDateColor, 1, 31);
baseDictMonthValue iMonthCurrentDateTime((ifaceItem *)&iCurrentDateTime, fontSizeX[currentDateSize] * 3, fontSizeY[currentWDaySize]+fontSizeY[currentTimeSize],
currentDateSize, currentDateColor, 0, 11);
baseNum2digValue iYearCurrentDateTime((ifaceItem *)&iCurrentDateTime, fontSizeX[currentDateSize] * 13, fontSizeY[currentWDaySize]+fontSizeY[currentTimeSize],
currentDateSize, currentDateColor, 23, 30);
//-- pump data
baseUnit iPumperDaysTime((ifaceItem *)&iMainDisplay, 0, fontSizeY[currentWDaySize]+fontSizeY[currentDateSize]+fontSizeY[currentTimeSize],
st7735sizeX, fontSizeY[currentWDaySize]+fontSizeY[currentDateSize]+fontSizeY[currentTimeSize]+fontSizeY[pumpDaysSize]*2+fontSizeY[pumpTimeSize]+fontSizeY[0]*2,
pumpBackground);
baseDictPumpDaysValue i1DayPumper((ifaceItem *)&iPumperDaysTime, fontSizeX[0], fontSizeY[0], pumpDaysSize, pumpDaysColor, 1, pumpSelectedDay, pumpSelectedBack);
baseDictPumpDaysValue i2DayPumper((ifaceItem *)&iPumperDaysTime, fontSizeX[0]+fontSizeX[pumpDaysSize]*4, fontSizeY[0], pumpDaysSize, pumpDaysColor, 2, pumpSelectedDay, pumpSelectedBack);
baseDictPumpDaysValue i3DayPumper((ifaceItem *)&iPumperDaysTime, fontSizeX[0]+fontSizeX[pumpDaysSize]*8, fontSizeY[0], pumpDaysSize, pumpDaysColor, 3, pumpSelectedDay, pumpSelectedBack);
baseDictPumpDaysValue i4DayPumper((ifaceItem *)&iPumperDaysTime, fontSizeX[0]+fontSizeX[pumpDaysSize]*12, fontSizeY[0], pumpDaysSize, pumpDaysColor, 4, pumpSelectedDay, pumpSelectedBack);
baseDictPumpDaysValue i5DayPumper((ifaceItem *)&iPumperDaysTime, fontSizeX[0]+fontSizeX[pumpDaysSize]*2, fontSizeY[0]+fontSizeY[pumpDaysSize], pumpDaysSize, pumpDaysColor, 5, pumpSelectedDay, pumpSelectedBack);
baseDictPumpDaysValue i6DayPumper((ifaceItem *)&iPumperDaysTime, fontSizeX[0]+fontSizeX[pumpDaysSize]*6, fontSizeY[0]+fontSizeY[pumpDaysSize], pumpDaysSize, pumpDaysColor, 6, pumpSelectedDay, pumpSelectedBack);
baseDictPumpDaysValue i0DayPumper((ifaceItem *)&iPumperDaysTime, fontSizeX[0]+fontSizeX[pumpDaysSize]*10, fontSizeY[0]+fontSizeY[pumpDaysSize], pumpDaysSize, pumpDaysColor, 0, pumpSelectedDay, pumpSelectedBack);
baseNum2digValue iHourPumpTime((ifaceItem *)&iPumperDaysTime, currentTimeStartX, fontSizeY[0]+fontSizeY[pumpDaysSize]*2,
pumpTimeSize, pumpTimeColor, 8, 22);
baseOneCharValue iPointPumpTime((ifaceItem *)&iPumperDaysTime, currentTimeStartX + fontSizeX[pumpTimeSize] * 2, fontSizeY[0]+fontSizeY[pumpDaysSize]*2,
pumpTimeSize, pumpTimeColor);
baseNum2digValue iMinPumpTime((ifaceItem *)&iPumperDaysTime, currentTimeStartX + fontSizeX[pumpTimeSize] * 3, fontSizeY[0]+fontSizeY[pumpDaysSize]*2,
pumpTimeSize, pumpTimeColor, 0, 59);
//--period pump
baseUnit iPeriodTime((ifaceItem *)&iMainDisplay, 0,
fontSizeY[currentWDaySize]+fontSizeY[currentDateSize]+fontSizeY[currentTimeSize]+
fontSizeY[pumpDaysSize]*2+fontSizeY[pumpTimeSize]+fontSizeY[0]*2,
st7735sizeX,
fontSizeY[currentWDaySize]+fontSizeY[currentDateSize]+fontSizeY[currentTimeSize]+
fontSizeY[pumpDaysSize]*2+fontSizeY[pumpTimeSize]+fontSizeY[0]*2+
fontSizeY[pumpPeriodSize]+fontSizeY[0]*2,
pumpPeriodBack);
baseNum2digText iPeriodPump((ifaceItem *)&iPeriodTime, 0, fontSizeY[0],
pumpPeriodSize, pumpPeriodColor, (unsigned char *)" min", 5, 40);
baseUnit::baseUnit(ifaceItem * itemParent, unsigned short pX, unsigned short pY, unsigned short sX, unsigned short sY, unsigned short bColor) {
this->countChildren = 0;
this->parentItem = itemParent;
if (itemParent != nullptr) {
this->posX = pX;
this->posY = pY;
this->sizeX = sX;
this->sizeY = sY;
this->backgroundColor = bColor;
this->modeShow = 0;
}
}
void baseUnit::showItem(void) {
this->modeShow = 0;
f103st7735fillRect(this->backgroundColor, this->posX, this->posY, this->sizeX-1, this->sizeY-1);
if (this->countChildren) for(unsigned char i=0; i<this->countChildren; ++i) this->childItems[i]->showItem();
}
baseOneCharValue::baseOneCharValue(ifaceItem * itemParent, unsigned short pX, unsigned short pY, unsigned char iSize, unsigned short iColor, unsigned short mV, unsigned short xV) {
this->countChildren = 0;
this->parentItem = itemParent;
this->iX = pX;
this->iY = pY;
this->itemColor = iColor;
this->modeShow = 0;
this->fontSize = iSize;
this->minValue = mV;
this->maxValue = xV;
}
void baseOneCharValue::showItem(void) {
this->modeShow = 0;
f103st7735printOneChar(this->currentValue, this->itemColor, this->parentItem->backgroundColor, this->fontSize, this->parentItem->posX+this->iX, this->parentItem->posY+this->iY);
}
void baseNum2digValue::showItem(void) {
this->modeShow = 0;
unsigned short posX = 0;
f103st7735printOneChar((this->currentValue/10)+'0', this->itemColor, this->parentItem->backgroundColor, this->fontSize, this->parentItem->posX+this->iX+posX, this->parentItem->posY+this->iY);
posX += fontSizeX[this->fontSize];
f103st7735printOneChar((this->currentValue%10)+'0', this->itemColor, this->parentItem->backgroundColor, this->fontSize, this->parentItem->posX+this->iX+posX, this->parentItem->posY+this->iY);
}
void baseDictWDayValue::showItem(void) {
this->modeShow = 0;
f103st7735printString((unsigned char *)this->textWDay[this->currentValue], this->itemColor, this->parentItem->backgroundColor,
this->fontSize, this->iX+this->parentItem->posX, this->iY+this->parentItem->posY);
}
void baseDictMonthValue::showItem(void) {
this->modeShow = 0;
f103st7735printString((unsigned char *)this->textMonths[this->currentValue], this->itemColor, this->parentItem->backgroundColor,
this->fontSize, this->iX+this->parentItem->posX, this->iY+this->parentItem->posY);
}
baseDictPumpDaysValue::baseDictPumpDaysValue(ifaceItem * itemParent, unsigned short pX, unsigned short pY, unsigned char iSize, unsigned short iColor, unsigned char inDay, unsigned short daColor, unsigned short lbColor) {
this->countChildren = 0;
this->parentItem = itemParent;
this->iX = pX;
this->iY = pY;
this->itemColor = iColor;
this->modeShow = 0;
this->fontSize = iSize;
this->weekDay = inDay;
this->colorDay = daColor;
this->colorLabel = lbColor;
}
void baseDictPumpDaysValue::showItem(void) {
this->modeShow = 0;
if (this->currentValue) {
f103st7735printOneChar((unsigned char)this->textWDay[this->weekDay][0], this->colorDay, this->colorLabel, this->fontSize, this->parentItem->posX+this->iX, this->parentItem->posY+this->iY);
f103st7735printOneChar((unsigned char)this->textWDay[this->weekDay][1], this->colorDay, this->colorLabel, this->fontSize, this->parentItem->posX+this->iX+fontSizeY[this->fontSize], this->parentItem->posY+this->iY);
} else {
f103st7735printOneChar((unsigned char)this->textWDay[this->weekDay][0], this->itemColor, this->parentItem->backgroundColor, this->fontSize, this->parentItem->posX+this->iX, this->parentItem->posY+this->iY);
f103st7735printOneChar((unsigned char)this->textWDay[this->weekDay][1], this->itemColor, this->parentItem->backgroundColor, this->fontSize, this->parentItem->posX+this->iX+fontSizeY[this->fontSize], this->parentItem->posY+this->iY);
}
}
baseNum2digText::baseNum2digText(ifaceItem * itemParent, unsigned short pX, unsigned short pY, unsigned char iSize, unsigned short iColor, unsigned char * inText, unsigned short mV, unsigned short xV) {
this->countChildren = 0;
this->parentItem = itemParent;
this->iX = pX;
this->iY = pY;
this->itemColor = iColor;
this->modeShow = 0;
this->fontSize = iSize;
this->endText = inText;
this->minValue = mV;
this->maxValue = xV;
}
void baseNum2digText::showItem(void) {
this->modeShow = 0;
unsigned short posX = 0;
if (this->currentValue < 10) {
f103st7735printOneChar('0', this->itemColor, this->parentItem->backgroundColor, this->fontSize,
this->parentItem->posX+this->iX,
this->parentItem->posY+this->iY);
posX += fontSizeX[this->fontSize];
}
f103st7735printUInt(this->currentValue, this->itemColor, this->parentItem->backgroundColor, this->fontSize,
this->parentItem->posX+this->iX+posX,
this->parentItem->posY+this->iY);
posX += fontSizeX[this->fontSize];
f103st7735printString((unsigned char *)this->endText, this->itemColor, this->parentItem->backgroundColor, this->fontSize, posX, this->parentItem->posY+this->iY);
}
void fillPumpDaysFromData() {
if (iPumperDaysTime.getCountChildren()) {
for(unsigned char i=0; ((i<iPumperDaysTime.getCountChildren()) && (i<7)); ++i) {
if (pumpDays[i]) iPumperDaysTime.getChild(i)->setValue(1); else iPumperDaysTime.getChild(i)->setValue(0);
}
if ((iPumperDaysTime.getCountChildren()>7) && (iPumperDaysTime.getCountChildren()<11)) {
iHourPumpTime.setValue(pumpTime[0]);
iMinPumpTime.setValue(pumpTime[1]);
}
}
}
void initPumper(void) {
//--current date time
iMainDisplay.addChild((ifaceItem *)&iCurrentDateTime);
iCurrentDateTime.addChild((ifaceItem *)&iDayOfWeekCurrentDateTime);
iCurrentDateTime.addChild((ifaceItem *)&iHourTimeCurrentDateTime);
iCurrentDateTime.addChild((ifaceItem *)&iPointTimeCurrentDateTime);
iPointTimeCurrentDateTime.setValue(' ');
iPointTimeCurrentDateTime.setNoEditedItem();
iCurrentDateTime.addChild((ifaceItem *)&iMinTimeCurrentDateTime);
iCurrentDateTime.addChild((ifaceItem *)&iMDayCurrentDateTime);
iCurrentDateTime.addChild((ifaceItem *)&iMonthCurrentDateTime);
iCurrentDateTime.addChild((ifaceItem *)&iYearCurrentDateTime);
//iCurrentDateTime.showItem();
//-- pump data
iMainDisplay.addChild((ifaceItem *)&iPumperDaysTime);
iPumperDaysTime.addChild((ifaceItem *)&i0DayPumper);
iPumperDaysTime.addChild((ifaceItem *)&i1DayPumper);
iPumperDaysTime.addChild((ifaceItem *)&i2DayPumper);
iPumperDaysTime.addChild((ifaceItem *)&i3DayPumper);
iPumperDaysTime.addChild((ifaceItem *)&i4DayPumper);
iPumperDaysTime.addChild((ifaceItem *)&i5DayPumper);
iPumperDaysTime.addChild((ifaceItem *)&i6DayPumper);
iPumperDaysTime.addChild((ifaceItem *)&iHourPumpTime);
iPumperDaysTime.addChild((ifaceItem *)&iPointPumpTime);
iPointPumpTime.setValue('.');
iPointPumpTime.setNoEditedItem();
iPumperDaysTime.addChild((ifaceItem *)&iMinPumpTime);
//fillPumpDaysFromData();
//iPumperDaysTime.showItem();
//--period pump
iMainDisplay.addChild((ifaceItem *)&iPeriodTime);
iPeriodTime.addChild((ifaceItem *)&iPeriodPump);
//iPeriodPump.setValue(pumpPeriod);
//iPeriodTime.showItem();
}
void f1InitPumpGpio(void) {
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; // GPIO port B
// PB14 - key 1
GPIOB->CRH &= ~GPIO_CRH_MODE14; // 00: Input mode (reset state)
GPIOB->CRH &= ~GPIO_CRH_CNF14; // 10: Input with pull-up / pull-down
GPIOB->CRH |= GPIO_CRH_CNF14_1; // 10: Input with pull-up / pull-down
GPIOB->ODR |= GPIO_ODR_ODR14; // Input with pull-up
// PB15 - key 2
GPIOB->CRH &= ~GPIO_CRH_MODE15; // 00: Input mode (reset state)
GPIOB->CRH &= ~GPIO_CRH_CNF15; // 10: Input with pull-up / pull-down
GPIOB->CRH |= GPIO_CRH_CNF15_1; // 10: Input with pull-up / pull-down
GPIOB->ODR |= GPIO_ODR_ODR15; // Input with pull-up
}
void showDateTime(void) {
static unsigned long timerShowDateTime = 59000UL;
static unsigned long timerBlinkSec = 0;
static unsigned char secBlink =0;
if ((millis() - timerShowDateTime) >= 60000UL) {
timerShowDateTime = millis();
if (getDS3231currentDateTime((struct tm *)¤tDateTime) == dsI2CerrorReturn) {
timeIsGood = 0;
f103st7735printString((unsigned char *)"Error", ST7735_RED, currentWDayBack, currentWDaySize, 0, 0);
} else {
timeIsGood = 1;
iDayOfWeekCurrentDateTime.setValue(currentDateTime.tm_wday);
iHourTimeCurrentDateTime.setValue(currentDateTime.tm_hour);
iMinTimeCurrentDateTime.setValue(currentDateTime.tm_min);
iMDayCurrentDateTime.setValue(currentDateTime.tm_mday);
iMonthCurrentDateTime.setValue(currentDateTime.tm_mon);
iYearCurrentDateTime.setValue((currentDateTime.tm_year+1900)%100);
iCurrentDateTime.showItem();
}
} else if (timeIsGood && ((millis() - timerBlinkSec) >= 1000UL)) {
timerBlinkSec = millis();
if (secBlink) {
iPointTimeCurrentDateTime.setValue(':');
secBlink = 0;
} else {
iPointTimeCurrentDateTime.setValue(' ');
secBlink = 1;
}
iPointTimeCurrentDateTime.showItem();
}
}
void baseUnit::blinkItem(void) {
if ((millis() - this->blinkTimer) >= blinkPeriod) {
this->blinkTimer = millis();
f103st7735fillRect(this->backgroundColor, this->posX, this->posY, this->sizeX-1, this->sizeY-1);
if ((this->modeShow == 0) || (this->modeShow == 1)) {
this->modeShow = 2;
} else {
this->modeShow = 1;
if (this->countChildren) for(unsigned char i=0; i<this->countChildren; ++i) this->childItems[i]->showItem();
}
}
}
void baseNum2digValue::blinkItem(void) {
unsigned short posX = 0;
if ((millis() - this->blinkTimer) >= blinkPeriod) {
this->blinkTimer = millis();
if ((this->modeShow == 0) || (this->modeShow == 1)) {
this->modeShow = 2;
f103st7735printOneChar(' ', this->itemColor, this->parentItem->backgroundColor, this->fontSize, this->parentItem->posX+this->iX, this->parentItem->posY+this->iY);
posX += fontSizeX[this->fontSize];
f103st7735printOneChar(' ', this->itemColor, this->parentItem->backgroundColor, this->fontSize, this->parentItem->posX+this->iX+posX, this->parentItem->posY+this->iY);
} else {
this->modeShow = 1;
f103st7735printOneChar((this->currentValue/10)+'0', this->itemColor, this->parentItem->backgroundColor, this->fontSize, this->parentItem->posX+this->iX+posX, this->parentItem->posY+this->iY);
posX += fontSizeX[this->fontSize];
f103st7735printOneChar((this->currentValue%10)+'0', this->itemColor, this->parentItem->backgroundColor, this->fontSize, this->parentItem->posX+this->iX+posX, this->parentItem->posY+this->iY);
}
}
}
void baseDictWDayValue::blinkItem(void) {
if ((millis() - this->blinkTimer) >= blinkPeriod) {
this->blinkTimer = millis();
if ((this->modeShow == 0) || (this->modeShow == 1)) {
this->modeShow = 2;
f103st7735printString((unsigned char *)this->textWDay[7], this->itemColor, this->parentItem->backgroundColor,
this->fontSize, this->iX+this->parentItem->posX, this->iY+this->parentItem->posY);
} else {
this->modeShow = 1;
f103st7735printString((unsigned char *)this->textWDay[this->currentValue], this->itemColor, this->parentItem->backgroundColor,
this->fontSize, this->iX+this->parentItem->posX, this->iY+this->parentItem->posY);
}
}
}
void baseDictMonthValue::blinkItem(void) {
if ((millis() - this->blinkTimer) >= blinkPeriod) {
this->blinkTimer = millis();
if ((this->modeShow == 0) || (this->modeShow == 1)) {
this->modeShow = 2;
f103st7735printString((unsigned char *)this->textMonths[12], this->itemColor, this->parentItem->backgroundColor,
this->fontSize, this->iX+this->parentItem->posX, this->iY+this->parentItem->posY);
} else {
this->modeShow = 1;
f103st7735printString((unsigned char *)this->textMonths[this->currentValue], this->itemColor, this->parentItem->backgroundColor,
this->fontSize, this->iX+this->parentItem->posX, this->iY+this->parentItem->posY);
}
}
}
/*void baseOneCharValue::blinkItem(void) {
if ((millis() - this->blinkTimer) >= blinkPeriod) {
this->blinkTimer = millis();
if ((this->modeShow == 0) || (this->modeShow == 1)) {
this->modeShow = 2;
f103st7735printOneChar(' ', this->itemColor, this->parentItem->backgroundColor, this->fontSize, this->parentItem->posX+this->iX, this->parentItem->posY+this->iY);
} else {
this->modeShow = 1;
f103st7735printOneChar(this->currentValue, this->itemColor, this->parentItem->backgroundColor, this->fontSize, this->parentItem->posX+this->iX, this->parentItem->posY+this->iY);
}
}
}*/
void baseDictPumpDaysValue::blinkItem(void) {
if ((millis() - this->blinkTimer) >= blinkPeriod) {
this->blinkTimer = millis();
if ((this->modeShow == 0) || (this->modeShow == 1)) {
this->modeShow = 2;
if (this->currentValue) {
f103st7735printOneChar(' ', this->colorDay, this->colorLabel, this->fontSize, this->parentItem->posX+this->iX, this->parentItem->posY+this->iY);
f103st7735printOneChar(' ', this->colorDay, this->colorLabel, this->fontSize, this->parentItem->posX+this->iX+fontSizeY[this->fontSize], this->parentItem->posY+this->iY);
} else {
f103st7735printOneChar(' ', this->itemColor, this->parentItem->backgroundColor, this->fontSize, this->parentItem->posX+this->iX, this->parentItem->posY+this->iY);
f103st7735printOneChar(' ', this->itemColor, this->parentItem->backgroundColor, this->fontSize, this->parentItem->posX+this->iX+fontSizeY[this->fontSize], this->parentItem->posY+this->iY);
}
} else {
this->modeShow = 1;
if (this->currentValue) {
f103st7735printOneChar((unsigned char)this->textWDay[this->weekDay][0], this->colorDay, this->colorLabel, this->fontSize, this->parentItem->posX+this->iX, this->parentItem->posY+this->iY);
f103st7735printOneChar((unsigned char)this->textWDay[this->weekDay][1], this->colorDay, this->colorLabel, this->fontSize, this->parentItem->posX+this->iX+fontSizeY[this->fontSize], this->parentItem->posY+this->iY);
} else {
f103st7735printOneChar((unsigned char)this->textWDay[this->weekDay][0], this->itemColor, this->parentItem->backgroundColor, this->fontSize, this->parentItem->posX+this->iX, this->parentItem->posY+this->iY);
f103st7735printOneChar((unsigned char)this->textWDay[this->weekDay][1], this->itemColor, this->parentItem->backgroundColor, this->fontSize, this->parentItem->posX+this->iX+fontSizeY[this->fontSize], this->parentItem->posY+this->iY);
}
}
}
}
void baseNum2digText::blinkItem(void) {
unsigned short posX = 0;
if ((millis() - this->blinkTimer) >= blinkPeriod) {
this->blinkTimer = millis();
if ((this->modeShow == 0) || (this->modeShow == 1)) {
this->modeShow = 2;
f103st7735printOneChar(' ', this->itemColor, this->parentItem->backgroundColor, this->fontSize, this->parentItem->posX+this->iX+posX, this->parentItem->posY+this->iY);
posX += fontSizeX[this->fontSize];
f103st7735printOneChar(' ', this->itemColor, this->parentItem->backgroundColor, this->fontSize, this->parentItem->posX+this->iX+posX, this->parentItem->posY+this->iY);
posX += fontSizeX[this->fontSize];
f103st7735printString((unsigned char *)" ", this->itemColor, this->parentItem->backgroundColor, this->fontSize, posX, this->parentItem->posY+this->iY);
} else {
this->modeShow = 1;
f103st7735printOneChar((this->currentValue/10)+'0', this->itemColor, this->parentItem->backgroundColor, this->fontSize, this->parentItem->posX+this->iX+posX, this->parentItem->posY+this->iY);
posX += fontSizeX[this->fontSize];
f103st7735printOneChar((this->currentValue%10)+'0', this->itemColor, this->parentItem->backgroundColor, this->fontSize, this->parentItem->posX+this->iX+posX, this->parentItem->posY+this->iY);
posX += fontSizeX[this->fontSize];
f103st7735printString((unsigned char *)this->endText, this->itemColor, this->parentItem->backgroundColor, this->fontSize, posX, this->parentItem->posY+this->iY);
}
}
}
unsigned char getKey1(void) { // выдает 1 если нажата 1 кнопка
static unsigned char last1Level = 1;
static unsigned char flag1KeysDown = 0;
static unsigned long start1TimeDown;
unsigned char current1Level;
if (GPIOB->IDR & GPIO_IDR_IDR14) current1Level = 1; else current1Level = 0;
if (current1Level != last1Level) { // change level
unusedDevice = millis();
if (current1Level == 0) { // key down
if (flag1KeysDown == 0) { // no timer
flag1KeysDown = 1; // begin timer
start1TimeDown = millis();
}
} else { // key up
if (flag1KeysDown != 0) { // timer started
if ((millis() - start1TimeDown) >= 500UL) { // error press
flag1KeysDown = 0; // stop timer
} else if ((millis() - start1TimeDown) >= keys_short_press) { // short press
flag1KeysDown = 0; // stop timer
last1Level = current1Level; // save current level
return 1;
}
}
}
} else { // level not change
if ((flag1KeysDown != 0) && (current1Level == 0)) { // timer started and key down
if ((millis() - start1TimeDown) >= keys_long_press) { // long press
flag1KeysDown = 0; // stop timer
last1Level = current1Level; // save current level
return 2;
}
} else if (current1Level != 0) { // key up
flag1KeysDown = 0; // reset timer
}
}
last1Level = current1Level; // save current level
return 0;
}
unsigned char getKey2(void) { // выдает 1 если нажата 2 кнопка
static unsigned char last2Level = 1;
static unsigned char flag2KeysDown = 0;
static unsigned long start2TimeDown;
unsigned char current2Level;
if (GPIOB->IDR & GPIO_IDR_IDR15) current2Level = 1; else current2Level = 0;
if (current2Level != last2Level) { // change level
unusedDevice = millis();
if (current2Level == 0) { // key down
if (flag2KeysDown == 0) { // no timer
flag2KeysDown = 1; // begin timer
start2TimeDown = millis();
}
} else { // key up
if (flag2KeysDown != 0) { // timer started
if ((millis() - start2TimeDown) >= 500UL) { // error press
flag2KeysDown = 0; // stop timer
} else if ((millis() - start2TimeDown) >= keys_short_press) { // short press
flag2KeysDown = 0; // stop timer
last2Level = current2Level; // save current level
return 1;
}
}
}
} else { // level not change
if ((flag2KeysDown != 0) && (current2Level == 0)) { // timer started and key down
if ((millis() - start2TimeDown) >= keys_long_press) { // long press
flag2KeysDown = 0; // stop timer
last2Level = current2Level; // save current level
return 2;
}
} else if (current2Level != 0) { // key up
flag2KeysDown = 0; // reset timer
}
}
last2Level = current2Level; // save current level
return 0;
}
unsigned char controlDevice(void) { // выдать 1 если изменились параметры и их все надо обновить на экране
unsigned char data1key = getKey1();
unsigned char data2key = getKey2();
static unsigned char numEditMainUnit = 0; // номер главного модуля который редактируется
static unsigned char enteredSubUnit = 0; // перешли в редактирование значения в модуле
static unsigned char numSubItem = 0; // номер элемента который редактируется
if (!devModes) { // standby mode
if (data1key) { // enter set mode
devModes = 1; // enter set mode
numEditMainUnit = 0; // номер главного модуля который редактируется
enteredSubUnit = 0; // моргаем пока модулем
}
} else { // settings mode
if ((millis()-unusedDevice) >= 10000UL) { // если кнопки долго не нажимали
devModes = 0; // возвращаемся в ждущий режим
return 1; // с обновлением данных
}
if (enteredSubUnit) { // в режиме редактирования элемента
iMainDisplay.getChild(numEditMainUnit)->getChild(numSubItem)->blinkItem(); // моргаем элементом
if (data2key) { // если продолжается нажиматься вторая кнопка
iMainDisplay.getChild(numEditMainUnit)->getChild(numSubItem)->showItem(); // предыдущий элемент просто отобразим
++numSubItem; // будем моргать следующим элементом
if (numSubItem >= iMainDisplay.getChild(numEditMainUnit)->getCountChildren()) numSubItem = 0;
if (iMainDisplay.getChild(numEditMainUnit)->getChild(numSubItem)->getNoEditedItem()) { // если элемент не редактируемый
++numSubItem; // будем моргать следующим элементом
if (numSubItem >= iMainDisplay.getChild(numEditMainUnit)->getCountChildren()) numSubItem = 0;
}
} else {
if (data1key) { // нажалась кнопка 1 - изменить значение
iMainDisplay.getChild(numEditMainUnit)->getChild(numSubItem)->changeValue();
}
}
} else { // в режиме выбора модуля
iMainDisplay.getChild(numEditMainUnit)->blinkItem(); // моргаем модулем
if (data1key) { // если продолжается нажиматься первая кнопка
iMainDisplay.getChild(numEditMainUnit)->showItem(); // предыдущий модуль просто отобразим
++numEditMainUnit; // будем моргать следующим модулем
if (numEditMainUnit >= iMainDisplay.getCountChildren()) numEditMainUnit = 0;
} else {
if (data2key) { // если нажалась вторая кнопка
iMainDisplay.getChild(numEditMainUnit)->showItem(); // текущий модуль просто отобразим
enteredSubUnit = 1; // перешли в редактирование значения в модуле
numSubItem = 0; // номер элемента который редактируется
}
}
}
}
return 0;
}
void loopPumper(void) {
static unsigned char needShowPumpDate = 1; // в обычном ждущем режиме один раз показать данные полива
if (!devModes) { // standby mode
showDateTime();
if (needShowPumpDate) {
needShowPumpDate = 0;
fillPumpDaysFromData();
iPumperDaysTime.showItem();
iPeriodPump.setValue(pumpPeriod);
iPeriodTime.showItem();
}
}
needShowPumpDate = controlDevice(); // основная работа с кнопками и режимами настройки
}
Неужели нельзя сделать универсальной ???
наверное можно, разбить разнотипные данные на еще более мелкие обьекты. Т е у меня есть, текст(символ)/число/три типа элементов справочника. Но это потом…сначала функционал добить.
шаблонами проще было бы, наерна. Во главе абстрактный класс без хранилища данных и pure virtual функции для обработки. И наследуй потом от него разных потомков.
это пока выше моего понимания
У Вас нешаблонное мышление?
Не знаю какое у меня мышление)
Но пока не очень получается…научусь.
https://youtu.be/rF5-7VZekz8
Это как выглядит в реальности.
и в каком месте тут шаблоны?
Ну так типы-то разные, а работать с ними надо единообразно. Я подумаю тщательно на досуге.
Хотя, нет, шаблоны не проще, ты прав. Простое наследование падёт.
у меня получается шесть переопределенных функций blinkItem
если я сделаю щесть функций clearItem, т е очистка поля вывода информации, то тогда я смогу прописать в головном классе одну функцию blinkItem и будет наверное немного красивее и логичнее.