AVR. Учебный Курс. Библиотека для LCD на базе HD44780

Сел я и дописал свою библиотеку для LCD на базе HD44780.

Как она работает я тут расписывать не буду — код весьма плотно фарширован комментариями. Тем более я уже рассказывал как работать с этим дисплеем Поэтому, думаю, разберетесь. Если будут вопросы, то обращайтесь. Тут же я расскажу как ей пользоваться.

Состав
Библиотека состоит из двух файлов LCD.asm и LCD_macro.inc для подключения по 8ми битной шине и LCD4.asm и LCD4_macro.inc для подключения по четырех битной шине данных. Используете тот вариант, по которому у вас подключен дисплей.

  • Файл LCD.asm содержит все основные настройки портов и, собственно, код.
  • LCD_macro.inc содержит макросы для работы с дисплеем. И используется для работы с библиотекой.
Подключение LCD к микроконтроллеру.
Порт данных использует биты 7…4 любого порта на 4 битном подключении, или весь порт целиком на 8ми разрядном
Порт управления использует 3 любых бита любого порта. Главное, чтобы они были на одном порту. Впрочем код можно и чуток подправить :)

Подключение библиотеки в код.
Где нибудь в начале программы, там где обычно определяют макросы, добавляете строчку

1
.include "LCD4_macro.inc"

А в конце кода, там где все процедуры, добавляете

1
.include "LCD4.asm"

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

Настройка
В файле LCD.asm есть раздел LCD_Define

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
;=========== LCD Define ====================================
	.equ	DATA_PORT	= PORTB		; LCD Порт данных
	.equ	DATA_PIN	= PINB
	.equ	DATA_DDR	= DDRB
 
	.equ	CMD_PORT	= PORTA		; LCD Порт управления
	.equ	CMD_PIN		= PINA
	.equ	CMD_DDR	= DDRA
 
	.equ	E		= 0		; Бит строба
	.equ	RW		= 1		; Бит чтения/записи
	.equ	RS		= 2		; Бит команда/Данные
 
	.equ	SPEED	= 14	; 14 для XTAL=16MHz, 10 для XTAL=8MHz,  
				; 6 для XTAL=4MHz, 5 для XTAL<4MHz

Порт данных и порт управления указывай те, которые у тебя используются. У меня вот это В и А. Также не забудь указать к каким битам подключены линии управления.
Параметр SPEED задается в зависимости от скорости кристалла. Больше можно, меньше нет. Можно поставить 14 и не парится. Но некрасиво :)

В файле LCD_macro.inc нужно найти блок настроек дисплея и выставить там нужные биты. Выглядит это так:

1
2
3
4
5
6
7
8
9
10
11
12
13
	.MACRO	INIT_LCD				; Инициализация LCD
	RCALL	InitHW					; Настроить контрольный порт
	RCALL	LCD_DELAY				; Подождать
	WR_CMD	(1<<LCD_F)|(0<<LCD_F_8B)		; Выдать функцию смены разрядности.
	WR_CMD	(1<<LCD_F)|(0<<LCD_F_8B)|(1<<LCD_F_2L) 	; Дважды.
 
; Так как по дефолту шина 8 бит и нельзя передать сразу вторую половину байта.
 
	WR_CMD	(1<<LCD_CLR)								;0x01
	WR_CMD	(1<<LCD_ENTRY_MODE)|(1<<LCD_ENTRY_INC)					;0x06
	WR_CMD	(1<<LCD_ON)|(1<<LCD_ON_DISPLAY)|(0<<LCD_ON_CURSOR)|(0<<LCD_ON_BLINK)	;0x0C
	WR_CMD	(1<<LCD_HOME)		
	.ENDM

Перечень опций, сгруппированных по типу приведен там чуть выше. Обращу внимание на то, что инициализация 4х разрядной шины идет ДВА РАЗА. Первый раз мы говорим контроллеру, что у нас шина 4 разрядная. Но при этом мы не можем сказать второй полубайт слова управления. Поэтому, когда контроллер перейдет на 4х разрядный режим, выдаем нашу посылку снова, на этот раз вторая тетрада нормально пройдет.

Использование
Перед первым использованием надо сделать инициализацию индикатора. Делается это макросом

1
	INIT_LCD

При этом задаются параметры дисплея, указанные в разделе инициализации.

Запись байта в дисплей осуществляется макросами

1
2
	WR_CMD xx
	WR_DATA xx

Где вместо хх вписываем наш байт.

Если надо выдать на экран, что либо программно сгенеренное, в таком случае используется прямой вызов процедуры. Байт передается через регистр R17.

1
2
	RCALL	CMD_WR
	RCALL	DATA_WR

Чтение осуществляется аналогичным образом:

1
2
	RD_CMD
	RD_DATA

или

1
2
	RCALL	CMD_RD
	RCALL	DATA_RD

В данном случае макрос и процедура ничем не отличаются. Сделано просто для унификации. Считанный байт будет в регистре R17

Установка координаты курсора осуществляется макросом
LCD_COORD X,Y
Где X и Y координаты по горизонтали, и вертикали в знакоместах.

Сдвиг курсора или экрана осуществляется макросом SHIFT xx, где вместо xx подставляются нужные аргументы

1
2
3
4
	SHIFT SCR_L 	; сдвиг экрана влево
	SHIFT SCR_К	; сдвиг экрана вправо
	SHIFT CUR_L	; сдвиг курсора влево
	SHIFT CUR_R	; сдвиг курсора вправо

Макрос LCDCLR делает полную очистку видеопамяти.

Макрос WR_CGADR xx позволяет установить указатель в область памяти знакогенератора, чтобы можно было записать свой символ. Если затем начать слать данные, то они будут записаны в ячейки знакогенератора.
Макрос RD_CGADR xx позволяет установить указатель в область памяти знакогенератора,чтобы можно было считать байт из знакогенератора.
Макрос WR_DDADR xx устанавливает указатель на видео память. С этого момента все данные попадают на экран.

Для примера попробуем создать зиг руну, ранее упомянутую в записи про описании контроллера

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
	INIT_LCD		; Инициализируем
 
	WR_CGADR 0		; Указатель на начало знакогенератора.
 
	WR_DATA 0b00000001	; Запись данных нового знака
	WR_DATA 0b00000010
	WR_DATA 0b00000100
	WR_DATA 0b00011111
	WR_DATA 0b00000010
	WR_DATA 0b00000100
	WR_DATA 0b00001000
 
	WR_DDADR 0		; Указатель на начало видео памяти (ячейка с координатми 0,0)
 
	WR_DATA 0		; У новоиспеченного символа код 0 напечатем его

Системные требования и ограничения
Используется система команда ATMega на некоторых ATTiny может начать ругаться. Придется править. Занимает 474 байта кода в максимальном исполнении (4 битная шина). На 8ми битной шине будет байт на 100 короче. Если выкинуть процедуру чтения, то будет еще короче.

Процедура активно использует регистр R16 и R17, поэтому их содержимое меняется непредсказуемым образом!!! Так что либо учитывайте это, либо сохраняйте заранее эти регистры.

Вот так вот, если что будет нового то выпущу версию 2. Пользуйтесь.

