Кривые Безье

sadman41
Offline
Зарегистрирован: 19.10.2016

yul-i-an пишет:

Костыль на костыле. Может кто преобразовываль числа с плавающей точкой в строки?

см. dtostrf()

А длинный красивый switch проигрывает некрасивому длинному if-у по progmem space. Ну, у меня так было, во всяком случае.

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

Воще и приобразовывать чето в стринг - это тоже не в тему векторного шрифта, достаточно строку выводить.

Картинка к вчерашнему ночному спринту ;)

//А длинный красивый switch проигрывает некрасивому длинному if-у по progmem space.

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

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

Кривые Безье - оно конечно неплохо, но легко заметить что формат векторного описания сильно избыточен для шрифта. Потому в планирую cменить формат описания векторов на такой в котором:

 а. значения координат в диапазоне 0-31, для текущего шрифта достаточно и даже с запасом

 б. есть команды - аналоги SVG M и L, также есть команда вызова "библиотечной" последовательности, пусть команда P.  Она - для сжатия, одинаковые загогулины символов можна будет вынести в "библиотеку" и вызывать этой командой.

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

 г. команды аналоги SVG M и L задаются 2-я байтами, команда Р- одним.

 д.все символы разбиваем на группы по 32 символа. Одна группа хранится в одном массиве. всего на 256 символов получим 8 массивов,  но учитывая что символы с кодами 0-31 не юзаем - 7 массивов. Разумеется в progmem.

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

ж. Наличие групп в конкретном проекте - опционально. Нада только цифры - одна группа с векторным описанием цифр, нужна еще латиница - добавляем несколько групп (для строчных и/или заглавных). Кирилица - аналогично

з. указатели на массивы-группы символов хранятся в отдельном масиве (назовем массив групп) на 7 указателей (группы 0 - нету). Разумеется в progmem.

Таким образом алгоритм обработки векторного описания для прорисовки символа гдето такой:

1. Извлекаем из массива групп указатель на группу, соответствующую символу по индексу - старшие 3 бита кода символа.

2. Ищем в группе начало описания символа по его порядковому номеру перебирая группу, номер нужного символа - младшие 5 бит кода символа. При переборе достаточно читать первый байт - длинну векторного описани символа.

3. После нахождения нужного векторного описани обрабатываем команды М и L аналогично существующему. При нахождении команды P - обращаемся к "библиотеке" по индексу из команды. Структура библиотеки - аналогична структуре группы, но подробности (допустимость в ней тоже команды Р и вид координат, наверно относительные лучше будут) оговорю позже, для начала команду Р вобще можна не пользовать.

 

Получается чтоб добратся до описания символа надо будет из progmem прочитать указатель - 2 байта и пробежатся по группе - от 0 до 30 байт, в среднем 15. Думаю не тормознет сильно.

 

Вид векторного описани гдето так : LEN; CMD1; CMD2; ...CMDN;  где LEN - один байт на длину, CMD - команды, 1 байт для команды Р или 2 байта для М или L.

Вид команд:

00rxxxxx rrryyyyy - команда M

01rxxxxx rrryyyyy  - команда L

1nnnnnnn - команда Р

где xxxxx - 5 бит для координаты х; ууууу - 5 бит для координаты у; nnnnnnn - 7 бит для индекса в "библиотеке"; r - резерв, потом может пригодится, может разрядность х и/или у увеличить может на флаг из пункта "в" задействовать.

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

Еще пожалуй стоит принять что перед прорисовкой каждого символа по умолчанию делается команда М, 0, 0. Если она для какого символа нужна такая первой, то её можна не указывать. Экономим.

sadman41
Offline
Зарегистрирован: 19.10.2016

Logik пишет:

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

Так-то да, но по свичу я не увидел непрерывной последовательности. В массиве будут null-евые ячейки. Оправдано это или нет в данном случае - не знаю. У меня на рисовалке по семисегментному индикатору "дешевле" вышло if-ов нашмалять.

 

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

Ну чё у нас данном случае  null-евые ячейки? Нет реализации отрисовки данного символа, а если учесть что я вобщем так не символы а их группы, до 7 групп адресую (см#52) - то неприятность эту мы переживем. Получится нет заглавных кирилицы - ну  null ей в корму )))

а в составе существующей группы если нет реализации отрисовки данного символа - длина 0, один байт издержек. Всё продумано. Надеюсь ;)

 

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

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

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

yul-i-an пишет:
Я думаю что после того как нашли символ в группе необходимо в строке для вывода на дисплей посмотрет повторяется ли он. Если повторяется вывести его сразу чтобы не производить поиск снова.

Для этого нужно, чтобы все символы шрифта имели одинаковую ширину и не было кернинга. Но отказываться от пропорциональных шрифтов и от кернинга - это похерить всю прелесть использования векторных шрифтов. Чем они в этом случае лучше растровых?

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

yul-i-an пишет:
Я думаю что после того как нашли символ в группе необходимо в строке для вывода на дисплей посмотрет повторяется ли он.

Оно конечно можна, кеширование сделать, но не думаю что сильно ускорится. Основное время - на рисование прямых и выпихивание на экран. Рисование прямых можна ускорить если отдельно обрабатывать вертикали и горизонтали, а отдельно наклонные.

Я тут попробовал реализовать как описал. Чисто перекодировка строки в вызовы рисования прямых.


#define L_CMD_MSK (0b01000000)
#define M_CMD_MSK (0b00000000)
#define P_CMD_MSK (0b10000000)
#define CMD_MSK   (P_CMD_MSK | L_CMD_MSK | M_CMD_MSK)
#define X_MSK     (0b00011111)
#define Y_MSK     (0b00011111)

#define L_CMD(x,y)  (L_CMD_MSK | (X_MSK & x)),(Y_MSK & y)
#define M_CMD(x,y)  (M_CMD_MSK | (X_MSK & x)),(Y_MSK & y)
#define P_CMD(p)    (P_CMD_MSK | ((~P_CMD_MSK) & p))

#define ELM_X_MAX  18

const byte ElementLib[] PROGMEM={ 
                          8*2, M_CMD(0,6), L_CMD(2,3), L_CMD(4,1), L_CMD(6,0), L_CMD(ELM_X_MAX-6,0), L_CMD(ELM_X_MAX-3,2), L_CMD(ELM_X_MAX-1,4), L_CMD(ELM_X_MAX,6),
                          8*2, M_CMD(0,25),L_CMD(2,28),L_CMD(4,30),L_CMD(6,31),L_CMD(ELM_X_MAX-6,31),L_CMD(ELM_X_MAX-3,30),L_CMD(ELM_X_MAX-1,28),L_CMD(ELM_X_MAX,26),
};


const byte ElementNum[] PROGMEM={
                           0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                           3*2+2, P_CMD(0), L_CMD(ELM_X_MAX,25),P_CMD(1), M_CMD(0,6), L_CMD(0,25),  //0
                           5*2, M_CMD(4,25),   L_CMD(9,31),        L_CMD(9,0),    M_CMD(0,0), L_CMD(18,0),            //1
                           7*2+1, P_CMD(1), L_CMD(ELM_X_MAX,22),L_CMD(ELM_X_MAX-1,20),L_CMD(ELM_X_MAX-8,15),L_CMD(5,10),L_CMD(1,5),L_CMD(0,0),L_CMD(ELM_X_MAX,0), //2
                           0,0,0,0,0,0,0,0,0,0,0,0,0,             };


PGM_VOID_P const GroupsSym[] PROGMEM= {
                       ElementNum, NULL, NULL, NULL, NULL, NULL, NULL};

  byte Xn=0;
  byte Yn=0;
  
#define LINE(x0,y0,x,y) {Serial.print("x0=");Serial.print(x0);Serial.print("  y0=");Serial.print(y0);Serial.print("  x=");Serial.print(x);Serial.print(" y=");Serial.println(y);}


byte x0;
byte y0;

//выполнение команды, возвращает текущий x
byte RunCMD(byte cmd_x)
{
   PGM_P  g;
 
   g=(PGM_P)ElementLib;
   
   //пробежимся по группе, найдем описание нужного символа
   FindInGroup(&g, cmd_x & (~P_CMD_MSK));

   return RunVectDef(g);
}

//выполнение команды, возвращает текущий x
byte RunCMD(byte cmd_x, byte cmd_y)
{
  byte x;
  byte y;
  
    x=cmd_x & X_MSK;
    y=cmd_y & Y_MSK;
    
    if(cmd_x & L_CMD_MSK)
      LINE(Xn+x0,Yn+y0,Xn+x,Yn+y);
  

  x0=x;
  y0=y;  
  return x;
}

//отрисовка векторного описания 
byte RunVectDef(PGM_P  g)
{
    byte Xm;
    byte x;
    
    Xm=0;
  //первый байт - длинна, затем команды
  for(byte len=pgm_read_byte_near(g);len;len--)
  {
    g++;
    byte cmd_x=pgm_read_byte_near(g);

    if(cmd_x & P_CMD_MSK)
     x=RunCMD(cmd_x);
    else 
    {
       g++;
       byte cmd_y=pgm_read_byte_near(g);
       x=RunCMD(cmd_x,cmd_y);
       len--;
    }
   
    if(x>Xm) 
       Xm=x;
    
  }
 
  return Xm;
}

//ищем векторное описание с заданым номером в группе
void FindInGroup(PGM_P*  g, byte n)
{
  //пробежимся по группе, найдем описание нужного символа
  for(;n;n--)
  {
    *g+=pgm_read_byte_near(*g)+1;
  }
}

//выводим символ
void OutChar(char c)
{
  PGM_P  g;
  byte i;
  byte len;
 //Serial.print("OutChar ");Serial.println((byte)c);
  
  c-=32; //первые 32 символа нет
  memcpy_P(&g, GroupsSym+(c>>5),  sizeof(PGM_P));  //указатель на первый символ группы
 
  //пробежимся по группе, найдем описание нужного символа
  FindInGroup(&g, c & 0x1f);
 
  x0=0;
  y0=0;

  Xn+=2+RunVectDef(g);
}

//выводим строки
void OutStr(byte X, byte Y, char* s)
{
  byte i;
  
  Xn=X;
  Yn=Y;
  
  for(i=0;s[i];i++)
  {
    OutChar(s[i]);
  }
}

void setup() {
  // put your setup code here, to run once:

Serial.begin(57600);
Serial.println("FontVector");

//  int t=millis();
//  for(word i=1000;i;i--)
  {
  OutStr(0,0,"012");
  }
//Serial.print("t1000=");
//Serial.println(millis()-t);

}

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

}

Вывод на экран без экрана :) В порт. Вроде работает. Только надо символов набросать, возьму наверно пока из Вашего примера и доброшу позже, пусть и без сжатия.
Померил время - около 0,05мсек на символ. Это понятно без собственно прорисовки на экран (и разумеется без вывода в порт). Но судя по цифре предыдущего кода порядка 2мсек на символ то и нормально, прорисовка намного дольше чем код распаковки.

Да, про ширину символа - я её по ходу прорисовки определяю, как максимальный х, делаю отступ в два пикселя и следующий символ с этого места.

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

Попробовал с экраном, цифры 0,1,2 - мои большие, остальные Ваши, поменше.

https://youtu.be/uCLsGVeV2Q4

#include <SPI.h>
#include <Wire.h>
#include <avr/pgmspace.h>
#include <itoa.h>

#include "SH1106.h"
#define OLED_SCL_PIN 5
#define OLED_SDA_PIN 6
#define OLED_VCC_PIN 3
#define OLED_GND_PIN 4


ssd1306_i2c(OLED_SCL_PIN, OLED_SDA_PIN, myOLED) ;

#define L_CMD_MSK (0b01000000)
#define M_CMD_MSK (0b00000000)
#define P_CMD_MSK (0b10000000)
#define CMD_MSK   (P_CMD_MSK | L_CMD_MSK | M_CMD_MSK)
#define X_MSK     (0b00011111)
#define Y_MSK     (0b00011111)

#define L_CMD(x,y)  (L_CMD_MSK | (X_MSK & x)),(Y_MSK & y)
#define M_CMD(x,y)  (M_CMD_MSK | (X_MSK & x)),(Y_MSK & y)
#define P_CMD(p)    (P_CMD_MSK | ((~P_CMD_MSK) & p))

#define ELM_X_MAX  18

const byte ElementLib[] PROGMEM={ 
                          8*2, M_CMD(0,25), L_CMD(2,28), L_CMD(4,30), L_CMD(6,31), L_CMD(ELM_X_MAX-6,31), L_CMD(ELM_X_MAX-3,29), L_CMD(ELM_X_MAX-1,27), L_CMD(ELM_X_MAX,25),
                          8*2, M_CMD(0,6),L_CMD(2,3),L_CMD(4,1),L_CMD(6,0),L_CMD(ELM_X_MAX-6,0),L_CMD(ELM_X_MAX-3,1),L_CMD(ELM_X_MAX-1,3),L_CMD(ELM_X_MAX,5),
};


const byte ElementNum[] PROGMEM={
                           0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                           3*2+2, P_CMD(0), L_CMD(ELM_X_MAX,6),P_CMD(1), M_CMD(0,25), L_CMD(0,6),  //0
                           5*2, M_CMD(4,6),   L_CMD(9,0),        L_CMD(9,31),    M_CMD(0,31), L_CMD(18,31),            //1
                           7*2+1, P_CMD(1), L_CMD(ELM_X_MAX,9),L_CMD(ELM_X_MAX-1,11),L_CMD(ELM_X_MAX-8,16),L_CMD(5,21),L_CMD(1,26),L_CMD(0,31),L_CMD(ELM_X_MAX,31), //2
   
                         10*2, L_CMD(6, 0), L_CMD(8, 2), L_CMD(8, 6), L_CMD(6, 8), L_CMD(8, 10), L_CMD(8, 14), L_CMD(6, 16), L_CMD(0, 16), M_CMD(2, 8), L_CMD(6, 8), //3
                         5*2,L_CMD(0, 6), L_CMD(2, 8), L_CMD(8, 8), M_CMD(8, 0), L_CMD(8, 16), //4

                         8*2,M_CMD(8, 0), L_CMD(0, 0), L_CMD(0, 8), L_CMD(6, 8), L_CMD(8, 10), L_CMD(8, 14), L_CMD(6, 16), L_CMD(0, 16), //5
                         11*2,M_CMD(8, 2), L_CMD(6, 0), L_CMD(2, 0), L_CMD(0, 2), L_CMD(0, 14), L_CMD(2, 16), L_CMD(6, 16), L_CMD(8, 14), L_CMD(8, 12), L_CMD(8, 8), L_CMD(0, 8), //6
                 3*2,L_CMD(8, 0), L_CMD(8, 4), L_CMD(0, 16),

               16*2,M_CMD(2, 0), L_CMD(6, 0), L_CMD(8, 2), L_CMD(8, 6), L_CMD(6, 8), L_CMD(8, 10), L_CMD(8, 14), L_CMD(6, 16), L_CMD(2, 16), L_CMD(0, 14), L_CMD(0, 10), L_CMD(2, 8), L_CMD(0, 6), L_CMD(0, 2),  M_CMD(2, 8), L_CMD(6, 8),
             11*2,M_CMD(8, 8), L_CMD(2, 8), L_CMD(0, 6), L_CMD(0, 2), L_CMD(2, 0), L_CMD(6, 0), L_CMD(8, 2), L_CMD(8, 14), L_CMD(6, 16), L_CMD(2, 16), L_CMD(0, 14), 
           
         0,0,0,0,0,0,             };


PGM_VOID_P const GroupsSym[] PROGMEM= {
                       ElementNum, NULL, NULL, NULL, NULL, NULL, NULL};

  byte Xn=0;
  byte Yn=0;
  
//#define LINE(x0,y0,x,y) {Serial.print("x0=");Serial.print(x0);Serial.print("  y0=");Serial.print(y0);Serial.print("  x=");Serial.print(x);Serial.print(" y=");Serial.println(y);}
#define LINE(x0,y0,x,y) {myOLED.drawLine(x0, y0, x, y);}


byte x0;
byte y0;

//выполнение команды, возвращает текущий x
byte RunCMD(byte cmd_x)
{
   PGM_P  g;
 
   g=(PGM_P)ElementLib;
   
   //пробежимся по группе, найдем описание нужного символа, и отрисуем
   return RunVectDef(g, cmd_x & (~P_CMD_MSK));
}

//выполнение команды, возвращает текущий x
byte RunCMD(byte cmd_x, byte cmd_y)
{
  byte x;
  byte y;
  
    x=cmd_x & X_MSK;
    y=cmd_y & Y_MSK;
    
    if(cmd_x & L_CMD_MSK)
    {
      LINE(Xn+x0,Yn+y0,Xn+x,Yn+y);
    }

  x0=x;
  y0=y;  
  return x;
}

//отрисовка векторного описания с заданым номером в указаной группе
byte RunVectDef(PGM_P  g, byte n)
{
    byte Xm;
    byte x;
    
  //пробежимся по группе  
  FindInGroup(&g,n); 
  
  Xm=0;
  //первый байт - длинна, затем команды
  for(byte len=pgm_read_byte_near(g);len;len--)
  {
    g++;
    byte cmd_x=pgm_read_byte_near(g);

    if(cmd_x & P_CMD_MSK)
     x=RunCMD(cmd_x);
    else 
    {
       g++;
       byte cmd_y=pgm_read_byte_near(g);
       x=RunCMD(cmd_x,cmd_y);
       len--;
    }
   
    if(x>Xm) 
       Xm=x;
    
  }
 
  return Xm;
}

//ищем векторное описание с заданым номером в группе
void FindInGroup(PGM_P*  g, byte n)
{
  //пробежимся по группе, найдем описание нужного символа
  for(;n;n--)
  {
    *g+=pgm_read_byte_near(*g)+1;
  }
}

//выводим символ
void OutChar(char c)
{
  PGM_P  g;
  byte i;
  byte len;
 //Serial.print("OutChar ");Serial.println((byte)c);
  
  c-=32; //первые 32 символа нет
  memcpy_P(&g, GroupsSym+(c>>5),  sizeof(PGM_P));  //указатель на первый символ группы
 
  x0=0;
  y0=0;

  //пробежимся по группе, найдем описание нужного символа
 // FindInGroup(&g, c & 0x1f);
 

  Xn+=4+RunVectDef(g, c & 0x1f);
}

//выводим строки
void OutStr(byte X, byte Y, char* s)
{
  byte i;
  
  Xn=X;
  Yn=Y;
  
  for(i=0;s[i];i++)
  {
    OutChar(s[i]);
  }
}

void setup() {
  // put your setup code here, to run once:

  pinMode(OLED_GND_PIN, OUTPUT);
  digitalWrite(OLED_GND_PIN, LOW);
  pinMode(OLED_VCC_PIN, OUTPUT);
  digitalWrite(OLED_VCC_PIN, HIGH);
  delay(1);
  myOLED.begin();
  myOLED.clrScr();
  myOLED.setFont( SSD1306::FONT_SIZE_1); 
  myOLED.drawString(2,5,"FontVect");
  delay(500);

Serial.begin(57600);
Serial.println("FontVector");


}

void loop() {
  // put your main code here, to run repeatedly:
  
  uint8_t bufg[128*5];
  char c[12];

   myOLED.InitFrame(0,1,128,5, myOLED.FRAME_MODE_BUFER, bufg);
   memset(bufg, 0, sizeof(bufg));
   unsigned long startTime = millis();
//  int t=millis();
//  for(word i=1000;i;i--)
  {
      ltoa(analogRead(0),c,10);

  OutStr(0,0,c);
  }
//Serial.print("t1000=");
//Serial.println(millis()-t);
 myOLED.update();

  unsigned long totalTime = millis() - startTime;
  myOLED.setFont( SSD1306::FONT_SIZE_1);
  myOLED.drawString(0,7,"              ");  
  myOLED.drawString(6,7,c);  
  ltoa(totalTime,c,10);
  myOLED.drawString(0,7,c);  
  delay(250);
  
}

 

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

Отлично получилось.

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

Попробовал масштабировать. Отлично! От 40% до 200% и все замечательно.

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

Запустил Вашу версию на своем дисплее SSD1306

#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <avr/pgmspace.h>

#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

#define L_CMD_MSK (0b01000000)
#define M_CMD_MSK (0b00000000)
#define P_CMD_MSK (0b10000000)
#define CMD_MSK   (P_CMD_MSK | L_CMD_MSK | M_CMD_MSK)
#define X_MSK     (0b00011111)
#define Y_MSK     (0b00011111)

