понедельник, 19 июля 2021 г.

семисегментный printf

Разобравшись с драйвером неплохо научиться выводить на него информацию. Как вы помните с первого курса, текст и числа в любом формате на экран можно выводить через printf. Так вот, давайте адаптируем эту функцию под выбранный тип, с позволения сказать, экрана. Про особенности языка потом, сперва нужен алфавит, ну чтож, википедия, настало твоё время:
Теперь, как будем вносить эту таблицу, думаете массивом? Было бы логично, но не в моем случае. Поступим по другому, на каждый сегмент выделим по макросу. А символы будем задавать в switch case как сумму макросов. Контроллер хоть и не железный, но проглотит и такой код. Так вот, при таком подходе можно менять биты, соответствующие разным сегментам. То есть теперь можно и не по порядку 0-1-2-3-4-5-6-7 и A-B-C-D-E-F-G-DP, а произвольно. Таким способом мы и получили возможность развести печатную плату так, как нам удобнее. Здесь приведу только отрывок функции uint8_t alphabet(char c) где c - ACSI символ, а возвращаемое восьмибитное число, это то что отправляется в драйвер. 

case '9': return SEGA + SEGB + SEGC + SEGD + SEGF + SEGG; break; case 'A': case 'a': return SEGA + SEGB + SEGC + SEGE + SEGF + SEGG; break; case 'B': case 'b': return SEGC + SEGD + SEGE + SEGF + SEGG; break; case '[' : case 'C' : case 'c' : return SEGA + SEGD + SEGE + SEGF; break; case 'D' : case 'd' : return SEGB + SEGC + SEGD + SEGE + SEGG;

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

for( uint8_t i = 0 ; (i < strlen(buffer)) && (outCnt < DIGITS) ; ++i ) { if( (buffer[i] != '.') && (buffer[i] != ',') && \ ((buffer[i+1] == '.') || (buffer[i+1] == ',')) ) { dispBuffer[outCnt++] = (alphabet(buffer[i++]) | SEGDP); } else { dispBuffer[outCnt++] = (alphabet(buffer[i])); } }

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

void myprintf(char *format, ... ) { char buffer[DIGITS*4]; uint8_t dispBuffer[DIGITS]; va_list args; va_start (args, format); vsprintf (buffer, format, args); va_end (args);

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

tmUpd(dispBuffer);

А теперь, не побоюсь этого слова, во же сколько нам обойдется такой шик. В случае с восьмибитками нереально дорого. Эти полтора килобайта 1/5 всей памяти какой нибудь восьмой меги. Для stm с их 32 на минималках, как то пофиг, попробуйте забить у них всю память, у меня только на половину получалось. Файлы с кодом вот и вот.

Комментариев нет :

Отправить комментарий