Как лучше сделать цикл?
- Войдите на сайт для отправки комментариев
Втр, 15/01/2019 - 15:36
Всем привет! В программирование новичок. Сейчас пишу программу на ардуино, которая должна при 95 градусах включать вентилятор, а при достяжении 90 градусов выключать его. По мимо этого есть и другие условия при которых должен включаться вентилятор.
Вот весь код
#include <DallasTemperature.h> #include <OneWire.h> //OLED #include "U8glib.h" //OLED int EngineT; int InsideT; int OutsideT; //OLED U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE|U8G_I2C_OPT_DEV_0); // I2C / TWI //OLED OneWire oneWire(A2); DallasTemperature sensors(&oneWire); DeviceAddress TempI = { 0x28, 0xFF, 0x65, 0x95, 0x50, 0x17, 0x4, 0x73 }; // адрес датчика DS18B20 28 FF 65 95 50 17 4 73 DeviceAddress TempO = { 0x28, 0xFF, 0xC2, 0x53, 0xC3, 0x17, 0x4, 0xED }; // адрес датчика DS18B20 28 FF C2 53 C3 17 4 ED DeviceAddress TempE = { 0x28, 0x37, 0xC3, 0x77, 0x91, 0x11, 0x2, 0x23 }; // адрес датчика DS18B20 28 37 C3 77 91 11 2 23 //OLED void draw(void) { // graphic commands to redraw the complete screen should be placed here u8g.setFont(u8g_font_unifont); u8g.setPrintPos(0, 20); u8g.print("Engine = "); u8g.print(EngineT); u8g.print("c"); u8g.setFont(u8g_font_unifont); u8g.setPrintPos(0, 40); u8g.print("Inside = "); u8g.print(InsideT); u8g.print("c"); u8g.setFont(u8g_font_unifont); u8g.setPrintPos(0, 60); u8g.print("Outside = "); u8g.print(OutsideT); u8g.print("c"); } //OLED void setup(){ sensors.begin(); sensors.setResolution(TempI, 10); sensors.setResolution(TempO, 10); sensors.setResolution(TempE, 10); Serial.begin(9600); pinMode(A1, OUTPUT); pinMode(A0, OUTPUT); digitalWrite (A0, LOW); pinMode(5, OUTPUT); digitalWrite (5, HIGH); pinMode(4, OUTPUT); digitalWrite (4, LOW); } void loop(void){ sensors.requestTemperatures(); EngineT = sensors.getTempC(TempE); Serial.print("Температура двигателя = "); Serial.println(EngineT); InsideT = sensors.getTempC(TempI); Serial.print("Температура в салоне = "); Serial.println(InsideT); OutsideT = sensors.getTempC(TempO); Serial.print("Температура на улице = "); Serial.println(OutsideT); //OLED u8g.firstPage(); do { draw(); } while( u8g.nextPage() ); // rebuild the picture after some delay delay(500); //OLED if (OutsideT < -50 || EngineT < -50 || InsideT < -50) //если температура одного из датчиков < 50 { analogWrite(A1, LOW); //выключаем питание } else if (EngineT >= 95) //если температура двигателя >= 95 градусов то { digitalWrite(A1, HIGH); //включаем питание } else if (OutsideT <= 10 && InsideT < 22) //если температура на улице <= 10 градусам и температура внутри < 22 градусов то { digitalWrite(A1, HIGH); //включаем питание } else { digitalWrite(A1, LOW); //выключаем питание } delay(2000); //ждем 2 сек }
Я попробывал сделать так
else if (EngineT >= 95) //если температура двигателя >= 95 градусов то { while (EngineT > 90) { sensors.requestTemperatures(); EngineT = sensors.getTempC(TempE); Serial.print("Температура двигателя = "); Serial.println(EngineT); digitalWrite(A1, HIGH); //включаем питание } }
В этом цикле есть проблема. Как только он запускается, то перестает отображаться температура на монтиоре, и приходится дополнительно в цикле получать температуру датчика, мне кажется, что это не правильно.
Подскажите пожалуйста как поправить данный скетч.
Гистерезис: https://helpiks.org/8-11314.html
условия повнимательнее задавайте и разберитесь , чем if отличается от else if. И не нужно никаких while будет.
loop ведь почти также как while крутится, дак зачем вам while тогда?
надеюсь вы поняли, почему добавив while, у вас перестала обновляться инфа на дисплее.
Честно говоря я не очень понимаю, как с помошью функции if можно выполнить нужное мне действие, т.к. при 95 и более градусах должен сработать вентилятор и он не должен отключаться до тех пор пока температура не станет <= 90 градусов, а оператор if двигается дальше по коду и начинает выполнять другие условия которые в свою очередь могут выключить или на оборот включить вентилятор при определенных условиях, а начав заново код температура уже упадет ниже 95 градусов и вентилятор не включится, т.к. условие будет не выполнено. Вот по этому я и сделал цикл с помощью While, за счет которого вентилятор будет крутиться до тех пор пока температура не станет <= 90 в не зависимости от других условий.
Ести ли какие-то другие варианты с помощью которых можно выполнить мою задачу? Например приостановить движение кода в loop до тех пор пока температура не станет <=90.
Читайте разъяснения, которые находятся по приведенной ссылке.
Надо вводить флаги, при достижении температуры 95 градусов устанавливать проверять на температуру ИЛИ установленный флаг, то реле работает, если температура упала ниже 90 градусов флаг сбросить и не будет тогда блокирующий циклов
Уберите ВСЕ else и опишите, что делать только с помощью if. Тем более, что вы управляете только одним пином. И не забудьте про гистерезис, как вам уже советовали.
Загоню в песочницу и побуду добрым феем, все таки код с первого раза вставил. Не оптимально, но работоспособно.
P/S Кстати, сейчас подключить не к чему. Если заменить конструкцию if-else с флагом на digitalWrite(pin, flag); работать будет?
To TC, и выкиньте нахрен свои делеи и далекие температуры с ними вместе. Во первых, они тоже блокирующие, во вторых, жрут лишних 2К программы. ИМХО.
Загоню в песочницу и побуду добрым феем, все таки код с первого раза вставил. Не оптимально, но работоспособно.
Ну вот, всю интригу убил :( А помучится? Хотя если ТС правильно применит эту программу - я за него порадуюсь. Значит понял человек.
Не совсем понятно зачем тут лишний флаг...
Загоню в песочницу и побуду добрым феем, все таки код с первого раза вставил. Не оптимально, но работоспособно.
P/S Кстати, сейчас подключить не к чему. Если заменить конструкцию if-else с флагом на digitalWrite(pin, flag); работать будет?
To TC, и выкиньте нахрен свои делеи и далекие температуры с ними вместе. Во первых, они тоже блокирующие, во вторых, жрут лишних 2К программы. ИМХО.
if (t >= 95) {включить вентилятор;}
if (t <= 90) {выключить вентилятор;}
// всё!
// и флаги нахрен.
if (t >= 95) {включить вентилятор;}
if (t <= 90) {выключить вентилятор;}
// всё!
Логично.))))
if (t <= 90) {выключить вентилятор;}
// всё!
ПС: У каждой задачи всегда есть гениальное и неправильное решение, и чаще и не одно. Вот это одно из них
Если включать прямой записью в порт, то еще надо посчитать, что экономнее, обрабатывать флаг или включать включенный.
Один байт ОЗУ точно экономим, и флеш тоже. А по тактам примерно то на то.
Помоему вы немного не понимаете или много не понимаете. Если вы включили вентилятор, он далее так и остаётся включенным. Не нужно его включать каждый проход цикла.
Если включать прямой записью в порт, то еще надо посчитать, что экономнее, обрабатывать флаг или включать включенный.
Один байт ОЗУ точно экономим, и флеш тоже. А по тактам примерно то на то.
Помоему вы немного не понимаете или много не понимаете. Если вы включили вентилятор, он далее так и остаётся включенным. Не нужно его включать каждый проход цикла.
Так чтобы не включать, придется анализировать, включен или нет. Добавить дополнительное условие или дрыгнуть впустую ногой, надо сильно считать и думать, неоднозначненько.
имхо, для ТС впустую дрыгами ногать не такая уж и важная дилемма на данном этапе, тем более он не подозревает о её существовании. Ему бы с условиями разобраться и с приоритетами условий.
if (t <= 90) {выключить вентилятор;}
// всё!
С флагом, как в коде bwn он тоже будет постоянно включать и выключать. В данном случае от применения флага нет никакого эффекта.
Я фигею с таких конструкций. Просто графомания какая-то...
1. Зачем глобальная переменная flag? Если она нужна, то она должна принадлежать исключительно объекту "вентилятор". Кстати, в случае порта Ардуино в ее качестве может быть исользован сам порт. Без использования оперативной памяти. Но это - вопрос реализации, которая внутреннее дело объекта/класса.
2. Одновременно именно класс (объект) должен решать, переключать "всегда" или только по изменению. witch в loop() (равно как и if на его месте) - абсолютно избыточен.
3. С какогго перепугу для переключения по булевой переменной используется switch? Общее правило: логические - всегда if, switch - только для целых, принимающих не менее трех значений. Неужели Вы предполагаете, что при работе над проектом bool у Вас постепеннь будет принимать все больше и больше значений?
в
Да-да, а в военное время косинус фи может достигать даже семи....
С флагом, как в коде bwn он тоже будет постоянно включать и выключать. В данном случае от применения флага нет никакого эффекта.
Ну, дык, я уже покаялся.(((
Ну, дык, я уже покаялся.(((
Так это я внимание квона пытаюсь обратить - малое надо решать малым, а не начинать выстраивать мозголомные конструкции, где не нужно, а потом отлаживать их неделями.
по ресурсу (digitalRead()+digitalWrite()) > digitalWrite(). А от повторной записи в порт никому не поплохеет, вобщем-то.
а если много портов диджиталВрайтим то, видимо, просто прямой записью в порт пользоваться и не париться.
А от повторной записи в порт никому не поплохеет, вобщем-то.
В общем, погонял разные варианты на digitalWrite с фиксацией времени. Вариант ВН где-то на 5-8% шустрее, но +116 байт флэша 2742/2858 (в тестовом коде). А замена float на byte, ускорило почти в четыре раза и флэш 2742/2604.))))
У меня простой вопрос, а не создает ли повторная запись в порт в момент записи какой-либо переходный процесс на пине вывода?
Это же легко проверить осциллографом: while(true) {digitalWrite(13,1); delay(500);}
С другой стороны: aVar = 0x01 не приводит же к тому, что aVar на один такт становится нулём ;)
ребята, вы тут спорите - А ТС давно свалил :) сказав напоследок, что его логика программы не может работать без while ^)
Вы тут все что-то очень интересное между собой обсуждаете, но ни какого дельно совета я так и не увидел. Большенство из вышеперечисленного было пременено до того как я написал сообшение на форум. Единственное что я не пробывал, это флаги, сегодня вечером попробую, посмотрю как будет работать.
Вы тут все что-то очень интересное между собой обсуждаете, но ни какого дельно совета я так и не увидел.
самый дельный совет был в самом начале - избавляйтесь от while
Чем заменить while - просто if-ами, или конструкцией с флагами, или кейсом - не так и важно, главное - с while ваш код верно работать не будет.
Цикл while - это практически всегда путь к блокирующему коду, а значит везде, где вы его применяете - вы будете сталкиваться с проблемой, что программа выполняет только одну задачу. совершенно забивая на другие
#22 и не мудрите никаких флагов.
Коллеги, мне кажется, здесь нет предмета для спора.
Вентилятор может быть подключен непосредственно к пину контроллера, может - к пину сдвигового регистра, а может - через радиоканал либо другую медленную линию связи передавать команду на включение/выключение другому контроллеру.
Прежде, чем решать задачу, следует провести ее декомпозицию.
И если эта декомпозиция будет выполнена правильно, то особенности способа передачи вентилятору команды окажутся в ведении исключительно объекта/класса, управляющего этим вентилятором.
Следовательно, эта особенность никак не должна учитываться в основной логике работы программы.
А это достигается решением, в котором указанный объект/класс постоянно "долбится" командами включения/выключенмия, а уже внутри класса принимается решение, тупо пропускать эту "долбежку" к исполнительному устройству, завести переменную для отслеживания текущего состояния, запрашивать текущее состояние у самого прибора, либо применять какие-либо методы оптимизации потока команд.
это достигается решением, в котором указанный объект/класс постоянно "долбится" командами включения выключенмия, а уже внутри класса принимается решение, тупопропускать эту "долбежку" к исполнительному устройству, завести переменную для отслеживания текущего состояния, запрашивать текущее состояние у самого прибора, либо применять какие-либо методы оптимизации потока команд.
это один из многих возможных вариантов, но не единственно верный.
Прелесть программирования в том и состоит, что почти любую задачу можно решить более чем одним способом.
Так что в вашем сообщении первая фраза была самой правильной :
- а остальное не так и важно :)
И всетаки.
Почему не
f (t >= 95) {включить вентилятор;}
if (t <= 90) {выключить вентилятор;}
Предложенный ув SLKH (см пост #10 )?
В чем проблема дергать пином? Тем более что когда вы дергаете одним пином вы по факту дергаете весь порт МК? Так для Atmega 168 PB (порт B) это 8 пинов микросхемы. И обращаясь к любому из пинов этого порта вы переписываете все остальные.
Прежде, чем решать задачу, следует провести ее декомпозицию.
Уважаемый andriano, думаю, что выражу мнение ряда присутствующих в теме писателей и читателей: декомпозиция легко проводится на подсознательном уровне при чтении кода в первом сообщении, анализе вопроса и сущности ветки ("песочница").
Не думаю, что в данном случае есть вероятность использования станций космической связи с TTL = 5 суток для включения вентилятора.
Несомненно, что настоящий специалист должен учесть все способы и уметь написать генерализованное решение, пользуясь классами, но заклинаю Вас - не привлекайте внимание квона, иначе мы все пожалеем. И не дай бог еще дойдет до автоматного программирования и мы будем погребены под массой постов со страшными функциями stand(), nOff() и nOn().
Это же легко проверить осциллографом: while(true) {digitalWrite(13,1); delay(500);}
С другой стороны: aVar = 0x01 не приводит же к тому, что aVar на один такт становится нулём ;)
Осциллографом можно и не увидеть...Такие вещи ловить надо триггером с защёлкой, ...есть у кого такой пробник?
И всетаки.
Почему не
f (t >= 95) {включить вентилятор;}
if (t <= 90) {выключить вентилятор;}
Предложенный ув SLKH (см пост #10 )?
В чем проблема дергать пином?
Другое дело, что действия "включить вентилятор" и "выключить вентилятор" отнюдь не предполагают обязательного "дергания пином".
Уважаемый andriano, думаю, что выражу мнение ряда присутствующих в теме писателей и читателей: декомпозиция легко проводится на подсознательном уровне при чтении кода в первом сообщении, анализе вопроса и сущности ветки ("песочница").
Но хочу заметить, что декомпозиция, даже проведенная на подсознательном уровне, продолжает оставаться неотъемлемым этапом решения задачи. Поэтому нет ничего предосудительного в том, чтобы в логическом рассуждении сделать на ней небольшой акцент.
Несомненно, что настоящий специалист должен учесть все способы и уметь написать генерализованное решение, пользуясь классами...
Задумался...
К типовому D-триггеру следует присобачивать на входе схему, которая проверяет актуальное и предыдущее состояние входа D и, если оно не изменилось, блоктрует очередной тактовый сигнал, дабы лишний раз не перезаписывать одно и то же.
Таким образом экономится ресурс микросхемы.
Куда обратиться за премией?
Задумался...
К типовому D-триггеру следует присобачивать на входе схему, которая проверяет актуальное и предыдущее состояние входа D и, если оно не изменилось, блоктрует очередной тактовый сигнал, дабы лишний раз не перезаписывать одно и то же.
Таким образом экономится ресурс микросхемы.
Куда обратиться за премией?
Странно это...
Обычно принято поступать наоборот.
Это же легко проверить осциллографом: while(true) {digitalWrite(13,1); delay(500);}
Осциллографом можно и не увидеть...Такие вещи ловить надо триггером с защёлкой, ...есть у кого такой пробник?
ТС, исходя из сказанного тобой в нулевом посте, совершенно не понятно, зачем ты добавил while. Ведь выше был какой то код. Что тебя в нём не устроило, ты так и не написал. Да, там косяки, но while то нахрена было добавлять?
А советы дельные тебе все уже дали, читай внимательнее. Про дискуссию о том, что за зря дёргать ногой, лучше не обращай внимание, в твоём случае это вообще не важно.
Таким образом экономится ресурс микросхемы.
Куда обратиться за премией?
В премии отказать - отсуствует новизна подхода :) Данный принцип давно используетсяв методе EEPROM.update()
Осциллографом можно и не увидеть...Такие вещи ловить надо триггером с защёлкой, ...есть у кого такой пробник?
Да прекрасно все ловится осциллографом. Естественно при условии n*(1 / Tимп) < Fмах осциллографа. Где n обычно равно 2м, но зависить от степени китайскости в определении максимальной рабочей часторы осциллографа.
аппаратное прерывание ардуино, пин 2 или 3, не?