Как этим пользоваться? Да очень просто. Одна функция для инициализации “кастомных” символов, вторая – для вывода нужного элемента с настройками его размера и позиции на дисплее!

Полоса загрузки: fillBar(столбец, строка, ширина, значение)

  • Столбец: отвечает за положение левой точки полосы, нумерация идёт слева направо с нуля
  • Строка: отвечает за положение левой точки полосы, нумерация идёт сверху вниз с нуля
  • Ширина: полная ширина полосы по горизонтали. Очевидно, что ширина + стартовая позиция по горизонтали (столбец) не должны превышать ширину дисплея в символах по горизонтали
  • Значение: число от 0 до 100 – процент заполнения полосы. Любая ваша величина приводится к диапазону 0-100 при помощи ардуиновской функции map
  • Особенность: если вы используете свои кастомные символы, то перед выводом полосок нужно обязательно вызвать initBar() для загрузки в память дисплея символов полосы! Полоски занимают разное количество мест в зависимости от типа, подробнее смотрите в самих примерах

График из массива: drawPlotArray(столбец, строка, ширина, высота, мин. значение, макс. значение, массив) – смотри пример!

График в реальном времени: drawPlot(столбец, строка, ширина, высота, мин. значение, макс. значение, величина)

  • Столбец: нумерация идёт слева направо с нуля. Начало координат графика – нижняя левая точка!
  • Строка: нумерация идёт сверху вниз с нуля. Начало координат графика – нижняя левая точка!
  • Ширина: ширина графика по горизонтали. Очевидно, что ширина + стартовая позиция по горизонтали (столбец) не должны превышать ширину дисплея в символах по горизонтали
  • Высота: высота графика по вертикали. Очевидно, что высота+ стартовая позиция по вертикали (строка) не должны превышать высоту дисплея в символах по вертикали. То  есть для 2004 максимум высота 4, для 1602 максимум 2.
  • Мин. значение: минимальное значение для графика, ниже него строиться не будет (тип данных int -32,768 to 32,767)
  • Макс. значение: максимальное значение для графика, выше него строиться не будет (тип данных int -32,768 to 32,767)
  • Величина: значение, которое будет построено на графике с краю, предыдущие столбики автоматически сдвинутся в сторону при вызове функции drawPlot. Тип данных int -32,768 to 32,767
  • Также в примере есть готовый кусок кода для расчёта и вывода максимального и минимального значения на текущем графике!
  • Особенность: если вы используете свои кастомные символы, то перед выводом графика нужно обязательно вызвать initPlot() для загрузки в память дисплея символов графика! Они занимают все места, с 0 по 7!

Как этим пользоваться? Да очень просто. Одна функция для инициализации “кастомных” символов, вторая – для вывода нужного элемента с настройками его размера и позиции на дисплее!

Полоса загрузки: fillBar(столбец, строка, ширина, значение)

  • Столбец: отвечает за положение левой точки полосы, нумерация идёт слева направо с нуля
  • Строка: отвечает за положение левой точки полосы, нумерация идёт сверху вниз с нуля
  • Ширина: полная ширина полосы по горизонтали. Очевидно, что ширина + стартовая позиция по горизонтали (столбец) не должны превышать ширину дисплея в символах по горизонтали
  • Значение: число от 0 до 100 – процент заполнения полосы. Любая ваша величина приводится к диапазону 0-100 при помощи ардуиновской функции map
  • Особенность: если вы используете свои кастомные символы, то перед выводом полосок нужно обязательно вызвать initBar() для загрузки в память дисплея символов полосы! Полоски занимают разное количество мест в зависимости от типа, подробнее смотрите в самих примерах

График: drawPlot(столбец, строка, ширина, высота, мин. значение, макс. значение, величина,)

  • Столбец: нумерация идёт слева направо с нуля. Начало координат графика – нижняя левая точка!
  • Строка: нумерация идёт сверху вниз с нуля. Начало координат графика – нижняя левая точка!
  • Ширина: ширина графика по горизонтали. Очевидно, что ширина + стартовая позиция по горизонтали (столбец) не должны превышать ширину дисплея в символах по горизонтали
  • Высота: высота графика по вертикали. Очевидно, что высота+ стартовая позиция по вертикали (строка) не должны превышать высоту дисплея в символах по вертикали. То  есть для 2004 максимум высота 4, для 1602 максимум 2.
  • Мин. значение: минимальное значение для графика, ниже него строиться не будет (тип данных int -32,768 to 32,767)
  • Макс. значение: максимальное значение для графика, выше него строиться не будет (тип данных int -32,768 to 32,767)
  • Величина: значение, которое будет построено на графике с краю, предыдущие столбики автоматически сдвинутся в сторону при вызове функции drawPlot. Тип данных int -32,768 to 32,767
  • Также в примере есть готовый кусок кода для расчёта и вывода максимального и минимального значения на текущем графике!
  • Особенность: если вы используете свои кастомные символы, то перед выводом графика нужно обязательно вызвать initPlot() для загрузки в память дисплея символов графика! Они занимают все места, с 0 по 7!

