Там ни то ни другое некрасиво, там массив указателей на векторное описание символа нужно. Но о планах - по порядку.
Вобщем принципиально все выглядит неплохо: и символы смотрятся и рисуются быстро. Подход вобщем работает, разве что маштабизацию еще проверить. Дело за деталями.
Кривые Безье - оно конечно неплохо, но легко заметить что формат векторного описания сильно избыточен для шрифта. Потому в планирую 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 - резерв, потом может пригодится, может разрядность х и/или у увеличить может на флаг из пункта "в" задействовать.
Еще пожалуй стоит принять что перед прорисовкой каждого символа по умолчанию делается команда М, 0, 0. Если она для какого символа нужна такая первой, то её можна не указывать. Экономим.
Там ни то ни другое некрасиво, там массив указателей на векторное описание символа нужно.
Так-то да, но по свичу я не увидел непрерывной последовательности. В массиве будут null-евые ячейки. Оправдано это или нет в данном случае - не знаю. У меня на рисовалке по семисегментному индикатору "дешевле" вышло if-ов нашмалять.
Ну чё у нас данном случае null-евые ячейки? Нет реализации отрисовки данного символа, а если учесть что я вобщем так не символы а их группы, до 7 групп адресую (см#52) - то неприятность эту мы переживем. Получится нет заглавных кирилицы - ну null ей в корму )))
а в составе существующей группы если нет реализации отрисовки данного символа - длина 0, один байт издержек. Всё продумано. Надеюсь ;)
Я думаю что после того как нашли символ в группе необходимо в строке для вывода на дисплей посмотрет повторяется ли он. Если повторяется вывести его сразу чтобы не производить поиск снова. Завести битовый массив равный длине строки и отмечать в нем позиции уже выведенные чтобы повторно их не считывать.
Я думаю что после того как нашли символ в группе необходимо в строке для вывода на дисплей посмотрет повторяется ли он. Если повторяется вывести его сразу чтобы не производить поиск снова.
Для этого нужно, чтобы все символы шрифта имели одинаковую ширину и не было кернинга. Но отказываться от пропорциональных шрифтов и от кернинга - это похерить всю прелесть использования векторных шрифтов. Чем они в этом случае лучше растровых?
Я думаю что после того как нашли символ в группе необходимо в строке для вывода на дисплей посмотрет повторяется ли он.
Оно конечно можна, кеширование сделать, но не думаю что сильно ускорится. Основное время - на рисование прямых и выпихивание на экран. Рисование прямых можна ускорить если отдельно обрабатывать вертикали и горизонтали, а отдельно наклонные.
Я тут попробовал реализовать как описал. Чисто перекодировка строки в вызовы рисования прямых.
#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мсек на символ то и нормально, прорисовка намного дольше чем код распаковки.
Да, про ширину символа - я её по ходу прорисовки определяю, как максимальный х, делаю отступ в два пикселя и следующий символ с этого места.
Теперь в буфер читаю не весь массив с описанием символа, а только по одной команде. (в теории можно безболезненно увеличить длину принимаемых векторных описаний символов без забивания памяти.
Организовал вывод разноширинных символов. Масштабирование - вместо * на 0,5 применил здвиг вправо на 1. Скорость прорисовки теперь 23-24мс на 65 символов в отличии от прошлого кода который выводил тое самое за 35-37мсек (если пользоватся стандартными средствами библиотеки то вывод на 10мсек быстрее) при масштабироаании с помощью средств библиотеки не проаер
Думаю что шрифт с самого начало нужно было делать маленким, чтобы не сталкиватся с масштабированием т.к. маленкий чаще принимают.
Теперь в буфер читаю не весь массив с описанием символа, а только по одной команде. (в теории можно безболезненно увеличить длину принимаемых векторных описаний символов без забивания памяти.
Очень правильно.
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);
}
Прикольно, на второй фотке вполне годно. Тоже про курсив думал. А еще и про "болд". Прорисовать символ с его координаты и повторно прорисовать сдвинув по горизонтали на 1. Должно с жирными вертикалями получится.
Глазками различие намного заметней, светящуюся линию камера утолщает. Очень годно для подсветки активного пункта меню, на монохроме это проблема, инверсия не смотрится совсем.
Пробовал и в 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КБ влезть.
Вобщем возможности технологии понятны целиком и полностю.
Вопрос есть. Где можно взять голую библиотеку для OLED которая только пикселы может выводить? Чтобы на её основе свою сколхозить. Думаю этот материал использовать.
Где можно взять голую библиотеку для OLED которая только пикселы может выводить? Чтобы на её основе свою сколхозить. Думаю этот материал использовать.
Собственно, непосредственно на экран символы выводить невозможно.
Поэтому для пиксельной графики используется буферизация.
Ну а вывод пикселя в буфер от экрана никак не зависит. Поэтому, собственно, библиотека не нужна, нужна одна функция - вывод пикселя, которая сводится к установке одного бита в байте по вычисленному адресу. Т.е. вся "библиотека" - одна строка.
Где можно взять голую библиотеку для 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));
}
Отлично выводит символ прям на экран без бухера. Но символ растровый. Векторный, т.е. набор линии, теоретически тоже можна, но я не осилил. Нужно перед выводом каждого байта сформировать этот байт основываясь на массиве координат точек начала конца линий. Нимагу алгоритм придумать, может кто поможет...
А с пикселем, не все так просто. Как видно из кода вывод идет побайтно, т.е. сразу по 8 пикселей. И вобщем вывести сам один пиксель можна, но возникает вопрос а чё делать с остальными 7 пикселями. И тут есть 2 подхода: 1. взять их из буфера, в таком случае буфер необходим. 2. определить их каким либо образом, ведь както мы ж их в коде определяем, это бывает не так просто, как непросто в случае с линиями векторного шрифта, но принципиально возможно. Тогда и без буфера можна.
Заработал лайк! Прикольно получилось. Напомнило как в старых играх имена победителей вводились. Кольцо символов врощаеш пока нужный в фокус не встанет, затем выбираеш и для ввода следующего опять вращаеш...
Юлиан - описание фонта лучше делать в виде двумерного массива, где первый инлекс - указатель по коду ASCII. Тогда этот огромный switch -case начния со строки 322 можно будет выкинуть
Юлиан - описание фонта лучше делать в виде двумерного массива, где первый инлекс - указатель по коду ASCII. Тогда этот огромный switch -case начния со строки 322 можно будет выкинуть
Про свичь +1. Но двумерный то зачем? Ну коды символов не от нуля, та к делаем -0х20 и усьо. Да, есть в реализации шрифтов пропуски символов, хотя вобще их конечно быть не должно, ну будут 0. Всеравно на них потратится памяти в progmem менше чем на двумерный.
Юлиан, кстати, а где кирилица ;) По бартеру - символы недостающие из "цифровых", правда форматы у нас не совпадают, но решаемо.
Осталось только в библиотеку затолкать. Незнаю с чего начать. Хачу что-то вроде adafruit_gfx. Может знатоки подскажут с чего начать...?
Определится с интерфейсами, можна OutStr(x,y,str, size, mode) в одном вызове, можна разными, типа SetSize(.., SetX(.., OutStr(str),.. Потом решить ООП/не ООП. Ща холивар будет ))) Полезно о разбиении на файлы подумать, вынести шрифты в отдельный, чтоб заменить проще было. Еще о оптимизации при частичном использовании подумать, чтоб, например, если без букв, только цифры нужны, так лишней памяти не отжирало для букв. Потом интнрфейсы в ашники, реализацию в сишники, шрифты отдельно в файл, а все файлы в папку. Папку в либы, на этом обязательная часть закончена. Примеры, доки подсветку идентификаторов - если силы останутся.
Воще говоря в данном случае толково будет чтоб либа просто решала задачу конвертации строки в вызов функций отрисовки линии. Тогда её можна юзать с любым экраном, лиш бы либа к экрану своя была и умела линии рисовать.
Вобщем долепил кирилицу. Итого 5 групп (цифры и знаки, латиница большая и малая с всякими тильдами ;) кирилица большая и малая), имею 5групп*32=160 символов. Минус один символ, сделал без '@', я эту хрень рисовать нибуду! ))) Заняли 1471 байт прогмема. Самым мелким шрифтом 5х8 былобы 795 байт. Ужать еще можна, я просто уже задолбался этим процессом, надо не ручками делать, а писать прогу. А там очень не тривиально, учитывая возможность один и тот же символ задать векторно в разном порядке начертания. Будет время - чето придумаю. И формат можна немного перекроить, теперь видно что команды М редкие и не разнообразные. Этот факт можна задействовать. Но пока работает и можна пользовать :)
Оценить размер в общем с кодом прорисовки векторного шрифта пока затруднительно, надо старый растровый сразу выпилить, но скетч компилится в 14КБ.
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;
Кирилицей пока не занимался. Не могу сообразить как получить код символа кирилицы из строки.
Кирилицей пока не занимался. Не могу сообразить как получить код символа кирилицы из строки.
Также как и латиницы. Тока у латиницы коды начинаются с 0x41 и 0x61 для заглавных и строчных а у кирилицы с 0xc0 и 0xe0. Ровно по 32 буквы в алфавитном порядке без Ё и ё. В общем согласно Windows-1251.
Это по результатам распаковки из сжатых. Теперь хочу оптимизировать сжатие. По ходу надо перевести все к одной матрице 7*15, а то часть так а часть 8*16. Тогда можна будет команду в байт засунуть. Старший бит будет определять тип команды: L или вызов библиотеки, команды M будут реализованы только в библиотеке и отличатся от остальных библиотечных диапазоном номеров. Еще с явным указанием количества байт в векторном описании симвала чтото придумать, былоб просто бомба.
#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();
}
Кирилицей пока не занимался. Не могу сообразить как получить код символа кирилицы из строки.
Также как и латиницы. Тока у латиницы коды начинаются с 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;
}
А че в preferences.txt параметр preproc.substitute_unicode? пробуйте вместо case144: так case 'А':. странная кодировка, чтоб кирилическая А стала 0х90. Наверно UTF-8, там 0xd090 должно быть. Тогда пробуйтеcase 0xd090:Что дают Serial.println(sizeof('А')); и Serial.println((uint16_t)'А',HEX);?
Чё за хрень.. А 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;
Чё за хрень.. А 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.
Не знаю что произошло, пришлось вкорячить костыль временный
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
Этот отчёт будет иметь больше информации с
включенной опцией Файл -> Настройки ->
"Показать подробный вывод во время компиляции"
Где можно взять голую библиотеку для 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));
}
Отлично выводит символ прям на экран без бухера. Но символ растровый. Векторный, т.е. набор линии, теоретически тоже можна, но я не осилил. Нужно перед выводом каждого байта сформировать этот байт основываясь на массиве координат точек начала конца линий. Нимагу алгоритм придумать, может кто поможет...
А если сначала определить размер символа ВхШ создать временный массив такого размера, отрисовать в нем символ (растеризовать), а потом вывести его как битмап в нужное место. Тогда буфер размером с экран не нужен.
А если сначала определить размер символа ВхШ создать временный массив такого размера, отрисовать в нем символ (растеризовать), а потом вывести его как битмап в нужное место. Тогда буфер размером с экран не нужен.
Да. Можна буфер размером в символ или в строку. А размером с экран, т.е. в 1Кб имея всего 2Кб ОЗУ - дурость. Да еще если статическиго буфера, как в одной популярной библиотеке:(
Пашу в свободное время над алгоритмом сжатия растрового шрифта. Сейчас все структуры и массивы занимают около 1,2Кб. Думаю реально до 1Кб сделать.
Костыль на костыле. Может кто преобразовываль числа с плавающей точкой в строки?
см. dtostrf()
А длинный красивый switch проигрывает некрасивому длинному if-у по progmem space. Ну, у меня так было, во всяком случае.
Воще и приобразовывать чето в стринг - это тоже не в тему векторного шрифта, достаточно строку выводить.
Картинка к вчерашнему ночному спринту ;)
//А длинный красивый 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 - резерв, потом может пригодится, может разрядность х и/или у увеличить может на флаг из пункта "в" задействовать.
Еще пожалуй стоит принять что перед прорисовкой каждого символа по умолчанию делается команда М, 0, 0. Если она для какого символа нужна такая первой, то её можна не указывать. Экономим.
Там ни то ни другое некрасиво, там массив указателей на векторное описание символа нужно.
Так-то да, но по свичу я не увидел непрерывной последовательности. В массиве будут null-евые ячейки. Оправдано это или нет в данном случае - не знаю. У меня на рисовалке по семисегментному индикатору "дешевле" вышло if-ов нашмалять.
Ну чё у нас данном случае null-евые ячейки? Нет реализации отрисовки данного символа, а если учесть что я вобщем так не символы а их группы, до 7 групп адресую (см#52) - то неприятность эту мы переживем. Получится нет заглавных кирилицы - ну null ей в корму )))
а в составе существующей группы если нет реализации отрисовки данного символа - длина 0, один байт издержек. Всё продумано. Надеюсь ;)
Я думаю что после того как нашли символ в группе необходимо в строке для вывода на дисплей посмотрет повторяется ли он. Если повторяется вывести его сразу чтобы не производить поиск снова. Завести битовый массив равный длине строки и отмечать в нем позиции уже выведенные чтобы повторно их не считывать.
Для этого нужно, чтобы все символы шрифта имели одинаковую ширину и не было кернинга. Но отказываться от пропорциональных шрифтов и от кернинга - это похерить всю прелесть использования векторных шрифтов. Чем они в этом случае лучше растровых?
Оно конечно можна, кеширование сделать, но не думаю что сильно ускорится. Основное время - на рисование прямых и выпихивание на экран. Рисование прямых можна ускорить если отдельно обрабатывать вертикали и горизонтали, а отдельно наклонные.
Я тут попробовал реализовать как описал. Чисто перекодировка строки в вызовы рисования прямых.
Вывод на экран без экрана :) В порт. Вроде работает. Только надо символов набросать, возьму наверно пока из Вашего примера и доброшу позже, пусть и без сжатия.
Померил время - около 0,05мсек на символ. Это понятно без собственно прорисовки на экран (и разумеется без вывода в порт). Но судя по цифре предыдущего кода порядка 2мсек на символ то и нормально, прорисовка намного дольше чем код распаковки.
Да, про ширину символа - я её по ходу прорисовки определяю, как максимальный х, делаю отступ в два пикселя и следующий символ с этого места.
Попробовал с экраном, цифры 0,1,2 - мои большие, остальные Ваши, поменше.
https://youtu.be/uCLsGVeV2Q4
Отлично получилось.
Попробовал масштабировать. Отлично! От 40% до 200% и все замечательно.
Запустил Вашу версию на своем дисплее SSD1306
Сижу вникаю, все работает.
И видео масштабирования https://youtu.be/i-GS8nJsbME
Код. Немного векторизацию цифр 6 и 2 правил.
Смотреть приятно, растр курит.
Продолжаю мучать свою версию
Теперь в буфер читаю не весь массив с описанием символа, а только по одной команде. (в теории можно безболезненно увеличить длину принимаемых векторных описаний символов без забивания памяти.
Организовал вывод разноширинных символов. Масштабирование - вместо * на 0,5 применил здвиг вправо на 1. Скорость прорисовки теперь 23-24мс на 65 символов в отличии от прошлого кода который выводил тое самое за 35-37мсек (если пользоватся стандартными средствами библиотеки то вывод на 10мсек быстрее) при масштабироаании с помощью средств библиотеки не проаер
Думаю что шрифт с самого начало нужно было делать маленким, чтобы не сталкиватся с масштабированием т.к. маленкий чаще принимают.
Теперь в буфер читаю не весь массив с описанием символа, а только по одной команде. (в теории можно безболезненно увеличить длину принимаемых векторных описаний символов без забивания памяти.
Очень правильно.
масштабироаании с помощью средств библиотеки не проаер
А там просто получаются большие квадратные "пиксели". И прорисует их тоже не быстро.
Думаю что шрифт с самого начало нужно было делать маленким, чтобы не сталкиватся с масштабированием т.к. маленкий чаще принимают.
Маленькие то чаще применяются, но масштабировать с маленьких в большие приведет к грубой прорисовке больших. А масштабирование из больших в малые нормально.
Наилучшее решение - координаты хранить в байте и "масштаб" в байте. Перемножение байтовых значений быстрое, одной ассемблерной командой. Перемножение 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; компактно компилится. Пример:
Компилируется в
А если сдвиг на 6 то уже с циклами, честно 6 раз прокрутит однобитный сдвиг :(
Эксперементировал с курсивом
Прикольно, на второй фотке вполне годно. Тоже про курсив думал. А еще и про "болд". Прорисовать символ с его координаты и повторно прорисовать сдвинув по горизонтали на 1. Должно с жирными вертикалями получится.
Попробовал. Было #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);;}
И стал болд ))
Тоже попробовал, неплохо получается.
Вопрос есть. Где можно взять голую библиотеку для OLED которая только пикселы может выводить? Чтобы на её основе свою сколхозить. Думаю этот материал использовать.
Где можно взять голую библиотеку для OLED которая только пикселы может выводить? Чтобы на её основе свою сколхозить. Думаю этот материал использовать.
Собственно, непосредственно на экран символы выводить невозможно.
Поэтому для пиксельной графики используется буферизация.
Ну а вывод пикселя в буфер от экрана никак не зависит. Поэтому, собственно, библиотека не нужна, нужна одна функция - вывод пикселя, которая сводится к установке одного бита в байте по вычисленному адресу. Т.е. вся "библиотека" - одна строка.
Буду разбиратся! Спасибо.
Где можно взять голую библиотеку для OLED которая только пикселы может выводить? Чтобы на её основе свою сколхозить. Думаю этот материал использовать.
Собственно, непосредственно на экран символы выводить невозможно.
Поэтому для пиксельной графики используется буферизация.
Ну а вывод пикселя в буфер от экрана никак не зависит. Поэтому, собственно, библиотека не нужна, нужна одна функция - вывод пикселя, которая сводится к установке одного бита в байте по вычисленному адресу. Т.е. вся "библиотека" - одна строка.
Ну не все так просто, еще инитить нужно.
Вывод пикселя у меня так.
Вывод буфера, это FRAME_MODE_BUFER
ПС. "Собственно, непосредственно на экран символы выводить невозможно." - чего вдруг? Все возможно,
Отлично выводит символ прям на экран без бухера. Но символ растровый. Векторный, т.е. набор линии, теоретически тоже можна, но я не осилил. Нужно перед выводом каждого байта сформировать этот байт основываясь на массиве координат точек начала конца линий. Нимагу алгоритм придумать, может кто поможет...
ПС. "Собственно, непосредственно на экран символы выводить невозможно." - чего вдруг? Все возможно,
Опечатка. Следует читать, естественно, "пиксели" - собственно именно о них и шла речь.
А с пикселем, не все так просто. Как видно из кода вывод идет побайтно, т.е. сразу по 8 пикселей. И вобщем вывести сам один пиксель можна, но возникает вопрос а чё делать с остальными 7 пикселями. И тут есть 2 подхода: 1. взять их из буфера, в таком случае буфер необходим. 2. определить их каким либо образом, ведь както мы ж их в коде определяем, это бывает не так просто, как непросто в случае с линиями векторного шрифта, но принципиально возможно. Тогда и без буфера можна.
Добавил латиницу и немного извращений. https://youtu.be/Omc9WdDXeWE
А всегото вывод линий стал
Добавил латиницу и немного извращений. https://youtu.be/Omc9WdDXeWE
А всегото вывод линий стал
Заработал лайк! Прикольно получилось. Напомнило как в старых играх имена победителей вводились. Кольцо символов врощаеш пока нужный в фокус не встанет, затем выбираеш и для ввода следующего опять вращаеш...
Еще немного фото
Цифры
Цифры Bold + Italic
Заглавные латиница
Заглавные латиница Bold
Строчные латиница
Максимальная высота символов 18 пикселей.
Когда Bold прорисовываю, горизонтальные линии пропускаю для ускорения прорисовки.
Размер шрифта задаю в пикселях
Осталось только в библиотеку затолкать. Незнаю с чего начать. Хачу что-то вроде adafruit_gfx. Может знатоки подскажут с чего начать...?
Код всего безобразия
Юлиан - описание фонта лучше делать в виде двумерного массива, где первый инлекс - указатель по коду ASCII. Тогда этот огромный switch -case начния со строки 322 можно будет выкинуть
Еще немного фото
Цифры
ифры Bold + Italic
Заглавные латиница
Заглавные латиница Bold
трочные латиница
yul-i-an, возможны два варианта:
1. Вас сразу же начнут донимать насчет кириллицы.
2. Вас не начнут донимать.
При этом "2" безусловно означает, что Ваша идея осталась невостребованной.
Юлиан - описание фонта лучше делать в виде двумерного массива, где первый инлекс - указатель по коду ASCII. Тогда этот огромный switch -case начния со строки 322 можно будет выкинуть
Про свичь +1. Но двумерный то зачем? Ну коды символов не от нуля, та к делаем -0х20 и усьо. Да, есть в реализации шрифтов пропуски символов, хотя вобще их конечно быть не должно, ну будут 0. Всеравно на них потратится памяти в progmem менше чем на двумерный.
Юлиан, кстати, а где кирилица ;) По бартеру - символы недостающие из "цифровых", правда форматы у нас не совпадают, но решаемо.
Осталось только в библиотеку затолкать. Незнаю с чего начать. Хачу что-то вроде adafruit_gfx. Может знатоки подскажут с чего начать...?
Определится с интерфейсами, можна OutStr(x,y,str, size, mode) в одном вызове, можна разными, типа SetSize(.., SetX(.., OutStr(str),.. Потом решить ООП/не ООП. Ща холивар будет ))) Полезно о разбиении на файлы подумать, вынести шрифты в отдельный, чтоб заменить проще было. Еще о оптимизации при частичном использовании подумать, чтоб, например, если без букв, только цифры нужны, так лишней памяти не отжирало для букв. Потом интнрфейсы в ашники, реализацию в сишники, шрифты отдельно в файл, а все файлы в папку. Папку в либы, на этом обязательная часть закончена. Примеры, доки подсветку идентификаторов - если силы останутся.
Воще говоря в данном случае толково будет чтоб либа просто решала задачу конвертации строки в вызов функций отрисовки линии. Тогда её можна юзать с любым экраном, лиш бы либа к экрану своя была и умела линии рисовать.
Вобщем долепил кирилицу. Итого 5 групп (цифры и знаки, латиница большая и малая с всякими тильдами ;) кирилица большая и малая), имею 5групп*32=160 символов. Минус один символ, сделал без '@', я эту хрень рисовать нибуду! ))) Заняли 1471 байт прогмема. Самым мелким шрифтом 5х8 былобы 795 байт. Ужать еще можна, я просто уже задолбался этим процессом, надо не ручками делать, а писать прогу. А там очень не тривиально, учитывая возможность один и тот же символ задать векторно в разном порядке начертания. Будет время - чето придумаю. И формат можна немного перекроить, теперь видно что команды М редкие и не разнообразные. Этот факт можна задействовать. Но пока работает и можна пользовать :)
Оценить размер в общем с кодом прорисовки векторного шрифта пока затруднительно, надо старый растровый сразу выпилить, но скетч компилится в 14КБ.
Я тоже немного эксперементировал.
Чуть чуть сжал массив
Распаковываю так
Повторяющиеся элементы вывожу так
Кирилицей пока не занимался. Не могу сообразить как получить код символа кирилицы из строки.
Кирилицей пока не занимался. Не могу сообразить как получить код символа кирилицы из строки.
Также как и латиницы. Тока у латиницы коды начинаются с 0x41 и 0x61 для заглавных и строчных а у кирилицы с 0xc0 и 0xe0. Ровно по 32 буквы в алфавитном порядке без Ё и ё. В общем согласно Windows-1251.
Все 159 символов без ужатия более 2К занимают:
Это по результатам распаковки из сжатых. Теперь хочу оптимизировать сжатие. По ходу надо перевести все к одной матрице 7*15, а то часть так а часть 8*16. Тогда можна будет команду в байт засунуть. Старший бит будет определять тип команды: L или вызов библиотеки, команды M будут реализованы только в библиотеке и отличатся от остальных библиотечных диапазоном номеров. Еще с явным указанием количества байт в векторном описании симвала чтото придумать, былоб просто бомба.
Запихал в недобиблиотеку
пример
Сравнить с растром!
Кирилицей пока не занимался. Не могу сообразить как получить код символа кирилицы из строки.
Также как и латиницы. Тока у латиницы коды начинаются с 0x41 и 0x61 для заглавных и строчных а у кирилицы с 0xc0 и 0xe0. Ровно по 32 буквы в алфавитном порядке без Ё и ё. В общем согласно Windows-1251.
Так и немогу сообразить как получить код символа в кирилице.
Я у себя так делаю
Если передаю символ на кирилице, получаю прочерк (по умолчанию в case если символа для отрисовки нет то "-" вывести )
например пробовал так
Получил "-"
Непонятно.
Попробуйте Serial.println((uint8_t)'А'); в монитор прийдет код символа.
Можна прямо писать case 'А':
Попробуйте Serial.println((uint8_t)'А'); в монитор прийдет код символа.
Можна прямо писать case 'А':
Попробовал. А-144, Я-175, а-176, я-143. Бред какойто. Латиница 65-122 от A до z по таблице.
Пробовал
Не катит.
А че в preferences.txt параметр preproc.substitute_unicode? пробуйте вместо
case
144:
такcase
'А':
. странная кодировка, чтоб кирилическая А стала 0х90. Наверно UTF-8, там 0xd090 должно быть. Тогда пробуйтеcase
0xd090:
Что дают Serial.println(sizeof('А')); и Serial.println((uint16_t)'А',HEX);?preproc.substitute_unicode = true
Дает
2
D090
не помогает
Менял preproc.substitute_unicode = false результата нет.
таки UTF-8. Значить пробуйте
case
0xd090:
А версия ИДЕ какая?таки UTF-8. Значить пробуйте
case
0xd090:
А версия ИДЕ какая?ИДЕ 1.8.7
case
0xd090: не помогло
Чё за хрень.. А Serial.println(sizeof(sym)); и Serial.println((uint16_t)sym,HEX); непосредственно перед
switch
(sym)
что дают.Чё за хрень.. А Serial.println(sizeof(sym)); и Serial.println((uint16_t)sym,HEX); непосредственно перед
switch
(sym)
что дают.1
C0
Попробовал так
Заработало ввроде
Чё за хрень.. А Serial.println(sizeof(sym)); и Serial.println((uint16_t)sym,HEX); непосредственно перед
switch
(sym)
что дают.1
C0
Попробовал так
Заработало ввроде
Заработало после замены char sym; на byte sym. Но это было вчера. Нарисовал кирилицу, все работало. Сегодня тотже скетч без изменений перезагрузил иместо всех символов кирилицы выводится лат. P.
Тест
опять выводит
2
D090
Не знаю что произошло, пришлось вкорячить костыль временный
Почемуто не получилось так написать
Ошибку компилятор выдал
Приходится пока так
Шрифт пока не полный
Изменил костыль
Пока все работает
Недобиблиотека VF
Кирилица пока только заглавная
Где можно взять голую библиотеку для OLED которая только пикселы может выводить? Чтобы на её основе свою сколхозить. Думаю этот материал использовать.
Собственно, непосредственно на экран символы выводить невозможно.
Поэтому для пиксельной графики используется буферизация.
Ну а вывод пикселя в буфер от экрана никак не зависит. Поэтому, собственно, библиотека не нужна, нужна одна функция - вывод пикселя, которая сводится к установке одного бита в байте по вычисленному адресу. Т.е. вся "библиотека" - одна строка.
Ну не все так просто, еще инитить нужно.
Вывод пикселя у меня так.
Вывод буфера, это FRAME_MODE_BUFER
ПС. "Собственно, непосредственно на экран символы выводить невозможно." - чего вдруг? Все возможно,
Отлично выводит символ прям на экран без бухера. Но символ растровый. Векторный, т.е. набор линии, теоретически тоже можна, но я не осилил. Нужно перед выводом каждого байта сформировать этот байт основываясь на массиве координат точек начала конца линий. Нимагу алгоритм придумать, может кто поможет...
А если сначала определить размер символа ВхШ создать временный массив такого размера, отрисовать в нем символ (растеризовать), а потом вывести его как битмап в нужное место. Тогда буфер размером с экран не нужен.
А если сначала определить размер символа ВхШ создать временный массив такого размера, отрисовать в нем символ (растеризовать), а потом вывести его как битмап в нужное место. Тогда буфер размером с экран не нужен.
Да. Можна буфер размером в символ или в строку. А размером с экран, т.е. в 1Кб имея всего 2Кб ОЗУ - дурость. Да еще если статическиго буфера, как в одной популярной библиотеке:(
Пашу в свободное время над алгоритмом сжатия растрового шрифта. Сейчас все структуры и массивы занимают около 1,2Кб. Думаю реально до 1Кб сделать.