Проблема с подсветкой

DominGo
Offline
Зарегистрирован: 08.01.2020


Всем привет!!! Помогите найти проблему. Хотел сделать, чтобы при событиях на энкодере счетчик подсветки переназначался на дефолтное значение. Соответсвенно если активности у энкодера нету то считчик уменьшается до 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;
	}
}

 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Дак это, наерна, к нему: 

003 #include <GyverEncoder.h>
004  

 

sadman41
Offline
Зарегистрирован: 19.10.2016

В какой таймер попадает 8425 и откуда?  

DominGo
Offline
Зарегистрирован: 08.01.2020

а библиотека может изменять мои значения переменных, которые я объявлял в скетче? вот собственно часть кода, в которой я работаю с данной переменной

	if(secondChanges && btn_timer > 0 ){
		btn_timer--;
	};
	if (btn_click || btn_turn){
		Serial.println("turn or click");
		btn_timer = cfg_timer_backlight;
	}; 
sadman41
Offline
Зарегистрирован: 19.10.2016

В мире всякое может быть. Даже вирус глупости может завестись в ардуине и портить дев.. переменные. 

Для начала Вам нужно сформулировать свою проблему понятно для остальных людей. Из приведённого кода не усматривается попадание какой-то там 8425 в таймер (по секрету скажу, что запихать нечто в таймер - весьма нетривиальная операция). Может у Вас значение некоторой переменной принимает неожидаемое значение в некий момент времени? Подумайте над этим и спросите ещё раз.

DominGo
Offline
Зарегистрирован: 08.01.2020

Может быть я неправильные слова подобрал. Но меня волнует вопрос почему в переменной появляются странные значения, наблюдаю я их в консоли. логика у меня такая

1. объявил переменную.

2. установил дефолтное значение, которое взял из другой переменной ( типы у них одинаковые)

3. если срабатывает событие на энкодере (поворот, клик), то я устанавливаю переменной дефолтное значение

4. если события не происходят, то я уменьшаю значение переменной на единицу каждую секунду ( дойдя до нуля перестаю уменьшать и выключаю подсветку)

код отрабатывает, но иногда в моей переменной при срабатывании события на энкодере неожиданно может появиться 0 хотя предыдущее значение было допустим 10

объявление переменной

// ---------------- Кнопка ------------------
bool btn_active = true;
int8_t btn_timer;
// ---------------- Конфиг ------------------
int8_t cfg_timer_backlight = 20;

присваиваю деф значение

btn_timer = cfg_timer_backlight;

часть функции в которой работаю с переменной

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;
	}; 
sadman41
Offline
Зарегистрирован: 19.10.2016

Криминала я тут не усматриваю.

Посему возникает два вопроса: в каком месте "портится" переменная и каким образом контролируется "порча"?

Вы же понимаете, что можно сделать так: 

	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);
	}; 

И экспериментально определить - портится ли переменная в процессе присвоения или же туда попадает уже "испорченное", таким образом локализовав проблемное место в коде и, в последствии, сосредоточить внимание на нём и его взаимосвязях с остальными частями прошивки.

Предваряя вопрос, отвечаю: более простого пути нет и волшебного фонаря, который подсветит ошибку в коде - тоже нет. Всё в этом деле - через тернии к звёздам.

DominGo
Offline
Зарегистрирован: 08.01.2020

вот вывод в консоль

все работает стабильно пока не сработает клик по энкодеру, после него несколько раз повернул и получил 0

cfg_timer_backlight: 20
btn_timer before: 6
btn_timer after: 20

cfg_timer_backlight: 20
btn_timer before: 18
btn_timer after: 20

cfg_timer_backlight: 20
btn_timer before: 18
btn_timer after: 20

cfg_timer_backlight: 20
btn_timer before: 19
btn_timer after: 20

cfg_timer_backlight: 20
btn_timer before: 19
btn_timer after: 20

cfg_timer_backlight: 20
btn_timer before: 19
btn_timer after: 20

cfg_timer_backlight: 20
btn_timer before: 19
btn_timer after: 20

cfg_timer_backlight: 20
btn_timer before: 20
btn_timer after: 20

cfg_timer_backlight: 20
btn_timer before: 19
btn_timer after: 20

cfg_timer_backlight: 20
btn_timer before: 19
btn_timer after: 20

cfg_timer_backlight: 20
btn_timer before: 20
btn_timer after: 20

cfg_timer_backlight: 20
btn_timer before: 19
btn_timer after: 20

cfg_timer_backlight: 20
btn_timer before: 20
btn_timer after: 20

cfg_timer_backlight: 20
btn_timer before: 20
btn_timer after: 20