/*
  Скетч примера полосы загрузки на символьном LCD дисплее 1602/2004 итд.
*/

// библиотеки дисплея
#include 
#include 

// создаём дисплей
// дисплей 1602. Если не работает, используйте другой адрес
LiquidCrystal_I2C lcd(0x3f, 16, 2);
//LiquidCrystal_I2C lcd(0x27, 16, 2);

// дисплей 2004. Если не работает, используйте другой адрес!
//LiquidCrystal_I2C lcd(0x3f, 20, 4);
//LiquidCrystal_I2C lcd(0x27, 20, 4);

void setup() {
  Serial.begin(9600);
  lcd.init();
  lcd.backlight();
  lcd.clear();
}

void loop() {
  // для примера потенциометр подключен к A0
  int perc = map(analogRead(0), 0, 1023, 0, 100);

  //fillBar0 принимает аргументы (столбец, строка, длина полосы, значение в % (0 - 100) )
  fillBar0(0, 0, 10, perc);
  fillBar0(0, 1, 16, perc);
  delay(50);
}

void fillBar0(byte start_pos, byte row, byte bar_length, byte fill_percent) {
  byte infill = round((float)bar_length * fill_percent / 100);
  lcd.setCursor(start_pos, row);
  if (infill == 0) lcd.write(16);
  else lcd.write(255);
  for (int n = 1; n < bar_length - 1; n++) {
    if (n < infill) lcd.write(255); if (n >= infill) lcd.write(16);
  }
  if (infill == bar_length) lcd.write(255);
  else lcd.write(16);
}
/*
  Скетч примера полосы загрузки на символьном LCD дисплее 1602/2004 итд.
*/

// библиотеки дисплея
#include 
#include 

// создаём дисплей
// дисплей 1602. Если не работает, используйте другой адрес
LiquidCrystal_I2C lcd(0x3f, 16, 2);
//LiquidCrystal_I2C lcd(0x27, 16, 2);

// дисплей 2004. Если не работает, используйте другой адрес!
//LiquidCrystal_I2C lcd(0x3f, 20, 4);
//LiquidCrystal_I2C lcd(0x27, 20, 4);

void setup() {
  Serial.begin(9600);
  lcd.init();
  lcd.backlight();
  lcd.clear();
  
  // инициализация символов для отрисовки. При использовании каких то своих символов,
  // нужно вызывать эту функцию перед отрисовкой графика/полосы!
  initBar1();
}

void loop() {
  // для примера потенциометр подключен к A0
  int perc = map(analogRead(0), 0, 1023, 0, 100);

  //fillBar1 принимает аргументы (столбец, строка, длина полосы, значение в % (0 - 100) )
  fillBar1(0, 0, 10, perc);
  fillBar1(0, 1, 16, perc);
  delay(50);
}

void initBar1() {
  // необходимые символы для работы
  // создано в http://maxpromer.github.io/LCD-Character-Creator/
  byte right_empty[8] = {0b11111,  0b00001,  0b00001,  0b00001,  0b00001,  0b00001,  0b00001,  0b11111};
  byte left_empty[8] = {0b11111,  0b10000,  0b10000,  0b10000,  0b10000,  0b10000,  0b10000,  0b11111};
  byte center_empty[8] = {0b11111, 0b00000,  0b00000,  0b00000,  0b00000,  0b00000,  0b00000,  0b11111};
  lcd.createChar(0, left_empty);
  lcd.createChar(1, center_empty);
  lcd.createChar(2, right_empty);
}

