Цифровые автоматы в классах по qwone

Logik
Offline
Зарегистрирован: 05.08.2014

qwone пишет:

Сброшу мои наметки для работы EEROMом

В ней работа без классов! Ну как так можна! Да еще в такой теме.

Исправте немедленно!

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Пух, держи подарок!

Если в коде из #195 перенести метод write в public и добавить шесть строчек (в моём коде ниже) помечены комментарием «/*** GIFT ***/», то можно писать, например, вот так:

int temp = 366;
printf ("TEMP:%3d,%dC", temp / 10, temp % 10);

По-моему удобно. Дарю!

Вот код. Он, собственно твой, я только перенёс функцию и вставил шесть строк:

/**/
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
//------дисплей lcd2004_i2c-----------------------------
// даташит <"<a href="https://www.sparkfun.com/datasheets/LCD/ADM1602K-NSW-FBS-3.3v.pdf" rel="nofollow">https://www.sparkfun.com/datasheets/LCD/ADM1602K-NSW-FBS-3.3v.pdf</a>"><a href="https://www.sparkfun.com/datasheets/LCD/HD44780.pdf" rel="nofollow">https://www.sparkfun.com/datasheets/LCD/HD44780.pdf</a>
// на русском <"<a href="http://www.melt.aha.ru/pdf/mt-16s2h.pdf" rel="nofollow">http://www.melt.aha.ru/pdf/mt-16s2h.pdf</a>">
#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  // Бит выбора регистра
class Cl_lcd1602_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_lcd1602_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);
      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;
    }
  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
    }
};
Cl_lcd1602_i2c lcd(0x3F);//0x27
//--------------------------------------------------
static int lcd_fputchar(const char ch, FILE *stream) { /*** GIFT ***/
	lcd.write(ch); /*** GIFT ***/
	return 1; /*** GIFT ***/
} /*** GIFT ***/
static FILE *lcd_stream = fdevopen(lcd_fputchar, NULL); /*** GIFT ***/

void setup() {
	stdout = lcd_stream; /*** GIFT ***/
	lcd.init();
	lcd.backlight();
	lcd.clear();
	lcd.setCursor(0, 0);
	int temp = 366;
	printf("TEMP:%3d,%dC", temp / 10, temp % 10);
	lcd.show();
}
void loop() {
}
Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Опа! Спасибо за плюсик. Пусть кто хочет, думает, что эти плюсики ни на что не влияют, а мне приятно, что ты поблагодарил. Спасибо, Пух.

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

работа с указателями на методы класса

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

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
/**/
//------дисплей 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  // Бит выбора регистра
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);
      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;
    }
  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
//--------------------------------------------------
void setup() {
  lcd << &Cl_lcd2004_i2c::init << &Cl_lcd2004_i2c::backlight;// инициализация
  
  lcd << &Cl_lcd2004_i2c::clear << (int)366 << &Cl_lcd2004_i2c::show; // вывод сообщения на экран
}
void loop() {
}

 

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

Организовать меню используя один потенциометр вместо энкодера не получится. Но используя потенциометр и кнопку можно организовать ввод пароля или чего-то еще.

/**/
//------дисплей 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();
}

 

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

Подключил реле 

/**/
//------дисплей 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
  {21, 10, 21, 10, 21, 10, 21,  0},// \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_relay {
  protected:
    const byte pin;
    unsigned long past;
    static const byte sOFF = 0;
    static const byte sON  = 1;
    byte state;
    void set(byte s) {
      past = millis();
      state = s;
      switch (state) {
        case  sOFF :
          digitalWrite(pin, LOW);
          break;
        case  sON :
          digitalWrite(pin, HIGH);
          break;
      }
    }
  public:
    Cl_relay(byte p): pin(p) {}
    void init() {
      pinMode(pin,OUTPUT);
      set(sOFF);
    }
    void run() {
      if (state == sON && millis() - past >= 1000)set(sOFF);
    }
    void ON() {
      set(sON);
    }
    void OFF() {
      set(sOFF);
    }
};
Cl_relay relay(/*пин*/12);//<- подключено реле
//-----потенциометр---------------------------------------------
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("");//<- буфер ввода
String parol("12345");//<- пароль
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 << '\5';//<-вид курсора
        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;
            if (str==parol)relay.ON();
            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();
  relay.init();
  BtnS.init();
  menu_init();
}

void loop() {
  aaa.run();
  relay.run();
  BtnS.run();
  menu_run();
}

 

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

проведем эксперимент.

typedef void (*pDo)();
class cl_G {
  protected:
    pDo Do = [] {};
  public:
    void set() {
      Do = [] {Serial.print("\n Set");};
    }
    void reset() {
      Do = [] {Serial.print("\n Reset");};
    }
    void print() {
      Do();
    }
};

cl_G G;
void setup() {
  Serial.begin(9600);
  G.set();
  G.print();
  G.reset();
  G.print();
}

void loop() {
}

Работает . Упростим скетч.

typedef void (*pDo)();
class cl_G {
  public:
    pDo Do = [] {};
    void set() {
      Do = [] {Serial.print("\n Set");};
    }
    void reset() {
      Do = [] {Serial.print("\n Reset");};
    }
};

cl_G G;
void setup() {
  Serial.begin(9600);
  G.set();
  G.Do();
  G.reset();
  G.Do();
}

void loop() {

}

Не правда ли что метод Do похож на виртуальную функцию. Но фишка не в этом. Вот к примеру пишем мы графическую библиотеку. И для установки пикселя в байте в зависимости от цвета нужно производить или логическое сложение или логическое умножение. А если много то этот анализ проводить для каждого пикселя. А этим способом мы можем банально прописать нужный "карандаш" однократно и дальше не заморачиваться в попиксельной работе.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

qwone пишет:
А этим способом мы можем банально прописать нужный "карандаш" однократно и дальше не заморачиваться в попиксельной работе.
А лямбды-то зачем? Чем не угодил обычный указатель на функцию?

Я вот смотрю на Ваши лямбды и никак не возьму в толк для чего Вы их тянете туда, где достаточно обычного указателя? Это примерно как ставить микроконтроллер для того, чтобы сделать плавное выключение лампочки - работать, конечно, будет, но ведь там достаточно конденсатора!

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

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

Есть глобальные переменные,есть локальные, есть даже статик переменные. Но в Си  есть глобальные функции, а вот с локальными или статик функциями не очень . Но есть некий эрзац .  Лямда это один из вариантов эрзаца. 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, не знаю, освойте функторы - те же локальные функции, но с ними можно и как с переменными работать (параметром передавать, операции выполнять). Лямбда собственно тоже функтор, но она ещё много чего - это огромная пушка для воробья - локальной функции.

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

О. Хочу спросить уважаемого ЕвгенияП.  Если у меня одна функция в качестве параметров требует указатель на другую функцию, чтоб её потом вызвать, а та функция короткая в одну строку,  можно ли передать её лямбдой, или это тоже из пушки пабабачкам? 



   hTimerSeconds = TimerList.Add(1000, [](){ SendMessage(msg_SecondTick);}

или сиравно, лучше делать правильную, обычную функцию и не плодить лишних сучностей?

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

qwone, если захочешь разобраться, то вот это

ЕвгенийП пишет:

Главная фишка лямбд в том, что они тянут за собой внешний контекст

правильно называется "замыкание" и это действительно одна из двух главных фишек лямбда-выражений в этом языке. Другая - то, что они (лямбда-выражения) являются функторами. Без этих двух фишек (а ты их не используешь) лямбда-выражения теряют смысл и не дают никаких выгод по сравнению с указателями на функции.

(Хотя, многие говорят, что это на самом деле одна фишка, а не две - первая. т.к. замыкание, по определению, функция первого класса, стало быть замыкание можно рассматривать как функтор)

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

DetSimen, можно я отвечу.

DetSimen пишет:

требует указатель на другую функцию, чтоб её потом вызвать, а та функция короткая в одну строку,  можно ли передать её лямбдой, или это тоже из пушки пабабачкам? 

Делай как тебе удобно и не парься. С точки зрения кода особой разницы нет, как уже писали и я, и петрович, если не использовать замыкания, то лямбда ничем особым не отличается от указателя на функцию.

Просто лямбды - гораздо более мощный механизм, чем указатели на функции, а раз Пух явно интересуется, хочется помочь ему освоить его на более глубоком уровне, а то сейчас он похоже, просто пихает лямбды ради того, чтобы пихать лямбды.

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

Ворота пишет:

Делай как тебе удобно и не парься. С точки зрения кода особой разницы нет, как уже писали и я, и петрович, если не использовать замыкания, то лямбда ничем особым не отличается от указателя на функцию.

Просто лямбды - гораздо более мощный механизм, чем указатели на функции, а раз Пух явно интересуется, хочется помочь ему освоить его на более глубоком уровне, а то сейчас он похоже, просто пихает лямбды ради того, чтобы пихать лямбды.

Мда.  Пора читать, полупьяный щуря глаз, про функторы и замыкания. А то так дураком и помру. 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Дед, это штучки из функционального программирования, оно те правда надо?

А если реально хочется поиграться всякими лямбдами, замыканиями и прочими свёртками, то уж лучше делать это не на С++, где они притянуты через задницу, а на каком-нибудь языке, где они естественны. Например, возьми Haskell. Классный язык и там всё это естественно и натурально, он собственно для этого и создавался. Особенно мне нравится как в википедии определили его (языка) класс: "Класс языка: функциональный, ленивый, модульный". Как видишь, что-то родное в нём есть :)

