помогите разобраться в коде для oled дисплея

skodec
Offline
Зарегистрирован: 26.07.2015

Здравствуйте. Делаю для себя некое устройство с oled дисплеем и батарейным питанием. На дисплее надо отображать заряд, ну как в телефоне. Возникла маленькая проблемка с массивами. Если раскоментировать сторки и убрать ненужные с _batdisp то все работает. Захотел сделать через указатель на массивы - не получается, выводиться какая то фигня. Как поправить код, чтобы работало. Сразу оговорюсь Ардуино - хобби, поэтому язык знаю не очень.

#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <SPI.h>
#include <Wire.h>
#define OLED_MOSI   9
#define OLED_CLK   10
#define OLED_DC    11
#define OLED_CS    12
#define OLED_RESET 8
#define A1_PIN 1      // акб

Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);

#if (SSD1306_LCDHEIGHT != 64)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif

float vcc=0.00;
int vb;
char _batdisp;

static  const unsigned char PROGMEM bat2 []= {    //24x16 66% батарейки
  0,0,0,
  63,255,255,
  63,255,255,  
  48,0,3,
  48,30,123,
  240,30,123,
  240,30,123,
  240,30,123,
  240,30,123,
  240,30,123,
  240,30,123,
  48,30,123,
  48,0,3, 
  63,255,255,
  63,255,255,
  0,0,0
};
static const unsigned char PROGMEM bat3 []= {    //24x16 100% батарейки
  0,0,0,
  63,255,255,
  63,255,255,  
  48,0,3,
  55,158,123,
  247,158,123,
  247,158,123,
  247,158,123,
  247,158,123,
  247,158,123,
  247,158,123,
  55,158,123,
  48,0,3, 
  63,255,255,
  63,255,255,
  0,0,0
};
static  const unsigned char PROGMEM bat1 []= {    //24x16 33% батарейки
  0,0,0,
  63,255,255,
  63,255,255,  
  48,0,3,
  48,0,123,
  240,0,123,
  240,0,123,
  240,0,123,
  240,0,123,
  240,0,123,
  240,0,123,
  48,0,123,
  48,0,3, 
  63,255,255,
  63,255,255,
  0,0,0
};
static const unsigned char PROGMEM bat0 []= {    //24x16 0% батарейки
  
  0,0,0,
  63,255,255,
  63,255,255,  
  48,0,3,
  48,0,3,
  240,0,3,
  240,0,3,
  240,0,3,
  240,0,3,
  240,0,3,
  240,0,3,
  48,0,3,
  48,0,3, 
  63,255,255,
  63,255,255,
  0,0,0
};
void disp_on(){                       //функция вкл дисплея
 digitalWrite(7,HIGH);             //подаем питание на дисплей
 delay(1);
 display.begin(SSD1306_SWITCHCAPVCC);
  display.clearDisplay();
  delay(5);
}
float vbat(){                           //функция определения и отображения напряжения батареи
    vb = analogRead(A1_PIN);
    vcc = (vb* 5.00) / 1023.0;
    if(vcc>=3.4)
    {
      _batdisp=&bat3;
      //display.drawBitmap(100,0,bat3,24,16,WHITE);
    }
    if(vcc>=3.2 && vcc<3.4 )
    {
      _batdisp=&bat2;
     // display.drawBitmap(100,0,bat2,24,16,WHITE);
    }
    if(vcc>=3.0 && vcc<3.2 )
    {
      _batdisp=&bat1;
    // display.drawBitmap(100,0,bat1,24,16,WHITE);
    }
    if(vcc<3.0 )
    {
      _batdisp=&bat0;
     // display.drawBitmap(100,0,bat0,24,16,WHITE);
    }
    return _batdisp;
    }
void setup() { 
  pinMode(7, OUTPUT);  
   disp_on(); 
}
void loop() {
display.clearDisplay();
    display.setTextSize(2);
    display.setTextColor(WHITE);
    display.setCursor(6,1);
// vbat();
    display.drawBitmap(100,0,_batdisp,24,16,WHITE);  
    display.display();
}

 

yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

А Вы не думали что батарейку можно линиями нарисовать, а процент заряженности выводить с помощью закрашенного прямоугольника? Так и гралаций больше можно полчить. Или нарисовать батарейку, а внутри тупа текстом 15% например... имхо. Или {20%].

skodec
Offline
Зарегистрирован: 26.07.2015

Линиями попробую. Я рисую батарейку, а в ней есть 3 зоны, которые закрашиваються в зависимости от заряда. Никаких процентов мне не надо. 

yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

Ну зоны тоже маленькими прямругольниками можно. Хотя дело хозяйское.

skodec
Offline
Зарегистрирован: 26.07.2015

Рисую вот такую.

yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

Так и понял, но чем забивать память "BITMAP`ами" мне кажеться проще генерировать изобраение батареи из примитивов.

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

yul-i-an пишет:

Так и понял, но чем забивать память "BITMAP`ами" мне кажеться проще генерировать изобраение батареи из примитивов.

Это уж вопрос художественный.

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

Кроме того, непонятна политика использования _batdisp. Если она глобальная - зачем возвращать её из функции, если возвращается из функции - почему не использовать это и зачем она глобальная. 

skodec
Offline
Зарегистрирован: 26.07.2015

yul-i-an пишет:

Так и понял, но чем забивать память "BITMAP`ами" мне кажеться проще генерировать изобраение батареи из примитивов.

Я почему то думал наоборот.  Картинка готова, указал какую и на печать.... Сидел сейчас читал про progmem - как то все размыто там.  Будем изучать дальше, а пока вернул функцию выбора обратно.

Logik пишет:

Это уж вопрос художественный.

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

Кроме того, непонятна политика использования _batdisp. Если она глобальная - зачем возвращать её из функции, если возвращается из функции - почему не использовать это и зачем она глобальная. 

Пытался по разному указывать на массивы с картинками. Я же говорю неочень я в си. Может можно копировать нужный массив в batdisp?

arDubino
Offline
Зарегистрирован: 12.01.2017

:))) сделать индикатор заряда.... чтоб этот заряд садить :))))))))))

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

skodec пишет:

Может можно копировать нужный массив в batdisp?

Можна конечно и копировать. Функции для работы PROGMEM например здесь - http://www.nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html

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

skodec
Offline
Зарегистрирован: 26.07.2015

Спасибо за справочник. Поизучал про копирование через memccpy - долго все это, не целесообразно выделять еще памяти для временного массива. Вобщем удалю все что связано с batdisp и оставлю как было раньше. 

arduinec
Offline
Зарегистрирован: 01.09.2015

skodec пишет:

На дисплее надо отображать заряд, ну как в телефоне.

http://arduino.ru/forum/programmirovanie/rusifikatsiya-biblioteki-adafru...
Там в примере OledSymbolTest показано как это можно сделать.

neyasbltb_88
Offline
Зарегистрирован: 19.01.2017

Я думаю, что тут основная проблема в том, что вы объявляете возвращаемое значение функции как float: float vbat() и пытаетесь в нее вернуть массив: return _batdisp;

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

ага. я сразу не смотрел весь код . А там мрак. Сама _batdisp это char, ей присваиваются указатели а возвращвется float и передается в display.drawBitmap которая указатель на буфер ждет. Оно вобще компилируется?

neyasbltb_88
Offline
Зарегистрирован: 19.01.2017

Logik пишет:

передается в display.drawBitmap которая указатель на буфер ждет.

Спасибо за наводку, я все думал, что же тут еще не так)) исправил тип переменной с char на int и все заработало!

Вот код для ТС, только я его под свой дисплей от Нокии 5110 адаптировал, но думаю, что разберется))

#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
#include <Wire.h>
//#define OLED_MOSI   9
//#define OLED_CLK   10
//#define OLED_DC    11
//#define OLED_CS    12
//#define OLED_RESET 8
//#define A1_PIN 1      // акб

Adafruit_PCD8544 display = Adafruit_PCD8544(8, 9, 10, 11, 12);
int Vcc = 7;
int Bl = 6;
int Gnd = 5;
//#if (SSD1306_LCDHEIGHT != 64)
//#error("Height incorrect, please fix Adafruit_SSD1306.h!");
//#endif

float vcc=3.5;
int vb;
//char _batdisp[48];
int _batdisp;

