Как вместо digitalRead() использовать регистр ?
- Войдите на сайт для отправки комментариев
Вс, 11/02/2018 - 17:39
Здавствуйте уважаемые форумчане.
Помогите подставить PORTD вместо "!digitalRead(4)".
/*
*/
#include <avr/io.h>
#include <util/delay.h>
#include <OLED_I2C.h>
OLED myOLED(SDA, SCL, 1);
extern uint8_t SmallFont[];
volatile int encoderPin1 = 2;
volatile int encoderPin2 = 3;
volatile int MSB ;
volatile int LSB ;
volatile int encoded = 0 ;
volatile int lastEncoded = 0;
volatile int sum ;
volatile int a = 0;
volatile int b = 0;
volatile int c = 0;
volatile int d = 0;
volatile int encoderValue = 0;
byte menuPos = 1;
long val;
long val_old = 0;
int i = 0;
void setup(){
Serial.begin (9600);
myOLED.begin();
myOLED.clrScr();
myOLED.setFont(SmallFont);
DDRD &= ~(1<<2);
DDRD &= ~(1<<3);
PORTD |= 1<<2;
PORTD |= 1<<3;
PORTD |= 1<<4; // pinMode(4, INPUT);// Kнопка "Mеню"
DDRD &= ~(1<<4); // digitalWrite(4, HIGH);
attachInterrupt(0, updateEncoder, CHANGE);
attachInterrupt(1, updateEncoder, CHANGE);
}
void loop(){
MainScreen();
if(!digitalRead(4)){ // Заменить на порт прямого доступа "pin 4 Arduino Nano"
delay(200);
Menu();
}
}
void updateEncoder(){
MSB = digitalRead(encoderPin1);
LSB = digitalRead(encoderPin2);
encoded = (MSB << 1) |LSB;
sum = (lastEncoded << 2) | encoded;
if(encoded==0b0000){
if(a==0){
encoderValue = encoderValue+d; c=1; a=1; b=0;
}
}
if(encoded==0b0011){
if(b==0){
encoderValue = encoderValue+d; c=1; b=1; a=0;
}
}
if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011){
d=+1;
}
if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000){
d=-1;
}
lastEncoded = encoded;
}
void MainScreen() {
myOLED.clrScr();
//myOLED.invertText(true);
myOLED.print("MainScreen", CENTER, 20);
//myOLED.invertText(false);
myOLED.printNumI(encoderValue, CENTER, 40);
myOLED.update();
}
void Menu(){
for (i=0; i<=500; i++){
val = encoderValue;
//***************************** Выбор позиции в меню ***********************
if(val > val_old){
menuPos = menuPos + 1;
val_old = val;
}
if(menuPos > 6){
menuPos = 1;
}
if(val < val_old){
menuPos = menuPos - 1;
val_old = val;
}
if(menuPos < 1){
menuPos = 6;
}
switch(menuPos){
//*************** устанавливаем курсор согласно позиции в меню ***************
case 1:
myOLED.clrScr();
//myOLED.print(">", 0, 0);
myOLED.invertText(true);
myOLED.print("Alarm", 10, 0);
myOLED.invertText(false);
myOLED.print("Time", 10, 10);
myOLED.print("Setting", 10, 20);
myOLED.print("Setting2", 10, 30);
myOLED.print("Setting3", 10, 40);
myOLED.print("back", 10, 50);
if (menuPos == 1 && !digitalRead(4)) MenuSetAlarm();
break;
case 2:
myOLED.clrScr();
//myOLED.print(">", 0, 10);
myOLED.print("Alarm", 10, 0);
myOLED.invertText(true);
myOLED.print("Time", 10, 10);
myOLED.invertText(false);
myOLED.print("Setting", 10, 20);
myOLED.print("Setting2", 10, 30);
myOLED.print("Setting3", 10, 40);
myOLED.print("back", 10, 50);
if (menuPos == 2 && !digitalRead(4)) MenuSetTime();
break;
case 3:
myOLED.clrScr();
//myOLED.print(">", 0, 20);
myOLED.print("Alarm", 10, 0);
myOLED.print("Time", 10, 10);
myOLED.invertText(true);
myOLED.print("Setting", 10, 20);
myOLED.invertText(false);
myOLED.print("Setting2", 10, 30);
myOLED.print("Setting3", 10, 40);
myOLED.print("back", 10, 50);
if (menuPos == 3 && !digitalRead(4)) MenuSetting();
break;
case 4:
myOLED.clrScr();
//myOLED.print(">", 0, 30);
myOLED.print("Alarm", 10, 0);
myOLED.print("Time", 10, 10);
myOLED.print("Setting", 10, 20);
myOLED.invertText(true);
myOLED.print("Setting2", 10, 30);
myOLED.invertText(false);
myOLED.print("Setting3", 10, 40);
myOLED.print("back", 10, 50);
if (menuPos == 4 && !digitalRead(4)) MenuSetting();
break;
case 5:
myOLED.clrScr();
//myOLED.print(">", 0, 40);
myOLED.print("Alarm", 10, 0);
myOLED.print("Time", 10, 10);
myOLED.print("Setting", 10, 20);
myOLED.print("Setting2", 10, 30);
myOLED.invertText(true);
myOLED.print("Setting3", 10, 40);
myOLED.invertText(false);
myOLED.print("back", 10, 50);
if (menuPos == 5 && !digitalRead(4)) MenuSetting();
break;
case 6:
myOLED.clrScr();
//myOLED.print(">", 0, 50);
myOLED.print("Alarm", 10, 0);
myOLED.print("Time", 10, 10);
myOLED.print("Setting", 10, 20);
myOLED.print("Setting2", 10, 30);
myOLED.print("Setting3", 10, 40);
myOLED.invertText(true);
myOLED.print("back", 10, 50);
myOLED.invertText(false);
}
myOLED.update();
if (!digitalRead(4) && menuPos == 6){break;}
}
delay (150);
}
void MenuSetTime(){
for (i=0; i<=500; i++){
myOLED.clrScr();
myOLED.print("MenuSetTime", CENTER, 20);
myOLED.update();
if(!digitalRead(4)){break;}
}
}
void MenuSetAlarm(){
for (i=0; i<=500; i++){
myOLED.clrScr();
myOLED.print("MenuSetAlarm", CENTER, 20);
myOLED.update();
if(!digitalRead(4)){break;}
}
}
void MenuSetting(){
}
Для разных контроллеров по-разному, но, если верить остальным фрагментам кода, то должно подойти !(PIND & (1<<4)).
Но в совокупности с delay(200) это не имеет никакого смысла.
PS. Поправлено: оказывается, "остальным фрагментам" верить нельзя.
!(PIND & 1<<4)
Igoreck, для чего вам это? На фоне delay(200) никакого смысла в этом нет.
Вы для начала научитесь просто писать нормальный код, без делеев и без жутких операторв кэйса, где в пяти вариантах выбора на 80% один и тот же код.
А чё, RTFМ прямо на этом сайте ... с религией что-то?
Спасибо за "!(PIND & 1<<4)" работает четко.
Но поповоду "жутких операторв кэйса" , посоветуйте пожалуйста правильную альтернативу!
Но поповоду "жутких операторв кэйса" , посоветуйте пожалуйста правильную альтернативу!
ну вот смотрите - у вас все кейсы выводят одно и то же - меняется только то, какая строка инвертирована, верно? Так сделайте процедуру вывода меню, которая будет принимать в качестве параметра номер строки, которую надо подсветить.
По поводу использования регистров вместо digitalRead - вам наверно кажется, что это признак крутого программиста? ^) На самом деле неуклюжий код кейса опускает вас куда сильнее, чем использование регистров - поднимает. По коду кейса сразу видно, что писал чайник. И на фоне этого кажется, что код с регистрами вы просто где-то списали.
Признаюсь - да я в этом пока чайник.
Собрал этот код по кускам и хочу зделать задуманное устройство, но места уже не хватает.
Пришлось укорачивать код посредством перехода из digitalRead() на тот кошмар который Вы видите.
Говорите "принимать в качестве параметра номер строки, которую надо подсветить", подскажите как привильно это реализовать.
Не кричите на меня, ведь я только учусь.
Прошу Вас поправте в меня в коде.
Кто нибудь помогите сделайть процедуру вывода меню, которая будет принимать в качестве параметра номер строки, которую надо подсветить.
Собрал этот код по кускам и хочу зделать задуманное устройство, но места уже не хватает.
Какого места не хватает? - флеша или оперативки? скорее оперативки...
По моему, вы не с того начали оптимизацию программы, у вас куча строк в оперативной памяти, которые можно оттуда выкинуть.
Какие именно строки?
Собрал этот код по кускам и хочу зделать задуманное устройство, но места уже не хватает.
Какого места не хватает? - флеша или оперативки? скорее оперативки...
По моему, вы не с того начали оптимизацию программы, у вас куча строк в оперативной памяти, которые можно оттуда выкинуть.
Прошу Вас помогите с оптимизацией кода!
В начале скетча добавить
#include <avr/pgmspace.h> const char string_1[] PROGMEM = "Alarm"; const char string_2[] PROGMEM = "Time"; const char string_3[] PROGMEM = "Settings"; const char string_4[] PROGMEM = "Settings2"; const char string_5[] PROGMEM = "Settings3"; const char string_6[] PROGMEM = "back"; char * menu_table[] ={string_1,string_2,string_3,string_4,string_5,string_6}; void printMenu (int invertLine) { int i; myOLED.clrScr(); for (i = 0; i < 6; i++ ) {if (i == (invertLine - 1)) myOLED.invertText(true); myOLED.print((const __FlashStringHelper *) menu_table[i] , 10, i*10); if (i == (invertLine - 1)) myOLED.invertText(false); } myOLED.update(); }а вместо всего твоего switch - вот это
printMenu(menuPos); if (digitalRead(4)) { case (menuPos) { case 1: MenuSetAlarm();break; case 2: MenuSetTime();;break; case 3: MenuSettings();;break; case 4: MenuSettings();;break; case 5: MenuSettings();;break; }и не забудь померить, сколько занимал код до и после
В начале скетча добавить
#include <avr/pgmspace.h> const char string_1[] PROGMEM = "Alarm"; const char string_2[] PROGMEM = "Time"; const char string_3[] PROGMEM = "Settings"; const char string_4[] PROGMEM = "Settings2"; const char string_5[] PROGMEM = "Settings3"; const char string_6[] PROGMEM = "back"; char * menu_table[] ={string_1,string_2,string_3,string_4,string_5,string_6}; void printMenu (int invertLine) { int i; myOLED.clrScr(); for (i = 0; i < 6; i++ ) {if (i == (invertLine - 1)) myOLED.invertText(true); myOLED.print((const __FlashStringHelper *) menu_table[i] , 10, i*10); if (i == (invertLine - 1)) myOLED.invertText(false); } myOLED.update(); }а вместо всего твоего switch - вот это
printMenu(menuPos); if (digitalRead(4)) { case (menuPos) { case 1: MenuSetAlarm();break; case 2: MenuSetTime();;break; case 3: MenuSettings();;break; case 4: MenuSettings();;break; case 5: MenuSettings();;break; }и не забудь померить, сколько занимал код до и после
Выражаю особеную благодарность и дай Вам Бог здоровья.
Выражаю особеную благодарность и дай Вам Бог здоровья.
напишите лучше - помогло или нет? что-то у меня ваш код и мой дают примерно одинаквую загрузку памяти, что удивительно, с учетом переноса строк в Пргмем и того, насколько мой код короче
Выражаю особеную благодарность и дай Вам Бог здоровья.
напишите лучше - помогло или нет? что-то у меня ваш код и мой дают примерно одинаквую загрузку памяти, что удивительно, с учетом переноса строк в Пргмем и того, насколько мой код короче
Помойму 28%. Точнее сравнить смогу завтра.
К сожалению Ваша оптимизация занимает 8 514 bytes (27%) памяти, а до этого была 7 954 bytes (25%).
Может мой быдлокод не такой плохой как кажется?
К сожалению Ваша оптимизация занимает 8 514 bytes (27%) памяти, а до этого была 7 954 bytes (25%).
Может мой быдлокод не такой плохой как кажется?
Свертывание шести одинаковых кейсов в одну компактную функцию - это однозначно более правильно, чем было. А почему более компактный код занял больше места - у меня есть некие мысли, вечером вам напишу. Я, видимо, где-то не совсем оптимально построил код, размер скетча явно должен быть менше.
К сожалению Ваша оптимизация занимает 8 514 bytes (27%) памяти, а до этого была 7 954 bytes (25%).
Может мой быдлокод не такой плохой как кажется?
Это не ваша заслуга. Это заслуга компилятора.)
Не хочу показаться назойливым, но Вы обещали помочь с оптимизацией !
Если Вы про использование регистра, так я же Вам дал ссылку - RTFМ прямо на этом сайте .
Вам нужно что-то ещё?
Не хочу показаться назойливым, но Вы обещали помочь с оптимизацией !
Не совсем так. Я обещал посмотреть, почему уменьшение скетча не привелу к уменьшению кода. Я мельком глянул - явных ошибок нет, на большее времени пока не хватило. Сегодня попытаюсь покопаться подробнее - мне самому этот вопрос интересен.
#include <avr/pgmspace.h> const char string_1[] PROGMEM = "Alarm"; const char string_2[] PROGMEM = "Time"; const char string_3[] PROGMEM = "Settings"; const char string_4[] PROGMEM = "Settings2"; const char string_5[] PROGMEM = "Settings3"; const char string_6[] PROGMEM = "back"; char * menu_table[] = {string_1, string_2, string_3, string_4, string_5, string_6}; void printMenu (int invertLine) { int i; myOLED.clrScr(); for (i = 0; i < 6; i++ ) { if (i == (invertLine - 1)) myOLED.invertText(true); char buffer[15]; strcpy_P(buffer, (char*)pgm_read_word(&(menu_table[i]))); myOLED.print( buffer, 10, i * 10); if (i == (invertLine - 1)) myOLED.invertText(false); } myOLED.update(); }qwone? ты меня потроллить решил? :)
Строки 16 и 17 не обязательны, возьми ИДЕ и проверь :)
И вообще - вопрос в другом - вставь этот код в код ТС из заголовка темы и убедись - число строк скетча сокращается с 200 до 150, а размер прошивки при этом растет с 6700 до 7700 байт. почему?
ПС: У меня этого железа нет, а значит и программу под это железо писать не могу. Потому что успешное компилирование и успешная работа это тоже разные вещи.
ПС: У меня этого железа нет, а значит и программу под это железо писать не могу. Потому что успешное компилирование и успешная работа это тоже разные вещи.
Ссылки на неунжное железо можно выкинуть, суть вопроса не в этом. Я, собственно, собирался сегодня об этом даже новую тему открыть (что у меня случается крайне редко) - но потом решил, что еще не готов, не все варианты кода попробовал. Я не совсем рад, что эта тема выплыла - рано еще - но если у кого есть свежие мысли, то велкам.
Добрый вечер уважаемые колеги.
#include <OLED_I2C.h> const char string_1[] PROGMEM = "Alarm"; const char string_2[] PROGMEM = "Time"; const char string_3[] PROGMEM = "Setting"; const char string_4[] PROGMEM = "Setting2"; const char string_5[] PROGMEM = "Setting3"; const char string_6[] PROGMEM = "back"; const char * menu_table[] ={string_1,string_2,string_3,string_4,string_5,string_6}; OLED myOLED(SDA, SCL, 1); extern uint8_t SmallFont[]; #define encoderPin1 2 #define encoderPin2 3 byte MSB ; byte LSB ; byte encoded = 0 ; byte lastEncoded = 0; byte sum; byte a = 0; byte b = 0; byte c = 0; volatile int d = 0; volatile int encoderValue = 0; byte menuPos = 1; byte val; byte val_old = 0; int i = 0; void setup(){ Serial.begin (9600); myOLED.begin(); myOLED.clrScr(); myOLED.setFont(SmallFont); DDRD &= ~(1<<2); DDRD &= ~(1<<3); PORTD |= 1<<2; PORTD |= 1<<3; PORTD |= 1<<4; // pinMode(4, INPUT); // Kнопка "Mеню" DDRD &= ~(1<<4); // digitalWrite(4, HIGH); attachInterrupt(0, updateEncoder, CHANGE); attachInterrupt(1, updateEncoder, CHANGE); } void loop(){ MainScreen(); if(!(PIND & 1<<4)){ delay(200); Menu(); } } void printMenu (byte invertLine) { byte i; myOLED.clrScr(); for (i = 0; i < 6; i++ ) {if (i == (invertLine - 1)) myOLED.invertText(true); myOLED.print((const __FlashStringHelper *) menu_table[i] , 10, i*10); if (i == (invertLine - 1)) myOLED.invertText(false); } myOLED.update(); } void updateEncoder(){ MSB = digitalRead(encoderPin1); LSB = digitalRead(encoderPin2); encoded = (MSB << 1) |LSB; sum = (lastEncoded << 2) | encoded; if(encoded==0b0000){ if(a==0){ encoderValue = encoderValue+d; c=1; a=1; b=0; } } if(encoded==0b0011){ if(b==0){ encoderValue = encoderValue+d; c=1; b=1; a=0; } } if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011){ d=+1; } if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000){ d=-1; } lastEncoded = encoded; } void MainScreen() { myOLED.clrScr(); myOLED.print("MainScreen", CENTER, 20); myOLED.printNumI(encoderValue, CENTER, 40); myOLED.update(); } void Menu(){ for (i=0; i<=500; i++){ val = encoderValue; //***************************** Выбор позиции в меню *********************** if(val > val_old){ menuPos = menuPos + 1; val_old = val; } if(menuPos > 6){ menuPos = 1; } if(val < val_old){ menuPos = menuPos - 1; val_old = val; } if(menuPos < 1){ menuPos = 6; } printMenu(menuPos); if (!(PIND & 1<<4)) { switch (menuPos) { case 1: MenuSetAlarm();break; case 2: MenuSetTime();break; case 3: MenuSetting();break; case 4: MenuSetting2();break; case 5: MenuSetting3();break; case 6: MainScreen();break; } } } } void MenuSetTime(){ for (i=0; i<=500; i++){ myOLED.clrScr(); myOLED.print("MenuSetTime", CENTER, 20); myOLED.update(); if(!(PIND & 1<<4)){break;} } } void MenuSetAlarm(){ for (i=0; i<=500; i++){ myOLED.clrScr(); myOLED.print("MenuSetAlarm", CENTER, 20); myOLED.update(); if(!(PIND & 1<<4)){break;} } } void MenuSetting(){ } void MenuSetting2(){ } void MenuSetting3(){ }Может библиотеку заменить на U8glib, она меньше весит, но сам я не справлюсь ?
Помогите мне пожалуйста.
Вообще-то скетч на Ардуине, если в ней должно быть меню надо начинать так :)
/**/ //------------------------------- typedef struct { uint16_t Name;/*выводимый текст*/ uint8_t PgUp; uint8_t PgDn; uint16_t Left; uint16_t Right; } MenuNote; //-------------------------------------- void Do0minus() {} /*обработчик 0 экрана*/ void Do0plus() {} /*обработчик 0 экрана*/ void Do1minus() {} /*обработчик 1 экрана*/ void Do1plus() {} /*обработчик 1 экрана*/ void Do2minus() {} /*обработчик 2 экрана*/ void Do2plus() {} /*обработчик 2 экрана*/ void Do3minus() {} /*обработчик 3 экрана*/ void Do3plus(){}/*обработчик 3 экрана*/ const char PROGMEM txt0[] = "0-punkt"; const char PROGMEM txt1[] = "1-punkt"; const char PROGMEM txt2[] = "2-punkt"; const char PROGMEM txt3[] = "3-punkt"; const MenuNote PROGMEM Menu[] = { /*имя,PgUp,PgDn,Left,Right*/ txt0, 0, 0, (uint16_t)Do0minus, (uint16_t)Do0plus, /*0-экран*/ txt1, 0, 0, (uint16_t)Do1minus, (uint16_t)Do1plus, /*1-экран*/ txt2, 0, 0, (uint16_t)Do2minus, (uint16_t)Do2plus, /*2-экран*/ txt3, 0, 0, (uint16_t)Do3minus, (uint16_t)Do3plus /*3-экран*/ }; //---------------------------------------- void setup() { } void loop() { }Разбирался, почему у меня после сокращения исходника на четверть размер прошивки вдруг вырос. Провел тесты, упростил скетч до предела - и НАШЕЛ.
Правда найти - не значит понять. Вот примеры, чтобы ВЫСВЕТИТЬ ЭФФЕКТ.
Эффект, надо сказать, классный.
Скетч номер 1
#include <OLED_I2C.h> OLED myOLED(SDA, SCL, 1); void setup() { myOLED.begin(); } void loop() { myOLED.print("Alarm", 10, 0); } Flash: 2786 bytes, RAM: 1050Скетч номер 2
#include <OLED_I2C.h> OLED myOLED(SDA, SCL, 1); const char string_1[] = "Alarm"; void setup() { myOLED.begin(); } void loop() { myOLED.print( string_1, 10, 10); } Flash: 4338 bytes, RAM: 1060Непостижимо. Откуда разница в 1500 байт? Можно было бы подумать, что для разных параметров вызываются разные функции myOLED.print(). Но параметр-то вроде одного типа - const char*
А что говорит дизассемблер?
Если хотите, чтобы я тоже попытался поломать голову, то дайте пожалуйста ссылку где Вы брали OLED_I2C.h(ну и вообще библиотеку), чтобы эксперимент чистым был.
Если хотите, чтобы я тоже попытался поломать голову, то дайте пожалуйста ссылку где Вы брали OLED_I2C.h(ну и вообще библиотеку), чтобы эксперимент чистым был.
Пожалуйста.
http://www.rinkydinkelectronics.com/library.php?id=79
b707, ну, понятно.
По идее разработчики системных вещей должны быть грамотными (очень), а здесь ситуация наоборот - Вы грамотнее разработчика библиотеки - отсюда и беда. Вы использовали константу, а он - нет.
Уберите const в строке 4 и скомпилируйте. Полюбуйтесь.
А потом (тоже интересно) ещё попробуйте ту же строку в виде
char*string_1 ="Alarm";)Проблема же в том, что разработчик библиотеки не предусмотрел метода print с константным параметром. У него параметр не объявлен константой (и, кстати, совершенно необоснованно). Ну, а коль так, Ваш компилятор тащит "службу защиты констант", с копированием, дублированием и восстановлением после вызова.
Почему он не сделал параметр константой - хрен его знает. Как говорил Мюллер в исполнении Броневого: "Невозможно понять логику непрофессионала".
ЕвгенийП, спасибо за ответ. Но яснее не стало. Назвать меня "грамотным" вы явно поспешили :)
Мне непонятно, почему код компилируется по разному. Ведь если автор библиотеки поленился обьявить параметр функции константой - это должно сказываться в обоих случаях, рахве нет?
Разве константная строка "Alarm" и константа const char string_1[] = "Alarm"; - это не один тип данных для компилятора?
Если ответ лежит в примерах, которые вы предлагаете проверить - тогда подождем до вечера, мне сейчас нечем компилировать.
это должно сказываться в обоих случаях, рахве нет?
Нет. Вот смотрите.
В "плохом" случае константа описана снаружи и, значит, что её читают из прогмема во время инициализации и с тех пор она живёт в RAM и ею теоретически может воспользоваться кто-то ещё, кроме оператора вызова функции. Функция же имеет право в неё нагадить, т.к. параметр функции не константый. И компилятор вставляет код для сохранения её неизменной независимо от того будет функция её менять или нет (копирование и восстановление, но на самом деле там здоровый кусок кода на все случаи жизни).
В "хорошем" случае эта константа стоит как литерал прямо в вызове функции, а значит она читается из прогмема непосредственно перед вызовом и после вызова её никто уже использовать не сможет - она никому не нужна, так что пусть себе функция в неё гадит, никого это не волнует.
понял, огромное спасибо.
Igoreck - практический вывод из этой дискуссии - надо чуть подправить библиотеку OLED_I2C.h. Я вечером посмотрю и напишу. что вам сделать. Думаю, получится выиграть порядка 1500 - 2000 байт в размере кода.
Но это касается флеш. Занятость оперативной памяти от этого почти не изменится - а у вас, насколько я вижу - загвоздка в этом. Чтобы решить эту проблему кардинально - надо выбирать другую библиотеку ОЛЕД или вообще писать свою.
Кстати, попробовал поменять в библиотеке тип параметра на const (ну, и всё, что для этого надо аккуратно сделал). Ваш "плохой пример" сразу стал нормально компилироваться с нормальным размером.
P.S. Заодно глянул код библиотеки - действительно очень по-любительски написано.
Так накидал примерный скетч Меню, работает. Если ТС разберется, то сможет применить.
/**/ unsigned long mill;// переменная для millis() typedef void (*pDo)() ;// тип -функция обработчик //------------------------------- typedef struct { uint16_t Name;/*текст страницы*/ uint8_t ThisLine;/*текущая строка*/ uint8_t TopLine;/*верхняя строка*/ uint8_t LowerLine;/*нижняя строка*/ uint8_t UpPg;/*верхняя страница*/ uint8_t DnPg;/*нижняя страница*/ uint16_t DoExe;/*обработчик привязанный к странице*/ } MenuNote; //------Cl_Display---------------------- // класс регулярный вывод на дисплей class Cl_Display { protected: pDo Do;//обработчик bool refreshON = 1; //сигнал обновить public: /*конструктор*/ Cl_Display(pDo D): Do(D) {} /*инициализация-вставить в setup()*/ void init() { } /*работа-вставить в loop()*/ void run() { if (refreshON) { refreshON = 0; Do(); } } void refresh() { refreshON = 1; } /*записать новый обработчик*/ void write( pDo D) { Do = D; } }; //------Cl_Btn---------------------- // класс кнопка class Cl_Btn { protected: const byte pin; pDo Do;//обработчик bool bounce = 0; bool btn = 1, oldBtn; unsigned long past; public: /*конструктор*/ Cl_Btn(byte p, pDo D): pin(p), Do(D) {} /*инициализация-вставить в setup()*/ void init() { pinMode(pin, INPUT_PULLUP); } /*работа-вставить в loop()*/ void run() { bool newBtn = digitalRead(pin); if (!bounce && newBtn != btn) { bounce = 1; past = mill; } if (bounce && mill - past >= 10) { bounce = 0 ; oldBtn = btn; btn = newBtn; past = mill; if (!btn && oldBtn) Do(); } } /*записать новый обработчик*/ void write( pDo D) { Do = D; } }; //-------------------------------------- const byte maxScreen = 6; byte screen = 0;// текущий экран void DoExe0() { /*обработчик 0 экрана*/ Serial.println(); Serial.print("DoExe0"); } void DoExe1() { /*обработчик 1 экрана*/ Serial.println(); Serial.print("DoExe1"); } void DoExe2() { /*обработчик 2 экрана*/ Serial.println(); Serial.print("DoExe2"); } void DoExe3() { /*обработчик 3 экрана*/ Serial.println(); Serial.print("DoExe3"); } void DoExe4() {/*обработчик 4 экрана*/ Serial.println(); Serial.print("DoExe4"); } void DoExe5() { /*обработчик 5 экрана*/ Serial.println(); Serial.print("DoExe5"); } const char txt0[] PROGMEM = "Alarm"; const char txt1[] PROGMEM = "Time"; const char txt2[] PROGMEM = "Setting"; const char txt3[] PROGMEM = "Setting2"; const char txt4[] PROGMEM = "Setting3"; const char txt5[] PROGMEM = "Back"; const MenuNote PROGMEM Menu[maxScreen] = { /*Name,ThisLine,TopLine,LowerLine,UpPg,DnPg,DoExe*/ {txt0 , 0 , 5 , 0 , 0 , 1 , (uint16_t)DoExe0}, /*0-экран*/ {txt1 , 1 , 5 , 0 , 0 , 2 , (uint16_t)DoExe1}, /*1-экран*/ {txt2 , 2 , 5 , 0 , 1 , 3 , (uint16_t)DoExe2}, /*2-экран*/ {txt3 , 3 , 5 , 0 , 2 , 4 , (uint16_t)DoExe3}, /*3-экран*/ {txt4 , 4 , 5 , 0 , 3 , 5 , (uint16_t)DoExe4}, /*4-экран*/ {txt5 , 5 , 5 , 0 , 4 , 5 , (uint16_t)DoExe5} /*5-экран*/ }; // дисплей /*вывеcти страницу на дисплей*/ void vievPg() { byte ThisLine = (uint8_t)pgm_read_byte_near(&Menu[screen].ThisLine); byte TopLine = (uint8_t)pgm_read_byte_near(&Menu[screen].TopLine); byte LowerLine = (uint8_t)pgm_read_byte_near(&Menu[screen].LowerLine); Serial.println(); for (byte i = LowerLine; i <= TopLine; ++i) { char buffer[15]; strcpy_P(buffer, (char*)pgm_read_word(&Menu[i].Name)); Serial.println(); if (i == ThisLine) Serial.print(">"); else Serial.print(" "); Serial.print(buffer); } } Cl_Display Display(/*обработчик*/vievPg); /*перейти на верхнюю строчку*/ void GoTopLine() { screen = (uint8_t)pgm_read_byte_near(&Menu[screen].UpPg); Display.refresh(); } /*перейти на нижнюю строчку*/ void GoLowerLine() { screen = (uint8_t)pgm_read_byte_near(&Menu[screen].DnPg); Display.refresh(); } Cl_Btn BtnUp (/*пин*/2,/*обработчик*/GoTopLine);/*Кнопка строка вверх*/ Cl_Btn BtnDown(/*пин*/3,/*обработчик*/GoLowerLine);/*Кнопка строка вниз*/ /*Выполнить обработчик строки*/ void DoExe() { pDo Do = (pDo)pgm_read_word_near(&Menu[screen].DoExe); Do(); //Display.refresh(); } Cl_Btn BtnExe(/*пин*/4,/*обработчик*/DoExe);/*Кнопка Выполнить*/ //---main()------------------------------------- void setup() { Serial.begin(9600); Display.init(); BtnUp.init(); BtnDown.init(); BtnExe.init(); } void loop() { mill = millis(); Display.run(); BtnUp.run(); BtnDown.run(); BtnExe.run(); } /*Скетч использует 2662 байт (8%) памяти устройства. Всего доступно 30720 байт. Глобальные переменные используют 270 байт (13%) динамической памяти, оставляя 1778 байт для локальных переменных. Максимум: 2048 байт. */Ценю Ваш труд колега, но есть вопросы.
Мои вам соболезнования и вашему компилятору. Как вариант могу этот вариант скинуть . Но у меня все в норме
/**/ unsigned long mill;// переменная для millis() typedef void (*pDo)() ;// тип -функция обработчик //------------------------------- typedef struct { const char *Name;/*текст страницы*/ const uint8_t ThisLine;/*текущая строка*/ const uint8_t TopLine;/*верхняя строка*/ const uint8_t LowerLine;/*нижняя строка*/ const uint8_t UpPg;/*верхняя страница*/ const uint8_t DnPg;/*нижняя страница*/ const pDo DoExe;/*обработчик привязанный к странице*/ } MenuNote; //------Cl_Display---------------------- // класс регулярный вывод на дисплей class Cl_Display { protected: pDo Do;//обработчик bool refreshON = 1; //сигнал обновить public: /*конструктор*/ Cl_Display(pDo D): Do(D) {} /*инициализация-вставить в setup()*/ void init() { } /*работа-вставить в loop()*/ void run() { if (refreshON) { refreshON = 0; Do(); } } void refresh() { refreshON = 1; } /*записать новый обработчик*/ void write( pDo D) { Do = D; } }; //------Cl_Btn---------------------- // класс кнопка class Cl_Btn { protected: const byte pin; pDo Do;//обработчик bool bounce = 0; bool btn = 1, oldBtn; unsigned long past; public: /*конструктор*/ Cl_Btn(byte p, pDo D): pin(p), Do(D) {} /*инициализация-вставить в setup()*/ void init() { pinMode(pin, INPUT_PULLUP); } /*работа-вставить в loop()*/ void run() { bool newBtn = digitalRead(pin); if (!bounce && newBtn != btn) { bounce = 1; past = mill; } if (bounce && mill - past >= 10) { bounce = 0 ; oldBtn = btn; btn = newBtn; past = mill; if (!btn && oldBtn) Do(); } } /*записать новый обработчик*/ void write( pDo D) { Do = D; } }; //-------------------------------------- const byte maxScreen = 6; byte screen = 0;// текущий экран void DoExe0() { /*обработчик 0 экрана*/ Serial.println(); Serial.print("DoExe0"); } void DoExe1() { /*обработчик 1 экрана*/ Serial.println(); Serial.print("DoExe1"); } void DoExe2() { /*обработчик 2 экрана*/ Serial.println(); Serial.print("DoExe2"); } void DoExe3() { /*обработчик 3 экрана*/ Serial.println(); Serial.print("DoExe3"); } void DoExe4() {/*обработчик 4 экрана*/ Serial.println(); Serial.print("DoExe4"); } void DoExe5() { /*обработчик 5 экрана*/ Serial.println(); Serial.print("DoExe5"); } const char txt0[] PROGMEM = "Alarm"; const char txt1[] PROGMEM = "Time"; const char txt2[] PROGMEM = "Setting"; const char txt3[] PROGMEM = "Setting2"; const char txt4[] PROGMEM = "Setting3"; const char txt5[] PROGMEM = "Back"; const MenuNote PROGMEM Menu[maxScreen] = { /*Name,ThisLine,TopLine,LowerLine,UpPg,DnPg,DoExe*/ {txt0 , 0 , 5 , 0 , 0 , 1 , &DoExe0}, /*0-экран*/ {txt1 , 1 , 5 , 0 , 0 , 2 , &DoExe1}, /*1-экран*/ {txt2 , 2 , 5 , 0 , 1 , 3 , &DoExe2}, /*2-экран*/ {txt3 , 3 , 5 , 0 , 2 , 4 , &DoExe3}, /*3-экран*/ {txt4 , 4 , 5 , 0 , 3 , 5 , &DoExe4}, /*4-экран*/ {txt5 , 5 , 5 , 0 , 4 , 5 , &DoExe5} /*5-экран*/ }; // дисплей /*вывеcти страницу на дисплей*/ void vievPg() { byte ThisLine = (uint8_t)pgm_read_byte_near(&Menu[screen].ThisLine); byte TopLine = (uint8_t)pgm_read_byte_near(&Menu[screen].TopLine); byte LowerLine = (uint8_t)pgm_read_byte_near(&Menu[screen].LowerLine); Serial.println(); for (byte i = LowerLine; i <= TopLine; ++i) { char buffer[15]; strcpy_P(buffer, (char*)pgm_read_word(&Menu[i].Name)); Serial.println(); if (i == ThisLine) Serial.print(">"); else Serial.print(" "); Serial.print(buffer); } } Cl_Display Display(/*обработчик*/vievPg); /*перейти на верхнюю строчку*/ void GoTopLine() { screen = (uint8_t)pgm_read_byte_near(&Menu[screen].UpPg); Display.refresh(); } /*перейти на нижнюю строчку*/ void GoLowerLine() { screen = (uint8_t)pgm_read_byte_near(&Menu[screen].DnPg); Display.refresh(); } Cl_Btn BtnUp (/*пин*/2,/*обработчик*/GoTopLine);/*Кнопка строка вверх*/ Cl_Btn BtnDown(/*пин*/3,/*обработчик*/GoLowerLine);/*Кнопка строка вниз*/ /*Выполнить обработчик строки*/ void DoExe() { pDo Do = (pDo)pgm_read_word_near(&Menu[screen].DoExe); Do(); //Display.refresh(); } Cl_Btn BtnExe(/*пин*/4,/*обработчик*/DoExe);/*Кнопка Выполнить*/ //---main()------------------------------------- void setup() { Serial.begin(9600); Display.init(); BtnUp.init(); BtnDown.init(); BtnExe.init(); } void loop() { mill = millis(); Display.run(); BtnUp.run(); BtnDown.run(); BtnExe.run(); } /*Скетч использует 2662 байт (8%) памяти устройства. Всего доступно 30720 байт. Глобальные переменные используют 270 байт (13%) динамической памяти, оставляя 1778 байт для локальных переменных. Максимум: 2048 байт. */Igoreck.
Как обещал - пишу что надо поправить в библиотеке OLED_I2C.h.
=== В файле OLED_I2C.h ===
---- строка 113
void print(char *st, int x, int y);
исправить на
void print(const char *st, int x, int y);
=== В файле OLED_I2C.cpp ===
---- строка 181
void OLED::print(char *st, int x, int y)
исправить на
void OLED::print(const char *st, int x, int y)
===========================
У меня исправление двух этих строк уменьшают ваш код на 1450 байт.
Спасибо огромное, мне очень приятно что Вы находите на это время, и помогаете.
На чем Вы работаете?
Какая у Вас среда и версия разработки?
Можно ли в Visual Studio, но заливать потом как?
На чем Вы работаете?
Какая у Вас среда и версия разработки?
Ваш код я проверял на Ардуино ИДЕ 1.8.3, Вин7 х64
Тогда все ясно- 1.6.5!
Тогда все ясно- 1.6.5!
А что, что-то не работает?
Да тут Qwone пишет что соболезнует моему компилятору, поэтому я разпереживался.
Можно ли в Visual Studio, но заливать потом как?
при уже установленной Arduino IDE добавить в Visual Studio плагин Visual Micro