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

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

Arhat109-2 пишет:

Воспользуйтесь этим драйвером I2C, ....

Не ведись квон! Это провокация, там классов нет! И даже без шаблонов. Такой код недопустим, работать будет не стабильно, он не масштабируется и его поддержка невозможна. Ему здесь не место!

bwn
Offline
Зарегистрирован: 25.08.2014

Logik пишет:

Arhat109-2 пишет:

Воспользуйтесь этим драйвером I2C, ....

Не ведись квон! Это провокация, там классов нет! И даже без шаблонов. Такой код недопустим, работать будет не стабильно, он не масштабируется и его поддержка невозможна. Ему здесь не место!

И ты, Брут. А он тебя жалел, говорил, флудерасты выгнали, на форум не пущают.

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

DetSimen,точно херня с буфером на 30 вылезла.

/*cluster*/
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
#include <Wire.h>
#define SIZE_CLUSTER 32 // размер кластера
#define MAX_CLUSTER 128 // кол-во кластеров
class buffer_t {
  public:
    byte buffer[SIZE_CLUSTER];
    buffer_t();
    buffer_t(const __FlashStringHelper* txt);
};
buffer_t::buffer_t(void) {
  for (int i = 0; i < SIZE_CLUSTER; i++)buffer[i] = '!';
}
buffer_t::buffer_t(const __FlashStringHelper* txt) {
  int len = strlen_P((const char*)txt);
  if (len > SIZE_CLUSTER)len = SIZE_CLUSTER;
  for (int i = 0; i < SIZE_CLUSTER; i++)buffer[i] = pgm_read_byte_near((const char*)txt + i);
}
class e24c32 {
  protected:
    byte adr_i2c;
  public:
    byte buffer[SIZE_CLUSTER];
    byte cluster;
    void save_cluster();
    void load_cluster();
    void viev_byffer();
    void save_byffer(buffer_t obj);
    e24c32(byte adr): adr_i2c(adr) {}
    void init();
};
void e24c32::init() {
  Wire.begin();
}
void e24c32::save_cluster() {
  Wire.beginTransmission(adr_i2c);
  uint16_t address = cluster * SIZE_CLUSTER;
  Wire.write(address >> 8);
  Wire.write(address & 0xFF);
  for (byte i = 0; i < SIZE_CLUSTER; i++) Wire.write(buffer[i]);
  Wire.endTransmission();
  delay(10);
}
void e24c32::load_cluster() {
  Wire.beginTransmission(adr_i2c);
  uint16_t address = cluster * SIZE_CLUSTER;
  Wire.write(address >> 8);
  Wire.write(address & 0xFF);
  Wire.endTransmission();
  Wire.requestFrom(adr_i2c, (byte)SIZE_CLUSTER );
  for (byte i = 0; i < SIZE_CLUSTER; i++)
    if (Wire.available())
      buffer[i] = Wire.read();
}
void e24c32::viev_byffer() {
  for (int i = 0; i < SIZE_CLUSTER; i++) {
    char tmp = buffer[i];
    if (tmp == 0) break;
    Serial << tmp;
  }
  Serial << F("\n");
}
void e24c32::save_byffer(buffer_t obj = buffer_t()) {
  for (int i = 0; i < SIZE_CLUSTER; i++)buffer[i] = obj.buffer[i];
}
e24c32 cluster(/* адр i2c*/0x57);
void setup() {
  Serial.begin(9600);
  cluster.init();
  cluster.save_byffer();//<
  cluster.save_cluster();
  Serial << F("1\n");
  cluster.viev_byffer();
  cluster.save_byffer(F("qwertyuiop"));
  Serial << F("2\n");
  cluster.viev_byffer();
  cluster.load_cluster();
  Serial << F("3\n");
  cluster.viev_byffer();
}

void loop() {
}
/* Выведено
  1
  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  2
  qwertyuiop
  3
  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!Hб
*/

ПС: и да когда кому-нибудь захочется проверить этот код не забудьте подключить модуль

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

Logik пишет:
там классов нет! И даже без шаблонов.
А уж про лямбды я вообще молчу!

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

Примитив но просто не интересовался этим.

void setup() {
  Serial.begin(9600);
  String AAA(F("1234567890"));
  Serial.println(AAA.begin());
}
void loop() {

}

 

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

qwone пишет:

Примитив но просто не интересовался этим.

void setup() {
  Serial.begin(9600);
  String AAA(F("1234567890"));
  Serial.println(AAA.begin());
}
void loop() {

}

и так тоже отрабатывает
 

void setup() {
  Serial.begin(9600);
  String AAA(("1234567890"));
  Serial.println(AAA.begin());
}
void loop() {

 

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

ua6em пишет:
и так тоже отрабатывает
Но посмотрите на код #153  Мне пришлось городить class buffer_t , а мог бы обойтись String. Да и ваша версия отъедает ОЗУ.

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

qwone пишет:

Да и ваша версия отъедает ОЗУ.

А Ваша? Точно так же отъёдает, ни на байт не меньше. Только не статикой, а запросом памяти при работе конструктора.

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

/**/
#include <EEPROM.h>
void saveStringToEeprom(int adr, String obj);
void loadStringFromEeprom(int adr, String &obj);
void saveStringToEeprom(int adr, String obj) {
  unsigned int len = obj.length() + 1;
  for (unsigned int i = 0; i < len; i++) EEPROM.write(adr + i, obj[i]);
}
void loadStringFromEeprom(int adr, String &obj) {
  obj = "";
  uint8_t tmp;
  do {
    tmp = EEPROM.read(adr);
    adr++;
    obj += String((char)tmp);
  }
  while (tmp != 0);
}
//---------------------------------------------
const int adr1 =/*адресс eeprom*/10;
const int adr2 =/*адресс eeprom*/20;
//-----------------------------------------------------
void setup() {
  Serial.begin(9600);
  String aaa("qwerty");
  Serial.println(aaa);
  saveStringToEeprom(adr1, F("qwone"));
  saveStringToEeprom(adr2, F("Winnie the Pooh"));
  loadStringFromEeprom(adr1, aaa);
  Serial.println(aaa);
  loadStringFromEeprom(adr2, aaa);
  Serial.println(aaa);
}

void loop() {
}

 

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

Пух, ты лучше на выборы сходи. 

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

DetSimen, вы тоже сходите. Напишите на бумажке свой выбор и бростьте ближайшую урну.Результат будет такой же.

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

Пух, за что так с памятью-то? Совсем не жалко? Чё она тебе плохого сделала, что ты её так?

#include <MemoryExplorer.h>

/**/
#include <EEPROM.h>
void saveStringToEeprom(int adr, String obj);
void loadStringFromEeprom(int adr, String &obj);
void saveStringToEeprom(int adr, String obj) {
  unsigned int len = obj.length() + 1;
  for (unsigned int i = 0; i < len; i++) EEPROM.write(adr + i, obj[i]);
}
void loadStringFromEeprom(int adr, String &obj) {
  unsigned int len = 0;
  while (EEPROM.read(adr + len) != 0) {
    len++;
  }
  char *buf = new char[len + 1];
  for (unsigned int i = 0; i <= len; i++) buf[i] = EEPROM.read(adr + i);
  obj = String(buf);
  delete[] buf;
}
//---------------------------------------------
const int adr1 =/*адресс eeprom*/10;
const int adr2 =/*адресс eeprom*/20;
//-----------------------------------------------------
void setup() {
	Serial.begin(115200);
	memoryReport("At Start");
	String aaa("qwerty");
	Serial.println(aaa);
	saveStringToEeprom(adr1, F("qwone"));
	saveStringToEeprom(adr2, F("Winnie the Pooh"));
	loadStringFromEeprom(adr1, aaa);
	Serial.println(aaa);
	loadStringFromEeprom(adr2, aaa);
	Serial.println(aaa);
	memoryReport("At End");
}

void loop() {
}

вот чего печатает

---- Memory report: At Start
HEAP:@025D(605)-@0832(2098);
Unallocated from:@025D(605);
Stack pointer: @08B2(2226)
Free List: EMPTY
-----
qwerty
qwone
Winnie the Pooh
---- Memory report: At End
HEAP:@025D(605)-@0832(2098);
Unallocated from:@028A(650);
Stack pointer: @08B2(2226)
Free List:
	Block at:@025D(605); Size:25
-----

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

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
/**/
void saveStringToEeprom(int adr, String obj) {
  unsigned int len = obj.length() + 1;
  for (unsigned int i = 0; i < len; i++, adr++)
    eeprom_write_byte((uint8_t*)adr, obj[i]);
}
void loadStringFromEeprom(int adr, String &obj) {
  obj = "";
  uint8_t tmp;
  do {
    tmp = eeprom_read_byte((uint8_t*)adr);
    adr++;
    obj += String((char)tmp);
  }
  while (tmp != 0);
}
String StringFromEeprom(int adr) {
  String obj("");
  uint8_t tmp;
  do {
    tmp = eeprom_read_byte((uint8_t*)adr);
    adr++;
    obj += String((char)tmp);
  }
  while (tmp != 0);
  return obj;
}
//---------------------------------------------
const int adr1 =/*адресс eeprom*/10;
const int adr2 =/*адресс eeprom*/20;
//-----------------------------------------------------
void setup() {
  Serial.begin(9600);
  String aaa("qwerty");
  Serial.println(aaa);
  saveStringToEeprom(adr1, F("qwone"));
  saveStringToEeprom(adr2, F("Winnie the Pooh"));
  
  loadStringFromEeprom(adr1, aaa);
  Serial.println(aaa);
  
  String bbb(StringFromEeprom(adr2));
  Serial.println(bbb);
}

void loop() {
}

 

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

qwone пишет:

/**/
void saveStringToEeprom(int adr, String obj) {
  unsigned int len = obj.length() + 1;
  for (unsigned int i = 0; i < len; i++, adr++)
    eeprom_write_byte((uint8_t*)adr, obj[i]);
}
void loadStringFromEeprom(int adr, String &obj) {
  obj = "";
  uint8_t tmp;
  do {
    tmp = eeprom_read_byte((uint8_t*)adr);
    adr++;
    obj += String((char)tmp);
  }
  while (tmp != 0);
}
String StringFromEeprom(int adr) {
  String obj("");
  uint8_t tmp;
  do {
    tmp = eeprom_read_byte((uint8_t*)adr);
    adr++;
    obj += String((char)tmp);
  }
  while (tmp != 0);
  return obj;
}
//---------------------------------------------
const int adr1 =/*адресс eeprom*/10;
const int adr2 =/*адресс eeprom*/20;
//-----------------------------------------------------
void setup() {
  Serial.begin(9600);
  String aaa("qwerty");
  Serial.println(aaa);
  saveStringToEeprom(adr1, F("qwone"));
  saveStringToEeprom(adr2, F("Winnie the Pooh"));
  
  loadStringFromEeprom(adr1, aaa);
  Serial.println(aaa);
  
  String bbb(StringFromEeprom(adr2));
  Serial.println(bbb);
}

void loop() {
}

 

Строка номер 2 - надо по ссылке передавать параметр типа String, чтобы не было копирования, со всеми вытекающими, типа жёсткой работы с памятью.

Писать/читаться строки в EEPROM лучше с префиксом - сколько байт сохранено. У String есть чудесный метод reserve, который избавит тебя от дичайшей переаллокации каждый раз, когда ты плюсуешь к строке один байт. Представь, что у тебя сохранена строка в 50 байт - в твоём случае это целых 50 выделений/освобождений памяти, зачем ты так не любишь микроконтроллеры?

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

DIYMan пишет:

... У String есть чудесный метод ...

Вот если меня спросить, что мне более всего нравится в стрингах, то я отвечу, что в "стрингах" мне более всего нравятся барышни... лет 25ти. ;))))

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

