Проблема с подсветкой
- Войдите на сайт для отправки комментариев
Ср, 08/01/2020 - 18:02
Всем привет!!! Помогите найти проблему. Хотел сделать, чтобы при событиях на энкодере счетчик подсветки переназначался на дефолтное значение. Соответсвенно если активности у энкодера нету то считчик уменьшается до 0 и посдсветка отключается. Вроде все работает, но если я захожу в меню при повороте энкодера в таймер попадают странные значения, может 0 прилететь или 8425 хотя в скетче идет отсчте от 20.
#include <microLiquidCrystal_I2C.h>
#include <microDS3231.h>
#include <GyverEncoder.h>
#define CLK 4
#define DT 3
#define SW 2
#define POWER_ON 5
LiquidCrystal_I2C lcd(0x27,16,2); // Устанавливаем дисплей
MicroDS3231 timeClock;// Устанавливаем часы
Encoder enc1(CLK, DT, SW); // Устанавливаем енкодер
// =================== НОВЫЕ ПЕРЕМЕННЫЕ ======================
// ---------------- Меню ------------------
const byte menu = 10;
const byte sub_menu = 20;
const byte first = 100;
bool active_menu = false;
bool active_submenu = false;
int8_t current_item = 0;
int8_t dispayed_item = 1;
byte currentPage;
// ---------------- Таймер ------------------
int secondLast = 0;
bool secondChanges = true;
int cur_time;
int display_time;
int work_time_value = 0;
bool work_time_min = true;
// ---------------- Оповещение ------------------
bool time_error = false;
bool power_enable = false;
// ---------------- Кнопка ------------------
bool btn_active = true;
int btn_timer;
// ---------------- Дисплей ------------------
bool backlight_enable = true;
// ---------------- Конфиг ------------------
int8_t cfg_timer_backlight = 20;
int8_t cfg_time_sys_h;
int8_t cfg_time_sys_m;
int8_t cfg_time_poweron = 8;
int8_t cfg_time_poweroff = 23;
int8_t cfg_time_highlight;
// =================== НОВЫЕ ПЕРЕМЕННЫЕ ======================
const char *menu_items[] = {
"System time", // 0
"Time power on", // 1
"Time power off", // 2
"Highlight on", // 2
"Display led", // 2
};
const char *menu_items_set[] = {
};
void setup()
{
Serial.begin(9600);
lcd.init();
lcd.backlight();
enc1.setType(TYPE1);
if (timeClock.lostPower()) {
lcd.setCursor(1, 0);
lcd.print('RTC lost power');
lcd.blink();
timeClock.setTime(COMPILE_TIME);
time_error = true;
}
display_time = timeClock.getMinutes();
btn_timer = cfg_timer_backlight;
calcWorkTime();
goPage(first);
}
void loop()
{
powerBp();
calcWorkTime();
checkActivity();
displayBacklight();
goPage(currentPage);
}
void powerBp(){
int curHours = timeClock.getHours();
if (cfg_time_poweron < curHours && cfg_time_poweroff > curHours){
if(power_enable) return;
digitalWrite(POWER_ON, HIGH);
Serial.println("high");
power_enable = true;
}else{
power_enable = false;
digitalWrite(POWER_ON, LOW);
Serial.println("low");
}
}
void goPage(byte menuItem){
char firstLine[16];
char secondLine[16];
switch (menuItem) {
case menu:
sprintf(firstLine,"%s","Options ========");
sprintf(secondLine,"-%s ",menu_items[dispayed_item]);
break;
case sub_menu:
sprintf(firstLine,"%s ===========",menu_items[dispayed_item]);
sprintf(secondLine,"%s",menu_items_set[dispayed_item]);
break;
default:
sprintf(firstLine,"Time %d:%d:%d",timeClock.getHours(),timeClock.getMinutes(),timeClock.getSeconds());
sprintf(secondLine,"work %d %s",work_time_value,(work_time_min)?"minutes":"hours");
break;
}
checkTimer();
if(secondChanges){
lcd.clear();
}
lcd.setCursor(0, 0);
lcd.print(firstLine);
if(time_error){
lcd.setCursor(14, 0);
lcd.print(" x");
}
lcd.setCursor(0, 1);
lcd.print(secondLine);
}
void calcWorkTime(){
if(work_time_min){
cur_time = millis()/60000;
}else{
cur_time = millis()/360000;
}
if (display_time != cur_time){
display_time = cur_time;
work_time_value++;
if (work_time_value > 59 && work_time_min){
work_time_value = 1;
work_time_min = false;
display_time = millis()/360000;
}
}
}
void checkTimer(){
if(millis()/1000 != secondLast){
secondLast = millis()/1000;
secondChanges = true;
return;
}
secondChanges = false;
}
void checkActivity(){
enc1.tick();
bool btn_click = enc1.isClick();
bool btn_left = enc1.isLeft();
bool btn_right = enc1.isRight();
bool btn_turn = enc1.isTurn();
if(secondChanges && btn_timer > 0 ){
btn_timer--;
};
if (btn_click || btn_turn){
Serial.println("turn or click");
btn_timer = cfg_timer_backlight;
};
if (btn_click){
Serial.println("click");
if(!active_menu && !active_submenu){
toggleStateMenu(menu);
return;
}
if(active_menu){
toggleStateMenu(sub_menu);
}
}
if (enc1.isHolded()){
lcd.clear();
if(active_submenu){
toggleStateMenu(menu);
}else{
toggleStateMenu(first);
}
};
if (btn_right && active_menu){
Serial.println("right");
dispayed_item++;
if(dispayed_item == 5) dispayed_item = 0;
};
if (btn_left && active_menu){
Serial.println("left");
dispayed_item--;
if(dispayed_item <= 0) dispayed_item = 4;
};
}
void displayBacklight(){
if (btn_timer == 0){
toggleStateMenu(first);
lcd.noBacklight();
}else{
lcd.backlight();
};
}
void toggleStateMenu(byte state){
switch (state) {
case menu:
active_menu = true;
currentPage = menu;
break;
case sub_menu:
active_menu = false;
active_submenu = true;
currentPage = sub_menu;
break;
default:
active_menu = false;
active_submenu = false;
currentPage = first;
}
}
Дак это, наерна, к нему:
003#include <GyverEncoder.h>004В какой таймер попадает 8425 и откуда?
а библиотека может изменять мои значения переменных, которые я объявлял в скетче? вот собственно часть кода, в которой я работаю с данной переменной
if(secondChanges && btn_timer > 0 ){ btn_timer--; }; if (btn_click || btn_turn){ Serial.println("turn or click"); btn_timer = cfg_timer_backlight; };В мире всякое может быть. Даже вирус глупости может завестись в ардуине и портить дев.. переменные.
Для начала Вам нужно сформулировать свою проблему понятно для остальных людей. Из приведённого кода не усматривается попадание какой-то там 8425 в таймер (по секрету скажу, что запихать нечто в таймер - весьма нетривиальная операция). Может у Вас значение некоторой переменной принимает неожидаемое значение в некий момент времени? Подумайте над этим и спросите ещё раз.
Может быть я неправильные слова подобрал. Но меня волнует вопрос почему в переменной появляются странные значения, наблюдаю я их в консоли. логика у меня такая
1. объявил переменную.
2. установил дефолтное значение, которое взял из другой переменной ( типы у них одинаковые)
3. если срабатывает событие на энкодере (поворот, клик), то я устанавливаю переменной дефолтное значение
4. если события не происходят, то я уменьшаю значение переменной на единицу каждую секунду ( дойдя до нуля перестаю уменьшать и выключаю подсветку)
код отрабатывает, но иногда в моей переменной при срабатывании события на энкодере неожиданно может появиться 0 хотя предыдущее значение было допустим 10
объявление переменной
присваиваю деф значение
часть функции в которой работаю с переменной
void checkActivity(){ enc1.tick(); bool btn_click = enc1.isClick(); bool btn_left = enc1.isLeft(); bool btn_right = enc1.isRight(); bool btn_turn = enc1.isTurn(); if(secondChanges && btn_timer > 0 ){ btn_timer--; }; if (btn_click || btn_turn){ btn_timer = cfg_timer_backlight; };Криминала я тут не усматриваю.
Посему возникает два вопроса: в каком месте "портится" переменная и каким образом контролируется "порча"?
Вы же понимаете, что можно сделать так:
if (btn_click || btn_turn){ Serial.print("cfg_timer_backlight: "); Serial.println(cfg_timer_backlight); Serial.print("btn_timer before: "); Serial.println(btn_timer); btn_timer = cfg_timer_backlight; Serial.print("btn_timer after: "); Serial.println(btn_timer); };И экспериментально определить - портится ли переменная в процессе присвоения или же туда попадает уже "испорченное", таким образом локализовав проблемное место в коде и, в последствии, сосредоточить внимание на нём и его взаимосвязях с остальными частями прошивки.
Предваряя вопрос, отвечаю: более простого пути нет и волшебного фонаря, который подсветит ошибку в коде - тоже нет. Всё в этом деле - через тернии к звёздам.
вот вывод в консоль
все работает стабильно пока не сработает клик по энкодеру, после него несколько раз повернул и получил 0
и в чем собственно жопа, уважаемый??? можете более детально для простых людей объяснить на примере??
Если же Вы хотите организовать меню через автомат. Да я этой методы то где это??
const byte page0=0;// погасить экран const byte page1=10;// главная страница const byte page2=20;// страница 1 const byte page3=30;// страница 2 const byte page4=40;//страница 3 void setup() { } void loop() { }А ежели так сделать: btn_timer = 20; - в переменной после "... after" тоже 0 будет?
Удивительное, конечно дело. Что-то я не могу придумать иных причин, кроме порчи значений вследствие недостатка памяти. Сколько IDE пишет в остатках RAM после компиляции?
Надо брать слона целиком, если конечно интересует слон а не его филейные части.
const byte page0 = 0; // погасить экран const byte page1 = 10; // главная страница const byte page2 = 20; // страница 1 const byte page3 = 30; // страница 2 const byte page4 = 40; //страница 3 uint32_t past; byte page; void goPage(byte p) { page = p; past = millis(); switch (p) { case page0: // выключить экран // настроить кнопки break; case page1: // включить экран // отобразить страницу // настроить кнопки break; case page2: // отобразить страницу // настроить кнопки break; case page3: // отобразить страницу // настроить кнопки break; case page4: // отобразить страницу // настроить кнопки break; } } void menu_init() { goPage(page1); } void menu_run() { if (page !=page0 && millis()-past>6000) goPage(page0); } void setup() { menu_init(); } void loop() { menu_run(); }Напрямую присвоил цифру 20, итого нуль все равно.
по памяти вот что пишет, насколько понимаю вполне хватает
А что за компилятор такой странный?
Я тут не могу ничего пояснить. Если уж константа не присваивается, то дело пахнет керосином.
Надо брать слона целиком, если конечно интересует слон а не его филейные части.
const byte page0 = 0; // погасить экран const byte page1 = 10; // главная страница const byte page2 = 20; // страница 1 const byte page3 = 30; // страница 2 const byte page4 = 40; //страница 3 uint32_t past; byte page; void goPage(byte p) { page = p; past = millis(); switch (p) { case page0: // выключить экран // настроить кнопки break; case page1: // включить экран // отобразить страницу // настроить кнопки break; case page2: // отобразить страницу // настроить кнопки break; case page3: // отобразить страницу // настроить кнопки break; case page4: // отобразить страницу // настроить кнопки break; } } void menu_init() { goPage(page1); } void menu_run() { if (page !=page0 && millis()-past>6000) goPage(page0); } void setup() { menu_init(); } void loop() { menu_run(); }теперь понятно почему у вас был такой пролог
да вы правы в моем коде есть часть вашего, но это было не просто копи паст, я искал варианты решения. наткнулся на этот форум. читал ветку на форуме с вашим кодом, вот и отложилось, но просто у меня проблема как мне кажется в другом
А что за компилятор такой странный?
Я тут не могу ничего пояснить. Если уж константа не присваивается, то дело пахнет керосином.
я через sublime text 3 c модулем для ардуино компилирую
попробовал скомпилировать в Arduino IDE
W:\arduino\lamp\lamp.ino: In function 'goPage': W:\arduino\lamp\lamp.ino:124:11: warning: '__builtin_strcpy' writing 17 bytes into a region of size 16 overflows the destination [-Wstringop-overflow=] sprintf(firstLine,"%s","Options ========"); ^ Скетч использует 8140 байт (26%) памяти устройства. Всего доступно 30720 байт. Глобальные переменные используют 475 байт (23%) динамической памяти, оставляя 1573 байт для локальных переменных. Максимум: 2048 байт. Неверная библиотека найдена в D:\HataB\My documents\Arduino\libraries\minimLibs: нет заголовочных файлов (.h), найденных в D:\HataB\My documents\Arduino\libraries\minimLibs Неверная библиотека найдена в D:\HataB\My documents\Arduino\libraries\minimLibs: нет заголовочных файлов (.h), найденных в D:\HataB\My documents\Arduino\libraries\minimLibsДля теста:
firstLine[50];
secondLine[50];
Хотя, уже понятно, что \0 не учитываете, суёте в буфер 17 символов и функция ещё сама 0x00 лепит в конец:
------------
The size of the buffer should be large enough to contain the entire resulting string (see snprintf for a safer version).
A terminating null character is automatically appended after the content.
------------
Для теста:
firstLine[50];
secondLine[50];
Хотя, уже понятно, что \0 не учитываете, суёте в буфер 17 символов и функция ещё сама 0x00 лепит в конец:
------------
The size of the buffer should be large enough to contain the entire resulting string (see snprintf for a safer version).
A terminating null character is automatically appended after the content.
------------
подправил, и все норм заработало. видимо в этом и была проблема. Спасибо Вам большое!
Ну, тогда надо snprintf использовать, чтобы не было пересечений переменных в памяти.
Ну, тогда надо snprintf использовать, чтобы не было пересечений переменных в памяти.
честно говоря я не знал, что может быть такое. после этого теперь буду учитывать. это как раз первые тернии, про которые вы говорили
Просто помните, что компилятор - Ваш друг.
И лучше всего будет включить вывод всех предупреждений, не игнорируя их. Тогда 90% ошибок отсеются сразу.