[Из песочницы] Строим график на символьном дисплее 1602 Ардуино

Нам понадобится Ардуино УНО, дисплей 1602(и переходник i2c), датчик давления БМП180. Прошу прощения за качество фото, но какое есть.

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

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

Остальное комментариями в коде.

#include 
#include 
#include  //Подключаем библиотеку для работы с LCD через i2c
LiquidCrystal_I2C lcd(0x3F,16,2);  // иницилизируем дисплей по его i2c адресу
//это нужно для подключения дополнительных символов дисплея
          #if defined(ARDUINO) && ARDUINO >= 100
          #define printByte(args)  write(args);
          #else
          #define printByte(args)  print(args,BYTE);
          #endif
//Создаем массив значений на дисплее, от пустого к полному.          
          uint8_t graf0[8] = {0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F};
          uint8_t graf1[8] = {B00000, B11111, B11111, B11111, B11111, B11111, B11111};
          uint8_t graf2[8] = {B00000, B00000, B11111, B11111, B11111, B11111, B11111};
          uint8_t graf3[8] = {B00000, B00000, B00000, B11111, B11111, B11111, B11111};
          uint8_t graf4[8] = {B00000, B00000, B00000, B00000, B11111, B11111, B11111};
          uint8_t graf5[8] = {B00000, B00000, B00000, B00000, B00000, B11111, B11111};
          uint8_t graf6[8] = {B00000, B00000, B00000, B00000, B00000, B00000, B11111};
          uint8_t graf7[8] = {B00000, B00000, B00000, B00000, B00000, B00000, B00000};
//Добавили символы для графиков

int stat[2][25]; //Возьмем 2х мерный массив, где один массив время(контроль действительности значения) и второй массив наши данные
//int stat[0]; //Давление
//int stat[1]; //Время


#include 
BMP085 dps = BMP085();      // Подключаем датчик давления 
long Pressure = 0;
void setup(void) {
  lcd.init();  
  lcd.backlight(); //включаем подсветку
  lcd.createChar(0, graf0);// Подключаем доп. символы
  lcd.createChar(1, graf1);
  lcd.createChar(2, graf2);
  lcd.createChar(3, graf3);
  lcd.createChar(4, graf4);
  lcd.createChar(5, graf5);
  lcd.createChar(6, graf6);
  lcd.createChar(7, graf7);

}


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

void loop(void) {

if (((millis()/3600000)-stat[1][23]) >= 1.0) //заполняем текущее значение раз 1 час (3600000)
     {
       //сдвигаем массив влево, чтобы освободить предпоследнюю ячейку
         int i=0;
         for (i = 0; i < 24; i++) stat[0][i] = stat[0][i+1];
         for (i = 0; i < 24; i++) stat[1][i] = stat[1][i+1];
      
      dps.getPressure(&Pressure); //Записываем значения давления
      stat[0][23] = Pressure/13.33;
      stat[1][23] = millis()/3600000; 
      
      grafik(0, 2, 0); //строим график, вызов усложнен для построения разных графиков из массива, первое число номер массива, затем периодичность выборки данных, потом начальное значение в массиве. Мы берем первый массив(0), берем каждое второе значение(2) и начинаем с начала(0)
  }


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

int interval(int x) {
  int maxy = -5000;
  int inty = 0;
  int minx = minimum(x);

       for (int k = 0; k <= 24; k++) {
                                if (stat[1][k] != 0) {                     //если значение не ноль
                                if (stat[x][k] > maxy) maxy = stat[x][k];   //считаем максимальное значение
                                }}
                      if (maxy == -5000) maxy = 0;                                         
     //Строим интервал
     inty = maxy - minx;
     intx = inty/8;
     return intx;
  } 


При расчете интервала нам нужно минимальное значение в массиве:

int minimum(int d) {
      minx = 32767; 
      for (int i = 0; i <= 24; i++) {
                              if (stat[1][i] != 0)  {                 //если значение не ноль
                                if (stat[d][i] < minx) minx = stat[d][i];//считаем минимальное значение
                               }}
       if (minx == 50000) minx = 0;
       return minx;
  }


Строим сам график, если значений в массиве времени нет, выводим прочерк. Вызов функции усложнен для построения разных графиков из массива. Первое число номер массива, затем периодичность выборки данных, потом начальное значение в массиве. Мы берем первый массив (0), берем каждое второе значение (2) и начинаем с начала (0):

void grafik(int x, int y, int z) {
        lcd.setCursor(0, 1);
        lcd.print("Dav"); //Подпись на дисплее

           intx = interval(x); //вызовем функцию расчета интервала графика
           int minx = minimum(x); //Уточним минимальное значение
           for (int i=z; i <= 24; i= i + y){
              if (stat[x][i] == 0){                              //проверяем есть ли данные о времени
                lcd.print("-");                                  //если значений нет, отображаем прочерк
              } else if (stat[x][i] > (minx + intx*7)) {
                lcd.printByte(0);
              } else if (stat[x][i] > (minx + intx*6)) {
                lcd.printByte(1);
              }else if (stat[x][i] > (minx + intx*5)) {
                lcd.printByte(2);
              }else if (stat[x][i] > (minx + intx*4)) {
                lcd.printByte(3);
              }else if (stat[x][i] > (minx + intx*3)) {
                lcd.printByte(4);
              }else if (stat[x][i] > (minx + intx*2)) {
                lcd.printByte(5);
              }else if (stat[x][i] > (minx + intx)) {
                lcd.printByte(6);
              } else {
                lcd.printByte(7);
              }
           }
         
  }

© Geektimes