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

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);  //кнопка 1
Cl_btn    BtnU(/*пин*/3);  //кнопка 2
Cl_btn    BtnD(/*пин*/4);  //кнопка 3
#include "lcd2004_i2c.h"
qGTX display1(LCD_W, LCD_H);
qGTX display2(LCD_W, LCD_H);
qGTX display3(LCD_W, LCD_H);
//--------------------------------
void setup() {
  BtnS.init();
  BtnU.init();
  BtnD.init();
  lcd.init();
  lcd.backlight();
  lcd.show(display1);
  display1 << xy_t(0, 0) << F("Virtual screen 1");
  display2 << xy_t(1, 1) << F("Virtual screen 2");
  display3 << xy_t(2, 2) << F("Virtual screen 3");
  BtnS.Do = [] {lcd.show(display1);};
  BtnU.Do = [] {lcd.show(display2);};
  BtnD.Do = [] {lcd.show(display3);};
}
void loop() {
  BtnS.run();
  BtnU.run();
  BtnD.run();
}

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

 

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); // загрузка флоат части
}
#include "menu.h"
//----------------------------------------
void setup() {
  menu_init();
  while (1) {
    menu_run();
  }
}
void loop() {}

Cl_btn.h

/*Cl_btn.h*/
#ifndef Cl_btn_h
#define Cl_btn_h
//Cl_btn.h--------------------------------
typedef void (*pDo)();
class Cl_btn {
  public:
    Cl_btn(byte p): pin(p) {}
    pDo Do = [] {};
    void init();
    void run();
  protected:
    void set(bool s);
    byte pin;
    bool state;
    unsigned long past;
};
//Cl_btn.cpp--------------------------------
void Cl_btn::set(bool s) {
  state = s;
  past = millis();
  if (s == true) Do();
}
void Cl_btn::init() {
  pinMode(pin, INPUT_PULLUP);
  set(false);
}
void Cl_btn::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;
    }
}
#endif

lcd2004_i2c.h

/*lcd2004_i2c.h*/
//.h----------------------------
#ifndef LCD2004_I2C_H
#define LCD2004_I2C_H
//--класс обработки данных ------------------------------------------
// xy.h------------------------------------
class Cl_lcd2004_i2c;
class xy { // класс задание позиции
  public:
    int x, y;
    explicit xy(): x(0), y(0) {}
    explicit xy(int _x, int _y): x(_x), y(_y) {}
};
// xy.cpp------------------------------------
// qGTX.h------------------------------------
class qGTX: public Print { // класс графической обработки данных
    friend class Cl_lcd2004_i2c;
    friend qGTX operator+(const qGTX &obj,  xy pos);
    friend qGTX operator+(const qGTX &obj1, const qGTX &obj2); // наложение на 1-й 2-го
    friend qGTX operator*(const qGTX &obj1, const qGTX &obj2); // горизонтальная склейка
    friend qGTX operator/(const qGTX &obj1, const qGTX &obj2); // вертикальная склейка
  protected:
    uint8_t *buffer;
  public:
    uint8_t W, H;
    int posX, posY;
    qGTX(uint8_t w, uint8_t h);
    qGTX(const qGTX &obj);
    qGTX(qGTX &&obj);
    qGTX & operator=(const xy& pos);
    qGTX& operator=(const qGTX& obj);
    qGTX& operator=(qGTX&& obj) ;
    qGTX& operator +=(const xy& pos);
    qGTX& operator +=(const qGTX& obj);
    qGTX& operator *=(const qGTX& obj);
    qGTX& operator /=(const qGTX& obj);
    ~qGTX();
    inline size_t write(uint8_t c);
    void copy(uint8_t *d1, uint8_t *d2, int len);
    void setCursor(uint8_t x, uint8_t y);
    void clear();
    void put(int x, int y, uint8_t c);
    uint8_t get(int x, int y) const ;
};
// qGTX.cpp------------------------------------
qGTX::qGTX(uint8_t w, uint8_t h) {
  W = (w == 0) ? 1 : w;
  H = (h == 0) ? 1 : h;
  posX = posY = 0;
  buffer = new  uint8_t[W * H];
  clear();
}
qGTX::qGTX(const qGTX &obj) {// конструктор копирования
  W = obj.W, H = obj.H, posX = obj.posX, posY = obj.posY;
  buffer = new  uint8_t[W * H];
  copy(buffer, obj.buffer, W * H);
}
qGTX::qGTX(qGTX &&obj) { // конструктор копирования c перемещением
  buffer = obj.buffer, W = obj.W, H = obj.H, posX = obj.posX, posY = obj.posY;
  obj.buffer = nullptr;
}
qGTX& qGTX::operator=(const xy& pos) {
  posX = (pos.x < W) ? pos.x : W;
  posY = (pos.y < H) ? pos.y : H;
  return *this;
}
qGTX& qGTX::operator=(const qGTX& obj) { // копирование по левой ссылке
  if (&obj == this) return *this;
  delete[] buffer;
  W = obj.W; H = obj.H;
  posX = obj.posX, posY = obj.posY;
  buffer = new  uint8_t[W * H];
  copy(buffer, obj.buffer, W * H);
  return *this;
}
qGTX& qGTX::operator=(qGTX&& obj) { // копирование по правой ссылке
  if (&obj == this) return *this;
  delete[] buffer;
  W = obj.W, H = obj.H, posX = obj.posX,
  posY = obj.posY, buffer = obj.buffer;
  obj.buffer = nullptr;
  return *this;
}
qGTX& qGTX::operator +=(const xy& pos) {
  posX += pos.x;
  posY += pos.y;
  return *this;
}
qGTX& qGTX::operator +=(const qGTX& obj) {
  for (int j = 0; j < obj.H; j++)
    for (int i = 0; i < obj.W; i++)
      put(i + posX, j + posY, obj.get(i, j));
  posX += obj.W;
  //posY += obj.H-1;
  return *this;
}
qGTX::~qGTX() {
  delete[] buffer;
}
size_t qGTX::write(uint8_t c) {
  if (c == '\n') {
    posX = 0;
    posY = (posY < H) ? (posY + 1) : H;
    return 1;
  }
  if (posX < W && posY < H) {
    buffer[posY * W + posX] = c;
    posX++;
  }
  return 1;
}
void qGTX::copy(uint8_t *d1, uint8_t *d2, int len) {
  for (int i = 0; i < len; i++) d1[i] = d2[i];
}
void qGTX::setCursor(uint8_t x, uint8_t y) {
  *this = xy(x, y);
}
void qGTX::clear() {
  for (uint8_t i = 0; i < W * H; i++) buffer[i] = 0x20;
  posX = posY = 0;
}
void qGTX::put(int x, int y, uint8_t c) { // поместить чар
  if (x < 0 || x >= W) return;
  if (y < 0 || y >= H) return;
  buffer[x + W * y] = c;
}
uint8_t qGTX::get(int x, int y) const { // извлеч чар
  if (x < 0 || x >= W) return 0x20;
  if (y < 0 || y >= H) return 0x20;
  return buffer[x + W * y];
}
qGTX operator+(const qGTX &obj,  xy pos) { //перемещение на шаг
  qGTX out(obj);
  return out += pos;
}
qGTX operator+(const qGTX &obj1, const qGTX &obj2) { // наложение на 1-й 2-го
  qGTX out(obj1);
  return out += obj2;
}
template <typename TT> qGTX & operator << (qGTX & obj, const TT& n) {
  obj.print(n);
  return obj;
}
template <> qGTX & operator << <xy>(qGTX &obj, const xy& pos) {
  return obj = pos;
}
template <> qGTX & operator << <qGTX>(qGTX &obj1, const qGTX& obj2) {
  return obj1 += obj2;
}
// Cl_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 LCD_W 20
#define LCD_H 4

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

class Cl_lcd2004_i2c { // класс канала передачи
  public:
    Cl_lcd2004_i2c(uint8_t a): adr(a) {}
    void init();                // иницирование
    void backlight(void);       // подсветка вкл
    void noBacklight(void);     // подсветка выкл
    void show(const qGTX &obj); // отправить информацию из qGTX на экран
  private:
    /*внутрение функции*/
    inline void out(uint8_t value);
    inline void command(uint8_t value);
    void send(uint8_t value, uint8_t mode);
    void write4bits(uint8_t value);
    void expanderWrite(uint8_t _data);
    void pulseEnable(uint8_t _data);
  protected:
    uint8_t adr;
    uint8_t _backlightval;
    uint8_t _displayfunction;
    uint8_t _displaycontrol;
    uint8_t _displaymode;
};
// Cl_lcd2004_i2c.cpp------------------------------------
void Cl_lcd2004_i2c::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 Cl_lcd2004_i2c::backlight(void) {
  _backlightval = LCD_BACKLIGHT;
  expanderWrite(0);
}
void Cl_lcd2004_i2c::noBacklight(void) {
  _backlightval = LCD_NOBACKLIGHT;
  expanderWrite(0);
}
void Cl_lcd2004_i2c::show(const qGTX &obj) {
  command(LCD_SETDDRAMADDR + 0x00);
  for (uint8_t i = 0; i < obj.W; i++ )out(obj.buffer[i]);
  command(LCD_SETDDRAMADDR + 0x40);
  for (uint8_t i = obj.W; i < 2 * obj.W; i++ )out(obj.buffer[i]);
  command(LCD_SETDDRAMADDR + 0x14);
  for (uint8_t i = 2 * obj.W; i < 3 * obj.W; i++ )out(obj.buffer[i]);
  command(LCD_SETDDRAMADDR + 0x54);
  for (uint8_t i = 3 * obj.W; i < 4 * obj.W; i++ )out(obj.buffer[i]);
}
void Cl_lcd2004_i2c::out(uint8_t value) {
  send(value, Rs);
}
void Cl_lcd2004_i2c::command(uint8_t value) {
  send(value, 0);
}
void Cl_lcd2004_i2c::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 Cl_lcd2004_i2c::write4bits(uint8_t value) {
  expanderWrite(value);
  pulseEnable(value);
}
void Cl_lcd2004_i2c::expanderWrite(uint8_t _data) {
  Wire.beginTransmission(adr);
  Wire.write((int)(_data | _backlightval));
  Wire.endTransmission();
}
void Cl_lcd2004_i2c::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
}
//qGTX display(LCD_W, LCD_H);
Cl_lcd2004_i2c lcd(0x3F);//0x27
#endif

menu.h