#define L_CMD(x,y)  (L_CMD_MSK | (X_MSK & x)),(Y_MSK & y)
#define M_CMD(x,y)  (M_CMD_MSK | (X_MSK & x)),(Y_MSK & y)
#define P_CMD(p)    (P_CMD_MSK | ((~P_CMD_MSK) & p))

#define ELM_X_MAX  18

const byte ElementLib[] PROGMEM = {
  8 * 2, M_CMD(0, 25), L_CMD(2, 28), L_CMD(4, 30), L_CMD(6, 31), L_CMD(ELM_X_MAX - 6, 31), L_CMD(ELM_X_MAX - 3, 29), L_CMD(ELM_X_MAX - 1, 27), L_CMD(ELM_X_MAX, 25),
  8 * 2, M_CMD(0, 6), L_CMD(2, 3), L_CMD(4, 1), L_CMD(6, 0), L_CMD(ELM_X_MAX - 6, 0), L_CMD(ELM_X_MAX - 3, 1), L_CMD(ELM_X_MAX - 1, 3), L_CMD(ELM_X_MAX, 5),
};

const byte ElementNum[] PROGMEM = {
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  3 * 2 + 2, P_CMD(0), L_CMD(ELM_X_MAX, 6), P_CMD(1), M_CMD(0, 25), L_CMD(0, 6), //0
  5 * 2, M_CMD(4, 6),  L_CMD(9, 0),        L_CMD(9, 31),    M_CMD(0, 31), L_CMD(18, 31),     //1
  7 * 2 + 1, P_CMD(1), L_CMD(ELM_X_MAX, 9), L_CMD(ELM_X_MAX - 1, 11), L_CMD(ELM_X_MAX - 8, 16), L_CMD(5, 21), L_CMD(1, 26), L_CMD(0, 31), L_CMD(ELM_X_MAX, 31), //2

  10 * 2, L_CMD(6, 0), L_CMD(8, 2), L_CMD(8, 6), L_CMD(6, 8), L_CMD(8, 10), L_CMD(8, 14), L_CMD(6, 16), L_CMD(0, 16), M_CMD(2, 8), L_CMD(6, 8), //3
  5 * 2, L_CMD(0, 6), L_CMD(2, 8), L_CMD(8, 8), M_CMD(8, 0), L_CMD(8, 16), //4

  8 * 2, M_CMD(8, 0), L_CMD(0, 0), L_CMD(0, 8), L_CMD(6, 8), L_CMD(8, 10), L_CMD(8, 14), L_CMD(6, 16), L_CMD(0, 16), //5
  11 * 2, M_CMD(8, 2), L_CMD(6, 0), L_CMD(2, 0), L_CMD(0, 2), L_CMD(0, 14), L_CMD(2, 16), L_CMD(6, 16), L_CMD(8, 14), L_CMD(8, 12), L_CMD(8, 8), L_CMD(0, 8), //6
  3 * 2, L_CMD(8, 0), L_CMD(8, 4), L_CMD(0, 16),

  16 * 2, M_CMD(2, 0), L_CMD(6, 0), L_CMD(8, 2), L_CMD(8, 6), L_CMD(6, 8), L_CMD(8, 10), L_CMD(8, 14), L_CMD(6, 16), L_CMD(2, 16), L_CMD(0, 14), L_CMD(0, 10), L_CMD(2, 8), L_CMD(0, 6), L_CMD(0, 2),  M_CMD(2, 8), L_CMD(6, 8),
  11 * 2, M_CMD(8, 8), L_CMD(2, 8), L_CMD(0, 6), L_CMD(0, 2), L_CMD(2, 0), L_CMD(6, 0), L_CMD(8, 2), L_CMD(8, 14), L_CMD(6, 16), L_CMD(2, 16), L_CMD(0, 14),

  0, 0, 0, 0, 0, 0,
};

PGM_VOID_P const GroupsSym[] PROGMEM = {
  ElementNum, NULL, NULL, NULL, NULL, NULL, NULL
};

byte Xn = 0;
byte Yn = 0;

#define LINE(x0,y0,x,y) {display.drawLine(x0, y0, x, y,WHITE);}
byte RunVectDef(PGM_P  g, byte n);
void FindInGroup(PGM_P*  g, byte n);

byte x0;
byte y0;

//выполнение команды, возвращает текущий x
byte RunCMD(byte cmd_x)
{
  PGM_P  g;

  g = (PGM_P)ElementLib;

  //пробежимся по группе, найдем описание нужного символа, и отрисуем
  return RunVectDef(g, cmd_x & (~P_CMD_MSK));
}

//выполнение команды, возвращает текущий x
byte RunCMD(byte cmd_x, byte cmd_y)
{
  byte x;
  byte y;

  x = cmd_x & X_MSK;
  y = cmd_y & Y_MSK;

  if (cmd_x & L_CMD_MSK)
  {
    LINE(Xn + x0, Yn + y0, Xn + x, Yn + y);
  }

  x0 = x;
  y0 = y;
  return x;
}

//отрисовка векторного описания с заданым номером в указаной группе
byte RunVectDef(PGM_P  g, byte n)
{
  byte Xm;
  byte x;

  //пробежимся по группе
  FindInGroup(&g, n);

  Xm = 0;
  //первый байт - длинна, затем команды
  for (byte len = pgm_read_byte_near(g); len; len--)
  {
    g++;
    byte cmd_x = pgm_read_byte_near(g);

    if (cmd_x & P_CMD_MSK)
      x = RunCMD(cmd_x);
    else
    {
      g++;
      byte cmd_y = pgm_read_byte_near(g);
      x = RunCMD(cmd_x, cmd_y);
      len--;
    }

    if (x > Xm)
      Xm = x;

  }

  return Xm;
}

//ищем векторное описание с заданым номером в группе
void FindInGroup(PGM_P*  g, byte n)
{
  //пробежимся по группе, найдем описание нужного символа
  for (; n; n--)
  {
    *g += pgm_read_byte_near(*g) + 1;
  }
}

//выводим символ
void OutChar(char c)
{
  PGM_P  g;
  byte i;
  byte len;
  //Serial.print("OutChar ");Serial.println((byte)c);

  c -= 32; //первые 32 символа нет
  memcpy_P(&g, GroupsSym + (c >> 5),  sizeof(PGM_P)); //указатель на первый символ группы

  x0 = 0;
  y0 = 0;

  //пробежимся по группе, найдем описание нужного символа
  // FindInGroup(&g, c & 0x1f);


  Xn += 4 + RunVectDef(g, c & 0x1f);
}

//выводим строки
void OutStr(byte X, byte Y, char* s)
{
  byte i;

  Xn = X;
  Yn = Y;

  for (i = 0; s[i]; i++)
  {
    OutChar(s[i]);
  }
}

void setup() {
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.display();
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(2, 5);
  display.println("VectFont");
  delay(5000);

//  Serial.begin(57600);
//  Serial.println("FontVector");


}

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

  uint8_t bufg[128 * 5];
  char c[12];

  //  myOLED.InitFrame(0, 1, 128, 5, myOLED.FRAME_MODE_BUFER, bufg);
  //  memset(bufg, 0, sizeof(bufg));
  unsigned long startTime = millis();
  //  int t=millis();
  //  for(word i=1000;i;i--)
  {
    ltoa(analogRead(0), c, 10);

    OutStr(0, 0, c);
  }
  //Serial.print("t1000=");
  //Serial.println(millis()-t);
  display.display();

 // unsigned long totalTime = millis() - startTime;
/*  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0, 7);
  //display.print("              ");
  display.print(c);
  display.setCursor(6, 7);
  display.print(totalTime);*/
  delay(250);
  display.clearDisplay();
}

Сижу вникаю, все работает.

 

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

И видео масштабирования https://youtu.be/i-GS8nJsbME

Код. Немного векторизацию цифр 6 и 2 правил.

#include <SPI.h>
#include <Wire.h>
#include <avr/pgmspace.h>
#include <itoa.h>

#include "SH1106.h"
#define OLED_SCL_PIN 5
#define OLED_SDA_PIN 6
#define OLED_VCC_PIN 3
#define OLED_GND_PIN 4


ssd1306_i2c(OLED_SCL_PIN, OLED_SDA_PIN, myOLED) ;

#define L_CMD_MSK (0b01000000)
#define M_CMD_MSK (0b00000000)
#define P_CMD_MSK (0b10000000)
#define CMD_MSK   (P_CMD_MSK | L_CMD_MSK | M_CMD_MSK)
#define X_MSK     (0b00011111)
#define Y_MSK     (0b00011111)

#define L_CMD(x,y)  (L_CMD_MSK | (X_MSK & x)),(Y_MSK & y)
#define M_CMD(x,y)  (M_CMD_MSK | (X_MSK & x)),(Y_MSK & y)
#define P_CMD(p)    (P_CMD_MSK | ((~P_CMD_MSK) & p))

#define ELM_X_MAX  18

const byte ElementLib[] PROGMEM={ 
                          8*2, M_CMD(0,25), L_CMD(2,28), L_CMD(4,30), L_CMD(6,31), L_CMD(ELM_X_MAX-6,31), L_CMD(ELM_X_MAX-3,29), L_CMD(ELM_X_MAX-1,27), L_CMD(ELM_X_MAX,25),
                          8*2, M_CMD(0,6),L_CMD(2,3),L_CMD(4,1),L_CMD(6,0),L_CMD(ELM_X_MAX-6,0),L_CMD(ELM_X_MAX-3,1),L_CMD(ELM_X_MAX-1,3),L_CMD(ELM_X_MAX,5),
};


const byte ElementNum[] PROGMEM={
                           0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    //   3*2+2, P_CMD(0), L_CMD(ELM_X_MAX,6),P_CMD(1), M_CMD(0,25), L_CMD(0,6),  //0
    //   5*2, M_CMD(4,6),   L_CMD(9,0),        L_CMD(9,31),    M_CMD(0,31), L_CMD(18,31),            //1
    //   7*2+1, P_CMD(1), L_CMD(ELM_X_MAX,9),L_CMD(ELM_X_MAX-1,11),L_CMD(ELM_X_MAX-8,16),L_CMD(5,21),L_CMD(1,26),L_CMD(0,31),L_CMD(ELM_X_MAX,31), //2
   9*2, M_CMD(0, 6), L_CMD(2, 0), L_CMD(6, 0), L_CMD(8, 6), L_CMD(8, 10), L_CMD(6, 16), L_CMD(2, 16), L_CMD(0, 10), L_CMD(0, 6),  //0
   3*2, M_CMD(8, 16), L_CMD(8, 0), L_CMD(0, 5),   //1
   10*2,M_CMD(0, 2), L_CMD(2, 0),L_CMD(6, 0), L_CMD(8, 2), L_CMD(8, 6), L_CMD(6, 8), L_CMD(2, 8), L_CMD(0, 10), L_CMD(0, 16),L_CMD(8, 16), //2

       10*2, L_CMD(6, 0), L_CMD(8, 2), L_CMD(8, 6), L_CMD(6, 8), L_CMD(8, 10), L_CMD(8, 14), L_CMD(6, 16), L_CMD(0, 16), M_CMD(2, 8), L_CMD(6, 8), //3
       5*2,  L_CMD(0, 6), L_CMD(2, 8), L_CMD(8, 8), M_CMD(8, 0), L_CMD(8, 16), //4
       8*2,  M_CMD(8, 0), L_CMD(0, 0), L_CMD(0, 8), L_CMD(6, 8), L_CMD(8, 10), L_CMD(8, 14), L_CMD(6, 16), L_CMD(0, 16), //5
       11*2, M_CMD(8, 2), L_CMD(6, 0), L_CMD(2, 0), L_CMD(0, 2), L_CMD(0, 14), L_CMD(2, 16), L_CMD(6, 16), L_CMD(8, 14), L_CMD(8, 10), L_CMD(6, 8), L_CMD(0, 8), //6
       3*2,  L_CMD(8, 0), L_CMD(8, 4), L_CMD(0, 16), //7
       17*2, M_CMD(2, 0), L_CMD(6, 0), L_CMD(8, 2), L_CMD(8, 6), L_CMD(6, 8), L_CMD(8, 10), L_CMD(8, 14), L_CMD(6, 16), L_CMD(2, 16), L_CMD(0, 14), L_CMD(0, 10), L_CMD(2, 8), L_CMD(0, 6), L_CMD(0, 2), L_CMD(2, 0),  M_CMD(2, 8), L_CMD(6, 8),
       11*2, M_CMD(8, 8), L_CMD(2, 8), L_CMD(0, 6), L_CMD(0, 2), L_CMD(2, 0), L_CMD(6, 0), L_CMD(8, 2), L_CMD(8, 14), L_CMD(6, 16), L_CMD(2, 16), L_CMD(0, 14), //9
   
       0,0,0,0,0,0,             };


PGM_VOID_P const GroupsSym[] PROGMEM= {
                       ElementNum, NULL, NULL, NULL, NULL, NULL, NULL};

  byte Xn=0;
  byte Yn=0;
  
//#define LINE(x0,y0,x,y) {Serial.print("x0=");Serial.print(x0);Serial.print("  y0=");Serial.print(y0);Serial.print("  x=");Serial.print(x);Serial.print(" y=");Serial.println(y);}
#define LINE(x0,y0,x,y) {myOLED.drawLine(x0, y0, x, y);}


  byte x0;
  byte y0;
  byte m=128;

//выполнение команды, возвращает текущий x
byte RunCMD(byte cmd_x)
{
   PGM_P  g;
 
   g=(PGM_P)ElementLib;
   
   //пробежимся по группе, найдем описание нужного символа, и отрисуем
   return RunVectDef(g, cmd_x & (~P_CMD_MSK));
}

//выполнение команды, возвращает текущий x
byte RunCMD(byte cmd_x, byte cmd_y)
{
  byte x;
  byte y;
  
    x=cmd_x & X_MSK;
    y=cmd_y & Y_MSK;
    
    x=(x*m)>>7;
    y=(y*m)>>7;
    
    if(cmd_x & L_CMD_MSK)
    {
      LINE(Xn+x0,Yn+y0,Xn+x,Yn+y);
    }

  x0=x;
  y0=y;  
  return x;
}

//отрисовка векторного описания с заданым номером в указаной группе
byte RunVectDef(PGM_P  g, byte n)
{
    byte Xm;
    byte x;
    
  //пробежимся по группе  
  FindInGroup(&g,n); 
  
  Xm=0;
  //первый байт - длинна, затем команды
  for(byte len=pgm_read_byte_near(g);len;len--)
  {
    g++;
    byte cmd_x=pgm_read_byte_near(g);

    if(cmd_x & P_CMD_MSK)
     x=RunCMD(cmd_x);
    else 
    {
       g++;
       byte cmd_y=pgm_read_byte_near(g);
       x=RunCMD(cmd_x,cmd_y);
       len--;
    }
   
    if(x>Xm) 
       Xm=x;
    
  }
 
  return Xm;
}

//ищем векторное описание с заданым номером в группе
void FindInGroup(PGM_P*  g, byte n)
{
  //пробежимся по группе, найдем описание нужного символа
  for(;n;n--)
  {
    *g+=pgm_read_byte_near(*g)+1;
  }
}

//выводим символ
void OutChar(char c)
{
  PGM_P  g;
  byte i;
  byte len;
 //Serial.print("OutChar ");Serial.println((byte)c);
  
  c-=32; //первые 32 символа нет
  memcpy_P(&g, GroupsSym+(c>>5),  sizeof(PGM_P));  //указатель на первый символ группы
 
  x0=0;
  y0=0;

  //пробежимся по группе, найдем описание нужного символа
 // FindInGroup(&g, c & 0x1f);
 

  Xn+=4+RunVectDef(g, c & 0x1f);
}

//выводим строки
void OutStr(byte X, byte Y, char* s)
{
  byte i;
  
  Xn=X;
  Yn=Y;
  
  for(i=0;s[i];i++)
  {
    OutChar(s[i]);
  }
}

void setup() {
  // put your setup code here, to run once:

  pinMode(OLED_GND_PIN, OUTPUT);
  digitalWrite(OLED_GND_PIN, LOW);
  pinMode(OLED_VCC_PIN, OUTPUT);
  digitalWrite(OLED_VCC_PIN, HIGH);
  delay(1);
  myOLED.begin();
  myOLED.clrScr();
  myOLED.setFont( SSD1306::FONT_SIZE_1); 
  myOLED.drawString(2,5,"FontVect");
  delay(500);

Serial.begin(57600);
Serial.println("FontVector");


}

void loop() {
  // put your main code here, to run repeatedly:
  
  uint8_t bufg[128*5];
  char c[12];

   unsigned long startTime = millis();
//  int t=millis();
//  for(word i=1000;i;i--)
  {
      ltoa(analogRead(0),c,10);
  for(byte i=0;i<=23;i++)
  {
    m=i*10+25;
    myOLED.InitFrame(0,1,128,5, myOLED.FRAME_MODE_BUFER, bufg);
   memset(bufg, 0, sizeof(bufg));
   OutStr(0,0,c);
 //Serial.print("t1000=");
//Serial.println(millis()-t);
 myOLED.update();
   delay(20);
 }
  }

  unsigned long totalTime = millis() - startTime;
  myOLED.setFont( SSD1306::FONT_SIZE_1);
  myOLED.drawString(0,7,"              ");  
  myOLED.drawString(6,7,c);  
  ltoa(totalTime,c,10);
  myOLED.drawString(0,7,c);  
  delay(250);
  
}

 

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

Смотреть приятно, растр курит.

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

Продолжаю мучать свою версию

#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <avr/pgmspace.h>

//SVG Команды
#define M 1 //стартовая точка
#define L 2 //линия
#define Q 3 //кривая 3 порядка
#define C 4 //кривая 4 порядка
#define S 5 //кривая S типа
#define V 6 //вертикальная линия
#define z 10 //замкнуть контур со стартовой точкой
#define Z 10 //замкнуть контур со стартовой точкой
//добавить фигуры (круг, прямоугольник элипс и т.п.
void setCursorVF(byte, byte);
void printVF(char);
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);
//byte st = 0; //шаги по массиву
//позиция курсора
byte cx = 0;
byte cy = 0;
//масштаб
double m = 0.5; //минимально читаемый 0.5
//векторное описание символов

//const PROGMEM uint8_t test[]  = {M,100,31.25,L,50,0,L,0,31.25,M,100,31.25,L,100,100,L,0,100,L,0,31.25,M,43.75,69.54,C,43.75,69.54,43.75,69.54,43.75,69.54,C,40.3,72.99,40.3,78.59,43.75,82.04,C,43.75,82.04,43.75,82.04,43.75,82.04,C,43.75,82.04,43.75,82.04,43.75,82.04,C,47.2,85.49,52.8,85.49,56.25,82.04,C,56.25,82.04,56.25,82.04,56.25,82.04,C,56.25,82.04,56.25,82.04,56.25,82.04,C,59.7,78.59,59.7,72.99,56.25,69.54,C,56.25,69.54,56.25,69.54,56.25,69.54,C,56.25,52.28,56.25,41.49,56.25,37.17,C,56.25,33.8,55.46,30.46,53.95,27.44,C,53.16,25.86,54.41,28.36,53.95,27.44,C,52.32,24.19,47.68,24.19,46.05,27.44,C,45.59,28.36,46.84,25.86,46.05,27.44,C,44.54,30.46,43.75,33.8,43.75,37.17,C,43.75,41.49,43.75,52.28,43.75,69.54,Z,M,93.75,93.75,L,93.75,33.17,L,50,6.25,L,6.25,33.83,L,6.25,93.75,L,93.75,93.75,Z,M,50,37.5,L,43.75,37.5,M,50,43.75,L,43.75,43.75,M,50,50,L,43.75,50,M,50,56.25,L,43.75,56.25,M,56.25,62.5,L,43.75,62.5,0
//};