static  const unsigned char PROGMEM bat2 []= {    //24x16 66% батарейки
  0,0,0,
  63,255,255,
  63,255,255,  
  48,0,3,
  48,30,123,
  240,30,123,
  240,30,123,
  240,30,123,
  240,30,123,
  240,30,123,
  240,30,123,
  48,30,123,
  48,0,3, 
  63,255,255,
  63,255,255,
  0,0,0
};
static const unsigned char PROGMEM bat3 []= {    //24x16 100% батарейки
  0,0,0,
  63,255,255,
  63,255,255,  
  48,0,3,
  55,158,123,
  247,158,123,
  247,158,123,
  247,158,123,
  247,158,123,
  247,158,123,
  247,158,123,
  55,158,123,
  48,0,3, 
  63,255,255,
  63,255,255,
  0,0,0
};
static  const unsigned char PROGMEM bat1 []= {    //24x16 33% батарейки
  0,0,0,
  63,255,255,
  63,255,255,  
  48,0,3,
  48,0,123,
  240,0,123,
  240,0,123,
  240,0,123,
  240,0,123,
  240,0,123,
  240,0,123,
  48,0,123,
  48,0,3, 
  63,255,255,
  63,255,255,
  0,0,0
};
static const unsigned char PROGMEM bat0 []= {    //24x16 0% батарейки
  
  0,0,0,
  63,255,255,
  63,255,255,  
  48,0,3,
  48,0,3,
  240,0,3,
  240,0,3,
  240,0,3,
  240,0,3,
  240,0,3,
  240,0,3,
  48,0,3,
  48,0,3, 
  63,255,255,
  63,255,255,
  0,0,0
};
//void disp_on(){                       //функция вкл дисплея
// digitalWrite(7,HIGH);             //подаем питание на дисплей
// delay(1);
// display.begin(SSD1306_SWITCHCAPVCC);
//  display.clearDisplay();
//  delay(5);
//}
//float vbat(){                           //функция определения и отображения напряжения батареи
//    vb = analogRead(A1_PIN);
//    vcc = (vb* 5.00) / 1023.0;

//    return _batdisp;
//    }
void setup() { 
pinMode(Vcc, OUTPUT);
digitalWrite(Vcc, HIGH);
pinMode(Bl, OUTPUT);
analogWrite(Bl, 150);
pinMode(Gnd, OUTPUT);
digitalWrite(Gnd, LOW);
Serial.begin(9600);
//Serial.setTimeout(3000);
//i = sizeof(incomingBytes);
display.begin();
display.cp437(true);
display.setContrast(50);
display.setTextColor(BLACK);
display.clearDisplay();
display.display();
}
void loop() {
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(BLACK);
    display.setCursor(0,0);
// vbat();
    if(vcc>=3.4)
    {
      _batdisp=&bat3;
//      display.drawBitmap(0,0,bat3,24,16, 1);
    }
    if(vcc>=3.2 && vcc<3.4 )
    {
      _batdisp=&bat2;
      //display.drawBitmap(0,0,bat2,24,16, 1);
    }
    if(vcc>=3.0 && vcc<3.2 )
    {
      _batdisp=&bat1;
//     display.drawBitmap(0,0,bat1,24,16, 1);
    }
    if(vcc<3.0 )
    {
      _batdisp=&bat0;
//      display.drawBitmap(0,0,bat0,24,16, 1);
    }
    display.drawBitmap(0,0,_batdisp,24,16, 1);  
    display.display();
}

 

neyasbltb_88
Offline
Зарегистрирован: 19.01.2017

А вот у меня еще вопрос по этой теме: зачем надо было делать это _batdisp=&bat3;? Почему просто каждый раз не использовать display.drawBitmap(0,0,bat3,24,16, 1);? Это как то сказывается на расход батареи?

skodec
Offline
Зарегистрирован: 26.07.2015

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

neyasbltb_88 пишет:

А вот у меня еще вопрос по этой теме: зачем надо было делать это _batdisp=&bat3;? Почему просто каждый раз не использовать display.drawBitmap(0,0,bat3,24,16, 1);? Это как то сказывается на расход батареи?

Тогда картинка батарейки будет всегда заряжена, независимо от напряжения на аналоговом входе.

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

Ну и зашибись! Вечнозаряженый;)

Я так думаю, neyasbltb_88 имел ввиду что вместо _batdisp=... стр. 136,141,146 и 151 предпочтительней оставить вызовы, закоментированые на следующих строках. Дак нет, не лучше. Это и называется оптимизация. Т.к. организация вызова display.drawBitmap довольно ресурсоемка, то лучше вызывать его только раз передавая указатель через переменную, как приведено в примере.

Но если уж писать про оптимизацию, то надо и про float vcc; заметить. Нечего его в форме с плавающей запятой держать. Обязательно на фиксированую перейти. Самое верное - в форме как с analogRead прийдет - так и оставлять, а значения границ диапазонов определить константными выражениями, так чтоб в тексте проги задавать в миливольтах, а компилятор пересчитывал их в значения соответствующие получаемому с analogRead. Так и код короткий и человеку в программе удобно.