wdrakula пишет:
барышни... лет 25ти. ;))))
Я бы сказал ОТ 25. До 25 у них много всякой романики в башке, а потом они на эти вещи ширше смотрят :)

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

Ответ на #163.

Квон, я понимаю, что сказать нам - дуракам хоть слово, с высоты твое величия - западло. А потому я не знаю, зачем ты выложил этот вариант. Но, если в смысле, что в нём нету фрагемнтации памяти, то мимо - никуда она не делась, смотри

#include <MemoryExplorer.h>

/**/
void saveStringToEeprom(int adr, String obj) {
  unsigned int len = obj.length() + 1;
  for (unsigned int i = 0; i < len; i++, adr++)
    eeprom_write_byte((uint8_t*)adr, obj[i]);
}
void loadStringFromEeprom(int adr, String &obj) {
  obj = "";
  uint8_t tmp;
  do {
    tmp = eeprom_read_byte((uint8_t*)adr);
    adr++;
    obj += String((char)tmp);
  }
  while (tmp != 0);
}
String StringFromEeprom(int adr) {
  String obj("");
  uint8_t tmp;
  do {
    tmp = eeprom_read_byte((uint8_t*)adr);
    adr++;
    obj += String((char)tmp);
  }
  while (tmp != 0);
  return obj;
}
//---------------------------------------------
const int adr1 =/*адресс eeprom*/10;
const int adr2 =/*адресс eeprom*/20;
//-----------------------------------------------------
void setup() {
  Serial.begin(115200);
  memoryReport("At Start");
  String aaa("qwerty");
  Serial.println(aaa);
  saveStringToEeprom(adr1, F("qwone"));
  saveStringToEeprom(adr2, F("Winnie the Pooh"));

  loadStringFromEeprom(adr1, aaa);
  Serial.println(aaa);

  String bbb(StringFromEeprom(adr2));
  Serial.println(bbb);
  memoryReport("Freed p1");
}

void loop() {
}

Печатаить

---- Memory report: At Start
HEAP:@025F(607)-@082A(2090);
Unallocated from:@025F(607);
Stack pointer: @08AA(2218)
Free List: EMPTY
-----
qwerty
qwone
Winnie the Pooh
---- Memory report: Freed p1
HEAP:@025F(607)-@082A(2090);
Unallocated from:@0282(642);
Stack pointer: @08AA(2218)
Free List:
	Block at:@0268(616); Size:6
-----

 

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

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

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

 

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Ну с точками и тире каждый может. А ты с буквами покажи :)

А почему для статусов какой нибудь enum, ну или #define не используешь ? Какая у тебя на сей счет религия ?

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

brokly пишет:

Ну с точками т тире каждый может. А ты с буквами покажи :)

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

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Не, не экономно... Не красиво получится :(

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

Квон - какой такой душ? 

st_dush

Тире - это dash.

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

с точками, тире и генерацией частоты на пине самый простой скетч у Максима Клименко, занимает менее 1600 байт, озу 445 байт )))

// Arduino simply CW beacon
// (c) 2012 Max Klimenko
// emaster [at] mail.ru
// <a href="http://max-ter.livejournal.com/571.html" title="http://max-ter.livejournal.com/571.html" rel="nofollow">http://max-ter.livejournal.com/571.html</a>

// It sends beacon at 8 MHz from pin D9

// Beacon message
const char message[] = "VVV CQ CQ CQ DX DE BEACON BAND 40M 8000KHZ";

// Period of single point (ms)
const int point_time = 80;

// Carrier frequency divider.
// Carrier freq. (MHz) = 16 / (2 * (1 + freq_div))
const unsigned char freq_div = 1;

//////////////////////////////////////////////////////////////////
struct s_abc
{
        char letter;
        char sign[7];
};

const s_abc abc[] = {
        'A',".-", 'B',"-...", 'W',".--", 'G',"--.", 'D',"-..", 
        'E',".", 'V',"...-", 'Z',"--..", 'I',"..",
        'J',".---", 'K',"-.-", 'L',".-..", 'M',"--", 'N',"-.", 
        'O',"---", 'P',".--.", 'R',".-.", 'S',"...",
        'T',"-", 'U',"..-", 'F',"..-.", 'H',"....", 'C',"-.-.", 
        'Q',"--.-", 'Y',"-.--", 'X',"-..-", '1',".----",
        '2',"..---", '3',"...--", '4',"....-", '5',".....", 
        '6',"-....", '7',"--...", '8',"---..", '9',"----.",
        '0',"-----", '.',"......", ',',".-.-.-", ':',"---...", 
        ';',"-.-.-.", '(',"-.--.-", '`',".----.",
        '"',".-..-.", '-',"-....-", '/',"-..-.", '?',"..--..", 
        '!',"--..--", '@',".--.-.", '\\',"..-.-" };

unsigned char abc_size = sizeof(abc) / sizeof(abc[0]);

void setup()
{
  PORTB = 0;
  DDRB |= 1<<1;
  
  OCR1A = freq_div;
  TCCR1A = 0x48;
  TCCR1B = 0x09;
  
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH);   // set the LED on
}

void send_letter(char l)
{
  if (l == ' ')
  {
    delay(point_time * 7);
    return;
  }
  
  unsigned char idx = 255;
  for (unsigned char i = 0; i < abc_size; i++)
    if (abc[i].letter == l)
    {
      idx = i;
      break;
    }
    
  if (idx == 255) return;
  
  const char *s = abc[idx].sign;
  
  for (unsigned char c = 0; s[c] != 0; c++)
  {
    char q = s[c];
    
    DDRB |= 1<<1;
    digitalWrite(13, HIGH);   // set the LED on
    
    if (q == '.') delay(point_time);
    else delay(point_time * 3);
    
    DDRB &= ~(1<<1);
    digitalWrite(13, LOW);   // set the LED off
    
    delay(point_time);
  }

  delay(point_time * 2);
}

void loop()
{
  for (int n = 0; message[n] != 0; n++)
    send_letter(message[n]);
  
  delay(2000);
}

 

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

ua6em пишет:

с точками, тире и генерацией частоты на пине самый простой скетч у Максима Клименко, занимает менее 1600 байт, озу 445 байт )))

Расход ОЗУ в приведённом скетче можно сократить раз в 10 ;) Переместив кое-чего во флеш ;)

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
const char CODE[] = {
  B0000000, B01110011, B0000000, B0000000, B0000000, B0000000, B0000000, B0000000,// !"# $%&'
  B0000000, B0000000, B0000000, B0000000, B01010101, B01010101, B0000000, B0110010,//()*+ -,./

  B0111111, B0101111, B0100111, B0100011, B0100001, B0100000, B0110000, B0111000,//0123 4567
  B0111100, B0111110, B0000000, B0000000, B0000000, B0000000, B0000000, B01001100,//89:; <=>?

  B01011010, B0101, B011000, B011010, B01100, B010, B010010, B01110,//@ABC DEFG
  B01000, B0100, B010111, B01101, B010100, B0111, B0110, B01111,//HIJK LMNO

  B010110, B011101, B01010, B01000, B011, B01001, B010001, B01011,//PQRS TUVW
  B011001, B011011, B011100, B0000000, B0000000, B0000000, B0000000, B0000000,//XYZ[ \]^_

  B0000000, B0101, B011000, B011010, B01100, B010, B010010, B01110,//`abc defg
  B01000, B0100, B010111, B01101, B010100, B0111, B0110, B01111,//hijk lmno

  B010110, B011101, B01010, B01000, B011, B01001, B010001, B01011,//pgrs tuvw
  B011001, B011011, B011100, B0000000, B0000000, B0000000, B0000000, B0000000 //xyz{ |}~
};
String msg(".,/?!@0123456789 abcdef");
void setup() {
  Serial.begin(9600);
  for (unsigned int i = 0; i < msg.length(); i++) {
    String aaa;
    byte tmp = CODE[msg[i] - ' '];
    if (tmp == 0) aaa = "  ";
    else {
      bool f = 0;
      aaa = "";
      for (int i = 0; i < 8; ++i) {
        if (f) {
          if (tmp & 0x80) aaa += "-";
          else aaa += ".";
        }
        else if (tmp & 0x80) f = 1;
        tmp = tmp << 1;
      }
    }
    Serial.println();
    Serial.print(msg[i]);
    Serial.print("   ");
    Serial.print(aaa);
  }
}

void loop() {

}

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

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

DIYMan пишет:

ua6em пишет:

с точками, тире и генерацией частоты на пине самый простой скетч у Максима Клименко, занимает менее 1600 байт, озу 445 байт )))

Расход ОЗУ в приведённом скетче можно сократить раз в 10 ;) Переместив кое-чего во флеш ;)

со строкой понятно, а массив как?

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

ua6em пишет:
со строкой понятно, а массив как?

Так же само. #250

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

ua6em пишет:

DIYMan пишет:

ua6em пишет:

с точками, тире и генерацией частоты на пине самый простой скетч у Максима Клименко, занимает менее 1600 байт, озу 445 байт )))

Расход ОЗУ в приведённом скетче можно сократить раз в 10 ;) Переместив кое-чего во флеш ;)

со строкой понятно, а массив как?

А чем массив отличается от строки таким, что его нельзя во флеш поместить? Правильно - ничем.

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

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

Я сделал так (строка в ROM храница вместе с нулем) 

// читает строку из адреса ASrcAddr в буфер AStrBuf вместе с завершающим нулем
// отдает длину в байтах прочитанной строки (вместе с нулём)
// если вызвать с NULL вместо адреса буфера куда читать, можно невозбранно поиметь длину строки
// 
// Пример:
//
// size_t len = EEPROM.ReadString(0x100, NULL);	сначала узнаем, скока байт надо (вместе с нулём)
// char *str = new char[len];				потом выделим память
// EEPROM.ReadString(0x100, str);				потом прочитаем строку
// Serial << str << '\n';					чонить с ней сделаем
// delete[] str;						и удалим, када станет не надо

size_t ReadString(addr_t ASrcAddr, char *AStrBuf) {
	char c;
	size_t len = 0;
	do {
		c = readByte(ASrcAddr++);
		if (AStrBuf != NULL) AStrBuf[len] = c;
	} while (len++, (c > '\0'));

	return len;
}

 

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

DIYMan пишет:

ua6em пишет:

DIYMan пишет:

ua6em пишет:

с точками, тире и генерацией частоты на пине самый простой скетч у Максима Клименко, занимает менее 1600 байт, озу 445 байт )))

Расход ОЗУ в приведённом скетче можно сократить раз в 10 ;) Переместив кое-чего во флеш ;)

со строкой понятно, а массив как?

А чем массив отличается от строки таким, что его нельзя во флеш поместить? Правильно - ничем.

у меня не получилось, компилируется но не работает )))

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
/**/
void saveToEeprom(int adr, String obj) {
  unsigned int len = obj.length() + 1;
  for (unsigned int i = 0; i < len; i++, adr++)
    eeprom_write_byte((uint8_t*)adr, obj[i]);
}
String loadFromEeprom(int adr) {
  unsigned int a = adr;
  for (; eeprom_read_byte((uint8_t*)a) != 0; a++);
  String obj;
  obj.reserve(a - adr + 1);
  uint8_t tmp;
  do {
    tmp = eeprom_read_byte((uint8_t*)adr++);
    obj += String((char)tmp);
  }
  while (tmp != 0);
  return obj;
}
//---------------------------------------------
const int adr1 =/*адресс eeprom*/10;
const int adr2 =/*адресс eeprom*/20;
//-----------------------------------------------------
void setup() {
  Serial.begin(9600);
  String aaa("qwerty");
  Serial.println(aaa);
  saveToEeprom(adr1, F("qwone"));
  saveToEeprom(adr2, F("Winnie the Pooh"));

  Serial.println(loadFromEeprom(adr1));
  Serial.println(loadFromEeprom(adr2));
}

