Покритикуйте код
- Войдите на сайт для отправки комментариев
Вс, 16/02/2020 - 12:16
Здравствуйте, уважаемые форумчане.
Решил сделать себе маленькую домашнюю метеостанцию с часами. Посмотрите, если не сложно, код. Покритикуйте. Код собирал из примеров, честно говоря, первый раз. До этого только читал форум, учился общаться с ардуино и отдельными чипами. Буду рад любым замечаниям.
[code]
#include <stdint.h>
#include <Wire.h>
#include "SPI.h"
#include "SparkFunBME280.h"
#include <DS3231.h>
#include <LiquidCrystal_I2C.h>
BME280 mySensor;
DS3231 rtc(SDA, SCL);
LiquidCrystal_I2C lcd(0x27,16,2);
//Кнопка на 4 пине, подсветка на 10 пине
int regim=1;
int flag=0;
void setup() {
pinMode(10,OUTPUT);
pinMode(4,INPUT);
digitalWrite(4,HIGH);
Wire.begin();
lcd.init();
rtc.begin();
lcd.backlight();
mySensor.settings.commInterface = I2C_MODE;
mySensor.settings.I2CAddress = 0x76;
mySensor.settings.runMode = 3;
mySensor.settings.tStandby = 5;
mySensor.settings.filter = 0;
mySensor.settings.tempOverSample = 1;
mySensor.settings.pressOverSample = 1;
mySensor.settings.humidOverSample = 1;
mySensor.begin();
lcd.setCursor(0,0);
lcd.print(" MeteoChasy");
lcd.setCursor(0,1);
lcd.print(" Evgeniy v.03");
// The following lines can be commented out to use the values already stored in the DS1307
// rtc.setDOW(TUESDAY); // Set Day-of-Week to SUNDAY
// rtc.setTime(14,31, 0); // Set the time to 12:00:00 (24hr format)
// rtc.setDate(27, 03, 2018); // Set the date to October 3th, 2010
delay(5000);
lcd.clear();
}
void loop() {
if(digitalRead(4)==LOW&&flag==0)
{
regim++;
flag=1;
if(regim>5)
{
regim=1;
}
}
if(digitalRead(4)==HIGH&&flag==1)
{
flag=0;
}
if(regim==1)
{
analogWrite(10,255);
}
if(regim==2)
{
analogWrite(10,190);
}
if(regim==3)
{
analogWrite(10,120);
}
if(regim==4)
{
analogWrite(10,70);
}
if(regim==5)
{
analogWrite(10,0);
}
lcd.setCursor(0,0);
lcd.print(rtc.getTimeStr(FORMAT_SHORT ));
lcd.setCursor(8,0);
lcd.print(rtc.getDateStr(FORMAT_SHORT ));
lcd.setCursor(0,1);
float temp=mySensor.readTempC()-1.5;
lcd.print(temp,1);
lcd.print("'C");
lcd.setCursor(7,1);
lcd.print((uint8_t)mySensor.readFloatHumidity());
lcd.print("%");
lcd.setCursor(11,1);
int mmH=mySensor.readFloatPressure()/133;
lcd.print(mmH);
lcd.print("mm");
delay(1000);
}
[/code]