void fillBar1(byte start_pos, byte row, byte bar_length, byte fill_percent) {
  byte infill = round((float)bar_length * fill_percent / 100);
  lcd.setCursor(start_pos, row);
  if (infill == 0) lcd.write(0);
  else lcd.write(255);
  for (int n = 1; n < bar_length - 1; n++) {
    if (n < infill) lcd.write(255); if (n >= infill) lcd.write(1);
  }
  if (infill == bar_length) lcd.write(255);
  else lcd.write(2);
}
/*
  Скетч примера полосы загрузки на символьном LCD дисплее 1602/2004 итд.
*/

// библиотеки дисплея
#include 
#include 

// создаём дисплей
// дисплей 1602. Если не работает, используйте другой адрес
LiquidCrystal_I2C lcd(0x3f, 16, 2);
//LiquidCrystal_I2C lcd(0x27, 16, 2);

// дисплей 2004. Если не работает, используйте другой адрес!
//LiquidCrystal_I2C lcd(0x3f, 20, 4);
//LiquidCrystal_I2C lcd(0x27, 20, 4);

void setup() {
  Serial.begin(9600);
  lcd.init();
  lcd.backlight();
  lcd.clear();
  
  // инициализация символов для отрисовки. При использовании каких то своих символов,
  // нужно вызывать эту функцию перед отрисовкой графика/полосы!
  initBar2();
}

void loop() {
  // для примера потенциометр подключен к A0
  int perc = map(analogRead(0), 0, 1023, 0, 100);

  //fillBar2 принимает аргументы (столбец, строка, длина полосы, значение в % (0 - 100) )
  fillBar2(0, 0, 10, perc);
  fillBar2(0, 1, 16, perc);
  delay(50);
}

void initBar2() {
  // необходимые символы для работы
  // создано в http://maxpromer.github.io/LCD-Character-Creator/
  byte right_empty[8] = {0b11111,  0b00001,  0b00001,  0b00001,  0b00001,  0b00001,  0b00001,  0b11111};
  byte left_empty[8] = {0b11111,  0b10000,  0b10000,  0b10000,  0b10000,  0b10000,  0b10000,  0b11111};
  byte center_empty[8] = {0b11111, 0b00000,  0b00000,  0b00000,  0b00000,  0b00000,  0b00000,  0b11111};
  byte left_full[8] = {0b11111, 0b10000, 0b10111, 0b10111, 0b10111, 0b10111, 0b10000, 0b11111};
  byte right_full[8] = {0b11111, 0b00001, 0b11101, 0b11101, 0b11101, 0b11101, 0b00001, 0b11111};
  byte center_full[8] = {0b11111, 0b00000, 0b11111, 0b11111, 0b11111, 0b11111, 0b00000, 0b11111};
  lcd.createChar(0, left_empty);
  lcd.createChar(1, center_empty);
  lcd.createChar(2, right_empty);
  lcd.createChar(3, left_full);
  lcd.createChar(4, center_full);
  lcd.createChar(5, right_full);
}

void fillBar2(byte start_pos, byte row, byte bar_length, byte fill_percent) {
  byte infill = round((float)bar_length * fill_percent / 100);
  lcd.setCursor(start_pos, row);
  if (infill == 0) lcd.write(0);
  else lcd.write(3);
  for (int n = 1; n < bar_length - 1; n++) {
    if (n < infill) lcd.write(4); if (n >= infill) lcd.write(1);
  }
  if (infill == bar_length) lcd.write(5);
  else lcd.write(2);
}
/*
  Скетч примера полосы загрузки на символьном LCD дисплее 1602/2004 итд.
*/

// библиотеки дисплея
#include 
#include 

// создаём дисплей
// дисплей 1602. Если не работает, используйте другой адрес
LiquidCrystal_I2C lcd(0x3f, 16, 2);
//LiquidCrystal_I2C lcd(0x27, 16, 2);

// дисплей 2004. Если не работает, используйте другой адрес!
//LiquidCrystal_I2C lcd(0x3f, 20, 4);
//LiquidCrystal_I2C lcd(0x27, 20, 4);

boolean change_flag = true;     // флаг для 3 типа полосы

void setup() {
  Serial.begin(9600);
  lcd.init();
  lcd.backlight();
  lcd.clear();
  
  // инициализация символов для отрисовки. При использовании каких то своих символов,
  // нужно вызывать эту функцию перед отрисовкой графика/полосы!
  initBar3();
}

void loop() {
  // для примера потенциометр подключен к A0
  int perc = map(analogRead(0), 0, 1023, 0, 100);

  //fillBar3 принимает аргументы (столбец, строка, длина полосы, значение в % (0 - 100) )
  fillBar3(0, 0, 10, perc);
  fillBar3(0, 1, 16, perc);
  delay(50);
}