/*menu.h*/
#ifndef MENU_H
#define MENU_H
#include "Cl_btn.h"
Cl_btn BtnS(/*пин*/2);  //кнопка селект
Cl_btn BtnU(/*пин*/3);  //кнопка верх
Cl_btn BtnD(/*пин*/4);  //кнопка вниз
//--------------- меню---------------------------------------------
#include "lcd2004_i2c.h"
void goPage(byte p); // перейти на страницу p
void menu_init();    // инициализировать меню
void menu_run();     // текущая работа
// обозначение страницы меню - что делает
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(0, 0) << F("info:");
      display << xy(0, 1) << F(" byte(") << index << F(")=") << (eeRef <byte>)(&adr1[index].bData); // вывод байтовой части
      display << xy(0, 2) << F("  int(") << index << F(")=") << (eeRef <int>)  (&adr1[index].iData); // вывод интовой части
      display << xy(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(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(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(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(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(0, 0) << F("setting(") << setting_index  << F(")");
      display << xy(0, 1) << F(" byte(") << index << F(")=") << (eeRef <byte>)(&adr1[index].bData); // вывод байтовой части
      display << xy(0, 2) << F("  int(") << index << F(")=") << (eeRef <int>) (&adr1[index].iData); // вывод интовой части
      display << xy(0, 3) << F("float(") << index << F(")=") << (eeRef <float>)(&adr1[index].fData); // вывод флоат части
      break;
  }
  lcd.show(display);
}
void menu_init() {
  BtnS.init();
  BtnU.init();
  BtnD.init();
  lcd.init();
  goPage(page1);
}
void menu_run() {
  BtnS.run();
  BtnU.run();
  BtnD.run();
  switch (page) {
    case page0:
      break;
    default:
      if (millis() - past >= 10000)goPage(page0);// если долго не щелкают по кнопкам то погасить экран
      break;
  }
}
#endif

qwonelib.h

/*qwonelib.h*/
#ifndef QWONELIB_H
#define QWONELIB_H
//pgmRef.h-------------------------------------------
#include <avr/pgmspace.h>
template <typename TT> struct pgmRef { // шаблон ссылка на PROGMEM
  uint8_t* adr;
  pgmRef( const TT *_adr);
  void setNewAdr(const TT *_adr);
  TT operator*() const ;
  operator TT() const ;
};
//pgmRef.cpp-------------------------------------------
template <typename TT>
pgmRef<TT>::pgmRef( const TT *_adr): adr((uint8_t*)_adr) {}
template <typename TT> void  pgmRef<TT>::setNewAdr(const TT *_adr) {
  adr = (uint8_t*)_adr;
}
template <typename TT> TT pgmRef<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;
}
template <typename TT> pgmRef<TT>::operator TT() const {
  return **this;
}
//eeRef.h ----------------------------------------------
#include <avr/eeprom.h>
template <typename TT> class eeRef { // шаблон ссылка на EEROM
  protected:
    uint8_t* adr;
  public:
    eeRef( const TT* _adr);
    void setNewAdr(const TT* _adr);
    TT operator*() const ;
    operator TT() const;
    //Assignment/write members.
    eeRef& operator=( const eeRef &ref );
    eeRef& operator=( TT data );
    eeRef& operator +=( TT data );
    eeRef& operator -=( TT data );
    eeRef& operator *=( TT data );
    eeRef& operator /=( TT data );
    eeRef& operator ^=( TT data );
    eeRef& operator %=( TT data );
    eeRef& operator &=( TT data );
    eeRef& operator |=( TT data );
    eeRef& operator <<=( TT data );
    eeRef& operator >>=( TT data );
    eeRef& update( TT data );
    /** Prefix datacrement/decrement **/
    eeRef& operator++();
    eeRef& operator--();
    /** Postfix datacrement/decrement **/
    TT operator++ (int);
    TT operator-- (int);
};
//eeRef.cpp-------------------------
template <typename TT> eeRef<TT>::eeRef( const TT *_adr): adr((uint8_t*)_adr) {}
template <typename TT> void eeRef<TT>::setNewAdr(const TT *_adr) {
  adr = (uint8_t*)_adr;
}
template <typename TT> TT eeRef<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;
}
template <typename TT> eeRef<TT>::operator TT() const {
  return **this;
}
template <typename TT> eeRef<TT>& eeRef<TT>::operator=(const eeRef<TT> &ref ) {
  return *this = *ref;
}
template <typename TT> eeRef<TT>& eeRef<TT>::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;
}
template <typename TT> eeRef<TT>& eeRef<TT>::operator +=( TT data ) {
  return *this = **this + data;
}
template <typename TT> eeRef<TT>& eeRef<TT>::operator -=( TT data ) {
  return *this = **this - data;
}
template <typename TT> eeRef<TT>& eeRef<TT>::operator *=( TT data ) {
  return *this = **this * data;
}
template <typename TT> eeRef<TT>& eeRef<TT>::operator /=( TT data ) {
  return *this = **this / data;
}
template <typename TT> eeRef<TT>& eeRef<TT>::operator ^=( TT data ) {
  return *this = **this ^ data;
}
template <typename TT> eeRef<TT>& eeRef<TT>::operator %=( TT data ) {
  return *this = **this % data;
}
template <typename TT> eeRef<TT>& eeRef<TT>::operator &=( TT data ) {
  return *this = **this & data;
}
template <typename TT> eeRef<TT>& eeRef<TT>::operator |=( TT data ) {
  return *this = **this | data;
}
template <typename TT> eeRef<TT>& eeRef<TT>::operator <<=( TT data ) {
  return *this = **this << data;
}
template <typename TT> eeRef<TT>& eeRef<TT>::operator >>=( TT data ) {
  return *this = **this >> data;
}
template <typename TT> eeRef<TT>& eeRef<TT>::update( TT data ) {
  return  data != *this ? *this = data : *this;
}
template <typename TT> eeRef<TT>& eeRef<TT>::operator++() {
  return *this += 1;
}
template <typename TT> eeRef<TT>& eeRef<TT>::operator--() {
  return *this -= 1;
}
template <typename TT> TT eeRef<TT>::operator++ (int) {
  TT ret = **this;
  return ++(*this), ret;
}
template <typename TT> TT eeRef<TT>::operator-- (int) {
  TT ret = **this;
  return --(*this), ret;
}
#endif

 

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

qwone пишет:

Ну и зарисовки по Морзе

/**/
//-------------------------------------------------
const byte st_none       = 0;
const byte st_next       = 1;
const byte st_dot        = 2;
const byte st_dush       = 3;
const byte st_pause_dot = 4;
const byte st_pause_dush = 5;
class cMorse {
  protected:
    String buffer;
    unsigned int ii;
    byte pin;
    unsigned long past;
    unsigned long time;
    unsigned long dot_time;
    byte state, next_state;
    void set( byte s);
  public:
    cMorse(byte p);
    void init(unsigned long t = 300);
    void run();
    void play(String msg);
};
void cMorse::set(byte s) {
  state = s;
  past = millis();
  while (state == st_next) {
    char tmp = buffer[ii++];
    switch (tmp) {
      case '.':
        state = st_dot;
        break;
      case '-':
        state = st_dush;
        break;
      case ' ':
        state = st_pause_dush;
        break;
      case '\0':
        state = st_none;
        break;
    }
  }
  switch (state) {
    case  st_none:
      Serial.print(F("OK"));
      break;
    case  st_next:
      break;
    case  st_dot:
      Serial.print(F("."));
      digitalWrite(pin, HIGH);
      time = dot_time;
      next_state = st_pause_dot;
      break;
    case st_dush:
      Serial.print(F("-"));
      digitalWrite(pin, HIGH);
      time = dot_time * 3;
      next_state = st_pause_dot;
      break;
    case st_pause_dot:
      digitalWrite(pin, LOW);
      time = dot_time;
      next_state = st_next;
      break;
    case st_pause_dush:
      Serial.print(F(" "));
      digitalWrite(pin, LOW);
      time = dot_time * 3;
      next_state = st_next;
      break;
  }
}
cMorse::cMorse(byte p)
  : pin(p) {}
void cMorse::init(unsigned long t) {
  dot_time = t;
  ii = 0;
  set(st_none);
  pinMode(pin, OUTPUT);
}
void cMorse::run() {
  if (state != st_none && millis() - past >= time) set(next_state);
}
void cMorse::play(String msg) {
    buffer = msg;
    ii = 0;
    set(st_next);
}

cMorse Morse(/*пин*/13);
//-----------  кнопка  ------------------------
typedef void (*pDo)();
class Cl_Btn {
  protected:
    byte pin;
    unsigned long past;
    bool state;
    void set(bool s) {
      past = millis();
      state = s;
      if (s == true)Do();
    }
  public:
    pDo Do = [] {};
    Cl_Btn(byte p): pin(p) {}
    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);
            break;
        }
      }
    }
};
Cl_Btn Btn(/*пин*/2);// кнопка
void setup() {
  Serial.begin(9600);
  Morse.init(100);//0.1 секунды длит точки
  Btn.init();
  Btn.Do = [] {
    Serial.println();
    Morse.play(F("... --- ... "));// сообщение SOS
  };
}

void loop() {
  Morse.run();
  Btn.run();
}

для читабельности кода на слух пауза между буквами должна быть 1.5 паузы между точками и тире

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

Жду код заветной кнопки, то-есть, кнопка работающая на PCINT

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

А что, в лисапете нету?

Клапауций 003
Offline
Зарегистрирован: 20.07.2019

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

А что, в лисапете нету?

в лисапете калидоре булгахтеры...

страна русской дислексии - тьфу!

SLKH
Онлайн
Зарегистрирован: 17.08.2015

ua6em пишет:

 

 

для читабельности кода на слух пауза между буквами должна быть 1.5 паузы между точками и тире

не 3?

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

SLKH пишет:

ua6em пишет:

 

 

для читабельности кода на слух пауза между буквами должна быть 1.5 паузы между точками и тире

не 3?

три многовато видимо

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

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

А что, в лисапете нету?

не знаю )))
ВЫ же знаете, мы радисты и пятерные клики различаем, а там что-то с двойными и одинарными проблема, или я так понял

SLKH
Онлайн
Зарегистрирован: 17.08.2015

ua6em пишет:

SLKH пишет:

ua6em пишет:

 

 

для читабельности кода на слух пауза между буквами должна быть 1.5 паузы между точками и тире

не 3?

три многовато видимо

а полтора - не маловато?

вроде бы стандарт был 1 - 3 - 7 ?

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

возможно, но точка точно маловато, совсем всё сливается

Клапауций 003
Offline
Зарегистрирован: 20.07.2019

ua6em пишет:

не знаю )))
...проблема, или я так понял

не читал, но осуждаю(с) 

- садись! пять по геноциду здравого смысла!

dosikus
Offline
Зарегистрирован: 11.03.2017

Ну а что вы "гуру" не объясните болезному , что он пытается писать на суржике Си, ничего общего не имеющего ни с ООП ни с плюсами. А уж если "цЫфровые автоматы" это попытка создать конечный автомат тогда абма...

sadman41
Онлайн
Зарегистрирован: 19.10.2016

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

dosikus
Offline
Зарегистрирован: 11.03.2017

Я читал однако.
Вы счас что его засыпали фекалиями, если вам очевидно что человек болен.
Любите издеваться над жЫвотными, иголочками тыкать...

Клапауций 003
Offline
Зарегистрирован: 20.07.2019

dosikus пишет:
Я читал однако. Вы счас что его засыпали фекалиями, если вам очевидно что человек болен. Любите издеваться над жЫвотными, иголочками тыкать...

ты зачем Винни больным жывотным обозвал?

он не болен - это его нормально-стабильное состояние: вилкой ни себе, ни соседу не тыкает в глаз, пишет в код всякое. а, кто не писал всякое? - ткните в него вилкой!

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
/*EEPROM_qLib.ino*/
#include "EEPROM_qLib.h"
float *const adr1 = 0;
//float *const adr2 = (float*)((uint8_t*)adr1 + 2 * sizeof(float));
const PROGMEM float f_adr = {12.34};

void setup() {
  /*Serial.begin(9600);
  Serial.println((int)adr2);
  Serial.println((EERef<float>)adr1 = (pgmRef<float>)&f_adr);*/
  (EERef<float>)adr1 = (pgmRef<float>)&f_adr;
}

void loop() {

}

EEPROM_qLib.h