//const PROGMEM uint8_t test2[]={M,23.03,8.9,C,19.22,1.5,8.71,1.33,4.67,8.6,C,3.92,9.95,6.44,5.4,4.52,8.86,C,2.25,12.96,1.96,17.87,3.73,22.2,C,5.05,25.42,8.34,33.46,13.6,46.32,C,18.98,33.24,22.34,25.07,23.68,21.8,C,25.37,17.7,25.17,13.07,23.14,9.13,C,21.34,5.62,23.69,10.19,23.03,8.9,Z,M,21.38,15.49,C,21.38,19.77,17.91,23.24,13.63,23.24,C,9.35,23.24,5.88,19.77,5.88,15.49,C,5.88,11.21,9.35,7.74,13.63,7.74,C,17.91,7.74,21.38,11.21,21.38,15.49,Z,0
//};
//Векторное описание символов шрифта
const PROGMEM uint8_t space[]  = {0};
const PROGMEM uint8_t comma[] = {M, 2, 16, L, 0, 18, 0};
const PROGMEM uint8_t d1[]  = {M, 4, 16, L, 4, 0, L, 0, 5, 0};
const PROGMEM uint8_t d2[]  = {M, 0, 0, L, 6, 0, L, 8, 2, L, 8, 6, L, 6, 8, L, 2, 8, L, 0, 10, L, 0, 16, L, 8, 16, 0};
const PROGMEM uint8_t d3[]  = {M, 0, 0, L, 6, 0, L, 8, 2, L, 8, 6, L, 6, 8, L, 8, 10, L, 8, 14, L, 6, 16, L, 0, 16, M, 2, 8, L, 6, 8, 0};
const PROGMEM uint8_t d4[] = {M, 0, 0, L, 0, 6, L, 2, 8, L, 8, 8, M, 8, 0, L, 8, 16, 0};
const PROGMEM uint8_t d5[] = {M, 8, 0, L, 0, 0, L, 0, 8, L, 6, 8, L, 8, 10, L, 8, 14, L, 6, 16, L, 0, 16, 0};
const PROGMEM uint8_t d6[] = {M, 8, 2, L, 6, 0, L, 2, 0, L, 0, 2, L, 0, 14, L, 2, 16, L, 6, 16, L, 8, 14, L, 8, 12, L, 8, 10, L, 6, 8, L, 0, 8, 0};
const PROGMEM uint8_t d7[] = {M, 0, 0, L, 8, 0, L, 8, 4, L, 0, 16, 0};
const PROGMEM uint8_t d8[] = {M, 2, 0, L, 6, 0, L, 8, 2, L, 8, 6, L, 6, 8, L, 8, 10, L, 8, 14, L, 6, 16, L, 2, 16, L, 0, 14, L, 0, 10, L, 2, 8, L, 0, 6, L, 0, 2, Z, M, 2, 8, L, 6, 8, 0};
const PROGMEM uint8_t d9[] = {M, 8, 8, L, 2, 8, L, 0, 6, L, 0, 2, L, 2, 0, L, 6, 0, L, 8, 2, L, 8, 14, L, 6, 16, L, 2, 16, L, 0, 14, 0};
const PROGMEM uint8_t d0[] = {M, 0, 6, L, 2, 0, L, 6, 0, L, 8, 6, L, 8, 10, L, 6, 16, L, 2, 16, L, 0, 10, Z, 0};
const PROGMEM uint8_t dot[] = {M, 0, 16, L, 0, 16, 0};
const PROGMEM uint8_t dDot[] = {M, 0, 12, L, 0, 12, M, 0, 4, L, 0, 4, 0};
const PROGMEM uint8_t minus[] = {M, 0, 8, L, 6, 8, 0};
const PROGMEM uint8_t plus[] = {M, 0, 8, L, 6, 8, M, 3, 5, L, 3, 11, 0};
const PROGMEM uint8_t lA[] = {M, 0, 16, L, 4, 0, L, 8, 16, M, 2, 11, L, 6, 11, 0};
const PROGMEM uint8_t lB[] = {M, 0, 8, L, 0, 0, L, 6, 0, L, 8, 2, L, 8, 6, L, 6, 8, L, 8, 10, L, 8, 14, L, 6, 16, L, 0, 16, L, 0, 8, L, 8, 8, 0};
const PROGMEM uint8_t lC[] = {M, 8, 2, L, 6, 0, L, 2, 0, L, 0, 2, L, 0, 14, L, 2, 16, L, 6, 16, L, 8, 14, 0};
const PROGMEM uint8_t lD[] = {M, 0, 0, L, 6, 0, L, 8, 2, L, 8, 14, L, 6, 16, L, 0, 16, Z, 0};
const PROGMEM uint8_t lE[] = {M, 8, 0, L, 0, 0, L, 0, 16, L, 8, 16, M, 0, 8, L, 6, 8, 0};
const PROGMEM uint8_t lF[] = {M, 8, 0, L, 0, 0, L, 0, 16, M, 0, 8, L, 6, 8, 0};
const PROGMEM uint8_t lG[] = {M, 8, 2, L, 6, 0, L, 2, 0, L, 0, 2, L, 0, 14, L, 2, 16, L, 6, 16, L, 8, 14, L, 8, 8, L, 5, 8, 0};
const PROGMEM uint8_t lH[] = {M, 0, 0, L, 0, 16, M, 8, 0, L, 8, 16, M, 0, 8, L, 8, 8, 0};
const PROGMEM uint8_t lI[] = {M, 0, 0, L, 8, 0, M, 4, 0, L, 4, 16, M, 0, 16, L, 8, 16, 0};
const PROGMEM uint8_t lJ[] = {M, 0, 0, L, 8, 0, L, 8, 14, L, 6, 16, L, 2, 16, L, 0, 14, 0};
const PROGMEM uint8_t lK[] = {M, 0, 0, L, 0, 16, M, 8, 0, L, 0, 8, L, 8, 16, 0};
const PROGMEM uint8_t lL[] = {M, 0, 0, L, 0, 16, L, 8, 16, 0};
const PROGMEM uint8_t lM[] = {M, 0, 16, L, 0, 0, L, 4, 10, L, 8, 0, L, 8, 16, 0};
const PROGMEM uint8_t lN[] = {M, 0, 16, L, 0, 0, L, 8, 16, L, 8, 0, 0};
const PROGMEM uint8_t lO[] = {M, 0, 2, L, 2, 0, L, 6, 0, L, 8, 2, L, 8, 14, L, 6, 16, L, 2, 16, L, 0, 14, Z, 0};
const PROGMEM uint8_t lP[] = {M, 0, 16, L, 0, 0, L, 6, 0, L, 8, 2, L, 8, 6, L, 6, 8, L, 0, 8, 0};
const PROGMEM uint8_t lQ[] = {M, 0, 2, L, 2, 0, L, 6, 0, L, 8, 2, L, 8, 14, L, 6, 16, L, 2, 16, L, 0, 14, Z, M, 4, 14, L, 8, 16, 0};
const PROGMEM uint8_t lR[] = {M, 0, 16, L, 0, 0, L, 6, 0, L, 8, 2, L, 8, 6, L, 6, 8, L, 0, 8, M, 4, 8, L, 8, 16, 0};
const PROGMEM uint8_t lS[] = {M, 8, 0, L, 2, 0, L, 0, 2, L, 0, 6, L, 2, 8, L, 6, 8, L, 8, 10, L, 8, 14, L, 6, 16, L, 0, 16, 0};
const PROGMEM uint8_t lT[] = {M, 0, 0, L, 8, 0, M, 4, 0, L, 4, 16, 0};
const PROGMEM uint8_t lU[] = {M, 0, 0, L, 0, 14, L, 2, 16, L, 6, 16, L, 8, 14, L, 8, 0, 0};
const PROGMEM uint8_t lV[] = {M, 0, 0, L, 4, 16, L, 8, 0, 0};
const PROGMEM uint8_t lW[] = {M, 0, 0, L, 2, 16, L, 4, 6, L, 6, 16, L, 8, 0, 0};
const PROGMEM uint8_t lX[] = {M, 0, 0, L, 8, 16, M, 8, 0, L, 0, 16, 0};
const PROGMEM uint8_t lY[] = {M, 0, 0, L, 4, 8, L, 4, 16, M, 4, 8, L, 8, 0, 0};
const PROGMEM uint8_t lZ[] = {M, 0, 0, L, 8, 0, L, 0, 16, L, 8, 16, 0};
const PROGMEM uint8_t la[] = {M, 2, 6, L, 6, 6, L, 8, 8, L, 8, 16, L, 2, 16, L, 0, 14, L, 0, 12, L, 2, 10, L, 8, 10, 0};
const PROGMEM uint8_t lb[] = {M, 0, 0, L, 0, 16, L, 6, 16, L, 8, 14, L, 8, 10, L, 6, 6, L, 0, 6, 0};
const PROGMEM uint8_t lc[] = {M, 8, 6, L, 2, 6, L, 0, 8, L, 0, 14, L, 2, 16, L, 8, 16, 0};
const PROGMEM uint8_t ld[] = {M, 8, 0, L, 8, 16, L, 2, 16, L, 0, 14, L, 0, 8, L, 2, 6, L, 8, 6, 0};
const PROGMEM uint8_t le[] = {M, 8, 16, L, 2, 16, L, 0, 14, L, 0, 8, L, 2, 6, L, 6, 6, L, 8, 8, L, 8, 12, L, 0, 12, 0};
const PROGMEM uint8_t lf[] = {M, 0, 10, L, 6, 10, M, 2, 16, L, 2, 2, L, 4, 0, L, 6, 0, L, 8, 2, 0};
const PROGMEM uint8_t lg[] = {M, 8, 13, L, 2, 13, L, 0, 12, L, 0, 8, L, 2, 6, L, 6, 6, L, 8, 8, L, 8, 14, L, 6, 16, L, 0, 16, 0};
const PROGMEM uint8_t lh[] = {M, 0, 0, L, 0, 16, M, 0, 6, L, 6, 6, L, 8, 8, L, 8, 16, 0};
const PROGMEM uint8_t li[] = {M, 0, 5, L, 0, 16, M, 0, 1, L, 0, 1, 0};
const PROGMEM uint8_t lj[] = {M, 4, 5, L, 4, 14, L, 2, 16, L, 0, 16, M, 4, 1, L, 4, 1, 0};
const PROGMEM uint8_t lk[] = {M, 0, 0, L, 0, 16, M, 0, 10, L, 6, 6, M, 3, 9, L, 8, 16, 0};
const PROGMEM uint8_t ll[] = {M, 0, 0, L, 0, 16, 0};
const PROGMEM uint8_t lm[] = {M, 0, 16, L, 0, 6, L, 6, 6, L, 8, 8, L, 8, 16, M, 4, 6, L, 4, 16, 0};
const PROGMEM uint8_t ln[] = {M, 0, 16, L, 0, 6, L, 6, 6, L, 8, 8, L, 8, 16, 0};
const PROGMEM uint8_t lo[] = {M, 0, 7, L, 2, 6, L, 6, 6, L, 8, 8, L, 8, 14, L, 6, 16, L, 2, 16, L, 0, 14, Z, 0};
const PROGMEM uint8_t lp[] = {M, 0, 16, L, 0, 6, L, 6, 6, L, 8, 8, L, 8, 10, L, 6, 12, L, 0, 12, 0};
const PROGMEM uint8_t lq[] = {M, 8, 6, L, 8, 16, M, 8, 10, L, 6, 12, L, 2, 12, L, 0, 10, L, 0, 8, L, 2, 6, L, 6, 6, L, 8, 8, 0};
const PROGMEM uint8_t lr[] = {M, 0, 6, L, 0, 16, M, 0, 8, L, 2, 6, L, 6, 6, L, 8, 8, 0};
const PROGMEM uint8_t ls[] = {M, 8, 8, L, 6, 6, L, 2, 6, L, 0, 8, L, 0, 9, L, 2, 11, L, 6, 11, L, 8, 13, L, 8, 14, L, 6, 16, L, 2, 16, L, 0, 14, 0};
const PROGMEM uint8_t lt[] = {M, 2, 0, L, 2, 14, L, 4, 16, L, 6, 16, L, 8, 14, M, 0, 6, L, 6, 6, 0};
const PROGMEM uint8_t lu[] = {M, 0, 6, L, 0, 14, L, 2, 16, L, 8, 16, L, 8, 6, 0};
const PROGMEM uint8_t lv[] = {M, 0, 6, L, 4, 16, L, 8, 6, 0};
const PROGMEM uint8_t lw[] = {M, 0, 6, L, 2, 16, L, 4, 10, L, 6, 16, L, 8, 6, 0};
const PROGMEM uint8_t lx[] = {M, 0, 6, L, 8, 16, M, 8, 6, L, 0, 16, 0};
const PROGMEM uint8_t ly[] = {M, 0, 6, L, 0, 10, L, 2, 12, L, 8, 12, M, 8, 6, L, 8, 14, L, 6, 16, L, 0, 16, 0};
const PROGMEM uint8_t lz[] = {M, 0, 6, L, 8, 6, L, 0, 16, L, 8, 16, 0};


void setup()   {
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.display();
  //delay(5);
}