void initBar3() {
  // необходимые символы для работы
  // создано в http://maxpromer.github.io/LCD-Character-Creator/
  byte right_empty[8] = {0b11111,  0b00001,  0b00001,  0b00001,  0b00001,  0b00001,  0b00001,  0b11111};
  byte left_empty[8] = {0b11111,  0b10000,  0b10000,  0b10000,  0b10000,  0b10000,  0b10000,  0b11111};
  byte center_empty[8] = {0b11111, 0b00000,  0b00000,  0b00000,  0b00000,  0b00000,  0b00000,  0b11111};
  byte bar2[] = {0b11111, 0b11000, 0b11000, 0b11000, 0b11000, 0b11000, 0b11000, 0b11111};
  byte bar3[] = {  B11111,  B11100,  B11100,  B11100,  B11100,  B11100,  B11100,  B11111};
  byte bar4[] = {  B11111,  B11110,  B11110,  B11110,  B11110,  B11110,  B11110,  B11111};
  lcd.createChar(0, left_empty);
  lcd.createChar(1, center_empty);
  lcd.createChar(2, right_empty);
  lcd.createChar(3, bar2);
  lcd.createChar(4, bar3);
  lcd.createChar(5, bar4);
}

void fillBar3(byte start_pos, byte row, byte bar_length, byte fill_percent) {
  byte infill = bar_length * fill_percent / 10;
  byte fract = infill % 10;
  infill = infill / 10;
  // change_flag - true слева, false справа
  if (infill < bar_length - 1) { if (!change_flag) { change_flag = true; byte bar2[] = {0b11111, 0b11000, 0b11000, 0b11000, 0b11000, 0b11000, 0b11000, 0b11111}; byte bar3[] = { B11111, B11100, B11100, B11100, B11100, B11100, B11100, B11111}; byte bar4[] = { B11111, B11110, B11110, B11110, B11110, B11110, B11110, B11111}; lcd.createChar(3, bar2); lcd.createChar(4, bar3); lcd.createChar(5, bar4); } } else { if (change_flag) { change_flag = false; byte leftbar1[] = { B11111, B10001, B10001, B10001, B10001, B10001, B10001, B11111}; byte leftbar2[] = { B11111, B11001, B11001, B11001, B11001, B11001, B11001, B11111}; byte leftbar3[] = { B11111, B11101, B11101, B11101, B11101, B11101, B11101, B11111}; lcd.createChar(3, leftbar1); lcd.createChar(4, leftbar2); lcd.createChar(5, leftbar3); } } lcd.setCursor(start_pos, row); if (infill == 0) { if (fract >= 0 && fract < 2) lcd.write(0); else if (fract >= 2 && fract < 4) lcd.write(0); else if (fract >= 4 && fract < 6) lcd.write(3); else if (fract >= 6 && fract < 8) lcd.write(4); else if (fract >= 8) lcd.write(5);
  }
  else lcd.write(255);
  for (int n = 1; n < bar_length - 1; n++) {
    if (n < infill) lcd.write(255); if (n == infill) { if (fract >= 0 && fract < 2) lcd.write(1); else if (fract >= 2 && fract < 4) lcd.write(0); else if (fract >= 4 && fract < 6) lcd.write(3); else if (fract >= 6 && fract < 8) lcd.write(4); else if (fract >= 8) lcd.write(5);
    }
    if (n > infill) lcd.write(1);
  }
  if (infill == bar_length - 1) {
    if (fract >= 0 && fract < 2) lcd.write(2); else if (fract >= 2 && fract < 4) lcd.write(3); else if (fract >= 4 && fract < 6) lcd.write(4); else if (fract >= 6 && fract < 8) lcd.write(5); else if (fract >= 8) lcd.write(255);
  }
  else if (infill == bar_length) lcd.write(255);
  else lcd.write(2);
}
/*
  Скетч примера графика на символьном LCD дисплее 1602/2004 итд.
*/

// библиотеки дисплея
#include 
#include 

// создаём дисплей
// дисплей 1602. Если не работает, используйте другой адрес
//LiquidCrystal_I2C lcd(0x3f, 16, 2);
//LiquidCrystal_I2C lcd(0x27, 16, 2);

// дисплей 2004. Если не работает, используйте другой адрес!
//LiquidCrystal_I2C lcd(0x3f, 20, 4);
LiquidCrystal_I2C lcd(0x27, 20, 4);

