|
|
![]() ![]() |
|
|
![]() ![]() ![]() ![]() |
|
Опции темы | Поиск в этой теме |
![]() |
![]() ![]() |
Ветеран Фонарёвки
Регистрация: 15.02.2010 Последняя активность: 24.08.2019 11:36
Сообщений: 1342
Сказал(а) спасибо: 0
Поблагодарили: 0 раз(а) в 0 сообщениях
|
![]()
Делай программный ШИМ, но с прерываниями от таймера(ов). Между прерываниями программа будет заниматься своими делами, и переключать состояния пинов по прерыванию. Такты считать не придётся, лишь бы хватило производительности...
У меня в RGB индикаторе так реализовано. В принципе туда можно сколько угодно так каналов налепить, особенно если они все будут работать в динамическом режиме (один мультиплексируемый канал)... |
![]() |
![]() ![]() |
![]() |
![]() ![]() |
Ветеран Фонарёвки
|
![]()
производительности хватает - реализации есть, просто начинаю изучать
![]() Спасибо за совет. |
![]() |
![]() ![]() |
![]() ![]() |
![]() ![]() |
|
Увлеченный
Регистрация: 21.06.2010 Последняя активность: 01.08.2015 23:26
Сообщений: 179
Сказал(а) спасибо: 0
Поблагодарили: 0 раз(а) в 0 сообщениях
|
![]() Цитата:
Си имеет сокращенную запись для строки. Массив c[] = { 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 0 }; может быть записан следующим образом: c[] = "Hello world"; Это абсолютно одно и то же, только более короткая запись. Копирование, конкатенация и прочие операции над строками делаются с помощью циклов. Поскольку в конце каждой строки стоит байт с кодом 0, обычно используется цикл while. В стандартной библиотеке C имеется набор готовых функций на основе таких циклов: strlen - определяет длину строки strcpy - копирует побайтно строку (массив в массив) strnlen - то же самое, но обрезает строку, если она не влезает в отведенное для нее место (strlen в этом случае молча портит содержимое памяти) memcpy - копирует содержимое массива побайтно (на 0 в конце строк внимания не обращает, число байтов указывается) strcmp - сравнивает две строки побайтно memcmp - сравнивает два массива байтов побайтно strcat - конкатенация двух строк, сокращение для strlen+memcpy+memcpy Все эти функции объявлены в string.h. Для форматирования строк для вывода на экран можно использовать sprintf или snprintf. Описание всех этих функций есть в любом руководстве по Си, дублировать его я не буду. Следует иметь в виду, что работа со строками (копирование и т.п.) всегда крайне медленна и затратна. PHP и Pascal скрывают эту сложность, Си - нет. На микроконтроллере использования string.h вообще лучше избегать, построив программу таким образом, чтобы она вообще использовала только константные строки. На большом компьютере (не на микроконтроллере) есть еще выделение памяти. Там появляются дополнительные функции: malloc - выделить память free - освободить память strdup - сокращенная запись strlen+malloc+memcpy На микроконтроллере они бесполезны. Использование строк на микроконтроллере имеет свою специфику. Там строки и массивы бывают двух видов - в оперативной памяти и в памяти программ. Поэтому у таких функций, как strcpy, появляются двойники, отличающиеся тем, что читают строку из флеша, а не из ОЗУ. Их описание есть в документации на AVR-LIBC. |
|
![]() |
![]() ![]() |
![]() |
![]() ![]() |
||
Завсегдатай Фонарёвки
|
![]() Цитата:
Мой код с листингом выглядит так: Код:
lcd[2]='M'; 56e: 8d e4 ldi r24, 0x4D ; 77 570: 80 93 02 01 sts 0x0102, r24 lcd[3]='H'; 574: 88 e4 ldi r24, 0x48 ; 72 576: 80 93 03 01 sts 0x0103, r24 lcd[4]='z'; 57a: 8a e7 ldi r24, 0x7A ; 122 57c: 80 93 04 01 sts 0x0104, r24 Цитата:
|
||
![]() |
![]() ![]() |
![]() ![]() |
![]() ![]() |
||
Увлеченный
Регистрация: 21.06.2010 Последняя активность: 01.08.2015 23:26
Сообщений: 179
Сказал(а) спасибо: 0
Поблагодарили: 0 раз(а) в 0 сообщениях
|
![]() Цитата:
Код:
memcpy_P(lcd+2, PSTR("MHz"), 3); Добавлено через 1 минуту Цитата:
Код:
lcd_gotoxy(1, 3); lcd_put_text(PSTR("MHz")); PSTR - это специальный макрос, указывающий, что строка не должна размещаться в оперативной памяти. Такая строка либо кладется во флеш и грузится инструкцией lpm, либо непосредственно подставляется в инструкции ldi. |
||
![]() |
![]() ![]() |
![]() |
![]() ![]() |
Завсегдатай Фонарёвки
|
![]()
Gall Так если дисплей я могу обновлять только целиком, значит должен где-то в памяти быть буффер всего экрана, как иначе?
|
![]() |
![]() ![]() |
![]() ![]() |
![]() ![]() |
Увлеченный
Регистрация: 21.06.2010 Последняя активность: 01.08.2015 23:26
Сообщений: 179
Сказал(а) спасибо: 0
Поблагодарили: 0 раз(а) в 0 сообщениях
|
![]() |
![]() |
![]() ![]() |
![]() |
![]() ![]() |
Завсегдатай Фонарёвки
|
![]()
Ну например у дисплея 3310 такая хитрая адресация, что обновлять можно только по строкам в 8 пикселей в высоту. А если я хочу шрифт сделать чуть больше - тут надо весь экран перерисовывать, т.к. будут задеваться соседние строки.
Тоесть: в нём 6 строк по 8 пикселей в высоту, и если мне надо что-то перерисовать - затираться будет именно столбиками по 8 пикселей. Дурацкая адресация ![]() |
![]() |
![]() ![]() |
![]() ![]() |
![]() ![]() |
Увлеченный
Регистрация: 21.06.2010 Последняя активность: 01.08.2015 23:26
Сообщений: 179
Сказал(а) спасибо: 0
Поблагодарили: 0 раз(а) в 0 сообщениях
|
![]() Цитата:
Если ширина знакоместа равна одному целому или половине блока битов, ширина трех знакомест равна двум блокам и т.п., то имеет смысл оперировать соответствующими группами байтов (диграммами или триграммами) вместо отдельных символов. При 8-битном экране и шрифте 6x8 работать триграммами - самое милое дело. При этом больше трех символов в памяти никогда не хранится, а биты не хранятся совсем. Отрисовка экрана при этом происходит "вразнобой", но на большинстве экранов это никак не сказывается на быстродействии. Если пиксели расположены вертикальными блоками, то все еще проще. Символ в этом случае делается равным целому блоку, тем более что символы меьше 8 пикселей в высоту читаются очень плохо. Тогда буферизуется один символ, отрисовывается слева направо по столбцам. Если по какой-то причине надо обновлять часть изображения (не текста) на экране, например, при рисовании графиков, это можно сделать за счет организации фреймбуфера. В памяти располагается битовая маска, соответствующая пикселам экрана. Рисование делается на фреймбуфере непосредственно (это не проблема), после чего его часть переносится на дисплей. Этот режим работы вполне соответствует графике на мониторе CGA, EGA или ZX Spectrum, поэтому относительно такого метода рисования отсылаю к соответствующей литературе. Может случиться, однако, что памяти под организацию фреймбуфера не хватает. В этом случае используется возможность подгрузки частей изображения обратно из дисплея в контроллер для организации частичного фреймбуфера (в пределе - 1-байтного). Для такого режима имеются исключительно эффективные алгоритмы, например, алгоритм рисования прямых линий Брезенхэма. |
![]() |
![]() ![]() |
![]() |
![]() ![]() |
Ветеран Фонарёвки
Регистрация: 15.02.2010 Последняя активность: 05.09.2022 18:18
Сообщений: 1034
Сказал(а) спасибо: 0
Поблагодарили: 0 раз(а) в 0 сообщениях
|
![]()
Не понял проблемы. 8МГц AVR-ки хватает, чтоб перерисовывать весь экран десятки раз в секунду. Вы чего, с килогерцовой частотой экран обновлять хотите? Так глаз все равно это не отследит
![]() |
![]() |
![]() ![]() |
![]() ![]() |
![]() ![]() |
Увлеченный
Регистрация: 21.06.2010 Последняя активность: 01.08.2015 23:26
Сообщений: 179
Сказал(а) спасибо: 0
Поблагодарили: 0 раз(а) в 0 сообщениях
|
![]()
Сразу видно, ни разу с дисплеями не работал
![]() |
![]() |
![]() ![]() |
![]() |
![]() ![]() |
|
Ветеран Фонарёвки
Регистрация: 15.02.2010 Последняя активность: 05.09.2022 18:18
Сообщений: 1034
Сказал(а) спасибо: 0
Поблагодарили: 0 раз(а) в 0 сообщениях
|
![]() Цитата:
![]() |
|
![]() |
![]() ![]() |
![]() ![]() |
![]() ![]() |
Увлеченный
Регистрация: 21.06.2010 Последняя активность: 01.08.2015 23:26
Сообщений: 179
Сказал(а) спасибо: 0
Поблагодарили: 0 раз(а) в 0 сообщениях
|
![]() Цитата:
Для ГРАФИЧЕСКОГО дисплея в чисто текстовом режиме можно использовать тот же подход. Кусок изображения, поверх которого выводятся новые символы, все равно затирается. Для графического дисплея, на котором текст чередуется с настоящей графикой, необходимо либо хранить пиксели, либо заново рендерить. |
![]() |
![]() ![]() |
![]() |
![]() ![]() |
Завсегдатай Фонарёвки
|
![]()
Gall, давай я попробую картинкой обьяснить, что я хочу. Вот допустим кусок дисплея от 3310, адресация там по строкам в 8 пикселей в высоту. А я допустим хочу написать текст шрифтом 12 пикселей.
Вложение 3072 В итоге, если я захочу перерисовать "строка текста #2", я обязан перерисовать "строка дисплея #2". А эта строка захватила обе текстовых строки, и я ну никак не могу её перерисовать, если я до этого не хранил "строка текста #1". В итоге, мне надо постоянно хранить обе строки текста, т.к. без одной я не могу обновить другую, чтобы не затереть кусок первой. Конечно можно "строка дисплея #2" прочесть из дисплея назад в мк, изменить её нижнюю половину, и залить назад, но это крайне затратно по скорости такого обновления и тактам мк... В итоге, у меня ГРАФИЧЕСКИЙ дисплей в чисто текстовом режиме, но я не могу вот так влоб обновить лишь одну из строк. |
![]() |
![]() ![]() |
![]() ![]() |
![]() ![]() |
Увлеченный
Регистрация: 21.06.2010 Последняя активность: 01.08.2015 23:26
Сообщений: 179
Сказал(а) спасибо: 0
Поблагодарили: 0 раз(а) в 0 сообщениях
|
![]()
Существует и третье решение. А именно, научиться определять нужные символы, не храня строки полностью. Для отображения цифр оно как правило оптимально, поскольку число в памяти скорее всего хранится, определение цифры по числу - операция легкая.
Если же более удобным кажется организация теневой видеопамяти (именно так по-научному называется хранение строк для отображения в памяти), то это лучше делать не как строки, а как ДВУМЕРНЫЙ массив символов. Каждому элементу такого массива однозначно соответствует некоторая позиция экрана. Изменения отдельных элементов массива делается прямым присваиванием, а групп элементов - memcpy / memcpy_P или в цикле. На таком массиве можно сделать исключительно эффективный алгоритм перевода двоичных чисел в символы. Правильный тип такого массива - char[M][N] для экрана MxN символов. Если памяти микроконтроллера достаточно, можно сделать теневую видеопамять не символов, а пикселей (фреймбуфер). Тогда каждому пикселю экрана будет соответствовать 1 бит. Правильный тип такого массива - uint8_t[M/8][N] для экрана разрешением MxN. Такая организация позволяет легко рисовать линии и окружности, выводить графики. По сравнению с чисто текстовой памятью требуется в 5-8 раз больше байтов, поэтому решение подходит только для МК с достаточно большим ОЗУ или с подключенной внешней памятью. При подключении 64к внешнего ОЗУ возможен вывод сложных изображений на телевизор, как в "Денди". |
![]() |
![]() ![]() |
![]() |
![]() ![]() |
Ветеран Фонарёвки
Регистрация: 15.02.2010 Последняя активность: 05.09.2022 18:18
Сообщений: 1034
Сказал(а) спасибо: 0
Поблагодарили: 0 раз(а) в 0 сообщениях
|
![]()
SviMik, ты бы подробнее описал, для чего дисплей, какой МК, и т.д. Тогда и советы были бы конкретнее.
Одно дело чисто интерфейсный дисплейчик, который подключается к примеру в USB. Тут на МК нужен просто тупой транслятор из USB в экран. Шрифты, видеопамять, логику можно вынести в драйвер/управляющее ПО. И совсем другой вариант - автономный контроллер с экранчиком. И кстати, при разработке девайсов на МК, есть еще пара аспектов: 1. Экономический. При небольшой партии устройств, скажем до 100..1000шт, может быть выгодней упростить(и удешевить) разработку ПО, за счет применения более дорогих комлектующих(с большим объемом памяти, быстродействием и т.д). При больших объемах (от 10000..100000шт) наоборот, выгоднее экономить на комплектующих, за счет усложнения ПО и разработки в целом. При средних- соответственно середина на половину ![]() 2. Надежность устройства и удобство поддержки. Принцип тут простой: чем сложнее алгоритм, тем больше вероятность глюков и сложнее эти глюки лечить. Из личных наблюдений: У простых программ и глюки простые- зависла или свалилась. А вот начиная с определенного уровня сложности, программа уже начинает жить какой-то своей жизнью.... |
![]() |
![]() ![]() |
![]() |
![]() ![]() |
Завсегдатай Фонарёвки
|
![]()
AVSel Естественно, автономный! МК - мега48 (но ОЗУ уже осталось мало), дисплей - третий раз пишу, от нокии 3310
![]() |
![]() |
![]() ![]() |
![]() |
![]() ![]() |
Ветеран Фонарёвки
Регистрация: 15.02.2010 Последняя активность: 05.09.2022 18:18
Сообщений: 1034
Сказал(а) спасибо: 0
Поблагодарили: 0 раз(а) в 0 сообщениях
|
![]()
Мда, не особо развернешся...
У тебя вроде все тексты константные, сделай теневую видеопамять, где будут храниться индексы выведенных на экран строк. Всего 5..10 байт потребуется. Или мегу88 ставь и сразу будет вагон запасной памяти. Которая правда тоже быстро закончится ![]() |
![]() |
![]() ![]() |
![]() ![]() |
![]() ![]() |
Увлеченный
Регистрация: 21.06.2010 Последняя активность: 01.08.2015 23:26
Сообщений: 179
Сказал(а) спасибо: 0
Поблагодарили: 0 раз(а) в 0 сообщениях
|
![]()
Сжатие спасет. И константы в ПЗУ. Хранить индексы массивов из ПЗУ дешевле, чем строки из ОЗУ. Если количество разнообразных выводимых строк невелико, это спасает.
Что касается сжатия, то даже элементарное RLE может иногда жать в 10 раз. Иногда - Хаффман. Эти алгоритмы достаточно быстры, чтобы не напрягать процессор, и достаточно малы, чтобы лезть в память. Пример "продвинутой" работы с дисплеем nokia есть в коде Yampp (www.myplace.nu). Вообще же, если выводить надо только текст, я настоятельно не рекомендую использовать графические ЖКИ и ограничиваться чисто текстовыми со встроенным знакогенератором - разумеется, если есть подходящий по габаритам. Экраны от сотиков имеет смысл ставить только тогда, когда другой экран не влезает в корпус. Это очень большая экономия при программировании. А еще есть мега168. |
![]() |
![]() ![]() |
![]() |
![]() ![]() |
Лазеростроитель
Регистрация: 19.12.2011 Последняя активность: 30.12.2011 20:41
Сообщений: 1
Сказал(а) спасибо: 0
Поблагодарили: 0 раз(а) в 0 сообщениях
|
![]()
Доброго времени суток жителям форума! Вопрос вот в чем, накидал програмку для tyni13. Должна по внешнеу событию переключать порта.
Ткните пож. носом где и что не так. P.S. Программу пишу первый раз, языков не знаю, но оч нужно! |
![]() |
![]() ![]() |