void loop() {
  display.clearDisplay();

  setCursorVF(0, 0);
  //display.setCursor(0, 0);
  unsigned long startTime = millis();

  int n = analogRead(0);
  /*
    //вывод стандартными средствами
    display.print("ADC-0:");
    display.print(n);
    display.setCursor(0, 13);
    display.print("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
    display.print("abcdefghijklmnopqrstuvwxyz+-=;:.");*/
  //вывод векторами
  printVF("ADC-0:");
  printVF(n);
  setCursorVF(0, 13);
  printVF("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
  printVFln("abcdefghijklmnopqrstuvwxyz+-=;:.");
  //вывод на экран времени затраченного на прорисовку
  unsigned long totalTime = millis() - startTime;
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(64, 50);
  display.println(totalTime);
  //display.println(memoryFree());
  display.display();
  delay(500);
  display.clearDisplay();
}


///
extern int __bss_end;
extern void *__brkval;

// Функция, возвращающая количество свободного ОЗУ (RAM)
int memoryFree()
{
  int freeValue;
  if ((int)__brkval == 0)
    freeValue = ((int)&freeValue) - ((int)&__bss_end);
  else
    freeValue = ((int)&freeValue) - ((int)__brkval);
  return freeValue;
}

void PMRead( byte x[]) {
  /*  display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(0, 45);*/

#define interval 3//интервал между символами
  byte startPoint[2];//начальная точка линии
  byte lostPoint[2];//последняя (текущая) точка
  byte b, k = 0; //переменные
  byte xmax = 0;//максимальное по Х для расчета отступа
  while (b != 0)
  {
    b =  pgm_read_byte_near(x + k);//читаем из PROGMEM
    /*        display.print(b);
            display.print(",");
            display.display();
            //delay(100);*/
    /*   if (pgm_read_byte_near(x) != 10) {
         startPoint[0] = (pgm_read_byte_near(x) + cx);
         startPoint[1] = (pgm_read_byte_near(x + 1) + cy);
         k = k + 2;
       }*/
    if (b == M) {//M SVG
      byte *bufer = new byte[3];
      bufer[0] = b;//заносим в буфер команду
      bufer[1] = pgm_read_byte_near(x + k + 1) >> 1; //заносим в буфер
      bufer[2] = pgm_read_byte_near(x + k + 2) >> 1; //заносим в буфер
      startPoint[0] = bufer[1];
      startPoint[1] = bufer[2];
      lostPoint[0] = startPoint[0];
      lostPoint[1] = startPoint[1];
      k = k + 3;
      delete [] bufer; //удаление временного буфера
    }
    if (b == L) {//L SVG
      byte *bufer = new byte[5];//создаем динамический массив
      bufer[2] = b;//заносим в буфер команду
      bufer[0] = lostPoint[0];
      bufer[1] = lostPoint[1];
      bufer[3] = pgm_read_byte_near(x + k + 1) >> 1; //заносим в буфер
      bufer[4] = pgm_read_byte_near(x + k + 2) >> 1; //заносим в буфер
      lostPoint[0] = bufer[3];
      lostPoint[1] = bufer[4];
      display.drawLine(bufer[0]+cx, bufer[1]+cy, bufer[3] + cx, bufer[4] + cy, WHITE);
      if (bufer[0] > xmax) {
        xmax = bufer[0];
      }
      if (bufer[3] > xmax) {
        xmax = bufer[3];
      }
      k = k + 3;
      delete [] bufer; //удаление временного буфера
    }
    if (b == C) {//C SVG
      byte *bufer = new byte[9];//создаем динамический массив
      bufer[2] = b;//заносим в буфер команду
      bufer[0] = lostPoint[0];
      bufer[1] = lostPoint[1];
      bufer[3] = pgm_read_byte_near(x + k + 1) >> 1; //заносим в буфер
      bufer[4] = pgm_read_byte_near(x + k + 2) >> 1; //заносим в буфер
      bufer[5] = pgm_read_byte_near(x + k + 3) >> 1; //заносим в буфер
      bufer[6] = pgm_read_byte_near(x + k + 4) >> 1; //заносим в буфер
      bufer[7] = pgm_read_byte_near(x + k + 5) >> 1; //заносим в буфер
      bufer[8] = pgm_read_byte_near(x + k + 6) >> 1; //заносим в буфер
      lostPoint[0] = bufer[7];
      lostPoint[1] = bufer[8];
      display.drawCurve4p(bufer[0] + cx, bufer[1] + cy, bufer[3] + cx, bufer[4] + cy, bufer[5] + cx, bufer[6] + cy, bufer[7] + cx, bufer[8] + cy , WHITE);
      k = k + 7;
      delete [] bufer; //удаление временного буфера
    }
    if (b == Z) {//Z SVG
      display.drawLine(lostPoint[0] + cx, lostPoint[1] + cy, startPoint[0] + cx, startPoint[1] + cy, WHITE);
      k = k + 1;
    }
  }
  cx = cx + xmax + (interval);//отступ после каждого символа
  if (cx > (128) - 8) {//переход на следующую строку
    nl();
  }
}

void PMRead( byte x[]) {
  /*  display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(0, 45);*/

#define interval 3//интервал между символами
  byte startPoint[2];//начальная точка линии
  byte lostPoint[2];//последняя (текущая) точка
  byte b, k = 0; //переменные
  byte xmax = 0;//максимальное по Х для расчета отступа
  while (b != 0)
  {
    b =  pgm_read_byte_near(x + k);//читаем из PROGMEM
    /*        display.print(b);
            display.print(",");
            display.display();
            //delay(100);*/
    /*   if (pgm_read_byte_near(x) != 10) {
         startPoint[0] = (pgm_read_byte_near(x) + cx);
         startPoint[1] = (pgm_read_byte_near(x + 1) + cy);
         k = k + 2;
       }*/
    if (b == M) {//M SVG
      byte *bufer = new byte[3];
      bufer[0] = b;//заносим в буфер команду
      bufer[1] = pgm_read_byte_near(x + k + 1) >> 1; //заносим в буфер
      bufer[2] = pgm_read_byte_near(x + k + 2) >> 1; //заносим в буфер
      startPoint[0] = bufer[1];
      startPoint[1] = bufer[2];
      lostPoint[0] = startPoint[0];
      lostPoint[1] = startPoint[1];
      k = k + 3;
      delete [] bufer; //удаление временного буфера
    }
    if (b == L) {//L SVG
      byte *bufer = new byte[5];//создаем динамический массив
      bufer[2] = b;//заносим в буфер команду
      bufer[0] = lostPoint[0];
      bufer[1] = lostPoint[1];
      bufer[3] = pgm_read_byte_near(x + k + 1) >> 1; //заносим в буфер
      bufer[4] = pgm_read_byte_near(x + k + 2) >> 1; //заносим в буфер
      lostPoint[0] = bufer[3];
      lostPoint[1] = bufer[4];
      display.drawLine(bufer[0]+cx, bufer[1]+cy, bufer[3] + cx, bufer[4] + cy, WHITE);
      if (bufer[0] > xmax) {
        xmax = bufer[0];
      }
      if (bufer[3] > xmax) {
        xmax = bufer[3];
      }
      k = k + 3;
      delete [] bufer; //удаление временного буфера
    }
    if (b == C) {//C SVG
      byte *bufer = new byte[9];//создаем динамический массив
      bufer[2] = b;//заносим в буфер команду
      bufer[0] = lostPoint[0];
      bufer[1] = lostPoint[1];
      bufer[3] = pgm_read_byte_near(x + k + 1) >> 1; //заносим в буфер
      bufer[4] = pgm_read_byte_near(x + k + 2) >> 1; //заносим в буфер
      bufer[5] = pgm_read_byte_near(x + k + 3) >> 1; //заносим в буфер
      bufer[6] = pgm_read_byte_near(x + k + 4) >> 1; //заносим в буфер
      bufer[7] = pgm_read_byte_near(x + k + 5) >> 1; //заносим в буфер
      bufer[8] = pgm_read_byte_near(x + k + 6) >> 1; //заносим в буфер
      lostPoint[0] = bufer[7];
      lostPoint[1] = bufer[8];
      display.drawCurve4p(bufer[0] + cx, bufer[1] + cy, bufer[3] + cx, bufer[4] + cy, bufer[5] + cx, bufer[6] + cy, bufer[7] + cx, bufer[8] + cy , WHITE);
      k = k + 7;
      delete [] bufer; //удаление временного буфера
    }
    if (b == Z) {//Z SVG
      display.drawLine(lostPoint[0] + cx, lostPoint[1] + cy, startPoint[0] + cx, startPoint[1] + cy, WHITE);
      k = k + 1;
    }
  }
  cx = cx + xmax + (interval);//отступ после каждого символа
  if (cx > (128) - 8) {//переход на следующую строку
    nl();
  }
}

//вывод текста
void printVF(char txt[]) {
  byte symN = 0;
  while (txt[symN] != '\0') {
    char sym;//для хранения символа
    sym = txt[symN];
 sym = sym - 0;
    switch (sym) {
      case 32:
        PMRead(space);
        break;
      case 43:
        PMRead(plus);
        break;          
      case 44:
        PMRead(comma);
        break;        
      case 45:
        PMRead(minus);//-
        break;
      case 46:
        PMRead(dot);//.
        break;
      case 48:
        PMRead(d0);
        break;
      case 49:
      PMRead(d1);
        break;
      case 50:
      PMRead(d2);
        break;
      case 51:
        PMRead(d3);
        break;
      case 52:
        PMRead(d4);
        break;
      case 53:
        PMRead(d5);
        break;
      case 54:
        PMRead(d6);
        break;
      case 55:
        PMRead(d7);
        break;
      case 56:
        PMRead(d8);
        break;
      case 57:
        PMRead(d9);
        break;
      case 58:
        PMRead(dDot);//:
        break;
      case 65://A65
        PMRead(lA);
        break;
      case 66://B
        PMRead(lB);
        break;
      case 67://C
        PMRead(lC);
        break;
      case 68:
        PMRead(lD);
        break;
      case 69:
        PMRead(lE);
        break;
      case 70:
        PMRead(lF);
        break;
      case 71:
        PMRead(lG);
        break;
      case 72:
        PMRead(lH);
        break;
      case 73:
        PMRead(lI);
        break;
      case 74:
        PMRead(lJ);
        break;
      case 75:
        PMRead(lK);
        break;
      case 76:
        PMRead(lL);
        break;
      case 77:
        PMRead(lM);
        break;
      case 78:
        PMRead(lN);
        break;
      case 79:
        PMRead(lO);
        break;
      case 80:
        PMRead(lP);
        break;
      case 81:
        PMRead(lQ);
        break;
      case 82:
        PMRead(lR);
        break;
      case 83:
        PMRead(lS);
        break;
      case 84:
        PMRead(lT);
        break;
      case 85:
        PMRead(lU);
        break;
      case 86:
        PMRead(lV);
        break;
      case 87:
        PMRead(lW);
        break;
      case 88:
        PMRead(lX);
        break;
      case 89:
        PMRead(lY);
        break;
      case 90:
        PMRead(lZ);
        break;
      case 97:
        PMRead(la);
        break;
      case 98:
        PMRead(lb);
        break;
      case 99:
        PMRead(lc);
        break;
      case 100:
        PMRead(ld);
        break;
      case 101:
        PMRead(le);
        break;
      case 102:
        PMRead(lf);
        break;
      case 103:
        PMRead(lg);
        break;
      case 104:
        PMRead(lh);
        break;
      case 105:
        PMRead(li);
        break;
      case 106:
        PMRead(lj);
        break;
      case 107:
        PMRead(lk);
        break;
      case 108:
        PMRead(ll);
        break;
      case 109:
        PMRead(lm);
        break;
      case 110:
        PMRead(ln);
        break;
      case 111:
        PMRead(lo);
        break;
      case 112:
        PMRead(lp);
        break;
      case 113:
        PMRead(lq);
        break;
      case 114:
        PMRead(lr);
        break;
      case 115:
        PMRead(ls);
        break;
      case 116:
        PMRead(lt);
        break;
      case 117:
        PMRead(lu);
        break;
      case 118:
        PMRead(lv);
        break;
      case 119:
        PMRead(lw);
        break;
      case 120:
        PMRead(lx);
        break;
      case 121:
        PMRead(ly);
        break;
      case 122:
        PMRead(lz);
        break;
      default://если нет символа для вывода ставим пробел
        PMRead(space);
        break;
    }
    symN = symN + 1;//переходим к следующему символу
  }
}

void printVFln(char txt[]) {
  printVF(txt);
  nl();
}

Теперь в буфер читаю не весь массив с описанием символа, а только по одной команде. (в теории можно безболезненно увеличить длину принимаемых векторных описаний символов без забивания памяти.

Организовал вывод разноширинных символов. Масштабирование - вместо * на 0,5  применил здвиг вправо на 1. Скорость прорисовки теперь 23-24мс на 65 символов в отличии от прошлого кода который выводил тое самое за 35-37мсек (если пользоватся стандартными средствами библиотеки то вывод на 10мсек быстрее) при масштабироаании с помощью средств библиотеки не проаер

Думаю что шрифт с самого начало нужно было делать маленким, чтобы не сталкиватся с масштабированием т.к. маленкий чаще принимают.

 

 

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

yul-i-an пишет:

Теперь в буфер читаю не весь массив с описанием символа, а только по одной команде. (в теории можно безболезненно увеличить длину принимаемых векторных описаний символов без забивания памяти.

Очень правильно.

yul-i-an пишет:

масштабироаании с помощью средств библиотеки не проаер

А там просто получаются большие квадратные "пиксели". И прорисует их тоже не быстро.

 

yul-i-an пишет:

Думаю что шрифт с самого начало нужно было делать маленким, чтобы не сталкиватся с масштабированием т.к. маленкий чаще принимают.

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

Наилучшее решение - координаты хранить в байте и "масштаб" в байте. Перемножение байтовых значений быстрое, одной ассемблерной командой. Перемножение int - не один десятков команд. Со сдвигами разбирались когдато, сдвиги нормально на 1 бит,  сдвиги на много бит - плохо, реализует как цикл однобитных. Сдвиг на 8 и кратно 8 бит - очень хороше, просто байты перемещает. Неприятность в том что использовать перемножение на байт и сдвиг на 8 бит одновременно дает масштабы от 255/256 до 1/256 т.е. уменьшаем причем нет даже 1:1. Плохо. Как компромис - делаем байтное перемножение потом к результату прибавляем еще координту, получаем X*255+X=X*256, затем сдвигом деление на 256. Получаем масштабы от 256/256 (т.е. 1:1) до 2/256. И быстро работает. Другой подход - множим байтно и сдвиг вправо на 7, он вроде без циклов тоже. Масштабы 255/128 до 1/128. Я так делаю. И получается я могу хороше уменшать и увеличить пошти в 2 раза. Но для экрана с высотой 64 пикселя для максимального размера символа и маштабирования в 2 раза надо иметь высоту самого шрифта в 32 пикселя.

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

ПС. Проверил, да сдвиг вправо на 7 без циклов, строка x=(x*m)>>7; компактно компилится. Пример:

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

  x=millis();

      x=(x*m)>>7;
  Serial.println(x);
   
}

Компилируется в

000000be <loop>:
  be:	0e 94 c7 00 	call	0x18e	; 0x18e <millis>
  c2:	86 2f       	mov	r24, r22
  c4:	60 91 10 01 	lds	r22, 0x0110
  c8:	68 9f       	mul	r22, r24
  ca:	b0 01       	movw	r22, r0
  cc:	11 24       	eor	r1, r1
  ce:	66 0f       	add	r22, r22
  d0:	67 2f       	mov	r22, r23
  d2:	66 1f       	adc	r22, r22
  d4:	77 0b       	sbc	r23, r23
  d6:	82 ea       	ldi	r24, 0xA2	; 162
  d8:	91 e0       	ldi	r25, 0x01	; 1
  da:	4a e0       	ldi	r20, 0x0A	; 10
  dc:	50 e0       	ldi	r21, 0x00	; 0
  de:	0e 94 13 04 	call	0x826	; 0x826 <_ZN5Print7printlnEhi>
  e2:	08 95       	ret

А если сдвиг на 6 то уже с циклами, честно 6 раз прокрутит однобитный сдвиг :(

000000be <loop>:
  be:	0e 94 c8 00 	call	0x190	; 0x190 <millis>
  c2:	86 2f       	mov	r24, r22
  c4:	60 91 10 01 	lds	r22, 0x0110
  c8:	68 9f       	mul	r22, r24
  ca:	b0 01       	movw	r22, r0
  cc:	11 24       	eor	r1, r1
  ce:	86 e0       	ldi	r24, 0x06	; 6
  d0:	75 95       	asr	r23
  d2:	67 95       	ror	r22
  d4:	8a 95       	dec	r24
  d6:	e1 f7       	brne	.-8      	; 0xd0 <loop+0x12>
  d8:	82 ea       	ldi	r24, 0xA2	; 162
  da:	91 e0       	ldi	r25, 0x01	; 1
  dc:	4a e0       	ldi	r20, 0x0A	; 10
  de:	50 e0       	ldi	r21, 0x00	; 0
  e0:	0e 94 14 04 	call	0x828	; 0x828 <_ZN5Print7printlnEhi>
  e4:	08 95  

 

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

Эксперементировал с курсивом

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

Прикольно, на второй фотке вполне годно. Тоже про курсив думал. А еще и про "болд". Прорисовать символ с его координаты и повторно прорисовать сдвинув по горизонтали на 1. Должно с жирными вертикалями получится.

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

Попробовал. Было #define LINE(x0,y0,x,y) {myOLED.drawLine(x0, y0, x, y);} и

 

Поменял на #define LINE(x0,y0,x,y) {myOLED.drawLine(x0, y0, x, y);myOLED.drawLine(x0+1, y0, x+1, y);;}

И стал болд ))

Глазками различие намного заметней, светящуюся линию камера утолщает. Очень годно для подсветки активного пункта меню, на монохроме это проблема, инверсия не смотрится совсем.
Пробовал и в 3 линии рисовать, жирно, для наблюдения издалека самое оно.
Время отрисовки такой строки выросло на 2мсек (на экране разница 1573-1546=27мсек, но там 14 циклов масштабирования и делей на 100 в каждом), пустяк вобщем. Без болда было 10мсек, болд- 12мсек. 
Вобщем по времени расклад у меня такой буфер 640байт, выводится по i2c на 800КГц( в реале немного меньше) за 7,5мсек, формирование в буфере каринки из линий около 2мсек, ну и 0,5мсек на все остальное, включая масштабирование.
Теперь у меня есть 32 первых символа таблицы в форме 8*16, заняли 239байт + библиотека заняла 103байта. Оптимизацию с выносом элементов в библиотеку делал ручками, это плохо и не оптимально. В среднем 11 байт на символ, растровый 8*16 было бы ровно 16 байт. Экстраполируя и учитывая что буквы проще и больше повторяющихся элементов, получится что все 256-32=224 символа должны в 2КБ влезть.  
Вобщем возможности технологии понятны целиком и полностю.
yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

Тоже попробовал, неплохо получается.

Вопрос есть. Где можно взять голую библиотеку для OLED которая только пикселы может выводить? Чтобы на её основе свою сколхозить. Думаю этот материал использовать.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

yul-i-an пишет:

Где можно взять голую библиотеку для OLED которая только пикселы может выводить? Чтобы на её основе свою сколхозить. Думаю этот материал использовать.

Собственно, непосредственно на экран символы выводить невозможно.

Поэтому для пиксельной графики используется буферизация.

Ну а вывод пикселя в буфер от экрана никак не зависит. Поэтому, собственно, библиотека не нужна, нужна одна функция - вывод пикселя, которая сводится к установке одного бита в байте по вычисленному адресу. Т.е. вся "библиотека" - одна строка.

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

Буду разбиратся! Спасибо.

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

andriano пишет:

yul-i-an пишет:

Где можно взять голую библиотеку для OLED которая только пикселы может выводить? Чтобы на её основе свою сколхозить. Думаю этот материал использовать.

Собственно, непосредственно на экран символы выводить невозможно.

Поэтому для пиксельной графики используется буферизация.

Ну а вывод пикселя в буфер от экрана никак не зависит. Поэтому, собственно, библиотека не нужна, нужна одна функция - вывод пикселя, которая сводится к установке одного бита в байте по вычисленному адресу. Т.е. вся "библиотека" - одна строка.

Ну не все так просто, еще инитить нужно.

Вывод пикселя у меня так.

void SSD1306Graphic::_Pixel(uint8_t x, uint8_t y, uint8_t operation)
{
        byte* p=&Canva[((y>>3)*Width)+x];
        byte b=*p;
        byte m=_BV(y & 7);

        switch (operation)
        {
        case 0: b&= ~m;break;
        case 1: b|=  m;break;
        case 2: b^=  m;break;
        }

        *p=b;
}

Вывод буфера, это FRAME_MODE_BUFER

void SSD1306Graphic::SetModeUpdate(void)
{
    sendTWIcommand(SSD1306_MEMORY_ADDR_MODE);
    sendTWIcommand(0x00);

    sendTWIcommand(SSD1306_SET_COLUMN_ADDR);
    sendTWIcommand(Left);
    sendTWIcommand(Left+Width-1);

    sendTWIcommand(SSD1306_SET_PAGE_ADDR);
    sendTWIcommand(Top);
    sendTWIcommand(Top+Pages-1);

    sendStart(SSD1306_ADDR<<1);
    writeByte(SSD1306_DATA_CONTINUE);
}

void SSD1306Graphic::update(void)
{
	switch(FrameMode)
	{
		case FRAME_MODE_PGM:updatePGM();break;
		case FRAME_MODE_CALLBACK:updateCallBack();break;
		case FRAME_MODE_BUFER:updateBuf();break;
	}
}

void SSD1306Graphic::updateBuf(void)
{
    if(!Canva)
        return;
   SetModeUpdate();

    for (int b=0; b<Width*Pages; b++)		// Send data
    {
        writeByte(Canva[b]);
    }

    sendStop();

}

ПС. "Собственно, непосредственно на экран символы выводить невозможно." - чего вдруг? Все возможно, 

        for (uint8_t i =0; i<5; addr++,i++ ) 
        {
           writeByte(pgm_read_byte(addr));
         }

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

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Logik пишет:

ПС. "Собственно, непосредственно на экран символы выводить невозможно." - чего вдруг? Все возможно,

Опечатка. Следует читать, естественно, "пиксели" - собственно именно о них и шла речь.

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

А с пикселем, не все так просто. Как видно из кода вывод идет побайтно, т.е. сразу по 8 пикселей. И вобщем вывести сам один пиксель можна, но возникает вопрос а чё делать с остальными 7 пикселями. И тут есть 2 подхода: 1. взять их из буфера, в таком случае буфер необходим. 2. определить их каким либо образом, ведь както мы ж их в коде определяем, это бывает не так просто, как непросто в случае с линиями векторного шрифта, но принципиально возможно. Тогда и без буфера можна.

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

Добавил латиницу и немного извращений. https://youtu.be/Omc9WdDXeWE  

А всегото вывод линий стал 

#define LINE(x0,y0,x,y) {byte b0=y0+((((x0)-64)*((x0)-64))>>7);byte b=y+((((x)-64)*((x)-64))>>7); \
                         myOLED.drawLine(x0, b0, x, b);}
 
yul-i-an
yul-i-an аватар
Offline
Зарегистрирован: 10.12.2012

Logik пишет:

Добавил латиницу и немного извращений. https://youtu.be/Omc9WdDXeWE  

А всегото вывод линий стал 

#define LINE(x0,y0,x,y) {byte b0=y0+((((x0)-64)*((x0)-64))>>7);byte b=y+((((x)-64)*((x)-64))>>7); \
                         myOLED.drawLine(x0, b0, x, b);}
 

Заработал лайк! Прикольно получилось. Напомнило как в старых играх имена победителей вводились. Кольцо символов врощаеш пока нужный в фокус не встанет, затем выбираеш и для ввода следующего опять вращаеш...

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

Еще немного фото

Цифры

Цифры

Цифры Bold + Italic

Цифры Bold

Заглавные латиница

Заглавные латиница

Заглавные латиница Bold

Строчные латиница

Максимальная высота символов 18 пикселей.

Когда Bold прорисовываю, горизонтальные линии пропускаю для ускорения прорисовки.

Размер шрифта задаю в пикселях

//размер шрифта в пикселях
void setTextSize(double s) {
  m = s / 16;
}
m - глобальная

Осталось только в библиотеку затолкать. Незнаю с чего начать. Хачу что-то вроде adafruit_gfx. Может знатоки подскажут с чего начать...?

Код всего безобразия

#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <avr/pgmspace.h>

//SVG Команды
#define M 1 //стартовая точка
#define L 2 //линия
#define Q 3 //кривая 3 порядка
#define C 4 //кривая 4 порядка
#define S 5 //кривая S типа
#define V 6 //вертикальная линия
#define z 10 //замкнуть контур со стартовой точкой
#define Z 10 //замкнуть контур со стартовой точкой
//добавить фигуры (круг, прямоугольник элипс и т.п.
void setCursorVF(byte, byte);
void printVF(char);
void setTextSize(double);
void printVFln(char);
void nl();
//int it(int, int);
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);
//позиция курсора
int cx = 0;
int cy = 0;
//масштаб
double m = 1; //минимально читаемый 0.5
boolean bold = 0; //признак BOLD
boolean italic = 0; //признак ITALIC
//векторное описание символов

//const PROGMEM uint8_t test[]  = {M,100,31.25,L,50,0,L,0,31.25,M,100,31.25,L,100,100,L,0,100,L,0,31.25,M,43.75,69.54,C,43.75,69.54,43.75,69.54,43.75,69.54,C,40.3,72.99,40.3,78.59,43.75,82.04,C,43.75,82.04,43.75,82.04,43.75,82.04,C,43.75,82.04,43.75,82.04,43.75,82.04,C,47.2,85.49,52.8,85.49,56.25,82.04,C,56.25,82.04,56.25,82.04,56.25,82.04,C,56.25,82.04,56.25,82.04,56.25,82.04,C,59.7,78.59,59.7,72.99,56.25,69.54,C,56.25,69.54,56.25,69.54,56.25,69.54,C,56.25,52.28,56.25,41.49,56.25,37.17,C,56.25,33.8,55.46,30.46,53.95,27.44,C,53.16,25.86,54.41,28.36,53.95,27.44,C,52.32,24.19,47.68,24.19,46.05,27.44,C,45.59,28.36,46.84,25.86,46.05,27.44,C,44.54,30.46,43.75,33.8,43.75,37.17,C,43.75,41.49,43.75,52.28,43.75,69.54,Z,M,93.75,93.75,L,93.75,33.17,L,50,6.25,L,6.25,33.83,L,6.25,93.75,L,93.75,93.75,Z,M,50,37.5,L,43.75,37.5,M,50,43.75,L,43.75,43.75,M,50,50,L,43.75,50,M,50,56.25,L,43.75,56.25,M,56.25,62.5,L,43.75,62.5,0
//};