Logik
Offline
Зарегистрирован: 05.08.2014

DetSimen пишет:

Ворота пишет:

Делай как тебе удобно и не парься. С точки зрения кода особой разницы нет, как уже писали и я, и петрович, если не использовать замыкания, то лямбда ничем особым не отличается от указателя на функцию.

Просто лямбды - гораздо более мощный механизм, чем указатели на функции, а раз Пух явно интересуется, хочется помочь ему освоить его на более глубоком уровне, а то сейчас он похоже, просто пихает лямбды ради того, чтобы пихать лямбды.

Мда.  Пора читать, полупьяный щуря глаз, про функторы и замыкания. А то так дураком и помру. 

Не торописЯ. Это новодел в плюсах. Надо обождать лет десять пока устаканится, концепция выпрямится  и компиляторы допиляют до какогото единообразия в понимании стандарта. Я еще в 1.6.5 попробовал, наплевался и расслабился. Так шо наливай. Без замыкания 30 лет писали и ниче. Конечно лямдами нужно пользоваться т.к. менше имен придумывать. Главное внутр [] ничего не пиши! Вон как квон делает: классы, но без наследования, лямбды, но без замыкания. У него и вотка без спирту! 

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

Ну, оч. убедительно.  Не буду на старости лет память засорять. :) 

Лямбдами буду пользоваться по месту, для коротких функций. 

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

Продолжу. Вот к примеру надо написать библиотеку под lcd5110.(Знаю написана). Но как там решается проблема различия кода на аппаратном SPI и программном. Но ведь можно решить так. И нет плясок с бубном.

/**/
typedef void (*pDob)(byte c);
class PCD8544 {
  protected:
    int8_t _SCLK,  _DIN, _DC, _CS,  _RST;

  public:
    pDob command;

    PCD8544(int8_t SCLK, int8_t DIN, int8_t DC, int8_t CS, int8_t RST)
      : _SCLK(SCLK),  _DIN(DIN), _DC(DC), _CS(CS),  _RST(RST) {
      command = [](byte c) {
        Serial.print("\n shiftOut:");
        Serial.print(c);
      };
    }
    PCD8544( int8_t DC, int8_t CS, int8_t RST)
      : _SCLK(-1),  _DIN(-1), _DC(DC), _CS(CS),  _RST(RST) {
      command = [](byte c) {
        Serial.print("\n SPI:");
        Serial.print(c);
      };
    }
};
PCD8544 lcd1(/*SCLK*/3,/*DIN*/ 4,/*D/C*/ 5,/*CS*/ 6,/*RST*/7);
PCD8544 lcd2(/*D/C*/ 5,/*CS*/ 6,/*RST*/7);
void setup() {
  Serial.begin(9600);

  lcd1.command(5);
  lcd2.command(5);
}

void loop() {

}

ПС: Для тех кто в танке . https://github.com/adafruit/Adafruit-PCD8544-Nokia-5110-LCD-library/blob/master/Adafruit_PCD8544.cpp

bool Adafruit_PCD8544::isHardwareSPI() {
  return (_din == -1 && _sclk == -1);
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
/**/
// уровень данных
class aaa_t {
  protected:
  public:
    int a;
    aaa_t(int _a): a(_a) {}
} ;
// уровень канальный
class chanel_t {
  protected:
  public:
    void init() {
      Serial.begin(9600);
    }
    void show(aaa_t data) {
      Serial.print(data.a);
    }
};
chanel_t ch;
//-----------------------------------------------
// уровень прикладной
void setup() {
  ch.init();
  {
    aaa_t a(5);
    ch.show(a);
  }
}

void loop() {
}

 

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

qwone пишет:

/**/
// уровень данных
class aaa_t {
  protected:
  public:
    int a;
    aaa_t(int _a): a(_a) {}
} ;
// уровень канальный
class chanel_t {
  protected:
  public:
    void init() {
      Serial.begin(9600);
    }
    void show(aaa_t data) {
      Serial.print(data.a);
    }
};
chanel_t ch;
//-----------------------------------------------
// уровень прикладной
void setup() {
  ch.init();
  {
    aaa_t a(5);
    ch.show(a);
  }
}

void loop() {
}

Пух, сегодня в соседней теме народ говорил, что ООП-программы можно писать и без слова class.

Но ты уникум! Ты умудряешься писать не-ООПные (и даже анти-ООПные) программы с использованием слова class :-)

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

Заготовка меню для экрана lcd5110 и  библиотек <Adafruit_GFX.h><Adafruit_PCD8544.h>