/*EEPROM_qLib.h*/
#ifndef EEPROM_qLib_h
#define EEPROM_qLib_h
//pgmRef.h-------------------------------------------
#include <avr/pgmspace.h>
template <typename TT> class pgmRef { // шаблон ссылка на PROGMEM
  protected:
    uint8_t* _adr;
  public:
    explicit pgmRef(const TT* adr): _adr((uint8_t*)adr) {}
    TT read();
    operator TT() {
      return read();
    }
};
//pgmRef.cpp-------------------------------------------
template <typename TT>
TT pgmRef<TT>::read() {
  TT data;
  uint8_t* pdata = (uint8_t*)&data;
  for (uint8_t i = 0; i < sizeof(TT); i++)
    pdata[i] = pgm_read_byte(_adr + i);
  return data;
}
template <>
uint8_t pgmRef<uint8_t>::read() {
  uint8_t data = pgm_read_byte(_adr);
  return data;
}
// EERef.h------------------------------------
#include <avr/eeprom.h>
template <typename TT>
class EERef {
  protected:
    uint8_t* _adr;
  public:
    explicit EERef(const TT* adr): _adr((uint8_t*)adr) {}
    EERef& write(const TT& data);
    EERef& write(TT&& data);
    TT read();
    operator TT() {
      return read();
    }
    EERef& operator=(const EERef& ref ) {
      return write(ref);
    }
    EERef& operator=(const TT& in )       {
      return write(in);
    }
    EERef& operator +=(const TT&  in )     {
      return write(read() + in);
    }
    EERef& operator -=(const TT&  in )     {
      return write(read() - in);
    }
    EERef& operator *=(const TT&  in )     {
      return write(read() * in);
    }
    EERef& operator /=(const TT& in )     {
      return write(read() / in);
    }
    EERef& operator ^=(const uint8_t& in)     {
      return write(read() ^ in);
    }
    EERef& operator %=(const uint8_t& in )     {
      return write(read() % in);
    }
    EERef& operator &=(const uint8_t& in )     {
      return write(read() & in);
    }
    EERef& operator |=(const uint8_t& in )     {
      return write(read() | in);
    }
    EERef& operator <<=(const uint8_t& in )    {
      return write(read() << in);
    }
    EERef& operator >>=(const uint8_t& in )    {
      return write(read() >> in);
    }
    /** Prefix increment/decrement **/
    EERef& operator++()                  {
      return write(read() += 1);
    }
    EERef& operator--()                  {
      return write(read() -= 1);
    }
    /** Postfix increment/decrement **/
    EERef& operator++ (int) {
      TT ret = read();
      write(read() += 1);
      return  ret;
    }
    EERef& operator-- (int) {
      TT ret = read();
      write(read() -= 1);
      return  ret;
    }
};
// EERef.cpp------------------------------------
template <typename TT>
EERef<TT>& EERef<TT>::write(const TT& data) {
  uint8_t* pdata = (uint8_t*)&data;
  for (uint8_t i = 0; i < sizeof(TT); i++)
    if  (pdata[i] != eeprom_read_byte(_adr + i))
      eeprom_write_byte(_adr + i, pdata[i]);
  return *this;
}
template <>
EERef<uint8_t>& EERef<uint8_t>::write(const uint8_t& data) {
  if (data != eeprom_read_byte(_adr))
    eeprom_write_byte(_adr, data);
  return *this;
}
template <typename TT>
EERef<TT>& EERef<TT>::write(TT&& data) {
  uint8_t* pdata = (uint8_t*)&data;
  for (uint8_t i = 0; i < sizeof(TT); i++) {
    if  (pdata[i] != eeprom_read_byte(_adr + i))
      eeprom_write_byte(_adr + i, pdata[i]);
  }
  return *this;
}
template <>
EERef<uint8_t>& EERef<uint8_t>::write(uint8_t&& data) {
  if  (data != eeprom_read_byte(_adr))
    eeprom_write_byte(_adr, data);
  return *this;
}
template <typename TT>
TT EERef<TT>::read() {
  TT data = 0;
  uint8_t* pdata = (uint8_t*)&data;
  for (uint8_t i = 0; i < sizeof(TT); i++)
    pdata[i] = eeprom_read_byte(_adr + i);
  return data;
}
template <>
uint8_t EERef<uint8_t>::read() {
  uint8_t data = eeprom_read_byte(_adr);
  return data;
}
#endif

 

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

dosikus пишет:
Ну а что вы "гуру" не объясните болезному
Так объясни! Или ты не по этой части, а только другими покомандовать?

Клапауций 003
Offline
Зарегистрирован: 20.07.2019

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

dosikus пишет:
Ну а что вы "гуру" не объясните болезному
Так объясни! Или ты не по этой части, а только другими покомандовать?

я запретил разговаривать с болезными - сразу в пропасть!

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
/**/
float *adr1 = (float*)4; // размещение ее в EEPROM
float *adr2 = (float*)8;
#include "EEPROM_qLib.h"
const PROGMEM float adr[4] = {1.3, 2.3, 2.7, 4.3};

void setup() {
  Serial.begin(9600);
  EERef<float> aaa(adr1);
  aaa =pgmRef<float>(&adr[0]);
  Serial.println(aaa);
  EERef<float> bbb(adr2);
  bbb =pgmRef<float>(&adr[1]);
  Serial.println(bbb);
}
void loop() {
}

EEPROM_qLib.h

/*EEPROM_qLib.h*/
#ifndef EEPROM_qLib_h
#define EEPROM_qLib_h
//pgmRef.h---------------------------------
#include <avr/pgmspace.h>
template <typename T>
class pgmRef {
  protected:
    const uint8_t* _adr;
  public:
    pgmRef() = delete;
    explicit pgmRef(const T* adr);
    operator T(); // read
};
//pgmRef.cpp---------------------------------
template <typename T>
pgmRef<T>::pgmRef(const T* adr): _adr((uint8_t*)adr) {}
template <typename T>
pgmRef<T>::operator T() {
  T data;
  uint8_t* p = (uint8_t*)&data;
  for (uint8_t i = 0; i < sizeof(T); i++)
    p[i] = pgm_read_byte(_adr + i);
  return data;
}
/*uint8_t*/
template <>
pgmRef<uint8_t>::pgmRef(const uint8_t* adr): _adr(adr) {}
template <>
pgmRef<uint8_t>::operator uint8_t() {
  return pgm_read_byte(_adr);
}
// EERef.h------------------------------------
#include <avr/eeprom.h>
template <typename T>
class EERef {
  protected:
    uint8_t* _adr;
  public:
    EERef() = delete;
    explicit EERef(const T* adr);
    EERef(const EERef& other) = delete;
    operator T(); // read
    EERef& operator=(const T& data); // write
    EERef& operator=(const EERef& other); // write
};
// EERef.cpp------------------------------------
template <typename T>
EERef<T>::EERef(const T* adr): _adr((uint8_t*)adr) {}
template <typename T>
EERef<T>::operator T() {
  T data;
  uint8_t* p = (uint8_t*)&data;
  for (uint8_t i = 0; i < sizeof(T); i++) {
    p[i] = eeprom_read_byte(_adr + i);
  }
  return data;
}
template <typename T>
EERef<T>& EERef<T>::operator=(const T& data) {
  uint8_t* p = (uint8_t*)&data;
  for (uint8_t i = 0; i < sizeof(T); i++)
    if (p[i] != eeprom_read_byte(_adr + i))
      eeprom_write_byte(_adr + i, p[i]);
  return *this;
}
template <typename T>
EERef<T>& EERef<T>::operator=(const EERef<T>& other) {
  if (this != &other) {
    *this = other;
  }
  return *this;
}
/*uint8_t*/
template <>
EERef<uint8_t>::EERef(const uint8_t* adr): _adr((uint8_t*)adr) {}
template <>
EERef<uint8_t>::operator uint8_t() {
  return eeprom_read_byte(_adr);
}
template <>
EERef<uint8_t>& EERef<uint8_t>::operator=(const uint8_t& data) {
  eeprom_write_byte(_adr, data);
  return *this;
}
template <>
EERef<uint8_t>& EERef<uint8_t>::operator=(const EERef<uint8_t>& other) {
  if (this != &other) {
    *this = other;
  }
  return *this;
}
//---------------------------------
#endif

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
/**/
#include "aaa.h"
//-----------------------
void setup() {
  Serial.begin(9600);
  aaa<String> a(F("9912345789"));
  Serial.println(a);
  aaa<float> b(12.56);
  Serial.println(b);
}
void loop() {

aaa.h

/*aaa.h*/
#ifndef AAA_H
#define AAA_H
//aaa.h-------------------------
template <typename T>
class aaa {
  protected:
    uint8_t* pData;
  public:
    aaa() = delete;
    aaa(const T& d);
    ~aaa();
    operator T();
    aaa& operator=(const T& d);
    aaa& operator=(const aaa& other);
    aaa& read();
    aaa& write(const T& d);
};
//aaa.cpp-------------------------
template <typename T>
aaa<T>::aaa(const T& d): pData(new uint8_t[sizeof(T)]) {
  uint8_t* p =(uint8_t*)&d;
  for (uint8_t i = 0; i < sizeof(T); i++) pData[i] = p[i];
}
template <typename T>
aaa<T>::~aaa() {
  delete[]  pData;
}
template <typename T>
aaa<T>::operator T() {
  T data;
  uint8_t* p =(uint8_t*) &data;
  for (uint8_t i = 0; i < sizeof(T); i++) p[i] = pData[i];
  return data;
}
template <typename T>
aaa<T>& aaa<T>::operator=(const T& d) {
  uint8_t* p = &d;
  for (uint8_t i = 0; i < sizeof(T); i++) pData[i] = p[i];
  return *this;
}
template <typename T>
aaa<T>& aaa<T>::operator=(const aaa<T>& other) {
  if (this != &other) this = other;
  return *this;
}
template <typename T>
aaa<T>& aaa<T>::read() {
  return *this;
}
template <typename T>
aaa<T>& aaa<T>::write(const T& d) {
  return *this = d;
}
/*uint8_t*/
template <>
aaa<uint8_t>::aaa(const uint8_t& d): pData(new uint8_t) {}
template <>
aaa<uint8_t>::~aaa<uint8_t>() {
  delete  pData;
}
template <>
aaa<uint8_t>::operator uint8_t() {
  return *pData;
}
template <>
aaa<uint8_t>& aaa<uint8_t>::operator=(const uint8_t& d) {
  *pData = d;
  return *this;
}
template <>
aaa<uint8_t>& aaa<uint8_t>::operator=(const aaa<uint8_t>& other) {
  if (this != &other) *this = other;
  return *this;
}
template <>
aaa<uint8_t>& aaa<uint8_t>::read() {
  return *this;
}
template <>
aaa<uint8_t>& aaa<uint8_t>::write(const uint8_t& d) {
  return *this = d;
}
/*String*/
#define STRING_SIZE 16
template <>
aaa<String>::aaa(const String& d): pData(new uint8_t[STRING_SIZE]) {
  uint8_t len = (d.length() <= STRING_SIZE) ? d.length()  : STRING_SIZE;
  uint8_t i = 0;
  for (; i < len; i++) {
    pData[i] = d[i];
  }
}
template <>
aaa<String>::~aaa() {
  delete[]  pData;
}
template <>
aaa<String>::operator String() {
  String data = ""; data.reserve(STRING_SIZE);
  for (uint8_t i = 0; i < STRING_SIZE; i++) {
    uint8_t d = pData[i];
    if (d == 0) break;
    data += (char)d;
  }
  return data;
}
template <>
aaa<String>& aaa<String>::operator=(const String& d) {
  uint8_t len = (d.length() <= STRING_SIZE) ? d.length()  : STRING_SIZE;
  uint8_t i = 0;
  for (; i < len; i++) pData[i] = d[i];
  return *this;
}
template <>
aaa<String>& aaa<String>::operator=(const aaa<String>& other) {
  if (this != &other) *this = other;
  return *this;
}
template <>
aaa<String>& aaa<String>::read() {
  return *this;
}
template <>
aaa<String>& aaa<String>::write(const String& d) {
  return *this = d;
}
#endif

 

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

А теперь тоже самое но с записью EEPPROM

/**/
#include "aaa.h"
const String* adr1 = (String*)0; // адресс ячеек для записи String
const float*  adr2 = (float*)(&adr1 + STRING_SIZE);// адресс ячеек для записи float
//-----------------------
void setup() {
  Serial.begin(9600);
  aaa<String> a(adr1);
  a = String(F("temp String 1234567890"));
  Serial.println(a);
  aaa<float>  b(adr2);
  b = 12.14;
  Serial.println(b);
  aaa<String> c(adr1);
  Serial.println(c);
  aaa<float>  d(adr2);
  Serial.println(d);
}
void loop() {
}

aaa.h

/*aaa.h*/
#ifndef AAA_H
#define AAA_H
//aaa.h-------------------------
#include <avr/eeprom.h>
template <typename T>
class aaa {
  protected:
    uint8_t* pData;
  public:
    aaa() = delete;
    explicit aaa(const T* adr);
    operator T();
    aaa& operator=(const T& d);
    aaa& operator=(const aaa& other);
    aaa& read();
    aaa& write(const T& d);
};
//aaa.cpp-------------------------
template <typename T>
aaa<T>::aaa(const T* adr): pData((uint8_t*)adr) {}
template <typename T>
aaa<T>::operator T() {
  T data;
  uint8_t* p = (uint8_t*) &data;
  for (uint8_t i = 0; i < sizeof(T); i++) p[i] = eeprom_read_byte(pData + i);
  return data;
}
template <typename T>
aaa<T>& aaa<T>::operator=(const T& d) {
  uint8_t* p = (uint8_t*)&d;
  for (uint8_t i = 0; i < sizeof(T); i++) eeprom_write_byte(pData + i, p[i]);
  return *this;
}
template <typename T>
aaa<T>& aaa<T>::operator=(const aaa<T>& other) {
  if (this != &other) this = other;
  return *this;
}
template <typename T>
aaa<T>& aaa<T>::read() {
  return *this;
}
template <typename T>
aaa<T>& aaa<T>::write(const T& d) {
  return *this = d;
}
/*uint8_t*/
template <>
aaa<uint8_t>::operator uint8_t() {
  uint8_t d = eeprom_read_byte(pData);
  return d;
}
template <>
aaa<uint8_t>& aaa<uint8_t>::operator=(const uint8_t& d) {
  eeprom_write_byte(pData, d);
  return *this;
}
template <>
aaa<uint8_t>& aaa<uint8_t>::operator=(const aaa<uint8_t>& other) {
  if (this != &other) *this = other;
  return *this;
}
template <>
aaa<uint8_t>& aaa<uint8_t>::read() {
  return *this;
}
template <>
aaa<uint8_t>& aaa<uint8_t>::write(const uint8_t& d) {
  return *this = d;
}
/*String*/
#define STRING_SIZE 16
template <>
aaa<String>::operator String() {
  String data = ""; data.reserve(STRING_SIZE);
  for (uint8_t i = 0; i < STRING_SIZE; i++) {
    uint8_t d = eeprom_read_byte(pData + i);
    if (d == 0) break;
    data += (char)d;
  }
  return data;
}
template <>
aaa<String>& aaa<String>::operator=(const String& d) {
  uint8_t len = (d.length() <= STRING_SIZE) ? d.length()  : STRING_SIZE;
  uint8_t i = 0;
  for (; i < len; i++) eeprom_write_byte(pData + i, d[i]);
  eeprom_write_byte(pData + i, 0);
  return *this;
}
template <>
aaa<String>& aaa<String>::operator=(const aaa<String>& other) {
  if (this != &other) *this = other;
  return *this;
}
template <>
aaa<String>& aaa<String>::read() {
  return *this;
}
template <>
aaa<String>& aaa<String>::write(const String& d) {
  return *this = d;
}
#endif

 

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

шаблон только с явной специализаций.

/**/
//aaa.h------------------------
template <typename T>
class aaa {
  protected:
    T data;
  public:
    ~aaa();
    aaa();
    aaa(T d);
    aaa(const aaa& other);
    aaa(aaa&& other) noexcept;
    aaa& operator=(const aaa& other);
    aaa& operator=(aaa&& other) noexcept ;
    //
    operator  byte();
};
//aaa.cpp------------------------
/*общее*/
// отсутсвуют
/*byte*/
template <>
aaa<byte>::~aaa() {}
template <>
aaa<byte>::aaa(): data(0) {}
template <>
aaa<byte>::aaa(byte d): data(d) {}
template <>
aaa<byte>::aaa(const aaa<byte>& other): data(other.data) {}
template <>
aaa<byte>::aaa(aaa<byte>&& other): data(other.data) {}
template <>
aaa<byte>& aaa<byte>::operator=(const aaa<byte>& other) {
  data = other.data;
  return *this;
}
template <>
aaa<byte>& aaa<byte>::operator=(aaa<byte>&& other) {
  data = other.data;
  return *this;
}
//
template <>
aaa<byte>::operator  byte() {
  return data;
}
//------------------------
void setup() {
  Serial.begin(9600);
  aaa<byte> a(5);
  aaa<byte> b(a);
  aaa<byte> c;
  c = b;
  Serial.println(c);
}
void loop() {

}

 

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

А что допустимo в качестве T ? Кроме byte, конечно.

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

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

А что допустимo в качестве T ? Кроме byte, конечно.

Вопрос с подковыркой, насколько я понимаю, мельком взглянув на код? ;)

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