cfg_timer_backlight: 20
btn_timer before: 20
btn_timer after: 20

cfg_timer_backlight: 20
btn_timer before: 19
btn_timer after: 20

cfg_timer_backlight: 20
btn_timer before: 20
btn_timer after: 20

cfg_timer_backlight: 20
btn_timer before: 20
btn_timer after: 20

cfg_timer_backlight: 20
btn_timer before: 20
btn_timer after: 20

cfg_timer_backlight: 20
btn_timer before: 20
btn_timer after: 20

cfg_timer_backlight: 20
btn_timer before: 19
btn_timer after: 20

cfg_timer_backlight: 20
btn_timer before: 19
btn_timer after: 20

cfg_timer_backlight: 20
btn_timer before: 19
btn_timer after: 0

cfg_timer_backlight: 20
btn_timer before: 0
btn_timer after: 0

cfg_timer_backlight: 20
btn_timer before: 0
btn_timer after: 0

cfg_timer_backlight: 20
btn_timer before: 0
btn_timer after: 0

 

DominGo
Offline
Зарегистрирован: 08.01.2020

и в чем собственно жопа, уважаемый??? можете более детально для простых людей объяснить на примере??

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Если же Вы хотите организовать меню через автомат. Да я этой методы то где это??

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() {


}
sadman41
Offline
Зарегистрирован: 19.10.2016

А ежели так сделать: btn_timer = 20; - в переменной после "... after" тоже 0 будет?

Удивительное, конечно дело. Что-то я не могу придумать иных причин, кроме порчи значений вследствие недостатка памяти. Сколько IDE пишет в остатках RAM после компиляции?

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Надо брать слона целиком, если конечно интересует слон а не его филейные части.

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();
}

 

DominGo
Offline
Зарегистрирован: 08.01.2020

Напрямую присвоил цифру 20, итого нуль все равно.

по памяти вот что пишет, насколько понимаю вполне хватает

[Step 1] Check Toolchain.
[Step 2] Find all source files.
[Step 3] Start building.
[50.0%] Compiling lamp.ino.cpp...
[100.0%] Creating binary files...
Sketch uses 8,176 bytes (26.6%) of program storage space. Maximum is 30,720 bytes.
Global variables use 475 bytes (23.2%) of dynamic memory, leaving 1,573 bytes for local variables. Maximum is 2,048 bytes.
sadman41
Offline
Зарегистрирован: 19.10.2016

А что за компилятор такой странный?

Я тут не могу ничего пояснить. Если уж константа не присваивается, то дело пахнет керосином.

DominGo
Offline
Зарегистрирован: 08.01.2020

qwone пишет:

Надо брать слона целиком, если конечно интересует слон а не его филейные части.

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();
}

 

 

теперь понятно почему у вас был такой пролог

да вы правы в моем коде есть часть вашего, но это было не просто копи паст, я искал варианты решения. наткнулся на этот форум. читал ветку на форуме с вашим кодом, вот и отложилось, но просто у меня проблема как мне кажется в другом

DominGo
Offline
Зарегистрирован: 08.01.2020

sadman41 пишет:

А что за компилятор такой странный?

Я тут не могу ничего пояснить. Если уж константа не присваивается, то дело пахнет керосином.

я через 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

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

DominGo пишет:
да вы правы в моем коде есть часть вашего, но это было не просто копи паст, я искал варианты решения. наткнулся на этот форум. читал ветку на форуме с вашим кодом, вот и отложилось, но просто у меня проблема как мне кажется в другом

Вы почему-то не используете millis(). Если фиксировать время крайнего переключения и потом вычислять сколько на этой станице стоим, то можно погасить экран. Опять же на гашение экрана лучше выделить страницу  #297

sadman41
Offline
Зарегистрирован: 19.10.2016

Для теста:

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.
------------

DominGo
Offline
Зарегистрирован: 08.01.2020

sadman41 пишет:

Для теста:

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.
------------

подправил, и все норм заработало. видимо в этом и была проблема. Спасибо Вам большое!

sadman41
Offline
Зарегистрирован: 19.10.2016

Ну, тогда надо snprintf использовать, чтобы не было пересечений переменных в памяти.

DominGo
Offline
Зарегистрирован: 08.01.2020

sadman41 пишет:

Ну, тогда надо snprintf использовать, чтобы не было пересечений переменных в памяти.

честно говоря я не знал, что может быть такое. после этого теперь буду учитывать. это как раз первые тернии, про которые вы говорили

sadman41
Offline
Зарегистрирован: 19.10.2016

Просто помните, что компилятор - Ваш друг.

И лучше всего будет включить вывод всех предупреждений, не игнорируя их. Тогда 90% ошибок отсеются сразу.