/**/
//---кнопки-----------------------------
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);  //кнопка верх
//---------------------------------------------------------------------------
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
Adafruit_PCD8544 display(/*DC*/ 10,/*cs*/9,/*rst*/8); //*Din*/ 11,/*clk*/ 13
//Adafruit_PCD8544 display = Adafruit_PCD8544(/*clk*/ 13,/*Din*/ 11,/*DC*/ 10,/*cs*/ 9,/*rst*/8);
//--------------- меню---------------------------------------------
const byte page0 = 0;
const byte page1 = 10;
const byte page2 = 20;
const byte page3 = 30;
byte page;
unsigned long past;
void goPage(byte p) {
  past = millis();
  page = p;
  display.clearDisplay();
  switch (page) {
    case page0:
      {
        display.print("page 0");
      }
      BtnS.Do = [] {goPage(page1);};
      BtnU.Do = [] {};
      break;
    case page1:
      {
        display.print( "page 1");
      }
      BtnS.Do = [] {goPage(page2);};
      BtnU.Do = [] {};
      break;
    case page2:
      {
        display.print("page 2");
      }
      BtnS.Do = [] {goPage(page3);};
      BtnU.Do = [] {};
      break;
    case page3:
      {
        display.print("page 3");
      }
      BtnS.Do = [] {goPage(page0);};
      BtnU.Do = [] {};
      break;
  }
  display.display();
}
void menu_init() {
  display.begin();
  display.setTextSize(2);  // установка размера шрифта
  display.setTextColor(BLACK); // установка цвета текста
  display.setRotation(2); // перевернуть изображение
  display.setContrast(50); // установка контраста
  goPage(page0);
}
void menu_run() {}
void setup() {
  BtnS.init();
  BtnU.init();
  menu_init();
}
void loop() {
  BtnS.run();
  BtnU.run();
  menu_run();
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
/**/
//---кнопки-----------------------------
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);  //кнопка верх
//---------------------------------------------------------------------------
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
Adafruit_PCD8544 display(/*DC*/ 10,/*cs*/9,/*rst*/8); //*Din*/ 11,/*clk*/ 13
//Adafruit_PCD8544 display = Adafruit_PCD8544(/*clk*/ 13,/*Din*/ 11,/*DC*/ 10,/*cs*/ 9,/*rst*/8);
//--------------- меню---------------------------------------------
const byte page0 = 0;
const byte page1 = 10;
const byte page2 = 20;
const byte page3 = 30;
byte page;
unsigned long past;
void goPage(byte p) {
  past = millis();
  page = p;
  display.clearDisplay();
  switch (page) {
    case page0:
      { display.setTextSize(2);  // установка размера шрифта
        display.setTextColor(BLACK); // установка цвета текста
        display.print("page 0");
        Adafruit_GFX_Button btn;
        char label_1[] = "<0+>";
        char label_2[] = "<0->";
        btn.initButton(&display, // *gfx
                       20, 40, 24, 8, // x,y,w,h,
                       BLACK, BLACK,  //outline, fill,
                       WHITE, label_1 , 1); //textcolor, label,textsize
        btn.drawButton();
        btn.initButton(&display, // *gfx
                       50, 40, 24, 8, // x,y,w,h,
                       BLACK, BLACK,  //outline, fill,
                       WHITE, label_2 , 1); //textcolor, label,textsize
        btn.drawButton();
      }
      BtnS.Do = [] {goPage(page1);};
      BtnU.Do = [] {};
      break;
    case page1:
      { display.setTextSize(2);  // установка размера шрифта
        display.setTextColor(BLACK); // установка цвета текста
        display.print( "page 1");
        Adafruit_GFX_Button btn;
        char label_1[] = "<1+>";
        char label_2[] = "<1->";
        btn.initButton(&display, // *gfx
                       20, 40, 24, 8, // x,y,w,h,
                       BLACK, BLACK,  //outline, fill,
                       WHITE, label_1 , 1); //textcolor, label,textsize
        btn.drawButton();
        btn.initButton(&display, // *gfx
                       50, 40, 24, 8, // x,y,w,h,
                       BLACK, BLACK,  //outline, fill,
                       WHITE, label_2 , 1); //textcolor, label,textsize
        btn.drawButton();
      }
      BtnS.Do = [] {goPage(page2);};
      BtnU.Do = [] {};
      break;
    case page2:
      { display.setTextSize(2);  // установка размера шрифта
        display.setTextColor(BLACK); // установка цвета текста
        display.print("page 2");
        Adafruit_GFX_Button btn;
        char label_1[] = "<2+>";
        char label_2[] = "<2->";
        btn.initButton(&display, // *gfx
                       20, 40, 24, 8, // x,y,w,h,
                       BLACK, BLACK,  //outline, fill,
                       WHITE, label_1 , 1); //textcolor, label,textsize
        btn.drawButton();
        btn.initButton(&display, // *gfx
                       50, 40, 24, 8, // x,y,w,h,
                       BLACK, BLACK,  //outline, fill,
                       WHITE, label_2 , 1); //textcolor, label,textsize
        btn.drawButton();
      }
      BtnS.Do = [] {goPage(page3);};
      BtnU.Do = [] {};
      break;
    case page3:
      { display.setTextSize(2);  // установка размера шрифта
        display.setTextColor(BLACK); // установка цвета текста
        display.print("page 3");
        Adafruit_GFX_Button btn;
        char label_1[] = "<3+>";
        char label_2[] = "<3->";
        btn.initButton(&display, // *gfx
                       20, 40, 24, 8, // x,y,w,h,
                       BLACK, BLACK,  //outline, fill,
                       WHITE, label_1 , 1); //textcolor, label,textsize
        btn.drawButton();
        btn.initButton(&display, // *gfx
                       50, 40, 24, 8, // x,y,w,h,
                       BLACK, BLACK,  //outline, fill,
                       WHITE, label_2 , 1); //textcolor, label,textsize
        btn.drawButton();
      }
      BtnS.Do = [] {goPage(page0);};
      BtnU.Do = [] {};
      break;
  }
  display.display();
}
void menu_init() {
  display.begin();

  display.setRotation(2); // перевернуть изображение
  display.setContrast(50); // установка контраста
  goPage(page0);
}
void menu_run() {}
void setup() {
  BtnS.init();
  BtnU.init();
  menu_init();
}
void loop() {
  BtnS.run();
  BtnU.run();
  menu_run();
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
const uint8_t adr[] PROGMEM = {
  8, 7, 8, 5,   // h,w,h1,w1
  1, 2, 3, 4, 5 // первое изображение
};
void aaa(const  uint8_t * adr_obj) {
  int h = pgm_read_byte(adr_obj);
  int w = pgm_read_byte(adr_obj + 1);
  Serial.println(h);
  Serial.println(w);
}
class bbb {
  protected:
    uint8_t  h, w, h1, w1;
    uint8_t * buffer;
  public:
    bbb(const  uint8_t * adr_obj)
      : h (pgm_read_byte(adr_obj)),
        w (pgm_read_byte(adr_obj + 1)),
        h1(pgm_read_byte(adr_obj + 2)),
        w1(pgm_read_byte(adr_obj + 3)) {}
    bbb(uint8_t  _h, uint8_t  _w)
      : h (_h),
        w (_w) {}
};

void setup() {
  Serial.begin(9600);
  aaa(adr);
  bbb a(adr);
}

void loop() {
}

 

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

Посмотрим на это https://github.com/PaulStoffregen/EEPROM/blob/master/EEPROM.h, а особенно на структуру EERef

А потом напишем это.

#include <inttypes.h>
#include <avr/eeprom.h>
#include <avr/io.h>
//.h -------------------
struct EERef {
  int index; //Index of current EEPROM cell.
  EERef( const int index ) : index( index ) {}

  //Access/read members.
  uint8_t operator*() const            {
    return eeprom_read_byte( (uint8_t*) index );
  }
  operator uint8_t() const       { // <- да здесь 1 конст выкинут
    return **this;
  }

  //Assignment/write members.
  EERef &operator=( const EERef &ref ) {
    return *this = *ref;
  }
  EERef &operator=( uint8_t in )       {
    return eeprom_write_byte( (uint8_t*) index, in ), *this;
  }
  EERef &operator +=( uint8_t in )     {
    return *this = **this + in;
  }
  EERef &operator -=( uint8_t in )     {
    return *this = **this - in;
  }
  EERef &operator *=( uint8_t in )     {
    return *this = **this * in;
  }
  EERef &operator /=( uint8_t in )     {
    return *this = **this / in;
  }
  EERef &operator ^=( uint8_t in )     {
    return *this = **this ^ in;
  }
  EERef &operator %=( uint8_t in )     {
    return *this = **this % in;
  }
  EERef &operator &=( uint8_t in )     {
    return *this = **this & in;
  }
  EERef &operator |=( uint8_t in )     {
    return *this = **this | in;
  }
  EERef &operator <<=( uint8_t in )    {
    return *this = **this << in;
  }
  EERef &operator >>=( uint8_t in )    {
    return *this = **this >> in;
  }

  EERef &update( uint8_t in )          {
    return  in != *this ? *this = in : *this;
  }

  /** Prefix increment/decrement **/
  EERef& operator++()                  {
    return *this += 1;
  }
  EERef& operator--()                  {
    return *this -= 1;
  }
  /** Postfix increment/decrement **/
  uint8_t operator++ (int) {
    uint8_t ret = **this;
    return ++(*this), ret;
  }
  uint8_t operator-- (int) {
    uint8_t ret = **this;
    return --(*this), ret;
  }
};
//-------------------
uint8_t EEMEM adr;
EERef aaa(adr);
void setup() {
  aaa = 235;
  Serial.begin(9600);
  Serial.println(aaa);
  ++aaa;
  Serial.println(aaa);
}
void loop() {
}

Думаю понятно. То есть если напишем некий шаблон этого класса, то можем обращаться к структуре помещенную в EEPROM, как к структуре в ОЗУ.

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

небольшой пустячок

struct aaa {
  int index;
  aaa(const int index): index(index) {}
  operator int() const { // <-- обратите внимание на это
    return index;
  }
};

void setup() {
  aaa a(345);
  Serial.begin(9600);
  Serial.println(a); // <-- а потом сюда.
}

void loop() {

}

Осталось сюда воткнуть лямду и будет полный писец.

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

Да тут и без лямбды уже...

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
class Relay {
  protected:
    bool state;
    void set(bool s) {
      state = s;
    }
  public:
    int index;
    Relay(): state(0) {}
    operator bool () const { // <-- обратите внимание на это
      return state;
    }
    void ON() {
      state = 1;
    }
    void OFF() {
      state = 0;
    }
};

void setup() {
  Serial.begin(9600);
  Relay R1;
  Serial.println(R1);// выведено 0
  R1.ON();
  Serial.println(R1);// выведено 1
  R1.OFF();
  Serial.println(R1);// выведено 0
}

void loop() {

}

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

где энкодер?

nik182
Offline
Зарегистрирован: 04.05.2015

А восьмая строка зачем?

Logik
Offline
Зарегистрирован: 05.08.2014

Отстаньте от него, у него свое виденье. Он же четко указал, обращать внимание на строку 10. Наверно const приветствовать аплодисментами. В остальное селедку заворачивал, index зарезервировал для будущих применений.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

qwone пишет:
 <-- обратите внимание на это
Поясните, пожалуйста? Почему надо на это обращать внимание? Потому, что сделано так, чтобы могло быть только в правой части присваивания? Чтобы нельзя было экземпляру присвоить значение как обычному bool? Это-то я понял. А вот из каких соображений это было сделано, поясните пожалуйста.

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

да там вапще всё трэш, угар и ржака. :) 

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