//const PROGMEM uint8_t test2[]={M,23.03,8.9,C,19.22,1.5,8.71,1.33,4.67,8.6,C,3.92,9.95,6.44,5.4,4.52,8.86,C,2.25,12.96,1.96,17.87,3.73,22.2,C,5.05,25.42,8.34,33.46,13.6,46.32,C,18.98,33.24,22.34,25.07,23.68,21.8,C,25.37,17.7,25.17,13.07,23.14,9.13,C,21.34,5.62,23.69,10.19,23.03,8.9,Z,M,21.38,15.49,C,21.38,19.77,17.91,23.24,13.63,23.24,C,9.35,23.24,5.88,19.77,5.88,15.49,C,5.88,11.21,9.35,7.74,13.63,7.74,C,17.91,7.74,21.38,11.21,21.38,15.49,Z,0
//};
//Векторное описание символов шрифта
const PROGMEM uint8_t space[]  = {0};
const PROGMEM uint8_t comma[] = {M, 2, 16, L, 0, 18, 0};
const PROGMEM uint8_t d1[]  = {M, 0, 4, L, 4, 0, L, 4, 16, 0};
//const PROGMEM uint8_t d2[]  = {M, 0, 0, L, 6, 0, L, 8, 2, L, 8, 6, L, 6, 8, L, 2, 8, L, 0, 10, L, 0, 16, L, 8, 16, 0};
const PROGMEM uint8_t d2[]  = {M, 0, 0, L, 8, 0, L, 8, 6, L, 6, 8, L, 0, 8, L, 0, 16, L, 8, 16, 0};
const PROGMEM uint8_t d3[]  = {M, 0, 0, L, 8, 0, L, 8, 6, L, 6, 8, L, 8, 8, L, 8, 14, L, 6, 16, L, 0, 16, M, 0, 8, L, 6, 8, 0};
const PROGMEM uint8_t d4[] = {M, 8, 16, L, 8, 0, L, 0, 10, L, 8, 10, 0};
//const PROGMEM uint8_t d5[] = {M, 8, 0, L, 0, 0, L, 0, 8, L, 6, 8, L, 8, 10, L, 8, 14, L, 6, 16, L, 0, 16, 0};
const PROGMEM uint8_t d5[] = {M, 8, 0, L, 0, 0, L, 0, 8, L, 8, 8, L, 8, 14, L, 6, 16, L, 0, 16, 0};
//const PROGMEM uint8_t d6[] = {M, 8, 2, L, 6, 0, L, 2, 0, L, 0, 2, L, 0, 14, L, 2, 16, L, 6, 16, L, 8, 14, L, 8, 12, L, 8, 10, L, 6, 8, L, 0, 8, 0};
const PROGMEM uint8_t d6[] = {M, 8, 0, L, 2, 0, L, 0, 2, L, 0, 16, L, 6, 16, L, 8, 14, L, 8, 8, L, 0, 8, 0};
const PROGMEM uint8_t d7[] = {M, 0, 0, L, 8, 0, L, 0, 16, 0};
const PROGMEM uint8_t d8[] = {M, 2, 0, L, 6, 0, L, 8, 2, L, 8, 6, L, 6, 8, L, 8, 10, L, 8, 14, L, 6, 16, L, 2, 16, L, 0, 14, L, 0, 10, L, 2, 8, L, 0, 6, L, 0, 2, Z, M, 2, 8, L, 6, 8, 0};
//const PROGMEM uint8_t d9[] = {M, 8, 8, L, 2, 8, L, 0, 6, L, 0, 2, L, 2, 0, L, 6, 0, L, 8, 2, L, 8, 14, L, 6, 16, L, 2, 16, L, 0, 14, 0};
const PROGMEM uint8_t d9[] = {M, 8, 8, L, 0, 8, L, 0, 2, L, 2, 0, L, 8, 0, L, 8, 14, L, 6, 16, L, 0, 16, 0};
const PROGMEM uint8_t d0[] = {M, 0, 14, L, 0, 2, L, 2, 0, L, 6, 0, L, 8, 2, L, 8, 14, L, 6, 16, L, 2, 16, L, 0, 14, L, 8, 2, 0};
const PROGMEM uint8_t dot[] = {M, 0, 16, L, 0, 16, 0};
const PROGMEM uint8_t dDot[] = {M, 0, 12, L, 0, 12, M, 0, 4, L, 0, 4, 0};
const PROGMEM uint8_t minus[] = {M, 0, 8, L, 6, 8, 0};
const PROGMEM uint8_t plus[] = {M, 0, 8, L, 6, 8, M, 3, 5, L, 3, 11, 0};
const PROGMEM uint8_t lA[] = {M, 0, 16, L, 0, 2, L, 2, 0, L, 6, 0, L, 8, 2, L, 8, 16, M, 0, 10, L, 8, 10, 0};
const PROGMEM uint8_t lB[] = {M, 0, 8, L, 0, 0, L, 6, 0, L, 8, 2, L, 8, 6, L, 6, 8, L, 8, 10, L, 8, 14, L, 6, 16, L, 0, 16, L, 0, 8, L, 6, 8, 0};
const PROGMEM uint8_t lC[] = {M, 8, 2, L, 6, 0, L, 2, 0, L, 0, 2, L, 0, 14, L, 2, 16, L, 6, 16, L, 8, 14, 0};
const PROGMEM uint8_t lD[] = {M, 0, 0, L, 6, 0, L, 8, 2, L, 8, 14, L, 6, 16, L, 0, 16, Z, 0};
const PROGMEM uint8_t lE[] = {M, 8, 0, L, 2, 0, L, 0, 2, L, 0, 14, L, 2, 16, L, 8, 16, M, 0, 8, L, 6, 8, 0};
const PROGMEM uint8_t lF[] = {M, 8, 0, L, 2, 0, L, 0, 2, L, 0, 16, M, 0, 8, L, 6, 8, 0};
const PROGMEM uint8_t lG[] = {M, 8, 0, L, 2, 0, L, 0, 2, L, 0, 14, L, 2, 16, L, 6, 16, L, 8, 14, L, 8, 8, L, 5, 8, 0};
const PROGMEM uint8_t lH[] = {M, 0, 0, L, 0, 16, M, 8, 0, L, 8, 16, M, 0, 8, L, 8, 8, 0};
const PROGMEM uint8_t lI[] = {M, 0, 0, L, 8, 0, M, 4, 0, L, 4, 16, M, 0, 16, L, 8, 16, 0};
const PROGMEM uint8_t lJ[] = {M, 8, 0, L, 8, 14, L, 6, 16, L, 2, 16, L, 0, 14, 0};
const PROGMEM uint8_t lK[] = {M, 0, 0, L, 0, 16, M, 0, 8, L, 6, 8, L, 8, 6, L, 8, 0, M, 6, 8, L, 8, 10, L, 8, 16, 0};
const PROGMEM uint8_t lL[] = {M, 0, 0, L, 0, 14, L, 2, 16, L, 8, 16, 0};
const PROGMEM uint8_t lM[] = {M, 0, 16, L, 0, 0, L, 5, 7, L, 10, 0, L, 10, 16, 0};
const PROGMEM uint8_t lN[] = {M, 0, 16, L, 0, 0, L, 8, 16, L, 8, 0, 0};
const PROGMEM uint8_t lO[] = {M, 0, 2, L, 2, 0, L, 6, 0, L, 8, 2, L, 8, 14, L, 6, 16, L, 2, 16, L, 0, 14, Z, 0};
const PROGMEM uint8_t lP[] = {M, 0, 16, L, 0, 0, L, 6, 0, L, 8, 2, L, 8, 6, L, 6, 8, L, 0, 8, 0};
const PROGMEM uint8_t lQ[] = {M, 0, 2, L, 2, 0, L, 6, 0, L, 8, 2, L, 8, 14, L, 6, 16, L, 2, 16, L, 0, 14, Z, M, 4, 10, L, 8, 16, 0};
const PROGMEM uint8_t lR[] = {M, 0, 16, L, 0, 0, L, 6, 0, L, 8, 2, L, 8, 6, L, 6, 8, L, 0, 8, M, 6, 8, L, 8, 16, 0};
const PROGMEM uint8_t lS[] = {M, 8, 0, L, 2, 0, L, 0, 2, L, 0, 8, L, 8, 8, L, 8, 14, L, 6, 16, L, 0, 16, 0};
const PROGMEM uint8_t lT[] = {M, 0, 0, L, 8, 0, M, 4, 0, L, 4, 16, 0};
const PROGMEM uint8_t lU[] = {M, 0, 0, L, 0, 14, L, 2, 16, L, 6, 16, L, 8, 14, L, 8, 0, 0};
const PROGMEM uint8_t lV[] = {M, 0, 0, L, 4, 16, L, 8, 0, 0};
const PROGMEM uint8_t lW[] = {M, 0, 0, L, 0, 16, L, 5, 10, L, 10, 16, L, 10, 0, 0};
const PROGMEM uint8_t lX[] = {M, 0, 0, L, 8, 16, M, 8, 0, L, 0, 16, 0};
const PROGMEM uint8_t lY[] = {M, 0, 0, L, 0, 8, L, 2, 10, L, 6, 10, L, 8, 8, L, 8, 0, M, 4, 10, L, 4, 16, 0};
const PROGMEM uint8_t lZ[] = {M, 0, 0, L, 8, 0, L, 0, 16, L, 8, 16, 0};
const PROGMEM uint8_t la[] = {M, 2, 6, L, 6, 6, L, 8, 8, L, 8, 16, L, 2, 16, L, 0, 14, L, 0, 12, L, 2, 10, L, 8, 10, 0};
const PROGMEM uint8_t lb[] = {M, 0, 0, L, 0, 16, L, 6, 16, L, 8, 14, L, 8, 10, L, 6, 6, L, 0, 6, 0};
const PROGMEM uint8_t lc[] = {M, 8, 6, L, 2, 6, L, 0, 8, L, 0, 14, L, 2, 16, L, 8, 16, 0};
const PROGMEM uint8_t ld[] = {M, 8, 0, L, 8, 16, L, 2, 16, L, 0, 14, L, 0, 8, L, 2, 6, L, 8, 6, 0};
const PROGMEM uint8_t le[] = {M, 8, 16, L, 2, 16, L, 0, 14, L, 0, 8, L, 2, 6, L, 6, 6, L, 8, 8, L, 8, 12, L, 0, 12, 0};
const PROGMEM uint8_t lf[] = {M, 0, 10, L, 6, 10, M, 2, 16, L, 2, 2, L, 4, 0, L, 6, 0, L, 8, 2, 0};
const PROGMEM uint8_t lg[] = {M, 8, 13, L, 2, 13, L, 0, 12, L, 0, 8, L, 2, 6, L, 6, 6, L, 8, 8, L, 8, 14, L, 6, 16, L, 0, 16, 0};
const PROGMEM uint8_t lh[] = {M, 0, 0, L, 0, 16, M, 0, 6, L, 6, 6, L, 8, 8, L, 8, 16, 0};
const PROGMEM uint8_t li[] = {M, 0, 5, L, 0, 16, M, 0, 1, L, 0, 1, 0};
const PROGMEM uint8_t lj[] = {M, 4, 5, L, 4, 14, L, 2, 16, L, 0, 16, M, 4, 1, L, 4, 1, 0};
const PROGMEM uint8_t lk[] = {M, 0, 0, L, 0, 16, M, 0, 10, L, 6, 6, M, 3, 9, L, 8, 16, 0};
const PROGMEM uint8_t ll[] = {M, 0, 0, L, 0, 16, 0};
const PROGMEM uint8_t lm[] = {M, 0, 16, L, 0, 6, L, 6, 6, L, 8, 8, L, 8, 16, M, 4, 6, L, 4, 16, 0};
const PROGMEM uint8_t ln[] = {M, 0, 16, L, 0, 6, L, 6, 6, L, 8, 8, L, 8, 16, 0};
const PROGMEM uint8_t lo[] = {M, 0, 7, L, 2, 6, L, 6, 6, L, 8, 8, L, 8, 14, L, 6, 16, L, 2, 16, L, 0, 14, Z, 0};
const PROGMEM uint8_t lp[] = {M, 0, 16, L, 0, 6, L, 6, 6, L, 8, 8, L, 8, 10, L, 6, 12, L, 0, 12, 0};
const PROGMEM uint8_t lq[] = {M, 8, 6, L, 8, 16, M, 8, 10, L, 6, 12, L, 2, 12, L, 0, 10, L, 0, 8, L, 2, 6, L, 6, 6, L, 8, 8, 0};
const PROGMEM uint8_t lr[] = {M, 0, 6, L, 0, 16, M, 0, 8, L, 2, 6, L, 6, 6, L, 8, 8, 0};
const PROGMEM uint8_t ls[] = {M, 8, 8, L, 6, 6, L, 2, 6, L, 0, 8, L, 0, 9, L, 2, 11, L, 6, 11, L, 8, 13, L, 8, 14, L, 6, 16, L, 2, 16, L, 0, 14, 0};
const PROGMEM uint8_t lt[] = {M, 2, 0, L, 2, 14, L, 4, 16, L, 6, 16, L, 8, 14, M, 0, 6, L, 6, 6, 0};
const PROGMEM uint8_t lu[] = {M, 0, 6, L, 0, 14, L, 2, 16, L, 8, 16, L, 8, 6, 0};
const PROGMEM uint8_t lv[] = {M, 0, 6, L, 4, 16, L, 8, 6, 0};
const PROGMEM uint8_t lw[] = {M, 0, 6, L, 0, 16, L, 4, 10, L, 8, 16, L, 8, 6, 0};
const PROGMEM uint8_t lx[] = {M, 0, 6, L, 8, 16, M, 8, 6, L, 0, 16, 0};
const PROGMEM uint8_t ly[] = {M, 0, 6, L, 0, 10, L, 2, 12, L, 8, 12, M, 8, 6, L, 8, 14, L, 6, 16, L, 0, 16, 0};
const PROGMEM uint8_t lz[] = {M, 0, 6, L, 8, 6, L, 0, 16, L, 8, 16, 0};


void setup()   {
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.display();
  //delay(5);
}

void loop() {
  display.clearDisplay();
  setCursorVF(0, 0);
  unsigned long startTime = millis();
  int n = analogRead(0);
  //вывод векторами
  setTextSize(18);
  bold = 0;
  italic = 0;
  setCursorVF(0, 0);
  //printVFln("0123456789");
  //printVF("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
  printVF("Analog-");
  printVF(n);
  setTextSize(10);
  setCursorVF(0, 23);
  bold = 1;
  italic = 0;
  printVF("Bold font");
  bold = 0;
  italic = 1;
  setCursorVF(0, 36);
  printVF("Italic font");
  bold = 0;
  italic = 0;
  setCursorVF(0, 49);
  //printVF("0123456789");
  printVF("Normal font");
  //printVF("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
  //printVFln("abcdefghijklmnopqrstuvwxyz+-=;:.,");
  //italic = 0;
  //вывод на экран времени затраченного на прорисовку
  unsigned long totalTime = millis() - startTime;
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(110, 50);
  display.println(totalTime);
  //display.println(memoryFree());
  display.display();
  delay(500);
  display.clearDisplay();
}


///
extern int __bss_end;
extern void *__brkval;

// Функция, возвращающая количество свободного ОЗУ (RAM)
int memoryFree()
{
  int freeValue;
  if ((int)__brkval == 0)
    freeValue = ((int)&freeValue) - ((int)&__bss_end);
  else
    freeValue = ((int)&freeValue) - ((int)__brkval);
  return freeValue;
}

void PMRead(byte x[]) {
  byte interval = 3; //интервал между символами
  int startPoint[2];//начальная точка линии
  int lostPoint[2];//последняя (текущая) точка
  byte b, k = 0; //переменные
  int xmax = -10;//максимальное по Х для расчета отступа
  while (b != 0)
  {
    b =  pgm_read_byte_near(x + k);//читаем из PROGMEM
    if (b == M) {//M SVG
      int *bufer = new int[2];
      bufer[0] = pgm_read_byte_near(x + k + 1) * m; //заносим в буфер
      bufer[1] = pgm_read_byte_near(x + k + 2) * m; //заносим в буфер
      if (italic) {
        bufer[0] = bufer[0] - 0.2 * bufer[1] + (bufer[0] * 0.2);
      }
      if (bufer[0] > xmax) {
        xmax = bufer[0];
      }
      startPoint[0] = bufer[0];
      startPoint[1] = bufer[1];
      lostPoint[0] = startPoint[0];
      lostPoint[1] = startPoint[1];
      k = k + 3;
      delete [] bufer; //удаление временного буфера
    }
    if (b == L) {//L SVG
      int *bufer = new int[2];//создаем динамический массив
      bufer[0] = pgm_read_byte_near(x + k + 1) * m; //заносим в буфер
      bufer[1] = pgm_read_byte_near(x + k + 2) * m; //заносим в буфер
      if (italic) {
        bufer[0] = bufer[0] - 0.2 * bufer[1] + (bufer[0] * 0.2);
      }
      if (bufer[0] > xmax) {
        xmax = bufer[0];
      }
      display.drawLine(lostPoint[0] + cx, lostPoint[1] + cy, bufer[0] + cx, bufer[1] + cy, WHITE);
      if (bold) {
        if (lostPoint[1] != bufer[1]) {//если линия горизонтальная то не рисуем
          display.drawLine(lostPoint[0] + cx + 1, lostPoint[1] + cy, bufer[0] + cx + 1, bufer[1] + cy, WHITE);
        }
      }
      lostPoint[0] = bufer[0];
      lostPoint[1] = bufer[1];
      k = k + 3;
      delete [] bufer; //удаление временного буфера
    }
    /*   if (b == C) {//C SVG
      byte *bufer = new byte[9];//создаем динамический массив
      bufer[2] = b;//заносим в буфер команду
      bufer[0] = lostPoint[0];
      bufer[1] = lostPoint[1];
      bufer[3] = pgm_read_byte_near(x + k + 1) *m; //заносим в буфер
      bufer[4] = pgm_read_byte_near(x + k + 2) *m; //заносим в буфер
      bufer[5] = pgm_read_byte_near(x + k + 3) *m; //заносим в буфер
      bufer[6] = pgm_read_byte_near(x + k + 4) *m; //заносим в буфер
      bufer[7] = pgm_read_byte_near(x + k + 5) *m; //заносим в буфер
      bufer[8] = pgm_read_byte_near(x + k + 6) *m; //заносим в буфер
      lostPoint[0] = bufer[7];
      lostPoint[1] = bufer[8];
      display.drawCurve4p(bufer[0] + cx, bufer[1] + cy, bufer[3] + cx, bufer[4] + cy, bufer[5] + cx, bufer[6] + cy, bufer[7] + cx, bufer[8] + cy , WHITE);
      k = k + 7;
      delete [] bufer; //удаление временного буфера
      }*/
    if (b == Z) {//Z SVG
      display.drawLine(lostPoint[0] + cx, lostPoint[1] + cy, startPoint[0] + cx, startPoint[1] + cy, WHITE);
      if (bold) {
        if (lostPoint[1] != startPoint[1]) {
          display.drawLine(lostPoint[0] + cx + 1, lostPoint[1] + cy, startPoint[0] + cx + 1, startPoint[1] + cy, WHITE);
        }
      }
      k = k + 1;
    }
  }
  //отступы
  if (bold) {
    interval = 4;
  }
  cx = cx + xmax + interval;
  //cx = cx + ((interval*m)+2)-(interval-xmax);
  /* if (italic) {
     cx = cx + xmax + interval; //отступ после каждого символа
    }
    if (bold) {
     cx = cx + xmax + interval; //отступ после каждого символа
    }
    if (italic == 0 && bold == 0)
    {
     cx = cx  + xmax + interval; //отступ после каждого символа
    }*/
  xmax = 0;
  if (cx > 128 - 8*m) {//переход на следующую строку
    nl();
  }
}

int it(int a, int b) {
  int c =0;
  c = a - 0.2 * b + (b * 0.2);
  return c;
}

// Функция преобразования числа в строку
void printVF(int n)
{
  char buffer [12];
  itoa (n, buffer, 10);
  printVF(buffer);
}

void printVF(double n)
{
  char buffer [12];
  int a; //числитель
  int b; //знаменатель
  //округляем
  int c = n * 100;
  //получаем числитель
  a = (c / 100) % 1000;
  itoa (a, buffer, 10);
  printVF(buffer);
  printVF(".");
  //получем знаменатель
  b = abs(c % 100);
  itoa (b, buffer, 10);
  printVF(buffer);
}

// Функция преобразования числа в строку
void printVF(unsigned int n)
{
  // byte *buffer = new char[12];
  char buffer [12];
  itoa (n, buffer, 10);
  printVF(buffer);
  //  delete [] bufer; //удаление временного буфера
}