Интересуюсь.

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

DIYMan пишет:

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

А что допустимo в качестве T ? Кроме byte, конечно.

Вопрос с подковыркой, насколько я понимаю, мельком взглянув на код? ;)

а в фиге вместо косточки стриптиз? )))

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

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

Интересуюсь.

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

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

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

А что допустимo в качестве T ? Кроме byte, конечно.

В том то и дело что ничего. И это замечательно. Но пока char* не могу запустить.

template <>
aaa<char*>::operator char*() {
  return data;
}

ПС:https://metanit.com/cpp/tutorial/5.15.php

sadman41
Онлайн
Зарегистрирован: 19.10.2016

Опять квона бьют...

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

qwone пишет:

А теперь тоже самое но с записью EEPPROM

Семё-ё-ён Семёныч ...

Пух, ну ты же взрослый мужик, претендуешь на какие-то знания, ну что же ты творишь?

Вот это что такое?

const String* adr1 = (String*)0; // адресс ячеек для записи String
const float*  adr2 = (float*)(&adr1 + STRING_SIZE);// адресс ячеек для записи float

Давай напечатаем твои адреса.

#include "aaa.h"
const String* adr1 = (String*)0; // адресс ячеек для записи String
const float*  adr2 = (float*)(&adr1 + STRING_SIZE);// адресс ячеек для записи float
//-----------------------
void setup() {
  Serial.begin(57600);
  Serial.println((uint16_t)adr1);
  Serial.println((uint16_t)adr2);
}
void loop() {
}

/////////////////////////
// В МОНИТОРЕ
//
//  0
//  310

Ты точно этого хотел? Может, вот так надо было?

#include "aaa.h"
const String* adr1 = (String*)0; // адресс ячеек для записи String
const float*  adr2 = (float*)((byte *)adr1 + STRING_SIZE);// адресс ячеек для записи float
//-----------------------
void setup() {
  Serial.begin(57600);
  Serial.println((uint16_t)adr1);
  Serial.println((uint16_t)adr2);
}
void loop() {
}

/////////////////////////
// В МОНИТОРЕ
//
//  0
//  16

Так должно быть?

Но, если сделать так, то не проходит твой тест. Почти твой - я лишь переместил число раньше строки и само число поменял. Смотри сам:

#include "aaa.h"
const String* adr1 = (String*)0; // адресс ячеек для записи String
const float*  adr2 = (float*)((byte *)adr1 + STRING_SIZE);// адресс ячеек для записи float
//-----------------------
void setup() {
  Serial.begin(57600);
  aaa<float>  b(adr2);
  b = -12345678;
  Serial.println(b);
  aaa<String> a(adr1);
  a = String(F("temp String 1234567890"));
  Serial.println(a);
  aaa<String> c(adr1);
  Serial.println(c);
  aaa<float>  d(adr2);
  Serial.println(d);
}
void loop() {
}
/////////////////////////
// В МОНИТОРЕ
//
// -12345678.00
// temp String 1234
// temp String 1234
// -12345600.00

Видишь, что число переврано? Твоя строка его затирает!

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

qwone пишет:
В том то и дело что ничего. И это замечательно.
Понятно, спасибо.

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

Ворота пишет:
Видишь, что число переврано? Твоя строка его затирает!
Не сразу Москва строилась. Да и Гагарин шагнул в космос с домашнего подъезда. Вот потихоньку я двигаюсь к цели. 

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

sadman41 пишет:

Опять квона бьют...

за то, что двойное нажатие к кнопке не приделал?

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

qwone пишет:
Не сразу Москва строилась.
Квон, ты напрасно уверен в том, что я наезжаю на тебя. Используешь слова типа "обсирать". Это не так, поверь. Мне реально симпатичны твоё усердие и старание, и мне приятно тебе помочь. Пока моя помощь состоит только в демонстрации факта наличия ошибок (уверен с их сутью ты и сам разберёшься). Но если какая-то из ошибок непонятна, не стесняйся спрашивать - я всегда объясню и помогу.

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

разобрался с <char*>

/**/
#include "aaa.h"
//------------------------
void setup() {
  Serial.begin(9600);
  aaa<byte> a(5);
  aaa<byte> b(a);
  aaa<byte> c;
  c = b;
  Serial.println(c);
  aaa<char*> aa;
  aa="qwerty";
  Serial.println(aa);
}
void loop() {

}

aaa.h

/*aaa.h*/
#ifndef AAA_H
#define AAA_H
//aaa.h------------------------
template <typename T>
class aaa {
  protected:
    T data;
  public:
    ~aaa();
    aaa();
    aaa(T d);
    aaa(const aaa& other);
    aaa(aaa&& other) noexcept;
    aaa& operator=(const aaa& other);
    aaa& operator=(aaa&& other) noexcept ;
    //
    operator T() const;
};
//aaa.cpp------------------------
/*общее*/
// отсутсвуют
/*byte*/
template <>
aaa<byte>::~aaa() {}
template <>
aaa<byte>::aaa(): data(0) {}
template <>
aaa<byte>::aaa(byte d): data(d) {}
template <>
aaa<byte>::aaa(const aaa<byte>& other): data(other.data) {}
template <>
aaa<byte>::aaa(aaa<byte>&& other): data(other.data) {}
template <>
aaa<byte>& aaa<byte>::operator=(const aaa<byte>& other) {
  data = other.data;
  return *this;
}
template <>
aaa<byte>& aaa<byte>::operator=(aaa<byte>&& other) {
  data = other.data;
  return *this;
}
//
template <>
aaa<byte>::operator  byte() const{
  return data;
}
/* char* */
template <>
aaa<char*>::~aaa() {
  delete[] data;
}
template <>
aaa<char*>::aaa(): data(nullptr) {}
template <>
aaa<char*>::aaa(char* d)
  : data(new char[strlen(d) + 1]) {
  strcpy(data, d);
}
template <>
aaa<char*>::aaa(const aaa<char*>& other)
  : data(new char[strlen(other.data) + 1]) {
  strcpy(data, other.data);
}
template <>
aaa<char*>::aaa(aaa<char*> && other): data(other.data) {
  data = other.data;
  other.data = nullptr;
}
template <>
aaa<char*>& aaa<char*>::operator=(const aaa<char*>& other) {
  if (this == &other)return *this;
  char* tmp = new char[strlen(other.data) + 1];
  strcpy(tmp, other.data);
  delete[] data;
  data = tmp;
  return *this;
}
template <>
aaa<char*>& aaa<char*>::operator=(aaa<char*>&& other) {
  if (this == &other)return *this;
  delete[] data;
  data = other.data;
  other.data = nullptr;
  return *this;
}
//
template <>
aaa<char*>::operator char*() const{
  return data;
}
#endif