void loop() {
}

 

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

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

По итогу что это всё даёт:

1. Есть заголовок - проверка записи на валидность;

2. Есть длина данных - не надо её высчитывать мееедленным чтением из EEPROM.

На примере строки в 1 байт длиной: твой вариант (с хранением нулевого завершающего байта) - даст чтений 2 + 2 = 4. Мой вариант, с заголовком из двух байт, байтом длины и данными, даст чтений 2 + 1 + 1 = 4. При этом мой вариант бьёт твой, начиная с длины строки > 1.

Напишешь ещё вариант? Думаю, пригодится ;) 

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

DIYMan пишет:

мой вариант бьёт твой, начиная с длины строки > 1.

Пожалуй, я с тобой соглашуся.  Хоть чтение и не так тормозит, как запись, но сётаки переделаю. 

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

Ой квон, безнадежен ты. Абсолютно безнадежен.

Твое:

void saveToEeprom(int adr, String obj) {
  unsigned int len = obj.length() + 1;
  for (unsigned int i = 0; i < len; i++, adr++)
    eeprom_write_byte((uint8_t*)adr, obj[i]);
}

String loadFromEeprom(int adr) {
  unsigned int a = adr;
  for (; eeprom_read_byte((uint8_t*)a) != 0; a++);
  String obj;
  obj.reserve(a - adr + 1);
  uint8_t tmp;
  do {
    tmp = eeprom_read_byte((uint8_t*)adr++);
    obj += String((char)tmp);
  }
  while (tmp != 0);
  return obj;
}

const int adr1 =/*адресс eeprom*/10;

void setup() {
  Serial.begin(9600);
  saveToEeprom(adr1, F("qwone"));
  Serial.println(loadFromEeprom(adr1));
}
void loop() {
}

Скетч использует 3200 байт (10%) памяти устройства. Всего доступно 30720 байт.

Правильное:

void saveToEeprom(int adr, const char * p) {
  uint8_t a;
  do
  {
    a= pgm_read_byte(p++);
    eeprom_write_byte((uint8_t*)adr++,a);
  } while (a);

}

String loadFromEeprom(int adr) {
  unsigned int a = adr;
  for (; eeprom_read_byte((uint8_t*)a) != 0; a++);
  String obj;
  obj.reserve(a - adr + 1);
  uint8_t tmp;
  do {
    tmp = eeprom_read_byte((uint8_t*)adr++);
    obj += String((char)tmp);
  }
  while (tmp != 0);
  return obj;
}

const int adr1 =/*адресс eeprom*/10;
const char Sub[] PROGMEM ="pustozvon";

void setup() {
  Serial.begin(9600);
  saveToEeprom(adr1, Sub);
  Serial.println(loadFromEeprom(adr1));
}
void loop() {
}
Скетч использует 3088 байт (10%) памяти устройства. Всего доступно 30720 байт.
Глобальные переменные используют 198 байт 
 
Виш! 112 байт на ровном месте! И притом что "pustozvon" еще и длинней чем "qwone" ;)
Как избавится от стринга при переменной длине строки в loadFromEeprom, а заодно от использывания кучи и следовательно фрагментации - думай квон, думай ;) Меня ж тошнить начинает когда я вижу два прохода в loadFromEeprom и return obj.
 
 
DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Мда.  В какую битву титанов я влес...  А ведь даже писАть не умею. :) 

Но я, кста, не уверен, что он тут хотел из EEPROMa в EEPROM писать

void saveToEeprom(int adr, const char * p) {
  uint8_t a;
  do
  {
    a= pgm_read_byte(p++);
    eeprom_write_byte((uint8_t*)adr++,a);
  } while (a);

}

мне кажеца, *p это указатель на ОЗУ. 

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

кажется - проверь! Не сцо! В боях крепчают! Оба кода рабочие. А PROGMEM и EEPROM - точно разные штуковины.

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

АААААА   там же из флэша в EEPROM, точно.  Звиняйте. 

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

Logik пишет:

кажется - проверь! Не сцо! В боях крепчают! Оба кода рабочие. А PROGMEM и EEPROM - точно разные штуковины.

в WAVGAT это одно и тоже вроде как, только адреса разные

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

Да. В WAVGAT по другому. Но не суть важно, важно другое - указатель (или адрес) всегда эффективней будет.

Еще один забавный пример, давно хотел глянуть на эти цифры.

void setup() {
  int t;
  // put your setup code here, to run once:
  Serial.begin(9600);

  for(char c='1';c<'z';c++)
  {
    t=micros();
    Serial.print(c);
    Serial.print(':');
    Serial.println((int)micros()-t);
  }
}

void loop() {
  // put your main code here, to run repeatedly:
}

Все просто, меряем время вывода в сириал. Имеем

1:12
2:16
3:16
4:12
5:12
6:16
7:16
8:12
9:16
::12
;:12
<:1728
=:2076
>:2076
?:2076
@:2076
 
На 2 порядка!!!
Все просто, пока в буфер помещается - быстро. Потом сильно медлено. 
На первый взгляд это к примерам выше вобще не относится. Но только на первый. Т.к. на второй позволяет понять есть ли разница между выводом всей строки сразу и выводом её по символьно. Ну и когда как стоит делать. Кстати 2076мксек - время на реальную, физическую отправку 2 байт на скорости 9600бод.
ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Logik пишет:

 Кстати 2076мксек - время на реальную, физическую отправку 2 байт на скорости 9600бод.

так буфер у сериала вроде как должен быть 16 байт, куда остальные делись?

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

Я слышал что 64байта по умолчанию. И по примеру тоже похоже. Первые 11 быстро прошли. Имеют строк  по 6 байт в строке. Итого 66.

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

ua6em пишет:

Logik пишет:

 Кстати 2076мксек - время на реальную, физическую отправку 2 байт на скорости 9600бод.

так буфер у сериала вроде как должен быть 16 байт, куда остальные делись?

изучи нимательно 

#if ((RAMEND - RAMSTART) < 1023)
#define SERIAL_TX_BUFFER_SIZE 16
#else
#define SERIAL_TX_BUFFER_SIZE 64
#endif

и доложи, у какой ATMeg-и Serial буфер 16 байт.

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

DetSimen пишет:

ua6em пишет:

Logik пишет:

 Кстати 2076мксек - время на реальную, физическую отправку 2 байт на скорости 9600бод.

так буфер у сериала вроде как должен быть 16 байт, куда остальные делись?

изучи нимательно 

#if ((RAMEND - RAMSTART) < 1023)
#define SERIAL_TX_BUFFER_SIZE 16
#else
#define SERIAL_TX_BUFFER_SIZE 64
#endif

и доложи, у какой ATMeg-и Serial буфер 16 байт.

это тлетворное влияние PC-XT

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

Выдернутый отсюда код как писать большими буквами в lcd2004 https://github.com/voltnik/SmokeClock/blob/master/SmokeClock/SmokeClock.ino

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3F, 20, 4);
byte custom[8][8] = {   // символы большого шрифта
  { B11111, B11111, B11111, B00000, B00000, B00000, B00000, B00000 },
  { B11100, B11110, B11111, B11111, B11111, B11111, B11111, B11111 },
  { B11111, B11111, B11111, B11111, B11111, B11111, B01111, B00111 },
  { B00000, B00000, B00000, B00000, B00000, B11111, B11111, B11111 },
  { B11111, B11111, B11111, B11111, B11111, B11111, B11110, B11100 },
  { B11111, B11111, B11111, B00000, B00000, B00000, B11111, B11111 },
  { B11111, B00000, B00000, B00000, B00000, B11111, B11111, B11111 },
  { B00111, B01111, B11111, B11111, B11111, B11111, B11111, B11111 }
};
const char *bigChars[][2] = {   // символы из новых букв
  {"\024\024\024", "\024\024\024"}, // Space
  {"\377", "\007"}, // !
  {"\005\005", "\024\024"}, // "
  {"\004\377\004\377\004", "\001\377\001\377\001"}, // #
  {"\010\377\006", "\007\377\005"}, // $
  {"\001\024\004\001", "\004\001\024\004"}, // %
  {"\010\006\002\024", "\003\007\002\004"}, // &
  {"\005", "\024"}, // '
  {"\010\001", "\003\004"}, // (
  {"\001\002", "\004\005"}, // )
  {"\001\004\004\001", "\004\001\001\004"}, // *
  {"\004\377\004", "\001\377\001"}, // +
  {"\024", "\005"}, // ,
  {"\004\004\004", "\024\024\024"}, // -
  {"\024", "\004"}, // .
  {"\024\024\004\001", "\004\001\024\024"}, // /
  {"\010\001\002", "\003\004\005"}, // 0
  {"\001\002\024", "\024\377\024"}, // 1
  {"\006\006\002", "\003\007\007"}, // 2
  {"\006\006\002", "\007\007\005"}, // 3
  {"\003\004\002", "\024\024\377"}, // 4
  {"\377\006\006", "\007\007\005"}, // 5
  {"\010\006\006", "\003\007\005"}, // 6
  {"\001\001\002", "\024\010\024"}, // 7
  {"\010\006\002", "\003\007\005"}, // 8
  {"\010\006\002", "\024\024\377"}, // 9
  {"\004", "\001"}, // :
  {"\004", "\005"}, // ;
  {"\024\004\001", "\001\001\004"}, // <
  {"\004\004\004", "\001\001\001"}, // =
  {"\001\004\024", "\004\001\001"}, // >
  {"\001\006\002", "\024\007\024"}, // ?
  {"\010\006\002", "\003\004\004"}, // @
  {"\010\006\002", "\377\024\377"}, // A
  {"\377\006\005", "\377\007\002"}, // B
  {"\010\001\001", "\003\004\004"}, // C
  {"\377\001\002", "\377\004\005"}, // D
  {"\377\006\006", "\377\007\007"}, // E
  {"\377\006\006", "\377\024\024"}, // F
  {"\010\001\001", "\003\004\002"}, // G
  {"\377\004\377", "\377\024\377"}, // H
  {"\001\377\001", "\004\377\004"}, // I
  {"\024\024\377", "\004\004\005"}, // J
  {"\377\004\005", "\377\024\002"}, // K
  {"\377\024\024", "\377\004\004"}, // L
  {"\010\003\005\002", "\377\024\024\377"}, // M
  {"\010\002\024\377", "\377\024\003\005"}, // N
  {"\010\001\002", "\003\004\005"}, // 0/0
  {"\377\006\002", "\377\024\024"}, // P
  {"\010\001\002\024", "\003\004\377\004"}, // Q
  {"\377\006\002", "\377\024\002"}, // R
  {"\010\006\006", "\007\007\005"}, // S
  {"\001\377\001", "\024\377\024"}, // T
  {"\377\024\377", "\003\004\005"}, // U
  {"\003\024\024\005", "\024\002\010\024"}, // V
  {"\377\024\024\377", "\003\010\002\005"}, // W
  {"\003\004\005", "\010\024\002"}, // X
  {"\003\004\005", "\024\377\024"}, // Y
  {"\001\006\005", "\010\007\004"}, // Z
  {"\377\001", "\377\004"}, // [
  {"\001\004\024\024", "\024\024\001\004"}, // Backslash
  {"\001\377", "\004\377"}, // ]
  {"\010\002", "\024\024"}, // ^
  {"\024\024\024", "\004\004\004"}, // _
};
int writeBigChar(char ch, int x, int y) {
  const char *(*blocks)[2] = NULL; // Pointer to an array of two strings (character pointers)
  if (ch < ' ' || ch > '_') // If outside our table range, do nothing
    return 0;
  blocks = &bigChars[ch - ' ']; // Look up the definition
  for (int half = 0; half <= 1; half++) {
    int t = x; // Write out top or bottom string, byte at a time
    for (const char *cp = (*blocks)[half]; *cp; cp++) {
      lcd.setCursor(t, y + half);
      lcd.write(*cp);
      t = (t + 1) % 40; // Circular scroll buffer of 40 characters, loop back at 40
    }
    lcd.setCursor(t, y + half);
    lcd.write(' '); // Make space between letters, in case overwriting
  }
  return strlen((*blocks)[0]); // Return char width
}
void writeBigString(const char *str, int x, int y) { // пишем большие буквы
  char c;
  while ((c = *str++))
    x += writeBigChar(c, x, y) + 1;
}