int plot_array[20];         // массив данных для графика

void setup() {
  Serial.begin(9600);
  lcd.init();
  lcd.backlight();
  lcd.clear();

  // инициализация символов для отрисовки. При использовании каких то своих символов,
  // нужно вызывать эту функцию перед отрисовкой графика/полосы!
  initPlot();
}

void loop() {
  // для примера потенциометр подключен к A0
  int value = map(analogRead(0), 0, 1023, 10, 80);

  // drawPlot принимает аргументы (столбец, строка, ширина, высота, мин. значение, макс. значение, величина)
  // строка, столбец: начало графика - нижняя левая точка!
  // значения целочисленные (int) и могут быть отрицательными!
  // для примера отрисовка графика 12х4 занимает 140 миллисекунд
  // график сдвигается на 1 шаг АВТОМАТИЧЕСКИ при вызове функции!
  drawPlot(0, 3, 12, 4, 10, 80, value);

  // также можно вывести минимум и максимум по отображаемому участку графика
/*
  int max_value = -32000;
  int min_value = 32000;
  for (byte i = 0; i < 12; i++) { if (plot_array[i] > max_value) max_value = plot_array[i];
    if (plot_array[i] < min_value) min_value = plot_array[i];
  }

  lcd.setCursor(17, 1);
  lcd.print(value); lcd.print(" ");
  lcd.setCursor(13, 0);
  lcd.print("max "); lcd.print(max_value); lcd.print(" ");
  lcd.setCursor(13, 3);
  lcd.print("min "); lcd.print(min_value); lcd.print(" ");
*/
  delay(300);
}

void initPlot() {
  // необходимые символы для работы
  // создано в http://maxpromer.github.io/LCD-Character-Creator/
  byte row8[8] = {0b11111,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111};
  byte row7[8] = {0b00000,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111};
  byte row6[8] = {0b00000,  0b00000,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111};
  byte row5[8] = {0b00000,  0b00000,  0b00000,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111};
  byte row4[8] = {0b00000,  0b00000,  0b00000,  0b00000,  0b11111,  0b11111,  0b11111,  0b11111};
  byte row3[8] = {0b00000,  0b00000,  0b00000,  0b00000,  0b00000,  0b11111,  0b11111,  0b11111};
  byte row2[8] = {0b00000,  0b00000,  0b00000,  0b00000,  0b00000,  0b00000,  0b11111,  0b11111};
  byte row1[8] = {0b00000,  0b00000,  0b00000,  0b00000,  0b00000,  0b00000,  0b00000,  0b11111};
  lcd.createChar(0, row8);
  lcd.createChar(1, row1);
  lcd.createChar(2, row2);
  lcd.createChar(3, row3);
  lcd.createChar(4, row4);
  lcd.createChar(5, row5);
  lcd.createChar(6, row6);
  lcd.createChar(7, row7);
}

void drawPlot(byte pos, byte row, byte width, byte height, int min_val, int max_val, int fill_val) {
  for (byte i = 0; i < width; i++) {
    plot_array[i] = plot_array[i + 1];
  }
  fill_val = constrain(fill_val, min_val, max_val);
  plot_array[width] = fill_val;

  for (byte i = 0; i < width; i++) {                  // каждый столбец параметров
    byte infill, fract;
    // найти количество целых блоков с учётом минимума и максимума для отображения на графике
    infill = floor((float)(plot_array[i] - min_val) / (max_val - min_val) * height * 10);
    fract = (infill % 10) * 8 / 10;                   // найти количество оставшихся полосок
    infill = infill / 10;

    for (byte n = 0; n < height; n++) {     // для всех строк графика
      if (n < infill && infill > 0) {       // пока мы ниже уровня
        lcd.setCursor(i, (row - n));        // заполняем полными ячейками
        lcd.write(0);
      }
      if (n >= infill) {                    // если достигли уровня
        lcd.setCursor(i, (row - n));
        if (fract > 0) lcd.write(fract);          // заполняем дробные ячейки
        else lcd.write(16);                       // если дробные == 0, заливаем пустой
        for (byte k = n + 1; k < height; k++) {   // всё что сверху заливаем пустыми
          lcd.setCursor(i, (row - k));
          lcd.write(16);
        }
        break;
      }
    }
  }
}

На этом сегодня всё, надеюсь вам пригодятся эти наработки! Как говорится, лайк-подписка, до новых встреч =)


2018-09-13T15:59:11+00:00