//вывод текста
void printVF(char txt[]) {
  byte symN = 0;
  while (txt[symN] != '\0') {
    char sym;//для хранения символа
    sym = txt[symN];
    sym = sym - 0;
    switch (sym) {
      case 32:
        PMRead(space);
        cx = cx + 12;
        break;
      case 43:
        PMRead(plus);
        break;
      case 44:
        PMRead(comma);
        //cx = cx + 2;
        break;
      case 45:
        PMRead(minus);//-
        break;
      case 46:
        PMRead(dot);//.
        //cx = cx + 2;
        break;
      case 48:
        PMRead(d0);
        break;
      case 49:
        PMRead(d1);
        break;
      case 50:
        PMRead(d2);
        break;
      case 51:
        PMRead(d3);
        break;
      case 52:
        PMRead(d4);
        break;
      case 53:
        PMRead(d5);
        break;
      case 54:
        PMRead(d6);
        break;
      case 55:
        PMRead(d7);
        break;
      case 56:
        PMRead(d8);
        break;
      case 57:
        PMRead(d9);
        break;
      case 58:
        PMRead(dDot);//:
        //cx = cx + 2;
        break;
      case 65://A65
        PMRead(lA);
        break;
      case 66://B
        PMRead(lB);
        break;
      case 67://C
        PMRead(lC);
        break;
      case 68:
        PMRead(lD);
        break;
      case 69:
        PMRead(lE);
        break;
      case 70:
        PMRead(lF);
        break;
      case 71:
        PMRead(lG);
        break;
      case 72:
        PMRead(lH);
        break;
      case 73:
        PMRead(lI);
        break;
      case 74:
        PMRead(lJ);
        break;
      case 75:
        PMRead(lK);
        break;
      case 76:
        PMRead(lL);
        break;
      case 77:
        PMRead(lM);
        break;
      case 78:
        PMRead(lN);
        break;
      case 79:
        PMRead(lO);
        break;
      case 80:
        PMRead(lP);
        break;
      case 81:
        PMRead(lQ);
        break;
      case 82:
        PMRead(lR);
        break;
      case 83:
        PMRead(lS);
        break;
      case 84:
        PMRead(lT);
        break;
      case 85:
        PMRead(lU);
        break;
      case 86:
        PMRead(lV);
        break;
      case 87:
        PMRead(lW);
        break;
      case 88:
        PMRead(lX);
        break;
      case 89:
        PMRead(lY);
        break;
      case 90:
        PMRead(lZ);
        break;
      case 97:
        PMRead(la);
        break;
      case 98:
        PMRead(lb);
        break;
      case 99:
        PMRead(lc);
        break;
      case 100:
        PMRead(ld);
        break;
      case 101:
        PMRead(le);
        break;
      case 102:
        PMRead(lf);
        break;
      case 103:
        PMRead(lg);
        break;
      case 104:
        PMRead(lh);
        break;
      case 105:
        PMRead(li);
        break;
      case 106:
        PMRead(lj);
        break;
      case 107:
        PMRead(lk);
        break;
      case 108:
        PMRead(ll);
        break;
      case 109:
        PMRead(lm);
        break;
      case 110:
        PMRead(ln);
        break;
      case 111:
        PMRead(lo);
        break;
      case 112:
        PMRead(lp);
        break;
      case 113:
        PMRead(lq);
        break;
      case 114:
        PMRead(lr);
        break;
      case 115:
        PMRead(ls);
        break;
      case 116:
        PMRead(lt);
        break;
      case 117:
        PMRead(lu);
        break;
      case 118:
        PMRead(lv);
        break;
      case 119:
        PMRead(lw);
        break;
      case 120:
        PMRead(lx);
        break;
      case 121:
        PMRead(ly);
        break;
      case 122:
        PMRead(lz);
        break;
      default://если нет символа для вывода ставим прочерк
        PMRead(minus);
        break;
    }
    symN = symN + 1;//переходим к следующему символу
  }
}

void printVFln(char txt[]) {
  printVF(txt);
  nl();
}

//установка курсора
void setCursorVF(byte x, byte y) {
  cx = x;
  if (italic) {
    cx = x + 2;
  }
  cy = y;
}

//переход на след строку
void nl() {
  cx = 0;
  cy = cy + (m * 16) + 4;//16-высота символа в вект описании, 
  //cy = cy + 4;
}

//размер шрифта в пикселях
void setTextSize(double s) {
  m = s / 16;
}

 

b707
Онлайн
Зарегистрирован: 26.05.2017

Юлиан - описание фонта лучше делать в виде двумерного массива, где первый инлекс - указатель по коду ASCII. Тогда этот огромный switch -case начния со строки 322 можно будет выкинуть

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

yul-i-an пишет:

Еще немного фото

Цифры

 

ифры Bold + Italic

 

Заглавные латиница

 

Заглавные латиница Bold

 

трочные латиница

 

yul-i-an, возможны два варианта:

1. Вас сразу же начнут донимать насчет кириллицы.

2. Вас не начнут донимать.

При этом "2" безусловно означает, что Ваша идея осталась невостребованной.

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

b707 пишет:

Юлиан - описание фонта лучше делать в виде двумерного массива, где первый инлекс - указатель по коду ASCII. Тогда этот огромный switch -case начния со строки 322 можно будет выкинуть

Про свичь +1. Но двумерный то зачем? Ну коды символов не от нуля, та к делаем -0х20 и усьо. Да, есть в реализации шрифтов пропуски символов, хотя вобще их конечно быть не должно, ну будут 0. Всеравно на них потратится памяти в progmem менше чем на двумерный.

Юлиан, кстати, а где кирилица ;) По бартеру - символы недостающие  из "цифровых", правда форматы у нас не совпадают, но решаемо.

/*!*/    2+1 , L_CMD(0, 12),P_CMD(17),
/*"*/   2*2+1, P_CMD(10), M_CMD(3, 0), L_CMD(3, 2),
/*#*/   4*2+1, P_CMD(12), M_CMD(2, 4), L_CMD(1, 10), M_CMD(4, 4), L_CMD(3, 10),  
///*$*/   4*2+2, P_CMD(3),M_CMD(0,2), L_CMD(0, 4), P_CMD(2), M_CMD(4,0), L_CMD(3, 16),
/*$*/   8*2+1, M_CMD(7, 4), L_CMD(5, 2),  L_CMD(2, 2),  L_CMD(0, 4),L_CMD(0, 6),
               L_CMD(7, 9), P_CMD(13), M_CMD(4, 0), L_CMD(3, 15),
/*%*/   8*2+2, L_CMD(2, 0),L_CMD(2, 2),P_CMD(10),L_CMD(0, 0),
                M_CMD(4, 13),L_CMD(4, 15),L_CMD(6, 15),L_CMD(6, 13),L_CMD(4, 13),P_CMD(14),
/*&*/   6*2+1, P_CMD(13), L_CMD(6, 4), L_CMD(5, 2), L_CMD(3, 2), L_CMD(2, 3), L_CMD(2, 5), L_CMD(7, 14),
/*'*/   1,     P_CMD(10),
/*(*/   3*2+1, M_CMD(2, 0), L_CMD(0, 4), P_CMD(18), L_CMD(2, 15),
/*)*/   2*2+1, L_CMD(2, 4),L_CMD(2, 11),P_CMD(6),
/***/   4*2+1, P_CMD(9), M_CMD(0, 11), L_CMD(6, 3), M_CMD(0, 3), L_CMD(6, 11),
/*+*/   1,     P_CMD(9),
/*,*/   2+1,   M_CMD(1, 13), P_CMD(6),
/*-*/   1,     P_CMD(8),
/*.*/   3*2+1, P_CMD(17), L_CMD(1, 15), L_CMD(1, 14), L_CMD(0, 14),
/* / */ 1,     P_CMD(14),


/*:*/   3*2+2, P_CMD(11), L_CMD(0, 12), P_CMD(18), L_CMD(1, 11), L_CMD(1, 12),
/*;*/     2,   P_CMD(11), P_CMD(6),
/*<*/   3*2,   M_CMD(4,4), L_CMD(0, 8), L_CMD(4, 12),
/*=*/   1,     P_CMD(12),
/*>*/   3*2,   M_CMD(0,4), L_CMD(4, 8), L_CMD(0, 12),
/*?*/   4*2+1, P_CMD(0), L_CMD(5, 9), L_CMD(4, 13), M_CMD(4, 15), L_CMD(4, 15)             };


    /*  0  */        2*2+1, P_CMD(3), L_CMD(8, 5), L_CMD(6, 7),
    /*  1  */        2*2+2, P_CMD(0), L_CMD(2, 7), L_CMD(0, 5), P_CMD(10),
    /*  2  */        5*2  , L_CMD(8, 9), L_CMD(8, 13), L_CMD(6, 15), L_CMD(2, 15), L_CMD(0, 13),
    /*  3  */        4*2  , M_CMD(0, 2), L_CMD(2, 0),  L_CMD(6, 0),  L_CMD(8, 2), //
    /*  4  */        2*2  , L_CMD(0, 9), L_CMD(2, 7),
    /*  5  */        4*2+1, L_CMD(0, 7), L_CMD(3, 6),L_CMD(5, 6),L_CMD(7, 7),P_CMD(2),
    /*  6  */        2    , L_CMD(0, 15),
    /*  7  */        2    , M_CMD(8, 0),
    /*  8  */        2*2  , M_CMD(0, 7), L_CMD(6, 7),
    /*  9  */        2*2+1, P_CMD(8), M_CMD(3, 3), L_CMD(3, 11),
    /* 10  */        2    , L_CMD(0, 2),
    /* 11  */        6*2  , M_CMD(0, 4),L_CMD(0, 5),L_CMD(1, 5),L_CMD(1, 4),L_CMD(0, 4),M_CMD(1, 12),
    /* 12  */        4*2  , M_CMD(0, 6), L_CMD(5, 6),M_CMD(0, 8), L_CMD(5, 8),
    /* 13  */        3*2+1, L_CMD(7, 11), L_CMD(5, 13),L_CMD(2, 13),P_CMD(18),
    /* 14  */        2+1  , M_CMD(6, 0), P_CMD(6),
    /* 15  */           3 , P_CMD(3),P_CMD(2),P_CMD(10),
    /* 16 */            2 , L_CMD(8, 0),
    /* 17 */            3 , L_CMD(0, 14 ),P_CMD(6),
    /* 18 */            2 , L_CMD(0, 11),

 

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

yul-i-an пишет:

Осталось только в библиотеку затолкать. Незнаю с чего начать. Хачу что-то вроде adafruit_gfx. Может знатоки подскажут с чего начать...?

 

Определится с интерфейсами, можна OutStr(x,y,str, size, mode) в одном вызове, можна разными, типа SetSize(.., SetX(.., OutStr(str),.. Потом решить ООП/не ООП. Ща холивар будет ))) Полезно о разбиении на файлы подумать, вынести шрифты в отдельный, чтоб заменить проще было. Еще о оптимизации при частичном использовании подумать, чтоб, например, если без букв, только цифры нужны, так лишней памяти не отжирало для букв. Потом интнрфейсы в ашники, реализацию в сишники, шрифты отдельно в файл, а все файлы в папку. Папку в либы, на этом обязательная часть закончена. Примеры, доки подсветку идентификаторов - если силы останутся.

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

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

Вобщем долепил кирилицу. Итого 5 групп (цифры и знаки, латиница большая и малая с всякими тильдами ;)  кирилица большая и малая), имею 5групп*32=160 символов. Минус один символ, сделал без '@', я эту хрень рисовать нибуду! )))   Заняли 1471 байт прогмема. Самым  мелким шрифтом 5х8 былобы 795 байт. Ужать еще можна, я просто уже задолбался этим процессом, надо не ручками делать, а писать прогу. А там очень не тривиально, учитывая возможность один и тот же символ задать векторно в разном порядке начертания. Будет время - чето придумаю. И формат можна немного перекроить, теперь видно что команды М редкие и не разнообразные. Этот факт можна задействовать. Но пока работает и можна пользовать :)

Оценить размер в общем с кодом прорисовки векторного шрифта пока затруднительно, надо старый растровый сразу выпилить, но скетч компилится в 14КБ.

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

Я тоже немного эксперементировал.

Чуть чуть сжал массив

#define p(x,y) (x|(y<<4))
//Пример
const PROGMEM uint8_t d9[] = {M, p(8, 7), L, p(0, 7), L, p(0, 2), L, p(2, 0), L, p(8, 0), L, p(8, 13), L, p(6, 15), L, p(0, 15), 0};

Распаковываю так

void unpack(byte x[], byte c) {
  byte a, b;//переменные для распаковки координат
  a = (c << 4);//координаты
  a = a >> 4;//Х
  b = (c >> 4);//У
  x[0] = a; //заносим в буфер
  x[1] = b;
}

Повторяющиеся элементы вывожу так

         case 81://Вывод Q
        PMRead(lQ, 1);//вывод хвостика
        PMRead(lO);//вывод О
        break;
        case 82://вывод R
        PMRead(lR, 1);//ножка от символа R, 1 говорит о том что курсор не сдвигать 
        PMRead(lP);//символ Р
        break;

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

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

yul-i-an пишет:

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

Также как и латиницы. Тока у латиницы коды начинаются с 0x41 и 0x61 для заглавных и строчных а у кирилицы с 0xc0 и 0xe0. Ровно по 32 буквы в алфавитном порядке без Ё и ё. В общем согласно Windows-1251.