ПС: А это чисто поржать https://www.youtube.com/watch?v=XZEi0bzrMfY

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

очередной набросок

/**/
//eeprom_Ref.h---------------------------------
#include <avr/eeprom.h>
template <typename T>
class eeprom_Ref {
  protected:
    const T* adr;
  public:
    ~eeprom_Ref();
    eeprom_Ref() = delete;
    explicit eeprom_Ref(const T* a);
    eeprom_Ref(const eeprom_Ref& other) = delete;
    eeprom_Ref(eeprom_Ref&& other) = delete;
    eeprom_Ref& operator=(const eeprom_Ref& other);
    eeprom_Ref& operator=(eeprom_Ref&& other) noexcept ;
    //
    operator T() const;
    eeprom_Ref& operator=(const T& data);
};
//eeprom_Ref.cpp---------------------------------
/*все*/
template <typename T>
eeprom_Ref<T>::~eeprom_Ref() {}
/* uint8_t*/
template <>
eeprom_Ref<uint8_t>::eeprom_Ref(const uint8_t* a): adr(a) {}
template <>
eeprom_Ref<uint8_t>::operator uint8_t() const {
  return eeprom_read_byte (adr);
}
template <>
eeprom_Ref<uint8_t>& eeprom_Ref<uint8_t>::operator=(const uint8_t& data) {
  eeprom_write_byte (adr, data);
  return *this;
}
/* uint16_t*/
template <>
eeprom_Ref<uint16_t>::eeprom_Ref(const uint16_t* a): adr(a) {}
template <>
eeprom_Ref<uint16_t>::operator uint16_t() const {
  return eeprom_read_word(adr);
}
template <>
eeprom_Ref<uint16_t>& eeprom_Ref<uint16_t>::operator=(const uint16_t& data) {
  eeprom_write_word(adr, data);
  return *this;
}
/* uint32_t*/
template <>
eeprom_Ref<uint32_t>::eeprom_Ref(const uint32_t* a): adr(a) {}
template <>
eeprom_Ref<uint32_t>::operator uint32_t() const {
  return eeprom_read_dword(adr);
}
template <>
eeprom_Ref<uint32_t>& eeprom_Ref<uint32_t>::operator=(const uint32_t& data) {
  eeprom_write_dword(adr, data);
  return *this;
}
/* float*/
template <>
eeprom_Ref<float>::eeprom_Ref(const float* a): adr(a) {}
template <>
eeprom_Ref<float>::operator float() const {
  return eeprom_read_float ((const float *)adr);
}
template <>
eeprom_Ref<float>& eeprom_Ref<float>::operator=(const float& data) {
  eeprom_write_float(adr, data);
  return *this;
}
//---------------------------------
const uint8_t* adr1 = (uint8_t*)0;
const uint16_t* adr2 = (uint16_t*)10;
const float* adr3 = (float*)20;
void setup() {
  Serial.begin(9600);
  eeprom_Ref<uint8_t> aaa(adr1);
  aaa = 10;
  Serial.println(aaa);
  eeprom_Ref<uint16_t> bbb(adr2);
  bbb = 100 + aaa;
  Serial.println(bbb);
  eeprom_Ref<float> ccc(adr3);
  ccc = 12.34;
  Serial.println(ccc);
}
void loop() {
}

 

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

qwone пишет:

очередной набросок

C:\Qwone\test\test.ino: In member function 'eeprom_Ref<T>& eeprom_Ref<T>::operator=(const T&) [with T = unsigned char]':

C:\Qwone\test\test.ino:33:22: warning: invalid conversion from 'const unsigned char*' to 'uint8_t* {aka unsigned char*}' [-fpermissive]

In file included from C:\Arduino\arduino-1.8.10\hardware\arduino\avr\cores\arduino/USBAPI.h:25:0,

                 from C:\Arduino\arduino-1.8.10\hardware\arduino\avr\cores\arduino/Arduino.h:233,

                 from sketch\test.ino.cpp:1:

c:\arduino\arduino-1.8.10\hardware\tools\avr\avr\include\avr\eeprom.h:164:6: note:   initializing argument 1 of 'void eeprom_write_byte(uint8_t*, uint8_t)'

 void eeprom_write_byte (uint8_t *__p, uint8_t __value);

      ^~~~~~~~~~~~~~~~~

C:\Qwone\test\test.ino: In member function 'eeprom_Ref<T>& eeprom_Ref<T>::operator=(const T&) [with T = unsigned int]':

C:\Qwone\test\test.ino:45:21: warning: invalid conversion from 'const unsigned int*' to 'uint16_t* {aka unsigned int*}' [-fpermissive]

In file included from C:\Arduino\arduino-1.8.10\hardware\arduino\avr\cores\arduino/USBAPI.h:25:0,

                 from C:\Arduino\arduino-1.8.10\hardware\arduino\avr\cores\arduino/Arduino.h:233,

                 from sketch\test.ino.cpp:1:

c:\arduino\arduino-1.8.10\hardware\tools\avr\avr\include\avr\eeprom.h:169:6: note:   initializing argument 1 of 'void eeprom_write_word(uint16_t*, uint16_t)'

 void eeprom_write_word (uint16_t *__p, uint16_t __value);

      ^~~~~~~~~~~~~~~~~

C:\Qwone\test\test.ino: In member function 'eeprom_Ref<T>& eeprom_Ref<T>::operator=(const T&) [with T = long unsigned int]':

C:\Qwone\test\test.ino:57:22: warning: invalid conversion from 'const long unsigned int*' to 'uint32_t* {aka long unsigned int*}' [-fpermissive]

In file included from C:\Arduino\arduino-1.8.10\hardware\arduino\avr\cores\arduino/USBAPI.h:25:0,

                 from C:\Arduino\arduino-1.8.10\hardware\arduino\avr\cores\arduino/Arduino.h:233,

                 from sketch\test.ino.cpp:1:

c:\arduino\arduino-1.8.10\hardware\tools\avr\avr\include\avr\eeprom.h:174:6: note:   initializing argument 1 of 'void eeprom_write_dword(uint32_t*, uint32_t)'

 void eeprom_write_dword (uint32_t *__p, uint32_t __value);

      ^~~~~~~~~~~~~~~~~~

C:\Qwone\test\test.ino: In member function 'eeprom_Ref<T>& eeprom_Ref<T>::operator=(const T&) [with T = float]':

C:\Qwone\test\test.ino:69:22: warning: invalid conversion from 'const float*' to 'float*' [-fpermissive]

In file included from C:\Arduino\arduino-1.8.10\hardware\arduino\avr\cores\arduino/USBAPI.h:25:0,

                 from C:\Arduino\arduino-1.8.10\hardware\arduino\avr\cores\arduino/Arduino.h:233,

                 from sketch\test.ino.cpp:1:

c:\arduino\arduino-1.8.10\hardware\tools\avr\avr\include\avr\eeprom.h:179:6: note:   initializing argument 1 of 'void eeprom_write_float(float*, float)'

 void eeprom_write_float (float *__p, float __value);

      ^~~~~~~~~~~~~~~~~~

Скетч использует 3166 байт (9%) памяти устройства. Всего доступно 32256 байт.
Глобальные переменные используют 200 байт (9%) динамической памяти, оставляя 1848 байт для локальных переменных. Максимум: 2048 байт.

 

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

очередной набросок

/**/
//aaa.h-----------------------
template <typename T>
class aaa {
  protected:
    T* pointer;
  public:
    ~aaa();
    aaa() = delete;
    explicit aaa(T* p);
    aaa(const aaa& other);
    aaa(aaa&& other) noexcept;
    aaa& operator=(const aaa& other);
    aaa& operator=(aaa&& other) noexcept ;
    //
    aaa& operator=(const T data);
    aaa operator[] (const int index);
    operator T();
};
//aaa.cpp-----------------------
/*общее*/
// отсутсвуют
/*byte*/
template <>
aaa<byte>::~aaa() {}
template <>
aaa<byte>::aaa(byte* p): pointer(p) {}
template <>
aaa<byte>::aaa(const aaa<byte>& other): pointer(other.pointer) {}
template <>
aaa<byte>::aaa(aaa<byte>&& other): pointer(other.pointer) {}
template <>
aaa<byte>& aaa<byte>::operator=(const aaa<byte>& other) {
  pointer = other.pointer;
  return *this;
}
template <>
aaa<byte>& aaa<byte>::operator=(aaa<byte>&& other) {
  pointer = other.pointer;
  return *this;
}
//
template <>
aaa<byte>& aaa<byte>::operator=(const byte data) {
  pointer[0] = data;
  return *this;
}
template <>
aaa<byte> aaa<byte>::operator[] (const int index) {
  aaa other(pointer + index);
  return other;
}
template <>
aaa<byte>::operator byte() {
  return pointer[0];
}
//-----------------------
#define num 10
void setup() {
  byte Array[num];
  aaa<byte> a(Array); a = 14;
  Serial.begin(9600);
  Serial.println(a);
  Serial.println(a[6] = a + 3);
}
void loop() {
}

 

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

qwone пишет:

очередной набросок

/**/
//aaa.h-----------------------
template <typename T>
class aaa {
  protected:
    T* pointer;
  public:
    ~aaa();
    aaa() = delete;
    explicit aaa(T* p);
    aaa(const aaa& other);
    aaa(aaa&& other) noexcept;
    aaa& operator=(const aaa& other);
    aaa& operator=(aaa&& other) noexcept ;
    //
    aaa& operator=(const T data);
    aaa operator[] (const int index);
    operator T();
};
//aaa.cpp-----------------------
/*общее*/
// отсутсвуют
/*byte*/
template <>
aaa<byte>::~aaa() {}
template <>
aaa<byte>::aaa(byte* p): pointer(p) {}
template <>
aaa<byte>::aaa(const aaa<byte>& other): pointer(other.pointer) {}
template <>
aaa<byte>::aaa(aaa<byte>&& other): pointer(other.pointer) {}
template <>
aaa<byte>& aaa<byte>::operator=(const aaa<byte>& other) {
  pointer = other.pointer;
  return *this;
}
template <>
aaa<byte>& aaa<byte>::operator=(aaa<byte>&& other) {
  pointer = other.pointer;
  return *this;
}
//
template <>
aaa<byte>& aaa<byte>::operator=(const byte data) {
  pointer[0] = data;
  return *this;
}
template <>
aaa<byte> aaa<byte>::operator[] (const int index) {
  aaa other(pointer + index);
  return other;
}
template <>
aaa<byte>::operator byte() {
  return pointer[0];
}
//-----------------------
#define num 10
void setup() {
  byte Array[num];
  aaa<byte> a(Array); a = 14;
  Serial.begin(9600);
  Serial.println(a);
  Serial.println(a[6] = a + 3);
}
void loop() {
}

 

вопрос можно? Реально в твоём коде кнопки добавить двойное-тройное нажатие, хотя бы двойное

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

ua6em пишет:
вопрос можно? Реально в твоём коде кнопки добавить двойное-тройное нажатие, хотя бы двойное

Можно, хоть титановый велосипед. Просто я считаю, что в нормально спроектированном меню это не желательно. Где-то я Гайверовские кнопки подключал. Используйте их.

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

qwone пишет:

ua6em пишет:
вопрос можно? Реально в твоём коде кнопки добавить двойное-тройное нажатие, хотя бы двойное

Можно, хоть титановый велосипед. Просто я считаю, что в нормально спроектированном меню это не желательно. Где-то я Гайверовские кнопки подключал. Используйте их.