//-----------------------------------------------
void setup() {
  lcd.init();
  lcd.backlight();
  lcd.clear();
  for (int i = 0; i < 8; i++) lcd.createChar(i + 1, custom[i]);
  writeBigString("GAS", 0, 0);
  writeBigString("1.2", 0, 2);
  lcd.setCursor(10, 2);
  lcd.print("SmokeClock");
  lcd.setCursor(13, 3);
  lcd.print("voltNik");

}
void loop() {
}

 

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

Моя библиотека для работы с 2004 

/**/
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
//------дисплей lcd2004_i2c-----------------------------
// даташит <"https://www.sparkfun.com/datasheets/LCD/ADM1602K-NSW-FBS-3.3v.pdf">https://www.sparkfun.com/datasheets/LCD/HD44780.pdf
// на русском <"http://www.melt.aha.ru/pdf/mt-16s2h.pdf">
#include <Wire.h>
// команды
#define LCD_CLEARDISPLAY 0x01
#define LCD_RETURNHOME 0x02
#define LCD_ENTRYMODESET 0x04
#define LCD_DISPLAYCONTROL 0x08
#define LCD_CURSORSHIFT 0x10
#define LCD_FUNCTIONSET 0x20
#define LCD_SETCGRAMADDR 0x40
#define LCD_SETDDRAMADDR 0x80
// флаги для режима ввода дисплея
#define LCD_ENTRYRIGHT 0x00
#define LCD_ENTRYLEFT 0x02
#define LCD_ENTRYSHIFTINCREMENT 0x01
#define LCD_ENTRYSHIFTDECREMENT 0x00
// флаги для управления включением / выключением дисплея
#define LCD_DISPLAYON 0x04
#define LCD_DISPLAYOFF 0x00
#define LCD_CURSORON 0x02
#define LCD_CURSOROFF 0x00
#define LCD_BLINKON 0x01
#define LCD_BLINKOFF 0x00
// флаги для отображения / сдвига курсора
#define LCD_DISPLAYMOVE 0x08
#define LCD_CURSORMOVE 0x00
#define LCD_MOVERIGHT 0x04
#define LCD_MOVELEFT 0x00
// флаги для набора функций
#define LCD_8BITMODE 0x10
#define LCD_4BITMODE 0x00
#define LCD_2LINE 0x08
#define LCD_1LINE 0x00
#define LCD_5x10DOTS 0x04
#define LCD_5x8DOTS 0x00
// флаги для управления подсветкой
#define LCD_BACKLIGHT 0x08
#define LCD_NOBACKLIGHT 0x00

#define En B00000100  // Бит разрешения
#define Rw B00000010  // Чтение / запись бит
#define Rs B00000001  // Бит выбора регистра
class Cl_lcd1602_i2c : public Print {
  protected:
    uint8_t adr, posX, posY;
    uint8_t _backlightval;
    uint8_t _displayfunction;
    uint8_t _displaycontrol;
    uint8_t _displaymode;
    byte buffer[80];
  public:
    Cl_lcd1602_i2c(uint8_t a): adr(a) {}
    void init() {
      Wire.begin();
      write4bits(0x03 << 4);
      delayMicroseconds(4500); // wait min 4.1ms
      write4bits(0x03 << 4);
      delayMicroseconds(4500); // wait min 4.1ms
      write4bits(0x03 << 4);
      delayMicroseconds(150);
      write4bits(0x02 << 4);
      delay(50);
      _backlightval = LCD_NOBACKLIGHT;
      expanderWrite(_backlightval); // сбросить расширение и выключить подсветку (бит 8 = 1)
      // режим работы дисплея 4-х битный интерфейс ,две строки,5х8 точек
      _displayfunction = LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS;
      command(LCD_FUNCTIONSET | _displayfunction);
      // режим контроля дисплей вкл, курсор не мигает,дисплей не мигает
      _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
      command(LCD_DISPLAYCONTROL | _displaycontrol);
      // режим ввода текста в память-начинать слева с движением в право
      _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
      command(LCD_ENTRYMODESET | _displaymode);
      clear();
    }
    // подсветку вкл/выкл
    void backlight(void) {
      _backlightval = LCD_BACKLIGHT;
      expanderWrite(0);
    }
    void noBacklight(void) {
      _backlightval = LCD_NOBACKLIGHT;
      expanderWrite(0);
    }
    // очистить буфер
    void clear() {
      for (byte i = 0; i < 80; i++ )buffer[i] = 0x20;
      posX = 0; posY = 0;
    }
    // отправить информацию из буфера на экран
    void show() {
      line(0);
      for (byte i = 0; i < 20; i++ )out(buffer[i]);
      line(1);
      for (byte i = 20; i < 40; i++ )out(buffer[i]);
      line(2);
      for (byte i = 40; i < 60; i++ )out(buffer[i]);
      line(3);
      for (byte i = 60; i < 80; i++ )out(buffer[i]);
    }
    void setCursor(byte x, byte y) {
      if (x > 20) x = 20;
      else posX = x;
      if (y > 4) x = 4;
      else posY = y;
    }
  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 size_t write(uint8_t value) {
      if (posX < 20 && posY < 4) {
        buffer[posY * 20 + posX] = value;
        posX++;
      }
      return 1;
    }
    /*команды низкоуровневого управления*/
    inline void command(uint8_t value) {
      send(value, 0);
    }
    void send(uint8_t value, uint8_t mode) {
      uint8_t highnib = value & 0xf0;
      write4bits((highnib) | mode);
      uint8_t lownib = (value << 4) & 0xf0;
      write4bits((lownib) | mode);
    }
    void write4bits(uint8_t value) {
      expanderWrite(value);
      pulseEnable(value);
    }
    void expanderWrite(uint8_t _data) {
      Wire.beginTransmission(adr);
      Wire.write((int)(_data) | _backlightval);
      Wire.endTransmission();
    }
    void pulseEnable(uint8_t _data) {
      expanderWrite(_data | En);  // En high
      delayMicroseconds(1);   // enable pulse must be >450ns
      expanderWrite(_data & ~En); // En low
      delayMicroseconds(50);    // commands need > 37us to settle
    }
};
Cl_lcd1602_i2c lcd(0x3F);//0x27
//--------------------------------------------------
void setup() {
  lcd.init();
  lcd.backlight();
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd << F("12345678901234567890");
  lcd.setCursor(0, 1);
  lcd << F("12345678901234567890");
  lcd.setCursor(0, 2);
  lcd << F("12345678901234567890");
  lcd.setCursor(0, 3);
  lcd << F("12345678901234567890");
  lcd.show();
}
void loop() {
}
/**/

 

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

/**/
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
//------дисплей lcd2004_i2c-----------------------------

#include <Wire.h>
// команды
#define LCD_CLEARDISPLAY 0x01
#define LCD_RETURNHOME 0x02
#define LCD_ENTRYMODESET 0x04
#define LCD_DISPLAYCONTROL 0x08
#define LCD_CURSORSHIFT 0x10
#define LCD_FUNCTIONSET 0x20
#define LCD_SETCGRAMADDR 0x40
#define LCD_SETDDRAMADDR 0x80
// флаги для режима ввода дисплея
#define LCD_ENTRYRIGHT 0x00
#define LCD_ENTRYLEFT 0x02
#define LCD_ENTRYSHIFTINCREMENT 0x01
#define LCD_ENTRYSHIFTDECREMENT 0x00
// флаги для управления включением / выключением дисплея
#define LCD_DISPLAYON 0x04
#define LCD_DISPLAYOFF 0x00
#define LCD_CURSORON 0x02
#define LCD_CURSOROFF 0x00
#define LCD_BLINKON 0x01
#define LCD_BLINKOFF 0x00
// флаги для отображения / сдвига курсора
#define LCD_DISPLAYMOVE 0x08
#define LCD_CURSORMOVE 0x00
#define LCD_MOVERIGHT 0x04
#define LCD_MOVELEFT 0x00
// флаги для набора функций
#define LCD_8BITMODE 0x10
#define LCD_4BITMODE 0x00
#define LCD_2LINE 0x08
#define LCD_1LINE 0x00
#define LCD_5x10DOTS 0x04
#define LCD_5x8DOTS 0x00
// флаги для управления подсветкой
#define LCD_BACKLIGHT 0x08
#define LCD_NOBACKLIGHT 0x00

