Официальный сайт компании Arduino по адресу arduino.cc
Управление для аквариума
- Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии
Вс, 26/02/2017 - 20:13
Помогите новичку. Пишу простой скетч первый раз вчера и сегодня. Было много проблем на программном уровне, разобрался. Скетч работает, но есть одна непонятка.
Вот скетч
[code] // Date and time functions using a DS1307 RTC connected via I2C and Wire lib #include <Wire.h> #include "RTClib.h" RTC_DS1307 rtc; const int rele_sv = 3; const int rele_bul = 2; const int button_bul = 9; //int btn_bul = 0; unsigned long nowBtn = 0; //char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; void setup () { while (!Serial); // for Leonardo/Micro/Zero Serial.begin(57600); pinMode(rele_sv, OUTPUT); digitalWrite(rele_sv, LOW); pinMode(rele_bul, OUTPUT); digitalWrite(rele_bul, LOW); pinMode (button_bul, INPUT); if (! rtc.begin()) { Serial.println("Couldn't find RTC"); while (1); } // rtc.adjust(DateTime(2017, 2, 24, 17, 32, 0)); if (! rtc.isrunning()) { Serial.println("RTC is NOT running!"); // following line sets the RTC to the date & time this sketch was compiled // rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); // This line sets the RTC with an explicit date & time, for example to set // January 21, 2014 at 3am you would call: //rtc.adjust(DateTime(2016, 2, 24, 17, 17, 0)); } } void loop () { DateTime now = rtc.now(); //Получили текущее время int btn_bul = digitalRead(button_bul); //Считали состояние кнопки Serial.print(now.hour(), DEC); // Время в монитор Serial.print(':'); Serial.print(now.minute(), DEC); Serial.print(':'); Serial.print(now.second(), DEC); Serial.println(); if ((now.hour() == 6) && (now.minute() == 50)) { //Если 6:50 включили реле света и компресора digitalWrite(rele_sv, LOW); digitalWrite(rele_bul, LOW); }; if ((now.hour() == 21) && (now.minute() == 0)) { // Если 21:00 выключили реле света и компресора digitalWrite(rele_sv, HIGH); digitalWrite(rele_bul, HIGH); }; // if (((now.hour() >= 6) && (now.minute() >= 50)) || ((now.hour() <= 21) && (now.minute() <= 0))) { // Здесь не сработала проверка нажатия кнопки только между 6:50 и 21:00 if (btn_bul == 1) { //Если нажата кнопка должны получить время в секундах с 0:0:0 nowBtn = (int(now.hour())*3600) + (now.minute()*60) + now.second(); //но получается какая то хрень в 19:54:48 получаем 6149 }; // }; if ((((int(now.hour()) * 3600) + (now.minute() * 60) + now.second())-nowBtn)<1200) { // если разница между полученным значением и текущим меньше 20 минут отключаем компрессор (кормим рыбок) digitalWrite(rele_bul, HIGH); } else { digitalWrite(rele_bul, LOW); }; Serial.print(btn_bul); // выводим статус нажатия кнопки Serial.println(); Serial.print(nowBtn); //выводим значение переменной nowBtn Serial.println(); delay(3000); } [/code]
Непонятно как считается переменная nowBtn, в коментах описано.
вот пример
какая то хрень в 19:54:48 получаем 6149
по идее должно быть 19*3600+54*60+48=71697, а в монитор выводится 6149. Не могу понять почему.
Помогите.
Переполнение интегер , макс. 64536. Попробуйте
nowBtn =
(now.hour()*3600UL) + (now.minute()*60) + now.second();
//но
Спасибо помогло.
Теперь бы еще понять как такое произошло на будущее.
Я так понимаю UL преобразует к unsigned long
2Волшебник: 32767. А unsigned int 65535.
Спасибо помогло.
Теперь бы еще понять как такое произошло на будущее.
Я так понимаю UL преобразует к unsigned long
И ещё у авр-гсс есть старый хитрый баг, если сделать uint32_t proizvedenie = (uint16_t A) x (uint16_t B) то результат с больший долей вероятности будет неверный, потому что сначала произведение посчитается как 16-бит а уже потом присвоится на 32-бита. Поэтому, если есть сомнения всегда лучше указать компилёру 32-битную операцию, путём подстановки UL в названии константы, или принудителным кастингом (uint32_t) для переменной. uint32_t proizvedenie = ((uint32_t)(uint16_t A)) x (uint16_t B)
2Волшебник: 32767. А unsigned int 65535.
Волшебник, это не старый хитрый баг, это правило вычисления, принятое в языке. Другое дело, что на 32-разрядных процессорах никто специально обнулять старшие 16 битов 32-разрядного регистра не будет, поэтому с большой вероятностью вычисления приведут к желаемому результату.
Общее же правило - результат зависит от типа операндов. Правда, есть исключение: промежуточные результаты всегда не менее 16 разрядов. Поэтому, например, можно сдвинуть байт на 8 разрядов и они не пропадут.
А если баг запротоколировать то он становится принятым правилом? Я честно скажу, стндарты не читаю, там же что угодно написать витееватым пейсательским языком можно. А потом перевести неакуратно. Я сошлюсь на авр-гсс
1. Ну, как бы приведенные 9 вариантов - это как раз запротоколированное творчество программистов. А по стандарту 16х16 допускается быть 16. Т.е. если программисту нужно, чтобы было 32, он (и именно он) должен об этом позаботиться.
2. Тогда 32х32 тоже запретить.
3. Весь Си - одна большая диверсия.
А по стандарту 16х16 допускается быть 16. Т.е. если программисту нужно, чтобы было 32, он (и именно он) должен об этом позаботиться.
На фик такой стандарт, он идиотский. Язык С тут ни чего не решает, авр-гсс выбирает сам какую процедуру использовать. И какому правилу азыка С-99/ 2011 следовать а какому нет.
Кстати, там есть вторая диверсия, если принудить выполнить операцию 32 х 16 кастингом одного из 16-битных операндов, то будет выполнена 32х32 - а она как минимум в 2.5 раза более трудоёмка. На ардуино 5 микросекунд, я себе макрос на ассемблере писал 32х16 по времени 2 мксек. А то БПФ медленно очень выполнялось.
/// Я честно скажу, стндарты не читаю
))) Наш чел, понимаю, сам такой, стандарт читать - последнее дело если уже ниче не помогает, а такого пока ещё не было.. (Даже знаю какие форумчане нас заплевывать будут, но то их проблемы)
Почему такая лажа с этой разрядностью?! Так Си он кросплатформенный, должен давать одинаковый результати на 8-и и на 64-х разрядной машине. А всем не угодиш. Что скомпилится коротко на 8-и будет громоздко на 64-х и наоборот. Потому такое компромисное решение. Увы, нет идеала.
Почему такая лажа с этой разрядностью?! Так Си он кросплатформенный, должен давать одинаковый результати на 8-и и на 64-х разрядной машине.
Отнюдь.
Разработчики явно указывают, что не должен.
И в то же время указывают, что существуют средства языка, обеспечивающие кроссплатформенность, но использование именно этих средств - выбор программиста. Авторы языка явно указывают, что язык рассчитан на квалифицированного программиста, который знает, что делает. Следовательно, язык не отслеживает и не прощает глупые ошибки. В том числе и с неправильным применением типов.