ЕвгенийП пишет:

qwone пишет:
 <-- обратите внимание на это
Поясните, пожалуйста? Почему надо на это обращать внимание?

Вы как маленький...  Разве не помните, что "иллюзионисты" обычно отвлекают ваше внимание на что-то нелогичное, а тем временем бумажник из кармана прут?

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
/**/
//.h -------------------
#include <avr/eeprom.h>
template <typename TT> struct EERef {
  uint8_t* index;
  EERef( const TT *_index) {
    index = (uint8_t*)_index;
  }
  TT operator*() const        {
    TT data;
    uint8_t* p = (uint8_t*)&data;
    for (uint8_t i = 0; i < sizeof(TT); i++)
      p[i] = eeprom_read_byte(index + i);
    return data;
  }
  operator TT() const {
    return **this;
  }
  //Assignment/write members.
  EERef &operator=( const EERef &ref ) {
    return *this = *ref;
  }
  EERef &operator=( TT data ) {
    uint8_t* p = (uint8_t*)&data;
    for (uint8_t i = 0; i < sizeof(TT); i++)
      eeprom_write_byte(index + i , p[i] );
    return  *this;
  }
  EERef &operator +=( TT data ) {
    return *this = **this + data;
  }
  EERef &operator -=( TT data ) {
    return *this = **this - data;
  }
  EERef &operator *=( TT data ) {
    return *this = **this * data;
  }
  EERef &operator /=( TT data ) {
    return *this = **this / data;
  }
  EERef &operator ^=( TT data ) {
    return *this = **this ^ data;
  }
  EERef &operator %=( TT data ) {
    return *this = **this % data;
  }
  EERef &operator &=( TT data ) {
    return *this = **this & data;
  }
  EERef &operator |=( TT data ) {
    return *this = **this | data;
  }
  EERef &operator <<=( TT data ) {
    return *this = **this << data;
  }
  EERef &operator >>=( TT data ) {
    return *this = **this >> data;
  }

  EERef &update( TT data ) {
    return  data != *this ? *this = data : *this;
  }
  /** Prefix datacrement/decrement **/
  EERef& operator++() {
    return *this += 1;
  }
  EERef& operator--() {
    return *this -= 1;
  }
  /** Postfix datacrement/decrement **/
  TT operator++ (int) {
    TT ret = **this;
    return ++(*this), ret;
  }
  TT operator-- (int) {
    TT ret = **this;
    return --(*this), ret;
  }
};
//-------------------
float EEMEM adr[10];
EERef<float> aaa(&adr[3]);
void setup() {
  aaa = -12.50;
  Serial.begin(9600);
  Serial.println(aaa);
  aaa += 3.14;
  Serial.println(aaa);
}
void loop() {
}

продолжаем выступление "иллюзиониста" 

nik182
Offline
Зарегистрирован: 04.05.2015

Красиво конечно, очень прошу, объясни простыми словами зачем это нужно и как это работает?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

qwone пишет:

продолжаем выступление "иллюзиониста" 

Если я ничего не путаю, то в строке №26 запись без проверки - может не стоит? update как-то более щадящая конструкция.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
/**/
#include "qwonelib.h"
//-------------------
struct data_t {
  int iData;
  float fData;
};
data_t EEMEM adr1;

void setting() {
  static const PROGMEM data_t adr2 = {-9556, 13.14};
  {
    eeRef <int> aaa1(&adr1.iData);
    pgmRef<int> aaa2(&adr2.iData);
    aaa1 = aaa2;
  }
  {
    eeRef <float> aaa1(&adr1.fData);
    pgmRef<float> aaa2(&adr2.fData);
    aaa1 = aaa2;
  }
}
void setup() {
  setting();
  Serial.begin(9600);
  {
    eeRef <int> aaa1(&adr1.iData);
    Serial.println(aaa1);
  }
  {
    eeRef <float> aaa1(&adr1.fData);
    Serial.println(aaa1);
  }
}
void loop() {
}

файл qwonelib.h

/**/

#ifndef QWONELIB_H
#define QWONELIB_H
#include <avr/eeprom.h>
template <typename TT> struct eeRef {
  uint8_t* adr;
  eeRef( const TT *_adr): adr((uint8_t*)_adr) {}
  void setNewAdr(const TT *_adr) {
    adr = (uint8_t*)_adr;
  }
  TT operator*() const        {
    TT data;
    uint8_t* p = (uint8_t*)&data;
    for (uint8_t i = 0; i < sizeof(TT); i++)
      p[i] = eeprom_read_byte(adr + i);
    return data;
  }
  operator TT() const {
    return **this;
  }
  //Assignment/write members.
  eeRef &operator=( const eeRef &ref ) {
    return *this = *ref;
  }
  eeRef &operator=( TT data ) {
    uint8_t* p = (uint8_t*)&data;
    for (uint8_t i = 0; i < sizeof(TT); i++)
      if ( p[i] != eeprom_read_byte(adr + i))
        eeprom_write_byte(adr + i, p[i]);
    return  *this;
  }
  eeRef &operator +=( TT data ) {
    return *this = **this + data;
  }
  eeRef &operator -=( TT data ) {
    return *this = **this - data;
  }
  eeRef &operator *=( TT data ) {
    return *this = **this * data;
  }
  eeRef &operator /=( TT data ) {
    return *this = **this / data;
  }
  eeRef &operator ^=( TT data ) {
    return *this = **this ^ data;
  }
  eeRef &operator %=( TT data ) {
    return *this = **this % data;
  }
  eeRef &operator &=( TT data ) {
    return *this = **this & data;
  }
  eeRef &operator |=( TT data ) {
    return *this = **this | data;
  }
  eeRef &operator <<=( TT data ) {
    return *this = **this << data;
  }
  eeRef &operator >>=( TT data ) {
    return *this = **this >> data;
  }

  eeRef &update( TT data ) {
    return  data != *this ? *this = data : *this;
  }
  /** Prefix datacrement/decrement **/
  eeRef& operator++() {
    return *this += 1;
  }
  eeRef& operator--() {
    return *this -= 1;
  }
  /** Postfix datacrement/decrement **/
  TT operator++ (int) {
    TT ret = **this;
    return ++(*this), ret;
  }
  TT operator-- (int) {
    TT ret = **this;
    return --(*this), ret;
  }
};
#include <avr/pgmspace.h>
template <typename TT> struct pgmRef {
  uint8_t* adr;
  pgmRef( const TT *_adr): adr((uint8_t*)_adr) {}
  void setNewAdr(const TT *_adr) {
    adr = (uint8_t*)_adr;
  }
  TT operator*() const        {
    TT data;
    uint8_t* p = (uint8_t*)&data;
    for (uint8_t i = 0; i < sizeof(TT); i++)
      p[i] = pgm_read_byte(adr + i);
    return data;
  }
  operator TT() const {
    return **this;
  }
};
#endif

 

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

Тот же скетч в упакованном виде, хотя define можно ее сделать компактнее и удобочитаемей

/**/
#include "qwonelib.h"
//-------------------
struct data_t { // некая пользовательская структура
  byte bData;
  int iData;
  float fData;
};
data_t EEMEM adr1; // размещение ее в EEPROM

void setting() {
  static const PROGMEM data_t adr2 = { 99, -9556, 13.14}; // набор констант для пользовательской функции
  (eeRef <byte>) (&adr1.bData) = (pgmRef<byte>) (&adr2.bData); // загрузка байтовой части
  (eeRef <int>)  (&adr1.iData) = (pgmRef<int>)  (&adr2.iData); // загрузка интовой части
  (eeRef <float>)(&adr1.fData) = (pgmRef<float>)(&adr2.fData); // загрузка флоат части
}
//----------------------------------------
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
//----------------------------------------
void setup() {
  setting();
  Serial.begin(9600);
  Serial << (eeRef <byte>) (&adr1.bData) << '\n';  // вывод байтовой части
  Serial << (eeRef <int>)  (&adr1.iData) << '\n';  // вывод интовой части
  Serial << (eeRef <float>)(&adr1.fData) << '\n';  // вывод флоат части 
}
void loop() {
}

qwonelib.h