#define En B00000100  // Бит разрешения
#define Rw B00000010  // Чтение / запись бит
#define Rs B00000001  // Бит выбора регистра
class Cl_lcd2004_i2c : public Print {
  protected:
    uint8_t adr, posX, posY;
    uint8_t _backlightval;
    uint8_t _displayfunction;
    uint8_t _displaycontrol;
    uint8_t _displaymode;
    byte buffer[80];
  public:
    Cl_lcd2004_i2c(uint8_t a): adr(a) {}
    void init() {
      Wire.begin();
      write4bits(0x03 << 4);
      delayMicroseconds(4500); // wait min 4.1ms
      write4bits(0x03 << 4);
      delayMicroseconds(4500); // wait min 4.1ms
      write4bits(0x03 << 4);
      delayMicroseconds(150);
      write4bits(0x02 << 4);
      delay(50);
      _backlightval = LCD_NOBACKLIGHT;
      expanderWrite(_backlightval); // сбросить расширение и выключить подсветку (бит 8 = 1)
      // режим работы дисплея 4-х битный интерфейс ,две строки,5х8 точек
      _displayfunction = LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS;
      command(LCD_FUNCTIONSET | _displayfunction);
      // режим контроля дисплей вкл, курсор не мигает,дисплей не мигает
      _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
      command(LCD_DISPLAYCONTROL | _displaycontrol);
      // режим ввода текста в память-начинать слева с движением в право
      _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
      command(LCD_ENTRYMODESET | _displaymode);
      clear();
    }
    // подсветку вкл/выкл
    void backlight(void) {
      _backlightval = LCD_BACKLIGHT;
      expanderWrite(0);
    }
    void noBacklight(void) {
      _backlightval = LCD_NOBACKLIGHT;
      expanderWrite(0);
    }
    // очистить буфер
    void clear() {
      for (byte i = 0; i < 80; i++ )buffer[i] = 0x20;
      posX = 0; posY = 0;
    }
    // отправить информацию из буфера на экран
    void show() {
      line(0);
      for (byte i = 0; i < 20; i++ )out(buffer[i]);
      line(1);
      for (byte i = 20; i < 40; i++ )out(buffer[i]);
      line(2);
      for (byte i = 40; i < 60; i++ )out(buffer[i]);
      line(3);
      for (byte i = 60; i < 80; i++ )out(buffer[i]);
    }
    void setCursor(byte x, byte y) {
      if (x > 20) x = 20;
      else posX = x;
      if (y > 4) x = 4;
      else posY = y;
    }
    void createCharPROGMEM(uint8_t location, const uint8_t *charmap) {
      location &= 0x7; // we only have 8 locations 0-7
      command(LCD_SETCGRAMADDR | (location << 3));
      for (int i = 0; i < 8; i++) {
        out(pgm_read_byte_near(charmap + i));
      }
    }
    void createChar(uint8_t location, uint8_t charmap[]) {
      location &= 0x7; // we only have 8 locations 0-7
      command(LCD_SETCGRAMADDR | (location << 3));
      for (int i = 0; i < 8; i++) {
        out(charmap[i]);
      }
    }
  private:
    /*внутрение функции*/
    void line(byte l) {
      switch (l) {
        case 0: command(LCD_SETDDRAMADDR + 0x00);
          break;
        case 1: command(LCD_SETDDRAMADDR + 0x40);
          break;
        case 2: command(LCD_SETDDRAMADDR + 0x14);
          break;
        case 3: command(LCD_SETDDRAMADDR + 0x54);
          break;
      }
    }
    inline size_t write(uint8_t value) {
      if (posX < 20 && posY < 4) {
        buffer[posY * 20 + posX] = value;
        posX++;
      }
      return 1;
    }
    inline void out(uint8_t value) {
      send(value, Rs);
    }
    /*команды низкоуровневого управления*/
    inline void command(uint8_t value) {
      send(value, 0);
    }
    void send(uint8_t value, uint8_t mode) {
      uint8_t highnib = value & 0xf0;
      write4bits((highnib) | mode);
      uint8_t lownib = (value << 4) & 0xf0;
      write4bits((lownib) | mode);
    }
    void write4bits(uint8_t value) {
      expanderWrite(value);
      pulseEnable(value);
    }
    void expanderWrite(uint8_t _data) {
      Wire.beginTransmission(adr);
      Wire.write((int)(_data) | _backlightval);
      Wire.endTransmission();
    }
    void pulseEnable(uint8_t _data) {
      expanderWrite(_data | En);  // En high
      delayMicroseconds(1);   // enable pulse must be >450ns
      expanderWrite(_data & ~En); // En low
      delayMicroseconds(50);    // commands need > 37us to settle
    }
};
Cl_lcd2004_i2c lcd(0x3F);//0x27
//--------------------------------------------------

const byte custom[5][8] PROGMEM = {
  {0b00000, 0b01010, 0b11111, 0b11111, 0b11111, 0b01110, 0b00100, 0b00000},// \1 сердце
  {0b00000, 0b00000, 0b01010, 0b00000, 0b00000, 0b10001, 0b01110, 0b00000},// \2 улыбка
  {0b00000, 0b00000, 0b01010, 0b00000, 0b00000, 0b00000, 0b01110, 0b10001},// \3 грусть
  {0b00100, 0b01010, 0b00100, 0b00100, 0b01110, 0b10101, 0b00100, 0b0101}, // \4 руки вниз
  {0b00100, 0b01010, 0b00100, 0b10101, 0b01110, 0b00100, 0b00100, 0b01010} // \5 руки вверх
};

void setup() {
  lcd.init();
  lcd.backlight();
  lcd.clear();
  for (int i = 1; i < 6; i++)
    lcd.createCharPROGMEM(i, custom[i-1]);
  lcd.print("I \1 Arduino! \2\3\4\5");
  lcd.show();
}

void loop() {
}
qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
/**/
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
//------дисплей lcd2004_i2c-----------------------------
#include <Wire.h>
// команды
#define LCD_CLEARDISPLAY 0x01
#define LCD_RETURNHOME 0x02
#define LCD_ENTRYMODESET 0x04
#define LCD_DISPLAYCONTROL 0x08
#define LCD_CURSORSHIFT 0x10
#define LCD_FUNCTIONSET 0x20
#define LCD_SETCGRAMADDR 0x40
#define LCD_SETDDRAMADDR 0x80
// флаги для режима ввода дисплея
#define LCD_ENTRYRIGHT 0x00
#define LCD_ENTRYLEFT 0x02
#define LCD_ENTRYSHIFTINCREMENT 0x01
#define LCD_ENTRYSHIFTDECREMENT 0x00
// флаги для управления включением / выключением дисплея
#define LCD_DISPLAYON 0x04
#define LCD_DISPLAYOFF 0x00
#define LCD_CURSORON 0x02
#define LCD_CURSOROFF 0x00
#define LCD_BLINKON 0x01
#define LCD_BLINKOFF 0x00
// флаги для отображения / сдвига курсора
#define LCD_DISPLAYMOVE 0x08
#define LCD_CURSORMOVE 0x00
#define LCD_MOVERIGHT 0x04
#define LCD_MOVELEFT 0x00
// флаги для набора функций
#define LCD_8BITMODE 0x10
#define LCD_4BITMODE 0x00
#define LCD_2LINE 0x08
#define LCD_1LINE 0x00
#define LCD_5x10DOTS 0x04
#define LCD_5x8DOTS 0x00
// флаги для управления подсветкой
#define LCD_BACKLIGHT 0x08
#define LCD_NOBACKLIGHT 0x00

#define En B00000100  // Бит разрешения
#define Rw B00000010  // Чтение / запись бит
#define Rs B00000001  // Бит выбора регистра
class Cl_lcd1602_i2c : public Print {
  protected:
    uint8_t adr, posX, posY;
    uint8_t _backlightval;
    uint8_t _displayfunction;
    uint8_t _displaycontrol;
    uint8_t _displaymode;
    byte buffer[80];
  public:
    Cl_lcd1602_i2c(uint8_t a): adr(a) {}
    void init() {
      Wire.begin();
      write4bits(0x03 << 4);
      delayMicroseconds(4500); // wait min 4.1ms
      write4bits(0x03 << 4);
      delayMicroseconds(4500); // wait min 4.1ms
      write4bits(0x03 << 4);
      delayMicroseconds(150);
      write4bits(0x02 << 4);
      delay(50);
      _backlightval = LCD_NOBACKLIGHT;
      expanderWrite(_backlightval); // сбросить расширение и выключить подсветку (бит 8 = 1)
      // режим работы дисплея 4-х битный интерфейс ,две строки,5х8 точек
      _displayfunction = LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS;
      command(LCD_FUNCTIONSET | _displayfunction);
      // режим контроля дисплей вкл, курсор не мигает,дисплей не мигает
      _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
      command(LCD_DISPLAYCONTROL | _displaycontrol);
      // режим ввода текста в память-начинать слева с движением в право
      _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
      command(LCD_ENTRYMODESET | _displaymode);
      clear();
    }
    // подсветку вкл/выкл
    void backlight(void) {
      _backlightval = LCD_BACKLIGHT;
      expanderWrite(0);
    }
    void noBacklight(void) {
      _backlightval = LCD_NOBACKLIGHT;
      expanderWrite(0);
    }
    // очистить буфер
    void clear() {
      for (byte i = 0; i < 80; i++ )buffer[i] = 0x20;
      posX = 0; posY = 0;
    }
    // отправить информацию из буфера на экран
    void show() {
      line(0);
      for (byte i = 0; i < 20; i++ )out(buffer[i]);
      line(1);
      for (byte i = 20; i < 40; i++ )out(buffer[i]);
      line(2);
      for (byte i = 40; i < 60; i++ )out(buffer[i]);
      line(3);
      for (byte i = 60; i < 80; i++ )out(buffer[i]);
    }
    void setCursor(byte x, byte y) {
      if (x > 20) x = 20;
      else posX = x;
      if (y > 4) x = 4;
      else posY = y;
    }
    void createChar(uint8_t location, uint8_t charmap[]) {
      location &= 0x7; // we only have 8 locations 0-7
      command(LCD_SETCGRAMADDR | (location << 3));
      for (int i = 0; i < 8; i++) {
        out(charmap[i]);
      }
    }
    inline size_t write(uint8_t value) {
      if (posX < 20 && posY < 4) {
        buffer[posY * 20 + posX] = value;
        posX++;
      }
      return 1;
    }
  private:
    /*внутрение функции*/
    void line(byte l) {
      switch (l) {
        case 0: command(LCD_SETDDRAMADDR + 0x00);
          break;
        case 1: command(LCD_SETDDRAMADDR + 0x40);
          break;
        case 2: command(LCD_SETDDRAMADDR + 0x14);
          break;
        case 3: command(LCD_SETDDRAMADDR + 0x54);
          break;
      }
    }
    inline void out(uint8_t value) {
      send(value, Rs);
    }
    /*команды низкоуровневого управления*/
    inline void command(uint8_t value) {
      send(value, 0);
    }
    void send(uint8_t value, uint8_t mode) {
      uint8_t highnib = value & 0xf0;
      write4bits((highnib) | mode);
      uint8_t lownib = (value << 4) & 0xf0;
      write4bits((lownib) | mode);
    }
    void write4bits(uint8_t value) {
      expanderWrite(value);
      pulseEnable(value);
    }
    void expanderWrite(uint8_t _data) {
      Wire.beginTransmission(adr);
      Wire.write((int)(_data) | _backlightval);
      Wire.endTransmission();
    }
    void pulseEnable(uint8_t _data) {
      expanderWrite(_data | En);  // En high
      delayMicroseconds(1);   // enable pulse must be >450ns
      expanderWrite(_data & ~En); // En low
      delayMicroseconds(50);    // commands need > 37us to settle
    }
};
Cl_lcd1602_i2c lcd(0x3F);//0x27
byte custom[8][8] = {   // символы большого шрифта
  { B11111, B11111, B11111, B00000, B00000, B00000, B00000, B00000 },
  { B11100, B11110, B11111, B11111, B11111, B11111, B11111, B11111 },
  { B11111, B11111, B11111, B11111, B11111, B11111, B01111, B00111 },
  { B00000, B00000, B00000, B00000, B00000, B11111, B11111, B11111 },
  { B11111, B11111, B11111, B11111, B11111, B11111, B11110, B11100 },
  { B11111, B11111, B11111, B00000, B00000, B00000, B11111, B11111 },
  { B11111, B00000, B00000, B00000, B00000, B11111, B11111, B11111 },
  { B00111, B01111, B11111, B11111, B11111, B11111, B11111, B11111 }
};
const char *bigChars[][2] = {   // символы из новых букв
  {"\024\024\024", "\024\024\024"}, // Space
  {"\377", "\007"}, // !
  {"\005\005", "\024\024"}, // "
  {"\004\377\004\377\004", "\001\377\001\377\001"}, // #
  {"\010\377\006", "\007\377\005"}, // $
  {"\001\024\004\001", "\004\001\024\004"}, // %
  {"\010\006\002\024", "\003\007\002\004"}, // &
  {"\005", "\024"}, // '
  {"\010\001", "\003\004"}, // (
  {"\001\002", "\004\005"}, // )
  {"\001\004\004\001", "\004\001\001\004"}, // *
  {"\004\377\004", "\001\377\001"}, // +
  {"\024", "\005"}, // ,
  {"\004\004\004", "\024\024\024"}, // -
  {"\024", "\004"}, // .
  {"\024\024\004\001", "\004\001\024\024"}, // /
  {"\010\001\002", "\003\004\005"}, // 0
  {"\001\002\024", "\024\377\024"}, // 1
  {"\006\006\002", "\003\007\007"}, // 2
  {"\006\006\002", "\007\007\005"}, // 3
  {"\003\004\002", "\024\024\377"}, // 4
  {"\377\006\006", "\007\007\005"}, // 5
  {"\010\006\006", "\003\007\005"}, // 6
  {"\001\001\002", "\024\010\024"}, // 7
  {"\010\006\002", "\003\007\005"}, // 8
  {"\010\006\002", "\024\024\377"}, // 9
  {"\004", "\001"}, // :
  {"\004", "\005"}, // ;
  {"\024\004\001", "\001\001\004"}, // <
  {"\004\004\004", "\001\001\001"}, // =
  {"\001\004\024", "\004\001\001"}, // >
  {"\001\006\002", "\024\007\024"}, // ?
  {"\010\006\002", "\003\004\004"}, // @
  {"\010\006\002", "\377\024\377"}, // A
  {"\377\006\005", "\377\007\002"}, // B
  {"\010\001\001", "\003\004\004"}, // C
  {"\377\001\002", "\377\004\005"}, // D
  {"\377\006\006", "\377\007\007"}, // E
  {"\377\006\006", "\377\024\024"}, // F
  {"\010\001\001", "\003\004\002"}, // G
  {"\377\004\377", "\377\024\377"}, // H
  {"\001\377\001", "\004\377\004"}, // I
  {"\024\024\377", "\004\004\005"}, // J
  {"\377\004\005", "\377\024\002"}, // K
  {"\377\024\024", "\377\004\004"}, // L
  {"\010\003\005\002", "\377\024\024\377"}, // M
  {"\010\002\024\377", "\377\024\003\005"}, // N
  {"\010\001\002", "\003\004\005"}, // 0/0
  {"\377\006\002", "\377\024\024"}, // P
  {"\010\001\002\024", "\003\004\377\004"}, // Q
  {"\377\006\002", "\377\024\002"}, // R
  {"\010\006\006", "\007\007\005"}, // S
  {"\001\377\001", "\024\377\024"}, // T
  {"\377\024\377", "\003\004\005"}, // U
  {"\003\024\024\005", "\024\002\010\024"}, // V
  {"\377\024\024\377", "\003\010\002\005"}, // W
  {"\003\004\005", "\010\024\002"}, // X
  {"\003\004\005", "\024\377\024"}, // Y
  {"\001\006\005", "\010\007\004"}, // Z
  {"\377\001", "\377\004"}, // [
  {"\001\004\024\024", "\024\024\001\004"}, // Backslash
  {"\001\377", "\004\377"}, // ]
  {"\010\002", "\024\024"}, // ^
  {"\024\024\024", "\004\004\004"}, // _
};
int writeBigChar(char ch, int x, int y) {
  const char *(*blocks)[2] = NULL; // Pointer to an array of two strings (character pointers)
  if (ch < ' ' || ch > '_') // If outside our table range, do nothing
    return 0;
  blocks = &bigChars[ch - ' ']; // Look up the definition
  for (int half = 0; half <= 1; half++) {
    int t = x; // Write out top or bottom string, byte at a time
    for (const char *cp = (*blocks)[half]; *cp; cp++) {
      lcd.setCursor(t, y + half);
      lcd.write(*cp);
      t = (t + 1) % 40; // Circular scroll buffer of 40 characters, loop back at 40
    }
    lcd.setCursor(t, y + half);
    lcd.write(' '); // Make space between letters, in case overwriting
  }
  return strlen((*blocks)[0]); // Return char width
}
void writeBigString(const char *str, int x, int y) { // пишем большие буквы
  char c;
  while ((c = *str++))
    x += writeBigChar(c, x, y) + 1;
}