Все 159 символов без ужатия более 2К занимают:

  /*   */  1*2, M_CMD(4, 0 ), 
  /* ! */  3*2, L_CMD(0, 12 ), L_CMD(0, 14 ), L_CMD(0, 15 ), 
  /* " */  3*2, L_CMD(0, 2 ), M_CMD(3, 0 ), L_CMD(3, 2 ), 
  /* # */  8*2, M_CMD(0, 6 ), L_CMD(5, 6 ), M_CMD(0, 8 ), L_CMD(5, 8 ), M_CMD(2, 4 ), L_CMD(1, 10 ), M_CMD(4, 4 ), L_CMD(3, 10 ), 
  /* $ */  12*2, M_CMD(7, 4 ), L_CMD(5, 2 ), L_CMD(2, 2 ), L_CMD(0, 4 ), L_CMD(0, 6 ), L_CMD(7, 9 ), L_CMD(7, 11 ), L_CMD(5, 13 ), L_CMD(2, 13 ), L_CMD(0, 11 ), M_CMD(4, 0 ), L_CMD(3, 15 ), 
  /* % */  11*2, L_CMD(2, 0 ), L_CMD(2, 2 ), L_CMD(0, 2 ), L_CMD(0, 0 ), M_CMD(4, 13 ), L_CMD(4, 15 ), L_CMD(6, 15 ), L_CMD(6, 13 ), L_CMD(4, 13 ), M_CMD(6, 0 ), L_CMD(0, 15 ), 
  /* & */  10*2, L_CMD(7, 11 ), L_CMD(5, 13 ), L_CMD(2, 13 ), L_CMD(0, 11 ), L_CMD(6, 4 ), L_CMD(5, 2 ), L_CMD(3, 2 ), L_CMD(2, 3 ), L_CMD(2, 5 ), L_CMD(7, 14 ), 
  /* ' */  1*2, L_CMD(0, 2 ), 
  /* ( */  4*2, M_CMD(2, 0 ), L_CMD(0, 4 ), L_CMD(0, 11 ), L_CMD(2, 15 ), 
  /* ) */  3*2, L_CMD(2, 4 ), L_CMD(2, 11 ), L_CMD(0, 15 ), 
  /* * */  8*2, M_CMD(0, 7 ), L_CMD(6, 7 ), M_CMD(3, 3 ), L_CMD(3, 11 ), M_CMD(0, 11 ), L_CMD(6, 3 ), M_CMD(0, 3 ), L_CMD(6, 11 ), 
  /* + */  4*2, M_CMD(0, 7 ), L_CMD(6, 7 ), M_CMD(3, 3 ), L_CMD(3, 11 ), 
  /* , */  2*2, M_CMD(1, 13 ), L_CMD(0, 15 ), 
  /* - */  2*2, M_CMD(0, 7 ), L_CMD(6, 7 ), 
  /* . */  5*2, L_CMD(0, 14 ), L_CMD(0, 15 ), L_CMD(1, 15 ), L_CMD(1, 14 ), L_CMD(0, 14 ), 
  /* / */  2*2, M_CMD(6, 0 ), L_CMD(0, 15 ), 
  /* 0 */  10*2, M_CMD(0, 2 ), L_CMD(2, 0 ), L_CMD(6, 0 ), L_CMD(8, 2 ), L_CMD(8, 9 ), L_CMD(8, 13 ), L_CMD(6, 15 ), L_CMD(2, 15 ), L_CMD(0, 13 ), L_CMD(0, 2 ), 
  /* 1 */  3*2, M_CMD(3, 15 ), L_CMD(3, 0 ), L_CMD(0, 5 ), 
  /* 2 */  10*2, M_CMD(0, 2 ), L_CMD(2, 0 ), L_CMD(6, 0 ), L_CMD(8, 2 ), L_CMD(8, 5 ), L_CMD(6, 7 ), L_CMD(3, 10 ), L_CMD(0, 14 ), L_CMD(0, 15 ), L_CMD(8, 15 ), 
  /* 3 */  13*2, M_CMD(0, 2 ), L_CMD(2, 0 ), L_CMD(6, 0 ), L_CMD(8, 2 ), L_CMD(8, 5 ), L_CMD(6, 7 ), M_CMD(2, 7 ), L_CMD(6, 7 ), L_CMD(8, 9 ), L_CMD(8, 13 ), L_CMD(6, 15 ), L_CMD(2, 15 ), L_CMD(0, 13 ), 
  /* 4 */  5*2, L_CMD(0, 5 ), L_CMD(2, 7 ), L_CMD(8, 7 ), M_CMD(8, 0 ), L_CMD(8, 15 ), 
  /* 5 */  11*2, M_CMD(8, 0 ), L_CMD(2, 0 ), L_CMD(0, 7 ), L_CMD(3, 6 ), L_CMD(5, 6 ), L_CMD(7, 7 ), L_CMD(8, 9 ), L_CMD(8, 13 ), L_CMD(6, 15 ), L_CMD(2, 15 ), L_CMD(0, 13 ), 
  /* 6 */  15*2, M_CMD(0, 2 ), L_CMD(2, 0 ), L_CMD(6, 0 ), L_CMD(8, 2 ), M_CMD(0, 2 ), L_CMD(0, 7 ), L_CMD(3, 6 ), L_CMD(5, 6 ), L_CMD(7, 7 ), L_CMD(8, 9 ), L_CMD(8, 13 ), L_CMD(6, 15 ), L_CMD(2, 15 ), L_CMD(0, 13 ), L_CMD(0, 7 ), 
  /* 7 */  3*2, L_CMD(8, 0 ), L_CMD(8, 4 ), L_CMD(0, 15 ), 
  /* 8 */  17*2, M_CMD(0, 2 ), L_CMD(2, 0 ), L_CMD(6, 0 ), L_CMD(8, 2 ), L_CMD(8, 5 ), L_CMD(6, 7 ), L_CMD(2, 7 ), L_CMD(0, 5 ), L_CMD(0, 2 ), M_CMD(6, 7 ), L_CMD(8, 9 ), L_CMD(8, 13 ), L_CMD(6, 15 ), L_CMD(2, 15 ), L_CMD(0, 13 ), L_CMD(0, 9 ), L_CMD(2, 7 ), 
  /* 9 */  15*2, M_CMD(0, 2 ), L_CMD(2, 0 ), L_CMD(6, 0 ), L_CMD(8, 2 ), L_CMD(8, 5 ), L_CMD(6, 7 ), L_CMD(2, 7 ), L_CMD(0, 5 ), L_CMD(0, 2 ), M_CMD(8, 5 ), L_CMD(8, 9 ), L_CMD(8, 13 ), L_CMD(6, 15 ), L_CMD(2, 15 ), L_CMD(0, 13 ), 
  /* : */  10*2, M_CMD(0, 4 ), L_CMD(0, 5 ), L_CMD(1, 5 ), L_CMD(1, 4 ), L_CMD(0, 4 ), M_CMD(1, 12 ), L_CMD(0, 12 ), L_CMD(0, 11 ), L_CMD(1, 11 ), L_CMD(1, 12 ), 
  /* ; */  7*2, M_CMD(0, 4 ), L_CMD(0, 5 ), L_CMD(1, 5 ), L_CMD(1, 4 ), L_CMD(0, 4 ), M_CMD(1, 12 ), L_CMD(0, 15 ), 
  /* < */  3*2, M_CMD(4, 4 ), L_CMD(0, 8 ), L_CMD(4, 12 ), 
  /* = */  4*2, M_CMD(0, 6 ), L_CMD(5, 6 ), M_CMD(0, 8 ), L_CMD(5, 8 ), 
  /* > */  3*2, M_CMD(0, 4 ), L_CMD(4, 8 ), L_CMD(0, 12 ), 
  /* ? */  10*2, M_CMD(0, 2 ), L_CMD(2, 0 ), L_CMD(6, 0 ), L_CMD(8, 2 ), L_CMD(8, 5 ), L_CMD(6, 7 ), L_CMD(5, 9 ), L_CMD(4, 13 ), M_CMD(4, 15 ), L_CMD(4, 15 ), 
  /* @ */  0*2, 
  /* A */  5*2, M_CMD(0, 16 ), L_CMD(4, 0 ), L_CMD(8, 16 ), M_CMD(2, 11 ), L_CMD(6, 11 ), 
  /* B */  12*2, M_CMD(0, 8 ), L_CMD(0, 0 ), L_CMD(6, 0 ), L_CMD(8, 2 ), L_CMD(8, 6 ), L_CMD(6, 8 ), L_CMD(8, 10 ), L_CMD(8, 14 ), L_CMD(6, 16 ), L_CMD(0, 16 ), L_CMD(0, 8 ), L_CMD(8, 8 ), 
  /* C */  8*2, M_CMD(8, 2 ), L_CMD(6, 0 ), L_CMD(2, 0 ), L_CMD(0, 2 ), L_CMD(0, 14 ), L_CMD(2, 16 ), L_CMD(6, 16 ), L_CMD(8, 14 ), 
  /* D */  6*2, L_CMD(6, 0 ), L_CMD(8, 2 ), L_CMD(8, 14 ), L_CMD(6, 16 ), L_CMD(0, 16 ), L_CMD(0, 0 ), 
  /* E */  6*2, M_CMD(8, 0 ), L_CMD(0, 0 ), L_CMD(0, 16 ), L_CMD(8, 16 ), M_CMD(0, 8 ), L_CMD(6, 8 ), 
  /* F */  5*2, M_CMD(8, 0 ), L_CMD(0, 0 ), L_CMD(0, 16 ), M_CMD(0, 8 ), L_CMD(6, 8 ), 
  /* G */  10*2, M_CMD(8, 2 ), L_CMD(6, 0 ), L_CMD(2, 0 ), L_CMD(0, 2 ), L_CMD(0, 14 ), L_CMD(2, 16 ), L_CMD(6, 16 ), L_CMD(8, 14 ), L_CMD(8, 8 ), L_CMD(5, 8 ), 
  /* H */  5*2, L_CMD(0, 16 ), M_CMD(8, 0 ), L_CMD(8, 16 ), M_CMD(0, 8 ), L_CMD(6, 8 ), 
  /* I */  5*2, L_CMD(8, 0 ), M_CMD(4, 0 ), L_CMD(4, 16 ), M_CMD(0, 16 ), L_CMD(8, 16 ), 
  /* J */  5*2, L_CMD(8, 0 ), L_CMD(8, 14 ), L_CMD(6, 16 ), L_CMD(2, 16 ), L_CMD(0, 14 ), 
  /* K */  4*2, L_CMD(0, 16 ), M_CMD(8, 0 ), L_CMD(0, 8 ), L_CMD(8, 16 ), 
  /* L */  2*2, L_CMD(0, 16 ), L_CMD(8, 16 ), 
  /* M */  5*2, M_CMD(0, 16 ), L_CMD(0, 0 ), L_CMD(4, 10 ), L_CMD(8, 0 ), L_CMD(8, 16 ), 
  /* N */  4*2, M_CMD(0, 16 ), L_CMD(0, 0 ), L_CMD(8, 16 ), L_CMD(8, 0 ), 
  /* O */  10*2, M_CMD(0, 2 ), L_CMD(2, 0 ), L_CMD(6, 0 ), L_CMD(8, 2 ), L_CMD(8, 9 ), L_CMD(8, 13 ), L_CMD(6, 15 ), L_CMD(2, 15 ), L_CMD(0, 13 ), L_CMD(0, 2 ), 
  /* P */  7*2, M_CMD(0, 16 ), L_CMD(0, 0 ), L_CMD(6, 0 ), L_CMD(8, 2 ), L_CMD(8, 6 ), L_CMD(6, 8 ), L_CMD(0, 8 ), 
  /* Q */  12*2, M_CMD(0, 2 ), L_CMD(2, 0 ), L_CMD(6, 0 ), L_CMD(8, 2 ), L_CMD(8, 9 ), L_CMD(8, 13 ), L_CMD(6, 15 ), L_CMD(2, 15 ), L_CMD(0, 13 ), L_CMD(0, 2 ), M_CMD(4, 14 ), L_CMD(8, 16 ), 
  /* R */  9*2, M_CMD(0, 16 ), L_CMD(0, 0 ), L_CMD(6, 0 ), L_CMD(8, 2 ), L_CMD(8, 6 ), L_CMD(6, 8 ), L_CMD(0, 8 ), M_CMD(4, 8 ), L_CMD(8, 16 ), 
  /* S */  10*2, M_CMD(8, 0 ), L_CMD(2, 0 ), L_CMD(0, 2 ), L_CMD(0, 6 ), L_CMD(2, 8 ), L_CMD(6, 8 ), L_CMD(8, 10 ), L_CMD(8, 14 ), L_CMD(6, 16 ), L_CMD(0, 16 ), 
  /* T */  3*2, L_CMD(8, 0 ), M_CMD(4, 0 ), L_CMD(4, 16 ), 
  /* U */  5*2, L_CMD(0, 14 ), L_CMD(2, 16 ), L_CMD(6, 16 ), L_CMD(8, 14 ), L_CMD(8, 0 ), 
  /* V */  2*2, L_CMD(4, 16 ), L_CMD(8, 0 ), 
  /* W */  4*2, L_CMD(2, 16 ), L_CMD(4, 6 ), L_CMD(6, 16 ), L_CMD(8, 0 ), 
  /* X */  3*2, L_CMD(8, 16 ), M_CMD(8, 0 ), L_CMD(0, 16 ), 
  /* Y */  4*2, L_CMD(4, 8 ), L_CMD(4, 16 ), M_CMD(4, 8 ), L_CMD(8, 0 ), 
  /* Z */  3*2, L_CMD(8, 0 ), L_CMD(0, 16 ), L_CMD(8, 16 ), 
  /* [ */  4*2, M_CMD(4, 0 ), L_CMD(0, 0 ), L_CMD(0, 16 ), L_CMD(4, 16 ), 
  /* \ */  1*2, L_CMD(4, 16 ), 
  /* ] */  3*2, L_CMD(4, 9 ), L_CMD(4, 16 ), L_CMD(0, 16 ), 
  /* ^ */  3*2, M_CMD(0, 2 ), L_CMD(2, 0 ), L_CMD(2, 0 ), 
  /* _ */  2*2, M_CMD(0, 16 ), L_CMD(4, 16 ), 
  /* ` */  1*2, L_CMD(2, 3 ), 
  /* a */  9*2, M_CMD(2, 6 ), L_CMD(6, 6 ), L_CMD(8, 8 ), L_CMD(8, 16 ), L_CMD(2, 16 ), L_CMD(0, 14 ), L_CMD(0, 12 ), L_CMD(2, 10 ), L_CMD(8, 10 ), 
  /* b */  6*2, L_CMD(0, 16 ), L_CMD(6, 16 ), L_CMD(8, 14 ), L_CMD(8, 10 ), L_CMD(6, 6 ), L_CMD(0, 6 ), 
  /* c */  6*2, M_CMD(8, 6 ), L_CMD(2, 6 ), L_CMD(0, 8 ), L_CMD(0, 14 ), L_CMD(2, 16 ), L_CMD(8, 16 ), 
  /* d */  7*2, M_CMD(8, 0 ), L_CMD(8, 16 ), L_CMD(2, 16 ), L_CMD(0, 14 ), L_CMD(0, 8 ), L_CMD(2, 6 ), L_CMD(8, 6 ), 
  /* e */  9*2, M_CMD(8, 16 ), L_CMD(2, 16 ), L_CMD(0, 14 ), L_CMD(0, 8 ), L_CMD(2, 6 ), L_CMD(6, 6 ), L_CMD(8, 8 ), L_CMD(8, 12 ), L_CMD(0, 12 ), 
  /* f */  7*2, M_CMD(0, 10 ), L_CMD(6, 10 ), M_CMD(2, 16 ), L_CMD(2, 2 ), L_CMD(4, 0 ), L_CMD(6, 0 ), L_CMD(8, 2 ), 
  /* g */  10*2, M_CMD(8, 13 ), L_CMD(2, 13 ), L_CMD(0, 12 ), L_CMD(0, 8 ), L_CMD(2, 6 ), L_CMD(6, 6 ), L_CMD(8, 8 ), L_CMD(8, 14 ), L_CMD(6, 16 ), L_CMD(0, 16 ), 
  /* h */  5*2, L_CMD(0, 16 ), M_CMD(0, 6 ), L_CMD(6, 6 ), L_CMD(8, 8 ), L_CMD(8, 16 ), 
  /* i */  4*2, M_CMD(0, 5 ), L_CMD(0, 16 ), M_CMD(0, 1 ), L_CMD(0, 1 ), 
  /* j */  6*2, M_CMD(4, 5 ), L_CMD(4, 14 ), L_CMD(2, 16 ), L_CMD(0, 16 ), M_CMD(4, 1 ), L_CMD(4, 1 ), 
  /* k */  5*2, L_CMD(0, 16 ), M_CMD(0, 10 ), L_CMD(6, 6 ), M_CMD(3, 9 ), L_CMD(8, 16 ), 
  /* l */  1*2, L_CMD(0, 16 ), 
  /* m */  7*2, M_CMD(0, 16 ), L_CMD(0, 6 ), L_CMD(6, 6 ), L_CMD(8, 8 ), L_CMD(8, 16 ), M_CMD(4, 6 ), L_CMD(4, 16 ), 
  /* n */  5*2, M_CMD(0, 16 ), L_CMD(0, 6 ), L_CMD(6, 6 ), L_CMD(8, 8 ), L_CMD(8, 16 ), 
  /* o */  9*2, M_CMD(0, 7 ), L_CMD(2, 6 ), L_CMD(6, 6 ), L_CMD(8, 8 ), L_CMD(8, 14 ), L_CMD(6, 16 ), L_CMD(2, 16 ), L_CMD(0, 14 ), L_CMD(0, 7 ), 
  /* p */  7*2, M_CMD(0, 16 ), L_CMD(0, 6 ), L_CMD(6, 6 ), L_CMD(8, 8 ), L_CMD(8, 10 ), L_CMD(6, 12 ), L_CMD(0, 12 ), 
  /* q */  10*2, M_CMD(8, 6 ), L_CMD(8, 16 ), M_CMD(8, 10 ), L_CMD(6, 12 ), L_CMD(2, 12 ), L_CMD(0, 10 ), L_CMD(0, 8 ), L_CMD(2, 6 ), L_CMD(6, 6 ), L_CMD(8, 8 ), 
  /* r */  6*2, M_CMD(0, 6 ), L_CMD(0, 16 ), M_CMD(0, 8 ), L_CMD(2, 6 ), L_CMD(6, 6 ), L_CMD(8, 8 ), 
  /* s */  12*2, M_CMD(8, 8 ), L_CMD(6, 6 ), L_CMD(2, 6 ), L_CMD(0, 8 ), L_CMD(0, 9 ), L_CMD(2, 11 ), L_CMD(6, 11 ), L_CMD(8, 13 ), L_CMD(8, 14 ), L_CMD(6, 16 ), L_CMD(2, 16 ), L_CMD(0, 14 ), 
  /* t */  7*2, M_CMD(2, 0 ), L_CMD(2, 14 ), L_CMD(4, 16 ), L_CMD(6, 16 ), L_CMD(8, 14 ), M_CMD(0, 6 ), L_CMD(6, 6 ), 
  /* u */  5*2, M_CMD(0, 6 ), L_CMD(0, 14 ), L_CMD(2, 16 ), L_CMD(8, 16 ), L_CMD(8, 6 ), 
  /* v */  3*2, M_CMD(0, 6 ), L_CMD(4, 16 ), L_CMD(8, 6 ), 
  /* w */  5*2, M_CMD(0, 6 ), L_CMD(2, 16 ), L_CMD(4, 10 ), L_CMD(6, 16 ), L_CMD(8, 6 ), 
  /* x */  4*2, M_CMD(0, 6 ), L_CMD(8, 16 ), M_CMD(8, 6 ), L_CMD(0, 16 ), 
  /* y */  8*2, M_CMD(0, 6 ), L_CMD(0, 10 ), L_CMD(2, 12 ), L_CMD(8, 12 ), M_CMD(8, 6 ), L_CMD(8, 14 ), L_CMD(6, 16 ), L_CMD(0, 16 ), 
  /* z */  4*2, M_CMD(0, 6 ), L_CMD(8, 6 ), L_CMD(0, 16 ), L_CMD(8, 16 ), 
  /* { */  5*2, L_CMD(1, 6 ), L_CMD(0, 7 ), L_CMD(1, 8 ), L_CMD(1, 14 ), L_CMD(3, 16 ), 
  /* | */  1*2, L_CMD(0, 16 ), 
  /* } */  6*2, L_CMD(2, 2 ), L_CMD(2, 6 ), L_CMD(3, 7 ), L_CMD(2, 8 ), L_CMD(2, 14 ), L_CMD(0, 16 ), 
  /* ~ */  6*2, M_CMD(0, 7 ), L_CMD(1, 6 ), L_CMD(3, 6 ), L_CMD(5, 8 ), L_CMD(7, 8 ), L_CMD(8, 7 ), 
  /* А */  5*2, M_CMD(0, 16 ), L_CMD(4, 0 ), L_CMD(8, 16 ), M_CMD(2, 11 ), L_CMD(6, 11 ), 
  /* Б */  9*2, M_CMD(0, 16 ), L_CMD(0, 0 ), L_CMD(8, 0 ), M_CMD(0, 8 ), L_CMD(6, 8 ), L_CMD(8, 10 ), L_CMD(8, 14 ), L_CMD(6, 16 ), L_CMD(0, 16 ), 
  /* В */  12*2, M_CMD(0, 8 ), L_CMD(0, 0 ), L_CMD(6, 0 ), L_CMD(8, 2 ), L_CMD(8, 6 ), L_CMD(6, 8 ), L_CMD(8, 10 ), L_CMD(8, 14 ), L_CMD(6, 16 ), L_CMD(0, 16 ), L_CMD(0, 8 ), L_CMD(8, 8 ), 
  /* Г */  3*2, M_CMD(0, 16 ), L_CMD(0, 0 ), L_CMD(8, 0 ), 
  /* Д */  9*2, M_CMD(0, 16 ), L_CMD(0, 15 ), L_CMD(8, 15 ), L_CMD(8, 16 ), M_CMD(1, 15 ), L_CMD(2, 14 ), L_CMD(4, 0 ), L_CMD(7, 0 ), L_CMD(7, 15 ), 
  /* Е */  6*2, M_CMD(8, 0 ), L_CMD(0, 0 ), L_CMD(0, 16 ), L_CMD(8, 16 ), M_CMD(0, 8 ), L_CMD(6, 8 ), 
  /* Ж */  7*2, L_CMD(4, 6 ), L_CMD(0, 16 ), M_CMD(4, 0 ), L_CMD(4, 16 ), M_CMD(8, 0 ), L_CMD(4, 6 ), L_CMD(8, 16 ), 
  /* З */  13*2, M_CMD(0, 2 ), L_CMD(2, 0 ), L_CMD(6, 0 ), L_CMD(8, 2 ), L_CMD(8, 5 ), L_CMD(6, 7 ), M_CMD(2, 7 ), L_CMD(6, 7 ), L_CMD(8, 9 ), L_CMD(8, 13 ), L_CMD(6, 15 ), L_CMD(2, 15 ), L_CMD(0, 13 ), 
  /* И */  3*2, L_CMD(0, 16 ), L_CMD(8, 0 ), L_CMD(8, 16 ), 
  /* Й */  6*2, L_CMD(0, 16 ), L_CMD(8, 0 ), L_CMD(8, 16 ), M_CMD(3, 0 ), L_CMD(4, 1 ), L_CMD(5, 0 ), 
  /* К */  4*2, L_CMD(0, 16 ), M_CMD(8, 0 ), L_CMD(0, 8 ), L_CMD(8, 16 ), 
  /* Л */  5*2, M_CMD(0, 16 ), L_CMD(2, 14 ), L_CMD(2, 0 ), L_CMD(8, 0 ), L_CMD(8, 16 ), 
  /* М */  5*2, M_CMD(0, 16 ), L_CMD(0, 0 ), L_CMD(4, 10 ), L_CMD(8, 0 ), L_CMD(8, 16 ), 
  /* Н */  5*2, L_CMD(0, 16 ), M_CMD(0, 8 ), L_CMD(8, 8 ), M_CMD(8, 0 ), L_CMD(8, 16 ), 
  /* О */  10*2, M_CMD(0, 2 ), L_CMD(2, 0 ), L_CMD(6, 0 ), L_CMD(8, 2 ), L_CMD(8, 9 ), L_CMD(8, 13 ), L_CMD(6, 15 ), L_CMD(2, 15 ), L_CMD(0, 13 ), L_CMD(0, 2 ), 
  /* П */  4*2, M_CMD(0, 16 ), L_CMD(0, 0 ), L_CMD(8, 0 ), L_CMD(8, 16 ), 
  /* Р */  7*2, M_CMD(0, 16 ), L_CMD(0, 0 ), L_CMD(6, 0 ), L_CMD(8, 2 ), L_CMD(8, 6 ), L_CMD(6, 8 ), L_CMD(0, 8 ), 
  /* С */  8*2, M_CMD(8, 2 ), L_CMD(6, 0 ), L_CMD(2, 0 ), L_CMD(0, 2 ), L_CMD(0, 14 ), L_CMD(2, 16 ), L_CMD(6, 16 ), L_CMD(8, 14 ), 
  /* Т */  3*2, L_CMD(8, 0 ), M_CMD(4, 0 ), L_CMD(4, 16 ), 
  /* У */  6*2, L_CMD(3, 8 ), L_CMD(5, 9 ), M_CMD(8, 0 ), L_CMD(4, 12 ), L_CMD(2, 14 ), L_CMD(0, 16 ), 
  /* Ф */  11*2, M_CMD(2, 2 ), L_CMD(6, 2 ), L_CMD(8, 4 ), L_CMD(8, 12 ), L_CMD(6, 14 ), L_CMD(2, 14 ), L_CMD(0, 12 ), L_CMD(0, 4 ), L_CMD(2, 2 ), M_CMD(4, 0 ), L_CMD(4, 16 ), 
  /* Х */  3*2, L_CMD(8, 16 ), M_CMD(8, 0 ), L_CMD(0, 16 ), 
  /* Ц */  5*2, L_CMD(0, 15 ), L_CMD(6, 15 ), L_CMD(6, 0 ), M_CMD(6, 15 ), L_CMD(8, 16 ), 
  /* Ч */  5*2, L_CMD(0, 5 ), L_CMD(2, 7 ), L_CMD(8, 7 ), M_CMD(8, 0 ), L_CMD(8, 15 ), 
  /* Ш */  5*2, L_CMD(0, 16 ), L_CMD(8, 16 ), L_CMD(8, 0 ), M_CMD(4, 0 ), L_CMD(4, 16 ), 
  /* Щ */  7*2, L_CMD(0, 15 ), L_CMD(6, 15 ), L_CMD(6, 0 ), M_CMD(6, 15 ), L_CMD(8, 16 ), M_CMD(3, 0 ), L_CMD(3, 15 ), 
  /* Ъ */  7*2, L_CMD(2, 0 ), L_CMD(2, 16 ), L_CMD(6, 16 ), L_CMD(8, 14 ), L_CMD(8, 10 ), L_CMD(6, 8 ), L_CMD(2, 8 ), 
  /* Ы */  8*2, L_CMD(0, 16 ), L_CMD(4, 16 ), L_CMD(6, 14 ), L_CMD(6, 10 ), L_CMD(4, 8 ), L_CMD(0, 8 ), M_CMD(8, 0 ), L_CMD(8, 16 ), 
  /* Ь */  6*2, L_CMD(0, 16 ), L_CMD(6, 16 ), L_CMD(8, 14 ), L_CMD(8, 10 ), L_CMD(6, 6 ), L_CMD(0, 6 ), 
  /* Э */  7*2, L_CMD(6, 0 ), L_CMD(8, 2 ), L_CMD(8, 14 ), L_CMD(6, 16 ), L_CMD(0, 16 ), M_CMD(2, 8 ), L_CMD(8, 8 ), 
  /* Ю */  12*2, L_CMD(0, 16 ), M_CMD(0, 8 ), L_CMD(3, 8 ), M_CMD(3, 2 ), L_CMD(5, 0 ), L_CMD(6, 0 ), L_CMD(8, 2 ), L_CMD(8, 14 ), L_CMD(6, 16 ), L_CMD(5, 16 ), L_CMD(3, 14 ), L_CMD(3, 2 ), 
  /* Я */  8*2, M_CMD(0, 16 ), L_CMD(8, 8 ), L_CMD(2, 8 ), L_CMD(0, 6 ), L_CMD(0, 2 ), L_CMD(2, 0 ), L_CMD(8, 0 ), L_CMD(8, 16 ), 
  /* а */  9*2, M_CMD(2, 6 ), L_CMD(6, 6 ), L_CMD(8, 8 ), L_CMD(8, 16 ), L_CMD(2, 16 ), L_CMD(0, 14 ), L_CMD(0, 12 ), L_CMD(2, 10 ), L_CMD(8, 10 ), 
  /* б */  12*2, M_CMD(0, 7 ), L_CMD(2, 6 ), L_CMD(6, 6 ), L_CMD(8, 8 ), L_CMD(8, 14 ), L_CMD(6, 16 ), L_CMD(2, 16 ), L_CMD(0, 14 ), L_CMD(0, 7 ), M_CMD(0, 6 ), L_CMD(2, 2 ), L_CMD(6, 0 ), 
  /* в */  15*2, M_CMD(0, 7 ), L_CMD(2, 6 ), L_CMD(6, 6 ), L_CMD(8, 8 ), L_CMD(8, 14 ), L_CMD(6, 16 ), L_CMD(2, 16 ), L_CMD(0, 14 ), L_CMD(0, 7 ), M_CMD(0, 6 ), L_CMD(0, 2 ), L_CMD(3, 0 ), L_CMD(5, 0 ), L_CMD(6, 2 ), L_CMD(0, 6 ), 
  /* г */  12*2, M_CMD(0, 7 ), L_CMD(2, 6 ), L_CMD(6, 6 ), L_CMD(8, 8 ), L_CMD(8, 10 ), L_CMD(6, 11 ), L_CMD(2, 11 ), L_CMD(0, 12 ), L_CMD(0, 14 ), L_CMD(2, 16 ), L_CMD(6, 16 ), L_CMD(8, 15 ), 
  /* д */  12*2, L_CMD(6, 1 ), L_CMD(8, 3 ), L_CMD(8, 8 ), M_CMD(0, 7 ), L_CMD(2, 6 ), L_CMD(6, 6 ), L_CMD(8, 8 ), L_CMD(8, 14 ), L_CMD(6, 16 ), L_CMD(2, 16 ), L_CMD(0, 14 ), L_CMD(0, 7 ), 
  /* е */  9*2, M_CMD(8, 16 ), L_CMD(2, 16 ), L_CMD(0, 14 ), L_CMD(0, 8 ), L_CMD(2, 6 ), L_CMD(6, 6 ), L_CMD(8, 8 ), L_CMD(8, 12 ), L_CMD(0, 12 ), 
  /* ж */  6*2, M_CMD(0, 6 ), L_CMD(8, 16 ), M_CMD(4, 6 ), L_CMD(4, 16 ), M_CMD(8, 6 ), L_CMD(0, 16 ), 
  /* з */  11*2, M_CMD(2, 8 ), L_CMD(4, 6 ), L_CMD(5, 6 ), L_CMD(7, 8 ), L_CMD(6, 10 ), L_CMD(3, 11 ), L_CMD(6, 11 ), L_CMD(8, 14 ), L_CMD(6, 16 ), L_CMD(2, 16 ), L_CMD(0, 14 ), 
  /* и */  5*2, M_CMD(0, 6 ), L_CMD(0, 14 ), L_CMD(2, 16 ), L_CMD(8, 16 ), L_CMD(8, 6 ), 
  /* й */  8*2, M_CMD(0, 6 ), L_CMD(0, 14 ), L_CMD(2, 16 ), L_CMD(8, 16 ), L_CMD(8, 6 ), M_CMD(3, 5 ), L_CMD(4, 6 ), L_CMD(5, 5 ), 
  /* к */  5*2, M_CMD(0, 6 ), L_CMD(0, 16 ), M_CMD(8, 16 ), L_CMD(0, 12 ), L_CMD(8, 6 ), 
  /* л */  5*2, M_CMD(0, 16 ), L_CMD(2, 14 ), L_CMD(4, 6 ), L_CMD(8, 6 ), L_CMD(8, 16 ), 
  /* м */  5*2, M_CMD(0, 16 ), L_CMD(0, 6 ), L_CMD(4, 10 ), L_CMD(8, 6 ), L_CMD(8, 16 ), 
  /* н */  6*2, M_CMD(0, 6 ), L_CMD(0, 16 ), M_CMD(0, 12 ), L_CMD(8, 12 ), M_CMD(8, 6 ), L_CMD(8, 16 ), 
  /* о */  9*2, M_CMD(0, 7 ), L_CMD(2, 6 ), L_CMD(6, 6 ), L_CMD(8, 8 ), L_CMD(8, 14 ), L_CMD(6, 16 ), L_CMD(2, 16 ), L_CMD(0, 14 ), L_CMD(0, 7 ), 
  /* п */  4*2, M_CMD(0, 16 ), L_CMD(0, 6 ), L_CMD(8, 6 ), L_CMD(8, 16 ), 
  /* р */  7*2, M_CMD(0, 16 ), L_CMD(0, 6 ), L_CMD(6, 6 ), L_CMD(8, 8 ), L_CMD(8, 10 ), L_CMD(6, 12 ), L_CMD(0, 12 ), 
  /* с */  6*2, M_CMD(8, 6 ), L_CMD(2, 6 ), L_CMD(0, 8 ), L_CMD(0, 14 ), L_CMD(2, 16 ), L_CMD(8, 16 ), 
  /* т */  7*2, M_CMD(0, 16 ), L_CMD(0, 6 ), L_CMD(6, 6 ), L_CMD(8, 8 ), L_CMD(8, 16 ), M_CMD(4, 6 ), L_CMD(4, 16 ), 
  /* у */  8*2, M_CMD(0, 6 ), L_CMD(0, 10 ), L_CMD(2, 12 ), L_CMD(8, 12 ), M_CMD(8, 6 ), L_CMD(8, 14 ), L_CMD(6, 16 ), L_CMD(0, 16 ), 
  /* ф */  11*2, M_CMD(2, 7 ), L_CMD(6, 7 ), L_CMD(8, 9 ), L_CMD(8, 12 ), L_CMD(6, 14 ), L_CMD(2, 14 ), L_CMD(0, 12 ), L_CMD(0, 9 ), L_CMD(2, 7 ), M_CMD(4, 6 ), L_CMD(4, 16 ), 
  /* х */  4*2, M_CMD(0, 6 ), L_CMD(8, 16 ), M_CMD(8, 6 ), L_CMD(0, 16 ), 
  /* ц */  6*2, M_CMD(0, 6 ), L_CMD(0, 15 ), L_CMD(6, 15 ), L_CMD(6, 6 ), M_CMD(6, 15 ), L_CMD(8, 16 ), 
  /* ч */  6*2, M_CMD(0, 6 ), L_CMD(0, 10 ), L_CMD(2, 12 ), L_CMD(8, 12 ), M_CMD(8, 6 ), L_CMD(8, 16 ), 
  /* ш */  6*2, M_CMD(0, 6 ), L_CMD(0, 16 ), L_CMD(8, 16 ), L_CMD(8, 6 ), M_CMD(4, 6 ), L_CMD(4, 16 ), 
  /* щ */  8*2, M_CMD(0, 6 ), L_CMD(0, 15 ), L_CMD(6, 15 ), L_CMD(6, 6 ), M_CMD(6, 15 ), L_CMD(8, 16 ), M_CMD(3, 6 ), L_CMD(3, 15 ), 
  /* ъ */  8*2, M_CMD(0, 6 ), L_CMD(2, 6 ), L_CMD(2, 16 ), L_CMD(6, 16 ), L_CMD(8, 14 ), L_CMD(8, 12 ), L_CMD(6, 10 ), L_CMD(2, 10 ), 
  /* ы */  9*2, M_CMD(0, 6 ), L_CMD(0, 16 ), L_CMD(4, 16 ), L_CMD(6, 14 ), L_CMD(6, 12 ), L_CMD(4, 10 ), L_CMD(0, 10 ), M_CMD(8, 6 ), L_CMD(8, 16 ), 
  /* ь */  7*2, M_CMD(0, 6 ), L_CMD(0, 16 ), L_CMD(4, 16 ), L_CMD(6, 14 ), L_CMD(6, 12 ), L_CMD(4, 10 ), L_CMD(0, 10 ), 
  /* э */  10*2, M_CMD(0, 7 ), L_CMD(2, 6 ), L_CMD(6, 6 ), L_CMD(8, 8 ), L_CMD(8, 14 ), L_CMD(6, 16 ), L_CMD(2, 16 ), L_CMD(0, 14 ), M_CMD(2, 11 ), L_CMD(8, 11 ), 
  /* ю */  13*2, M_CMD(0, 6 ), L_CMD(0, 16 ), M_CMD(0, 11 ), L_CMD(3, 11 ), M_CMD(3, 8 ), L_CMD(5, 6 ), L_CMD(6, 6 ), L_CMD(8, 8 ), L_CMD(8, 14 ), L_CMD(6, 16 ), L_CMD(5, 16 ), L_CMD(3, 14 ), L_CMD(3, 8 ), 
  /* я */  8*2, M_CMD(0, 16 ), L_CMD(8, 12 ), L_CMD(2, 12 ), L_CMD(0, 10 ), L_CMD(0, 8 ), L_CMD(2, 6 ), L_CMD(8, 6 ), L_CMD(8, 16 ), 