Всякий раз, когда ТС просил покритиковать код и я, сдуру, начинал это делать внимательно и добросовестно, заканчивалось одним и тем же - я оказывался мудаком, который прикапывается к мелочам, издевается над начинающими и подкармливает своё ненасытное ЧСВ за счёт новичка :-(и
ну если мелочь delay, то я согласен. Их много в программе.
ЕвгенийП. Зря Вы так. Я всегда с удовольствием читаю все Ваши посты, стараясь почерпнуть что-то новое и интересное для себя. Поэтому буду очень рад, если Вы посмотрите и посоветуете как будет лучше. А мы с Вами тезки.
Спасибо, уважаемый qwone. А как это исправить?
У Вас, все работает? Вас это устраивает? Тады зачем впустую телепонить? Будете делать следующий релиз, сами уберете ошибки опираясь на опыт и новые знания. ИМХО.
Вместо строк 18-19 лучше писать "INPUT_PULLUP", когда захотите притянуть кнопку к земле эта привычка убережет от непонятной ошибки в работе программы.
ну если мелочь delay, то я согласен. Их много в программе.
в loop всего один делей.
2 ТС - убрать его просто, см пример "блинк без делей"
Но есть еще скрытые - в библиотеке MySensors. Тут уже сложнее, придется писать работу с датчиками самому, без библиотеки
bwn. Спасибо.
b707. Спасибо, попробую убрать этот delay. Но работу с датчиком напрямую пока не осилил.
Изучить более современные концепции программирования. Конечно можно из свалки набрать говна и слепить себе дом. Но если Вы планируете уже на этом месте построить трехэтажный дом. Мол часть квартир сдать в аренду, то такой подход уже идет лесом.
qwone. Если я правильно Вас понимаю, Вы советуете не заниматься ерундой, а изучать нормальный язык программирования, правильно? Я согласен. Правда, возраст уже не тот, хотя для себя все равно интересно.
qwone. Если я правильно Вас понимаю, Вы советуете не заниматься ерундой, а изучать нормальный язык программирования, правильно? Я согласен. Правда, возраст уже не тот, хотя для себя все равно интересно.
Сразу встречный вопрос: и как оно работает?
Ну и по коду: если кнопка без дребезга, то система, похоже, будет работать (первое впечатление, всерьёз не разбирался. Если твой индикатор нормально управляется от ШИМ, естественно).
Если с дребезгом - возможны спецэффекты.
ну если мелочь delay, то я согласен. Их много в программе.
в loop всего один делей.
2 ТС - убрать его просто, см пример "блинк без делей"
Но есть еще скрытые - в библиотеке MySensors. Тут уже сложнее, придется писать работу с датчиками самому, без библиотеки
Это метеостанция, а не головка самонаведения противоракеты.
qwone. Спасибо.
SLKH. Работает, если честно, уже с октября. Индикатор от ШИМа работает нормально, яркость регулируется, спецэффектов пока не было. На кнопке, на контактах висит пленка 0,1 мкФ.
qwone. Спасибо.
SLKH. Работает, если честно, уже с октября. Индикатор от ШИМа работает нормально, яркость регулируется, спецэффектов пока не было. На кнопке, на контактах висит пленка 0,1 мкФ.
Вот на хрена их убирать-то? Чему они мешают?
Это метеостанция, а не головка самонаведения противоракеты.
SLKH - а с чего столько эмоций-то? :))) Меня спросили - я ответил.
В лупе делей на 1 секунду, а коде измерения температуры - еще 800мс. Что там в коде датчика давления - не в курсе, но весь луп примерно занимает 2 секунды. Для программы, в которой есть кнопки - это много, реакция на нажатие будет ощутимо тормозить
b707. Действительно, реакция на изменение яркости тормозит. Правда, для меня это не существенно, выставил комфортную и забыл. Но для того, чтобы такого не было в дальнейшем, я и хочу это переделать. Спасибо.
Вот на хрена их убирать-то? Чему они мешают?
Это метеостанция, а не головка самонаведения противоракеты.
SLKH - а с чего столько эмоций-то? :))) Меня спросили - я ответил.
В лупе делей на 1 секунду, а коде измерения температуры - еще 800мс. Что там в коде датчика давления - не в курсе, но весь луп примерно занимает 2 секунды. Для программы, в которой есть кнопки - это много, реакция на нажатие будет ощутимо тормозить
а дальше:
если обновлять инфу на дисплее раз в 5 - 10 минут (или раз в минуту, если важна индикация времени), то остального времени вполне хватит на кнопки;
которые в данной конструкции на самом деле не особо и нужны - установить один раз предпочтительное значение яркости ("выставил комфортную и забыл") или же добавить фоторезистор и изменять его в зависимости от внешнего освещения.
2 ТС - убрать его просто, см пример "блинк без делей"
А зачем? Программе ведь всё равно в это время нечем заниматься. Какая разница, будет она циклиться в loop или в том цикле, что в delay?
ЕвгенийП. А поподробней?
А зачем? Программе ведь всё равно в это время нечем заниматься. Какая разница, будет она циклиться в loop или в том цикле, что в delay?
Евгений, и Вы туда же?
Я уже обьяснил "зачем" - чтобы кнопки не тормозили.
Независимо от того, сколько в программе кнопок и как часто они нажимаются, хоть раз в год - я все равно писал бы луп так, чтобы его "оборот" занимал максимум 100мс, а не 2 сек. Тем более что в этом коде для этого надо - всего-то! -добавить одну переменную и две строки.
Я не понимаю, почему вы кинулись меня переубеждать? ТС хочет научиться писать правильно - так пусть учится. В этой программе может в этом и нет особого смысла, зато когда у него будет задача, действительно требующая оперативной реакции - оно получится "само"
Я уже обьяснил "зачем" - чтобы кнопки не тормозили.
А там чё и кнопки есть? Тогда сорри, я чёт не заметил - недостаточно внимательно смотрел :-(
Т.С,, а Вы с простейшего начните. У Вас переменные regim и flag используются только в одной функции - в loop. Так нафига, спрашивается им быть глобальными?
Часики инициализировать лучше всего использованием переменных системного времени виндовс на стадии прошивки, ссылку не помню
// наверно так? if (rtc.lostPower()) rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));b707,
Вы знаете, на что я обратил внимание (давно уже). Вот, у ТС, как он выразился, "маленькая" метеостанция с температурой, давлением, кнопками и часами. Я сейчас делаю, видимо, не просто "маленькую", а прямо-таки "нано" - в ней нет ни часов, ни давления, ни кнопок (акромя Reset) - есть только температура (правда, две - на улице и в доме). Прошивку пишет Ворота (он проспорил мне, тут в какой-то теме об этом уже говорилось).
Функциональность, как видите, намного меньше, чем у ТС. Так вот, прошивка написанная профессионалом, получилась около 800 строк (без низкоуровневой работы с экраном - считаем это "библиотекой"). И почему-то всегда так. У профи прошивки в разы больше по строкам, чем у новичков :-)
Кстати, коль скоро там нет кнопок и ничего нет вообще, он не стесняется насчёт delay там, где это нужно. Правда, между измерениями у него не delay, а глубокий power_down на 10 минут. Всё добро (atmega + nrf-PA + e-paper + даллас) вместе взятое укладывается в < 5 микроампер.
ЕвгенийП. Правильно?
#include <stdint.h> #include <Wire.h> #include "SPI.h" #include "SparkFunBME280.h" #include <DS3231.h> #include <LiquidCrystal_I2C.h> BME280 mySensor; DS3231 rtc(SDA, SCL); LiquidCrystal_I2C lcd(0x27,16,2); //Кнопка на 4 пине, подсветка на 10 пине void setup() { pinMode(10,OUTPUT); pinMode(4,INPUT); digitalWrite(4,HIGH); Wire.begin(); lcd.init(); rtc.begin(); lcd.backlight(); mySensor.settings.commInterface = I2C_MODE; mySensor.settings.I2CAddress = 0x76; mySensor.settings.runMode = 3; mySensor.settings.tStandby = 5; mySensor.settings.filter = 0; mySensor.settings.tempOverSample = 1; mySensor.settings.pressOverSample = 1; mySensor.settings.humidOverSample = 1; mySensor.begin(); lcd.setCursor(0,0); lcd.print(" MeteoChasy"); lcd.setCursor(0,1); lcd.print(" Evgeniy v.03"); // The following lines can be commented out to use the values already stored in the DS1307 // rtc.setDOW(TUESDAY); // Set Day-of-Week to SUNDAY // rtc.setTime(14,31, 0); // Set the time to 12:00:00 (24hr format) // rtc.setDate(27, 03, 2018); // Set the date to October 3th, 2010 delay(5000); lcd.clear(); } void loop() { int regim=1; int flag=0; if(digitalRead(4)==LOW&&flag==0) { regim++; flag=1; if(regim>5) { regim=1; } } if(digitalRead(4)==HIGH&&flag==1) { flag=0; } if(regim==1) { analogWrite(10,255); } if(regim==2) { analogWrite(10,190); } if(regim==3) { analogWrite(10,120); } if(regim==4) { analogWrite(10,70); } if(regim==5) { analogWrite(10,0); } lcd.setCursor(0,0); lcd.print(rtc.getTimeStr(FORMAT_SHORT )); lcd.setCursor(8,0); lcd.print(rtc.getDateStr(FORMAT_SHORT )); lcd.setCursor(0,1); float temp=mySensor.readTempC()-1.5; lcd.print(temp,1); lcd.print("'C"); lcd.setCursor(7,1); lcd.print((uint8_t)mySensor.readFloatHumidity()); lcd.print("%"); lcd.setCursor(11,1); int mmH=mySensor.readFloatPressure()/133; lcd.print(mmH); lcd.print("mm"); delay(1000); }RG22EM, Green
Если я правильно понял, это чтобы не канителиться каждый раз с выставлением времени?
RG22EM, Green
Если я правильно понял, это чтобы не канителиться каждый раз с выставлением времени?
да, лишь бы в компьютере шли правильно
Так вот, прошивка написанная профессионалом, получилась около 800 строк (без низкоуровневой работы с экраном - считаем это "библиотекой"). И почему-то всегда так. У профи прошивки в разы больше по строкам, чем у новичков :-)
не согласен с вами, причем категорически:) В своих программах я всегда стараюсь выкинуть повторы, написать код эффективнее, в том числе и по числу строк. По Вашей квалификации я получаюсь дремучий чайник, что может и недалеко от истины, но абидно :)
у меня есть подобный проект, тини85 + HC-12 + даллас - в программе 193 строки, не считая библиотек. Среднее потребление 42 мкА - вроде в 10 раз больше, чему Ворота. Но есть нюанс - мой сенсор отсылает данные раз в минуту.
RG22EM Понятно, спасибо.
Вот вариант без делей.
#include <stdint.h> #include <Wire.h> #include "SPI.h" #include "SparkFunBME280.h" #include <DS3231.h> #include <LiquidCrystal_I2C.h> BME280 mySensor; DS3231 rtc(SDA, SCL); LiquidCrystal_I2C lcd(0x27,16,2); //Кнопка на 4 пине, подсветка на 10 пине long previousMillis = 0; long interval = 1000; void setup() { pinMode(10,OUTPUT); pinMode(4,INPUT); digitalWrite(4,HIGH); Wire.begin(); lcd.init(); rtc.begin(); lcd.backlight(); mySensor.settings.commInterface = I2C_MODE; mySensor.settings.I2CAddress = 0x76; mySensor.settings.runMode = 3; mySensor.settings.tStandby = 5; mySensor.settings.filter = 0; mySensor.settings.tempOverSample = 1; mySensor.settings.pressOverSample = 1; mySensor.settings.humidOverSample = 1; mySensor.begin(); lcd.setCursor(0,0); lcd.print(" MeteoChasy"); lcd.setCursor(0,1); lcd.print(" Evgeniy v.03"); // The following lines can be commented out to use the values already stored in the DS1307 // rtc.setDOW(TUESDAY); // Set Day-of-Week to SUNDAY // rtc.setTime(14,31, 0); // Set the time to 12:00:00 (24hr format) // rtc.setDate(27, 03, 2018); // Set the date to October 3th, 2010 delay(5000); lcd.clear(); } void loop() { unsigned long currentMillis = millis(); if(currentMillis - previousMillis > interval) { previousMillis = currentMillis; int regim=1; int flag=0; if(digitalRead(4)==LOW&&flag==0) { regim++; flag=1; if(regim>5) { regim=1; } } if(digitalRead(4)==HIGH&&flag==1) { flag=0; } if(regim==1) { analogWrite(10,255); } if(regim==2) { analogWrite(10,190); } if(regim==3) { analogWrite(10,120); } if(regim==4) { analogWrite(10,70); } if(regim==5) { analogWrite(10,0); } lcd.setCursor(0,0); lcd.print(rtc.getTimeStr(FORMAT_SHORT )); lcd.setCursor(8,0); lcd.print(rtc.getDateStr(FORMAT_SHORT )); lcd.setCursor(0,1); float temp=mySensor.readTempC()-1.5; lcd.print(temp,1); lcd.print("'C"); lcd.setCursor(7,1); lcd.print((uint8_t)mySensor.readFloatHumidity()); lcd.print("%"); lcd.setCursor(11,1); int mmH=mySensor.readFloatPressure()/133; lcd.print(mmH); lcd.print("mm"); } }ЕвгенийП. Правильно?
Нет. Так она будет забывать значения, которые были при предыдущем вызове loop. Посмотрите подробности вот здесь.
#include <stdint.h> #include <Wire.h> #include "SPI.h" #include "SparkFunBME280.h" #include <DS3231.h> #include <LiquidCrystal_I2C.h> BME280 mySensor; DS3231 rtc(SDA, SCL); LiquidCrystal_I2C lcd(0x27,16,2); //Кнопка на 4 пине, подсветка на 10 пине long previousMillis = 0; long interval = 1000; void setup() { pinMode(10,OUTPUT); pinMode(4,INPUT); digitalWrite(4,HIGH); Wire.begin(); lcd.init(); rtc.begin(); lcd.backlight(); mySensor.settings.commInterface = I2C_MODE; mySensor.settings.I2CAddress = 0x76; mySensor.settings.runMode = 3; mySensor.settings.tStandby = 5; mySensor.settings.filter = 0; mySensor.settings.tempOverSample = 1; mySensor.settings.pressOverSample = 1; mySensor.settings.humidOverSample = 1; mySensor.begin(); lcd.setCursor(0,0); lcd.print(" MeteoChasy"); lcd.setCursor(0,1); lcd.print(" Evgeniy v.03"); // The following lines can be commented out to use the values already stored in the DS1307 // rtc.setDOW(TUESDAY); // Set Day-of-Week to SUNDAY // rtc.setTime(14,31, 0); // Set the time to 12:00:00 (24hr format) // rtc.setDate(27, 03, 2018); // Set the date to October 3th, 2010 delay(5000); lcd.clear(); } void loop() { unsigned long currentMillis = millis(); if(currentMillis - previousMillis > interval) { previousMillis = currentMillis; static int regim=1; static int flag=0; if(digitalRead(4)==LOW&&flag==0) { regim++; flag=1; if(regim>5) { regim=1; } } if(digitalRead(4)==HIGH&&flag==1) { flag=0; } if(regim==1) { analogWrite(10,255); } if(regim==2) { analogWrite(10,190); } if(regim==3) { analogWrite(10,120); } if(regim==4) { analogWrite(10,70); } if(regim==5) { analogWrite(10,0); } lcd.setCursor(0,0); lcd.print(rtc.getTimeStr(FORMAT_SHORT )); lcd.setCursor(8,0); lcd.print(rtc.getDateStr(FORMAT_SHORT )); lcd.setCursor(0,1); float temp=mySensor.readTempC()-1.5; lcd.print(temp,1); lcd.print("'C"); lcd.setCursor(7,1); lcd.print((uint8_t)mySensor.readFloatHumidity()); lcd.print("%"); lcd.setCursor(11,1); int mmH=mySensor.readFloatPressure()/133; lcd.print(mmH); lcd.print("mm"); } }Значит правильно так?
Вообще убрать delay() совсем несложно - например Вы хотите производить какое-нибудь действие раз в секунду. Тогда с помощью millis() отслеживаем эту секунду и тогда производим действие. По поводу DS датчиков - так вроде в последних библиотеках разделили запрос и ответ. Т.е. Вы послали запрос, подождали секунду (с помощью millis()) и запросили результат измерений. В остальное время контроллер должен опрашивать кнопки. Общий цикл измерение-выдача результата будет порядка 2-х секунд. На кнопки реакция мгновенная.
Проблема даже не убрать delay(), а перейти на программирование через автоматы.А вот здесь и полезет основная засада для новичков.
Проблема даже не убрать delay(), а перейти на программирование через автоматы.А вот здесь и полезет основная засада для новичков.
не стращай )))
А что стращать. Я не зря приводил метафору про дом. Так и здесь. Пока живет семья в одном доме замечательно. Но она увеличится. Пристроим веранду. А еще больше и так до разделение на множество семей. То получится простая коммуналка. Туалет и ванна одна на кучу народу. Один засел на толчке и писец. Машину поставил и дом перекрыт. Вот что бы такой хрени и не было так развилось программирование. И все это можно рационально и удобно разместить на одном камне.
А если не учитывать это то будет так
Ну, это если по уму. А если есть куча чужих delay, то свою кнопку можно и в прерывании обрабатывать.)
#include <stdint.h> #include <Wire.h> #include "SPI.h" #include "SparkFunBME280.h" #include <DS3231.h> #include <LiquidCrystal_I2C.h> BME280 mySensor; DS3231 rtc(SDA, SCL); LiquidCrystal_I2C lcd(0x27,16,2); //Кнопка на 4 пине, подсветка на 10 пине long previousMillis = 0; long interval = 1000; void setup() { pinMode(10,OUTPUT); pinMode(4,INPUT); digitalWrite(4,HIGH); Wire.begin(); lcd.init(); rtc.begin(); lcd.backlight(); mySensor.settings.commInterface = I2C_MODE; mySensor.settings.I2CAddress = 0x76; mySensor.settings.runMode = 3; mySensor.settings.tStandby = 5; mySensor.settings.filter = 0; mySensor.settings.tempOverSample = 1; mySensor.settings.pressOverSample = 1; mySensor.settings.humidOverSample = 1; mySensor.begin(); lcd.setCursor(0,0); lcd.print(" MeteoChasy"); lcd.setCursor(0,1); lcd.print(" Evgeniy v.03"); // The following lines can be commented out to use the values already stored in the DS1307 // rtc.setDOW(TUESDAY); // Set Day-of-Week to SUNDAY // rtc.setTime(14,31, 0); // Set the time to 12:00:00 (24hr format) // rtc.setDate(27, 03, 2018); // Set the date to October 3th, 2010 delay(5000); lcd.clear(); } void loop() { unsigned long currentMillis = millis(); if(currentMillis - previousMillis > interval) { previousMillis = currentMillis; static int regim=1; static int flag=0; if(digitalRead(4)==LOW&&flag==0) { regim++; flag=1; if(regim>5) { regim=1; } } if(digitalRead(4)==HIGH&&flag==1) { flag=0; } if(regim==1) { analogWrite(10,255); } if(regim==2) { analogWrite(10,190); } if(regim==3) { analogWrite(10,120); } if(regim==4) { analogWrite(10,70); } if(regim==5) { analogWrite(10,0); } lcd.setCursor(0,0); lcd.print(rtc.getTimeStr(FORMAT_SHORT )); lcd.setCursor(8,0); lcd.print(rtc.getDateStr(FORMAT_SHORT )); lcd.setCursor(0,1); float temp=mySensor.readTempC()-1.5; lcd.print(temp,1); lcd.print("'C"); lcd.setCursor(7,1); lcd.print((uint8_t)mySensor.readFloatHumidity()); lcd.print("%"); lcd.setCursor(11,1); int mmH=mySensor.readFloatPressure()/133; lcd.print(mmH); lcd.print("mm"); } }Значит правильно так?
Раз в секунду (хотя зачем так часто?) нужно только измерять параметры и выводить их на экран, а кнопки следует опрашивать при каждом проходе.
Значит правильно так?
Ну, Вы, блин, даёте!
Только что убрали две переменные из глобальных и тут же засунули туда две новые, которые ТОЖЕ используются только в одной функции.
Если я все правильно понял, должно быть так:
#include <stdint.h> #include <Wire.h> #include "SPI.h" #include "SparkFunBME280.h" #include <DS3231.h> #include <LiquidCrystal_I2C.h> BME280 mySensor; DS3231 rtc(SDA, SCL); LiquidCrystal_I2C lcd(0x27,16,2); //Кнопка на 4 пине, подсветка на 10 пине void setup() { pinMode(10,OUTPUT); pinMode(4,INPUT); digitalWrite(4,HIGH); Wire.begin(); lcd.init(); rtc.begin(); lcd.backlight(); mySensor.settings.commInterface = I2C_MODE; mySensor.settings.I2CAddress = 0x76; mySensor.settings.runMode = 3; mySensor.settings.tStandby = 5; mySensor.settings.filter = 0; mySensor.settings.tempOverSample = 1; mySensor.settings.pressOverSample = 1; mySensor.settings.humidOverSample = 1; mySensor.begin(); lcd.setCursor(0,0); lcd.print(" MeteoChasy"); lcd.setCursor(0,1); lcd.print(" Evgeniy v.03"); // The following lines can be commented out to use the values already stored in the DS1307 // rtc.setDOW(TUESDAY); // Set Day-of-Week to SUNDAY // rtc.setTime(14,31, 0); // Set the time to 12:00:00 (24hr format) // rtc.setDate(27, 03, 2018); // Set the date to October 3th, 2010 delay(5000); lcd.clear(); } void loop() { static int regim=1; static int flag=0; if(digitalRead(4)==LOW&&flag==0) { regim++; flag=1; if(regim>5) { regim=1; } } if(digitalRead(4)==HIGH&&flag==1) { flag=0; } if(regim==1) { analogWrite(10,255); } if(regim==2) { analogWrite(10,190); } if(regim==3) { analogWrite(10,120); } if(regim==4) { analogWrite(10,70); } if(regim==5) { analogWrite(10,0); } lcd.setCursor(0,0); lcd.print(rtc.getTimeStr(FORMAT_SHORT )); lcd.setCursor(8,0); lcd.print(rtc.getDateStr(FORMAT_SHORT )); long previousMillis = 0; long interval = 1000; unsigned long currentMillis = millis(); if(currentMillis - previousMillis > interval) { previousMillis = currentMillis; lcd.setCursor(0,1); float temp=mySensor.readTempC()-1.5; lcd.print(temp,1); lcd.print("'C"); lcd.setCursor(7,1); lcd.print((uint8_t)mySensor.readFloatHumidity()); lcd.print("%"); lcd.setCursor(11,1); int mmH=mySensor.readFloatPressure()/133; lcd.print(mmH); lcd.print("mm"); } }Переменная в строке №85 будет сохранять значение между вызовами? Думайте же, что делаете-то!
Извините не успел ответить.
Или должно быть так:
#include <stdint.h> #include <Wire.h> #include "SPI.h" #include "SparkFunBME280.h" #include <DS3231.h> #include <LiquidCrystal_I2C.h> BME280 mySensor; DS3231 rtc(SDA, SCL); LiquidCrystal_I2C lcd(0x27,16,2); //Кнопка на 4 пине, подсветка на 10 пине void setup() { pinMode(10,OUTPUT); pinMode(4,INPUT); digitalWrite(4,HIGH); Wire.begin(); lcd.init(); rtc.begin(); lcd.backlight(); mySensor.settings.commInterface = I2C_MODE; mySensor.settings.I2CAddress = 0x76; mySensor.settings.runMode = 3; mySensor.settings.tStandby = 5; mySensor.settings.filter = 0; mySensor.settings.tempOverSample = 1; mySensor.settings.pressOverSample = 1; mySensor.settings.humidOverSample = 1; mySensor.begin(); lcd.setCursor(0,0); lcd.print(" MeteoChasy"); lcd.setCursor(0,1); lcd.print(" Evgeniy v.03"); // The following lines can be commented out to use the values already stored in the DS1307 // rtc.setDOW(TUESDAY); // Set Day-of-Week to SUNDAY // rtc.setTime(14,31, 0); // Set the time to 12:00:00 (24hr format) // rtc.setDate(27, 03, 2018); // Set the date to October 3th, 2010 delay(5000); lcd.clear(); } void loop() { static int regim=1; static int flag=0; if(digitalRead(4)==LOW&&flag==0) { regim++; flag=1; if(regim>5) { regim=1; } } if(digitalRead(4)==HIGH&&flag==1) { flag=0; } if(regim==1) { analogWrite(10,255); } if(regim==2) { analogWrite(10,190); } if(regim==3) { analogWrite(10,120); } if(regim==4) { analogWrite(10,70); } if(regim==5) { analogWrite(10,0); } lcd.setCursor(0,0); lcd.print(rtc.getTimeStr(FORMAT_SHORT )); lcd.setCursor(8,0); lcd.print(rtc.getDateStr(FORMAT_SHORT )); static long previousMillis = 0; long interval = 1000; unsigned long currentMillis = millis(); if(currentMillis - previousMillis > interval) { previousMillis = currentMillis; lcd.setCursor(0,1); float temp=mySensor.readTempC()-1.5; lcd.print(temp,1); lcd.print("'C"); lcd.setCursor(7,1); lcd.print((uint8_t)mySensor.readFloatHumidity()); lcd.print("%"); lcd.setCursor(11,1); int mmH=mySensor.readFloatPressure()/133; lcd.print(mmH); lcd.print("mm"); } }Подписался
... И почему-то всегда так. У профи прошивки в разы больше по строкам, чем у новичков :-)
не согласен с вами, причем категорически:) В своих программах я всегда стараюсь выкинуть повторы, написать код эффективнее, в том числе и по числу строк. По Вашей квалификации я получаюсь дремучий чайник, что может и недалеко от истины, но абидно :)
Вопрос на самом деле не столь очевидный.
Действительно, добрую половину публикуемых здесь программ новичков на 400 строк, можно легко свести к 30, используя массивы и циклы.
Но есть и другая сторона медали: профессионал делает гораздо больше проверок и предусматривает все варианты, в том числе и те, которые, на взгляд новичка, никогда не случатся.
Ну и простота поддержки кода (и его повторного использования) тоже немного увеличивают его объем (осмысленные (читай: длинные) названия переменных; стремление все, что можно, записать в виде предопределенных констант; комментарии; ООП ... ).
Так вот, прошивка написанная профессионалом, получилась около 800 строк (без низкоуровневой работы с экраном - считаем это "библиотекой"). И почему-то всегда так. У профи прошивки в разы больше по строкам, чем у новичков :-)
не согласен с вами, причем категорически:) В своих программах я всегда стараюсь выкинуть повторы, написать код эффективнее, в том числе и по числу строк. По Вашей квалификации я получаюсь дремучий чайник, что может и недалеко от истины, но абидно :)
Понимаешь, в чём дело: не всё так просто и очевидно. Я разумею, что Евгений вёл речь не о тупых повторах и эффективном коде, от слова "совсем". Так-то даже чайнику понятно, что если можно сделать декомпозицию и тем самым избавиться от повторяемого кода (просто как пример юзкейса) - то это надо делать.
Однако, в серьёзных рабочих проектах есть такое понятие, как архитектурный слой. А это, как минимум - обязывает. Обязывает выделять сущности, предусматривать между ними взаимодействие, и т.д. и т.п. Плюс - те же юнит-тесты, например. Плюс - отладочная информация, которую тоже надо делать настраиваемой, хотя бы по какому-нибудь условному Level (как пример - просто дефайны, по которым собирается прошивка с той или иной отладочной информацией).
Вот и получается, что рабочий код - это рабочий код. А вспомогательные вещи - они тоже строчки кода занимают, хотя на этапе продакшена в прошивку и не попадают, вообще.
Ну и, что касается примера из жизни (сейчас вожусь как раз): Android Studio, если хочешь сделать публичный enum или класс - рвёт и мечет, требует отдельного файла. Архитектурно это - очень правильно, очень. А файл лишний - есть. Ещё там можно документировать код комментариями сразу - тоже строчки кода.
Вот и имеем, что отличие прошивки любителя и профи - не в строчках кода (кто их считает) - а в подходе к работе.
Вот щас для интереса посмотрел публичный вариант проекта на гитхабе (а закрытый - поболее будет уже, за сотню тысяч строк давно), и вот что получил:
[ { "language": "C++", "files": "87", "lines": "52157", "blanks": "8657", "comments": "8277", "linesOfCode": "35223" }, { "language": "JavaScript", "files": "19", "lines": "33671", "blanks": "5202", "comments": "4068", "linesOfCode": "24401" }, { "language": "C/C++ Header", "files": "115", "lines": "18254", "blanks": "3107", "comments": "4438", "linesOfCode": "10709" }, { "language": "PHP", "files": "108", "lines": "11502", "blanks": "1699", "comments": "3399", "linesOfCode": "6404" }, { "language": "C", "files": "10", "lines": "5536", "blanks": "19", "comments": "61", "linesOfCode": "5456" }, { "language": "CSS", "files": "4", "lines": "3032", "blanks": "169", "comments": "160", "linesOfCode": "2703" }, { "language": "Markdown", "files": "3", "lines": "271", "blanks": "50", "comments": "0", "linesOfCode": "221" }, { "language": "Plain Text", "files": "27", "lines": "202", "blanks": "66", "comments": "0", "linesOfCode": "136" }, { "language": "XML", "files": "1", "lines": "88", "blanks": "0", "comments": "0", "linesOfCode": "88" }, { "language": "Batch", "files": "1", "lines": "1", "blanks": "0", "comments": "0", "linesOfCode": "1" }, { "language": "INI", "files": "1", "lines": "0", "blanks": "0", "comments": "0", "linesOfCode": "0" }, { "language": "Total", "files": "376", "lines": "124714", "blanks": "18969", "comments": "20403", "linesOfCode": "85342" } ]На С++ - 35223 (без комментов и пустых строк), в заголовочниках: 10709 строк, всего в проекте - 85342 строк, плюс 20403 строк комментариев.
Сколько строк сможешь сэкономить, переписав? :)))))
А такой вариант - не?
#include <stdint.h> #include <Wire.h> #include "SPI.h" #include "SparkFunBME280.h" #include <DS3231.h> #include <LiquidCrystal_I2C.h> BME280 mySensor; DS3231 rtc(SDA, SCL); LiquidCrystal_I2C lcd(0x27,16,2); byte const svet = 10; byte const knopka = 4; #define knopkaON digitalRead(knopka)==LOW // нажата #define knopkaOFF digitalRead(knopka)==HIGH // не нажата void brightness(); void disp(); void setup() { pinMode(svet,OUTPUT); pinMode(knopka,INPUT_PULLUP); Wire.begin(); lcd.init(); rtc.begin(); lcd.backlight(); mySensor.settings.commInterface = I2C_MODE; mySensor.settings.I2CAddress = 0x76; mySensor.settings.runMode = 3; mySensor.settings.tStandby = 5; mySensor.settings.filter = 0; mySensor.settings.tempOverSample = 1; mySensor.settings.pressOverSample = 1; mySensor.settings.humidOverSample = 1; mySensor.begin(); lcd.setCursor(0,0); lcd.print(" MeteoChasy"); lcd.setCursor(0,1); lcd.print(" Evgeniy v.03"); delay(5000); lcd.clear(); } void loop() { brightness(); disp(); } void brightness() { static byte regim=1; static byte flag=0; if(knopkaON && flag==0) { regim++; flag=1; if(regim>5) { regim=1; } } if(knopkaOFF && flag==1) { flag=0; } switch (regim) { case 1: analogWrite(svet,255); break; case 2: analogWrite(svet,190); break; case 3: analogWrite(svet,120); break; case 4: analogWrite(svet,70); break; case 5: analogWrite(svet,0); break; } } void disp() { const unsigned long interval = 60000; // Раз в минуту или как нравится static unsigned long previousMillis = 0; if (millis() - previousMillis > interval) { previousMillis = millis(); { lcd.setCursor(0,0); lcd.print(rtc.getTimeStr(FORMAT_SHORT )); lcd.setCursor(8,0); lcd.print(rtc.getDateStr(FORMAT_SHORT )); lcd.setCursor(0,1); float temp=mySensor.readTempC()-1.5; lcd.print(temp,1); lcd.print("'C"); lcd.setCursor(7,1); lcd.print((uint8_t)mySensor.readFloatHumidity()); lcd.print("%"); lcd.setCursor(11,1); int mmH=mySensor.readFloatPressure()/133; lcd.print(mmH); lcd.print("mm"); } } }Да уж правильно сказал ЕвгенийП.
Попросили меня как то скетч поправить для устройства отсечки оборотов двигателя.
Изначально было строк 10кода и работало, через pulseIn().
В итоге получилось такое:
Одна из вариации итоговой программы , всего их было штук 15
/* значения таймера для разных оборотов RPM3000_TIME=10000мкс=2500тиков RPM4000_TIME=7500мкс=1875тиков RPM5000_TIME=6000мкс=1500тиков RPM6000_TIME=5000мкс=1250тиков один тик таймера 4мкс */ #include <EEPROM.h> #include <avr/interrupt.h>//библиотека прерываний по таймеру #include <Arduino.h> #define RPM3000_TIME 2500 #define RPM4000_TIME 1875 #define RPM5000_TIME 1500 #define RPM6000_TIME 1250 #define output 5 //выходной пин отсечки #define modeSet 4 //пин кнопки выбор режима #define clutchPin A0 #define switch1 6 #define switch2 7 #define switch3 8 #define switch4 9 #define switch5 10 #define switch6 11 #define modeLedPin 3 int miss_cycles=0;//переменная для отсчета поопусков цикла #define PASSVALUE 2//количество циклов, которое будем пропускать #define HM_rpm3000_pause1 15000 #define HM_rpm3000_pause2 4000 #define HM_rpm4000_pause1 7500 #define HM_rpm4000_pause2 3000 #define HM_rpm5000_pause1 6000 #define HM_rpm5000_pause2 2400 #define HM_rpm6000_pause1 2000 #define HM_rpm6000_pause2 1600 #define SM_rpm3000_pause1 15000 #define SM_rpm3000_pause2 4000 #define SM_rpm4000_pause1 7500 #define SM_rpm4000_pause2 3000 #define SM_rpm5000_pause1 6000 #define SM_rpm5000_pause2 2400 #define SM_rpm6000_pause1 2000 #define SM_rpm6000_pause2 1600 //#define PASS_ON #define BUGFIX //константы работы с кнопкой //паузы рабочего режима 2 long work_pause1,work_pause2; byte work_mode_1_2; volatile boolean cut=0; byte pin_num=142; enum BtnState{ RELEASE, SHORT, LONG}; class btn//создадим класс кнопок {public://общие функции int key(int pin); private://личные переменные и функции класса unsigned long start_press=0;//переменная времени нажатия кнопки unsigned long pressTime=0;//переменная длительности нажатия кнопки boolean pressFlag=0;//переменная флага нажатия //переменные состояния/временного состояния/нажатия кнопки byte num=0,_num=0,button=0; }; uint32_t timer=0;//переменная мигания светодиода btn Btn1; byte MODE=1; //========================= //функция класса Btn(обработчик кнопок) int btn::key(int Sb){ button=!digitalRead(Sb);//читаем состояние кнопки if(!button){num=0;}//если кнопка отпущена, выдаем результат 0 if(button&&!pressFlag)//если кнопка нажата и флаг опущен {pressTime=millis()-start_press;//считаем время нажатия кнопки if(millis()-start_press>=2000){//если нажатие больше 2 сек pressFlag=1;//поднимаем флаг num=2;//значение кнопки 2 pressTime=0;//сбрасываем длительность нажатия } } if(!button){//если кнопка отпущена start_press=millis();//сбрасываем время нажатия pressFlag=0;//опускаем флаг } if(!button&&!pressFlag){//если кнопка и флаг отпущены if(pressTime>50&&pressTime<2000)//а время нажатия больше 50мс, но меньше 2сек {pressTime=0;//сбрасываем длительность нажатия num=1;}//значение кнопки 1 } _num=num; num=0; return _num;//возвращаем значение кнопки } //========================= uint32_t now_millis=millis(); volatile bool cutoff_flag=0,check_flag; uint16_t counter_work; unsigned long blink_time; enum WORKMODE{NORMAL_MODE=1,MODE_RPM3000,MODE_RPM4000,MODE_RPM5000,MODE_RPM6000}; byte KEY; //===============ФУНКЦИИ=========== //в режиме работа функция выполняемая по достижению счетчиком значения сравнения ISR(TIMER1_COMPA_vect){ cli();//запрещаем прерывания TCNT1=0;//сбрасываем счетчик check_flag=0;//опускаем флаг sei(); //разрешаем прерывания } //по внешнему прерыванию void work_count(){ cli();//отключаем прерывания TCNT1=0;//сбрасываем значение счетчика if(check_flag){//если флаг проверки поднят cutoff_flag=1;}//поднимаем флаг отсечки check_flag=1;//поднимаем флаг проверки /*принцип работы: при каждом сигнале с датчика, поднимаем флаг что сигнал пришел, если не успеем его сбросить прерыванием по таймеру, то тогда отсечка*/ cut=1; sei();//включаем прерывания } void check_mode(){ switch(work_mode_1_2){ case 0: if(!digitalRead(switch1)){MODE=NORMAL_MODE;} if(!digitalRead(switch2)){MODE=MODE_RPM3000;OCR1A=RPM3000_TIME; work_pause1=SM_rpm3000_pause1; work_pause2=SM_rpm3000_pause2; } if(!digitalRead(switch3)){MODE=MODE_RPM4000;OCR1A=RPM4000_TIME; work_pause1=SM_rpm4000_pause1; work_pause2=SM_rpm4000_pause2;} if(!digitalRead(switch4)){MODE=MODE_RPM5000;OCR1A=RPM5000_TIME; work_pause1=SM_rpm5000_pause1; work_pause2=SM_rpm5000_pause2;} if(!digitalRead(switch5)){MODE=MODE_RPM6000;OCR1A=RPM6000_TIME; work_pause1=SM_rpm6000_pause1; work_pause2=SM_rpm6000_pause2; } break; case 1: if(!digitalRead(switch1)){MODE=NORMAL_MODE;} if(!digitalRead(switch2)){MODE=MODE_RPM3000;OCR1A=RPM3000_TIME; work_pause1=HM_rpm3000_pause1; work_pause2=HM_rpm3000_pause2; } if(!digitalRead(switch3)){MODE=MODE_RPM4000;OCR1A=RPM4000_TIME; work_pause1=HM_rpm4000_pause1; work_pause2=HM_rpm4000_pause2;} if(!digitalRead(switch4)){MODE=MODE_RPM5000;OCR1A=RPM5000_TIME; work_pause1=HM_rpm5000_pause1; work_pause2=HM_rpm5000_pause2;} if(!digitalRead(switch5)){MODE=MODE_RPM6000;OCR1A=RPM6000_TIME; work_pause1=HM_rpm6000_pause1; work_pause2=HM_rpm6000_pause2; } break; } #ifdef BUGFIX Serial.print("mode= "); Serial.println(MODE); #endif } #ifdef PASS_ON void PASS(){ if(cut&&!cutoff_flag){ digitalWrite(output,1); delayMicroseconds(work_pause2); digitalWrite(output,0); cut=0; } if(cutoff_flag){//если флаг отсечки поднят if(!miss_cycles){//если не надо пpопускать циклы miss_cycles=PASSVALUE; if(digitalRead(2)){//ждем сигнала с пина 2 digitalWrite(output,1);//включаем delayMicroseconds(work_pause2);//даем задержку на выключение digitalWrite(output,0);//выключаем } }//опускаем флаг отсечки else{//если надо пропускать miss_cycles--; } } cutoff_flag=0;cut=0; }//end PASS func #else void PASS(){ if(cutoff_flag){//если флаг отсечки поднят if(digitalRead(2)){//ждем сигнала с пина 2 delayMicroseconds(work_pause1);//даем задержку на включение digitalWrite(output,1);//включаем delayMicroseconds(work_pause2);//даем задержку на выключение digitalWrite(output,0);//выключаем cut=0; } cutoff_flag=0;}//опускаем флаг отсечки else{//а если флаг отсечки опущен if(cut&&!cutoff_flag){ digitalWrite(output,digitalRead(2));}}//то просто ретранслируем сигнал с пина 2 на пин выхода } #endif void SHIFT(){ if(cutoff_flag){//если флаг отсечки поднят if(digitalRead(2)){//ждем сигнала с пина 2 delayMicroseconds(work_pause1);//даем задержку на включение digitalWrite(output,1);//включаем delayMicroseconds(work_pause2);//даем задержку на выключение digitalWrite(output,0);//выключаем cut=0; } cutoff_flag=0;}//опускаем флаг отсечки else{//а если флаг отсечки опущен if(cut&&!cutoff_flag){ digitalWrite(output,digitalRead(2));}}//то просто ретранслируем сигнал с пина 2 на пин выхода }//end SHIFT func void WORK_FUNC(){ if(KEY==SHORT){ work_mode_1_2=!work_mode_1_2; check_mode(); } if(MODE==NORMAL_MODE||!digitalRead(clutchPin)){digitalWrite(output,digitalRead(2)); digitalWrite(modeLedPin,0); }else{ switch(work_mode_1_2){ case 0:PASS(); digitalWrite(modeLedPin,1); break; case 1:SHIFT(); if(millis()-blink_time>=500){ blink_time=millis(); digitalWrite(modeLedPin,!digitalRead(modeLedPin)); } break;}//end switch }//end else }//end func //цикл настройки void setup(){ if(EEPROM.read(55)!=pin_num){ while(1){ digitalWrite(output,digitalRead(2)); KEY=Btn1.key(modeSet); if(KEY==1)digitalWrite(modeLedPin,!digitalRead(modeLedPin)); } } #ifdef BUGFIX Serial.begin(9600); #endif pinMode(output,OUTPUT);//настроим пин отсечки как выход pinMode(modeSet,INPUT_PULLUP);//пин кнопки как вход с подтяжкой к +5в pinMode(clutchPin,INPUT_PULLUP); pinMode(modeLedPin,OUTPUT); for(int i=switch1;i<=switch6;i++) {pinMode(i,0x2);} attachInterrupt(0,work_count,RISING);//на внешнее прерывание назначаем функцию work_count() TCCR1A=0;//сбрасываем настройки таймера 1А TCCR1B=0;// сбрасыва��м настройки таймера 1В TCNT1=0;//сбрасываем счетчик //Устанавливаем источник тактов -> 1/(16000000/64)* 256 = 1 мс TCCR1B =(1<<CS00)|(1<<CS01); //check_mode(); TIMSK1|=(1<<OCIE1A);//настроим таймер на сравнение digitalWrite(modeLedPin,work_mode_1_2); }//end setup //основной цикл void loop(){ KEY=Btn1.key(modeSet);//опросим кнопку и ее значение присвоим переменной KEY if(digitalRead(MODE+5)){ check_mode() ; } WORK_FUNC(); }//конец основного циклаТеперь по замечаниям:
1.ТС изучай типы данных. А не тупо из примеров Недалеких, а-ля гивер копируй. Не нужен однобайтовой переменной flag тип int, а вот boolean самое оно. То же самое с regim, byte сгодится вполне.
2. При конфигурации пинов можно сразу указать что нужна подтяжка по высокому уровню, указав в качестве второго аргумента функции pinMode, значение INPUT_PULLUP.
3. Все значения режимов поместить в один массив и скважность задавать обращаясь к нужному элементу массива:
byte pwm_regim[5]={20,50,100,150,255};
AnalogWrite(pin,pwm_regim[regim]);
Половина портянки сразу свернётся до одной строки.
4. delay() убирать тут в принципе необязательно, достаточно сократить до 50мс, будет в качестве дребезга выступать.
5.обновление информации на экране выполнять либо когда данные изменились, либо раз в 0.5-1сек через миллис. Ну до кучи можно ещё разделитель использовать ":" между часами/минутами и мыргать им раз в полсекунды.
Покритикуйте код
Вспомнилась "критика бегуна" из из известного фильма - «Как то он не концептуально пробежал ... да пошёл ты в жопу!»