пробовал, бывают сбои, на твоём коде за всё время отработки (ТАМ УЖЕ ЗА 800 СТРОК) одной программы ни одного сбоя )))
Правда сын посмотрев мой код изрёк - такое впечатление, что писали как минимум три программиста, ...
я жеж просто заимствую код...естественно - сборная солянка )))

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

Вот и я об этом. Лучше меньше, да надежней. Я к этому варианту меню пришел не сразу. И обработка кнопок с минимумом тоже не сразу. И да скорее обменял долгое нажатие на повторное нажатие. Вот сейчас ковыряюсь с EEPROM. Тоже неплохо выйдет. Вот только интерфейс команд класса и некоторая защита от идиота.

/**/
#include "aaa.h"
byte* adr1 = (byte*)0;
int num = 10;
void setup() {
  Serial.begin(9600);
  aaa<byte> a(adr1);
  Serial.print('\n');
  for (int i = 0; i < num; i++) {
    Serial.print(a[i]); Serial.print(' ');
  }
  Serial.print('\n');
  for (int i = 0; i < num; i++) {
    Serial.print(a[i] = a[i] + 1); Serial.print(' ');
  }
  Serial.print('\n');
}
void loop() {
}

aaa.h 

/* aaa.h */
#ifndef AAA_H
#define AAA_H
//aaa.h-----------------------
#include <avr/eeprom.h>
template <typename T>
class aaa {
  protected:
    T* pointer;
  public:
    ~aaa();
    aaa() = delete;
    explicit aaa(T* p);
    aaa(const aaa& other);
    aaa(aaa&& other) noexcept;
    aaa& operator=(const aaa& other);
    aaa& operator=(aaa&& other) noexcept ;
    //
    aaa& operator=(const T data);
    aaa operator[] (const int index);
    operator T();
};
//aaa.cpp-----------------------
/*общее*/
// отсутсвуют
/*byte*/
template <>
aaa<byte>::~aaa() {}
template <>
aaa<byte>::aaa(byte* p): pointer(p) {}
template <>
aaa<byte>::aaa(const aaa<byte>& other): pointer(other.pointer) {}
template <>
aaa<byte>::aaa(aaa<byte>&& other): pointer(other.pointer) {}
template <>
aaa<byte>& aaa<byte>::operator=(const aaa<byte>& other) {
  pointer = other.pointer;
  return *this;
}
template <>
aaa<byte>& aaa<byte>::operator=(aaa<byte>&& other) {
  pointer = other.pointer;
  return *this;
}
//
template <>
aaa<byte>& aaa<byte>::operator=(const byte data) {
  eeprom_write_byte(pointer, data);
  return *this;
}
template <>
aaa<byte> aaa<byte>::operator[](const int index) {
  aaa<byte> other(pointer + index);
  return other;
}
template <>
aaa<byte>::operator byte() {
  return eeprom_read_byte(pointer);
}
#endif

ПС: И да я совмещаю .h c .cpp для удобства выкладки на форуме.

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

Промежуточный вариант 

/**/
#include "eeprom_Ref.h"
float* adr1 = (float*)0;
int num = 10;
void setup() {
  Serial.begin(9600);
  eeprom_Ref<float> a(adr1);
  Serial.print('\n');
  for (int i = 0; i < num; i++) {
    Serial.print(a[i]); Serial.print(' ');
  }
  Serial.print('\n');
  for (int i = 0; i < num; i++) {
    Serial.print(a[i] = a[i] + 1.23); Serial.print(' ');
  }
  Serial.print('\n');
}
void loop() {
}

eeprom_Ref.h

/* eeprom_Ref.h */
#ifndef EEPROM_REF_H
#define EEPROM_REF_H
//eeprom_Ref.h-----------------------
#include <avr/eeprom.h>
template <typename T>
class eeprom_Ref {
  protected:
    T* pointer;
  public:
    ~eeprom_Ref();
    eeprom_Ref() = delete;
    explicit eeprom_Ref(T* p);
    eeprom_Ref(const eeprom_Ref& other);
    eeprom_Ref(eeprom_Ref&& other) noexcept;
    eeprom_Ref& operator=(const eeprom_Ref& other);
    eeprom_Ref& operator=(eeprom_Ref&& other) noexcept ;
    //
    eeprom_Ref& operator=(const T data);
    eeprom_Ref operator[] (const int index);
    operator T();
};
//eeprom_Ref.cpp-----------------------
/*общее*/
// отсутсвуют
/*byte*/
template <>
eeprom_Ref<byte>::~eeprom_Ref() {}
template <>
eeprom_Ref<byte>::eeprom_Ref(byte* p): pointer(p) {}
template <>
eeprom_Ref<byte>::eeprom_Ref(const eeprom_Ref<byte>& other): pointer(other.pointer) {}
template <>
eeprom_Ref<byte>::eeprom_Ref(eeprom_Ref<byte>&& other): pointer(other.pointer) {}
template <>
eeprom_Ref<byte>& eeprom_Ref<byte>::operator=(const eeprom_Ref<byte>& other) {
  pointer = other.pointer;
  return *this;
}
template <>
eeprom_Ref<byte>& eeprom_Ref<byte>::operator=(eeprom_Ref<byte>&& other) {
  pointer = other.pointer;
  return *this;
}
//
template <>
eeprom_Ref<byte>& eeprom_Ref<byte>::operator=(const byte data) {
  eeprom_write_byte(pointer, data);
  return *this;
}
template <>
eeprom_Ref<byte> eeprom_Ref<byte>::operator[](const int index) {
  eeprom_Ref<byte> other(pointer + index);
  return other;
}
template <>
eeprom_Ref<byte>::operator byte() {
  return eeprom_read_byte(pointer);
}
/* uint16_t*/
template <>
eeprom_Ref<uint16_t>::~eeprom_Ref() {}
template <>
eeprom_Ref<uint16_t>::eeprom_Ref(uint16_t* p): pointer(p) {}
template <>
eeprom_Ref<uint16_t>::eeprom_Ref(const eeprom_Ref<uint16_t>& other): pointer(other.pointer) {}
template <>
eeprom_Ref<uint16_t>::eeprom_Ref(eeprom_Ref<uint16_t>&& other): pointer(other.pointer) {}
template <>
eeprom_Ref<uint16_t>& eeprom_Ref<uint16_t>::operator=(const eeprom_Ref<uint16_t>& other) {
  pointer = other.pointer;
  return *this;
}
template <>
eeprom_Ref<uint16_t>& eeprom_Ref<uint16_t>::operator=(eeprom_Ref<uint16_t>&& other) {
  pointer = other.pointer;
  return *this;
}
//
template <>
eeprom_Ref<uint16_t>& eeprom_Ref<uint16_t>::operator=(const uint16_t data) {
  eeprom_write_word(pointer, data);
  return *this;
}
template <>
eeprom_Ref<uint16_t> eeprom_Ref<uint16_t>::operator[](const int index) {
  eeprom_Ref<uint16_t> other(pointer + index);
  return other;
}
template <>
eeprom_Ref<uint16_t>::operator uint16_t() {
  return eeprom_read_word(pointer);
}
/* uint32_t*/
template <>
eeprom_Ref<uint32_t>::~eeprom_Ref() {}
template <>
eeprom_Ref<uint32_t>::eeprom_Ref(uint32_t* p): pointer(p) {}
template <>
eeprom_Ref<uint32_t>::eeprom_Ref(const eeprom_Ref<uint32_t>& other): pointer(other.pointer) {}
template <>
eeprom_Ref<uint32_t>::eeprom_Ref(eeprom_Ref<uint32_t>&& other): pointer(other.pointer) {}
template <>
eeprom_Ref<uint32_t>& eeprom_Ref<uint32_t>::operator=(const eeprom_Ref<uint32_t>& other) {
  pointer = other.pointer;
  return *this;
}
template <>
eeprom_Ref<uint32_t>& eeprom_Ref<uint32_t>::operator=(eeprom_Ref<uint32_t>&& other) {
  pointer = other.pointer;
  return *this;
}
//
template <>
eeprom_Ref<uint32_t>& eeprom_Ref<uint32_t>::operator=(const uint32_t data) {
  eeprom_write_dword(pointer, data);
  return *this;
}
template <>
eeprom_Ref<uint32_t> eeprom_Ref<uint32_t>::operator[](const int index) {
  eeprom_Ref<uint32_t> other(pointer + index);
  return other;
}
template <>
eeprom_Ref<uint32_t>::operator uint32_t() {
  return eeprom_read_dword(pointer);
}
/* float*/
template <>
eeprom_Ref<float>::~eeprom_Ref() {}
template <>
eeprom_Ref<float>::eeprom_Ref(float* p): pointer(p) {}
template <>
eeprom_Ref<float>::eeprom_Ref(const eeprom_Ref<float>& other): pointer(other.pointer) {}
template <>
eeprom_Ref<float>::eeprom_Ref(eeprom_Ref<float>&& other): pointer(other.pointer) {}
template <>
eeprom_Ref<float>& eeprom_Ref<float>::operator=(const eeprom_Ref<float>& other) {
  pointer = other.pointer;
  return *this;
}
template <>
eeprom_Ref<float>& eeprom_Ref<float>::operator=(eeprom_Ref<float>&& other) {
  pointer = other.pointer;
  return *this;
}
//
template <>
eeprom_Ref<float>& eeprom_Ref<float>::operator=(const float data) {
  eeprom_write_float(pointer, data);
  return *this;
}
template <>
eeprom_Ref<float> eeprom_Ref<float>::operator[](const int index) {
  eeprom_Ref<float> other(pointer + index);
  return other;
}
template <>
eeprom_Ref<float>::operator float() {
  return eeprom_read_float(pointer);
}
#endif

 

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

Похоже почти получилось создать реферальный класс на EEPROM

/**/
#include "eeprom_Ref.h"
int* adr1 = (int*)0;
float* adr2 = (float*)50;

void setup() {
  Serial.begin(9600);
  eeprom_int a(adr1);
  a[5] = 5;
  Serial.println(a[5]);
  eeprom_float b(adr2);
  b[1] = 5.33;
  Serial.println(b[1]);
}
void loop() {
}

eeprom_Ref.h

/* eeprom_Ref.h */
#ifndef EEPROM_REF_H
#define EEPROM_REF_H
//Ref.h-----------------------
#include <avr/eeprom.h>
template <typename T>
class Ref {
  protected:
    T* pointer;
    void set(T data);
    T get();
  public:
    ~Ref();
    Ref() = delete;
    Ref(T* a);
    Ref(const Ref& other) = delete;
    Ref(Ref&& other);
    Ref& operator=(const Ref& other) = delete;
    Ref& operator=(Ref&& other);
    //
    operator T();
    Ref& operator=(T&& d);
    Ref& operator=(const T& d);
    Ref operator[] (const int index);
};
typedef Ref<byte>     eeprom_byte;
typedef Ref<int>      eeprom_int;
typedef Ref<uint16_t> eeprom_uint16_t;
typedef Ref<uint32_t> eeprom_uint32_t;
typedef Ref<float>    eeprom_float;
//Ref.cpp-----------------------
/*byte*/
template <>
void Ref<byte>::set(byte data) {
  eeprom_write_byte(pointer, data);
}
template <>
byte Ref<byte>::get() {
  return eeprom_read_byte(pointer);
}
/* int */
template <>
void Ref<int>::set(int data) {
  eeprom_write_word((uint16_t*)pointer, (uint16_t)data);
}
template <>
int Ref<int>::get() {
  return eeprom_read_word((uint16_t*)pointer);
}
/* uint16_t*/
template <>
void Ref<uint16_t>::set(uint16_t data) {
  eeprom_write_word(pointer, data);
}
template <>
uint16_t Ref<uint16_t>::get() {
  return eeprom_read_word(pointer);
}
/* uint32_t*/
template <>
void Ref<uint32_t>::set(uint32_t data) {
  eeprom_write_dword(pointer, data);
}
template <>
uint32_t Ref<uint32_t>::get() {
  return eeprom_read_dword(pointer);
}
/* float*/
template <>
void Ref<float>::set(float data) {
  eeprom_write_float(pointer, data);
}
template <>
float Ref<float>::get() {
  return eeprom_read_float(pointer);
}
/*общее*/
template <typename T>
Ref<T>::~Ref() {}
template <typename T>
Ref<T>::Ref(T* a): pointer(a) {}
template <typename T>
Ref<T>::Ref(Ref<T>&& other) {
  set(other.get());
}
template <typename T>
Ref<T>& Ref<T>::operator=(Ref<T>&& other) {
  set(other.get());
  return *this;
}
template <typename T>
Ref<T>::operator T() {
  return get();
}
template <typename T>
Ref<T>& Ref<T>::operator=(T&& d) {
  set(d);
  return *this;
}
template <typename T>
Ref<T>& Ref<T>::operator=(const T& d) {
  set(d);
  return *this;
}
template <typename T>
Ref<T> Ref<T>::operator[] (const int index) {
  return Ref<T>(pointer + index);
}
#endif

 

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