/*qwonelib.h*/
#ifndef QWONELIB_H
#define QWONELIB_H
#include <avr/pgmspace.h>
template <typename TT> struct pgmRef {
  uint8_t* adr;
  pgmRef( const TT *_adr): adr((uint8_t*)_adr) {}
  void setNewAdr(const TT *_adr) {
    adr = (uint8_t*)_adr;
  }
  TT operator*() const        {
    TT data;
    uint8_t* p = (uint8_t*)&data;
    for (uint8_t i = 0; i < sizeof(TT); i++)
      p[i] = pgm_read_byte(adr + i);
    return data;
  }
  operator TT() const {
    return **this;
  }
};
#include <avr/eeprom.h>
template <typename TT> struct eeRef {
  uint8_t* adr;
  eeRef( const TT *_adr): adr((uint8_t*)_adr) {}
  void setNewAdr(const TT *_adr) {
    adr = (uint8_t*)_adr;
  }
  TT operator*() const        {
    TT data;
    uint8_t* p = (uint8_t*)&data;
    for (uint8_t i = 0; i < sizeof(TT); i++)
      p[i] = eeprom_read_byte(adr + i);
    return data;
  }
  operator TT() const {
    return **this;
  }
  //Assignment/write members.
  eeRef &operator=( const eeRef &ref ) {
    return *this = *ref;
  }
  eeRef &operator=( TT data ) {
    uint8_t* p = (uint8_t*)&data;
    for (uint8_t i = 0; i < sizeof(TT); i++)
      if ( p[i] != eeprom_read_byte(adr + i))
        eeprom_write_byte(adr + i, p[i]);
    return  *this;
  }
  eeRef &operator +=( TT data ) {
    return *this = **this + data;
  }
  eeRef &operator -=( TT data ) {
    return *this = **this - data;
  }
  eeRef &operator *=( TT data ) {
    return *this = **this * data;
  }
  eeRef &operator /=( TT data ) {
    return *this = **this / data;
  }
  eeRef &operator ^=( TT data ) {
    return *this = **this ^ data;
  }
  eeRef &operator %=( TT data ) {
    return *this = **this % data;
  }
  eeRef &operator &=( TT data ) {
    return *this = **this & data;
  }
  eeRef &operator |=( TT data ) {
    return *this = **this | data;
  }
  eeRef &operator <<=( TT data ) {
    return *this = **this << data;
  }
  eeRef &operator >>=( TT data ) {
    return *this = **this >> data;
  }

  eeRef &update( TT data ) {
    return  data != *this ? *this = data : *this;
  }
  /** Prefix datacrement/decrement **/
  eeRef& operator++() {
    return *this += 1;
  }
  eeRef& operator--() {
    return *this -= 1;
  }
  /** Postfix datacrement/decrement **/
  TT operator++ (int) {
    TT ret = **this;
    return ++(*this), ret;
  }
  TT operator-- (int) {
    TT ret = **this;
    return --(*this), ret;
  }
};

#endif

 

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

Ну и наконец прикрутим это все к меню, если потом понадобится прикрутить это меню к чему-то другому.

/**/
#include "qwonelib.h"
//-------------------
struct data_t { // некая пользовательская структура
  byte bData;
  int iData;
  float fData;
};
data_t EEMEM adr1; // размещение ее в EEPROM

void setting() {
  static const PROGMEM data_t adr2 = { 100, 1000, 10.10}; // набор констант для пользовательской функции
  (eeRef <byte>) (&adr1.bData) = (pgmRef<byte>) (&adr2.bData); // загрузка байтовой части
  (eeRef <int>)  (&adr1.iData) = (pgmRef<int>)  (&adr2.iData); // загрузка интовой части
  (eeRef <float>)(&adr1.fData) = (pgmRef<float>)(&adr2.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 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(page1);};
      BtnU.Do = [] {};
      BtnD.Do = [] {};
      Serial << "info\n";
      Serial << "byte= "  << (eeRef <byte>) (&adr1.bData) << '\n'; // вывод байтовой части
      Serial << "int= "   << (eeRef <int>)  (&adr1.iData) << '\n'; // вывод интовой части
      Serial << "float= " << (eeRef <float>)(&adr1.fData) << '\n'; // вывод флоат части
      break;
    case page1:
      BtnS.Do = [] {goPage(page2);};
      BtnU.Do = [] {
        if ((eeRef <byte>) (&adr1.bData) <= 200)(eeRef <byte>) (&adr1.bData) += 10;
        goPage(page1);
      };
      BtnD.Do = [] {
        if ((eeRef <byte>) (&adr1.bData) >= 50)(eeRef <byte>) (&adr1.bData) -= 10;
        goPage(page1);
      };
      Serial << "set byte\n";
      Serial << (eeRef <byte>) (&adr1.bData) << '\n';  // вывод байтовой части
      break;
    case page2:
      BtnS.Do = [] {goPage(page3);};
      BtnU.Do = [] {
        if ((eeRef <int>) (&adr1.iData) <= 2000)(eeRef <int>) (&adr1.iData) += 100;
        goPage(page2);
      };
      BtnD.Do = [] {
        if ((eeRef <int>) (&adr1.iData) >= 500)(eeRef <int>) (&adr1.iData) -= 100;
        goPage(page2);
      };
      Serial << "set int\n";
      Serial << (eeRef <int>)  (&adr1.iData) << '\n';  // вывод интовой части
      break;
    case page3:
      BtnS.Do = [] {goPage(page4);};
      BtnU.Do = [] {
        if ((eeRef <float>) (&adr1.fData) <= 20.30)(eeRef <float>) (&adr1.fData) += 1.01;
        goPage(page3);
      };
      BtnD.Do = [] {
        if ((eeRef <float>) (&adr1.fData) >= 5.05)(eeRef <float>) (&adr1.fData) -=  1.01;
        goPage(page3);
      };
      Serial << "set float\n";
      Serial << (eeRef <float>)(&adr1.fData) << '\n';  // вывод флоат части
      break;
    case page4:
      BtnS.Do = [] {goPage(page0);};
      BtnU.Do = [] {setting(); goPage(page4);};
      BtnD.Do = [] {setting(); goPage(page4);};
      Serial << "setting\n";
      Serial << "byte= "  << (eeRef <byte>) (&adr1.bData) << '\n'; // вывод байтовой части
      Serial << "int= "   << (eeRef <int>)  (&adr1.iData) << '\n'; // вывод интовой части
      Serial << "float= " << (eeRef <float>)(&adr1.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();
}

qwonelib.h

/*qwonelib.h*/
#ifndef QWONELIB_H
#define QWONELIB_H
#include <avr/pgmspace.h>
template <typename TT> struct pgmRef {
  uint8_t* adr;
  pgmRef( const TT *_adr): adr((uint8_t*)_adr) {}
  void setNewAdr(const TT *_adr) {
    adr = (uint8_t*)_adr;
  }
  TT operator*() const        {
    TT data;
    uint8_t* p = (uint8_t*)&data;
    for (uint8_t i = 0; i < sizeof(TT); i++)
      p[i] = pgm_read_byte(adr + i);
    return data;
  }
  operator TT() const {
    return **this;
  }
};
#include <avr/eeprom.h>
template <typename TT> struct eeRef {
  uint8_t* adr;
  eeRef( const TT *_adr): adr((uint8_t*)_adr) {}
  void setNewAdr(const TT *_adr) {
    adr = (uint8_t*)_adr;
  }
  TT operator*() const        {
    TT data;
    uint8_t* p = (uint8_t*)&data;
    for (uint8_t i = 0; i < sizeof(TT); i++)
      p[i] = eeprom_read_byte(adr + i);
    return data;
  }
  operator TT() const {
    return **this;
  }
  //Assignment/write members.
  eeRef &operator=( const eeRef &ref ) {
    return *this = *ref;
  }
  eeRef &operator=( TT data ) {
    uint8_t* p = (uint8_t*)&data;
    for (uint8_t i = 0; i < sizeof(TT); i++)
      if ( p[i] != eeprom_read_byte(adr + i))
        eeprom_write_byte(adr + i, p[i]);
    return  *this;
  }
  eeRef &operator +=( TT data ) {
    return *this = **this + data;
  }
  eeRef &operator -=( TT data ) {
    return *this = **this - data;
  }
  eeRef &operator *=( TT data ) {
    return *this = **this * data;
  }
  eeRef &operator /=( TT data ) {
    return *this = **this / data;
  }
  eeRef &operator ^=( TT data ) {
    return *this = **this ^ data;
  }
  eeRef &operator %=( TT data ) {
    return *this = **this % data;
  }
  eeRef &operator &=( TT data ) {
    return *this = **this & data;
  }
  eeRef &operator |=( TT data ) {
    return *this = **this | data;
  }
  eeRef &operator <<=( TT data ) {
    return *this = **this << data;
  }
  eeRef &operator >>=( TT data ) {
    return *this = **this >> data;
  }

  eeRef &update( TT data ) {
    return  data != *this ? *this = data : *this;
  }
  /** Prefix datacrement/decrement **/
  eeRef& operator++() {
    return *this += 1;
  }
  eeRef& operator--() {
    return *this -= 1;
  }
  /** Postfix datacrement/decrement **/
  TT operator++ (int) {
    TT ret = **this;
    return ++(*this), ret;
  }
  TT operator-- (int) {
    TT ret = **this;
    return --(*this), ret;
  }
};

#endif

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

удастся заслушать начальника транспортного цеха? (энкодер), или как говорила экономист, когда мы автоматизировали одно предприятие, моя работа не поддаётся автоматизации )))

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

