Если в коде из #195 перенести метод write в public и добавить шесть строчек (в моём коде ниже) помечены комментарием «/*** GIFT ***/», то можно писать, например, вот так:
class Cl_aaa { //<- некий класс
public:
void go() { //<- метод класса 1
Serial.println("aaa.go()");
}
void ON() { //<- метод класса 2
Serial.println("aaa.ON()");
}
};
typedef void (Cl_aaa::*clDo)();// <- тип переменной метод класса Cl_aaa
Cl_aaa aaa;
//--------------------------
void setup() {
Serial.begin(9600);
Serial.println("Tuc");
clDo Do = &Cl_aaa::ON; //<-- создать переменую и присвоить значение метод класса
(aaa.*Do)(); //<- выполнить функцию записаную в переменной
aaa.go();
}
void loop() {
}
Организовать меню используя один потенциометр вместо энкодера не получится. Но используя потенциометр и кнопку можно организовать ввод пароля или чего-то еще.
/**/
//------дисплей lcd2004_i2c-----------------------------
#include <Wire.h>
// команды
#define LCD_CLEARDISPLAY 0x01
#define LCD_RETURNHOME 0x02
#define LCD_ENTRYMODESET 0x04
#define LCD_DISPLAYCONTROL 0x08
#define LCD_CURSORSHIFT 0x10
#define LCD_FUNCTIONSET 0x20
#define LCD_SETCGRAMADDR 0x40
#define LCD_SETDDRAMADDR 0x80
// флаги для режима ввода дисплея
#define LCD_ENTRYRIGHT 0x00
#define LCD_ENTRYLEFT 0x02
#define LCD_ENTRYSHIFTINCREMENT 0x01
#define LCD_ENTRYSHIFTDECREMENT 0x00
// флаги для управления включением / выключением дисплея
#define LCD_DISPLAYON 0x04
#define LCD_DISPLAYOFF 0x00
#define LCD_CURSORON 0x02
#define LCD_CURSOROFF 0x00
#define LCD_BLINKON 0x01
#define LCD_BLINKOFF 0x00
// флаги для отображения / сдвига курсора
#define LCD_DISPLAYMOVE 0x08
#define LCD_CURSORMOVE 0x00
#define LCD_MOVERIGHT 0x04
#define LCD_MOVELEFT 0x00
// флаги для набора функций
#define LCD_8BITMODE 0x10
#define LCD_4BITMODE 0x00
#define LCD_2LINE 0x08
#define LCD_1LINE 0x00
#define LCD_5x10DOTS 0x04
#define LCD_5x8DOTS 0x00
// флаги для управления подсветкой
#define LCD_BACKLIGHT 0x08
#define LCD_NOBACKLIGHT 0x00
#define En B00000100 // Бит разрешения
#define Rw B00000010 // Чтение / запись бит
#define Rs B00000001 // Бит выбора регистра
const byte custom[8][8] PROGMEM = {
{0, 0, 0, 0, 0, 0, 0, 0},// \0
{31, 31, 31, 0, 0, 0, 0, 0},// \1
{0, 0, 0, 31, 31, 31, 0, 0},// \2
{31, 31, 31, 31, 31, 31, 0, 0},// \3
{0, 0, 0, 0, 0, 0, 31, 31},// \4
{31, 31, 31, 0, 0, 0, 31, 31},// \5
{0, 4, 12, 31, 12, 4, 0, 0},// \6
{31, 31, 31, 31, 31, 31, 31, 31} // \7
};
class Cl_lcd2004_i2c : public Print {
protected:
uint8_t adr, posX, posY;
uint8_t _backlightval;
uint8_t _displayfunction;
uint8_t _displaycontrol;
uint8_t _displaymode;
byte buffer[80];
public:
Cl_lcd2004_i2c(uint8_t a): adr(a) {}
void init() {
Wire.begin();
write4bits(0x03 << 4);
delayMicroseconds(4500); // wait min 4.1ms
write4bits(0x03 << 4);
delayMicroseconds(4500); // wait min 4.1ms
write4bits(0x03 << 4);
delayMicroseconds(150);
write4bits(0x02 << 4);
delay(50);
_backlightval = LCD_NOBACKLIGHT;
expanderWrite(_backlightval); // сбросить расширение и выключить подсветку (бит 8 = 1)
// режим работы дисплея 4-х битный интерфейс ,две строки,5х8 точек
_displayfunction = LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS;
command(LCD_FUNCTIONSET | _displayfunction);
// режим контроля дисплей вкл, курсор не мигает,дисплей не мигает
_displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
command(LCD_DISPLAYCONTROL | _displaycontrol);
// режим ввода текста в память-начинать слева с движением в право
_displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
command(LCD_ENTRYMODESET | _displaymode);
for (int i = 0; i < 8; i++)
createCharPROGMEM(i, custom[i]);
clear();
}
// подсветку вкл/выкл
void backlight(void) {
_backlightval = LCD_BACKLIGHT;
expanderWrite(0);
}
void noBacklight(void) {
_backlightval = LCD_NOBACKLIGHT;
expanderWrite(0);
}
// очистить буфер
void clear() {
for (byte i = 0; i < 80; i++ )buffer[i] = 0x20;
posX = 0; posY = 0;
}
// отправить информацию из буфера на экран
void show() {
line(0);
for (byte i = 0; i < 20; i++ )out(buffer[i]);
line(1);
for (byte i = 20; i < 40; i++ )out(buffer[i]);
line(2);
for (byte i = 40; i < 60; i++ )out(buffer[i]);
line(3);
for (byte i = 60; i < 80; i++ )out(buffer[i]);
}
void setCursor(byte x, byte y) {
if (x > 20) x = 20;
else posX = x;
if (y > 4) x = 4;
else posY = y;
}
inline size_t write(uint8_t value) {
if (posX < 20 && posY < 4) {
buffer[posY * 20 + posX] = value;
posX++;
}
return 1;
}
void createCharPROGMEM(uint8_t location, const uint8_t *charmap) {
location &= 0x7; // we only have 8 locations 0-7
command(LCD_SETCGRAMADDR | (location << 3));
for (int i = 0; i < 8; i++) {
out(pgm_read_byte_near(charmap + i));
}
}
void createChar(uint8_t location, uint8_t charmap[]) {
location &= 0x7; // we only have 8 locations 0-7
command(LCD_SETCGRAMADDR | (location << 3));
for (int i = 0; i < 8; i++) {
out(charmap[i]);
}
}
private:
/*внутрение функции*/
void line(byte l) {
switch (l) {
case 0: command(LCD_SETDDRAMADDR + 0x00);
break;
case 1: command(LCD_SETDDRAMADDR + 0x40);
break;
case 2: command(LCD_SETDDRAMADDR + 0x14);
break;
case 3: command(LCD_SETDDRAMADDR + 0x54);
break;
}
}
inline void out(uint8_t value) {
send(value, Rs);
}
/*команды низкоуровневого управления*/
inline void command(uint8_t value) {
send(value, 0);
}
void send(uint8_t value, uint8_t mode) {
uint8_t highnib = value & 0xf0;
write4bits((highnib) | mode);
uint8_t lownib = (value << 4) & 0xf0;
write4bits((lownib) | mode);
}
void write4bits(uint8_t value) {
expanderWrite(value);
pulseEnable(value);
}
void expanderWrite(uint8_t _data) {
Wire.beginTransmission(adr);
Wire.write((int)(_data) | _backlightval);
Wire.endTransmission();
}
void pulseEnable(uint8_t _data) {
expanderWrite(_data | En); // En high
delayMicroseconds(1); // enable pulse must be >450ns
expanderWrite(_data & ~En); // En low
delayMicroseconds(50); // commands need > 37us to settle
}
};
typedef void (Cl_lcd2004_i2c::*clDo)(); // <- тип переменной метод класса Cl_lcd2004_i2c
inline Cl_lcd2004_i2c & operator <<(Cl_lcd2004_i2c &s, clDo Do) {
(s.*Do)();
return s;
}
template <typename T> inline Cl_lcd2004_i2c & operator << (Cl_lcd2004_i2c &s, T n) {
s.print(n);
return s;
}
Cl_lcd2004_i2c lcd(0x3F);//0x27
//--------------------------------------------------
class Cl_aaa {
protected:
const byte pin;
unsigned long past;
void read() {
int b = analogRead(pin);
if (b < 90)value = '0';
else if (b < 180)value = '1';
else if (b < 270)value = '2';
else if (b < 360)value = '3';
else if (b < 450)value = '4';
else if (b < 540)value = '5';
else if (b < 630)value = '6';
else if (b < 720)value = '7';
else if (b < 810)value = '8';
else if (b < 900)value = '9';
else value = '\6';
past = millis();
}
public:
char value;
Cl_aaa(byte p): pin(p) {}
void init() {
read();
}
void run() {
if (millis() - past >= 200) read();
}
};
Cl_aaa aaa(/*пин*/A0);
//------- кнопки ---------------------------
typedef void (*pDo)();
class Cl_Btn {
protected:
byte pin;
bool state;
unsigned long past;
void set(bool s) {
state = s;
past = millis();
if (s) Do();
}
public:
Cl_Btn(byte p): pin(p) {}
pDo Do = [] {};
void init() {
pinMode(pin, INPUT_PULLUP);
set(false);
}
void run() {
if (millis() - past >= 100)
switch (state) {
case false:
if (!digitalRead(pin))set(true);
break;
case true:
if (digitalRead(pin))set(false);
//if (millis() - past >= 300)set(false);
break;
}
}
};
Cl_Btn BtnS(/*пин*/2);
//-----------------------------------------------
const byte page0 = 0;
const byte page1a = 10;
const byte page1b = 11;
byte page;
unsigned long past;
String str("ABC");
void goPage(byte p) {
page = p;
past = millis();
switch (page) {
case page0:
break;
case page1a:
case page1b:
{ lcd << &Cl_lcd2004_i2c::clear << str ;
if (page == page1a) lcd << aaa.value;
else lcd << '\7';
lcd << &Cl_lcd2004_i2c::show; // вывод сообщения на экран
}
BtnS.Do = [] {
switch (aaa.value) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
str += aaa.value;
break;
case '\6':
str = "";
break;
}
}; // конец лямда
break;//page
}
}
void menu_init() {
goPage( page1a);
}
void menu_run() {
if (page == page1a && millis() - past >= 300)goPage( page1b);
if (page == page1b && millis() - past >= 300)goPage( page1a);
}
//-----------------------------------------------
void setup() {
lcd << &Cl_lcd2004_i2c::init << &Cl_lcd2004_i2c::backlight;// инициализация
aaa.init();
BtnS.init();
menu_init();
}
void loop() {
aaa.run();
BtnS.run();
menu_run();
}
Не правда ли что метод Do похож на виртуальную функцию. Но фишка не в этом. Вот к примеру пишем мы графическую библиотеку. И для установки пикселя в байте в зависимости от цвета нужно производить или логическое сложение или логическое умножение. А если много то этот анализ проводить для каждого пикселя. А этим способом мы можем банально прописать нужный "карандаш" однократно и дальше не заморачиваться в попиксельной работе.
А этим способом мы можем банально прописать нужный "карандаш" однократно и дальше не заморачиваться в попиксельной работе.
А лямбды-то зачем? Чем не угодил обычный указатель на функцию?
Я вот смотрю на Ваши лямбды и никак не возьму в толк для чего Вы их тянете туда, где достаточно обычного указателя? Это примерно как ставить микроконтроллер для того, чтобы сделать плавное выключение лампочки - работать, конечно, будет, но ведь там достаточно конденсатора!
Главная фишка лямбд в том, что они тянут за собой внешний контекст и являются функциями высшего порядка (вернее с их помощью такие функции строятся - та же свёртка). Вы же никогда этого (зазвата внешнего контекста) не используете, функций высших порядков не строите, а без этого лямбда не даёт никаких преимуществ по сравнению с обычной, именованной функцией и указателем на неё. Ну, вообще никаких.
Есть глобальные переменные,есть локальные, есть даже статик переменные. Но в Си есть глобальные функции, а вот с локальными или статик функциями не очень . Но есть некий эрзац . Лямда это один из вариантов эрзаца.
Ну, не знаю, освойте функторы - те же локальные функции, но с ними можно и как с переменными работать (параметром передавать, операции выполнять). Лямбда собственно тоже функтор, но она ещё много чего - это огромная пушка для воробья - локальной функции.
О. Хочу спросить уважаемого ЕвгенияП. Если у меня одна функция в качестве параметров требует указатель на другую функцию, чтоб её потом вызвать, а та функция короткая в одну строку, можно ли передать её лямбдой, или это тоже из пушки пабабачкам?
Главная фишка лямбд в том, что они тянут за собой внешний контекст
правильно называется "замыкание" и это действительно одна из двух главных фишек лямбда-выражений в этом языке. Другая - то, что они (лямбда-выражения) являются функторами. Без этих двух фишек (а ты их не используешь) лямбда-выражения теряют смысл и не дают никаких выгод по сравнению с указателями на функции.
(Хотя, многие говорят, что это на самом деле одна фишка, а не две - первая. т.к. замыкание, по определению, функция первого класса, стало быть замыкание можно рассматривать как функтор)
требует указатель на другую функцию, чтоб её потом вызвать, а та функция короткая в одну строку, можно ли передать её лямбдой, или это тоже из пушки пабабачкам?
Делай как тебе удобно и не парься. С точки зрения кода особой разницы нет, как уже писали и я, и петрович, если не использовать замыкания, то лямбда ничем особым не отличается от указателя на функцию.
Просто лямбды - гораздо более мощный механизм, чем указатели на функции, а раз Пух явно интересуется, хочется помочь ему освоить его на более глубоком уровне, а то сейчас он похоже, просто пихает лямбды ради того, чтобы пихать лямбды.
Делай как тебе удобно и не парься. С точки зрения кода особой разницы нет, как уже писали и я, и петрович, если не использовать замыкания, то лямбда ничем особым не отличается от указателя на функцию.
Просто лямбды - гораздо более мощный механизм, чем указатели на функции, а раз Пух явно интересуется, хочется помочь ему освоить его на более глубоком уровне, а то сейчас он похоже, просто пихает лямбды ради того, чтобы пихать лямбды.
Мда. Пора читать, полупьяный щуря глаз, про функторы и замыкания. А то так дураком и помру.
Дед, это штучки из функционального программирования, оно те правда надо?
А если реально хочется поиграться всякими лямбдами, замыканиями и прочими свёртками, то уж лучше делать это не на С++, где они притянуты через задницу, а на каком-нибудь языке, где они естественны. Например, возьми Haskell. Классный язык и там всё это естественно и натурально, он собственно для этого и создавался. Особенно мне нравится как в википедии определили его (языка) класс: "Класс языка: функциональный, ленивый, модульный". Как видишь, что-то родное в нём есть :)
Делай как тебе удобно и не парься. С точки зрения кода особой разницы нет, как уже писали и я, и петрович, если не использовать замыкания, то лямбда ничем особым не отличается от указателя на функцию.
Просто лямбды - гораздо более мощный механизм, чем указатели на функции, а раз Пух явно интересуется, хочется помочь ему освоить его на более глубоком уровне, а то сейчас он похоже, просто пихает лямбды ради того, чтобы пихать лямбды.
Мда. Пора читать, полупьяный щуря глаз, про функторы и замыкания. А то так дураком и помру.
Не торописЯ. Это новодел в плюсах. Надо обождать лет десять пока устаканится, концепция выпрямится и компиляторы допиляют до какогото единообразия в понимании стандарта. Я еще в 1.6.5 попробовал, наплевался и расслабился. Так шо наливай. Без замыкания 30 лет писали и ниче. Конечно лямдами нужно пользоваться т.к. менше имен придумывать. Главное внутр [] ничего не пиши! Вон как квон делает: классы, но без наследования, лямбды, но без замыкания. У него и вотка без спирту!
Продолжу. Вот к примеру надо написать библиотеку под lcd5110.(Знаю написана). Но как там решается проблема различия кода на аппаратном SPI и программном. Но ведь можно решить так. И нет плясок с бубном.
Отстаньте от него, у него свое виденье. Он же четко указал, обращать внимание на строку 10. Наверно const приветствовать аплодисментами. В остальное селедку заворачивал, index зарезервировал для будущих применений.
Поясните, пожалуйста? Почему надо на это обращать внимание? Потому, что сделано так, чтобы могло быть только в правой части присваивания? Чтобы нельзя было экземпляру присвоить значение как обычному bool? Это-то я понял. А вот из каких соображений это было сделано, поясните пожалуйста.
удастся заслушать начальника транспортного цеха? (энкодер), или как говорила экономист, когда мы автоматизировали одно предприятие, моя работа не поддаётся автоматизации )))
Мне энкодер как устройство регулировки давно перестало нравится. Глючное устройство. Где-то в моих темах валяется этот компонент. Так что заменить кнопки энкодером не трудно для разумного человека.
Продолжу. Если же надо к примеру использовать 10 однородных устройств и 3 комплектами настроек.
/**/
#include "qwonelib.h"
//-------------------
struct data_t { // некая пользовательская структура
byte bData;
int iData;
float fData;
};
byte index = 0;
const byte max_index = 10;
data_t EEMEM adr1[max_index]; // размещение ее в EEPROM
byte setting_index = 0;
const byte max_setting_index = 3;
void setting(byte in) {
static const PROGMEM data_t adr2[3] = { // набор констант для пользовательской функции
{100, 1000, 10.10} // 0 комплект настроек
, {101, 1001, 10.11} // 1 комплект настроек
, {102, 1002, 10.12} // 2 комплект настроек
};
(eeRef <byte>) (&adr1[in].bData) = (pgmRef<byte>) (&adr2[setting_index].bData); // загрузка байтовой части
(eeRef <int>) (&adr1[in].iData) = (pgmRef<int>) (&adr2[setting_index].iData); // загрузка интовой части
(eeRef <float>)(&adr1[in].fData) = (pgmRef<float>)(&adr2[setting_index].fData); // загрузка флоат части
}
//---кнопки-----------------------------
typedef void (*pDo)();
class Cl_btn {
protected:
byte pin;
bool state;
unsigned long past;
void set(bool s) {
state = s;
past = millis();
if (s == true) Do();
}
public:
Cl_btn(byte p): pin(p) {}
pDo Do = [] {};
void init() {
pinMode(pin, INPUT_PULLUP);
set(false);
}
void run() {
if (millis() - past >= 100)
switch (state) {
case false:
if (!digitalRead(pin))set(true);
break;
case true:
if (digitalRead(pin))set(false);
if (millis() - past >= 300)set(false);
break;
}
}
};
Cl_btn BtnS(/*пин*/2); //кнопка селект
Cl_btn BtnU(/*пин*/3); //кнопка верх
Cl_btn BtnD(/*пин*/4); //кнопка вниз
//--------------- меню---------------------------------------------
template <typename T> inline Print & operator << (Print &s, T n) {
s.print(n);
return s;
}
const byte page0 = 0; //ноказ настроек
const byte page0a = 5;// поменять индекс устройства
const byte page1 = 10;//изменение байтовой части
const byte page2 = 20;//изменение интовой части
const byte page3 = 30;//изменение флоат части
const byte page4 = 40; //сброс настроек
byte page;
unsigned long past;
void goPage(byte p) {
past = millis();
page = p;
switch (page) {
case page0:
BtnS.Do = [] {goPage(page0a);};
BtnU.Do = [] {};
BtnD.Do = [] {};
Serial << "info:\n";
Serial << "byte(" << index << ") =" << (eeRef <byte>) (&adr1[index].bData) << '\n'; // вывод байтовой части
Serial << "int(" << index << ") =" << (eeRef <int>) (&adr1[index].iData) << '\n'; // вывод интовой части
Serial << "float(" << index << ")=" << (eeRef <float>)(&adr1[index].fData) << '\n'; // вывод флоат части
break;
case page0a:
BtnS.Do = [] {goPage(page1);};
BtnU.Do = [] {
if (index < (max_index - 1))index++;
goPage(page0a);
};
BtnD.Do = [] {
if (index > 0)index--;
goPage(page0a);
};
Serial << "set index:" << index << "\n";
break;
case page1:
BtnS.Do = [] {goPage(page2);};
BtnU.Do = [] {
if ((eeRef <byte>) (&adr1[index].bData) <= 200)(eeRef <byte>) (&adr1[index].bData) += 10;
goPage(page1);
};
BtnD.Do = [] {
if ((eeRef <byte>) (&adr1[index].bData) >= 50)(eeRef <byte>) (&adr1[index].bData) -= 10;
goPage(page1);
};
Serial << "set byte(" << index << ")=";
Serial << (eeRef <byte>) (&adr1[index].bData) << '\n'; // вывод байтовой части
break;
case page2:
BtnS.Do = [] {goPage(page3);};
BtnU.Do = [] {
if ((eeRef <int>) (&adr1[index].iData) <= 2000)(eeRef <int>) (&adr1[index].iData) += 100;
goPage(page2);
};
BtnD.Do = [] {
if ((eeRef <int>) (&adr1[index].iData) >= 500)(eeRef <int>) (&adr1[index].iData) -= 100;
goPage(page2);
};
Serial << "set int(" << index << ")=";
Serial << (eeRef <int>) (&adr1[index].iData) << '\n'; // вывод интовой части
break;
case page3:
BtnS.Do = [] {goPage(page4);};
BtnU.Do = [] {
if ((eeRef <float>) (&adr1[index].fData) <= 20.30)(eeRef <float>) (&adr1[index].fData) += 1.01;
goPage(page3);
};
BtnD.Do = [] {
if ((eeRef <float>) (&adr1[index].fData) >= 5.05)(eeRef <float>) (&adr1[index].fData) -= 1.01;
goPage(page3);
};
Serial << "set float(" << index << ")=";
Serial << (eeRef <float>)(&adr1[index].fData) << '\n'; // вывод флоат части
break;
case page4:
BtnS.Do = [] {goPage(page0);};
BtnU.Do = [] {
if (setting_index < (max_setting_index - 1))setting_index++;
setting(index);
goPage(page4);
};
BtnD.Do = [] {
if (setting_index > 0)setting_index--;
setting(index);
goPage(page4);
};
Serial << "setting(" << setting_index << ")\n";
Serial << "byte(" << index << ") =" << (eeRef <byte>) (&adr1[index].bData) << '\n'; // вывод байтовой части
Serial << "int(" << index << ") =" << (eeRef <int>) (&adr1[index].iData) << '\n'; // вывод интовой части
Serial << "float(" << index << ")=" << (eeRef <float>)(&adr1[index].fData) << '\n'; // вывод флоат части
break;
}
}
void menu_init() {
Serial.begin(9600);
goPage(page0);
}
void menu_run() {}
//----------------------------------------
void setup() {
BtnS.init();
BtnU.init();
BtnD.init();
menu_init();
}
void loop() {
BtnS.run();
BtnU.run();
BtnD.run();
menu_run();
}
Мне энкодер как устройство регулировки давно перестало нравится. Глючное устройство.
перебирал библиотеки от разных авторов, даже на библиотеку Гайвера набрёл, нашёл ту, что подошла идеально, автор пишет, если ваш энкодер даёт глюки на моей библиотеке, то он настолько плох и раздолбан, что просто его выкиньте, эксперименты провожу с энкодером в чистом виде, ни резисторов ни конденсаторов в обвязке нет, пины вверх не притягиваю, видимо всё реализовано в библиотеке, твой код кнопок использую )))
Все верно, не знаю что за либа, но знаю что при правильной реализации все ок. И категорически, не при каких обстоятельствах, не вешать кондеры. С ними какбы дааже работает сразу лучше, но то только сразу. Они быстро ушатают контакт до состояния мусора. Их разряды окисляют и без того не самые стойкие контакты. После этого останется только снимать осцилограммы и публиковать их тут с нытьем "ну как с таким работать".
Все верно, не знаю что за либа, но знаю что при правильной реализации все ок. И категорически, не при каких обстоятельствах, не вешать кондеры. С ними какбы дааже работает сразу лучше, но то только сразу. Они быстро ушатают контакт до состояния мусора. Их разряды окисляют и без того не самые стойкие контакты. После этого останется только снимать осцилограммы и публиковать их тут с нытьем "ну как с таким работать".
У меня на YAESU FT-897 куча энкодеров, 20 лет полёт нормальный )))
Так отож. Китайские энкодеры пашут везде нормально, даже у самих китайцев, даже в автомагнитолах в суровых условиях. Везде кроме многих участников этого форума ))
Сброшу мои наметки для работы EEROMом
В ней работа без классов! Ну как так можна! Да еще в такой теме.
Исправте немедленно!
Пух, держи подарок!
Если в коде из #195 перенести метод write в public и добавить шесть строчек (в моём коде ниже) помечены комментарием «/*** GIFT ***/», то можно писать, например, вот так:
По-моему удобно. Дарю!
Вот код. Он, собственно твой, я только перенёс функцию и вставил шесть строк:
Опа! Спасибо за плюсик. Пусть кто хочет, думает, что эти плюсики ни на что не влияют, а мне приятно, что ты поблагодарил. Спасибо, Пух.
работа с указателями на методы класса
Организовать меню используя один потенциометр вместо энкодера не получится. Но используя потенциометр и кнопку можно организовать ввод пароля или чего-то еще.
Подключил реле
проведем эксперимент.
Работает . Упростим скетч.
Не правда ли что метод Do похож на виртуальную функцию. Но фишка не в этом. Вот к примеру пишем мы графическую библиотеку. И для установки пикселя в байте в зависимости от цвета нужно производить или логическое сложение или логическое умножение. А если много то этот анализ проводить для каждого пикселя. А этим способом мы можем банально прописать нужный "карандаш" однократно и дальше не заморачиваться в попиксельной работе.
Я вот смотрю на Ваши лямбды и никак не возьму в толк для чего Вы их тянете туда, где достаточно обычного указателя? Это примерно как ставить микроконтроллер для того, чтобы сделать плавное выключение лампочки - работать, конечно, будет, но ведь там достаточно конденсатора!
Главная фишка лямбд в том, что они тянут за собой внешний контекст и являются функциями высшего порядка (вернее с их помощью такие функции строятся - та же свёртка). Вы же никогда этого (зазвата внешнего контекста) не используете, функций высших порядков не строите, а без этого лямбда не даёт никаких преимуществ по сравнению с обычной, именованной функцией и указателем на неё. Ну, вообще никаких.
Есть глобальные переменные,есть локальные, есть даже статик переменные. Но в Си есть глобальные функции, а вот с локальными или статик функциями не очень . Но есть некий эрзац . Лямда это один из вариантов эрзаца.
Ну, не знаю, освойте функторы - те же локальные функции, но с ними можно и как с переменными работать (параметром передавать, операции выполнять). Лямбда собственно тоже функтор, но она ещё много чего - это огромная пушка для воробья - локальной функции.
О. Хочу спросить уважаемого ЕвгенияП. Если у меня одна функция в качестве параметров требует указатель на другую функцию, чтоб её потом вызвать, а та функция короткая в одну строку, можно ли передать её лямбдой, или это тоже из пушки пабабачкам?
или сиравно, лучше делать правильную, обычную функцию и не плодить лишних сучностей?
qwone, если захочешь разобраться, то вот это
Главная фишка лямбд в том, что они тянут за собой внешний контекст
правильно называется "замыкание" и это действительно одна из двух главных фишек лямбда-выражений в этом языке. Другая - то, что они (лямбда-выражения) являются функторами. Без этих двух фишек (а ты их не используешь) лямбда-выражения теряют смысл и не дают никаких выгод по сравнению с указателями на функции.
(Хотя, многие говорят, что это на самом деле одна фишка, а не две - первая. т.к. замыкание, по определению, функция первого класса, стало быть замыкание можно рассматривать как функтор)
DetSimen, можно я отвечу.
требует указатель на другую функцию, чтоб её потом вызвать, а та функция короткая в одну строку, можно ли передать её лямбдой, или это тоже из пушки пабабачкам?
Делай как тебе удобно и не парься. С точки зрения кода особой разницы нет, как уже писали и я, и петрович, если не использовать замыкания, то лямбда ничем особым не отличается от указателя на функцию.
Просто лямбды - гораздо более мощный механизм, чем указатели на функции, а раз Пух явно интересуется, хочется помочь ему освоить его на более глубоком уровне, а то сейчас он похоже, просто пихает лямбды ради того, чтобы пихать лямбды.
Делай как тебе удобно и не парься. С точки зрения кода особой разницы нет, как уже писали и я, и петрович, если не использовать замыкания, то лямбда ничем особым не отличается от указателя на функцию.
Просто лямбды - гораздо более мощный механизм, чем указатели на функции, а раз Пух явно интересуется, хочется помочь ему освоить его на более глубоком уровне, а то сейчас он похоже, просто пихает лямбды ради того, чтобы пихать лямбды.
Мда. Пора читать, полупьяный щуря глаз, про функторы и замыкания. А то так дураком и помру.
Дед, это штучки из функционального программирования, оно те правда надо?
А если реально хочется поиграться всякими лямбдами, замыканиями и прочими свёртками, то уж лучше делать это не на С++, где они притянуты через задницу, а на каком-нибудь языке, где они естественны. Например, возьми Haskell. Классный язык и там всё это естественно и натурально, он собственно для этого и создавался. Особенно мне нравится как в википедии определили его (языка) класс: "Класс языка: функциональный, ленивый, модульный". Как видишь, что-то родное в нём есть :)
Делай как тебе удобно и не парься. С точки зрения кода особой разницы нет, как уже писали и я, и петрович, если не использовать замыкания, то лямбда ничем особым не отличается от указателя на функцию.
Просто лямбды - гораздо более мощный механизм, чем указатели на функции, а раз Пух явно интересуется, хочется помочь ему освоить его на более глубоком уровне, а то сейчас он похоже, просто пихает лямбды ради того, чтобы пихать лямбды.
Мда. Пора читать, полупьяный щуря глаз, про функторы и замыкания. А то так дураком и помру.
Не торописЯ. Это новодел в плюсах. Надо обождать лет десять пока устаканится, концепция выпрямится и компиляторы допиляют до какогото единообразия в понимании стандарта. Я еще в 1.6.5 попробовал, наплевался и расслабился. Так шо наливай. Без замыкания 30 лет писали и ниче. Конечно лямдами нужно пользоваться т.к. менше имен придумывать. Главное внутр [] ничего не пиши! Вон как квон делает: классы, но без наследования, лямбды, но без замыкания. У него и вотка без спирту!
Ну, оч. убедительно. Не буду на старости лет память засорять. :)
Лямбдами буду пользоваться по месту, для коротких функций.
Продолжу. Вот к примеру надо написать библиотеку под lcd5110.(Знаю написана). Но как там решается проблема различия кода на аппаратном SPI и программном. Но ведь можно решить так. И нет плясок с бубном.
ПС: Для тех кто в танке . https://github.com/adafruit/Adafruit-PCD8544-Nokia-5110-LCD-library/blob/master/Adafruit_PCD8544.cpp
Пух, сегодня в соседней теме народ говорил, что ООП-программы можно писать и без слова class.
Но ты уникум! Ты умудряешься писать не-ООПные (и даже анти-ООПные) программы с использованием слова class :-)
Заготовка меню для экрана lcd5110 и библиотек <Adafruit_GFX.h><Adafruit_PCD8544.h>
Посмотрим на это https://github.com/PaulStoffregen/EEPROM/blob/master/EEPROM.h, а особенно на структуру EERef
А потом напишем это.
Думаю понятно. То есть если напишем некий шаблон этого класса, то можем обращаться к структуре помещенную в EEPROM, как к структуре в ОЗУ.
небольшой пустячок
Осталось сюда воткнуть лямду и будет полный писец.
Да тут и без лямбды уже...
где энкодер?
А восьмая строка зачем?
Отстаньте от него, у него свое виденье. Он же четко указал, обращать внимание на строку 10. Наверно const приветствовать аплодисментами. В остальное селедку заворачивал, index зарезервировал для будущих применений.
да там вапще всё трэш, угар и ржака. :)
Вы как маленький... Разве не помните, что "иллюзионисты" обычно отвлекают ваше внимание на что-то нелогичное, а тем временем бумажник из кармана прут?
продолжаем выступление "иллюзиониста"
Красиво конечно, очень прошу, объясни простыми словами зачем это нужно и как это работает?
продолжаем выступление "иллюзиониста"
Если я ничего не путаю, то в строке №26 запись без проверки - может не стоит? update как-то более щадящая конструкция.
файл qwonelib.h
Тот же скетч в упакованном виде, хотя define можно ее сделать компактнее и удобочитаемей
qwonelib.h
Ну и наконец прикрутим это все к меню, если потом понадобится прикрутить это меню к чему-то другому.
qwonelib.h
удастся заслушать начальника транспортного цеха? (энкодер), или как говорила экономист, когда мы автоматизировали одно предприятие, моя работа не поддаётся автоматизации )))
Мне энкодер как устройство регулировки давно перестало нравится. Глючное устройство. Где-то в моих темах валяется этот компонент. Так что заменить кнопки энкодером не трудно для разумного человека.
Продолжу. Если же надо к примеру использовать 10 однородных устройств и 3 комплектами настроек.
qwonelib.h
Мне энкодер как устройство регулировки давно перестало нравится. Глючное устройство.
)))
главное код работы с ним безглючный ))))
Мне энкодер как устройство регулировки давно перестало нравится. Глючное устройство.
перебирал библиотеки от разных авторов, даже на библиотеку Гайвера набрёл, нашёл ту, что подошла идеально, автор пишет, если ваш энкодер даёт глюки на моей библиотеке, то он настолько плох и раздолбан, что просто его выкиньте, эксперименты провожу с энкодером в чистом виде, ни резисторов ни конденсаторов в обвязке нет, пины вверх не притягиваю, видимо всё реализовано в библиотеке, твой код кнопок использую )))
Все верно, не знаю что за либа, но знаю что при правильной реализации все ок. И категорически, не при каких обстоятельствах, не вешать кондеры. С ними какбы дааже работает сразу лучше, но то только сразу. Они быстро ушатают контакт до состояния мусора. Их разряды окисляют и без того не самые стойкие контакты. После этого останется только снимать осцилограммы и публиковать их тут с нытьем "ну как с таким работать".
Все верно, не знаю что за либа, но знаю что при правильной реализации все ок. И категорически, не при каких обстоятельствах, не вешать кондеры. С ними какбы дааже работает сразу лучше, но то только сразу. Они быстро ушатают контакт до состояния мусора. Их разряды окисляют и без того не самые стойкие контакты. После этого останется только снимать осцилограммы и публиковать их тут с нытьем "ну как с таким работать".
У меня на YAESU FT-897 куча энкодеров, 20 лет полёт нормальный )))
Так отож. Китайские энкодеры пашут везде нормально, даже у самих китайцев, даже в автомагнитолах в суровых условиях. Везде кроме многих участников этого форума ))
Прикрутим экран lcd2004 через I2C
qwonelib.h
lcd2004_i2c.h
Сделаем гашение экрана, когда долго не работаем с кнопками
qwonelib.h
lcd2004_i2c.h
работает )))