Следующая доработка класса. И да шаблон класса почему-то на два файла .h  и .cpp не делится, а точнее не компилируется

/**/
#include "eeprom_Ref.h"
int* adr1 = (int*)0;
float* adr2 = (float*)50;
const float adr3[] PROGMEM = {0.23,12.34, 13.45, 14.56};
void setup() {
  Serial.begin(9600);
  eeprom_int a(adr1);
  a[5] = 5;
  Serial.println(a[5]);
  eeprom_float b(adr2);
  b[1] = 5.33;
  Serial.println(b[1]);
  pgm_float c(adr3);
  Serial.println(c[2]);
}
void loop() {
}

eeprom_Ref.h

/* Ref.h */
#ifndef EEPROM_REF_H
#define EEPROM_REF_H
//Ref.h-----------------------
#include <Arduino.h>
#include <avr/eeprom.h>
template <typename T>
class Ref {
  protected:
    T* pointer;
    void set(T data);
    T get();
  public:
    ~Ref();
    Ref() = delete;
    Ref(T* a);
    Ref(const Ref& other) = delete;
    Ref(Ref&& other);
    Ref& operator=(const Ref& other) = delete;
    Ref& operator=(Ref&& other);
    //
    operator T();
    Ref& operator=(T&& d);
    Ref& operator=(const T& d);
    Ref operator[] (const int index);
};
//Ref.cpp-----------------------
/* uint8_t */
template <>
void Ref<uint8_t>::set(uint8_t data) {
  eeprom_write_byte(pointer, data);
}
template <>
uint8_t Ref<uint8_t>::get() {
  return eeprom_read_byte(pointer);
}
/* int */
template <>
void Ref<int>::set(int data) {
  eeprom_write_word((uint16_t*)pointer, (uint16_t)data);
}
template <>
int Ref<int>::get() {
  return eeprom_read_word((uint16_t*)pointer);
}
/* uint16_t*/
template <>
void Ref<uint16_t>::set(uint16_t data) {
  eeprom_write_word(pointer, data);
}
template <>
uint16_t Ref<uint16_t>::get() {
  return eeprom_read_word(pointer);
}
/* uint32_t*/
template <>
void Ref<uint32_t>::set(uint32_t data) {
  eeprom_write_dword(pointer, data);
}
template <>
uint32_t Ref<uint32_t>::get() {
  return eeprom_read_dword(pointer);
}
/* float*/
template <>
void Ref<float>::set(float data) {
  eeprom_write_float(pointer, data);
}
template <>
float Ref<float>::get() {
  return eeprom_read_float(pointer);
}
/*общее*/
template <typename T>
Ref<T>::~Ref() {}
template <typename T>
Ref<T>::Ref(T* a): pointer(a) {}
template <typename T>
Ref<T>::Ref(Ref<T>&& other) {
  pointer = other.pointer;
}
template <typename T>
Ref<T>& Ref<T>::operator=(Ref<T>&& other) {
  if (pointer != other.pointer)
    set(other.get());
  return *this;
}
template <typename T>
Ref<T>::operator T() {
  return get();
}
template <typename T>
Ref<T>& Ref<T>::operator=(T&& d) {
  set(d);
  return *this;
}
template <typename T>
Ref<T>& Ref<T>::operator=(const T& d) {
  set(d);
  return *this;
}
template <typename T>
Ref<T> Ref<T>::operator[] (const int index) {
  return Ref<T>(pointer + index);
}
using eeprom_int      = Ref<int> ;
using eeprom_uint8_t  = Ref<uint8_t>;
using eeprom_uint16_t = Ref<uint16_t>;
using eeprom_uint32_t = Ref<uint32_t>;
using eeprom_float    = Ref<float>;
//pRef.h-----------------------------
#include <avr/pgmspace.h>
template <typename T>
class pRef {
  protected:
    const T* pointer;
    T get();
  public:
    ~pRef();
    pRef() = delete;
    pRef(const T* a);
    pRef(const pRef& other) = delete;
    pRef(pRef&& other);
    pRef& operator=(const pRef& other) = delete;
    pRef& operator=(pRef&& other);
    //
    operator T();
    pRef operator[] (const int index);
};
//pRef.cpp-----------------------------
/*uint8_t*/
template <>
uint8_t pRef<uint8_t>::get() {
  return pgm_read_byte(pointer);
}
/* int */
template <>
int pRef<int>::get() {
  return pgm_read_word((uint16_t*)pointer);
}
/* uint16_t*/
template <>
uint16_t pRef<uint16_t>::get() {
  return pgm_read_word(pointer);
}
/* uint32_t*/
template <>
uint32_t pRef<uint32_t>::get() {
  return pgm_read_dword(pointer);
}
/* float*/
template <>
float pRef<float>::get() {
  return pgm_read_float(pointer);
}
/*общее*/
template <typename T>
pRef<T>::~pRef() {}
template <typename T>
pRef<T>::pRef(const T* a): pointer(a) {}
template <typename T>
pRef<T>::pRef(pRef<T>&& other)
  : pointer(other.pointer) {}

template <typename T>
pRef<T>& pRef<T>::operator=(pRef<T>&& other) {
  pointer = other.pointer;
  return *this;
}
template <typename T>
pRef<T>::operator T() {
  return get();
}
template <typename T>
pRef<T> pRef<T>::operator[] (const int index) {
  return pRef<T>(pointer + index);
}
//-------------------------------------------------
using pgm_int      = pRef<int>;
using pgm_uint8_t  = pRef<uint8_t>;
using pgm_uint16_t = pRef<uint16_t>;
using pgm_uint32_t = pRef<uint32_t>;
using pgm_float    = pRef<float>;
#endif

 

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

Организовал на основе этого класса меню и посмотрел как выглядит он в этой комбинации

/**/
// 10 устройств с данными uint8_t,int,float
#include "eeprom_Ref.h"
byte index = 0;
const byte max_index = 10;
uint8_t* eeprom_b = (uint8_t*)(100);
int*     eeprom_i = (int*)    ((int)eeprom_b + max_index*sizeof(uint8_t));
float*   eeprom_f = (float*)  ((int)eeprom_i + max_index*sizeof(int));
eeprom_uint8_t eeprom_B(eeprom_b);
eeprom_int     eeprom_I(eeprom_i);
eeprom_float   eeprom_F(eeprom_f);
byte setting_index = 0;
const byte max_setting_index = 5;
static const PROGMEM uint8_t pgm_b[] = {100,101,102,103,104};
static const PROGMEM int     pgm_i[] = {1000,1001,1002,1003,1004};
static const PROGMEM float   pgm_f[] = {10.10,10.11,10.12,10.13,10.14};
pgm_uint8_t pgm_B(pgm_b);
pgm_int     pgm_I(pgm_i);
pgm_float   pgm_F(pgm_f);

#include "menu.h"
//----------------------------------------
void setup() {
  menu_init();
  while (1) {
    menu_run();
  }
}
void loop() {}

Cl_btn.h

/*Cl_btn.h*/
#ifndef Cl_btn_h
#define Cl_btn_h
//Cl_btn.h--------------------------------
typedef void (*pDo)();
class Cl_btn {
  public:
    Cl_btn(byte p): pin(p) {}
    pDo Do = [] {};
    void init();
    void run();
  protected:
    void set(bool s);
    byte pin;
    bool state;
    unsigned long past;
};
//Cl_btn.cpp--------------------------------
void Cl_btn::set(bool s) {
  state = s;
  past = millis();
  if (s == true) Do();
}
void Cl_btn::init() {
  pinMode(pin, INPUT_PULLUP);
  set(false);
}
void Cl_btn::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;
    }
}
#endif

eeprom_Ref.h

/* eeprom_Ref.h */
#ifndef EEPROM_REF_H
#define EEPROM_REF_H
//Ref.h-----------------------
#include <Arduino.h>
#include <avr/eeprom.h>
template <typename T>
class Ref {
  protected:
    T* pointer;
    void set(T data);
    T get();
  public:
    ~Ref();
    Ref() = delete;
    Ref(T* a);
    Ref(const Ref& other) = delete;
    Ref(Ref&& other);
    Ref& operator=(const Ref& other) = delete;
    Ref& operator=(Ref&& other);
    //
    operator T();
    Ref& operator=(T&& d);
    Ref& operator=(const T& d);
    Ref operator[] (const int index);
    Ref& operator +=(T&& d);
    Ref& operator -=(T&& d);
};
//Ref.cpp-----------------------
/* uint8_t */
template <>
void Ref<uint8_t>::set(uint8_t data) {
  eeprom_write_byte(pointer, data);
}
template <>
uint8_t Ref<uint8_t>::get() {
  return eeprom_read_byte(pointer);
}
/* int */
template <>
void Ref<int>::set(int data) {
  eeprom_write_word((uint16_t*)pointer, (uint16_t)data);
}
template <>
int Ref<int>::get() {
  return eeprom_read_word((uint16_t*)pointer);
}
/* uint16_t*/
template <>
void Ref<uint16_t>::set(uint16_t data) {
  eeprom_write_word(pointer, data);
}
template <>
uint16_t Ref<uint16_t>::get() {
  return eeprom_read_word(pointer);
}
/* uint32_t*/
template <>
void Ref<uint32_t>::set(uint32_t data) {
  eeprom_write_dword(pointer, data);
}
template <>
uint32_t Ref<uint32_t>::get() {
  return eeprom_read_dword(pointer);
}
/* float*/
template <>
void Ref<float>::set(float data) {
  eeprom_write_float(pointer, data);
}
template <>
float Ref<float>::get() {
  return eeprom_read_float(pointer);
}
/*общее*/
template <typename T>
Ref<T>::~Ref() {}
template <typename T>
Ref<T>::Ref(T* a): pointer(a) {}
template <typename T>
Ref<T>::Ref(Ref<T>&& other) {
  pointer = other.pointer;
}
template <typename T>
Ref<T>& Ref<T>::operator=(Ref<T>&& other) {
  if (pointer != other.pointer)
    set(other.get());
  return *this;
}
template <typename T>
Ref<T>::operator T() {
  return get();
}
template <typename T>
Ref<T>& Ref<T>::operator=(T&& d) {
  set(d);
  return *this;
}
template <typename T>
Ref<T>& Ref<T>::operator=(const T& d) {
  set(d);
  return *this;
}
template <typename T>
Ref<T> Ref<T>::operator[] (const int index) {
  return Ref<T>(pointer + index);
}
template <typename T>
Ref<T>& Ref<T>::operator +=(T&& d) {
  set(get() + d);
  return *this;
}
template <typename T>
Ref<T>& Ref<T>::operator -=(T&& d) {
  set(get() - d);
  return *this;
}
using eeprom_int      = Ref<int> ;
using eeprom_uint8_t  = Ref<uint8_t>;
using eeprom_uint16_t = Ref<uint16_t>;
using eeprom_uint32_t = Ref<uint32_t>;
using eeprom_float    = Ref<float>;
//pRef.h-----------------------------
#include <avr/pgmspace.h>
template <typename T>
class pRef {
  protected:
    const T* pointer;
    T get();
  public:
    ~pRef();
    pRef() = delete;
    pRef(const T* a);
    pRef(const pRef& other) = delete;
    pRef(pRef&& other);
    pRef& operator=(const pRef& other) = delete;
    pRef& operator=(pRef&& other);
    //
    operator T();
    pRef operator[] (const int index);
};
//pRef.cpp-----------------------------
/*uint8_t*/
template <>
uint8_t pRef<uint8_t>::get() {
  return pgm_read_byte(pointer);
}
/* int */
template <>
int pRef<int>::get() {
  return pgm_read_word((uint16_t*)pointer);
}
/* uint16_t*/
template <>
uint16_t pRef<uint16_t>::get() {
  return pgm_read_word(pointer);
}
/* uint32_t*/
template <>
uint32_t pRef<uint32_t>::get() {
  return pgm_read_dword(pointer);
}
/* float*/
template <>
float pRef<float>::get() {
  return pgm_read_float(pointer);
}
/*общее*/
template <typename T>
pRef<T>::~pRef() {}
template <typename T>
pRef<T>::pRef(const T* a): pointer(a) {}
template <typename T>
pRef<T>::pRef(pRef<T>&& other)
  : pointer(other.pointer) {}