//-----------------------------------------------
void setup() {
  lcd.init();
  lcd.backlight();
  lcd.clear();
  for (int i = 0; i < 8; i++) lcd.createChar(i + 1, custom[i]);
  writeBigString("GAS", 0, 0);
  writeBigString("1.2", 0, 2);
  lcd.setCursor(10, 2);
  lcd.print("SmokeClock");
  lcd.setCursor(13, 3);
  lcd.print("voltNik");
  lcd.show();
}
void loop() {
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
/**/
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
//------дисплей lcd2004_i2c-----------------------------
#include <Wire.h>
// команды
#define LCD_CLEARDISPLAY 0x01
#define LCD_RETURNHOME 0x02
#define LCD_ENTRYMODESET 0x04
#define LCD_DISPLAYCONTROL 0x08
#define LCD_CURSORSHIFT 0x10
#define LCD_FUNCTIONSET 0x20
#define LCD_SETCGRAMADDR 0x40
#define LCD_SETDDRAMADDR 0x80
// флаги для режима ввода дисплея
#define LCD_ENTRYRIGHT 0x00
#define LCD_ENTRYLEFT 0x02
#define LCD_ENTRYSHIFTINCREMENT 0x01
#define LCD_ENTRYSHIFTDECREMENT 0x00
// флаги для управления включением / выключением дисплея
#define LCD_DISPLAYON 0x04
#define LCD_DISPLAYOFF 0x00
#define LCD_CURSORON 0x02
#define LCD_CURSOROFF 0x00
#define LCD_BLINKON 0x01
#define LCD_BLINKOFF 0x00
// флаги для отображения / сдвига курсора
#define LCD_DISPLAYMOVE 0x08
#define LCD_CURSORMOVE 0x00
#define LCD_MOVERIGHT 0x04
#define LCD_MOVELEFT 0x00
// флаги для набора функций
#define LCD_8BITMODE 0x10
#define LCD_4BITMODE 0x00
#define LCD_2LINE 0x08
#define LCD_1LINE 0x00
#define LCD_5x10DOTS 0x04
#define LCD_5x8DOTS 0x00
// флаги для управления подсветкой
#define LCD_BACKLIGHT 0x08
#define LCD_NOBACKLIGHT 0x00

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

const byte custom[8][8] PROGMEM = {
  {0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000},// \0
  {0b11111, 0b11111, 0b11111, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000},// \1
  {0b00000, 0b00000, 0b00000, 0b11111, 0b11111, 0b11111, 0b00000, 0b00000},// \2
  {0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b00000, 0b00000},// \3
  {0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b11111, 0b11111},// \4
  {0b11111, 0b11111, 0b11111, 0b00000, 0b00000, 0b00000, 0b11111, 0b11111},// \5
  {0b00000, 0b00000, 0b00000, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111},// \6
  {0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111} // \7
};
const byte fontChar[][6] PROGMEM = {
  {'\0', '\0', '\0', '\0', '\0', '\0'},//  Space
  {'\0', '\7', '\0', '\0', '\6', '\0'},// !
  {'"', ' ', ' ', ' ', ' ', ' '},// "
  {'#', ' ', ' ', ' ', ' ', ' '},// #
  {'$', ' ', ' ', ' ', ' ', ' '},// $
  {'/', ' ', ' ', ' ', ' ', ' '},// %
  {'&', ' ', ' ', ' ', ' ', ' '},// &
  {',', ' ', ' ', ' ', ' ', ' '},// ,
  {'\0', '\6', '\1', '\0', '\3', '\4'},// (
  {'\1', '\6', '\0', '\4', '\3', '\0'},// )
  {'\5', '\6', '\5', '\2', '\1', '\2'},// *
  {'\4', '\7', '\4', '\0', '\3', '\0'},// +
  {'\0', '\0', '\0', '\0', '\7', '\0'},// ,
  {'\4', '\4', '\4', '\0', '\0', '\0'},// -
  {'\0', '\0', '\0', '\0', '\6', '\0'},// .
  {'\0', '\4', '\3', '\6', '\1', '\0'},// /
  {'\7', '\1', '\7', '\7', '\4', '\7'},// 0
  {'\0', '\7', '\0', '\0', '\7', '\0'},// 1
  {'\5', '\5', '\7', '\7', '\5', '\5'},// 2
  {'\5', '\5', '\7', '\5', '\5', '\7'},// 3
  {'\7', '\4', '\7', '\1', '\1', '\7'},// 4
  {'\7', '\5', '\5', '\5', '\5', '\7'},// 5
  {'\7', '\5', '\5', '\7', '\5', '\7'},// 6
  {'\1', '\5', '\3', '\0', '\7', '\0'},// 7
  {'\7', '\5', '\7', '\7', '\5', '\7'},// 8
  {'\7', '\5', '\7', '\5', '\5', '\7'},// 9
  {'\0', '\3', '\0', '\0', '\6', '\0'},// :
  {'\0', '\3', '\0', '\0', '\7', '\0'},// ;
  {'>', ' ', ' ', ' ', ' ', ' '},// <
  {'\2', '\2', '\2', '\2', '\2', '\2'},// =
  {'>', ' ', ' ', ' ', ' ', ' '},// >
  {'\1', '\5', '\3', '\0', '\6', '\0'},// ?
  {'\7', '\1', '\3', '\7', '\4', '\6'},// @
  {'\6', '\1', '\6', '\7', '\1', '\7'},// A
  {'\7', '\5', '\3', '\7', '\4', '\3'},// B
  {'\7', '\1', '\3', '\7', '\4', '\6'},// C
  {'\7', '\1', '\6', '\7', '\4', '\3'},// D
  {'\7', '\5', '\1', '\7', '\5', '\4'},// E
  {'\7', '\5', '\1', '\7', '\0', '\0'},// F
  {'\7', '\1', '\1', '\7', '\4', '\7'},// G
  {'\7', '\4', '\7', '\7', '\0', '\7'},// H
  {'\0', '\7', '\0', '\0', '\7', '\0'},// I
  {'\0', '\7', '\0', '\4', '\7', '\0'},// J
  {'\7', '\4', '\3', '\7', '\1', '\6'},// K
  {'\7', '\0', '\0', '\7', '\3', '\3'},// L
  {'\7', '\4', '\7', '\7', '\0', '\7'},// M
  {'\7', '\4', '\7', '\7', '\0', '\7'},// N
  {'\7', '\1', '\7', '\7', '\4', '\7'},// O
  {'\7', '\1', '\6', '\7', '\1', '\0'},// P
  {'\7', '\1', '\7', '\7', '\4', '\3'},// Q
  {'R', ' ', ' ', ' ', ' ', ' '},// R
  {'S', ' ', ' ', ' ', ' ', ' '},// S
  {'T', ' ', ' ', ' ', ' ', ' '},// T
  {'U', ' ', ' ', ' ', ' ', ' '},// U
  {'V', ' ', ' ', ' ', ' ', ' '},// V
  {'W', ' ', ' ', ' ', ' ', ' '},// W
  {'X', ' ', ' ', ' ', ' ', ' '},// X
  {'Y', ' ', ' ', ' ', ' ', ' '},// Y
  {'Z', ' ', ' ', ' ', ' ', ' '},// Z
  {'\0', '\7', '\1', '\0', '\7', '\4'},// [
  {'\3', '\4', '\0', '\0', '\1', '\6'},// Backslash
  {'\1', '\7', '\0', '\4', '\7', '\0'},// ]
  {'^', ' ', ' ', ' ', ' ', ' '},// ^
  {'\4', '\4', '\4', '\4', '\4', '\4'}// _
};
class Cl_lcd2004_i2c : public Print {
  protected:
    uint8_t adr, posX, posY;
    uint8_t _backlightval;
    uint8_t _displayfunction;
    uint8_t _displaycontrol;
    uint8_t _displaymode;
    byte buffer[80];
    static const byte smallChar = 0;
    static const byte bigChar = 1;
    byte sizeChar;
  public:
    Cl_lcd2004_i2c(uint8_t a): adr(a) {}
    void small() {
      sizeChar = smallChar;
    }
    void big() {
      sizeChar = bigChar;
    }
    void init() {
      Wire.begin();
      write4bits(0x03 << 4);
      delayMicroseconds(4500); // wait min 4.1ms
      write4bits(0x03 << 4);
      delayMicroseconds(4500); // wait min 4.1ms
      write4bits(0x03 << 4);
      delayMicroseconds(150);
      write4bits(0x02 << 4);
      delay(50);
      _backlightval = LCD_NOBACKLIGHT;
      expanderWrite(_backlightval); // сбросить расширение и выключить подсветку (бит 8 = 1)
      // режим работы дисплея 4-х битный интерфейс ,две строки,5х8 точек
      _displayfunction = LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS;
      command(LCD_FUNCTIONSET | _displayfunction);
      // режим контроля дисплей вкл, курсор не мигает,дисплей не мигает
      _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
      command(LCD_DISPLAYCONTROL | _displaycontrol);
      // режим ввода текста в память-начинать слева с движением в право
      _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
      command(LCD_ENTRYMODESET | _displaymode);
      for (int i = 0; i < 8; i++)
        createCharPROGMEM(i, custom[i]);
      small();
      clear();
    }
    // подсветку вкл/выкл
    void backlight(void) {
      _backlightval = LCD_BACKLIGHT;
      expanderWrite(0);
    }
    void noBacklight(void) {
      _backlightval = LCD_NOBACKLIGHT;
      expanderWrite(0);
    }
    // очистить буфер
    void clear() {
      for (byte i = 0; i < 80; i++ )buffer[i] = 0x20;
      posX = 0; posY = 0;
    }
    // отправить информацию из буфера на экран
    void show() {
      line(0);
      for (byte i = 0; i < 20; i++ )out(buffer[i]);
      line(1);
      for (byte i = 20; i < 40; i++ )out(buffer[i]);
      line(2);
      for (byte i = 40; i < 60; i++ )out(buffer[i]);
      line(3);
      for (byte i = 60; i < 80; i++ )out(buffer[i]);
    }
    void setCursor(byte x, byte y) {
      if (x > 20) x = 20;
      else posX = x;
      if (y > 4) x = 4;
      else posY = y;
    }
    void createCharPROGMEM(uint8_t location, const uint8_t *charmap) {
      location &= 0x7; // we only have 8 locations 0-7
      command(LCD_SETCGRAMADDR | (location << 3));
      for (int i = 0; i < 8; i++) {
        out(pgm_read_byte_near(charmap + i));
      }
    }
    void createChar(uint8_t location, uint8_t charmap[]) {
      location &= 0x7; // we only have 8 locations 0-7
      command(LCD_SETCGRAMADDR | (location << 3));
      for (int i = 0; i < 8; i++) {
        out(charmap[i]);
      }
    }
  private:
    /*внутрение функции*/
    void line(byte l) {
      switch (l) {
        case 0: command(LCD_SETDDRAMADDR + 0x00);
          break;
        case 1: command(LCD_SETDDRAMADDR + 0x40);
          break;
        case 2: command(LCD_SETDDRAMADDR + 0x14);
          break;
        case 3: command(LCD_SETDDRAMADDR + 0x54);
          break;
      }
    }
    void writeToBuf(uint8_t value, uint8_t x, uint8_t y) {
      if (x < 20 && y < 4) buffer[y * 20 + x] = value;
    }
    inline size_t write(uint8_t value) {
      if (sizeChar == smallChar) {
        writeToBuf(value, posX, posY);
        posX++;
      }
      else {
        value -= ' ';
        writeToBuf(pgm_read_byte_near(&fontChar[value][0]), posX, posY);
        writeToBuf(pgm_read_byte_near(&fontChar[value][1]), posX + 1, posY);
        writeToBuf(pgm_read_byte_near(&fontChar[value][2]), posX + 2, posY);
        writeToBuf(' '                                    , posX + 3, posY);
        writeToBuf(pgm_read_byte_near(&fontChar[value][3]), posX    , posY + 1);
        writeToBuf(pgm_read_byte_near(&fontChar[value][4]), posX + 1, posY + 1);
        writeToBuf(pgm_read_byte_near(&fontChar[value][5]), posX + 2, posY + 1);
        writeToBuf(' '                                    , posX + 3, posY + 1);
        posX += 4;
      }
      return 1;
    }
    inline void out(uint8_t value) {
      send(value, Rs);
    }
    /*команды низкоуровневого управления*/
    inline void command(uint8_t value) {
      send(value, 0);
    }
    void send(uint8_t value, uint8_t mode) {
      uint8_t highnib = value & 0xf0;
      write4bits((highnib) | mode);
      uint8_t lownib = (value << 4) & 0xf0;
      write4bits((lownib) | mode);
    }
    void write4bits(uint8_t value) {
      expanderWrite(value);
      pulseEnable(value);
    }
    void expanderWrite(uint8_t _data) {
      Wire.beginTransmission(adr);
      Wire.write((int)(_data) | _backlightval);
      Wire.endTransmission();
    }
    void pulseEnable(uint8_t _data) {
      expanderWrite(_data | En);  // En high
      delayMicroseconds(1);   // enable pulse must be >450ns
      expanderWrite(_data & ~En); // En low
      delayMicroseconds(50);    // commands need > 37us to settle
    }
};
Cl_lcd2004_i2c lcd(0x3F);//0x27
//--------------------------------------------------
unsigned long past;
void view() {
  past = millis();
  {
    lcd.clear();
    lcd.big();
    lcd << past / 1000;
    lcd.setCursor(0, 3);
    lcd.small();
    lcd << past / 1000;
    lcd.show();
  }

}
void setup() {
  lcd.init();
  lcd.backlight();
  view();
}
void loop() {
  if (millis() - past >= 1000) view();
}

 

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

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

#include <EEPROM.h>
typedef struct {
  uint16_t adr_txt1;
  uint16_t adr_txt2;
  uint16_t adr_txt3;
  uint16_t adr_txt4;
} stData;
stData Data EEMEM;
uint8_t txt1[15] EEMEM = "uno";
uint8_t txt2[15] EEMEM = "due";
uint8_t txt3[15] EEMEM = "tre";
uint8_t txt4[15] EEMEM = "quattro";

void save() {
  // первая строка
  String aaa1(F("uno-1"));
  uint16_t i;
  for (i = 0; i < aaa1.length(); i++) {
    Serial.print(aaa1.charAt(i));
    EEPROM.put((int)&txt1[i], aaa1.charAt(i)); // сохранить строку в EEROM
  }
  EEPROM.put((int)&txt1[i], 0);// занести конец строки
  EEPROM.put((int)&Data.adr_txt1, (int)txt1);// сохранить адрес строки EEROM в структуре

  // вторая строка
  String aaa2(F("due-2"));
  Serial.print('\n');
  for (i = 0; i < aaa2.length(); i++) {
    Serial.print(aaa2.charAt(i));
    EEPROM.put((int)&txt2[i], aaa2.charAt(i));
  }
  EEPROM.put((int)&txt2[i], 0);
  EEPROM.put((int)&Data.adr_txt2, (int)txt2);// сохранить адрес строки EEROM в структуре

  // третья строка
  String aaa3(F("tre-3"));
  Serial.print('\n');
  for (i = 0; i < aaa3.length(); i++) {
    Serial.print(aaa3.charAt(i));
    EEPROM.put((int)&txt3[i], aaa3.charAt(i));
  }
  EEPROM.put((int)&txt3[i], 0);
  EEPROM.put((int)&Data.adr_txt3, (int)txt3);// сохранить адрес строки EEROM в структуре

  // четвертая строка
  String aaa4(F("quattro-3"));
  Serial.print('\n');
  for (i = 0; i < aaa4.length(); i++) {
    Serial.print(aaa4.charAt(i));
    EEPROM.put((int)&txt4[i], aaa4.charAt(i));
  }
  EEPROM.put((int)&txt4[i], 0);
  EEPROM.put((int)&Data.adr_txt4, (int)txt4);// сохранить адрес строки EEROM в структуре

  Serial.print('\n');
}
void viev() {
  uint16_t adr;
  uint8_t c;
  EEPROM.get((int)&Data.adr_txt1, adr);// получить адресс 1 строки
  // adr = (uint16_t)&txt1[0];
  while (1) {
    EEPROM.get(adr, c);
    if (c == 0) break;
    else {
      adr++;
      Serial.print((char)c);
    }
  }
  Serial.print('\n');

  EEPROM.get((int)&Data.adr_txt2, adr);// получить адресс 2 строки
  // adr = (uint16_t)&txt2[0];
  while (1) {
    EEPROM.get(adr, c);
    if (c == 0) break;
    else {
      adr++;
      Serial.print((char)c);
    }
  }
  Serial.print('\n');
  EEPROM.get((int)&Data.adr_txt3, adr);// получить адресс 3 строки
  // adr = (uint16_t)&txt3[0];
  while (1) {
    EEPROM.get(adr, c);
    if (c == 0) break;
    else {
      adr++;
      Serial.print((char)c);
    }
  }
  Serial.print('\n');

  EEPROM.get((int)&Data.adr_txt4, adr);// получить адресс 4 строки
  // adr = (uint16_t)&txt4[0];
  while (1) {
    EEPROM.get(adr, c);
    if (c == 0) break;
    else {
      adr++;
      Serial.print((char)c);
    }
  }
  Serial.print('\n');

}
void setup() {
  Serial.begin(9600);
  save();
  viev();
}

void loop() {
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
/**/
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
//------дисплей lcd2004_i2c-----------------------------
#include <Wire.h>
// команды
#define LCD_CLEARDISPLAY 0x01
#define LCD_RETURNHOME 0x02
#define LCD_ENTRYMODESET 0x04
#define LCD_DISPLAYCONTROL 0x08
#define LCD_CURSORSHIFT 0x10
#define LCD_FUNCTIONSET 0x20
#define LCD_SETCGRAMADDR 0x40
#define LCD_SETDDRAMADDR 0x80
// флаги для режима ввода дисплея
#define LCD_ENTRYRIGHT 0x00
#define LCD_ENTRYLEFT 0x02
#define LCD_ENTRYSHIFTINCREMENT 0x01
#define LCD_ENTRYSHIFTDECREMENT 0x00
// флаги для управления включением / выключением дисплея
#define LCD_DISPLAYON 0x04
#define LCD_DISPLAYOFF 0x00
#define LCD_CURSORON 0x02
#define LCD_CURSOROFF 0x00
#define LCD_BLINKON 0x01
#define LCD_BLINKOFF 0x00
// флаги для отображения / сдвига курсора
#define LCD_DISPLAYMOVE 0x08
#define LCD_CURSORMOVE 0x00
#define LCD_MOVERIGHT 0x04
#define LCD_MOVELEFT 0x00
// флаги для набора функций
#define LCD_8BITMODE 0x10
#define LCD_4BITMODE 0x00
#define LCD_2LINE 0x08
#define LCD_1LINE 0x00
#define LCD_5x10DOTS 0x04
#define LCD_5x8DOTS 0x00
// флаги для управления подсветкой
#define LCD_BACKLIGHT 0x08
#define LCD_NOBACKLIGHT 0x00

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

const byte custom[8][8] PROGMEM = {
  {0,   0,  0,  0, 0,   0,  0,  0},// \0
  {31, 31, 31,  0, 0,   0,  0,  0},// \1
  {0,   0,  0, 31, 31, 31,  0,  0},// \2
  {31, 31, 31, 31, 31, 31,  0,  0},// \3
  {0,   0,  0,  0,  0,  0, 31, 31},// \4
  {31, 31, 31,  0,  0,  0, 31, 31},// \5
  {0,   0,  0, 31, 31, 31, 31, 31},// \6
  {31, 31, 31, 31, 31, 31, 31, 31} // \7
};
const byte fontChar[][6] PROGMEM = {
  {'\0', '\0', '\0', '\0', '\0', '\0'},//  Space
  {'\0', '\7', '\0', '\0', '\6', '\0'},// !
  {'\3', '\0', '\3', '\0', '\0', '\0'},// "
  {'\7', '\2', '\7', '\3', '\1', '\3'}, // #
  {'\6', '\5', '\5', '\2', '\6', '\1'},// $
  {'o' , '\4', '\3', '\6', '\1', 'o' },// %
  {'\3', '\7', '\4', '\3', '\4', '\4'},// &
  {',', '\0', '\0', '\0', '\0', '\0' },// ,
  {'\0', '\6', '\1', '\0', '\3', '\4'},// (
  {'\1', '\6', '\0', '\4', '\3', '\0'},// )
  {'\5', '\6', '\5', '\2', '\1', '\2'},// *
  {'\4', '\7', '\4', '\0', '\3', '\0'},// +
  {'\0', '\0', '\0', '\0', '\7', '\0'},// ,
  {'\4', '\4', '\4', '\0', '\0', '\0'},// -
  {'\0', '\0', '\0', '\0', '\6', '\0'},// .
  {'\0', '\4', '\3', '\6', '\1', '\0'},// /
  {'\7', '\1', '\7', '\7', '\4', '\7'},// 0
  {'\2', '\7', '\0', '\0', '\7', '\0'},// 1
  {'\5', '\5', '\7', '\7', '\5', '\5'},// 2
  {'\5', '\5', '\7', '\5', '\5', '\7'},// 3
  {'\7', '\4', '\7', '\1', '\1', '\7'},// 4
  {'\7', '\5', '\5', '\5', '\5', '\7'},// 5
  {'\7', '\5', '\5', '\7', '\5', '\7'},// 6
  {'\1', '\5', '\3', '\0', '\7', '\0'},// 7
  {'\7', '\5', '\7', '\7', '\5', '\7'},// 8
  {'\7', '\5', '\7', '\5', '\5', '\7'},// 9
  {'\0', '\3', '\0', '\0', '\6', '\0'},// :
  {'\0', '\3', '\0', '\0', '\7', '\0'},// ;
  {'\4', '\2', '\1', '\0', '\1', '\2'},// <
  {'\2', '\2', '\2', '\2', '\2', '\2'},// =
  {'\1', '\2', '\4', '\2', '\1', '\0'},// >
  {'\1', '\5', '\3', '\0', '\6', '\0'},// ?
  {'\7', '\1', '\3', '\7', '\4', '\6'},// @
  {'\6', '\1', '\6', '\7', '\1', '\7'},// A
  {'\7', '\5', '\3', '\7', '\4', '\3'},// B
  {'\7', '\1', '\3', '\7', '\4', '\6'},// C
  {'\7', '\1', '\6', '\7', '\4', '\3'},// D
  {'\7', '\5', '\1', '\7', '\5', '\4'},// E
  {'\7', '\5', '\1', '\7', '\0', '\0'},// F
  {'\7', '\1', '\1', '\7', '\4', '\7'},// G
  {'\7', '\4', '\7', '\7', '\0', '\7'},// H
  {'\0', '\7', '\0', '\0', '\7', '\0'},// I
  {'\0', '\7', '\0', '\4', '\7', '\0'},// J
  {'\7', '\4', '\3', '\7', '\1', '\6'},// K
  {'\7', '\0', '\0', '\7', '\3', '\3'},// L
  {'\7', '\4', '\7', '\7', '\0', '\7'},// M
  {'\7', '\4', '\7', '\7', '\0', '\7'},// N
  {'\7', '\1', '\7', '\7', '\4', '\7'},// O
  {'\7', '\1', '\6', '\7', '\1', '\0'},// P
  {'\7', '\1', '\7', '\7', '\4', '\3'},// Q
  {'\7', '\1', '\6', '\7', '\1', '\6'},// R
  {'\7', '\5', '\5', '\5', '\5', '\7'},// S
  {'\1', '\7', '\1', '\0', '\7', '\0'},// T
  {'\7', '\0', '\7', '\3', '\6', '\3'},// U
  {'\7', '\0', '\7', '\0', '\7', '\0'},// V
  {'\7', '\0', '\7', '\0', '\7', '\0'},// W
  {'\3', '\4', '\3', '\6', '\1', '\6'},// X
  {'\3', '\4', '\3', '\0', '\7', '\0'},// Y
  {'\1', '\5', '\3', '\6', '\5', '\4'},// Z
  {'\0', '\7', '\1', '\0', '\7', '\4'},// [
  {'\3', '\4', '\0', '\0', '\1', '\6'},// Backslash
  {'\1', '\7', '\0', '\4', '\7', '\0'},// ]
  {'\2', '\1', '\2', '\0', '\0', '\0'},// ^
  {'\4', '\4', '\4', '\4', '\4', '\4'} // _
};
class Cl_lcd2004_i2c : public Print {
  protected:
    uint8_t adr, posX, posY;
    uint8_t _backlightval;
    uint8_t _displayfunction;
    uint8_t _displaycontrol;
    uint8_t _displaymode;
    byte buffer[80];
    static const byte smallChar = 0;
    static const byte bigChar = 1;
    byte sizeChar;
  public:
    Cl_lcd2004_i2c(uint8_t a): adr(a) {}
    void small() {
      sizeChar = smallChar;
    }
    void big() {
      sizeChar = bigChar;
    }
    void printSec(uint8_t b) {
      if (b > 99) return;
      if (b <= 9)print('0');
      print((int)b);
    }
    void init() {
      Wire.begin();
      write4bits(0x03 << 4);
      delayMicroseconds(4500); // wait min 4.1ms
      write4bits(0x03 << 4);
      delayMicroseconds(4500); // wait min 4.1ms
      write4bits(0x03 << 4);
      delayMicroseconds(150);
      write4bits(0x02 << 4);
      delay(50);
      _backlightval = LCD_NOBACKLIGHT;
      expanderWrite(_backlightval); // сбросить расширение и выключить подсветку (бит 8 = 1)
      // режим работы дисплея 4-х битный интерфейс ,две строки,5х8 точек
      _displayfunction = LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS;
      command(LCD_FUNCTIONSET | _displayfunction);
      // режим контроля дисплей вкл, курсор не мигает,дисплей не мигает
      _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
      command(LCD_DISPLAYCONTROL | _displaycontrol);
      // режим ввода текста в память-начинать слева с движением в право
      _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
      command(LCD_ENTRYMODESET | _displaymode);
      for (int i = 0; i < 8; i++)
        createCharPROGMEM(i, custom[i]);
      small();
      clear();
    }
    // подсветку вкл/выкл
    void backlight(void) {
      _backlightval = LCD_BACKLIGHT;
      expanderWrite(0);
    }
    void noBacklight(void) {
      _backlightval = LCD_NOBACKLIGHT;
      expanderWrite(0);
    }
    // очистить буфер
    void clear() {
      for (byte i = 0; i < 80; i++ )buffer[i] = 0x20;
      posX = 0; posY = 0;
    }
    // отправить информацию из буфера на экран
    void show() {
      line(0);
      for (byte i = 0; i < 20; i++ )out(buffer[i]);
      line(1);
      for (byte i = 20; i < 40; i++ )out(buffer[i]);
      line(2);
      for (byte i = 40; i < 60; i++ )out(buffer[i]);
      line(3);
      for (byte i = 60; i < 80; i++ )out(buffer[i]);
    }
    void setCursor(byte x, byte y) {
      if (x > 20) x = 20;
      else posX = x;
      if (y > 4) x = 4;
      else posY = y;
    }
    void createCharPROGMEM(uint8_t location, const uint8_t *charmap) {
      location &= 0x7; // we only have 8 locations 0-7
      command(LCD_SETCGRAMADDR | (location << 3));
      for (int i = 0; i < 8; i++) {
        out(pgm_read_byte_near(charmap + i));
      }
    }
    void createChar(uint8_t location, uint8_t charmap[]) {
      location &= 0x7; // we only have 8 locations 0-7
      command(LCD_SETCGRAMADDR | (location << 3));
      for (int i = 0; i < 8; i++) {
        out(charmap[i]);
      }
    }
  private:
    /*внутрение функции*/
    void line(byte l) {
      switch (l) {
        case 0: command(LCD_SETDDRAMADDR + 0x00);
          break;
        case 1: command(LCD_SETDDRAMADDR + 0x40);
          break;
        case 2: command(LCD_SETDDRAMADDR + 0x14);
          break;
        case 3: command(LCD_SETDDRAMADDR + 0x54);
          break;
      }
    }
    void writeToBuf(uint8_t value, uint8_t x, uint8_t y) {
      if (x < 20 && y < 4) buffer[y * 20 + x] = value;
    }
    inline size_t write(uint8_t value) {
      if (sizeChar == smallChar) {
        writeToBuf(value, posX, posY);
        posX++;
      }
      else {
        value -= ' ';
        writeToBuf(pgm_read_byte_near(&fontChar[value][0]), posX, posY);
        writeToBuf(pgm_read_byte_near(&fontChar[value][1]), posX + 1, posY);
        writeToBuf(pgm_read_byte_near(&fontChar[value][2]), posX + 2, posY);
        writeToBuf(' '                                    , posX + 3, posY);
        writeToBuf(pgm_read_byte_near(&fontChar[value][3]), posX    , posY + 1);
        writeToBuf(pgm_read_byte_near(&fontChar[value][4]), posX + 1, posY + 1);
        writeToBuf(pgm_read_byte_near(&fontChar[value][5]), posX + 2, posY + 1);
        writeToBuf(' '                                    , posX + 3, posY + 1);
        posX += 4;
      }
      return 1;
    }
    inline void out(uint8_t value) {
      send(value, Rs);
    }
    /*команды низкоуровневого управления*/
    inline void command(uint8_t value) {
      send(value, 0);
    }
    void send(uint8_t value, uint8_t mode) {
      uint8_t highnib = value & 0xf0;
      write4bits((highnib) | mode);
      uint8_t lownib = (value << 4) & 0xf0;
      write4bits((lownib) | mode);
    }
    void write4bits(uint8_t value) {
      expanderWrite(value);
      pulseEnable(value);
    }
    void expanderWrite(uint8_t _data) {
      Wire.beginTransmission(adr);
      Wire.write((int)(_data) | _backlightval);
      Wire.endTransmission();
    }
    void pulseEnable(uint8_t _data) {
      expanderWrite(_data | En);  // En high
      delayMicroseconds(1);   // enable pulse must be >450ns
      expanderWrite(_data & ~En); // En low
      delayMicroseconds(50);    // commands need > 37us to settle
    }
};
Cl_lcd2004_i2c lcd(0x3F);//0x27
//--------------------------------------------------
const byte page0 = 0; // главный экран
const byte page1 = 1; // 1 страница
byte page;
unsigned long past;
void goPage(byte p) {
  page = p;
  past = millis();
  lcd.clear();
  switch (page)  {
    case page0:
      {
        int sec = past / 1000;
        int minut = (sec / 60) % 60;
        sec %= 60;
        lcd.big();
        lcd.printSec(minut);
        lcd << ":";
        lcd.printSec(sec);
        lcd.setCursor(0, 3);
        lcd.small();
        lcd.printSec(minut);
        lcd << ":";
        lcd.printSec(sec);
     }
      break;
    case page1:
      {
        lcd.small();
        lcd << "page1";
      }
      break;
  }
  lcd.show();
}
void  run() {
  if (page == page0 && millis() - past >= 1000) goPage(page0);
}
//-----------------------
void setup() {
  lcd.init();
  lcd.backlight();
  goPage(page0);
}
void loop() {
  run();
}