Возвращаюсь к вопросу. На данный момент пришел к тому, что у меня не все датчики одного типа оказались. Отсюда в структуре поле
structDHTData {
02
DHT * dht;
03
chardhtTitle[20];
.....
09
boolf_DHTError;
10
};
DHTData dhts[COUNT_DHT];
...........
1
for(byten = 0; n < COUNT_DHT; n++) {
2
dhts[n].dht = newDHT(dhtPins[n], dhtType[n]);
3
dhts[n].dht->begin();
4
}
DHT * dht; - нужно как-то изменить.
Про вариант DetSimen'а помню это про отдельный класс, но пока хочу попробовать сделать "по своему" ибо в текущем коде хоть как-то с горем пополам разбираюсь. Хотя уже пару раз делал глобальные изменения, думал рухнет все.... ан-нет.
Так вот у меня вопрос: Каким образом можно переделать. В структуре поле DHT * dht; думаю будет void * sens;
Создание тоже думаю не возникнут вопросы: типа
switch (typesens)
case dht: dhts[n].sens= newDHT(dhtPins[n], dhtType[n]); break; - или так не пойдет?
case bmp; ... break;
case am: .... break;
ну и дальше как этот sens приводить к нужному классу (ну типа как в делфи temp:=(sens as TMySens).ReadTemp; про предварительный is тоже знаю...)
В общем вопрос, как "грамотно" это сделать? ("грамотно" в кавычках - это я понимаю, что грамотно будет типа как было предложено отдельным классом для каждого типа датчика, но...)
Это я знаю и понимаю. Буду стремиться к этому, но на данный момент хотелось бы узнать как нетипизированный указатель привязать к разного типа объектам и потом с ними работать. Спасибо
:( Т.е. то как я хочу это сделать - не получится. Только переделывание всего проекта с нуля всё и на отдельных классах? Или из-за моих "тупых" вопросов мне больше не стоит ждать помощи?(
Работает. Вопрос: что плохого/хорошего в этом способе?
с точки зрения синтаксиса языка - это допустимо, хотя и попахивает. Но с точки зрения обычной логики - это глупость. Зачем обьединять в одном классе термометр и серву, какой в этом смысл? Классы нужны для того.,чтобы проще работать с обьектами. А если при любом вызове метода вам придется насильно приводить тип сенсора либо к термометру либо к серве - зачем нужен такой общий класс. не проще ли пользоваться сразу классами термометра и сервы?
Зачем обьединять в одном классе термометр и серву, какой в этом смысл?
Дак тут смысл не в серве и термометре. Они - это что первое мне под руку попалось. Смысл данного кода в нетипизированном указателе и его приведении к нужному типу.
b707 пишет:
не проще ли пользоваться сразу классами термометра и сервы?
Скорее всего проще. На данном моменте моего проекта я это уже осознаю. Но переделывать с "нуля" пока не решаюсь. Но буду. Но и данный проект принес мне много нового и поучительного. Конкретно сейчас я понимаю, что если делать сначала то многие вещи нужно делать по другому. Но пусть здесь будет пока так. Возможно и следующий проект у меня не получится "грамотным", даже скорее всего не получится, но я разбираюсь в этом и стараюсь к этому (грамотному написанию) придти. Многие вещи я даже сейчас вижу как переделать в моем проекте, может потихоньку, не разом, но переделаю....
Спасибо что читаете и отвечаете на мои сообщения. Но жаль что уровень моих знаний пока не дотягивает до уровня ваших подсказок.
Зачем обьединять в одном классе термометр и серву, какой в этом смысл?
Вообще там будут только датчики (темпер/влаж) только разные. Изначально думал будут одного типа(DHT22) все, но оказалось, что у меня их несколько и все они разные(BME, AM ну и DHT). Поэтому вот это:
struct DHTData { //Данные датчика
DHT * dht;
char dhtTitle[20]; //Описание датчика
int tOn, tOff, hOn, hOff; //Температура включения/выключения, Влажность включения/отключения
int t = MYNAN, h = MYNAN; //Текущая температура и влажность
int prevT = MYNAN, prevH = MYNAN; //Предпоследние значения температуры и влажности (для определения динамики)
int8_t tDyn = 0, hDyn = 0; //Динамика изменения температуры и влажности
int ttmp = 0, htmp = 0; //Временные данные по температуре и влажности нужны в момент измерения
int tmin, tmax, hmin, hmax; //Минимальные и максимальные значения температуры и влажности
byte cnt[2][3]; //Счетчики срабатываний каналов сегодня/вчера/позавчера
uint32_t workTime[2]; //Продолжительность работы каналов, по завершению плюсуется к timesWork[0]
uint32_t workTimes[2][3]; //Общее время работы каналов сегодня/вчера/позавчера
bool isWorkCh[2]; //Признак работы каналов
bool f_DHTError; //True Если с датчика DHT ничего не считалось
};
DHTData dhts[COUNT_DHT]; //Массив данных датчиков
Хочу переделать вот в это:
struct DHTData { //Данные датчика
void * dht;
char dhtTitle[20]; //Описание датчика
int tOn, tOff, hOn, hOff; //Температура включения/выключения, Влажность включения/отключения
int t = MYNAN, h = MYNAN; //Текущая температура и влажность
int prevT = MYNAN, prevH = MYNAN; //Предпоследние значения температуры и влажности (для определения динамики)
int8_t tDyn = 0, hDyn = 0; //Динамика изменения температуры и влажности
int ttmp = 0, htmp = 0; //Временные данные по температуре и влажности нужны в момент измерения
int tmin, tmax, hmin, hmax; //Минимальные и максимальные значения температуры и влажности
byte cnt[2][3]; //Счетчики срабатываний каналов сегодня/вчера/позавчера
uint32_t workTime[2]; //Продолжительность работы каналов, по завершению плюсуется к timesWork[0]
uint32_t workTimes[2][3]; //Общее время работы каналов сегодня/вчера/позавчера
bool isWorkCh[2]; //Признак работы каналов
bool f_DHTError; //True Если с датчика DHT ничего не считалось
};
DHTData dhts[COUNT_DHT]; //Массив данных датчиков
Все одинаково, только вместо DHT * dht; будет void * dht;
Ну и по коду проделать некоторые изменения. Благо там их не должно быть много.
Я это не для выставки или соревнования делаю, даже не для продажи;). Более того мне было просто интересно это сделать. Я не программист... было лет 20 назад хобби, но уже все на столько забыл, да и в си (да еще и не под винду) это немного по другому... Хорошо хоть подсказываете и на путь истинный ставите. Не думайте что я к критике плохо отношусь.Спасибо.
посмотреть бы на список "признаков" говнокода.... ну чтоб стараться так не делать. :) Просто для кого-то работа с указателями - это нормально. Для меня - это кошмар. А кто-то понимает где нужно работать с указателями а где не нужно.
У меня данный проект не большой, всего-то около 900 строк.... Но думаю использовав нетипизированный указатель я малой кровью отредактирую его для использования разного типа датчиков. И в таком небольшом проекте скорее всего это будет безболезненно. Тем более что проект развиваться и меняться не будет.
Я бы сделал проще. Структуру с типом датчика, его идентифицирующим атрибутом и полем значения метрики. Потом в процедуре полинга, опираясь на тип и атрибут (для DHT это пин, к примеру), опрашивал датчик и выгружал полученное в поле значения метрики.
Я может это как-то всё понимаю по другому, может быть термины не правильно понимаю типа (поле значения метрики, процедура полинга...).... Но с другой стороны мне кажется что у меня в принципе почти так и сделано. В моем проекте есть три датчика. Сейчас вот как раз сделаю в структуру еще идентификатор датчика (константный) Исходя из него будет в начале создан и присвоен указателю dht нужный тип датчика (BME и AM по айтуси (I2C) т.е. им даже пин не нужно назначать, но с этим вопросов нет вообще) и далее в методе чтения так же исходя из типа считаю с трех датчиков с каждого в свои переменные структуры - данные с датчиков. Т.е. просто заполняется данными массив структур. А дальше в методе луп будет вызвана процедура Анализа данных (это в WorkChannelTimer())и затем процедура отрисовки экрана (Эх, вот ее мне точно нужно оптимизировать, разрослась дай боже...). Вот соб-но сам луп:
void loop() { // ---------- LOOP -------------------
readEncoder(); //Читаем энкодер
readDHTs(); //Считываем датчики
VerifyResetTimer(); //Таймер для сброса данных раз в сутки, так же используется для выключени дисплея при бездействии
verifyEditTimer(); //Таймер для автовыхода из режима редактирования
WorkChannelTimer(); //Таймер работы каналов
UpdateScreenTimer(); //Запрос обновления экрана
}
Все это суета сует. Просто три инстанса или три инстанса через указатели в массиве структур... Большого выигрыша ни по скорости, ни по размеру кода не будет. Динамически массив датчиков перестраиваться не будет, а без него указатели, кастинги и пр. - ментальные упражнения в попытке убить время.
Все может быть. Но так как у меня нет опыта в таких вещах, изначально думал, что массив - будет все упорядочено и легче работать. И оно может так и было бы если датчики все были одного типа.
А указатели, кастинги и убийство времени - это верно, я не отрицаю. Мне это было очень интересно в плане получения опыта.
Массив удобен для однотипных данных, обрабатываемых эквивалентно. Например - все температуры распечатать с 50ти датчиков. А когда в структуре разносол поштучный - то ее обработка раздувается похлеще живота программера в пятницу.
Хотите массив - заведите массив значений метрик. Хотя и там тоже наборы разноплановые... Красиво, в строчку, не выйдет, энивэй. Полезут уродливые кейсы, ифы.
Так в том и дело что у меня в структуре данные касаются только одного датчика, а по датчикам они однотипные, поэтому они в массиве. Чтение и наполнение данными структуры тоже однотипные для всех датчиков. А вот работа с этими данными уже будет для каждого датчика своя. И даже данные одного датчика могут использоваться в обработке данных с другого. У каждого датчика по два канала.
Например один датчик у меня установлен в кессоне. И вот его основная задача держать температуру выше ноля(точнее выше +2..2,5°С) (Первый канал) Подогрев воздуха - банально лампы накаливания две штуки по 200W. (две - на всякий случай если одна сгорит. Доступ в кессон зимой очень проблемный.) А второстепенная (второй канал) - это влажность. Включается вентилятор. И вот тут пригодится датчик с улицы. Если на улице высокая влажность то и нет смысла вертеть вентилятором.... как-то так. Но как обычно всех нюансов в одном сообщении не укажешь.
Там такие нюансы, что если низкая температура но еще не критичная что бы включить обогрев, но высокая влажность.... Вроде просто включаем вентилятор и все. Но нет, нужно сначала поднять температуру, а потом продуть все это дело.... В общем как-то так .... может я и занимаюсь фигней, но мне это просто интересно, и самое главное надеюсь будет полезно)
И вот его основная задача держать температуру выше ноля(точнее выше +2..2,5°С) (Первый канал) Подогрев воздуха - банально лампы накаливания две штуки по 200W.
Так-то кессон утеплен и по идее его греет скважина и температура не должна упасть ниже ноля. Но кессон не успели доделать как положено и вообще это первый опыт. Мало ли какие морозы будут зимой. А там труба, хоть и пвх, но... Поэтому я вспомнил про ардуину и решил немного подстраховаться в эту зиму. Заодно попробую возрадить хобби...)
Ну так я и понял, что у Вас много времени для выдумывания развесистых структур. Вместо заполнения двух переменных outdoorT и outdoorH готовы вертеть через три колена указатели на void.
Вы же не будете в цикле сравнивать температуру уличную и домовую. Налепите дерево if()-ов...
Впрочем, для того, чтобы осознать, что ООП - это не улучшающая приправа к любому блюду, нужна практика.
Ну так я и понял, что у Вас много времени для выдумывания развесистых структур. Вместо заполнения двух переменных outdoorT и outdoorH готовы вертеть через три колена указатели на void.
Прошу прощения, но я не понял как можно данные (T и Н) с трех! датчиков сохранить в двух переменных??
Ну я имею ввиду простые типы типа Int... :)
sadman41 пишет:
Вы же не будете в цикле сравнивать температуру уличную и домовую. Налепите дерево if()-ов...
Как раз наоборот по массиву легче "бегать". Вот например как у меня "предобработка" данных с датчиков:
uint32_t ms;
void WorkChannelTimer() {
if (millis() - ms >= 1000) {
{
for (byte n = 0; n < COUNT_DHT; n++)
if (!dhts[n].f_DHTError) for (byte ch = 0; ch < 2; ch++) //Если у датчика нет ошибки
if (dhts[n].isWorkCh[ch]) dhts[n].workTime[ch]++; //и канал включен - считаем время работы
static byte n = 0;
if (n > 0) n--; else {
n = 30; //Каждые 30 секунд
AnalizeDHTs(); //Анализируем данные с датчиков
}
}
do {
ms += 1000;
if (ms < 1000) break; // переполнение uint32_t
} while (ms < millis() - 1000); // защита от пропуска шага
}
}
По моему удобно и ifы в меру надобности... Я не отрицаю и не спорю что я много не знаю и можно сделать все проще. Но надеюсь не забросить это дело и развиваться в этом направлении.
sadman41 пишет:
ООП - это не улучшающая приправа к любому блюду, нужна практика.
Практика - это тоже нужно. Тем более теорию я без практики вообще не понимаю.
Если посмотреть на мою структуру, то там избыточные данные, но это чисто для практики и моего любопытства... Например, посмотреть сколько раз за сутки включались лампы и сколько они горели по времени....
А так, да.... можно код сократить в разы...
sadman41 пишет:
Вместо заполнения двух переменных outdoorT и outdoorH готовы вертеть через три колена указатели на void.
Или Вы имели ввиду у каждого датчика по две переменные?
Тогда да, но.... я уже сказал, что избыточность данных по датчикам - это да, у меня много времени и любопытства :)
sadman41 пишет:
А то, что сейчас вижу - это оверинжиниринг.
Ох, не заметил ) Так-то верно. Но не ругайте меня за это ;)
Возвращаюсь к вопросу. На данный момент пришел к тому, что у меня не все датчики одного типа оказались. Отсюда в структуре поле
struct
DHTData {
02
DHT * dht;
03
char
dhtTitle[20];
09
bool
f_DHTError;
10
};
DHTData dhts[COUNT_DHT];
...........
1
for
(
byte
n = 0; n < COUNT_DHT; n++) {
2
dhts[n].dht =
new
DHT(dhtPins[n], dhtType[n]);
3
dhts[n].dht->begin();
4
DHT * dht; - нужно как-то изменить.
Про вариант DetSimen'а помню это про отдельный класс, но пока хочу попробовать сделать "по своему" ибо в текущем коде хоть как-то с горем пополам разбираюсь. Хотя уже пару раз делал глобальные изменения, думал рухнет все.... ан-нет.
Так вот у меня вопрос: Каким образом можно переделать. В структуре поле DHT * dht; думаю будет void * sens;
Создание тоже думаю не возникнут вопросы: типа
switch (typesens)
case dht:
dhts[n].sens=
new
DHT(dhtPins[n], dhtType[n]); break; - или так не пойдет?
case bmp; ... break;
case am: .... break;
ну и дальше как этот sens приводить к нужному классу (ну типа как в делфи temp:=(sens as TMySens).ReadTemp; про предварительный is тоже знаю...)
В общем вопрос, как "грамотно" это сделать? ("грамотно" в кавычках - это я понимаю, что грамотно будет типа как было предложено отдельным классом для каждого типа датчика, но...)
Грамотно - через наследование классов
Создание тоже думаю не возникнут вопросы: типа
switch (typesens)
case dht:
dhts[n].sens=
new
DHT(dhtPins[n], dhtType[n]); break; - или так не пойдет?
case bmp; ... break;
case am: .... break;
Грамотно - через наследование классов
Это я знаю и понимаю. Буду стремиться к этому, но на данный момент хотелось бы узнать как нетипизированный указатель привязать к разного типа объектам и потом с ними работать. Спасибо
:( Т.е. то как я хочу это сделать - не получится. Только переделывание всего проекта с нуля всё и на отдельных классах? Или из-за моих "тупых" вопросов мне больше не стоит ждать помощи?(
:( Т.е. то как я хочу это сделать - не получится.
Сделал вот такой тестовый пример:
Работает. Вопрос: что плохого/хорошего в этом способе? Или работает - это просто мне повезло?)
Работает. Вопрос: что плохого/хорошего в этом способе?
с точки зрения синтаксиса языка - это допустимо, хотя и попахивает. Но с точки зрения обычной логики - это глупость. Зачем обьединять в одном классе термометр и серву, какой в этом смысл? Классы нужны для того.,чтобы проще работать с обьектами. А если при любом вызове метода вам придется насильно приводить тип сенсора либо к термометру либо к серве - зачем нужен такой общий класс. не проще ли пользоваться сразу классами термометра и сервы?
Зачем обьединять в одном классе термометр и серву, какой в этом смысл?
Дак тут смысл не в серве и термометре. Они - это что первое мне под руку попалось. Смысл данного кода в нетипизированном указателе и его приведении к нужному типу.
не проще ли пользоваться сразу классами термометра и сервы?
Скорее всего проще. На данном моменте моего проекта я это уже осознаю. Но переделывать с "нуля" пока не решаюсь. Но буду. Но и данный проект принес мне много нового и поучительного. Конкретно сейчас я понимаю, что если делать сначала то многие вещи нужно делать по другому. Но пусть здесь будет пока так. Возможно и следующий проект у меня не получится "грамотным", даже скорее всего не получится, но я разбираюсь в этом и стараюсь к этому (грамотному написанию) придти. Многие вещи я даже сейчас вижу как переделать в моем проекте, может потихоньку, не разом, но переделаю....
Спасибо что читаете и отвечаете на мои сообщения. Но жаль что уровень моих знаний пока не дотягивает до уровня ваших подсказок.
Зачем обьединять в одном классе термометр и серву, какой в этом смысл?
Вообще там будут только датчики (темпер/влаж) только разные. Изначально думал будут одного типа(DHT22) все, но оказалось, что у меня их несколько и все они разные(BME, AM ну и DHT). Поэтому вот это:
Хочу переделать вот в это:
Все одинаково, только вместо DHT * dht; будет void * dht;
Ну и по коду проделать некоторые изменения. Благо там их не должно быть много.
Это верный признак говнокода.
Я это не для выставки или соревнования делаю, даже не для продажи;). Более того мне было просто интересно это сделать. Я не программист... было лет 20 назад хобби, но уже все на столько забыл, да и в си (да еще и не под винду) это немного по другому... Хорошо хоть подсказываете и на путь истинный ставите. Не думайте что я к критике плохо отношусь. Спасибо.
посмотреть бы на список "признаков" говнокода.... ну чтоб стараться так не делать. :) Просто для кого-то работа с указателями - это нормально. Для меня - это кошмар. А кто-то понимает где нужно работать с указателями а где не нужно.
У меня данный проект не большой, всего-то около 900 строк.... Но думаю использовав нетипизированный указатель я малой кровью отредактирую его для использования разного типа датчиков. И в таком небольшом проекте скорее всего это будет безболезненно. Тем более что проект развиваться и меняться не будет.
Я бы сделал проще. Структуру с типом датчика, его идентифицирующим атрибутом и полем значения метрики. Потом в процедуре полинга, опираясь на тип и атрибут (для DHT это пин, к примеру), опрашивал датчик и выгружал полученное в поле значения метрики.
Я может это как-то всё понимаю по другому, может быть термины не правильно понимаю типа (поле значения метрики, процедура полинга...).... Но с другой стороны мне кажется что у меня в принципе почти так и сделано. В моем проекте есть три датчика. Сейчас вот как раз сделаю в структуру еще идентификатор датчика (константный) Исходя из него будет в начале создан и присвоен указателю dht нужный тип датчика (BME и AM по айтуси (I2C) т.е. им даже пин не нужно назначать, но с этим вопросов нет вообще) и далее в методе чтения так же исходя из типа считаю с трех датчиков с каждого в свои переменные структуры - данные с датчиков. Т.е. просто заполняется данными массив структур. А дальше в методе луп будет вызвана процедура Анализа данных (это в WorkChannelTimer())и затем процедура отрисовки экрана (Эх, вот ее мне точно нужно оптимизировать, разрослась дай боже...). Вот соб-но сам луп:
Все это суета сует. Просто три инстанса или три инстанса через указатели в массиве структур... Большого выигрыша ни по скорости, ни по размеру кода не будет. Динамически массив датчиков перестраиваться не будет, а без него указатели, кастинги и пр. - ментальные упражнения в попытке убить время.
Все может быть. Но так как у меня нет опыта в таких вещах, изначально думал, что массив - будет все упорядочено и легче работать. И оно может так и было бы если датчики все были одного типа.
А указатели, кастинги и убийство времени - это верно, я не отрицаю. Мне это было очень интересно в плане получения опыта.
Массив удобен для однотипных данных, обрабатываемых эквивалентно. Например - все температуры распечатать с 50ти датчиков. А когда в структуре разносол поштучный - то ее обработка раздувается похлеще живота программера в пятницу.
Хотите массив - заведите массив значений метрик. Хотя и там тоже наборы разноплановые... Красиво, в строчку, не выйдет, энивэй. Полезут уродливые кейсы, ифы.
Так в том и дело что у меня в структуре данные касаются только одного датчика, а по датчикам они однотипные, поэтому они в массиве. Чтение и наполнение данными структуры тоже однотипные для всех датчиков. А вот работа с этими данными уже будет для каждого датчика своя. И даже данные одного датчика могут использоваться в обработке данных с другого. У каждого датчика по два канала.
Например один датчик у меня установлен в кессоне. И вот его основная задача держать температуру выше ноля(точнее выше +2..2,5°С) (Первый канал) Подогрев воздуха - банально лампы накаливания две штуки по 200W. (две - на всякий случай если одна сгорит. Доступ в кессон зимой очень проблемный.) А второстепенная (второй канал) - это влажность. Включается вентилятор. И вот тут пригодится датчик с улицы. Если на улице высокая влажность то и нет смысла вертеть вентилятором.... как-то так. Но как обычно всех нюансов в одном сообщении не укажешь.
Там такие нюансы, что если низкая температура но еще не критичная что бы включить обогрев, но высокая влажность.... Вроде просто включаем вентилятор и все. Но нет, нужно сначала поднять температуру, а потом продуть все это дело.... В общем как-то так .... может я и занимаюсь фигней, но мне это просто интересно, и самое главное надеюсь будет полезно)
И вот его основная задача держать температуру выше ноля(точнее выше +2..2,5°С) (Первый канал) Подогрев воздуха - банально лампы накаливания две штуки по 200W.
Так-то кессон утеплен и по идее его греет скважина и температура не должна упасть ниже ноля. Но кессон не успели доделать как положено и вообще это первый опыт. Мало ли какие морозы будут зимой. А там труба, хоть и пвх, но... Поэтому я вспомнил про ардуину и решил немного подстраховаться в эту зиму. Заодно попробую возрадить хобби...)
Ну так я и понял, что у Вас много времени для выдумывания развесистых структур. Вместо заполнения двух переменных outdoorT и outdoorH готовы вертеть через три колена указатели на void.
Вы же не будете в цикле сравнивать температуру уличную и домовую. Налепите дерево if()-ов...
Впрочем, для того, чтобы осознать, что ООП - это не улучшающая приправа к любому блюду, нужна практика.
А то, что сейчас вижу - это оверинжиниринг.
Прошу прощения, но я не понял как можно данные (T и Н) с трех! датчиков сохранить в двух переменных??
Ну я имею ввиду простые типы типа Int... :)
Вы же не будете в цикле сравнивать температуру уличную и домовую. Налепите дерево if()-ов...
Как раз наоборот по массиву легче "бегать". Вот например как у меня "предобработка" данных с датчиков:
По моему удобно и ifы в меру надобности... Я не отрицаю и не спорю что я много не знаю и можно сделать все проще. Но надеюсь не забросить это дело и развиваться в этом направлении.
ООП - это не улучшающая приправа к любому блюду, нужна практика.
Практика - это тоже нужно. Тем более теорию я без практики вообще не понимаю.
Если посмотреть на мою структуру, то там избыточные данные, но это чисто для практики и моего любопытства... Например, посмотреть сколько раз за сутки включались лампы и сколько они горели по времени....
А так, да.... можно код сократить в разы...
Или Вы имели ввиду у каждого датчика по две переменные?
Тогда да, но.... я уже сказал, что избыточность данных по датчикам - это да, у меня много времени и любопытства :)