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. Пользуйтесь.

Запись опубликована в рубрике AVR. Учебный курс с метками , , , , . Добавьте в закладки постоянную ссылку.

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

  1. dlinyj говорит:

    надеюсь тебе помог тот код, что тебе кидал?

  2. Xok говорит:

    ; Так как по дефолту шина 8 бит и нельзя передать сразу вторую половину байта. — эммм… туплю? ;-)

    • DI HALT говорит:

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

  3. nwanomaly говорит:

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

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

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

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

  4. penzet говорит:

    Управление 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).

  5. vanchester говорит:

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

  6. vanchester говорит:

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

  7. VICTOR говорит:

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

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

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

    • DI HALT говорит:

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

      • VICTOR говорит:

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

        • DI HALT говорит:

          Стирается. При каждом включении питания его надо заново инитить.

          • VICTOR говорит:

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

          • DI HALT говорит:

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

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

          • VICTOR говорит:

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

          • DI HALT говорит:

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

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

          • VICTOR говорит:

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

          • VICTOR говорит:

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

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

  8. ymn говорит:

    а схему макетки, простите за наглость, не выложите?

  9. Vadim говорит:

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

  10. Vadim говорит:

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

  11. Vadim говорит:

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

  12. Vadim говорит:

    Указал номер строки, номер столбца и символ высветился где указано.
    Очень удобно.

  13. holyavko говорит:

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

  14. testicq говорит:

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

    • DI HALT говорит:

      А зачем ЭТО писать в EEPROM? Пиши это в Flash ROM она же не меняется никогда.

      • testicq говорит:

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

        • DI HALT говорит:

          Повесь внешнюю ЕЕПРОММ Флешку со шрифтами. На и2с шину.

          • DI HALT говорит:

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

          • testicq говорит:

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

          • DI HALT говорит:

            Так свежак же! Не больше года назад появилась. А еще есть 328. То же самое, но на 32 метра.

          • testicq говорит:

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

          • testicq говорит:

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

          • DI HALT говорит:

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

          • testicq говорит:

            Класс! Буду ждать

  15. testicq говорит:

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

  16. ignor говорит:

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

    • DI HALT говорит:

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

      • ignor говорит:

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

        • DI HALT говорит:

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

          • ignor говорит:

            Спасибо за отклик, подумаю ещё… может чего и придумаю. Ещё раз спасибо.

  17. rutic1 говорит:

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

    • DI HALT говорит:

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

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

  18. rutic1 говорит:

    а чем различаются символьные и графические десплеи? Уних разная система команд?

  19. dbf_usr говорит:

    Пытаюсь прикрутить 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
    *****************************************************
    При прошивке фусы по дефолту, компиллер не ругается, контроллер шьется без ошибок и замечаний.
    При включении без признаков жизни. Попрежнему горит только верхний ряд (при управлении контрасностью). Что сделал не так? Бьюсь третий день -понять немогу. Прошу помощи!

    • DI HALT говорит:

      Странно. У меня тоже именно 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

    • Kefir_Danon говорит:

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

  20. dansar говорит:

    «Порт данных и порт данных указывай те…»
    Очепятка :)

  21. FreeManGH говорит:

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

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

    Думал трабла с аврстудио, поставил на другом компе — тожесамое.
    Вот конфиг:
    =========== 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»

    • DI HALT говорит:

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

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

      • FreeManGH говорит:

        А куда посмотреть, чтоб понять где набочил?

        • DI HALT говорит:

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

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

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

          • FreeManGH говорит:

            Да, на первом шаге переполнение стека повалило.
            вставил эти 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 ‘,’

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

          • DI HALT говорит:

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

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

          • FreeManGH говорит:

            Спасибо! Уже нашел этот макрос в предидущих статьях.

  22. goodic говорит:

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

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

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

  23. Westbam говорит:

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

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

  24. Melted Metal говорит:

    “Порт данных и порт данных указывай те…”

    Опечатка же)

  25. nictrace говорит:

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

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

  26. Alexander Starchen говорит:

    Привет!

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

  27. holyavko говорит:

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

    • DI HALT говорит:

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

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

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

      • holyavko говорит:

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

  28. Igor говорит:

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

  29. Name4Me говорит:

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

  30. Name4Me говорит:

    Инициализация 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)
    Хотя исходя из практики можна пропустить…

    • DI HALT говорит:

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

      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)
  31. BuHTuk говорит:

    Вот онлайн эмулятор LCD кому интересно поэкспериментировать =)

    http://www.dinceraydin.com/djlcdsim/djlcdsim.html

  32. Kefir_Danon говорит:

    Ребята помогите, мучаюсь вторую неделю. 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мкс), компилятор ругается и прочее…
    Вообщем помогите пожалуйста с инициализацией.

  33. Kefir_Danon говорит:

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

  34. Kefir_Danon говорит:

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

  35. april26 говорит:

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

  36. RunningWolf говорит:

    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. Лень было причесывать.

  37. bigdigital говорит:

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

    • Igor говорит:

      Это тебе делить надо или как у меня без делителя
      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,0×30 ; 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
      ;————————————————————————
      я то вообще новичок в етом деле.может кто лучше посоветует

  38. ghenias говорит:

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

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

  39. Vlad777 говорит:

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

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

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

  40. xamlo говорит:

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

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

  41. sergiosv говорит:

    Доброго времени суток!
    Использую 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=0×12 ;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=0×00;
    DDRB=0×00;

    // 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=0×00;
    DDRC=0×00;

    // 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=0×00;
    PORTB=0xFF;
    DDRD=0xFF;

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

    // 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=0×00;
    TCCR1B=0×00;
    TCNT1H=0×00;
    TCNT1L=0×00;
    ICR1H=0×00;
    ICR1L=0×00;
    OCR1AH=0×00;
    OCR1AL=0×00;
    OCR1BH=0×00;
    OCR1BL=0×00;

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

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

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

    // Analog Comparator initialization
    // Analog Comparator: Off
    // Analog Comparator Input Capture by Timer/Counter 1: Off
    ACSR=0×80;
    SFIOR=0×00;

    // 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. Не пинайте если чё не так написал это мой первый проект.

  42. sergiosv говорит:

    Схема почти такая http://forum.qrz.ru/attachment.php?attachmentid=7685&d=1182537241 . только LCD подключён на порт B.

  43. qwert говорит:

    подскажите куда подключены неиспользуемые D0-D3 у LCD

  44. Filia говорит:

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

    • DI HALT говорит:

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

  45. Blacky говорит:

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

    • Blacky говорит:

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

  46. brother77 говорит:

    Что то замучался я совсем с подключением 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 на массе сидит, уже и задержки зверские прикрутил.
    Что я сделал не так?

    • DI HALT говорит:

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

      • brother77 говорит:

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

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

      • brother77 говорит:

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

        • DI HALT говорит:

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

          • brother77 говорит:

            я зашивал и ща проверил hfuse=9A lfuse=E3.
            бит JTAGEN=0 вроде как

          • DI HALT говорит:

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

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

          • brother77 говорит:

            выключил фуз JTAGEN и все получилось.
            Спасибо за помощь.

          • brother77 говорит:

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

          • brother77 говорит:

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

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

    • Да, забыл добавить — фузы никакие не менял (значит внутренний генератор на 1 Мгц), в библиотеке поменял только порты (D-данные, В-управление), задержка так и стоит 14

      • DI HALT говорит:

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

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

          • Вроде зарабртало. Переписал часть кода ближе к даташиту.
            [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) ;0×01
            WR_CMD (1<<LCD_ENTRY_MODE)|(1<<LCD_ENTRY_INC);0×06
            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, иначе команды не уходили.
            Только курсор теперь мигает (раньше его не было).

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

    • DI HALT говорит:

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

  48. tiger говорит:

    Сначала хотелось бы сказать большое спасибо за этот курс. Нашел много интерсного а главное полезного мне.
    Прошу не судить строго за вопросы я лишь недавно начал интересоваться микроконтроллерами.
    Недавно купил дисплей 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)
    {
     
    }
    • DI HALT говорит:

      А там адресация поди чрезжопная. Суть в том, что первые 8 символов это одна строка, вторые 8 символов они как бы вторая строка.

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

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

  49. skadi.exe говорит:

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

  50. trak400 говорит:

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

  51. dima_m говорит:

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

  52. dima_m говорит:

    И еще, чем принципиально отличаются файлы с расширением .asm и .inc. Почему не забабахать все в один файл?

  53. dima_m говорит:

    SHIFT SCR_K; опечатка, нужно R.
    Отсутствует в библиотеке LCD_macro.inc макрос RD_CGADR xx который описывается в статье.

  54. dima_m говорит:

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

  55. Ruslan говорит:

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

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

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

  56. henvert говорит:

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

  57. Kefir_Danon говорит:

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

  58. henvert говорит:

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

  59. Ruslan говорит:

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

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

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

    • Ruslan говорит:

      Писал так:

      .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

      • DI HALT говорит:

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

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

        • Ruslan говорит:

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

          • Ruslan говорит:

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

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

          • Prompt_ говорит:

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

  60. henvert говорит:

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

  61. Ruslan говорит:

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

  62. Dmitriyff говорит:

    Привет, подскажи в чем может быть причина, дублируются символы при выводе на дисплей
    к примеру
    беру из таблицы символы
    начинающиеся все на 0×3
    первые 0×30 — 0×33 такие же как и 0×38 — 0x3B
    и другая пара одинакова, не могу понять в чем может быть проблема, библиотека твоя,
    дисплей WH1602M

  63. leseni говорит:

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

  64. leseni говорит:

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

  65. Igor говорит:

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

  66. dima_m говорит:

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

    • DI HALT говорит:

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

      • dima_m говорит:

        Я сейчас все проверил в реали. Да ты правильно сделал. Нужно потом читать и младшую тетраду, обязательно, хотя она и не используется. Тоесть нужен полный цикл чтения всего байта из 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
        порт на выход

        • DI HALT говорит:

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

  67. Hits говорит:

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

    • DI HALT говорит:

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

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

  68. gheorghii1988 говорит:

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

    .org 0×0000
    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=0×0168. Такая же ошибка вываливается и у меня когда я пытаюсь использовать LCD_4.asm.
    Уже начинаю подозревать что проблема может быть как-то в самой версии в протеусе.
    Что посоветуете?

    • gheorghii1988 говорит:

      Проверял в 7.6. Результат тот же

    • DI HALT говорит:

      А она в протеусе и не работала никогда.

      Только в железе.

      • gheorghii1988 говорит:

        Но в протеусе ведь есть примеры с работающими экранчиками?

        • DI HALT говорит:

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

          • gheorghii1988 говорит:

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

          • DI HALT говорит:

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

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

          • DI HALT говорит:

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

  69. Ruslan говорит:

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

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

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

  70. Ruslan говорит:

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

  71. Ruslan говорит:

    Блин даже с «сишной» библиотекой не выводит ничего =(((

  72. Ruslan говорит:

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

    • DI HALT говорит:

      Никак. Контроллер не позволяет это узнать. Только самому где то запоминать

    • Andrey41 говорит:

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

  73. SergeyDon говорит:

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

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

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

  74. Si-Soft говорит:

    Как можно вывести значение переменной на LCD, в avr-lib.

  75. xrnd говорит:

    Привет.

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

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

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

    • DI HALT говорит:

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

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

  76. Sh@dow говорит:

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

    • Sh@dow говорит:

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

    • DI HALT говорит:

      Где проверял?

      • Sh@dow говорит:

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

  77. Fonarik говорит:

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

    • DI HALT говорит:

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

  78. vt1980 говорит:

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

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

    • DI HALT говорит:

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

      • vt1980 говорит:

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

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

        .equ l_0 = 0×30 ;0
        .equ l_1 = 0×31 ;1
        .equ l_2 = 0×32 ;2

        .equ lrb_a = 0×41 ;А
        .equ lrb_b = 0xA0 ;Б
        .equ lrb_v = 0×42 ;В

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

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

        • DI HALT говорит:

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

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

          • vt1980 говорит:

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

          • DI HALT говорит:

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

          • vt1980 говорит:

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

  79. arm-17 говорит:

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

    • DI HALT говорит:

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

      • arm-17 говорит:

        Вот код.Но 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

        • DI HALT говорит:

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

        • arm-17 говорит:

          вот что пишет:C:\AVR\WH\LCD_macro.inc(48): error: syntax error, unexpected STRING

          • DI HALT говорит:

            Ну так все правильно, кавычки должны быть одинарные, а не двойные.

          • arm-17 говорит:

            Все равно ругаетса именно на LDI R17,@0

          • DI HALT говорит:

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

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

          • arm-17 говорит:

            Все разобрался написал в 16-и рич. форме)))СПАСИБО!!!

  80. arm-17 говорит:

    ;Write Data
    .MACRO WR_DATA
    LDI R17,@0;Что тут надо подставить?
    RCALL DATA_WR
    .ENDM

  81. arm-17 говорит:

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

  82. arm-17 говорит:

    Я прочел просто не пойму как это зделать.

    • DI HALT говорит:

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

  83. salpingot говорит:

    http://easyelectronics.ru/repository.php?act=view&id=65 — тут код только на один байт т.е. значения от 0 до 255. А если мне нужно конвертировать больше разрядов??? (сам пока не смог придумать что либо простое и эффективное).

  84. shilow говорит:

    Добрый день!

    пытаюсь использовать Вашу библиотеку:
    .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 в основном файле.

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

    • DI HALT говорит:

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

      • shilow говорит:

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

        • DI HALT говорит:

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

          • shilow говорит:

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

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

        • DI HALT говорит:

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

    • shilow говорит:

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

  85. shilow говорит:

    В proteus-е заработало после этого:
    http://electronix.ru/forum/index.php?showtopic=52609&view=findpost&p=469720

    в lcd_macro.inc в макросе INIT_LCD после строки
    RCALL LCD_DELAY
    добавил строку
    WR_CMD 0×02
    и заработало.

  86. Gennadiy говорит:

    Доброго дня.
    Прошу подсказать новичку.
    Пишу программу (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 напечатем его

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

    • DI HALT говорит:

      А где инициализация порта A и E?

      • Gennadiy говорит:

        Инициализацию портов А и Е в основной программе я не делал, поскольку она должна выполняться после вызова макроса «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

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

  87. apexi говорит:

    Добрый день!
    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,0×80

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

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

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

  88. apexi говорит:

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

  89. b319926 говорит:

    .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 ряд черных квадратиков. Подскажите что не то делаю.

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