Мне энкодер как устройство регулировки давно перестало нравится. Глючное устройство. Где-то в моих темах валяется этот компонент. Так что заменить кнопки энкодером не трудно для разумного человека. 

  Продолжу. Если же надо к примеру использовать 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();
}

qwonelib.h

/*qwonelib.h*/
#ifndef QWONELIB_H
#define QWONELIB_H
#include <avr/pgmspace.h>
template <typename TT> struct pgmRef {
  uint8_t* adr;
  pgmRef( const TT *_adr): adr((uint8_t*)_adr) {}
  void setNewAdr(const TT *_adr) {
    adr = (uint8_t*)_adr;
  }
  TT operator*() const        {
    TT data;
    uint8_t* p = (uint8_t*)&data;
    for (uint8_t i = 0; i < sizeof(TT); i++)
      p[i] = pgm_read_byte(adr + i);
    return data;
  }
  operator TT() const {
    return **this;
  }
};
#include <avr/eeprom.h>
template <typename TT> struct eeRef {
  uint8_t* adr;
  eeRef( const TT *_adr): adr((uint8_t*)_adr) {}
  void setNewAdr(const TT *_adr) {
    adr = (uint8_t*)_adr;
  }
  TT operator*() const        {
    TT data;
    uint8_t* p = (uint8_t*)&data;
    for (uint8_t i = 0; i < sizeof(TT); i++)
      p[i] = eeprom_read_byte(adr + i);
    return data;
  }
  operator TT() const {
    return **this;
  }
  //Assignment/write members.
  eeRef &operator=( const eeRef &ref ) {
    return *this = *ref;
  }
  eeRef &operator=( TT data ) {
    uint8_t* p = (uint8_t*)&data;
    for (uint8_t i = 0; i < sizeof(TT); i++)
      if ( p[i] != eeprom_read_byte(adr + i))
        eeprom_write_byte(adr + i, p[i]);
    return  *this;
  }
  eeRef &operator +=( TT data ) {
    return *this = **this + data;
  }
  eeRef &operator -=( TT data ) {
    return *this = **this - data;
  }
  eeRef &operator *=( TT data ) {
    return *this = **this * data;
  }
  eeRef &operator /=( TT data ) {
    return *this = **this / data;
  }
  eeRef &operator ^=( TT data ) {
    return *this = **this ^ data;
  }
  eeRef &operator %=( TT data ) {
    return *this = **this % data;
  }
  eeRef &operator &=( TT data ) {
    return *this = **this & data;
  }
  eeRef &operator |=( TT data ) {
    return *this = **this | data;
  }
  eeRef &operator <<=( TT data ) {
    return *this = **this << data;
  }
  eeRef &operator >>=( TT data ) {
    return *this = **this >> data;
  }

  eeRef &update( TT data ) {
    return  data != *this ? *this = data : *this;
  }
  /** Prefix datacrement/decrement **/
  eeRef& operator++() {
    return *this += 1;
  }
  eeRef& operator--() {
    return *this -= 1;
  }
  /** Postfix datacrement/decrement **/
  TT operator++ (int) {
    TT ret = **this;
    return ++(*this), ret;
  }
  TT operator-- (int) {
    TT ret = **this;
    return --(*this), ret;
  }
};

#endif

 

Logik
Offline
Зарегистрирован: 05.08.2014

qwone пишет:

Мне энкодер как устройство регулировки давно перестало нравится. Глючное устройство. 

)))

главное код работы с ним безглючный ))))

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

qwone пишет:

Мне энкодер как устройство регулировки давно перестало нравится. Глючное устройство.

перебирал библиотеки от разных авторов, даже на библиотеку Гайвера набрёл, нашёл ту, что подошла идеально, автор пишет, если ваш энкодер даёт глюки на моей библиотеке, то он настолько плох и раздолбан, что просто его выкиньте, эксперименты провожу с энкодером в чистом виде, ни резисторов ни конденсаторов в обвязке нет, пины вверх не притягиваю, видимо всё реализовано в библиотеке, твой код кнопок использую  )))

Logik
Offline
Зарегистрирован: 05.08.2014

Все верно, не знаю что за либа, но знаю что при правильной реализации все ок. И категорически, не при каких обстоятельствах, не вешать кондеры. С ними какбы дааже работает сразу лучше, но то только сразу. Они быстро ушатают контакт до состояния мусора. Их разряды окисляют и без того не самые стойкие контакты. После этого останется только снимать осцилограммы и публиковать их тут с нытьем "ну как с таким работать".

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Logik пишет:

Все верно, не знаю что за либа, но знаю что при правильной реализации все ок. И категорически, не при каких обстоятельствах, не вешать кондеры. С ними какбы дааже работает сразу лучше, но то только сразу. Они быстро ушатают контакт до состояния мусора. Их разряды окисляют и без того не самые стойкие контакты. После этого останется только снимать осцилограммы и публиковать их тут с нытьем "ну как с таким работать".

У меня на YAESU FT-897 куча энкодеров, 20 лет полёт нормальный )))

Logik
Offline
Зарегистрирован: 05.08.2014

Так отож. Китайские энкодеры пашут везде нормально, даже у самих китайцев, даже в автомагнитолах в суровых условиях. Везде кроме многих участников этого форума ))

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

Прикрутим экран lcd2004 через I2C 

/**/
#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);  //кнопка вниз
//--------------- меню---------------------------------------------
#include "lcd2004_i2c.h"
/*template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
  }*/
