Помогите выловить ошибку.
- Войдите на сайт для отправки комментариев
Пт, 23/09/2016 - 07:20
Господа и снова приветствую. С месяц, а то и два, назад писал скетч. Недели с три он перекрасно работал, но потом по глупости спалил мк. Поменял/ Заливаю заново тот же скетч и упираюсь в ошибку.
#define INTERVAL2 4000UL
...
static unsigned long previousMillis2 = 0;
static byte flag2 = 0; // смена даты/день
if (millis() - previousMillis2 > INTERVAL2) {
previousMillis2 = millis();
if (flag2 == 0)
flag2 = 1;
else
flag2 = 0;
}
Serial.print(flag2);
В теории flag2 должен принимать значения 0 или 1 раз в 4 секунды. На практике только 0. Если считывать значение flag2 после строки previousMillis2 = millis();, то получаю 128. Откуда такое значение не понимаю, в коде больше нет упоменаний flag2. Все глаза сломал.
Неполный код - это плохо.
Для примера, посмотрите код в стартовом топике вот здесь. Представьте, что я дал бы Вам setup, без awfulShitCode. Много бы Вы там ошибое нашли?
#include <Sodaq_DS3231.h> #include <SPI.h> #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #include <EEPROM.h> #include <avr/pgmspace.h> #define FUEL 1 // 1 - Аналоговый вход датчика давления топлива #define WINCH 10 // 10 - Цифровой вход сигнала +12в "Лебедка" #define ODOFF 11 // 11 - Цифровой вход сигнала -12в "O/D OFF" #define MENU 12 // 12 - Цифровой вход кнопки выбора меню #define INTERVAL 1000UL // интервал мигания разделителя часов #define INTERVAL2 4000UL // интервал смены даты на день недели #define OLED_RESET 4 Adafruit_SSD1306 display(OLED_RESET); byte flag; //выбранный пункт меню const char string_0[] PROGMEM = "Январь"; const char string_1[] PROGMEM = "Февраль"; const char string_2[] PROGMEM = " Март"; const char string_3[] PROGMEM = "Апрель"; const char string_4[] PROGMEM = " Май"; const char string_5[] PROGMEM = " Июнь"; const char string_6[] PROGMEM = " Июль"; const char string_7[] PROGMEM = "Август"; const char string_8[] PROGMEM = "Сент-рь"; const char string_9[] PROGMEM = "Октябрь"; const char string_10[] PROGMEM = "Ноябрь"; const char string_11[] PROGMEM = "Декабрь"; const char string_12[] PROGMEM = "ПН"; const char string_13[] PROGMEM = "ВТ"; const char string_14[] PROGMEM = "СР"; const char string_15[] PROGMEM = "ЧТ"; const char string_16[] PROGMEM = "ПТ"; const char string_17[] PROGMEM = "СБ"; const char string_18[] PROGMEM = "ВС"; const char* const string_table[] PROGMEM = {string_0, string_1, string_2, string_3, string_4, string_5, string_6, string_7, string_8, string_9, string_10, string_11, string_12, string_13, string_14, string_15, string_16, string_17, string_18}; char buffer[10]; void setup() { flag = EEPROM.read(0); digitalWrite(ODOFF, HIGH); //подтяжка вверх "O/D OFF" digitalWrite(MENU, HIGH); //подтяжка вверх кнопки "меню" Serial.begin(9600); display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr 0x3C (for the 128x64) display.setRotation(2); display.cp437(true); display.setTextColor(WHITE); display.setTextWrap(0); display.display(); delay(2000); } String utf8rus(String source) // русификатор дисплея { int i, k; String target; unsigned char n; char m[2] = { '0', '\0' }; k = source.length(); i = 0; while (i < k) { n = source[i]; i++; if (n >= 0xC0) { switch (n) { case 0xD0: { n = source[i]; i++; if (n == 0x81) { n = 0xA8; break; } if (n >= 0x90 && n <= 0xBF) n = n + 0x30; break; } case 0xD1: { n = source[i]; i++; if (n == 0x91) { n = 0xB8; break; } if (n >= 0x80 && n <= 0x8F) n = n + 0x70; break; } } } m[0] = n; target = target + String(m); } return target; } void oled(String label, String value, String edenica) { display.clearDisplay(); display.setTextSize(2); display.setCursor(6, 0); display.println(utf8rus(label)); display.drawLine (0, 18, 128, 18, 1); display.setTextSize(4); display.setCursor(0, 30); display.print(utf8rus(value)); display.setTextSize(2); display.println(edenica); display.display(); delay(200); } void loop() { while (digitalRead(ODOFF) == LOW) { display.clearDisplay(); display.setTextSize(4); display.setCursor(0, 2); display.println(" O/D"); display.println(" OFF "); display.display(); while (digitalRead(WINCH) != LOW) { oled("Лебёдка", " ON", ""); } } while (digitalRead(WINCH) != LOW) { oled("Лебёдка", " ON", ""); } if (digitalRead(MENU) == LOW) { flag++; EEPROM.write(0, flag); // запоминаем выбранное меню } switch (flag) { case 0: { if (analogRead(FUEL) > 113) { oled("Топливо", String((((analogRead(FUEL) - 104) / 8.2) / 10), 1), " bar"); } else { oled("Топливо", "0", " bar"); } break; } case 1: { oled("Воздух", "-.-", " bar"); break; } case 2: { oled("Температ.", (" " + String(rtc.getTemperature(), 0)), " C#"); break; } case 3: { static unsigned long previousMillis = 0; static unsigned long previousMillis2 = 0; static byte flag2 = 0; // смена даты/день if (millis() - previousMillis2 > INTERVAL2) { previousMillis2 = millis(); if (flag2 == 0) flag2 = 1; else flag2 = 0; } DateTime now = rtc.now(); display.clearDisplay(); display.setTextSize(2); display.setCursor(3, 0); Serial.print(flag2); switch (flag2) { case 0: { if (now.date() < 10 ) display.print("0"); display.print(now.date()); break; } case 1: { strcpy_P(buffer, (char*)pgm_read_word(&(string_table[now.dayOfWeek() + 11]))); display.print(utf8rus(buffer)); break; } } display.print(" "); strcpy_P(buffer, (char*)pgm_read_word(&(string_table[now.month() - 1]))); display.print(utf8rus(buffer)); display.drawLine (0, 18, 128, 18, 1); display.setTextSize(4); display.setCursor(2, 30); if (now.hour() < 10 ) display.print("0"); display.print(now.hour()); if (millis() - previousMillis > INTERVAL) { previousMillis = millis(); display.print(":"); } else display.print(" "); if (now.minute() < 10 ) display.print("0"); display.print(now.minute()); display.display(); delay(200); break; } default: { flag = -1; } } }строки 164 - 177
скобки посмотри
http://arduino.ru/Reference/Else
Добавьте, пожалуйста печать переменной flag перед строкой 137 (с переводом строки) и печать чего угодно (хоть "-----" перед строкой 229. Скопипастите, пожалуйста печать в сериал мониторе. Хочется посмотреть
скобки посмотри
http://arduino.ru/Reference/Else
Попробоал так
if (flag2 == 0) { flag2 = 1;} else {flag2 = 0;}Не помогло.
Добавьте, пожалуйста печать переменной flag перед строкой 137 (с переводом строки) и печать чего угодно (хоть "-----" перед строкой 229. Скопипастите, пожалуйста печать в сериал мониторе. Хочется посмотреть
Грубо говоря получилось так:
3
------3
------3
------3
------3
И до бесконечности.
gergi, нет, что-то не сходится. Получается. что Ваша печать (строка 177) не отрабатывала? Не может быть. Или Вы убрали её? Зачем. Возвращайте обратно. КРоме того, добавьте ещё печатей - вместо строк 166-177 вставьте вот так
Serial.println("Enter case 3"); if (millis() - previousMillis2 > INTERVAL2) { Serial.println("CheckPoint #1"); previousMillis2 = millis(); if (flag2 == 0) { Serial.println("CheckPoint #2"); flag2 = 1; } else { Serial.println("CheckPoint #3"); flag2 = 0; } } DateTime now = rtc.now(); display.clearDisplay(); display.setTextSize(2); display.setCursor(3, 0); Serial.println("flag2 = "); Serial.println(flag2);Думаю, по тпакой печати и сима разюерётесь в проблеме, но если нет - давайте сюда что выдаст. ТОлько тогда уж и актуальную версию текста, чтобы лече было смотреть, а то изменений много.
Каюсь, 177 строка была убрана когда проделывал Ваши манипуляции из 5 поста.
Сейчас выдает следующее:
Вдруг поможет. Писал скетч на старой arduino IDE/ Сейчас заливаю с последней версии.
Так дайте актуальную версию текста скетча. а то много поменялось, а я хочу просто по тексту идти и сравнивать с печатью.
все в первом сообщении. 177 строчка нужна была для контроля, на функционал программы не влияет.
Не могу понять откуда flag2 получает значение 128. Хрен с ним, отредактировал код под это значение:
static byte flag2 = 128; // смена даты/день Serial.print("previousMillis2 = "); Serial.println(millis() - previousMillis2); if ((millis() - previousMillis2) > INTERVAL2) { previousMillis2 = millis(); if (flag2 == 128) flag2 = 0; else flag2 = 128; }Частично заработало. Но! Не работает интервал указзанный в строке №13 #define INTERVAL2 4000UL. В теории: значение flag2 должно менятся через каждые 4 секунды (INTERVAL2 4000UL). На практике меняется раз 5 за 1секунду.
нет, так нельзя. Если поведение программы непонятно, надо искать причину. Иначе Вы только замаскируете проблему, а не решите.
Я готов Вам помочь и вместе дожать, но давайте Вы будете показывать мне всё (например, откуда Вы взяли 128? Мне Вы это не показали!) и будете делать. что я говорю, чтобы я не просил у Вас свежую версию скетча по пять раз.
Давайте сюда свежую версию скетча (с 0, а не со 128) и её печать.
Евгений, скетч не меняется. Про не понятное значение flag2 "128" я описал в самом первом посте. Для чистоты проб давайте возьмем скетч из 2го поста.
Нет, мне нужен скетч с теми печатами, что Вы вставили, понимаете. Я просто хочу пальцем вести по коду и смотреть, что печатается. Т.е. мне нужен скетч со всеми печатями и собственно что он печатает.
Только знаете, что Вы ставляли печати из моего поста №8. Поправьте тот кусок таким образом:
Serial.println("Enter case 3"); if (millis() - previousMillis2 > INTERVAL2) { Serial.println("CheckPoint #1"); previousMillis2 = millis(); Serial.print("BEFORE flag2 = "); Serial.println(flag2); if (flag2 == 0) { Serial.println("CheckPoint #2"); flag2 = 1; } else { Serial.println("CheckPoint #3"); flag2 = 0; } } DateTime now = rtc.now(); display.clearDisplay(); display.setTextSize(2); display.setCursor(3, 0); Serial.print("AFTER flag2 = "); Serial.println(flag2);И после этого, жду от Вас полного скетча и копии того, что он печатает.
#include <Sodaq_DS3231.h> #include <SPI.h> #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #include <EEPROM.h> #include <avr/pgmspace.h> #define FUEL 1 // 1 - Аналоговый вход датчика давления топлива #define WINCH 10 // 10 - Цифровой вход сигнала +12в "Лебедка" #define ODOFF 11 // 11 - Цифровой вход сигнала -12в "O/D OFF" #define MENU 12 // 12 - Цифровой вход кнопки выбора меню #define INTERVAL 1000UL // интервал мигания разделителя часов #define INTERVAL2 4000UL // интервал смены даты на день недели #define OLED_RESET 4 Adafruit_SSD1306 display(OLED_RESET); byte flag; //выбранный пункт меню const char string_0[] PROGMEM = "Январь"; const char string_1[] PROGMEM = "Февраль"; const char string_2[] PROGMEM = " Март"; const char string_3[] PROGMEM = "Апрель"; const char string_4[] PROGMEM = " Май"; const char string_5[] PROGMEM = " Июнь"; const char string_6[] PROGMEM = " Июль"; const char string_7[] PROGMEM = "Август"; const char string_8[] PROGMEM = "Сент-рь"; const char string_9[] PROGMEM = "Октябрь"; const char string_10[] PROGMEM = "Ноябрь"; const char string_11[] PROGMEM = "Декабрь"; const char string_12[] PROGMEM = "ПН"; const char string_13[] PROGMEM = "ВТ"; const char string_14[] PROGMEM = "СР"; const char string_15[] PROGMEM = "ЧТ"; const char string_16[] PROGMEM = "ПТ"; const char string_17[] PROGMEM = "СБ"; const char string_18[] PROGMEM = "ВС"; const char* const string_table[] PROGMEM = {string_0, string_1, string_2, string_3, string_4, string_5, string_6, string_7, string_8, string_9, string_10, string_11, string_12, string_13, string_14, string_15, string_16, string_17, string_18}; char buffer[10]; void setup() { flag = EEPROM.read(0); digitalWrite(ODOFF, HIGH); //подтяжка вверх "O/D OFF" digitalWrite(MENU, HIGH); //подтяжка вверх кнопки "меню" Serial.begin(9600); display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr 0x3C (for the 128x64) display.setRotation(2); display.cp437(true); display.setTextColor(WHITE); display.setTextWrap(0); display.display(); } String utf8rus(String source) // русификатор дисплея { int i, k; String target; unsigned char n; char m[2] = { '0', '\0' }; k = source.length(); i = 0; while (i < k) { n = source[i]; i++; if (n >= 0xC0) { switch (n) { case 0xD0: { n = source[i]; i++; if (n == 0x81) { n = 0xA8; break; } if (n >= 0x90 && n <= 0xBF) n = n + 0x30; break; } case 0xD1: { n = source[i]; i++; if (n == 0x91) { n = 0xB8; break; } if (n >= 0x80 && n <= 0x8F) n = n + 0x70; break; } } } m[0] = n; target = target + String(m); } return target; } void oled(String label, String value, String edenica) { display.clearDisplay(); display.setTextSize(2); display.setCursor(6, 0); display.println(utf8rus(label)); display.drawLine (0, 18, 128, 18, 1); display.setTextSize(4); display.setCursor(0, 30); display.print(utf8rus(value)); display.setTextSize(2); display.println(edenica); display.display(); delay(200); } void loop() { while (digitalRead(ODOFF) == LOW) { display.clearDisplay(); display.setTextSize(4); display.setCursor(0, 2); display.println(" O/D"); display.println(" OFF "); display.display(); while (digitalRead(WINCH) != LOW) { oled("Лебёдка", " ON", ""); } } while (digitalRead(WINCH) != LOW) { oled("Лебёдка", " ON", ""); } if (digitalRead(MENU) == LOW) { flag++; EEPROM.write(0, flag); // запоминаем выбранное меню } Serial.print("flag = "); Serial.println(flag); switch (flag) { case 0: { if (analogRead(FUEL) > 113) { oled("Топливо", String((((analogRead(FUEL) - 104) / 8.2) / 10), 1), " bar"); } else { oled("Топливо", "0", " bar"); } break; } case 1: { oled("Воздух", "-.-", " bar"); break; } case 2: { oled("Температ.", (" " + String(rtc.getTemperature(), 0)), " C#"); break; } case 3: { static unsigned long previousMillis = 0; static unsigned long previousMillis2 = 0; static byte flag2 = 0; // смена даты/день Serial.println("Enter case 3"); if (millis() - previousMillis2 > INTERVAL2) { Serial.println("CheckPoint #1"); previousMillis2 = millis(); Serial.print("BEFORE flag2 = "); Serial.println(flag2); if (flag2 == 0) { Serial.println("CheckPoint #2"); flag2 = 1; } else { Serial.println("CheckPoint #3"); flag2 = 0; } } DateTime now = rtc.now(); display.clearDisplay(); display.setTextSize(2); display.setCursor(3, 0); Serial.print("AFTER flag2 = "); Serial.println(flag2); switch (flag2) { case 0: { if (now.date() < 10 ) display.print("0"); display.print(now.date()); break; } case 1: { strcpy_P(buffer, (char*)pgm_read_word(&(string_table[now.dayOfWeek() + 11]))); display.print(utf8rus(buffer)); break; } } display.print(" "); strcpy_P(buffer, (char*)pgm_read_word(&(string_table[now.month() - 1]))); display.print(utf8rus(buffer)); display.drawLine (0, 18, 128, 18, 1); display.setTextSize(4); display.setCursor(2, 30); if (now.hour() < 10 ) display.print("0"); display.print(now.hour()); if (millis() - previousMillis > INTERVAL) { previousMillis = millis(); display.print(":"); } else display.print(" "); if (now.minute() < 10 ) display.print("0"); display.print(now.minute()); display.display(); delay(200); break; } default: { flag = -1; } } Serial.println("-------------------------------------------------"); }Ага, при первом проходе у Вас flag2 в порядке. Но уже при втором он стал 128, что невозможно, т.к. Вы нигде ему такого не присваиваете.
Вывод - Вы где-то "распахиваете" память. Это ни в коем случае нельзя маскировать, как Вы пытались, потому что глюки от таких дел могут вылазить любые и в любых местах. Это надо обязательно локализовать и исправить.
Думаю, что проблема в строке 214. Но, на всякий случай. чтобы нам с Вами не неделю тут ковыряться, давайте поставим контрольные печати почаще и выловим этот момент, с Божьей помощью.
Итак, сейчас Вы делаете вот такую строку:
Serial.print("#1 flag2 = "); Serial.println(flag2);И вставляете её обязательно перед и после строки 214. Также, на всякий случай поставьте после строк 221 и 230. Если не лень, то понаставьте и больше в этом районе, хоть через строчку.
Только обязательно при кажой вставке меняйте номер (там вместо #1 пишите #2, #3, и т.д.) чтобы потом, разбирая печать, мы понимали из какого именно места это было напечатано.
Думаю, мы так поймаем где портится память.
Мне можно дать не весь скетч, а только кусок от нынешней строки 163 и до конца, ну и обязательно печать целиком.
На скорую руку закоментировал строку №214. Всё заработало как надо. Вы были правы.
Единственное не пойму с какой радости вдруг такой косяк. Скетч был рабочим на 100%, отработал 3 недели без косяков.
Распашка памяти вещь абсолютно непредсказуемая. Может быть всё. что угодно. Может и год работать. Вы не смотрели пример, которыя я давал в первом посте? Там ведь можно мозг вынести - явно написано одно, а печатается другое. Тоже распашка памяти.
Косяк-то Ваш понятен. Кстати, у Вас ещё один точно такой же в строке 202
Не подскажете где почитать про данный косяк и способ решения?
P.S. Изменил значение в строке №37 на:
Программа зароботала полностью как и раньше!
Евгений, спасибо за помощь.
gergi,
есть правило в программировании - никогда не работать вслепую. Я не зря просил Вас делать печати. Теперь позвольте дать Вам совет. Те строки с функцией strcpy_P по идее должны копировать данные из програмной памяти в оперативную. так? Так вот, вставьте сразу после этих строк печать buffer - просто, чтобы убедиться. что копируется именно то, что нужно.