L_CMD - 843 шт.
M_CMD - 199 шт.

Это по результатам распаковки из сжатых. Теперь хочу оптимизировать сжатие. По ходу надо перевести все к одной матрице 7*15, а то часть так а часть 8*16. Тогда можна будет команду в байт засунуть. Старший бит будет определять тип команды: L или вызов библиотеки, команды M будут реализованы только в библиотеке и отличатся от остальных библиотечных диапазоном номеров. Еще с явным указанием количества байт в векторном описании симвала чтото придумать, былоб просто бомба.

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

Запихал в недобиблиотеку

пример

#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);
#include <VF.h>//векторный шрифт
void setup() {
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.display();
}

void loop() {
  setCursorVF(0, 0);//позиция
  setTextSize(15);//размер текста в пикселях по у
  printVFln("Hello World");
  //можно так
  setTextSize(11, 10);//размер символа в пикселях по х и у
  printVFln("Hello World");
  bold = 1;
  setTextSize(12);//размер текста в пикселях по у
  printVFln("Hello World");
  bold = 0;
  italic = 1;
  setTextSize(13);//размер текста в пикселях по у
  printVFln("Hello World");
  italic = 0;
  display.display();
  delay(250);
  display.clearDisplay();
}

Сравнить с растром!

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

Logik пишет:

yul-i-an пишет:

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

Также как и латиницы. Тока у латиницы коды начинаются с 0x41 и 0x61 для заглавных и строчных а у кирилицы с 0xc0 и 0xe0. Ровно по 32 буквы в алфавитном порядке без Ё и ё. В общем согласно Windows-1251.

Так и немогу сообразить как получить код символа в кирилице.

Я у себя так делаю

void printVF(char txt[]) {
  byte symN = 0;
  while (txt[symN] != '\0') {
    char sym;//для хранения символа
    sym = txt[symN];
	sym = sym - 0;//полученный код символа
    switch (sym) {//выбираем по коду символа команду на отрисовку
      case 32://код символа 32
        PMRead(space);
        //cx = cx + 2;
        break;
      case 43://код символа 43
        PMRead(plus);
...

Если передаю символ на кирилице, получаю прочерк (по умолчанию в case если символа для отрисовки нет то "-" вывести )

например пробовал так

      case 65://en A 65
        PMRead(lA);
        break;
      case 192://rus A 192
        PMRead(lA);
        break;

Получил "-"

      default://если нет символа для вывода ставим прочерк
        PMRead(minus);//символ "-"
        break;
    }

Непонятно.

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

Попробуйте Serial.println((uint8_t)'А'); в монитор прийдет код символа.

Можна прямо писать case 'А':

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

Logik пишет:

Попробуйте Serial.println((uint8_t)'А'); в монитор прийдет код символа.

Можна прямо писать case 'А':

Попробовал. А-144, Я-175, а-176, я-143. Бред какойто. Латиница 65-122 от A до z по таблице.

Пробовал

 ...     
         case 122:
        PMRead(lz);
        break;
	  case 144://A192rus
        PMRead(lA);
        break;
      default://если нет символа для вывода ставим прочерк
        PMRead(minus);
	break;
    }

Не катит.

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

А че в preferences.txt параметр preproc.substitute_unicode? пробуйте вместо case 144: так case 'А':. странная кодировка, чтоб кирилическая А стала 0х90. Наверно UTF-8, там 0xd090 должно быть. Тогда  пробуйте case 0xd090:Что дают Serial.println(sizeof('А')); и Serial.println((uint16_t)'А',HEX);?

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

preproc.substitute_unicode = true

Serial.println(sizeof('А'));
Serial.println((uint16_t)'А',HEX);

Дает

2

D090

case 'А':

не помогает

Менял preproc.substitute_unicode = false результата нет.

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

таки UTF-8. Значить  пробуйте case 0xd090: А версия ИДЕ какая?

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

Logik пишет:

таки UTF-8. Значить  пробуйте case 0xd090: А версия ИДЕ какая?

ИДЕ 1.8.7

case 0xd090: не помогло

 

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

Чё за хрень.. А Serial.println(sizeof(sym)); и Serial.println((uint16_t)sym,HEX); непосредственно перед switch (sym)  что дают.

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

Logik пишет:

Чё за хрень.. А Serial.println(sizeof(sym)); и Serial.println((uint16_t)sym,HEX); непосредственно перед switch (sym)  что дают.

1
C0
 

Попробовал так

        case 192://A
        PMRead(lA);
        break;
	case 193://Б
        //PMRead(ll);
        break;
	case 194://В
        PMRead(lB);
        break;
	case 195://Г
        //PMRead(ll);
        break;
	case 196://Д
        PMRead(lDrus);
        break;

Заработало ввроде

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

yul-i-an пишет:

Logik пишет:

Чё за хрень.. А Serial.println(sizeof(sym)); и Serial.println((uint16_t)sym,HEX); непосредственно перед switch (sym)  что дают.

1
C0
 

Попробовал так

        case 192://A
        PMRead(lA);
        break;
	case 193://Б
        //PMRead(ll);
        break;
	case 194://В
        PMRead(lB);
        break;
	case 195://Г
        //PMRead(ll);
        break;
	case 196://Д
        PMRead(lDrus);
        break;

Заработало ввроде

Заработало после замены char sym; на byte sym. Но это было вчера. Нарисовал кирилицу, все работало. Сегодня тотже скетч без изменений перезагрузил иместо всех символов кирилицы выводится лат. P.

Тест

Serial.println(sizeof('А'));
Serial.println((uint16_t)'А',HEX);

опять выводит

2

D090

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

Не знаю что произошло, пришлось вкорячить костыль временный

void printVF(char txt[]) {
  byte symN = 0;
  while (txt[symN] != '\0') {
    byte sym;//для хранения символа
    sym = txt[symN];
    //  Serial.println(sym);

//КОСТЫЛЬ ДЛЯ КИРИЛИЦЫ
    if (kyr) {
      sym = sym + 0x30;
    }

    switch (sym) {
      case 32:
        PMRead(space);
        break;
      case 43:
        PMRead(plus);
        break;
      case 44:
        PMRead(comma);
        break;

Почемуто не получилось так написать

void printVF(char txt[], boolean kyr=0)

Ошибку компилятор выдал

Arduino: 1.8.7 (Windows XP), Плата:"Arduino/Genuino Uno"

In file included from G:\Documents and Settings\Андрей\Мои документы\Arduino\test_VF_RUS\test_VF_RUS.ino:5:0:

G:\Program Files\Arduino\libraries\VF/VF.h: In function 'void printVFln(char*)':

G:\Program Files\Arduino\libraries\VF/VF.h:565:14: error: call of overloaded 'printVF(char*&)' is ambiguous

   printVF(txt);

              ^

In file included from G:\Documents and Settings\Андрей\Мои документы\Arduino\test_VF_RUS\test_VF_RUS.ino:5:0:

G:\Program Files\Arduino\libraries\VF/VF.h:10:6: note: candidate: void printVF(char*)

 void printVF(char[12]);

      ^

In file included from G:\Documents and Settings\Андрей\Мои документы\Arduino\test_VF_RUS\test_VF_RUS.ino:5:0:

G:\Program Files\Arduino\libraries\VF/VF.h:235:6: note: candidate: void printVF(char*, boolean)

 void printVF(char txt[],boolean kyr=0) {

      ^

G:\Documents and Settings\Андрей\Мои документы\Arduino\test_VF_RUS\test_VF_RUS.ino: In function 'void loop()':

test_VF_RUS:22:20: error: call of overloaded 'printVF(const char [8])' is ambiguous

In file included from G:\Documents and Settings\Андрей\Мои документы\Arduino\test_VF_RUS\test_VF_RUS.ino:5:0:

G:\Program Files\Arduino\libraries\VF/VF.h:10:6: note: candidate: void printVF(char*)

 void printVF(char[12]);

      ^

In file included from G:\Documents and Settings\Андрей\Мои документы\Arduino\test_VF_RUS\test_VF_RUS.ino:5:0:

G:\Program Files\Arduino\libraries\VF/VF.h:235:6: note: candidate: void printVF(char*, boolean)

 void printVF(char txt[],boolean kyr=0) {

      ^

Несколько библиотек найдено для "Adafruit_SSD1306.h"
 Используется: G:\Documents and Settings\Андрей\Мои документы\Arduino\libraries\Adafruit_SSD1306
Не используется: G:\Program Files\Arduino\libraries\Adafruit_SSD1306
exit status 1
call of overloaded 'printVF(const char [8])' is ambiguous

Этот отчёт будет иметь больше информации с
включенной опцией Файл -> Настройки ->
"Показать подробный вывод во время компиляции"

Приходится пока так

 kyr=1;
  printVF("АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ",1);
  kyr=0;

Шрифт пока не полный

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

Изменил костыль

 if (sym>127) {
      sym = sym + 0x30;
    }

Пока все работает

Недобиблиотека VF

Кирилица пока только заглавная

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

Logik пишет:

andriano пишет:

yul-i-an пишет:

Где можно взять голую библиотеку для OLED которая только пикселы может выводить? Чтобы на её основе свою сколхозить. Думаю этот материал использовать.

Собственно, непосредственно на экран символы выводить невозможно.

Поэтому для пиксельной графики используется буферизация.

Ну а вывод пикселя в буфер от экрана никак не зависит. Поэтому, собственно, библиотека не нужна, нужна одна функция - вывод пикселя, которая сводится к установке одного бита в байте по вычисленному адресу. Т.е. вся "библиотека" - одна строка.

Ну не все так просто, еще инитить нужно.

Вывод пикселя у меня так.

void SSD1306Graphic::_Pixel(uint8_t x, uint8_t y, uint8_t operation)
{
        byte* p=&Canva[((y>>3)*Width)+x];
        byte b=*p;
        byte m=_BV(y & 7);

        switch (operation)
        {
        case 0: b&= ~m;break;
        case 1: b|=  m;break;
        case 2: b^=  m;break;
        }

        *p=b;
}

Вывод буфера, это FRAME_MODE_BUFER

void SSD1306Graphic::SetModeUpdate(void)
{
    sendTWIcommand(SSD1306_MEMORY_ADDR_MODE);
    sendTWIcommand(0x00);

    sendTWIcommand(SSD1306_SET_COLUMN_ADDR);
    sendTWIcommand(Left);
    sendTWIcommand(Left+Width-1);

    sendTWIcommand(SSD1306_SET_PAGE_ADDR);
    sendTWIcommand(Top);
    sendTWIcommand(Top+Pages-1);

    sendStart(SSD1306_ADDR<<1);
    writeByte(SSD1306_DATA_CONTINUE);
}

void SSD1306Graphic::update(void)
{
	switch(FrameMode)
	{
		case FRAME_MODE_PGM:updatePGM();break;
		case FRAME_MODE_CALLBACK:updateCallBack();break;
		case FRAME_MODE_BUFER:updateBuf();break;
	}
}

void SSD1306Graphic::updateBuf(void)
{
    if(!Canva)
        return;
   SetModeUpdate();

    for (int b=0; b<Width*Pages; b++)		// Send data
    {
        writeByte(Canva[b]);
    }

    sendStop();

}

ПС. "Собственно, непосредственно на экран символы выводить невозможно." - чего вдруг? Все возможно, 

        for (uint8_t i =0; i<5; addr++,i++ ) 
        {
           writeByte(pgm_read_byte(addr));
         }

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

А если сначала определить размер символа ВхШ создать временный массив такого размера, отрисовать в нем символ (растеризовать), а потом вывести его как битмап в нужное место. Тогда буфер размером с экран не нужен.

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

yul-i-an пишет:

А если сначала определить размер символа ВхШ создать временный массив такого размера, отрисовать в нем символ (растеризовать), а потом вывести его как битмап в нужное место. Тогда буфер размером с экран не нужен.

Да. Можна буфер размером в символ или в строку.  А размером с экран,  т.е. в 1Кб имея всего 2Кб ОЗУ - дурость. Да еще если статическиго буфера, как в одной популярной библиотеке:(

Пашу в свободное время над алгоритмом сжатия растрового шрифта. Сейчас все структуры и массивы занимают около 1,2Кб. Думаю реально до 1Кб сделать.