const byte page0 = 0; //ноказ настроек
const byte page1 = 10;//поменять индекс устройства
const byte page2 = 20;//изменение байтовой части
const byte page3 = 30;//изменение интовой части
const byte page4 = 40;//изменение флоат части
const byte page5 = 50; //сброс настроек
byte page;
unsigned long past;
void goPage(byte p) {
  past = millis();
  page = p;
  lcd.clear();
  switch (page) {
    case page0:
      BtnS.Do = [] {goPage(page1);};
      BtnU.Do = [] {};
      BtnD.Do = [] {};
      lcd << "info:";
      lcd.setCursor(0, 1);
      lcd << "byte(" << index << ") ="  << (eeRef <byte>) (&adr1[index].bData); // вывод байтовой части
      lcd.setCursor(0, 2);
      lcd << "int("  << index << ")  =" << (eeRef <int>)  (&adr1[index].iData); // вывод интовой части
      lcd.setCursor(0, 3);
      lcd << "float(" << index << ")="  << (eeRef <float>)(&adr1[index].fData); // вывод флоат части
      break;
    case page1:
      BtnS.Do = [] {goPage(page2);};
      BtnU.Do = [] {
        if (index < (max_index - 1))index++;
        goPage(page1);
      };
      BtnD.Do = [] {
        if (index > 0)index--;
        goPage(page1);
      };
      lcd << "set index:" << index;
      break;
    case page2:
      BtnS.Do = [] {goPage(page3);};
      BtnU.Do = [] {
        if ((eeRef <byte>) (&adr1[index].bData) <= 200)(eeRef <byte>) (&adr1[index].bData) += 10;
        goPage(page2);
      };
      BtnD.Do = [] {
        if ((eeRef <byte>) (&adr1[index].bData) >= 50)(eeRef <byte>) (&adr1[index].bData) -= 10;
        goPage(page2);
      };
      lcd << "set byte(" << index << ")=" << (eeRef <byte>) (&adr1[index].bData); // вывод байтовой части
      break;
    case page3:
      BtnS.Do = [] {goPage(page4);};
      BtnU.Do = [] {
        if ((eeRef <int>) (&adr1[index].iData) <= 2000)(eeRef <int>) (&adr1[index].iData) += 100;
        goPage(page3);
      };
      BtnD.Do = [] {
        if ((eeRef <int>) (&adr1[index].iData) >= 500)(eeRef <int>) (&adr1[index].iData) -= 100;
        goPage(page3);
      };
      lcd << "set int(" << index << ")=" << (eeRef <int>)  (&adr1[index].iData); // вывод интовой части
      break;
    case page4:
      BtnS.Do = [] {goPage(page5);};
      BtnU.Do = [] {
        if ((eeRef <float>) (&adr1[index].fData) <= 20.30)(eeRef <float>) (&adr1[index].fData) += 1.01;
        goPage(page4);
      };
      BtnD.Do = [] {
        if ((eeRef <float>) (&adr1[index].fData) >= 5.05)(eeRef <float>) (&adr1[index].fData) -=  1.01;
        goPage(page4);
      };
      lcd << "set float(" << index << ")=" << (eeRef <float>)(&adr1[index].fData);  // вывод флоат части
      break;
    case page5:
      BtnS.Do = [] {goPage(page0);};
      BtnU.Do = [] {
        if (setting_index < (max_setting_index - 1))setting_index++;
        setting(index);
        goPage(page5);
      };
      BtnD.Do = [] {
        if (setting_index > 0)setting_index--;
        setting(index);
        goPage(page5);
      };
      lcd << "setting(" << setting_index << ")";
      lcd.setCursor(0, 1);
      lcd << "byte(" << index << ") ="  << (eeRef <byte>) (&adr1[index].bData) ; // вывод байтовой части
      lcd.setCursor(0, 2);
      lcd << "int("  << index << ")  =" << (eeRef <int>)  (&adr1[index].iData) ; // вывод интовой части
      lcd.setCursor(0, 3);
      lcd << "float(" << index << ")="  << (eeRef <float>)(&adr1[index].fData) ; // вывод флоат части
      break;
  }
  lcd.show();
}
void menu_init() {
  lcd.init();
  lcd.backlight();
  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();
}

qwonelib.h

/*qwonelib.h*/
#ifndef QWONELIB_H
#define QWONELIB_H
#include <avr/pgmspace.h>
template <typename TT> struct pgmRef {
  uint8_t* adr;
  pgmRef( const TT *_adr): adr((uint8_t*)_adr) {}
  void setNewAdr(const TT *_adr) {
    adr = (uint8_t*)_adr;
  }
  TT operator*() const {
    TT data;
    uint8_t* p = (uint8_t*)&data;
    for (uint8_t i = 0; i < sizeof(TT); i++)
      p[i] = pgm_read_byte(adr + i);
    return data;
  }
  operator TT() const {
    return **this;
  }
};
#include <avr/eeprom.h>
template <typename TT> struct eeRef {
  uint8_t* adr;
  eeRef( const TT *_adr): adr((uint8_t*)_adr) {}
  void setNewAdr(const TT *_adr) {
    adr = (uint8_t*)_adr;
  }
  TT operator*() const        {
    TT data;
    uint8_t* p = (uint8_t*)&data;
    for (uint8_t i = 0; i < sizeof(TT); i++)
      p[i] = eeprom_read_byte(adr + i);
    return data;
  }
  operator TT() const {
    return **this;
  }
  //Assignment/write members.
  eeRef &operator=( const eeRef &ref ) {
    return *this = *ref;
  }
  eeRef &operator=( TT data ) {
    uint8_t* p = (uint8_t*)&data;
    for (uint8_t i = 0; i < sizeof(TT); i++)
      if ( p[i] != eeprom_read_byte(adr + i))
        eeprom_write_byte(adr + i, p[i]);
    return  *this;
  }
  eeRef &operator +=( TT data ) {
    return *this = **this + data;
  }
  eeRef &operator -=( TT data ) {
    return *this = **this - data;
  }
  eeRef &operator *=( TT data ) {
    return *this = **this * data;
  }
  eeRef &operator /=( TT data ) {
    return *this = **this / data;
  }
  eeRef &operator ^=( TT data ) {
    return *this = **this ^ data;
  }
  eeRef &operator %=( TT data ) {
    return *this = **this % data;
  }
  eeRef &operator &=( TT data ) {
    return *this = **this & data;
  }
  eeRef &operator |=( TT data ) {
    return *this = **this | data;
  }
  eeRef &operator <<=( TT data ) {
    return *this = **this << data;
  }
  eeRef &operator >>=( TT data ) {
    return *this = **this >> data;
  }

  eeRef &update( TT data ) {
    return  data != *this ? *this = data : *this;
  }
  /** Prefix datacrement/decrement **/
  eeRef& operator++() {
    return *this += 1;
  }
  eeRef& operator--() {
    return *this -= 1;
  }
  /** Postfix datacrement/decrement **/
  TT operator++ (int) {
    TT ret = **this;
    return ++(*this), ret;
  }
  TT operator-- (int) {
    TT ret = **this;
    return --(*this), ret;
  }
};

#endif

lcd2004_i2c.h

/*lcd2004_i2c.h*/
#ifndef LCD2004_I2C_H
#define LCD2004_I2C_H
#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  // Бит выбора регистра
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);
      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;
    }
  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;
}
//.cpp----------------------------
Cl_lcd2004_i2c lcd(0x3F);//0x27
#endif

 

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

Сделаем гашение экрана, когда долго не работаем с кнопками