360 thoughts on “AVR. Учебный Курс. Библиотека для LCD на базе HD44780”

    1. По дефолту контроллер ждет данные по 8ми битной шине. А У нас подключено только по 4х битной, поэтому младший полубайт мы передать не сможем и контроллер захавает его нулями (т.к. выводы висят). Но старший то пройдет и переключит шину в 4бита. И следующая посылка опять выставит 4бита (чтобы не переопределять) и в догонку выставит второй полубайт.

  1. только что вспомнил случайно совершенно…

    когда-то мне попадалася мега номер 160(?) вроде.

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

    есть ли такие на самом деле или мне это померещилося?

    1. Есть целое подсемейство AVR LCD которые содержат встроенный контроллер LCD, но не такой, а для прямого управления стекляхой.

  2. Управление LCD-дисплеем HD44780 по одному проводу
    Автор Noureddine Benabadji
    18.03.2008 г.
    LCD-дисплеи с контроллером HD44780 являются пожалуй одними из самых популярных символьных дисплеев для встраиваемых систем. Единственным их недостатком можно считать необходимость задействования для управления дисплеем шести I/O-линий микроконтроллера в 4-разрядном режиме либо одиннадцати I/O-линий в 8-разрядном режиме. Для сокращения числа управляющих линий можно использовать преобразователи последовательного кода в параллельный на основе стандартной логики. Однако, управлять HD44780-совместимыми LCD-дисплеями можно даже по одной линии. Такую функцию гораздо удобнее возложить не на микросхемы жёсткой логики, а на программируемый микроконтроллер, сократив, таким образом, стоимость и занимаемую схемой на печатной плате площадь. Этим целям в полной мере удовлетворяют микроконтроллеры Microchip серии PIC10F в миниатюрном корпусе SOT23–6.
    Схемотехническое решение, показанное на рисунке, может оказаться полезным для многих встраиваемых систем с ограниченным числом выводов, потому как способно управлять HD44780-совместимыми LCD-дисплеями посредством однопроводной линии передачи данных, задействуя простой асинхронный RS232 протокол на скорости 9600baud. В схеме применён PIC10F202, но подойдёт любой микроконтроллер из этого семейства, потому что хорошо оптимизированный программный код (прошивка 1) состоит из всего лишь 256 слов. Увеличить скорость выше 9600baud не представляется возможным, так как PIC10F202 содержит внутренний RC-генератор с точностью 1%, а LCD-дисплей требует задержку длиной 1.6ms для некоторых инструкций, таких как «очистка дисплея». Программный код представлен в виде исходников с комментариями для LCD232 модуля; основная программа состоит из дисплейной заставки на 2 секунды и дальнейшего бесконечного цикла для ожидания 1 байта команды, максимум 16 байт данных и нуля ASCII. В тестовых целях сопряжения дисплея с внешней встраиваемой PIC-системой можно воспользоваться простой прошивкой на ассемблере (прошивка 2).

  3. DI HALT, а ты в ISIS Proteus делал управление LCD? Я попробовал с теми библиотеками, которые ты сделал — не пошло. Попробовал пример из книжки на C сделать по выводу инфы на LCD, тоже безрезультатно. Использовал компоненты LM016L, LM017L. как на 4-х проводах, так и на 8.

    1. Собрал вчера на макетке на 8 проводах — все работает. Сделал все тоже самое в протеусе, используя эту же прошивку — не идет…

  4. DI HALT, и еще вопрос. В библиотеке LCD.asm есть команда LCD_PORT_IN. Не могу понять, откуда она взялась и как копилятор ее понимает, ведь ни функций, ни макросов, ни определений, ни меток нет с таким названием, и уж тем более в системе команд такой нету… При этой команде программа перепрыгивает на метку PortIn, но почему? Растолкуй, пожалуйста.

  5. Уважаемый DI HALT,
    помогите п-ста новичку с решением проблемы с ЖКИ.
    Купил WH0802 и решил его первоначально проверить. Подсветка работает нормально, а вот с контрастностью непонятки: в какое бы положение не встал движок переменного резистора, регулирующего контрастность, «загорается» только верхний ряд. Нижний ни при каких обстоятельствах не контрастирует.

    Перепробовал много кода — ничего не появляется.

    Заранее благодарен.

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

      1. Спасибо за ответ, попробую еще раз все проверить.
        Однако я был уверен в том, что после отключения питания LCD, вся информация инициализации стирается в модуле. Это не так?

          1. ОК. То есть если я его отключил от питания и от контроллера,а потом в отключенном состоянии запитал, и у меня все равно контрастирует только один ряд — это не проблема, а проблема с инициализацией? Я справшиваю потому, что, например, завтра-послезавтра могу пойти в магазин и обменять (недавно там купил). Если же это не признак брака, а мое неумение составить программу — то, понятно, в моем распоряжении целая вечность для исправления ошибок.

            1. Это не брак. Это неправильная инициализация. Ищи ошибку в коде :)

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

              1. Нет, по 8-ми проводной.
                Мне представляется, что я запутался во фьюзах (точнее я их не трогал), а кварц на плате, которая мне попалась (с контроллером) на 3,6864. Для формирования задержки я использую delay_ms(). может в этом дело? Временные периоды не соответствуют требуемым?

                1. Вполне возможно. Если фузы не трогал, то тактовая частота (у контроллеров Мега и Тини) задается по дефолту от внутренней РС цепочки и может быть от 1 до 8 мгц в зависимости от типа МК.

                  Можешь увеличить временные интервалы раз так в 10. Чтобы наверняка.

                  1. Простите, но у меня никак не получается. Теперь я выяснил, что на выводах LCD 11,12,13,14 всегда есть +3,76В. Даже если я принудительно устанавливаю 0 на всех выводах, то именно на этих всегда 1. Остальные же четыре линии устанавливаются в соответствии с командами.

                  2. Нашел ошибку.
                    У меня в контроллере был установлен бит JTAGEN=0 (а порт для LCD — PORTF), а я подумал, что 0 — это снят. А оказывается нет. Убрал его и все заработало.

                    Спасибо большое.

  6. Здравствуйте.
    Пробую воспользоваться библиотекой,но я новичок в этом деле и не всё понимаю.
    Подскажите что за значение @0 ?

  7. Большое спасибо за ссылку.
    Разобрался с библиотекой.Целый день промучился.
    Косяк оказался в протеусе,как выше писали.
    В железе всё работает.

  8. А для чего вот этот макрос LCD_COORD X,Y ?
    Какие он координаты задаёт ? У каждого знакоместа есть ведь свой адрес.

    1. Вот этот адрес он и вычисляет и переводит туда курсор. Просто удобнйе же мыслить категориеей столбец:строка чем линейным адресным пространством.

  9. Пытаюсь через AVR Studio откомпилировать на ATmega48 …. закрадывается вопрос … энто вообще возможно ? (порты я поменял, но зато потом начинается кишмар, макросы например отказывается видеть видимо принципиально)

  10. Решил заюзать LCD от nokia 1100 65×96 (чип PCF8814) и написать свою тру-библиотеку на асме. Для протеуса не нашел библиотечки, решил потренироваться на дисплее от nokia 3310 48×84, а потом чуток код подправить для 1100. Вот решил я биткарты для каждого символа забить в EEPROM. Вместе с русскими буквами вышло 810 байт для шрифта 8×5. Да вот засада: я под мегу8 писал, т.к. она в наличии у меня есть, а у нее только 512 байт EEPROM… Пришлось для моделирования взять мегу 32, а это и корпус крупнее и денег стоит больше. Может есть какой-то альтернативный выход? Кто как справлялся с нехваткой EEPROM ?

      1. Согласен. Уже так и сделал (гребаное выравнивание по размеру слова!!!). Но я точно знаю, что мне флеша не хватит, чтобы его еще на такие вещи тратить…
        У меня идея была сжать эти битмэпы и сжатые данные записать в eeprom, а при инициализации не сложным алгоритмом распаковки все это дело в ОЗУ распаковать, но пока не нашел алгоритм, который можно было бы достаточно компактно реализовать в МК… И, честно говоря, уже теряю надежду на эту задумку… Пока простой ответ нашел только такой: часть битмепов записасть в eeprom (ну например для редкоиспользуемых символов русского алфавита), а остальную часть пихнуть во флеш… пока думаю это оптимальный вариант.

          1. Да! Возьми мегу 168 у ней при полном совпадении по ногам памяти вдвое больше. А разница в цене небольшая.

            1. О, точно! А я смотрю — у Евстифеева нет в сводной таблице 168 меги… ДА, надо в нете сразу смотреть на сайте атмела все МК AVR…

                1. 328 это как 32, только ног по-меньше. про нее только на atmel.com написано, на русскоязычном сайте еще нет в списках

          2. Хм.. посмотрел на сайте атмела — куча всяких микрух: Data Flash, Flash, EEPROM, Последовательный EEPROM, Параллельный EEPROM. Есть даже какой-то Конфигурационный EEPROM. Я аж растерялся…
            Не планируется ли статейка о подключении к МК таких типов внешней памяти и методы работы с ней?

            1. Эх… планируется :))) давно хочу про i2c шину написать. Но все как то влом, тема больно жирная :) Но видимо возьмусь таки.

  11. Неплохая прога для перегона битовой картинки в массив байтов
    Я например юзал для создания биткарт символов шрифта для LCD дисплея
    ТУТ

      1. Все в массы!!!
        Я уже пару шрифтов 6×8 себе сделал. Один OEM (CP866), а второй ANSI (CP-1251)
        Вот думаю может в своей тру библиотеке сделать поддержку больших шрифтов типа 10х16… Смотрятся куда красивее чем 6×8 :-)

  12. Здравствуйте. Нужна помощь. Полностью сделал всё как описано, но разве что на LCD HY-1602H двухстрочный 2х16, МК — АТмега8515, порт А на дата шину LCD, порт Е на шину управления. Проблема в чём — при запуске всего этого добра все верхние сегменты полностью зажжены, нижняя строка не пашет. Я, всего лишь, для начала хочу вывести зиг руну как на примере, но ничего. Бьюсь уже достаточно времени скоро материться буду на этот LCD. Подскажите что-нибудь, пожалуйста.

    1. Сразу видно что у тебя инициализация не прошла. Некоторые LCD требуют ее два раза проходить.
      По какому интерфейсу подключил? 8 или 4 провода?

      1. самое интересное то, что это всё происходит при подключении одного LCD, подключаю потом сразу другой такой же LCD к этой же схеме, а он ничего не выводит вообще…

        1. Разные дисплеи, немножко разные контроллеры. Скорей всего придется поиграться с задержками временными. Сделай их чуток побольше. У меня там есть в коде LCD_Delay или как то так. Сделай ее дважды везде где найдешь. Ну и проверь не перепутал ли чего, может у них цоколевка отличается.

  13. Здравствуйте, у меня возникли проблемы при записи данных в дисплей: они туда не записываются. В результате инициализации включается две строки, и всё. Пытался включить курсор не получилось. Использовал два разных LCD, результат одинаковый.
    Использовал предложенную здесь библиотеку, то же самое.
    без инициализации вкл. только 1 строка, а после две, значит команды передаются правильно, тогда почему курсор не включается?
    Пробовал не проверять флаг занятости, а делать задержку, результат такой же
    подключал LCD: wh1202 и DV-16252
    МК ATmega16

    1. Попробуй поиграть с выдержками. Некоторые дисплеи тупые, им инициализацию два три раза слать надо.

      По какой схеме подключал? полной или половинчатой?

    2. Я думаю дисплеи типа wh-1602 и т.д. отличаются от МЭЛТ’овских процедурой инициализации. Все прекрасно работает, если последовательность команд инициализации и временные задержки сделать по даташиту на конкретный дисплей. Сам долго мучился, пока не плюнул и не начал с нуля изучать техописания. Есть еще один момент, касаемый JTAG. Так вот, много раз встречал на форумах, что мол, вырубите фьюзом JTAG, и все будет ok. Проверено, JTAG можно и не вырубать, если ЖКИ не задействует ноги, отвечающие за отладку по JTAG, для меги 16 это будет порт C.

  14. Пытаюсь прикрутить WH0802A он аналог HD44780 на Tiny2313
    И неполучается :(((
    Вот моя комутация:
    PD0=E
    PD1=R/W
    PD2=RS
    PB0=DB0
    PB1=DB1
    PB2=DB2
    PB3=DB3
    В прошивку внесены соответсвенно изменения:
    ***************lcd4.asm********************
    .equ DATA_PORT = PORTB ; LCD Data Port
    .equ DATA_PIN = PINB
    .equ DATA_DDR = DDRB

    .equ CMD_PORT = PORTD ; LCD Control Port
    .equ CMD_PIN = PIND
    .equ CMD_DDR = DDRD

    .equ E = 0
    .equ RW = 1
    .equ RS = 2

    .equ SPEED = 14
    *****************************************************

    Даже инициализацию повторил дважды (вдруг с ервого раза не раздуплиться)
    ***********************Сама программа****************
    .include»tn2313def.inc»
    .include»lcd4_macro.inc»
    .include»lcd4.asm»
    INIT_LCD
    INIT_LCD
    WR_CGADR 0
    WR_DATA 0b00000001
    WR_DATA 0b00000010
    WR_DATA 0b00000100
    WR_DATA 0b00011111
    WR_DATA 0b00000010
    WR_DATA 0b00000100
    WR_DATA 0b00001000
    WR_DDADR 0
    WR_DATA 0
    *****************************************************
    При прошивке фусы по дефолту, компиллер не ругается, контроллер шьется без ошибок и замечаний.
    При включении без признаков жизни. Попрежнему горит только верхний ряд (при управлении контрасностью). Что сделал не так? Бьюсь третий день -понять немогу. Прошу помощи!

    1. Странно. У меня тоже именно WH0802A и работает. INIT_LCD дважды повторять не надо. Это бессмысленно, лучше попробуй изменить этот макрос, дважды подав команду перехода на четырехпроводный режим.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      
      		.MACRO	INIT_LCD	; Инициализация LCD
      		RCALL	InitHW			; Настроить контрольный порт
       
      		RCALL	LCD_DELAY		; Подождать
       
      		WR_CMD	(1<<LCD_F)|(0<<LCD_F_8B)	; Выдать функции в порт. Команда инициализации адресации ДВА РАЗА!!!
      		WR_CMD	(1<<LCD_F)|(0<<LCD_F_8B)|(1<<LCD_F_2L) 	; Так как на 4 байтах нельзя передать сразу второй байт
      		WR_CMD	(1<<LCD_CLR)			;0x01
      		WR_CMD	(1<<LCD_ENTRY_MODE)|(1<<LCD_ENTRY_INC)			;0x06
      		WR_CMD	(1<<LCD_ON)|(1<<LCD_ON_DISPLAY)|(0<<LCD_ON_CURSOR)|(0<<LCD_ON_BLINK)	;0x0C
      		WR_CMD	(1<<LCD_HOME)		
      		.ENDM

      Попробуй добавить строку:
      WR_CMD (1<<LCD_F)|(0<<LCD_F_8B)
      Еще один раз. По всем признакам дисплей у тебя не может понять, что мы с ним общаемся по 4м проводам. И поиграй параметром SPEED

    2. Разве при использовнии четырехбитной шины не старшую тетраду нужно использовать?
      DB4-PB4
      DB5-PB5
      DB6-PB6
      DB7-PB7
      наверное так должно быть у тебя.

  15. Доброго времени суток!

    Вроде делаю все по статье, а не получается на макете. LCD не инициализируется.
    У меня atmega8535, юзаю потр C для управления и D для данных. Решил попробовать на эмуляторе в аврстудио + hapsim — в логе повалило:
    AVR Simulator: Stack Overflow at 0x0028
    AVR Simulator: Stack Overflow at 0x0000

    Думал трабла с аврстудио, поставил на другом компе — тожесамое.
    Вот конфиг:
    =========== LCD Define =======================
    .equ DATA_PORT = PORTD ; LCD Data Port
    .equ DATA_PIN = PIND
    .equ DATA_DDR = DDRD

    .equ CMD_PORT = PORTC ; LCD Control Port
    .equ CMD_PIN = PINC
    .equ CMD_DDR = DDRC

    .equ E = 2
    .equ RW = 1
    .equ RS = 0

    .equ SPEED = 14

    Вот сам файл:
    .device atmega8535
    .include «D:\AVR\PROJ\LCD123\m8535def.inc»
    .include «D:\AVR\LCD\WH\LCD4_macro.inc»

    ; INIT_LCD
    INIT_LCD ; Инициализируем

    WR_CGADR 0 ; Указатель на начало знакогенератора.

    WR_DATA 0b00000001 ; Запись данных нового знака
    WR_DATA 0b00000010
    WR_DATA 0b00000100
    WR_DATA 0b00011111
    WR_DATA 0b00000010
    WR_DATA 0b00000100
    WR_DATA 0b00001000

    WR_DDADR 0 ; Указатель на начало видео памяти (ячейка с координатми 0,0)

    WR_DATA 0 ; У новоиспеченного символа код 0 напечатем его

    .include «D:\AVR\LCD\WH\LCD4.asm»

    1. Судя по
      AVR Simulator: Stack Overflow at 0×0028
      AVR Simulator: Stack Overflow at 0×0000

      Косяк не в моем коде, а в твоем. Похоже ты где то забыл стек инициализировать или сорвал его ненароком. Так бывает :)

        1. Запусти в студии на эмуляцию и пошагово протрассируй. Скорей всего у тебя нет вот этого в начале:

          OUTI SPL,low(RAMEND)
          OUTI SPH,High(RAMEND)

          Ну, а дальше, если этого не вписать, у тебя будет краш на первом же вызовае RCALL или RET

          1. Да, на первом шаге переполнение стека повалило.
            вставил эти 2 строки перед INIT_LCD при компиляции вывалило:
            D:\AVR\PROJ\LCD123\LCD123.asm(2): error: OUTI: Unknown instruction or macro
            D:\AVR\PROJ\LCD123\LCD123.asm(2): error: SPL: Unknown instruction or macro
            D:\AVR\PROJ\LCD123\LCD123.asm(2): error: syntax error, unexpected ‘,’

            Может я чтото еще пропустил?

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

              .MACRO OUTI
              LDI R16,@1
              OUT @0,R16
              .ENDMACRO

  16. [quote]Запись байта в дисплей осуществляется макросами1
    2 WR_CMD xx
    WR_DATA xx

    Где вместо хх вписываем наш байт.[/quote]

    в каком формате xx подставлять? 00010 00100 или два числа в 16-тиричной?

  17. SHIFT SCR_L ; сдвиг экрана влево
    SHIFT SCR_К ; сдвиг экрана вправо
    SHIFT CUR_L ; сдвиг курсора влево
    SHIFT CUR_R ; сдвиг курсора вправо

    Опечатку нашел вместо SCR_К надо CSK_R :)

  18. замечание:
    все команды, начиная с инициализации, у вас реализованы через функцию CMD_WR, а она в свою очередь, использует BusyWait!

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

      1. возможно, это и необязательное условие. В железе еще не проверял, у меня МЭЛТ.
        Но протеус выдает предупреждение «попытка чтения после записи одного полубайта»…

    1. В Procyon AVRlib (откуда я передрал инициализацию дисплея) при инициализации тоже используется тот же самый BusyWait на ожидании флага.

  19. Привет!

    У меня вопрос — ежели я использую только часть функций, находящихся в инклюд-файле — остается ли «лишний» код за бортом при компилляции?

  20. Скачал уже давно твою библиотеку для ЛСД и юзал её не мог нарадоваться, однако сегодня благодаря ей любимой бился головой об стенку 2 дня пока не откопал багу. думаю будет всем полезно иметь ввиду мой горький опыт.
    При срабатывании прерывания от АЦП, запрещаю все прерывания и вытаскиваю результат и разрешаю прерывания. При срабатывании прерывания от таймера (3Гц) запрещаю все прерывания, и вывожу значение АЦП на экран. На экран вылазит лажа, и близко не похожая на то, что должно быть (сразу оговорюсь, речь идёт о переменном напряжении).
    Запускаю отладчик , комментирую все экранные функции(т.к. там есть ожидание ответа от дисплею, а оно меня кумарит да и времени много занимает) и всё работает как часы.
    Решение оказалось смешным до слёз, в библиотеках есть функции которые сначала запрещают, а потом разрешают прерывания, то есть посредине обработки прерывания от таймера вдруг включались все прерывания и начинался мегаприкол на экране.
    не знаю как кому, а я рекомендовал бы перед использование библиотеки с прерываниями комментировать SEI в коде библиотек

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

      Ну или на примере моей любимой RTOS в прерывании пихнуть задачу обновления дисплея в очередь и выйти.

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

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

  21. День добрый.вопрос новичка.неподскажите как можно организовать меню
    управления чтобы можнобыло как блакнот листать.знаю что это делается
    спомощью счотчика а представить немогу.немоглибы показать под
    SiSy-AVR здесь загоняется немного подругому.
    заране премного благодарен.

      1. Это тоже самое как AVR Studio но более продвинута для ЧАЙНИКОВ
        Я покупал пакет с учебниками програматором и другими прелестями.
        просто я занимаюсь ремонтом електроники а мир нестоит на месте
        вот решил заняться самообразованием.линк моего пакета
        http://shop.myavr.de/Komplettpakete/myAVR%20Einsteigerset%20MK2%20USB%20PLUS.htm?sp=article.sp.php&artID=45

  22. Как правильно подключать екран при 4 битном подключении свободние 4 оставлять в воздухе?
    А то ща имею трабл на 8 пашет гуд а при подключении на 4 ни в какую… либо пустой екран либо крякозяблики…

  23. Инициализация Winstar WH1602A-YGH-CTK# убил два дня на то чтоб разобраться как инициализируеться даний ЛСД поетому мож кому пригодиться :)
    инициализация для 4 бит используя либу автора статьи:
    WR_CMD 0b00110011 ; Важно!!!
    WR_CMD 0b00110010 ; Вместо WR_CMD (1<<LCD_F)|(0<<LCD_F_8B) !!!
    WR_CMD (1<<LCD_F)|(0<<LCD_F_8B)|(1<<LCD_F_2L)
    WR_CMD (1<<LCD_CLR)
    WR_CMD (1<<LCD_ENTRY_MODE)|(1<<LCD_ENTRY_INC)
    WR_CMD (1<<LCD_ON)|(1<<LCD_ON_DISPLAY)|(0<<LCD_ON_CURSOR)|(0<<LCD_ON_BLINK)
    WR_CMD (1<<LCD_HOME)

    При переходе на 8 битний режим перед 8 битной инициализацией по мануалу нада добавить 3 команди WR_CMD (1<<LCD_F)|(1<<LCD_F_8B)
    Хотя исходя из практики можна пропустить…

    1. У меня такой же дисплей, я его инициализирую так:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      
                  RCALL    InitHW                                ; Настроить контрольный порт
       
                  RCALL    LCD_DELAY                            ; Подождать
       
                  WR_CMD    (1<<LCD_F)|(0<<LCD_F_8B)                ; Выдать функции в порт. Команда инициализации адресации ДВА РАЗА!!!
                  WR_CMD    (1<<LCD_F)|(0<<LCD_F_8B)|(1<<LCD_F_2L)     ; Так как на 4 байтах нельзя передать сразу второй байт
                  WR_CMD    (1<<LCD_CLR)                                                            ;0x01
                  WR_CMD    (1<<LCD_ENTRY_MODE)|(1<<LCD_ENTRY_INC)                                    ;0x06
                  WR_CMD    (1<<LCD_ON)|(1<<LCD_ON_DISPLAY)|(0<<LCD_ON_CURSOR)|(0<<LCD_ON_BLINK)    ;0x0C
                  WR_CMD    (1<<LCD_HOME)
  24. Ребята помогите, мучаюсь вторую неделю. LCD: WH1602A-YYK-CTK (Winstar), шина 4 бит, использую библиотеки автора, но при инициализации еще добавил строки Name4me:
    WR_CMD 0b00110011 ; Важно!!!
    WR_CMD 0b00110010 ; Вместо WR_CMD (1<<LCD_F)|(0<<LCD_F_8B) !!!
    (без них не работал)
    В Протеусе все работает, в железе нет. (Загорается только верхний ряд черных квадратов)Читал\смотрел\разбирал даташиты коментарии других. Судя по всему нужно добавить в начале инициализации задержки или как то по другому инициализировать. Опыта нет,не могу должным образом вклинить в код эти задержки (по даташиту 15 мс,4,1 мс,100мкс), компилятор ругается и прочее…
    Вообщем помогите пожалуйста с инициализацией.

  25. Кто нибудь можеть кинуть программу которая у вас точно работает, с использованием библиотек DI HALT, и указанием на каком именно LCD работает. А то закипаю….

  26. Очень и всеми руками поддерживаю Kefir_Danon о просьбе размещения кода. Я пытаюсь заставить работать шестнадцатизнаковый двухстрочник, и чтоб он огнем горел! Я его скоро не паяльником, а молотком прибивать к АВР-у буду, чтобы не вредничал.Или на почту мне скиньте плиз исходник попроще. Дальше сам разберусь. Для полного подключения.
    Мыло: april_26(собачка)ukr.net Спасибо заранее и с Новым Годом!

  27. DI HALT, очередной респект.
    Сегодня свинтил ЖК c RoboPICA поиграться. Сзади на нем надпись «JHD 162A» однако интерфейс был такой же. Попробовал твою библиотечку и все получилось. Песня!

    april26, а что не понятно?
    Простейший вариант:

    ===========================================================

    .include «m8def.inc»
    .include «LCD_macro.inc»

    .MACRO outi
    LDI R16,@1
    OUT @0,R16
    .ENDMACRO

    .ORG INT_VECTORS_SIZE
    Reset:
    OUTI spl,LOW(RAMEND)
    OUTI sph,HIGH(RAMEND)

    INIT_LCD

    LCDCLR

    WR_DATA ‘A’
    WR_DATA ‘n’
    WR_DATA ‘t’
    WR_DATA ‘o’
    WR_DATA ‘n’

    Loop:
    RJMP Loop

    .include «LCD.asm»

    ===========================================================

    Сорри за MACRO outi. Лень было причесывать.

    1. Увы! Как и у других — никакой реакции! Вернее, реакция одна — заполненный кубиками верхний ряд. Что от этого кода, что от авторского…

  28. А можно узнать как в ассемблере написать код который бы из шестнадцетиричного числа делал десятичное? Или кинуть простой пример.

    1. Это тебе делить надо или как у меня без делителя
      onADC: cli
      ldi r16,0b01000000 ; Port, Referenzspannung und Auflösung
      out ADMUX,r16
      ;— Interrupts erlauben —
      in r26, ADCL
      in r27, ADCH
      sbi ADCSRA,6
      sei
      reti
      lcdZahl:
      mov r1,r26 ; Zwischenspeicher und Einer-Stelle
      mov r4,r27
      ldi r17,6
      ldi r18,5
      ldi r19,2
      clr r2
      clr r3
      hunderte:
      ldi r16,100 ; solange die 100 in die Restzahl (r1) passt
      cp r1,r16
      brlo zehner
      sub r1,r16 ; 100 abziehen und
      inc r3 ; Hunderter-Stelle erhöhen
      rjmp hunderte
      zehner:
      ldi r16,10 ; wie bei den Hundertern
      cp r1,r16
      brlo addiren
      sub r1,r16
      inc r2
      rjmp zehner
      addiren:
      ldi r16,1 ; solange die 100 in die Restzahl (r1) passt
      cp r4,r16
      brlo ein
      sub r4,r16 ; 100 abziehen und
      add r1,r17
      add r2,r18
      add r3,r19
      rjmp addiren
      ein:
      ldi r16,10 ; wie bei den Hundertern
      cp r1,r16
      brlo zehn
      sub r1,r16
      inc r2
      rjmp ein
      zehn:
      ldi r16,10 ; wie bei den Hundertern
      cp r2,r16
      brlo einer
      sub r2,r16
      inc r3
      rjmp zehn
      einer: ; der_Rest_sind_die_Einer
      ldi r21,0x30 ; 30 hex für Zahl
      mov r16,r3
      add r16,r21 ; hunderter + 30 hex
      rcall lcdData
      ; ldi r16,’.’
      ; rcall lcdData
      mov r16,r2
      add r16,r21 ; zehner + 30 hex
      rcall lcdData
      mov r16,r1
      add r16,r21 ; einer + 30 he
      rcall lcdData
      ret
      ;————————————————————————
      я то вообще новичок в етом деле.может кто лучше посоветует

  29. Всё отлично работает спасибо!, вот только не могу понять, как мне вывести на дисплей не константу , а с какого нибудь регистра данные, в который я буду класть информацию с UART?????

    и что вот это такое: (ниже код) ??? на дисплей ничего не выводится… и без этих строчек всё прекрасно работает:
    WR_DATA 0b00000001 ; Запись данных нового знака
    WR_DATA 0b00000010
    WR_DATA 0b00000100
    WR_DATA 0b00011111
    WR_DATA 0b00000010
    WR_DATA 0b00000100
    WR_DATA 0b00001000

    1. Так это, предварительно то идут команды записи в память знакогенератора. Т.е. мы сначала этот символ врисовываем, а потом только отсылаем его наружу.

  30. Уважаемый DI-HALT
    Включил Вашу библиотеку в свою тестовую прогу, все работает.
    Подскажите пож. как же все таки вывести значение регистра в десятичном виде на экран!
    (т.е. не символ с кодом …., а именно этот код!)
    Так же нет ли какой подпрограммы или макроса для вывода текстовой строки, что бы не мучатся посимвольно???

    П.С. Продолжаю разбираться с ассемблером, пока более или менее понятно, нет ли у Вас статьи по работе с данными типа INT, LONG INT и т.п. Интересует арифметические операции и опрации с сохранением этих данных в памяти. Если есть — ткните носом плиз! -)))

    Заранее спасибо!!!

  31. пытался сам написать код для инициализации по даташиту на wh0802a
    нифига мой код не заработал.
    подключил твою либу, заработало.
    захотел сделать без чтения готовности а только с заденржкой, везде поставил по 40мс.
    перестало работать.
    но стало похоже на то что я писал.

    какие задержки выставить чтобы все зафурычило без чтения состояния???

    1. А ХЗ. Вообще 40мс это дофига. Он работает почти как память, так что должно хватить и 1мс. Может что то еще забыл?

      1. да ХЗ

        [code]
        Вот как переделал LCD4.asm
        ;=========================================================================================
        ; Запись команды в дисплей. Код команды в R17
        CMD_WR: CLI ; Запрет прерываний
        ;RCALL BusyWait ; Ждем готовности
        ldi Razr1,40
        rcall Delay_ms

        CBI CMD_PORT,RS ; Идет команда!
        RJMP WR_END ; Переход на запись

        ;——————————————————————————————
        ; Запись данных в дисплей. Код данных в R17
        DATA_WR: CLI ; Запрет прерываний
        ;RCALL BusyWait ; Ждем готовности
        ldi Razr1,40
        rcall Delay_ms

        SBI CMD_PORT,RS ; Идут данные!
        WR_END: CBI CMD_PORT,RW ; Запись!

        функция Delay_ms:
        Delay_ms:

        ldi Razr2,32
        lp1:
        ldi temp,254
        lp2:
        dec temp
        brne lp2
        dec Razr2
        brne lp1

        dec Razr1
        brne Delay_ms

        reti
        [/code]

        1. Хм, так у тебя только нужный уровень выставить на RW и все. Не оставлять его болтаться в воздухе. Выстави его всегда в WRITE и все.

          1. Не разъясните, что значит «Выстави его всегда в WRITE»? У меня отладочная плата, из которой вышло несколько конструкций, с 4-проводным «подключением» и R/W сидит на земле.

  32. Доброго времени суток!
    Использую Atmega8 и wh0802a дисплей, как я понял он собран на аналоге HD44780 контроллера. Собрал я простую схемку с управлением по 4 пинам. Набросал программку в CodeVisonAVR и построил схему в Proteus но wh0802a поэтому использовал LM016L похожий индикатор.
    Итог:
    В proteus симуляторе всё работает, а когда зашил код в схему ничего не отображается.
    Код:
    /*****************************************************
    This program was produced by the
    CodeWizardAVR V1.25.8 Standard
    Automatic Program Generator
    © Copyright 1998-2007 Pavel Haiduc, HP InfoTech s.r.l.
    http://www.hpinfotech.com

    Project :
    Version :
    Date : 23.02.2010
    Author : F4CG
    Company : F4CG
    Comments:

    Chip type : ATmega8
    Program type : Application
    Clock frequency : 3.684400 MHz
    Memory model : Small
    External SRAM size : 0
    Data Stack size : 256
    *****************************************************/

    #include

    // Alphanumeric LCD Module functions
    #asm
    .equ __lcd_port=0x12 ;PORTD
    #endasm
    #include

    // Declare your global variables here

    void main(void)
    {
    // Declare your local variables here

    // Input/Output Ports initialization
    // Port B initialization
    // Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
    // State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
    PORTB=0x00;
    DDRB=0x00;

    // Port C initialization
    // Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
    // State6=T State5=T State4=T State3=T State2=T State1=T State0=T
    PORTC=0x00;
    DDRC=0x00;

    // Port D initialization
    // Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
    // State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0
    PORTD=0x00;
    PORTB=0xFF;
    DDRD=0xFF;

    // Timer/Counter 0 initialization
    // Clock source: System Clock
    // Clock value: Timer 0 Stopped
    TCCR0=0x00;
    TCNT0=0x00;

    // Timer/Counter 1 initialization
    // Clock source: System Clock
    // Clock value: Timer 1 Stopped
    // Mode: Normal top=FFFFh
    // OC1A output: Discon.
    // OC1B output: Discon.
    // Noise Canceler: Off
    // Input Capture on Falling Edge
    // Timer 1 Overflow Interrupt: Off
    // Input Capture Interrupt: Off
    // Compare A Match Interrupt: Off
    // Compare B Match Interrupt: Off
    TCCR1A=0x00;
    TCCR1B=0x00;
    TCNT1H=0x00;
    TCNT1L=0x00;
    ICR1H=0x00;
    ICR1L=0x00;
    OCR1AH=0x00;
    OCR1AL=0x00;
    OCR1BH=0x00;
    OCR1BL=0x00;

    // Timer/Counter 2 initialization
    // Clock source: System Clock
    // Clock value: Timer 2 Stopped
    // Mode: Normal top=FFh
    // OC2 output: Disconnected
    ASSR=0x00;
    TCCR2=0x00;
    TCNT2=0x00;
    OCR2=0x00;

    // External Interrupt(s) initialization
    // INT0: Off
    // INT1: Off
    MCUCR=0x00;

    // Timer(s)/Counter(s) Interrupt(s) initialization
    TIMSK=0x00;

    // Analog Comparator initialization
    // Analog Comparator: Off
    // Analog Comparator Input Capture by Timer/Counter 1: Off
    ACSR=0x80;
    SFIOR=0x00;

    // LCD module initialization
    lcd_init(8);
    while (1)
    {

    // display the message
    if (!PINB.0)
    {
    // display the message
    lcd_gotoxy(0,0);
    lcd_putsf(«KEY «);
    lcd_gotoxy(0,1);
    lcd_putsf(«PUSH_1 «);
    } else
    {
    lcd_gotoxy(0,0);
    lcd_putsf(«NO KEY «);
    lcd_gotoxy(0,1);
    lcd_putsf(«PRESSED «);}
    };
    }

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

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

    P.S. Не пинайте если чё не так написал это мой первый проект.

    1. А при чем тут тактовый генератор? Дисплей полностью синхронный и скорость работы МК тут совершенно не играет роли. Протеусовская модель тоже далека от реальности. особенно в плане инициализации.

        1. Смотри что может произойти:

          ПО ошибке не так инициализировал. Сделал случайно READ и получил высокие уровни на этих выводах со стороны дисплея. А они на земле. Опа и выгорели.

  33. Никак разобраться не могу: подключил дисплей на Pinboard 1.1 по 4-х битной шине на порт С mega16 (библиотеку использовал здешнюю), шлю данные — тишина. Подключаю точно по такой же схеме на порт B — все отлично работает. С портом A тоже работает, вешаю на порт D — опят тишина. Что не так? На будущей плате свободен только порт C, все остальные забиты под завязку. Выручайте

    1. Дело в том, что у всех старших мег по умолчанию включен JTAG, а значит четыре линии порта С нельзя использовать как порт. Чтобы выключить жтаг нужно зайти программатором в режим прошивки FUSE и выключить там бит JTAGEN

  34. Здрасьте. Прикупил я значит себе дисплейчик на контроллере Sumsung KS0066U. Даташит на первый взгляд идентичен даташиту HD44870. После тестового подключения дисплея показалась одна строка, контраст регулировался четко и ясно. Далее, естественно, решил попробовать вывести символ, подключил библиотеку, скопипастил код. Дисплей не заработал. Даже контрастность перестала регулироваться. (Правда в полной темноте можно заметить, что места символов начинают чуть-чуть светиться при выкручивании резистора на полную.) Все перепроверил — результата нет. Подскажите пожалуйста, при таких симптомах в чем может быть мой косяк? (Мерял прибором: RS=1, RW=0, E=0)

    1. Извини, DI HALT. Не сразу обратил внимание на твой пост от 2 апреря. Порт данных был портом С. Сообщение можешь удалить. Так или иначе, спасибо за статьи и библиотеку.

  35. Что то замучался я совсем с подключением WH2004А.

    вот код программы инициализации и вывода нескольких чисел:

    initLCD: rcall delay50ms

    ldi r28,0b111100 ;
    rcall icom
    rcall delay50ms

    ldi r28,0b111100 ;
    rcall icom
    rcall delay50ms

    ldi r28,0b111100 ;
    rcall icom
    rcall delay50ms

    ldi r28,0b1100 ;
    rcall icom
    rcall delay50ms

    ldi r28,0b1 ;
    rcall icom
    rcall delay50ms

    ldi r28,0b110 ;
    rcall icom
    rcall delay50ms

    ldi r28,0b111100 ;
    rcall icom
    rcall delay50ms

    ldi r28,$80
    rcall icom

    ldi r28,’1′
    rcall idat
    ldi r28,’1′
    rcall idat
    ldi r28,’1′
    rcall idat
    ldi r28,’1′
    rcall idat
    ldi r28,’1′
    rcall idat
    ldi r28,’1′
    rcall idat

    loop:
    rjmp loop

    icom: rcall delay ;задержка ~1,8 ms
    CBI portd,4
    rcall delay
    out porta,r28
    out portc,r28
    rcall delay
    SBI portd,5
    RJMP step

    idat: rcall delay
    SBI portd,4
    rcall delay ;
    out porta,r28
    out portc,r28
    rcall delay
    SBI portd,5

    step: rcall delay
    CBI portd,5
    ret

    что то не так, не выводит единици вместо них что попало пишет и куда попало.
    WR на массе сидит, уже и задержки зверские прикрутил.
    Что я сделал не так?

    1. А у 2004 там вроде бы все сложней, ЕМНИП там два контроллера HD44780. Надо почитать доку попоподробней.

      1. Контроллер один там. скурил штуки 4 даташита.
        примерно нашел где ошибка. пины D2 и D3 почемуто всегда на + висят. пробовал в конце кода на этот порт где пины 0 посылать один фиг + там висит, а не должно.
        инициализацию портов уже проверил раз на 5 тока Эти пины что то гонят остальные в норме вроде.

        Я в шоке. битый контроллер мега ? лсд на разъеме, отключал, таже хрень.

      2. Выводы TMS и TCK — JTAG в ATMEGA16 на этих пинах.
        я его не инитил. мб фусы кривые ?
        У меня hfuse=9A lfuse=E3.

        1. Ну так если ты фузы не трогал, то по дефолту жтаг включен и эти пины заняты им. Надо выключить фуз JTAGEN

            1. В нотации атмел 0=включен. Сделай его 1 :)

              Можно и через мкускр его программно вырубить, но фуз сбросить проще :)

          1. в книге написано ешо надо сбросить разряд JTD регистра MCUCSR.
            мб в этом дело. проверю ща.

            1. сократил задержки до приемлимых, да и код подправил.
              А так контроллер такойже как HD44780 вобщемто.

  36. У меня видеовопрос http://www.youtube.com/watch?v=8-p5Sm4AWDM
    Вкратце:
    Светодиод до инициализации дисплея должен гореть, после вывода на экран — мигать.
    Он мигает, но экран не инициализируется. Я грешу на задержки, так как после сброса контроллера все работает.
    Кстати, оффтопик: (к теме о подключении МК) я притянул РЕЗЕТ к питанию через 10к, а он все равно сбрасывается если тычешь в него щуп осциллографа (включенного или нет — без разницы) — как же мерить уровни на ногах, если осцилл так просаживает напругу?

      1. По поводу видео. Нормальное явление. Дисплеи часто стартую медленней чем МК. И может получиться так, что значительня часть инициализации уйдет в пустоту. Поставь небольшую задержку (тактов на 200) перед инитом дисплея и должно помочь.

        1. Поставил задержку 2FFFF вычитаний, и даже 2 раза INIT_LCD. Грешил на блок питания — у него медленно поднимается напряжение, а мега с индексом L может, думаю, мега стартует раньше из-за этого, поставил выключатель — все равно та же фигня. Заметил особенность — когда проходит инициализация и вывод букв (суда по задержке) на экране слегка моргают засвеченные (полуконтрастные) строки.
          Короче, пошел читать внимательнее даташит на WH2004D-YGH-CP.

          1. Вроде зарабртало. Переписал часть кода ближе к даташиту.
            [CODE]
            ; Init Config
            .MACRO INIT_LCD ; Инициализация LCD
            RCALL InitHW ; Настроить контрольный порт
            RCALL LCD_DELAY ; Подождать
            ;——— здесь 0b00110000 3 раза с задержками ————
            CBI CMD_PORT,RS
            CBI CMD_PORT,RW ; Запись!
            LDI R16,0b00110000
            OUT DATA_PORT,R16
            SBI CMD_PORT,E ; Поднять строб WR_CMD (1<<4)|(1<<5)|(0<<6)|(0<<7)
            RCALL LCD_DELAY ; Подождать
            CBI CMD_PORT,E ; Опустить строб WR_CMD (1<<4)|(1<<5)|(0<<6)|(0<<7)
            RCALL LCD_DELAY ; Подождать
            RCALL LCD_DELAY ; Подождать
            RCALL LCD_DELAY ; Подождать
            SBI CMD_PORT,E ; Поднять строб
            RCALL LCD_DELAY ; Подождать
            CBI CMD_PORT,E ; Опустить строб
            RCALL LCD_DELAY ; Подождать
            SBI CMD_PORT,E ; Поднять строб
            RCALL LCD_DELAY ; Подождать
            CBI CMD_PORT,E ; Опустить строб
            WR_CMD(1<<LCD_CLR) ;0x01
            WR_CMD (1<<LCD_ENTRY_MODE)|(1<<LCD_ENTRY_INC);0x06
            WR_CMD (1<<LCD_ON)|(1<<LCD_ON_DISPLAY)|(0<<LCD_ON_CURSOR)|(0<<LCD_ON_BLINK);0x0C
            WR_CMD (1<<LCD_HOME)
            .ENDM
            [/CODE]

            и еще в конце InitHW поменял RCALL PortIn на PortOut, иначе команды не уходили.
            Только курсор теперь мигает (раньше его не было).

            Конечно, по уму надо рассчитать задержки (благо в даташите они есть), а не тыкать наобум несколько ЛСД_Делэй и причесать код, но если у кого такой дисплей не работает, может быть поможет.

    1. Да он не просаживает напругу. Просто у щупа осцилла есть емкость, вот эта емкость и дает импульсный бросок вниз. Попробуй через резистор в 1к подключать щуп осцилла. У него входное напряжение в гигаомы, ему этот 1к что мертвому припарки, а вот кондер перезаряжаться не будет так быстро

        1. Странно, не должен он сбрасывать. У тебя там точно подтяжка нормально пропаяна? 1К подтяжку сделай, она будет куда надежней.

  37. Сначала хотелось бы сказать большое спасибо за этот курс. Нашел много интерсного а главное полезного мне.
    Прошу не судить строго за вопросы я лишь недавно начал интересоваться микроконтроллерами.
    Недавно купил дисплей SC1601A на 1 строку и 16 символов. Подлючил к Меге 16. Порты: RS к PD4;RW к PD5;E к PD6;DB0-DB7 к порту B.
    Вопрос 1: Дисплей работает и выводит,но лишь на первые восемь позиции. Остальные мервые. Я неправильно инициализировал или дисплей не работает?(если дисплей то как проверить?)
    Вопрос 2: Мучаюсь с написание процедуры для вывода строки. Продедура выводящая символ работает отлично. Можете подсказать?
    Вопрос 3: Очень хотелось бы почитать про разные датчики(с примерами на Си). Например датчики расстояния(хочу собрать робота а с датчиками пока не определился). Можете кинуть пару ссылок?
    Код:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    
    #define F_CPU 4000000UL // 4 MHz
    #include
    #include 
     
    #define RS PD4
    #define RW PD5
    #define E PD6
     
    //функция записи команды//
    void lcd_com(char x)
    {
    PORTD &= ~_BV(RS); //Сигнал RS=0
    PORTD |= _BV(E); //Сигнал EN=1
    PORTB=x; //команда на линиях порта В
    PORTD &= ~_BV(E); //Сигнал EN=0
    _delay_ms(35); // Задержка на выполнение
    }
     
    //функция записи данных в ЖКИ//
    void lcd_data(char a)
    {
    PORTD &= ~_BV(RW); //Сигнал RW=0
    PORTD |= _BV(RS) | _BV(E); // Сигнал RS=1 E=1
    PORTB=a; // Данные на линий порта В
    PORTD &= ~_BV(E); //Сигнал EN=0
    _delay_ms(35); // Задержка на выполнение
    }
     
    //функция записи данных в ЖКИ в определенный адрес//
    void lcd_moveto(char a,char x)
    {
    char y;
    y=0b10000000+x;
    lcd_com(y);
    lcd_data(a);
    }
     
    //инициализация дисплея//
    void lcd_unit(void)
    {
    lcd_com(0b00110000); // шина на 8 бит 1 строка
    lcd_com(0b00110000); // шина на 8 бит 1 строка
    lcd_com(0b00001000); //выключить дисплей
    lcd_com(0b00000001); //Очистка экрана. Счетчик адреса на 0 позицию DDRAM
    lcd_com(0b00000110); //Инкремент счетчика, без сдивига строки
    lcd_com(0b00001110);
    }
     
    //вывод строки//
    /*void lcd_write(char s[16] )
    {
    int i=0;
     
    while (s[i]!=”)
    {
    lcd_data(s[i]);//вывод i-го символа
    i++;
    }
    }
     
    //вывод не побуквенно//
    void lcd_writeline(char s[16])
    {
    lcd_com(0b00001010); //выключить дисплей
    int i=0;
     
    while (s[i]!=’/0′)
    {
    lcd_data(s[i]);//вывод i-го символа
    i++;
    }
    lcd_com(0b00001110); //включить дисплей
    }*/
     
    //очистить дисплей//
    void lcd_clear(void)
    {
    lcd_com(0b00000001);
    }
    ////////////////////////////////////////////////////////////////
    int main(void)
    {
     
    }
    1. А там адресация поди чрезжопная. Суть в том, что первые 8 символов это одна строка, вторые 8 символов они как бы вторая строка.

      Попробуй выводить аски коды по очереди, медленно, скажем раз в секунду, меняя выводимый аскии код. Тупо по порядку адресов дисплея, начиная с нуля. Вначале заполнится первые 8 символов, потом, спустя какое то время полезут и остальные. Вот по номеру аски кода узнаешь в каких адресах видеопамяти у тебя вторые 8 символов. ЕМНИП они начинаются с 0х40 адреса.

      А чем проблема с выводом строки?

  38. Выложите пожалуйста рабочий пример для протеуса, выше были комментарии, что в протеусе все работало. Спасибо.

  39. Привет, DI! Есть 2 вопроса6
    1) А почему при переключении портов МК на приём данных от LCD, они преключаются на вход с подтяжкой, а не с высоким входным сопротивлением? По идее, с высоким входным было бы лучше — меньше энергии бы потреблялось…
    2) Не мог бы ты поподробней раскрыть смысл такого макроса:
    .MACRO LCD_PORT_IN
    RCALL PortIn
    .ENDM
    ???
    Почему плохо сразу писать в программе
    RCALL PortIn
    ???
    Ведь и логически и по смыслу понятно что и макрос и подпрограмма переключат порт на вход.

  40. Я посмотрел библиотеку для LCD. Почему при вызове макросов допустим на чтение или запись данных в дисплей запрещаются прерывания? Ведь в прерываниях все равно рабочие регистры сохраняются в стеке?

    1. Можно разрешить. Я тогда это делал чтобы тайминги не сбивались, но протокол там синхронный, так что это не влияет, а багов добавляет дай боже :)

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

  41. Cлушай DI, сейчас пробую использовать твою библиотеку для lcd панели, а ведь работает же. Все пучком. Правда сперва ее исследовал часа 4 пока вник в суть. Оказалось не сильно все сложно. Составлена логика грамотно. Мне это понравилось. И в использовании в проекте удобно реально. Макросы это сила, ничего не скажешь. Спасибо. Хорошо что ты есть на свете.

  42. Добрый вечер парни!
    3 дня парюсь c этой библиотекой, и не получается =((
    проверил пошаговое выполнение: заходит в LCD_macro.inc, там проходит по двум меткам, выходит, проходит INIT_LCD и опять возвращается в LCD_macro.inc и вот такие циклы наворачивает и все…
    ппц загнобила меня LCD =))

    Отправьте кому не сложно рабочие схемы в Протеусе на мега16.(для 8ми и 4х битной шинки)
    И исходник на асме.

    Заранее благодарен.

    1. Оно в протеусе и не должно работать. В протеусе дисплей соответствует реальным с сильно большими упрощениями. ЕМНИП протеусовский дисплей не ставит флаг готовности, а моя либа требует проверки этого флага. В живую должно все работать.

      З.Ы.
      Протеус маздай!

      1. Ясно…
        Просто делается проект и хотелось бы сначала удостовериться в работоспособности модели на эмуляторе а потом уже на железе!!!

        Я кстати нашел «забугровую» библиотеку на LCD.
        Если интересует посмотри =)

        http://www.embedds.com/the-introduction-for-hd44780-based-lcds-with-avr-microcontroller/

        http://www.avrbeginners.net/interfacing/44780_lcd/4bit.html

          1. Не знаю не знаю…на русских порталах на асме нашел только 2е (включая твою).
            На зарубежных вот только эти которые указал =))

  43. Дорогие друзья. Обе библиотеки как для 8, так и для четырёх бит рабочие. В протеусе не работают, т.к. я думаю, что там для LCD необходимо выдерживать строгие времменые интервалы при инициализации. Кстати до сих пор не могу понять, как у DIHalt’a он инициализируется если в описании на HD 44780 чётко написано, что проверять бит готовности не нужно при старте, а нужно соблюдать временные задержки. Но оно работает!!!
    Всем у кого не получилось советую посмотреть к каким выводам подключен LCD (данные и управляющие выводы) и при необходимости внести изменения в библиотеку.
    Спасибо DIHalt. Продолжай в том же духе!!!

  44. Не знаю помогут ли кому мои мысли, но, в любом случае лишним не будет. Возможно в протеусе просто не успевает эмулироватся дисплей. Т.к. частота контроллера к примеру 8МГЦ а дисплея (в настройках дисплея) у меня по дефолту стояла 250кГц. Выставил 10МГц и все стало очень даже прекрасно работать и в протеусе и в железе. И не нужно кучу раз в коде прописывать инициализацию дисплея и задержки вставлять. У меня протеус 7.7

  45. Столкнулся вот с какой проблемой при работе LCD в 4-битном режиме. Допустим вбиваю подряд несколько символов, программирую и они появляются на экране. Но после того, как выключаю питание, и потом включаю на экран ничего не выводится. При последующей перепрошивке опять появляются символы. Ума не приложу что может быть. Добавлял задержку при старте перед инициализацией lcd — не помогает. Контроллер ATmega8, тактовая 1 МГц. На восьмибитной шине всё работает замечательно.
    Может кто-то умную мысль подкинет)

  46. Парни подскажите кто знает!!!
    Не могу сделать чтобы курсор двигался по экрану с помощью кнопки(один раз нажал, курсор сдвинулся на одно деление влево/вправо).

    Получается только сдвинуть его один раз, при втором и последующих нажатиях не чего не происходит…
    Если написать цикл то все ОК, передвигает курсор столько сколько раз проходит цикл, а через кнопку не хочет (((

    в чем прикол не пойму ?_?
    Прерывание внешнее делал через INT0.

    1. Писал так:

      .CSEG
      .org $000
      rjmp reset
      .ORG $002 ;(INT0) External Interrupt Request 0
      rjmp sdvig_cursora

      reset:
      ldi temp1, LOW(RAMEND) ; LOW-Byte der obersten RAM-Adresse
      out SPL, temp1
      ldi temp1, HIGH(RAMEND) ; HIGH-Byte der obersten RAM-Adresse
      out SPH, temp1

      ldi r20,0b00001111 ;настройка прерывания
      out MCUCR,r20
      ldi r20,0b11000000
      out GICR,r20
      sei

      ldi temp1, 0xFF ; Port D = Ausgang
      out DDRB, temp1

      rcall lcd_init ; Display initialisieren
      rcall lcd_clear ; Display loschen

      ldi temp1, 0b00001110 ; Display on, Cursor on
      rcall lcd_command

      ldi temp1, ‘T’
      rcall lcd_data

      ldi temp1, ‘e’
      rcall lcd_data

      ldi temp1, ‘s’
      rcall lcd_data

      sdvig_cursora: ; метка по внешнему прерыванию
      ldi temp1, 0b00010100 ; курсор сдвинуть вправо
      rcall lcd_command
      reti

      loop: rjmp loop

      1. У тебя прерывание категорически неправильно оформлено :) Хотя тут и не влияет, но потом вылезет в полный рост. Не сохранены регистры и флаги. Читать главу курса про подпрограммы и прерывания. И вообще неправильно такие тяжелые вещи (как работа с дисплеем) пихать в прерывания.

        А по факту проверь вызывается ли у тебя прерывание вообще. По входу в прерывание сделай инверсию какого либо бита и повесь туда светодиод. Скорей всего будет какой нибудь ад :)

        1. Прерывание вызывается один раз(курсор двигается один раз вправо), потом больше не вызывается…
          С буквами пробовал, так же один раз напишет ее при нажатии и все,при втором и последующих потом больше не пишет =))

          1. Все разобрался))) не внимательность подвела =)

            Появилась другая проблема)) как инстализировать 4х строчный дисплей???

            1. привет всем. Ruslan, ты наверное имел в виду «инициализировать», т.е. обьяснить ему самому, кто он (монитор) в этом мире? Я даташите видел, что 4 строчечники инициал. также как и 2-строчники 2х16, только поле знакомест идет так: первая строка — адрес первых 8 мест ( с 00 по 07)первой строки двустрочника, вторая строка-адрес первых 8 мест ( с 00 по 07)второй строки двустрочника ( т.е. арреса с 40 по 47) третья строка — вторая половина первой строки двустрочника(с 08 по 0F), четвертая, соответственно, втроая половина втрой строки (адреса с 48 по 4F).

  47. Ура!! Наконец-то решил проблему с пропаданием символом после перезагрузки.
    Переписал инициализацию «по даташиту». Сначала пихаю команду перехода в режим 8 бит. Затем 4.1мс пауза. После этого опять 8 бит, пауза 100мс. После этого идёт команда перехода на 4-битный режим, потом пауза 200мс. В этих трёх действиях не проверяется флаг занятости и запись команды производится как в 8-битном режиме (за 1 такт). Потом уже с проверкой флага снова устанавливается 4-битный режим, но уже за 2 такта. А далее как в исходной библиотеке…

  48. Подскажите можно ли как нибудь извлечь адрес места нахождения курсора на LCD?
    И как записывать символы в определенные ячейки с помощью указания адреса ячейки?

  49. Привет, подскажи в чем может быть причина, дублируются символы при выводе на дисплей
    к примеру
    беру из таблицы символы
    начинающиеся все на 0x3
    первые 0x30 — 0x33 такие же как и 0x38 — 0x3B
    и другая пара одинакова, не могу понять в чем может быть проблема, библиотека твоя,
    дисплей WH1602M

  50. Здраствуйте.
    Для нормальной работы в протеусе по 4 битной шине, нужно при подаче команды 20Н подавать только старшую часть байта. Т.е. 2. А младший не передавать вообще. А начинать второй байт. И уже передача идет обех частей байта.

  51. для этого нужно в LCD4_macro в макросе Init_Lcd дописать команду WR_CMD 0x32.
    Тогда протеус отрабатывает все нормально.

  52. День добрый.Не подскажете что такое холодный или горячий старт дисплея.В чём разница
    приемущества или недостатки.небольшие изменения в LCD_Init.

  53. DI у тебя при чтении флага занятости в 4х битном подключении считывается еще и младшая тетрада. Зачем? Ведь флаг находится в старшей тетраде. Младшая тетерада при этом не используется.

    1. Спроси че полегче. Я уже не помню. ВРоде бы сначала выдается младшая, потом старшая. Либо наоборот, но ее клинит и надо считать еще и младшую, чтобы в следующий раз получить адекватный результат. Либо просто чтобы не плодить ветвей в коде, а заюзать уже отработаный кусок.

      1. Я сейчас все проверил в реали. Да ты правильно сделал. Нужно потом читать и младшую тетраду, обязательно, хотя она и не используется. Тоесть нужен полный цикл чтения всего байта из lcd. Но! Я не использовал задержку lcd_delay. Она вообще не нужна, так как по даташиту время на считывание флага 0 мкс. получилось вот что.

        порт на вход
        sbi portC,0 // RW=1 (чтение из LCD)
        cbi portD,7// RS=0 (команда)
        BYSY: sbi portC,1// E=1
        cbi portC,1// E=0
        in r16,pinc
        sbi portC,1// E=1
        cbi portC,1// E=0
        andi r16,0b00100000
        brne BYSY
        порт на выход

        1. В принципе спорить не буду. Этот дисплей подключается по схеме внешней памяти, а она по определению должна быть быстрой. Но если вдруг при высоких частотах возникнет глюк — ищи его в отсутствии выдержки.

  54. а у меня вот возник тупой вопрос — почему .include «LCD4.asm» надо проставлять в конец кода? я этот момент упустил и ставил его следом за .include «LCD4_macro.inc» — ну и затем полночи разбирался, почему дисп не инициализируется.. :)

    1. Что такое инклюд? Это значит лишь что мы берем содержимое инклюднутого файла и вставляем его вместо строчки .include LSD4.asm содержит код. Соответственно вставить его надо туда, где он мешать не будет. Т.е. в конец.

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

  55. Здравствейте. Целый день уже мучаюсь и никак не могу заставить в ПРОТЭУСЕ дисплэй хоть что-то показывать. Использовал дисплэи LM_016L,LM_020L — безрезультатно. Выставил одинаковые частоты на микроконтроллер и на дисплэй.
    Пробовал оба варианта подключения как 4, так и 8. При подключении с 4 ногами в протеусе вообще вываливается ошибка. При подключении с 8 ногами ошибки нет, но ничего и не выводит.
    В основную программу я только инициализирую стек и все. основная программа состоит из след. кода:

    .org 0x0000
    rjmp RESET

    RESET:
    ldi r16, High(RAMEND)
    out SPH, r16
    ldi r17, Low(RAMEND)
    out SPL, r17 ;init steka
    rjmp MAIN

    MAIN:
    INIT_LCD ; Инициализируем

    WR_CGADR 0 ; Указатель на начало знакогенератора.

    WR_DATA 0b00000001 ; Запись данных нового знака
    WR_DATA 0b00000010
    WR_DATA 0b00000100
    WR_DATA 0b00011111
    WR_DATA 0b00000010
    WR_DATA 0b00000100
    WR_DATA 0b00001000

    WR_DDADR 0
    WR_DATA 0

    Ничего не выводит. Версия протеуса 7.7 SP2 (вроде последняя).
    В комментариях выше был выложен проект в протеусе и проект в AVR_STUDIO. Но при запуске в протеусе вывалилась ошибка Invalid opcode 0xFFFF at PC=0x0168. Такая же ошибка вываливается и у меня когда я пытаюсь использовать LCD_4.asm.
    Уже начинаю подозревать что проблема может быть как-то в самой версии в протеусе.
    Что посоветуете?

        1. Есть. Но заморачиваться и подгадывать свою прогу еще и к протеусу (которым я не пользуюсь, ибо УГ) мне было совершенно вломы.

          1. Ну я так посмотрел на вскидку и винили, то место где ожидался ответ lCD на готовность. Я это условие убрал, но безрезультатно. Не подскажите хотя бы направление куда копать?

            1. Собери уже в железе и не мучайся. Нафига тебе еще разбираться с глюками протеуса?

              Куда там копать я даже понятия не имею. Откуда я знаю что они там навертели и насколько точно работает эмуляция интерфейса. Может он флаг готовности вообще не ставит, т.к. расчитан на быдлокодинг, когда на флаг готовности тупо забивают, делая ожидание в десяток ms тупым циклом (90% примеров работы с дисплеем)

            2. В конце концов в том же протеусе есть и отладчик и можешь посмотреть на каком месте у тебя все затыкается

  56. {brother77 30 мая 2010 19:38
    Что то замучался я совсем с подключением WH2004А}

    в итоге было написано что все удачно решилось…

    Выложите пожалуйста у кого есть работающую библиотеку для такой модельки!

  57. Может быть такое что эта моделька WH2004A (а если точнее то WH2004A-YYB-CT) не может работать на 4 битах ??? т.е. только на 8 битной шине.

  58. DI HALT используя твою библиотеку, подскажи какой командой можно узнать место нахождение курсора на LCD в данный момент…
    если для этого надо добавить пару строк в библиотеку, подскажи пожалуйста куда и как…

    1. Чтение регистра команд возвращает 8 значащих разрядов. Старший разряд — busy flag ,а остальные 7 — значение счётчика АС(если адресуется DDRAM). Это и есть положение курсора.Один важный момент. После появления BF=0, прочитанное в этом же цикле АС не будет достоверным. Для получения достоверного значения АС нужно совершить повторную операцию чтения регистра команд через 4 мкс.(время указано для 270 кГц)

  59. если можно тут сохраню «финт ушами» я вот так избавился от Push/Pop при посылке данных/команды:

    [code]
    IN R16,PORTB // читаем состояние
    // финт ушами: биты[7..4] в R16 заменяем на биты из R17 (R17- остаётся без изменений)
    EOR R16,R17
    ANDI R16,0b00001111
    EOR R16,R17
    // готово
    OUT PORTB,R16 // записали в порт
    [/code]

    код тут геморно вставлять, и коменты из АВР на русском не перекидываются :(

  60. Привет.

    В твоей библиотеке есть косяк.
    Во-первых, чем отличается проверка флага занятости от чтения команды?

    На самом деле ничем: читать команду нельзя, вместо неё читается флаг занятости и счетчик адреса.

    Во-вторых, задержки выдачи сигналов слишком большие.
    Возможно, у меня более быстрый контроллер ЖКИ.
    Сигнал E удерживаю 3 такта при частоте 8 МГц и всё прекрасно работает.
    В Даташите HD44780 написано — min 230 наносекунд.

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

      Протокол там синхронный, поэтому задержка не может быть сильно большой. И сильно зависит от типа дисплея. Например МЭЛТы тупят.

  61. Добрый день.
    Зметил такую странность.Бит Busy читается только тогда когда высокий E.Если сбросить E то читается всегда 1. Длительность E у меня 750ns.По даташиту 400ns.

    1. Да еще хочу спросить такую вещь.Есть ли в препроцессоре компилятора которым ты собирал библиотеку возможность сделать что то типо такого : print(«string»); который препроцессор развернет в последовательный вызов процедур записи данных для кажлого символа.Построчно вводить каждую букву очень не удобно.

      1. Нет. Это СПАРТА!!!

        Но ты можешь разместить строку во флеше (итак придется) и написать дополнительную функцию которая их будет выводить.

      1. А меня дисплей подключен к микроконтроллеру PIС по 8 битной шине.Кварц 16 мегагерц.Я в при первом запуске вывожу в дисплей символ.(Не использую busy wait а ставлю большую паузу большой длительности).Потом перепрошиваю контроллер где просто делаю busy wait.Так вот контроллер висит.Всегда 1 выдает.Сегодня еще проверю вечером.

  62. Подсккажите пожалуйста, как при помощи этих библиотек вывести содержимое регистра целяком? то есть выводить не каждый символ отдельно, а содержимое регистра, например я хочу вывести код АЦП на дисплей. как это сделать?
    ЗЫ: ассамблер только учу

    1. Преобразовать код в символы и вывести. Гугли алгоритм bin2bcd он без проблем находится. После него у тебя будут три числа, которые несложно превратить в ascii код который легко поймет знакогенератор дисплея

  63. Поиски готовой библиотеки для RC1602B привели меня на этот сайт.
    Я не понял как выводятся символы хранящиеся в CGROM.
    В макросах плохо разбираюсь, поэтому не всё понял.
    Неужели для каждого символа нужно писать его цифровой код в ячейке памяти ?

    Я в своей библиотеке ввёл понятные для меня обозначения каждого символа через .equ
    Или есть способ проще ?

    1. Просто записываешь в видео память символы и они согласно таблице (RAM и ROM) выводятся. Если надо своих символов нарисовать, то вначале в 8 знакомест загоняешь нужные байты, для формирования их. А дальше просто по номерам вызываешь.

      1. Да это понятно.
        Но если я пишу код, не не имея перед глазами таблицу. Как мне знать, какой номер соответствует какому символу.
        Я делаю это так:
        В шапке пишу.

        .equ l_point = 0x2E ;.
        .equ l_comma = 0x2C ;,
        .equ l_colon = 0x3A ;:

        .equ l_0 = 0x30 ;0
        .equ l_1 = 0x31 ;1
        .equ l_2 = 0x32 ;2

        .equ lrb_a = 0x41 ;А
        .equ lrb_b = 0xA0 ;Б
        .equ lrb_v = 0x42 ;В

        а в теле программы
        ldi Data,lrb_a
        rcall out_letter

        В вашей библиотеке подобные перекодировки есть ?
        Или нужно указывать цифрами:
        типа
        ldi Data,0x41
        rcall (вывод символа)

        1. Нет у меня таблицы нет. Если надо, то я строки перекодирывал специальной утилиткой на компе ,а потом вставлял в исходник. Плюс ASCII коды для английского языка вроде бы совпадают с табличной раскладкой.

          Делать эквайшены подобные вашим, имхо, смысла не имеет. Т.к. строки все равно берутся из памяти, а посимвольно «вручную» выводить их неудобно. Разве что вывести один два символа, но это несложно и в таблицу поглядеть.

          1. Понятно. В памяти хранить, тоже вариант.
            У меня просто другой подход.
            Я их не в виде данных храню, прописываю командами, как в примере. И мне удобно сразу заменять их обозначениями. Особенно русские символы, без перекодировки.

            1. Так можно хранить только короткие сообщения. А попробуйте загнать абзац текста — замучаетесь, да и памяти потратите в десять раз больше, чем один цикл обработки строки.

              1. Согласен.
                Но я не книгу пишу, у меня несколько строк, и памяти остаётся достаточно.
                Хотя 4 байта на символ это роскошь, но мне хватает. А менять надписи я могу быстро, без никаких перекодировок.
                Но если пойдёт много текста , то придётся кардинально переписывать библиотеку.
                Спасибо за совет.

  64. Здравствуйте.Я все сделал ка надо и у меня вышла на LCD эта закарючка.Подсккажите пожалуйста, как настроить и где чтоб бегущая строка побежала?Пишу слово,а у меня только в одном квадрате меняетса.Заранее спасибо.

    1. Для бегущей строки надо перезаписывать весь экран, сдвигая текст. Либо двигать экранную область, но это большй гемор.

      1. Вот код.Но AVR ругаетса где ;Write Data
        Подскажите пожалуйсто где косяк?
        .include file «C:\AVR\AvrAssembler2\Appnotes\m8515def.inc»
        .include file «C:\AVR\WH\LCD_macro.inc»

        .def temp =r16
        .def temp1 =r17

        .cseg
        .org 0

        InitAvr:
        ;Initialize stack pointer
        ldi temp, LOW(RAMEND)
        out SPL, temp
        ldi temp, HIGH(RAMEND)
        out SPH, temp

        rcall LCD_Delay ; Пауза перед включением

        INIT_LCD
        INIT_LCD
        SHIFT CUR_R ; Сдвиг курсора в право

        LCDCLR

        WR_DATA «A»
        WR_DATA ‘n’
        WR_DATA ‘t’
        WR_DATA ‘o’
        WR_DATA ‘n’

        ; WR_DATA 0
        .include file «C:\AVR\WH\LCD.asm»

        Loop:
        RJMP Loop

        1. Лучше бы показал как ругается. По идее раз схавал WR_DATA ‘A’ то должен схавать и WR_DATA 0 т.к. с точки зрения компилятора это одно и то же.

              1. Значит не те кавычки стоят. Их одинарных существует как минимум два вида. Копипастил поди код? ;) А надо ручками вводить.

                А когда есть макросы, то он сильно тупит и может ругаться не на ту строку или ваще затупить.

  65. Подскажите пожалуйсто,а что надо сделать чтоб написать во второй строчке LCD?Я только учусь не судите строго))

    1. Стоит прочитать еще раз. Особенно часть про адресное пространство видео памяти. Тогда поймешь, что каждому знакоместу соответствует свой адрес. И чтобы написать в определенное место экрана надо вычислить адрес этого места и выставить его командой. А потом писать. Исключение составляет последовательная запись, когда пишешь с нулевого адреса, а он автоматически увеличивается на 1. Но для перевода на вторую сторку надо либо написать очень много символов в теневой части (за пределами видимого окна), чтобы адрес сам достиг второй строки, либо вручную, командой, его перенести куда надо. Через макрос LCD_COORD X,Y

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

        1. Судя по вопросу нихрена вам не понятно :)))))

          LCD_COORD 0,1 — перевести каретку на вторую строку нулевой символ.

  66. Добрый день!

    пытаюсь использовать Вашу библиотеку:
    .include «m8def.inc»
    .include «LCD4_macro.inc»

    BEGIN: INIT_LCD
    rjmp BEGIN

    .include «LCD4.asm»

    при компиляции такие ошибки:
    AVRASM: AVR macro assembler version 1.77.3 (Aug 25 2011 20:29:36)
    Copyright (C) 1995-2005 ATMEL Corporation

    Creating ‘test2.eep’
    Creating ‘test2.hex’

    Assembling ‘test2.asm’
    Including ‘C:\avrtools\AvrAssembler\Appnotes\m8def.inc’
    Including ‘LCD4_macro.inc’
    LCD4_macro.inc(38) : error : Unknown instruction opcode
    LCD4_macro.inc(39) : error : Unknown instruction opcode
    LCD4_macro.inc(40) : error : Unknown instruction opcode
    LCD4_macro.inc(41) : error : Unknown instruction opcode
    LCD4_macro.inc(42) : error : Unknown instruction opcode
    LCD4_macro.inc(43) : error : Unknown instruction opcode
    test2.asm(8) : error : Macro within macro not supported

    Assembly complete with 1 error

    Deleting ‘test2.eep’
    Deleting ‘test2.hex’

    строки 38-43 в LCD4_macro.inc это WR_CMD в макросе INIT_LCD
    если их закоментировать — то всё компилится, даже если использовать WR_CMD в основном файле.

    подскажите, в чём проблема?
    спасибо!

    1. Макросы вызываются раньше чем они обьявлены. Прописал либу неверно. Инк файлы описывающие макросы не должны быть позже появления этих макросов в коде.

      1. ругань идёт на Ваш файл LCD4_macro.inc
        я пробовал в нём переставить описание макроса WR_CMD до макроса INIT_LCD — это ничего не дало.
        я так понимаю, что такая проблема с вашей библиоткой только у меня, потому и спросил, в чём может быть проблема…

        1. Не надо в нем ничего переставлять. Надо в вашем исходнике место прописки файла LCD4_macro.inc поставить ПОСЛЕ того как будут описаны макросы WR_CMD и прочие.

          1. макрос WR_CMD описан в LCD4_macro.inc
            и в самом же LCD4_macro.inc WR_CMD используеться до того, как он будет описан.

            не могли бы Вы выслать мне на shilow@ukr.net любой проект, который использует LCD4, и который у вас компилиться? спасибо.

        2. А где он у вас в тексте программы вообще? и где в тексте моего примера? Сделайте также, ругаться должен перестать

    2. Разобрался:
      — компилятор 1-ой верси: avrasm32.exe version 1.77.3 не компилирует эту библиотеку
      — компилятор второй версии: avrasm2.exe version 2.1.43 замечательно всё компилирует.

  67. Доброго дня.
    Прошу подсказать новичку.
    Пишу программу (AVR Studio v.4) для ATmega8515 подключенному к 2-х строчному LCD по 8-ми битной шине. Использовал файлы выложенные автором. В файле LCD.asm подправил блок инициализации: порт данных — порт А (8 бит), порт управления — порт Е и очередность битов иная: E=2, RW=1, RS=0.
    LCD_macro.inc не менял там все биты соответствуют.
    Вот исходный код:
    .include «m8515def.inc»
    .include «LCD_macro.inc»
    .include «LCD.asm»

    ;Инициализация стека
    ldi r16, high(ramend)
    out sph, r16
    ldi r16, low(ramend)
    out spl, r16

    ;r16, r17 РОН используются
    ;Порты B, C, D не используются
    ldi r16, 0b00000000
    out DDRB, r16
    ldi r16, 0b00000000
    out PORTB, r16
    ldi r16, 0b00000000
    out DDRC, r16
    ldi r16, 0b00000000
    out PORTC, r16
    ldi r16, 0b00000000
    out DDRD, r16
    ldi r16, 0b00000000
    out PORTD, r16

    INIT_LCD ; Инициализируем

    WR_CGADR 0 ; Указатель на начало знакогенератора.

    WR_DATA 0b00000001 ; Запись данных нового знака
    WR_DATA 0b00000010
    WR_DATA 0b00000100
    WR_DATA 0b00011111
    WR_DATA 0b00000010
    WR_DATA 0b00000100
    WR_DATA 0b00001000

    WR_DDADR 0 ; Указатель на начало видео памяти (ячейка с координатми 0,0)

    WR_DATA 0 ; У новоиспеченного символа код 0 напечатем его

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

      1. Инициализацию портов А и Е в основной программе я не делал, поскольку она должна выполняться после вызова макроса «INIT_LCD», в подпрограммах «InitHW» и «PortIn».

        Фрагмент кода из «LCD_macro.inc»:
        ; Init Config
        .MACRO INIT_LCD
        RCALL InitHW
        WR_CMD (1<<LCD_F)|(1<<LCD_F_8B)|(1<<LCD_F_2L)
        WR_CMD(1<<LCD_CLR)
        WR_CMD (1<<LCD_ENTRY_MODE)|(1<<LCD_ENTRY_INC)
        WR_CMD (1<<LCD_ON)|(1<<LCD_ON_DISPLAY)|(0<<LCD_ON_CURSOR)|(0<<LCD_ON_BLINK)
        WR_CMD(1<<LCD_HOME)
        .ENDM

        ; Set DATA Port IN
        .MACRO LCD_PORT_IN
        RCALL PortIn
        .ENDM

        Фрагмент кода из «LCD.asm»:
        ;=========== LCD Define =========
        .equ DATA_PORT = PORTA ;Объявление порта данных
        .equ DATA_PIN = PINA
        .equ DATA_DDR = DDRA

        .equ CMD_PORT = PORTE ;Объявление порта управления
        .equ CMD_PIN = PINE
        .equ CMD_DDR = DDRE

        .equ E = 2 ;Объявление битов порта управления, в соот. со схемой подключения
        .equ RW = 1
        .equ RS = 0

        .equ SPEED = 6

        ;=========== LCD Proc ==============
        InitHW:
        CBI CMD_PORT,RS ; Инициализация порта Е
        CBI CMD_PORT,RW
        CBI CMD_PORT,E

        SBI CMD_DDR,RS
        SBI CMD_DDR,RW
        SBI CMD_DDR,E

        LCD_PORT_IN
        RET

        ;===================================
        PortIn: ; Инициализация порта А
        LDI R16, 0 ; LCD Data Port
        OUT DATA_DDR, R16 ; Выставить на вход

        LDI R16, 0xFF ; Установить подтяжку
        OUT DATA_PORT, R16
        RET

        Правильно ли я все понял?

  68. Добрый день!
    DI HALT кажись я нашел у тебя ошибку в п/п BusyWait.

    BusyWait: ;LCD_PORT_IN
    CBI CMD_PORT,RS
    SBI CMD_PORT,RW
    BusyLoop: SBI CMD_PORT,E

    RCALL LCD_Delay

    CBI CMD_PORT,E //рано сбрасываешь единичку

    IN R16,DATA_PIN //прочитает непонять что (у меня в таком случае на этой ноге весит всегда единица)
    ANDI R16,0x80

    BRNE BusyLoop
    CBI CMD_PORT,E // надо бы тут
    RET

    Т.е. чтение инфы с ЖК-модуля корректно тогда, когда на RW и на E единицы. А у тебя не так. И получается что перехода на BusyLoop у тебя не происходит.

    Проверь полуйста!
    С увжением.

    1. Да и выход из п/п необходимо осуществлять если флаг BF=0 а не 1.
      В документации к hd447 написано, что BF=1 в случае когда модуль занят, а 0 — соответственно наоборот.

      1. Там-то, наверное, работает, а вот в файле LCD4.asm подпрограмма BusyWait какая-то стремная на мой взгляд — не могу понять почему строка

        IN R16, DATA_PIN

        находится там, где она находится, и почему строб поднимается до этой команды, но опускается после?
        Помимо этого, раз уж я начал писать сообщения здесь, хочу выразить глубокую признательность автору сего сайта, потому как информация, найденная мною здесь, меня уже не раз здорово выручала. И нигде такой информации — разжеванной и подробной, я не находил. Даже если говорить про ЖКИ, то куда ни ткни рисуют код на Си, а мне хотелось найти именно описание всей этой кухни применительно к ассемблеру. Нашел пока только здесь. По мере возможностей буду подкреплять свою благодарность материально.

        1. Возможно это и не верно. Где то я находил другую диаграмму HD44780, там строб был чуток по другому. Так что не стоит смотреть на мою либу как на аксиому. Но она работает, потому править что то доводя до 100% следования стандарту мне лень.

          1. Да не, я не об этом немного. Просто в случае 8-битной шины логику той самой подпрограммы я понимаю, и алгоритм соответсвует тому, что по идее должно быть. А в случае 4-х битной шины эта подпрограмма (BisyWait) непонятно что делает — там получается, что поднимается строб, после этого данные считываются в r16 из индикатора (зачем это нужно именно здесь?), потом запихиваются в стек, после этого пауза и строб вниз. И все, больши никаких считываний данных из индикатора не происходит. Где-то под конец данные из стека вытаскиваются обратно в r16. Поэтому у меня и возник вопрос — а как, собственно, в r16 окажется флаг занятости? В случае 8-битной шины считывание данных происходит псле того, как бросается строб — и тут все понятно. Хотя сейчас уже лично для меня этот вопрос не особо актуален, в принципе я сам могу теперь написать все, что мне нужно, используя вашу либу как основу. Так что никаких претензий и еще спасибо за подробные объяснения.

  69. Ну в принципе модуль может работать и без проверки флага занятости, если выдерживается какая-то пауза. Так и получается в твоем случае. Но производитель все-же рекомендует проверять его. Хотя, конечно это мелочи :)

  70. .include «LCD4_macro.inc»
    .include «LCD4.asm»
    .include «m16def.inc»

    INIT_LCD

    WR_CGADR 0

    WR_DATA 0b00000001
    WR_DATA 0b00000010
    WR_DATA 0b00000100
    WR_DATA 0b00011111
    WR_DATA 0b00000010
    WR_DATA 0b00000100
    WR_DATA 0b00001000

    WR_DDADR 0

    WR_DATA 0

    Компилирую заливаю и на экране вижу только 1 ряд черных квадратиков. Подскажите что не то делаю.

  71. Не могу понять такую вещь(DI HALT, Ваша библиотека…). DATA_RD считывает символ который находится на текущей позиции?
    Почему то у меня записывать — записывает, но не читает…

    А еще чисто риторический вопрос. Что прочитает команда CMD_RD.

    Зы. Долго парился с WH1602. Ничего не выводит, хотя бит ожидания сбрасывается, и все инициализации проходит(ставил контрольные мигания светодиодом). Только что выяснил — чтобы заработало нужно 3 раза вкл/выкл контроллер. К чему бы это О_о???

    1. Да, с текущего места. А после чтения там, ЕМНИП, автоматом переводится на следующую ячейку. Там же стоит автоинкремент/декремент.

  72. У меня дисплей 16х2. При выводе в первую строку пикселы непрерывно исполняют «бегущий огонь», во второй строке такого не наблюдается. Почему? Еще не пойму, как вычислить кодировку, вин1251 и дос866 не совпадает. туплю?

    1. Там своя собственная кодировка, не совпадающая ни с одной из стандартных. Смотри в даташите на русскую версию контроллера.

      Как это бегущий огонь?

      1. Не удаётся мне отыскать подробный даташит на WH1602L-PGB-CT#, везде один док, в котором только пины и размеры.
        Пикселы символа горят не непрерывно, по ним сверху вниз пробегает как бы тень, так во всей строке, на скорость этого процесса влияет параметр SPEED. Теперь и на второй строке такой тетрис появился. На дисплей буду цифры выводить с 4 датчиков, очень неудобно наблюдать данные при таком эффекте.

        1. А ты ищи даташит не на дисплей, а на контроллер HD44780. А мерцание — ты просто слишком часто обновляешь картинку.

  73. Не работает. Использую 4-ёх битный режим. Atmega16. Шина данных — PB0…PB3, шина управления — PB4 — RS, PB5 — E, PB6 — RW.

    Подправил так:
    .equ DATA_PORT = PORTB ; LCD Data Port
    .equ DATA_PIN = PINB
    .equ DATA_DDR = DDRB

    .equ CMD_PORT = PORTB ; LCD Control Port
    .equ CMD_PIN = PINB
    .equ CMD_DDR = DDRB

    .equ E = 5
    .equ RW = 6
    .equ RS = 4

    .equ SPEED = 14 ;

    Думаю проблема в том, что шина данных и шина управления находятся на одном порте (PORTB). Не проходит инициализация LCD (макрос INIT_LCD). Отлаживаю по светодиоду. Пишу программу для уже существующего железа, потому перевесить какую-то шину на другой порт не могу. Подскажите, где подправить код.

      1. Использовал по ссылке библиотечные файлы на 4 пина. Изменил только:

        .equ E = 5
        .equ RW = 6
        .equ RS = 4

        В своей программе содержиться:

        Main:

        sbi ddrb,7 /* Включая подсветку LCD через полевик */
        sbi portb,7

        INIT_LCD ; Инициализируем

        sbi ddrd,6 /* Зажигаю светодиод */
        sbi portd,6

        WR_CGADR 0 ; Указатель на начало знакогенератора.

        WR_DATA 0b00000001 ; Запись данных нового знака
        WR_DATA 0b00000010
        WR_DATA 0b00000100
        WR_DATA 0b00011111
        WR_DATA 0b00000010
        WR_DATA 0b00000100
        WR_DATA 0b00001000

        WR_DDADR 0 ; Указатель на начало видео памяти (ячейка с координатми 0,0)

        WR_DATA 0 ; У новоиспеченного символа код 0 напечатем его

        JMP Main

        Остальной код — «скелет» — подключение файлов, таблица векторов, инициализация стека.
        Зажигаю светодиод до макроса INIT_LCD — горит, после — нет.

        1. Попробуй побаловатья с инициализацией. У тебя она на 4 пина или на 8? Если на 4ре бита, то дисплей мог не перевестить в другой режим. У них есть некоторы различия между собой. Некоторым, например, инициализацию надо дважды проводить. Некоторым выдержать 50мс после включения питания. В общем от дисплея зависит.

          1. Вот полностью рабочий код для мега16, где как раз все висит на одном только порту Б

            Копаюсь в этом коде, пытаюсь понять почему ничего не выводится. Вроде нашел ошибку.
            А именно в этом куске:

            BusyWait: CLI
            RCALL PortIn ; Порты на вход

            CBI CMD_PORT,RS ; Идет Команда!
            SBI CMD_PORT,RW ; Чтение!

            BusyLoop: SBI CMD_PORT,E ; Поднять строб
            RCALL LCD_Delay ; Подождать

            IN R16,DATA_PIN ; Считать байт

            PUSH R16 ; Сохранить его в стек. Дело в том, что у нас R16 убивается в LCD_Delay

            CBI CMD_PORT,E ; Бросить строб — первый цикл (старший полубайт)
            RCALL LCD_Delay ; Подождем маленько

            SBI CMD_PORT,E ; Поднимем строб
            RCALL LCD_Delay ; Подождем
            CBI CMD_PORT,E ; Опустим строб — нужно для пропуска второго полубайта

            RCALL LCD_Delay ; Задержка снова

            POP R16 ; А теперь достаем сныканый байт — в нем наш флаг. Может быть.

            ANDI R16,0x80 ; Продавливаем по маске. Есть флаг?
            BRNE BusyLoop ; Если нет, то переход

            BusyNo: SEI ; Разрешаем прерывания.
            RET

            Сразу после поднятия строба E и некоторой задержки происходит считывание флага занятости. По логике, считывание должно происходить после опускания стробирующей линии. Из-за этого процедура проверки флага занятости зациклилась.

            Ещё у тебя в программе было прописано линии управления — 0,1,2 биты, а линии данных — 4,5,6,7. А у меня в железе наоборот. )
            Поменяв лишь в LCD Define ничего не дало, менял ещё в самом коде — там где накладываются битовые маски — с точностью наоборот(поменял местами тетрады).
            Двигаюсь дальше…

  74. Не могу понять в чем дело, работает только с задержками после каждой команды вот так:
    INIT_LCD
    call Delay
    LCD_COORD 0,1
    call Delay
    WR_DATA 0b00110001
    call Delay
    WR_DATA 0b00110001
    call Delay
    WR_DATA 0b00110001
    call Delay
    WR_DATA 0b00110001
    call Delay
    Частота контроллера 8 мгц, если задержки убрать, то инициализация может не пройти (экран не гаснет) или выводит не 4 символа а меньше или ничего. Пробовал увеличивать параметр SPEED не помогает.

      1. Заменил процедуру ожидания готовности программной задержкой на 40 мкс стало нормально.

  75. DI HALT огромное спасибо за проделанную работу. Только изучаю AVR. После моргания светодиодами хателось ченить по серьезней забацать и мысль поперла в сторону LCD. В сети библиотеки попадались тока под Си, а тут просто падарок с небес. Разжевано все с примерами и доступным языком. С подключением разобрался. Сделал inc r17, RCALL DATA_WR, задержка и зациклил. На экране поперло по кругу все что в памяти LCD. Вариан 2, выводим фразу, например:
    INIT_LCD ; Инициализируем
    WR_DDADR 0 ; Указатель на начало видео памяти (ячейка с координатми 0,0)
    WR_DATA $5f ;
    WR_DATA $5f ;
    WR_DATA $41 ;выводим фразу: _ _AVR_ _
    WR_DATA $56 ;
    WR_DATA $52 ;
    Вопрос такой: как лучше оранизовать вызов целой фразы по команде, например нажатием кнопки.
    Создать несколько фраз. В общем технология создания меню. Читал статью «Подключение клавиатуры к МК по трем проводам на сдвиговых регистрах. Часть 2. Буквенный ввод как на телефоне», в надежде найти ответы. Но либо плохо искал, либо еще не созрел для самостоятельного осмысления.

    1. Запихай фразу в память программ, а по нажатию кнопки, в цикле, через LPM команды сгружай на дисплей.

      Причем я рекомендую следующий метод: Сделай видео память. Область памяти длинной Х*У байт, под размер дисплея. И все данные пиши туда. А раз десять-двадцать в секунду, параллельным потоком, по таймеру или еще как, эту видеопамять пропихивай в дисплей. В результате ты не будешь тратить драгоценное время проца на бессмысленные таскания данных туда сюда. Проще в видео память писать.

      В общем гугли в моем блоге статьи по работе с данными в памяти (команды LPM и подобные).

  76. Вот эта штука: LDI R17,(1<<LCD_DDRAM)|(@0+40*@1)
    почему-то не хочет работать на 4-х строчном. Пишу в 3-ю строку, выводит на 4-ю, смещение по Х не совпадает. С первыми строками всё ок.

    1. А у меня она и на двустрочном не работает почему-то, если координаты не задаю начинает с первой строчки выводить, если перед выводом использовать LCD_COORD X,Y вне зависимости от Y выводит во вторую строку, но по X выводит правильно.

    2. У четырехстрочного емнип сложней несколько. Там два контроллера, один отвечает за верхнюю половину, второй за нижнюю. Надо подробней смотреть ДШ на него.

  77. Я так понял команда LCDCLR должно полностью убирать все с экрана. Но у меня почему-то обновление не происходит. Оставил в программе только инициализацию и очистку, но старые надписи как были, так и остались. Как с ними справиться?

      1. Спасибо, а почему в протеусе не работает??
        И еще вопрос. Когда запускаю программу в студии, то после команды инициализации у меня курсор начинает крутиться по файлу LCD.asm и не выходит оттуда.
        Проект студии и файл протеуса http://yadi.sk/d/CcfoE0nO0miws

  78. Здравствуйте!
    Спасибо за полезные уроки. И сразу вопрос: хочу прикрутить LCD 1602 к Меге8 на один порт (D) по 4-х проводной схеме — данные на пинах 0…3, а управление — на пинах 5…7 того же порта. Такое возможно? Поддержит ли Ваша библиотека LCD_HD44780 такую задумку?
    Спасибо.

  79. Уважаемый DI HALT а не могли ли бы вы перекомпилировать эту библиотеку для IAR ? Я думаю куча людей была бы вам благодарно, весь нет перерыл ничего вменяемого не найду. С уважением Роман.

  80. У нас сегодня либа-таки заработала в протеусе после замены процедуры BusyWait на обычную задержку без опроса состояния индикатора. Конечно, это некрасиво, но для прота пойдет) Модель индикатора LM020L. SPEED была равен 14, тактовая в протеусе 1МГц, 8-ми битный режим. В макросе INIT_LCD был LCD_F_2L убран, т. к. LM020 — это 1 ряд дисплей.

  81. Странный глюк сегодня схватил. Вывожу на экран слово «осталось», жду 2 секунды и потом вывожу другой текст.
    так вот. если нажать на кнопку ресет в тот момент когда на экране слово «осталось» — все зависает контроллер. в другие моменты хоть жми, хоть нет — работает….
    если кнопку не нажать — программа выполняется без ошибок. O_o

    Что это? со стеком проблема? с дисплеем?
    вот кусок кода:

    RCALL Set_Dist_Interval
    RCALL CALC
    LCD_COORD 0,1
    RCALL Calc_Speed
    WR_DATA ' '
    RCALL Show_Speed //Показываем текст

    ldi R16, 2 //Ждем 2 секунды.
    RCALL WaitSeconds // Если здесь нажать RESET - просто уйдет в ресет
    // и начнет выполнятся заново

    //После этой функции указатель стека = 0х45F. т е в норме
    //проверял тупо выводя его на LCD

    LCDCLR
    LCD_COORD 0,0

    WR_DATA 'O' // Если здесь нажать RESET - камень повис
    WR_DATA 'c' // слово осталось
    WR_DATA 191
    WR_DATA 'a'
    WR_DATA 187
    WR_DATA 'o'
    WR_DATA 'c'
    WR_DATA 196

    LCDCLR
    LCD_COORD 0,0
    WR_DATA 'x' // Если здесь нажать RESET - просто уйдет в ресет
    // и начнет выполнятся заново

      1. зависает не сам микроконтроллер а зацикливается в BusyLoop

        BusyLoop: SBI CMD_PORT,E ; Поднять строб
        RCALL LCD_Delay ; Подождать

        IN R16,DATA_PIN ; Считать байт

        PUSH R16 ; Сохранить его в стек. Дело в том, что у нас R16 убивается в LCD_Delay

        CBI CMD_PORT,E ; Бросить строб - первый цикл (старший полубайт)
        RCALL LCD_Delay ; Подождем маленько

        SBI CMD_PORT,E ; Поднимем строб
        RCALL LCD_Delay ; Подождем
        CBI CMD_PORT,E ; Опустим строб - нужно для пропуска второго полубайта

        RCALL LCD_Delay ; Задержка снова

        POP R16 ; А теперь достаем сныканый байт - в нем наш флаг. Может быть.

        ANDI R16,0x80 ; Продавливаем по маске. Есть флаг?
        BRNE BusyLoop ; Если нет, то переход

      2. ито я только что вычислил. и никакой код кроме
        WR_DATA ‘O’ // Если здесь нажать RESET — камень повис
        WR_DATA ‘c’ // слово осталось
        WR_DATA 191
        WR_DATA ‘a’
        WR_DATA 187
        WR_DATA ‘o’
        WR_DATA ‘c’
        WR_DATA 196

        на эту ошибку не влияет

        1. Ну тогда встрой в Bussy Wait ограничитель циклов. У тебя видимо дисплей не отзывается на инициализацию между операциями записи в память.

  82. Когда в процедуре BusyWait начинается рабочий цикл, то в самом начале строб вверху, а в r16 уже читается DATA_PIN. Потом цикл будет работать нормально, но что окажется в r16 в тот начальный момент? Ведь флаг занятости в порт выскочит только после того, как строб уйдет вниз, так ведь? Не было бы логичней в r16 загонять содержание порта тремя строками позже — после того, как опускается первый строб? В общем, у меня на индикаторе WH1602A нифига не хотела работать эта процедура, пока я не сделал что-то в таком духе:

    BusyWait:
    CLI
    RCALL PortIn
    CBI CMD_PORT,RS
    SBI CMD_PORT,RW
    BusyLoop:
    SBI CMD_PORT,E ; Строб внизу, что там в DATA_PIN пока неизвестно.
    RCALL LCD_Delay
    CBI CMD_PORT,E ; Строб вниз, вот теперь в порт должен пойти адрес и BF
    IN R16,DATA_PIN ; Вот на это как раз стоит посмотреть.
    PUSH R16
    RCALL LCD_Delay
    SBI CMD_PORT,E ; Вот здесь начинается пропуск второго полубайта
    RCALL LCD_Delay
    CBI CMD_PORT,E ; Информация эта в данном случае не нужна, пропускаем мимо.
    RCALL LCD_Delay
    POP R16
    ANDI R16,0x80 ; Смотрим где флаг.
    BRNE BusyLoop ; Если флаг торчит начинаем все сначала.
    BusyNo:
    SEI
    RET

  83. Извините за чайничество. Я пишу проект на С в AVR Studio. Как включить вашу библиотеку в текущий проект на С?

  84. Помогите, не могу распинать LCD на PinboardII (HD44780)
    DI с твоей библиотекой не получилось, решил сначала в лоб все сделать
    так сказать «на примитивах» . Вот прога, при отладке проходит до конца
    косяков не обнаружил. Должны выводиться на LCD символы 1,Q,W,s.
    Но ничего не робит, горит только верхняя строчка и никакой активности более.
    Подскажите, а то два дня убил, мозг кипит. Мож опять какой-нибудь примитивный
    косяк у меня :-)
    .def temp = R16
    .def chet = R17
    .def cmd = R18
    .def data = R19
    ; ==================
    .CSEG
    .ORG $000
    rjmp RESET ; Reset Handler
    . тут остальные вектора
    .
    ; ==================
    RESET:
    ldi temp,0b11111111
    out DDRA,temp
    ldi temp,0b00000000
    out PortA,temp

    ldi temp,0b00000000
    out DDRB,temp
    ldi temp,0b11111111
    out PortB,temp

    ldi temp,low(RAMEND)
    out SPL,temp
    ldi temp,high(RAMEND)
    out SPH,temp

    rjmp main
    ;===================== MAIN ========================
    main:
    ldi chet, 0b00000000

    ;========================запись команд (cmd) и данных(data) в LCD ==========================================
    ldi cmd,0b00111000 ; шина 8 бит, 2 строки
    rcall REC_Command
    ldi cmd,0b00000001; очистка экрана
    rcall REC_Command
    ldi cmd,0b00000110; Инкремент адреса. Экран не движется
    rcall REC_Command
    ldi cmd,0b00001100; Включили дисплей (D=1)
    rcall REC_Command
    ldi cmd,0b00000001; Очистили дисплей, указатель встал на DDRAM
    rcall REC_Command
    ldi cmd,0b00010100; Сдвинули курсор (S/C=0) вправо (R/L=1)
    rcall REC_Command
    ldi data,0b00110001; один в кодировке ASCII
    rcall REC_DATA
    ldi data,0x51; Q
    rcall REC_DATA
    ldi data,0x57; W
    rcall REC_DATA
    ldi data,0x73; s
    rcall REC_DATA
    qwe:
    rjmp qwe зациклились

    ;======================= ПОДПРОГРАММЫ ===============================
    REC_Command: ; запись команды в LCD, команда передается в переменную cmd (R18)
    rcall Ogidanie_gotovnosti ; ожидание флага готовности LCD

    ldi temp,0b11111111 ; RS = 0
    out DDRA,temp
    ldi temp,0b00000000
    out PortA,temp

    ldi temp,0b11111111 ; R/W = 0
    out DDRA,temp
    ldi temp,0b00000000
    out PortA,temp

    rcall gotovsya

    ldi temp,0b11111111 ; порт данных на выход
    out DDRB,temp
    mov temp,cmd
    out PortB,temp

    rcall zadergka
    rcall priem

    ldi temp,0b00000000 ; порт данных на вход с подтяжкой
    out DDRB,temp
    ldi temp,0b11111111
    out PortB,temp
    ret
    ;———————————————————————————-
    REC_DATA:
    rcall Ogidanie_gotovnosti

    ldi temp,0b11111111 ; RS = 1
    out DDRA,temp
    ldi temp,0b00000000
    out PortA,temp

    ldi temp,0b11111111 ; R/W = 0
    out DDRA,temp
    ldi temp,0b00000000
    out PortA,temp

    rcall gotovsya

    ldi temp,0b11111111 ; порт данных на выход
    out DDRB,temp
    mov temp,data
    out PortB,temp

    rcall zadergka
    rcall priem

    ldi temp,0b00000000 ; порт данных на вход с подтяжкой
    out DDRB,temp
    ldi temp,0b11111111
    out PortB,temp
    ret
    ;————————————————————————————
    Ogidanie_gotovnosti:
    ldi temp,0b00000000 ; порт данных на вход с подтяжкой
    out DDRB,temp
    ldi temp,0b11111111
    out PortB,temp

    ldi temp,0b11111111 ; rs = 0
    out DDRA,temp
    ldi temp,0b00000000
    out PortA,temp

    ldi temp,0b11111111 ; r/w = 1
    out DDRA,temp
    ldi temp,0b00000010
    out PortA,temp
    Ogidanie:
    rcall gotovsya
    rcall zadergka
    rcall priem
    in temp, PinB
    cpi temp,0b10000000; смотрим бит готовности 7 ( D7 LCD)
    breq Ogidanie
    ret
    ;—————————————————————————————-
    zadergka:
    inc chet
    cpi chet, 0b00010100
    brne zadergka
    ldi chet, 0x00
    ret
    ;————————————————-
    gotovsya:
    ldi temp,0b11111111 ; строб ГОТОВСЬ ! (E=1)
    out DDRA,temp
    ldi temp,0b00000100
    out PortA,temp
    ret
    ;—————————————————
    priem:
    ldi temp,0b11111111 ; строб ПРИНЯТЬ ! (E=0)
    out DDRA,temp
    ldi temp,0b00000000
    out PortA,temp
    ret
    ;—————————————————

    1. Надо внимательней смотреть на тайминги. Для начала увеличить везде задержки. То, что при включении индикатор выдает только одну строку означает, что он не инициализировался. То есть затык скорее всего происходит уже в процедуре инициализации. Совет один — взять даташит на индикатор (только полный только даташит, а не урезанную форму в виде одной странички), найти там раздел с расписанным алгоритмом инициализации (ближе к концу), и строго выдержать все тайминги.

    2. Я писал свою библиотеку, имея на руках индикатор WH0802A. Когда у меня проблемы и ничего не хочет работать, я лезу смотреть даташит. Вот, например, что-то вроде этого:

      http://ekits.ru/published/publicdata/SHOPEKITEKITS/attachments/SC/products_docs/WH0802A-YGH-CT.pdf

      Там есть страница 18, где изображен алгоритм инициализации индикатора. И приведены тайминги, которые надо выдерживать, еще есть временные диаграммы, где расписано все досконально — сколько чего должно длиться. Я все делал по этой схеме, у меня все работает. И работает со всеми индикаторами такого типа всех производителей, что я использовал — и китайский ноунейм, и индикаторы agena, и еще куча других, на всех скоростях без каких-либо глюков.

      Вы какой индикатор используете? Если это винстар или какой-то китайский ноунейм, то все, что написано в даташитах по винстару будет, скорее всего, применимо и к ним.
      При беглом и невдумчивом просмотре вашего кода, сразу всплывает вопрос — а почему вы вот эту команду в инициализации:

      ldi cmd,0b00111000 ; шина 8 бит, 2 строки
      rcall REC_Command

      пересылаете только один раз? В даташите, ссылку на который я привел выше, написано, что эта команда должна быть подана дважды с задержкой между ними не менее 39 мкс.

      А что такое 39 мкс? Если у вас контроллер работает, скажем, на 8 МГц, то 1 такт = 1/8000000 = 125 нс. Чтобы сформировать минимальную задержку в 39 мкс, контроллеру надо потупить или занять себя чем-то на целых 312 тактов. Минимум. Вы уверены, что в вашем коде такая задержка реализуется? А как насчет остальных задержек?

      И все остальные команды в инициализации лучше подавать в соответсвии с рекомендациями даташита.

      Так что внимательно изучайте даташит и делайте так, как там написано.

      Еще совет, не пишите код таким способом.
      Используйте такие полезные штуки, как .equ
      Например, у нас есть строб E, есть биты направления запись/чтение RW и выбора регистра RS. Есть еще порт, куда подключен индикатор, поэтому, чтобы не городить в коде кучу плохочитаемых строк, типа

      sbi PortA, 0 ; что это? кто это? зачем это?
      cbi PortA, 2 ; через неделю уже фиг вспомнишь сразу

      Сразу пишем вначале библиотеки:
      .equ E = 0 ; строб прицепили, например, к биту 0 порта
      .equ RW = 1 ; а RW к биту 1
      .equ RS = 2 ; это бит 2
      .equ DT_PORT = PortA ; все прицепили к порту А
      .equ DT_PIN = PinA
      .equ DT_DDR = DDRA
      .equ CMD_PORT = PortA

      И дальше, когда надо, например, поднять строб, можно написать куда более читаемую строку:

      sbi CMD_PORT, E

      Если в другом проекте придется цеплять к другому порту и к другим битам — то не нужно в коде править кучу нулей и единиц, достаточно поменять значения в .equ, а ассемблер сам везде в коде подставит нужное значение вместо E, RW, RS и т.д.
      Кроме того, очень полезно обозначить все конфигурационные биты в командах индикатора, например:

      .equ DL = 1 ; разрядность шины, 1 = 8 бит, 0 = 4 бит.
      .equ N = 1 ; число строк, 1 = 2 строки, 0 = 1 строка
      .equ F = 0 ; формат символа, 1 = 5×11, 0 = 5×8

      и т.д., см. таблицу команд в даташите.
      Это позволяет писать понятные вещи:

      ; вначале все обозначили по-человечески
      .equ DL = 1 ; разрядность шины, 1 = 8 бит, 0 = 4 бит.
      .equ N = 1 ; число строк, 1 = 2 строки, 0 — 1 строка
      .equ F = 0 ; формат символа, 1 = 5×11, 0 = 5×8


      ; а теперь пишем красиво

      LCD_INIT:

      cbi CMD_PORT, RS ; все в исходное положение
      cbi CMD_PORT, RW ; будем писать команду
      cbi CMD_PORT, E ; неактивный уровень строба = 0

      ldi r16, (1<<5) | (DL<<4) | (N<<3) | (F<<2) ; первая команда — ставим нужные байтики
      out DT_PORT, r16 ; данные в порт
      sbi CMD_PORT, E ; поднимаем строб, формируем управляющий импульс
      nop ; немного тупим, так как импульс должен быть не менее 140 нс, см. даташит
      nop
      cbi CMD_PORT, E ; строб вниз, данные пошли в индикатор

      rcall delay_40us ; у нас тут инициализация, надо 40 мкс подождать, см. даташит

      Это начало инциализации, код пересылки в индикатор команды, устанавливающей интерфейс (DL), количество используемых строк (N) и формат символа (F) (для 8-битного интерфейса). Эту команду нужно повторить еще раз. В случае 4-битного интерфейса ситуация немного усложнится, но ненамного. Если понадобится изменить какие-то параметры, например, надо будет использовать только одну строку, то достаточно изменить строчку вначале файла:

      .equ N = 0 ; 1 строка

      и не надо будет лезть в сам код, искать среди нулей и единиц где там этот бит.

      1. Спасибо за советы ! Так писал потому что быстрее хотелось, но вышло наоборот )) Буду курить даташит, спасибо ))

      2. Да, спасибо! Тоже почитал, в целом мыслил аналогично, но примитивнее. Делал все согласно ДШ на MT-16S2H — результат 0. На 8 МГц как у тебя в примере, также между стробами пару нопов воткнул, ну и само собой задержки по 40 мкс при инициализации. Правда последовательность команд процедуры инициализации немного отличается от WH-1602, тем не менее для wh все ok, а вот МЭЛТ не арбайтн. Никаких признаков инициализации, одна подсветка горит. Продолжаю эксперимент, но думаю, может ЖКИ паленый!?

        1. Я сталкивался с МЭЛТами, в частности, с 8-символьными 2-х рядными индикаторами, 3-вольтовые версии. Паленого ничего ни разу не попадалось. Да, у них немного отличается процедура инициализации от Винстаровских индикаторов, но в даташите все вполне подробно расписано. В общем, когда я впервый раз столкнулся с МЭЛТом, то пришлось написать езще одну процедуру инициализации специально под эти индиткаторы. Собственно, весь остальнй код, который работал под Винстары (и все остальные индикаторы), отлично работал и с МЭЛТом. Можно оценить работоспособность индикатора таким образом: первые команды в инициализации — это выбор интерфейса и количество строк. По умолчанию индикатор работает в однострочном режиме. У меня чаще всего косяки были где-то в середине процедуры инициализации, а первые команды проходили. Поэтому я видел, что экран пустой, но индикатор перешел в двустрочный режим (включалась вторая строка и ее можно заметить). Это значит, что индиатор скорее работает нормально, но после первых команд в программе происходит какая-то лажа, и вся остальная настройка херится. Поэтому дальше инициализации ничего не идет. Бывают совсем глупые ошибки, на которые смотришь, но почему-то никак не можешь увидеть. Например, я сделал библиотеку так, чтобы можно было цеплять выводы индикатора к любым выводам контроллера в разнобой (не обязательно DB7 — bit7; DB6 — bit6 и т.д.). Это увеличивает код и снижает скорость, но для меня это не так критично было, куда важнее было удобство при разводке. Ну и потом, когда я написал процедуру проверки флага занятости, я почему-то забыл, что бит 7 индикатора (с которого и читается флаг занятости) у меня может приходить на любой бит порта контроллера. И написал код так, что по маске проверялся всегда бит 7 порта. И потом, далеко не сразу, я заметил, что моя библиотека в определенных условиях не хочет работать. Я никак не мог понять в чем дело, смотрел код много раз, все казалось правильно, и только через несколько дней до меня вдруг дошло, что процедура проверки флага занятости в моем случае работает через задницу. Поправил — и все стало ОК. Еще была ошибка — библиотека работала не на всех скоростях. Скажем, на 8 МГц работала, а на 1 МГц — нет. Оказалось, что я код написал таким образом, что у меня между пересылкой двух полубайт данных при 4-х битном интерфесе образовывалась определенная пауза. И на 1Мгц она увеличивалась настолько, что индикатор уже не понимал что в него пихают и уходил в пике. Допер не сразу, но потом поправил код и все заработало нормально. Кстати, на сайте МЭЛТа еще есть файлы с примерами кода для разных индикаторов. Полезно скачать и посмотреть.

          1. Только что победил его:) Работает как часы. В общем проблему по ДШ найти не удалось, ибо не смог найти такую вещь, что нужно оказывается шину данных при чтении на подтяжку вешать. Весь свой код 100 раз перепилил, задержки пересчитал, а вот банальную подтяжку упустил. Увидел сей момент еще сутра на свежую голову в здешней библиотеке. Поправил, а вот проверить только вечером получилось. Процедуры чтения/записи мои от здешних отличаются лишь в части реализации. Логику отлаживал через JTAG на 16й меге/8 MГц. Естественно только логику, работу ЖКИ через JTAG никак не проверить. Переписал код в более удобочитаемый и понимаемый вид, теперь можно двигаться дальше. Спасибо за советы — очень помогли!

  85. Приветствую, DI.
    Попробовал в железе библиотеку — все работает, но есть одна странность. Картинка на дисплее довольно сильно моргает. Задержку ставлю на 14, контроллер на 4 МГц. При снижении частоты до 1 МГц почти перестает моргать картинка, но все равно заметно (особенно если смотреть под углом). В чем может быть проблема?

          1. Вообще странное поведение дисплея. Ведь контроллер обращается к дисплею только во время записи команд/данных, дальше дисплей живет своей жизнью.

          2. Вобщем у меня полезли символы только при Speed = 1. Странно. У меня PBII, с частотой я не играю, внутреняя 8 Мгц.
            Но заработал он криво. Дисплей мутозит непадецки! Причем когда провода трогаю соеденительный колбасит еще больше — списал на дребезг контактов перемычек.
            Я вот что думаю, Pryanic, ведь у тебя когда прога прошла и честно вывела, допустим ), HELLO WORLD, дальше то что ? Прога не закольцована.
            ХЫ. Меня букавки первы порадовали на моем дисплее «LOLOLOL» — действительно ЛОЛ. ))))

          3. Думаю что затык в работе ATmega по дефолту на 1МГц.
            The device is shipped with CKSEL = “0001” and SUT = “10”. The default clock source setting is
            therefore the 1 MHz Internal RC Oscillator with longest startup time.

  86. Блин, ЖК с демкой от DI на PBII работает. Переменная SPEED = 14, шина 4 бита. Все пашет нормально.
    Когда беру просто библиотеку, нифига. Ни на шине 4 бита, ни 8 бит. Что уж там можно еще с таймингами воротить, геморой просто какой-то. Это что получается нужно реализовывать все задержки отдельно. Просто ЖОПА, проще еще либу поискать другую. Уже нет слов и настроения (((

  87. Не работает. Уже две недели бьюсь, больше сил нет.Использую 4-ёх битный режим. Atmega8515. Шина данных — PD4…PD7, шина управления — PD2 — RS, PD3 — E, GND — RW.
    Дисплей Winstar WH1602-TMI-ET#
    Кто сталкивался? Напишите код, чтобы понять в чем проблема.

  88. Прогнал программу в AVRstudio она у меня зацикливается на BusyLoop (флаг не появляется).Видно, что дисплей инициализируется нормально,только до команд дело не доходит.
    Как сделать в библиотеке чтоб RW всегда было =0 т.е (GND)?
    Не судите строго я только учусь.

    1. Ну так все правильно. В авр студии же ждет ответа от дисплея, а дисплея то нету! Вот она и циклится по кругу. Можешь вручную это условие обойти.

  89. Я так и понял. У меня на отладочной плате RW подключена на GND . И порт один PORTD. Что исправить в библиотеке чтоб RW была только на запись. Может закоментить все RW?
    Уже давно работаю с вашей библиотекой только по 8-ми бит.все работает,а на 4-бит досада((((

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

  90. Здравствуйте!!! Господа
    Есть такая программа. Задача такая при нажатии на кнопку срабатывает прерывания int0 или int1 неважно в прерывании есть число 9999 оно уменьшается на 1 и выводится на LCD. Вот как это число преобразовать в BCD формат для отображения на LCD в этой программе я не знаю ПОМОГИТЕ ПОЖАЛУЙТА!!!

    1.;*************************************************************************

    2. ;* *

    3. ;* Convert unsigned 16 bit to 5 digit ASCII *

    4. ;* *

    5. ;* *

    6. ;* *

    7. ;*************************************************************************

    8. ;

    9. ;Входной: R17, R16 = 16 bit значение 0… 65535

    10.; выход: R20, R18, R19, R17, R16 = 5 цифр (ASCII)

    11.; цикл: 20… 170

    12.

    13.push temp

    14.

    15.LCDCLR ;очистка LCD

    16.LCD_COORD 1,0;

    17.

    18.pop temp

    19.

    20. bin16_ascii:

    21.

    22.

    23.

    24.inc temp

    25. ldi r17,0

    26.

    27.

    28.

    29.; ldi r21, 10 + ‘0’

    30.; _bcd0: dec r21

    31.; subi r16, low(-100000) ;+100000

    32.; sbci r17, high(-100000)

    33.; brcs _bcd0

    34.

    35. ldi r20, -1 + ‘0’

    36. _bcd1: inc r20

    37. subi r16, low(10000) ;-10000

    38. sbci r17, high(10000)

    39. brcc _bcd1

    40.

    41. ldi r19, 10 + ‘0’

    42. _bcd2: dec r19

    43. subi r16, low(-1000) ;+1000

    44. sbci r17, high(-1000)

    45. brcs _bcd2

    46.

    47. ldi r18, -1 + ‘0’

    48. _bcd3: inc r18

    49. subi r16, low(100) ;-100

    50. sbci r17, high(100)

    51. brcc _bcd3

    52.

    53. ldi r17, 10 + ‘0’

    54. _bcd4: dec r17

    55. subi r16, -10 ;+10

    56. brcs _bcd4

    57.

    58. subi r16, -‘0’

    59.

    60. ;————————————————————————-

    61.

    62. rcall RD_DATA;

    63.

    64.

    65.

    66.

    67.reti ;выход

  91. DiHalt, помогите разжевать эту библиотеку для 4-х битного режима.
    Есть в наличии ЖКИ от Панасоник фаса. +5В, 4-х битный,2-ух строчный инициализируется в 1 строку.
    Ну и демо платка есть Attiny2313. Соединяю их посредством «проводков», программирование на асм в AVRSTUDIO, прошиваю в СodeVisionAVR самопальным программатором по LPT. Хотелось бы скелет программы типа «хелло ворлд», ну вот прям компильнул — прошил — посмотрел…

  92. DiHalt, здравствуйте.
    Нужна подсказка. Делаю макет термометра на вашей PB2. В двух регистрах есть значение температуры от 10 до 40 градусов в двоичном коде- как его преобразовать в ASCII и вывести на LCD ? Через таблицы, или есть другие способы ?

  93. Уважаемый Di Halt и жители этого чудестного сайта, выручайте.
    Попытался смоделировать на протеусе вывод символа на дисплей, используя предлагаемую, библиотеку и столкнулся с такой проблемой:
    В Авро студии все прекрасно заработало, а вот протеус работать не захотел. Путем трассиовки выяснилось, что проблема вот в этом месте:
    PortIn: IN R16,DATA_DDR ; Данные из DDR в регистр
    ANDI R16,0x0F
    OUT DATA_DDR,R16 ; Выдаем результат в порт.
    IN R16,DATA_PORT ; Берем данные из порта
    ORI R16,0xF0 ; Выставляем все биты старшей тетрады, не трогая младшую
    ;OUT DATA_PORT,R16 ; Выдаем в порт
    OUT DATA_PORT,R16 ; Выдаем в порт
    RET
    Дело в том, что студия, выставляя значение в DATA_PORT никак не затранивает при этом DATA_PIN, а протеус выставляет пины в соответсвиии со значеним DATA_PORT в единицы, из-за этого вся прога кроется медным тазом: зацикливает в подпрграмме BusyWait. Я сам новичок, и не совсем понимаю, что такое «подтяжка», но кажется, именно с этим и проблема. Как переписать код так, чтобы при выполнении команды
    OUT DATA_PORT,R16
    это число не шло на пины?

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

      1. Прошу прощения, но вопрос срочный, делаю курсовик, мне нужно ПРОСТО чтобы хоть что-нибудь появилось на дисплее, я весь интернет перелопатил.. Нет времени разбираться, как это все работает, нужно просто чтобы выводило на дисплей. Я сам я буду уже писать программу, что именно будет выводиться.
        Что нужно изменить в коде, чтобы в busywait не зацикливало и прога шла дальше? Умоляю, помогите!

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

        2. Надо выкинуть BusyWait вообще, воткнув вместо него простой Delay на пару мс. И все.

          Насчет фуза жтага… не знаю где он в протеусе, но его можно программно выключить, записав в начале программы дважды в бит JTD регистра MCUCSR.

  94. DI HALT, может быть у Вас есть простой asm исходник для любого МК AVR и любого дисплея, который бы выводил на него хоть что-нибудь? Мне просто нужно взглянуть на рабочую программу, чтобы понять как вообще происходит вывод на дисплей

    1. Неа, я все делал через свою библиотеку и везде она. Одно маленькое но… я отлаживаю всегда в железе, а протеусом не пользуюсь.

  95. При подключении по четырех битной шине данных «порт данных использует биты 7…4 любого порта» А где можно задать. чтобы использовались биты 3…0 например ? Если можно конкретную строчку укажите.

  96. Когда изучал асм, запускал дисплей на ваших библиотеках. Текст выводил через буфер видеопамяти.
    Для вывода кирилици использовал функцию перекодировки ansi2lcd и все работало. Сейчас осваиваю Си. Возникла проблема тот же принцип не катит. Строчку :»АБВГД ABCD» компилятор на асме в память пишет как:c0 c1 c2 c3 c4 20 41 42 43 44 , а на Си:d0 90 d0 91 d0 92 d0 93 d0 94 20 41 42 43 44 .
    Тоесть Кирилицу пишет 2 байтами. Несколько дней в гугле пользы не принесли. Даже кодировку в которой пишет не подобрал. Что делать не подскажеш?

    1. Ну дык. Уникод же :) Попробуй поискать в IDE настройки кодовой страницы и сохранить в чем то восьмибитном. Правда не факт, что заработает кирилица.

  97. Я об этом думал, но не нашел где это сделать в 6 студии. Смотрел таблицы уникода, кирилица вроде 0400-04ff. А сдесь с d0 начинается.

    1. Вопрос решил. Открыл файлы блокнотом и пересохранил их с кодировкой ANSI. Главный фаил был в UTF-8, а остальные ANSI. После исправления кирилица стала 8 бит, только некоторые коменты на русском превратились в кракозябры.

  98. DI HALT, cпасибо за проделанную работу и оптимизированный код.
    Как мне кажется — разобрался, почему симуляция не идет в Proteus 8.1.
    В вашу библиотеку добавил макрос WR_CMD_LO — досылает младшую часть полубайта в контроллер LCD после перехода в 4х битный режим.
    После этого в Proteus 8.1 все заработало (в прилагаемом архиве по этому поводу есть немного камментов в LCD4_macro_edited.inc).

    Более того, с помощью этой библиотеки получилось инициализировать LED (WEH001202ALPP5N00000) на контроллере WS0010 — без всяких танцев с бубном, т.е. без:
    — ожидание 500 ms перед стартом инициализации после подачи питания (реально конская задержка).
    — пять раз отсылки нулевого байта (в даташите не нашел такого «волшебства» — но люди пишут, что такое есть в даташите, и это реально помогает).

    Но есть пару непроверенных моментов:
    — в железе я использовал Atmega8 на частоте 1МГц (возможно на повышенных частотах не будет хватать задержки для инициализации WS0010), собрано на макетке с питанием от USB.
    — не проводил долговременного использования дисплея (встречал информацию — что сначала все нормально, но со временем идет какой то сбой в обработке команд, но вроде это было связанно с проверкой busy flag, а в вашей библиотеке этот флаг проверяется всегда — т.е. проблем не должно быть).

    Ссылка на архив, в котором тестовые проекты в AVR Studio 4 и Proteus 8.1: LCD_init.zip

  99. Возможно кому-нибудь окажется полезным чуток подправленный мной вариант этой же библиотеки с подключением по шести проводам в произвольном порядке. Это мой первый опыт программирования на asm avr, могут быть ошибки. Проверял на ATmega168 16МГц с дисплеем WH1602B, вроде работает.

  100. Всем доброго времени суток. Не давно начал контроллеры и вот мне захотелось провести эксперименты с дисплеем. Скачал Вашу библиотеку, для работы с дисплеем и клавиатурой. Немного подогнал под свои нужды. И тут же возник вопрос, стоит только подключить функцию инициализации дисплея, как все перестает работать. Может кто поможет разобраться. Все пока делаю в протеусе, а не на реальном железе. Все файлы можно скачать с темы на фуруме — http://forum.easyelectronics.ru/viewtopic.php?f=14&t=24079. Буду рад любой помощи.

  101. А почему при проверке готовности чтение выполняется после сброса E в 0, а при чтении команд/данных до? Почитал документацию, явного указания не нашел. Насколько понял по графикам, сигнал сохраняется после сброса E в течение 10 нс. МК не успеет прочитать данные. Думаю, что читать нужно всегда до сброса E.
    Или я не прав?

    1. Попробовал в порядке сброс Е -> чтение в Proteus-е. Зацикливается на проверке готовности (после сброса Е LCD сразу отпускает линию). В железе, возможно, будет работать по-другому.

Добавить комментарий

Ваш e-mail не будет опубликован.

Перед отправкой формы:
Human test by Not Captcha