template <typename T>
pRef<T>& pRef<T>::operator=(pRef<T>&& other) {
  pointer = other.pointer;
  return *this;
}
template <typename T>
pRef<T>::operator T() {
  return get();
}
template <typename T>
pRef<T> pRef<T>::operator[] (const int index) {
  return pRef<T>(pointer + index);
}
//-------------------------------------------------
using pgm_int      = pRef<int>;
using pgm_uint8_t  = pRef<uint8_t>;
using pgm_uint16_t = pRef<uint16_t>;
using pgm_uint32_t = pRef<uint32_t>;
using pgm_float    = pRef<float>;
#endif

lcd2004_i2c.h

/*lcd2004_i2c.h*/
#ifndef LCD2004_I2C_H
#define LCD2004_I2C_H
// xy.h------------------------------------
class Cl_lcd2004_i2c;
class xy { // класс задание позиции
  public:
    int x, y;
    explicit xy(): x(0), y(0) {}
    explicit xy(int _x, int _y): x(_x), y(_y) {}
};
// xy.cpp------------------------------------
// GTX.h------------------------------------
class GTX : public Print {
    friend class Cl_lcd2004_i2c;
  protected:
    uint8_t W, H;
    uint8_t* buffer;
    int posX, posY;
  public:
    ~GTX();
    GTX();
    GTX(uint8_t w, uint8_t h);
    GTX(const GTX& other) = delete;
    GTX(GTX&& other );
    GTX& operator=(const GTX& other) = delete;
    GTX& operator=(GTX&& other);
    //
    void clear();
    void setCursor(uint8_t x, uint8_t y);
    inline size_t write(uint8_t c);
    template <typename T> GTX& operator<< (T n);

};
// GTX.cpp------------------------------------
GTX::~GTX() {
  delete[] buffer;
}
GTX::GTX()
  : W(1), H(1), buffer(new uint8_t[1]) {
  buffer[0] = ' ';
}
GTX::GTX(uint8_t w, uint8_t h)
  : W(w), H(h), buffer(new uint8_t[W * H]),
    posX(0), posY(0) {
  clear();
}
GTX::GTX(GTX&& other )
  : W(other.W), H(other.H), buffer(other.buffer),
    posX(0), posY(0) {
  other.buffer = nullptr;
}
GTX& GTX::operator=(GTX&& other) {
  W = other.W, H = other.H,
  buffer = other.buffer, other.buffer = nullptr,
  posX = 0, posY = 0;
  return *this;
}
//
void GTX::clear() {
  memset(buffer, 0x20, W * H);
  posX = posY = 0;
}
void GTX::setCursor(uint8_t x, uint8_t y) {
  posX = x; posY = y;
}
size_t GTX::write(uint8_t c) {
  if (c == '\n') {
    posX = 0;
    posY = (posY < H) ? (posY + 1) : H;
    return 1;
  }
  if (posX < W && posY < H) {
    buffer[posY * W + posX] = c;
    posX++;
  }
  return 1;
}
template<>
GTX& GTX::operator<< (xy n) {
  posX = n.x;
  posY = n.y;
  return *this;
}
template <typename T> GTX& GTX::operator<< ( T n) {
  this->print(n);
  return *this;
}
// Cl_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 LCD_W 20
#define LCD_H 4

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

class Cl_lcd2004_i2c { // класс канала передачи
  public:
    Cl_lcd2004_i2c(uint8_t a): adr(a) {}
    void init();                // иницирование
    void backlight(void);       // подсветка вкл
    void noBacklight(void);     // подсветка выкл
    void show(const GTX &obj); // отправить информацию из qGTX на экран
  private:
    /*внутрение функции*/
    inline void out(uint8_t value);
    inline void command(uint8_t value);
    void send(uint8_t value, uint8_t mode);
    void write4bits(uint8_t value);
    void expanderWrite(uint8_t _data);
    void pulseEnable(uint8_t _data);
  protected:
    uint8_t adr;
    uint8_t _backlightval;
    uint8_t _displayfunction;
    uint8_t _displaycontrol;
    uint8_t _displaymode;
};
// Cl_lcd2004_i2c.cpp------------------------------------
void Cl_lcd2004_i2c::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 Cl_lcd2004_i2c::backlight(void) {
  _backlightval = LCD_BACKLIGHT;
  expanderWrite(0);
}
void Cl_lcd2004_i2c::noBacklight(void) {
  _backlightval = LCD_NOBACKLIGHT;
  expanderWrite(0);
}
void Cl_lcd2004_i2c::show(const GTX &obj) {
  command(LCD_SETDDRAMADDR + 0x00);
  for (uint8_t i = 0; i < obj.W; i++ )out(obj.buffer[i]);
  command(LCD_SETDDRAMADDR + 0x40);
  for (uint8_t i = obj.W; i < 2 * obj.W; i++ )out(obj.buffer[i]);
  command(LCD_SETDDRAMADDR + 0x14);
  for (uint8_t i = 2 * obj.W; i < 3 * obj.W; i++ )out(obj.buffer[i]);
  command(LCD_SETDDRAMADDR + 0x54);
  for (uint8_t i = 3 * obj.W; i < 4 * obj.W; i++ )out(obj.buffer[i]);
}
void Cl_lcd2004_i2c::out(uint8_t value) {
  send(value, Rs);
}
void Cl_lcd2004_i2c::command(uint8_t value) {
  send(value, 0);
}
void Cl_lcd2004_i2c::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 Cl_lcd2004_i2c::write4bits(uint8_t value) {
  expanderWrite(value);
  pulseEnable(value);
}
void Cl_lcd2004_i2c::expanderWrite(uint8_t _data) {
  Wire.beginTransmission(adr);
  Wire.write((int)(_data | _backlightval));
  Wire.endTransmission();
}
void Cl_lcd2004_i2c::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
}
//GTX display(LCD_W, LCD_H);
Cl_lcd2004_i2c lcd(0x3F);//0x27
#endif

menu.h

/*menu.h*/
#ifndef MENU_H
#define MENU_H
#include "Cl_btn.h"
Cl_btn BtnS(/*пин*/2);  //кнопка селект
Cl_btn BtnU(/*пин*/3);  //кнопка верх
Cl_btn BtnD(/*пин*/4);  //кнопка вниз
//--------------- меню---------------------------------------------
#include "lcd2004_i2c.h"
void goPage(byte p); // перейти на страницу p
void menu_init();    // инициализировать меню
void menu_run();     // текущая работа
// обозначение страницы меню - что делает
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;
  GTX 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(0, 0) << F("info:");
      display << xy(0, 1) << F(" byte(") << index << F(")=") << (eeprom_B[index]); // вывод байтовой части
      display << xy(0, 2) << F("  int(") << index << F(")=") << (eeprom_I[index]); // вывод интовой части
      display << xy(0, 3) << F("float(") << index << F(")=") << (eeprom_F[index]); // вывод флоат части
      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(0, 0) << F("set index:") << index;
      break;
    case page3:
      BtnS.Do = [] {goPage(page4);};
      BtnU.Do = [] {
        if (eeprom_B[index] <= 200)eeprom_B[index] +=  10 ;
        goPage(page3);
      };
      BtnD.Do = [] {
        if (eeprom_B[index] >= 50)eeprom_B[index] -=  10;
        goPage(page3);
      };
      display << xy(0, 0) << F("set byte(") << index << F(")=") << (eeprom_B[index]); // вывод байтовой части
      break;
    case page4:
      BtnS.Do = [] {goPage(page5);};
      BtnU.Do = [] {
        if (eeprom_I[index] <= 2000)eeprom_I[index] += 100;
        goPage(page4);
      };
      BtnD.Do = [] {
        if (eeprom_I[index]  >= 500)eeprom_I[index] -= 100;
        goPage(page4);
      };
      display << xy(0, 0) << F("set int(") << index << ")=" << (eeprom_I[index]); // вывод интовой части
      break;
    case page5:
      BtnS.Do = [] {goPage(page6);};
      BtnU.Do = [] {
        if (eeprom_F[index] <= 20.30)eeprom_F[index] +=  1.01;
        goPage(page5);
      };
      BtnD.Do = [] {
        if (eeprom_F[index] >= 5.05) eeprom_F[index] -=  1.01;
        goPage(page5);
      };
      display << xy(0, 0) << F("set float(") << index << F(")=") << (eeprom_F[index]); // вывод флоат части
      break;
    case page6:
      BtnS.Do = [] {goPage(page1);};
      BtnU.Do = [] {
        if (setting_index < (max_setting_index - 1)) {
          setting_index++;
          eeprom_B[index] = pgm_B[setting_index];
          eeprom_I[index] = pgm_I[setting_index];
          eeprom_F[index] = pgm_F[setting_index];
        }
        goPage(page6);
      };
      BtnD.Do = [] {
        if (setting_index > 0) {
          setting_index--;
          eeprom_B[index] = pgm_B[setting_index];
          eeprom_I[index] = pgm_I[setting_index];
          eeprom_F[index] = pgm_F[setting_index];
        }
        goPage(page6);
      };
      display << xy(0, 0) << F("setting(") << setting_index  << F(")");
      display << xy(0, 1) << F(" byte(") << index << F(")=") << (eeprom_B[index]); // вывод байтовой части
      display << xy(0, 2) << F("  int(") << index << F(")=") << (eeprom_I[index]); // вывод интовой части
      display << xy(0, 3) << F("float(") << index << F(")=") << (eeprom_F[index]); // вывод флоат части
      break;
  }
  lcd.show(display);
}
void menu_init() {
  BtnS.init();
  BtnU.init();
  BtnD.init();
  lcd.init();
  goPage(page1);
}
void menu_run() {
  BtnS.run();
  BtnU.run();
  BtnD.run();
  switch (page) {
    case page0:
      break;
    default:
      if (millis() - past >= 10000)goPage(page0);// если долго не щелкают по кнопкам то погасить экран
      break;
  }
}
#endif