/**/
#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 = 5;
void setting(byte in) {
  static const PROGMEM data_t adr2[max_setting_index] = { // набор констант для пользовательской функции
    {100, 1000, 10.10}   // 0 комплект настроек
    , {101, 1001, 10.11} // 1 комплект настроек
    , {102, 1002, 10.12} // 2 комплект настроек
    , {103, 1003, 10.13} // 3 комплект настроек
    , {104, 1004, 10.14} // 4 комплект настроек
  };
  (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);  //кнопка вниз
//--------------- меню---------------------------------------------
#include "lcd2004_i2c.h"
const byte page0 = 0;//гашение экрана
const byte page1 = 10;//ноказ настроек
const byte page2 = 20;//поменять индекс устройства
const byte page3 = 30;//изменение байтовой части
const byte page4 = 40;//изменение интовой части
const byte page5 = 50;//изменение флоат части
const byte page6 = 60; //сброс настроек
byte page;
unsigned long past;
void goPage(byte p) {
  past = millis();
  page = p;
  qGTX display(LCD_W, LCD_H);
  switch (page) {
    case page0:
      BtnS.Do = [] {goPage(page1);};
      BtnU.Do = [] {goPage(page1);};
      BtnD.Do = [] {goPage(page1);};
      lcd.noBacklight();
      break;
    case page1:
      BtnS.Do = [] {goPage(page2);};
      BtnU.Do = [] {};
      BtnD.Do = [] {};
      lcd.backlight();
      display << xy_t(0, 0) << F("info:");
      display << xy_t(0, 1) << F(" byte(") << index << F(")=") << (eeRef <byte>) (&adr1[index].bData); // вывод байтовой части
      display << xy_t(0, 2) << F("  int(") << index << F(")=") << (eeRef <int>)  (&adr1[index].iData); // вывод интовой части
      display << xy_t(0, 3) << F("float(") << index << F(")=") << (eeRef <float>)(&adr1[index].fData); // вывод флоат части
      break;
    case page2:
      BtnS.Do = [] {goPage(page3);};
      BtnU.Do = [] {
        if (index < (max_index - 1))index++;
        goPage(page2);
      };
      BtnD.Do = [] {
        if (index > 0)index--;
        goPage(page2);
      };
      display << xy_t(0, 0) << F("set index:") << index;
      break;
    case page3:
      BtnS.Do = [] {goPage(page4);};
      BtnU.Do = [] {
        if ((eeRef <byte>) (&adr1[index].bData) <= 200)(eeRef <byte>) (&adr1[index].bData) += 10;
        goPage(page3);
      };
      BtnD.Do = [] {
        if ((eeRef <byte>) (&adr1[index].bData) >= 50)(eeRef <byte>) (&adr1[index].bData) -= 10;
        goPage(page3);
      };
      display << xy_t(0, 0) << F("set byte(") << index << F(")=") << (eeRef <byte>) (&adr1[index].bData); // вывод байтовой части
      break;
    case page4:
      BtnS.Do = [] {goPage(page5);};
      BtnU.Do = [] {
        if ((eeRef <int>) (&adr1[index].iData) <= 2000)(eeRef <int>) (&adr1[index].iData) += 100;
        goPage(page4);
      };
      BtnD.Do = [] {
        if ((eeRef <int>) (&adr1[index].iData) >= 500)(eeRef <int>) (&adr1[index].iData) -= 100;
        goPage(page4);
      };
      display << xy_t(0, 0) << F("set int(") << index << ")=" << (eeRef <int>)  (&adr1[index].iData); // вывод интовой части
      break;
    case page5:
      BtnS.Do = [] {goPage(page6);};
      BtnU.Do = [] {
        if ((eeRef <float>) (&adr1[index].fData) <= 20.30)(eeRef <float>) (&adr1[index].fData) += 1.01;
        goPage(page5);
      };
      BtnD.Do = [] {
        if ((eeRef <float>) (&adr1[index].fData) >= 5.05)(eeRef <float>) (&adr1[index].fData) -=  1.01;
        goPage(page5);
      };
      display << xy_t(0, 0) << F("set float(") << index << F(")=") << (eeRef <float>)(&adr1[index].fData); // вывод флоат части
      break;
    case page6:
      BtnS.Do = [] {goPage(page1);};
      BtnU.Do = [] {
        if (setting_index < (max_setting_index - 1))setting_index++;
        setting(index);
        goPage(page6);
      };
      BtnD.Do = [] {
        if (setting_index > 0)setting_index--;
        setting(index);
        goPage(page6);
      };
      display << xy_t(0, 0) << F("setting(") << setting_index   << F(")");
      display << xy_t(0, 1) << F(" byte(") << index << F(")=") << (eeRef <byte>) (&adr1[index].bData) ; // вывод байтовой части
      display << xy_t(0, 2) << F("  int(") << index << F(")=") << (eeRef <int>)  (&adr1[index].iData) ; // вывод интовой части
      display << xy_t(0, 3) << F("float(") << index << F(")=") << (eeRef <float>)(&adr1[index].fData) ; // вывод флоат части
      break;
  }
  lcd.show(display);
}
void menu_init() {
  lcd.init();
  goPage(page1);
}
void menu_run() {
  switch (page) {
    case page0:
      break;
    default:
      if (millis() - past >= 10000)goPage(page0);// если долго не щелкают по кнопкам то погасить экран
      break;
  }
}
//----------------------------------------
void setup() {
  BtnS.init();
  BtnU.init();
  BtnD.init();
  menu_init();
}
void loop() {
  BtnS.run();
  BtnU.run();
  BtnD.run();
  menu_run();
}

qwonelib.h

/*qwonelib.h*/
#ifndef QWONELIB_H
#define QWONELIB_H
#include <avr/pgmspace.h>
template <typename TT> struct pgmRef {
  uint8_t* adr;
  pgmRef( const TT *_adr): adr((uint8_t*)_adr) {}
  void setNewAdr(const TT *_adr) {
    adr = (uint8_t*)_adr;
  }
  TT operator*() const {
    TT data;
    uint8_t* p = (uint8_t*)&data;
    for (uint8_t i = 0; i < sizeof(TT); i++)
      p[i] = pgm_read_byte(adr + i);
    return data;
  }
  operator TT() const {
    return **this;
  }
};
#include <avr/eeprom.h>
template <typename TT> struct eeRef {
  uint8_t* adr;
  eeRef( const TT *_adr): adr((uint8_t*)_adr) {}
  void setNewAdr(const TT *_adr) {
    adr = (uint8_t*)_adr;
  }
  TT operator*() const        {
    TT data;
    uint8_t* p = (uint8_t*)&data;
    for (uint8_t i = 0; i < sizeof(TT); i++)
      p[i] = eeprom_read_byte(adr + i);
    return data;
  }
  operator TT() const {
    return **this;
  }
  //Assignment/write members.
  eeRef &operator=( const eeRef &ref ) {
    return *this = *ref;
  }
  eeRef &operator=( TT data ) {
    uint8_t* p = (uint8_t*)&data;
    for (uint8_t i = 0; i < sizeof(TT); i++)
      if ( p[i] != eeprom_read_byte(adr + i))
        eeprom_write_byte(adr + i, p[i]);
    return  *this;
  }
  eeRef &operator +=( TT data ) {
    return *this = **this + data;
  }
  eeRef &operator -=( TT data ) {
    return *this = **this - data;
  }
  eeRef &operator *=( TT data ) {
    return *this = **this * data;
  }
  eeRef &operator /=( TT data ) {
    return *this = **this / data;
  }
  eeRef &operator ^=( TT data ) {
    return *this = **this ^ data;
  }
  eeRef &operator %=( TT data ) {
    return *this = **this % data;
  }
  eeRef &operator &=( TT data ) {
    return *this = **this & data;
  }
  eeRef &operator |=( TT data ) {
    return *this = **this | data;
  }
  eeRef &operator <<=( TT data ) {
    return *this = **this << data;
  }
  eeRef &operator >>=( TT data ) {
    return *this = **this >> data;
  }

  eeRef &update( TT data ) {
    return  data != *this ? *this = data : *this;
  }
  /** Prefix datacrement/decrement **/
  eeRef& operator++() {
    return *this += 1;
  }
  eeRef& operator--() {
    return *this -= 1;
  }
  /** Postfix datacrement/decrement **/
  TT operator++ (int) {
    TT ret = **this;
    return ++(*this), ret;
  }
  TT operator-- (int) {
    TT ret = **this;
    return --(*this), ret;
  }
};

#endif

lcd2004_i2c.h

/*lcd2004_i2c.h*/
//.h----------------------------
#ifndef LCD2004_I2C_H
#define LCD2004_I2C_H
//--класс обработки данных ------------------------------------------
class Cl_lcd2004_i2c;
struct xy_t {
  uint8_t x, y;
  explicit xy_t(int _x, int _y)
    : x(_x), y(_y) {}
};
class qGTX: public Print {
    friend class Cl_lcd2004_i2c;
  protected:
    uint8_t *buffer;
    uint8_t W, H, posX, posY;
  public:
    qGTX(uint8_t w, uint8_t h) {
      if (w == 0) w = 1;
      if (h == 0) h = 1;
      W = w; H = h;
      buffer = new  uint8_t[W * H];
      clear();
    }
    ~qGTX() {
      delete[] buffer;
    }
    inline size_t write(uint8_t value) {
      if (posX < W && posY < H) {
        buffer[posY * W + posX] = value;
        posX++;
      }
      return 1;
    }
    void setCursor(byte x, byte y) {
      if (x > W) x = W;
      else posX = x;
      if (y > H) x = H;
      else posY = y;
    }
    void clear() {
      for (byte i = 0; i < W * H; i++) buffer[i] = 0x20;
      posX = 0; posY = 0;
    }
};
template <typename T> qGTX & operator << (qGTX &s,const T n) {
  s.print(n);
  return s;
}
template <> qGTX & operator << <struct xy_t>(qGTX &s, const struct xy_t n) {
  s.setCursor(n.x, n.y);
  return s;
}
//-- канальный класс Cl_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 LCD_W 20
#define LCD_H 4

#define En B00000100  // Бит разрешения
#define Rw B00000010  // Чтение / запись бит
#define Rs B00000001  // Бит выбора регистра

class Cl_lcd2004_i2c {
  protected:
    uint8_t adr;
    uint8_t _backlightval;
    uint8_t _displayfunction;
    uint8_t _displaycontrol;
    uint8_t _displaymode;
  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);
    }
    // подсветку вкл/выкл
    void backlight(void) {
      _backlightval = LCD_BACKLIGHT;
      expanderWrite(0);
    }
    void noBacklight(void) {
      _backlightval = LCD_NOBACKLIGHT;
      expanderWrite(0);
    }
    // отправить информацию из qGTX на экран
    void show(const qGTX &obj) {
      line(0);
      for (byte i = 0; i < obj.W; i++ )out(obj.buffer[i]);
      line(1);
      for (byte i = obj.W; i < 2 * obj.W; i++ )out(obj.buffer[i]);
      line(2);
      for (byte i = 2 * obj.W; i < 3 * obj.W; i++ )out(obj.buffer[i]);
      line(3);
      for (byte i = 3 * obj.W; i < 4 * obj.W; i++ )out(obj.buffer[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
    }
};
//.cpp----------------------------


//qGTX display(20, 4);
Cl_lcd2004_i2c lcd(0x3F);//0x27
#endif

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

работает )))